3d2dc8aba5
Same comment as msdosfs applies: It would be nice if we had generic option names for charset conversions. Use vfs_mountefrom(). Rely on vfs_mount.c calling VFS_STATFS().
870 lines
17 KiB
C
870 lines
17 KiB
C
/*-
|
|
* Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/vnode.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/namei.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/bio.h>
|
|
#include <sys/buf.h>
|
|
|
|
#include <fs/hpfs/hpfs.h>
|
|
#include <fs/hpfs/hpfsmount.h>
|
|
#include <fs/hpfs/hpfs_subr.h>
|
|
|
|
u_long
|
|
hpfs_checksum(
|
|
u_int8_t *object,
|
|
int size)
|
|
{
|
|
register int i;
|
|
u_long csum=0L;
|
|
for (i=0; i < size; i++) {
|
|
csum += (u_long) *object++;
|
|
csum = (csum << 7) + (csum >> (25));
|
|
}
|
|
return (csum);
|
|
}
|
|
|
|
void
|
|
hpfs_bmdeinit(
|
|
struct hpfsmount *hpmp)
|
|
{
|
|
struct buf *bp;
|
|
int i;
|
|
|
|
dprintf(("hpmp_bmdeinit: "));
|
|
|
|
if (!(hpmp->hpm_mp->mnt_flag & MNT_RDONLY)) {
|
|
/*
|
|
* Write down BitMap.
|
|
*/
|
|
for (i=0; i<hpmp->hpm_dbnum; i++) {
|
|
dprintf(("[%d: 0x%x] ", i, hpmp->hpm_bmind[i]));
|
|
|
|
bp = getblk(hpmp->hpm_devvp, hpmp->hpm_bmind[i],
|
|
BMSIZE, 0, 0, 0);
|
|
clrbuf(bp);
|
|
|
|
bcopy(hpmp->hpm_bitmap + BMSIZE * i, bp->b_data,
|
|
BMSIZE);
|
|
|
|
bwrite(bp);
|
|
}
|
|
}
|
|
|
|
FREE(hpmp->hpm_bitmap,M_HPFSMNT);
|
|
FREE(hpmp->hpm_bmind,M_HPFSMNT);
|
|
|
|
dprintf(("\n"));
|
|
}
|
|
|
|
/*
|
|
* Initialize BitMap management, includes calculation of
|
|
* available blocks number.
|
|
*/
|
|
int
|
|
hpfs_bminit(
|
|
struct hpfsmount *hpmp)
|
|
{
|
|
struct buf *bp;
|
|
int error, i, k;
|
|
u_long dbavail;
|
|
|
|
dprintf(("hpfs_bminit: "));
|
|
|
|
hpmp->hpm_dbnum = (hpmp->hpm_su.su_btotal + 0x3FFF) / 0x4000;
|
|
|
|
dprintf(("0x%lx data bands, ", hpmp->hpm_dbnum));
|
|
|
|
MALLOC(hpmp->hpm_bmind, lsn_t *, hpmp->hpm_dbnum * sizeof(lsn_t),
|
|
M_HPFSMNT, M_WAITOK);
|
|
|
|
MALLOC(hpmp->hpm_bitmap, u_int8_t *, hpmp->hpm_dbnum * BMSIZE,
|
|
M_HPFSMNT, M_WAITOK);
|
|
|
|
error = bread(hpmp->hpm_devvp, hpmp->hpm_su.su_bitmap.lsn1,
|
|
((hpmp->hpm_dbnum + 0x7F) & ~(0x7F)) << 2, NOCRED, &bp);
|
|
if (error) {
|
|
brelse(bp);
|
|
FREE(hpmp->hpm_bitmap, M_HPFSMNT);
|
|
FREE(hpmp->hpm_bmind, M_HPFSMNT);
|
|
dprintf((" error %d\n", error));
|
|
return (error);
|
|
}
|
|
bcopy(bp->b_data, hpmp->hpm_bmind, hpmp->hpm_dbnum * sizeof(lsn_t));
|
|
|
|
brelse(bp);
|
|
|
|
/*
|
|
* Read in all BitMap
|
|
*/
|
|
for (i=0; i<hpmp->hpm_dbnum; i++) {
|
|
dprintf(("[%d: 0x%x] ", i, hpmp->hpm_bmind[i]));
|
|
|
|
error = bread(hpmp->hpm_devvp, hpmp->hpm_bmind[i],
|
|
BMSIZE, NOCRED, &bp);
|
|
if (error) {
|
|
brelse(bp);
|
|
FREE(hpmp->hpm_bitmap, M_HPFSMNT);
|
|
FREE(hpmp->hpm_bmind, M_HPFSMNT);
|
|
dprintf((" error %d\n", error));
|
|
return (error);
|
|
}
|
|
bcopy(bp->b_data, hpmp->hpm_bitmap + BMSIZE * i, BMSIZE);
|
|
|
|
brelse(bp);
|
|
}
|
|
|
|
/*
|
|
* Look througth BitMap and count free bits
|
|
*/
|
|
dbavail = 0;
|
|
for (i=0; i < hpmp->hpm_su.su_btotal >> 5; i++) {
|
|
register u_int32_t mask;
|
|
for (k=0, mask=1; k < 32; k++, mask<<=1)
|
|
if(((u_int32_t *)hpmp->hpm_bitmap)[i] & mask)
|
|
dbavail ++;
|
|
|
|
}
|
|
hpmp->hpm_bavail = dbavail;
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
hpfs_cmpfname (
|
|
struct hpfsmount *hpmp,
|
|
char * uname,
|
|
int ulen,
|
|
char * dname,
|
|
int dlen,
|
|
u_int16_t cp)
|
|
{
|
|
register int i, res;
|
|
|
|
for (i = 0; i < ulen && i < dlen; i++) {
|
|
res = hpfs_toupper(hpmp, hpfs_u2d(hpmp, uname[i]), cp) -
|
|
hpfs_toupper(hpmp, dname[i], cp);
|
|
if (res)
|
|
return res;
|
|
}
|
|
return (ulen - dlen);
|
|
}
|
|
|
|
int
|
|
hpfs_cpstrnnicmp (
|
|
struct hpfsmount *hpmp,
|
|
char * str1,
|
|
int str1len,
|
|
u_int16_t str1cp,
|
|
char * str2,
|
|
int str2len,
|
|
u_int16_t str2cp)
|
|
{
|
|
int i, res;
|
|
|
|
for (i = 0; i < str1len && i < str2len; i++) {
|
|
res = (int)hpfs_toupper(hpmp, ((u_char *)str1)[i], str1cp) -
|
|
(int)hpfs_toupper(hpmp, ((u_char *)str2)[i], str2cp);
|
|
if (res)
|
|
return res;
|
|
}
|
|
return (str1len - str2len);
|
|
}
|
|
|
|
|
|
int
|
|
hpfs_cpload (
|
|
struct hpfsmount *hpmp,
|
|
struct cpiblk *cpibp,
|
|
struct cpdblk *cpdbp)
|
|
{
|
|
struct buf *bp;
|
|
struct cpdsec * cpdsp;
|
|
int error, i;
|
|
|
|
error = bread(hpmp->hpm_devvp, cpibp->b_cpdsec, DEV_BSIZE, NOCRED, &bp);
|
|
if (error) {
|
|
brelse(bp);
|
|
return (error);
|
|
}
|
|
|
|
cpdsp = (struct cpdsec *)bp->b_data;
|
|
|
|
for (i=cpdsp->d_cpfirst; i<cpdsp->d_cpcnt; i++) {
|
|
if (cpdsp->d_cpdblk[i].b_cpid == cpibp->b_cpid) {
|
|
bcopy(cpdsp->d_cpdblk + i, cpdbp,
|
|
sizeof(struct cpdblk));
|
|
|
|
brelse(bp);
|
|
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
brelse(bp);
|
|
|
|
return (ENOENT);
|
|
}
|
|
|
|
|
|
/*
|
|
* Initialize Code Page information management.
|
|
* Load all copdepages in memory.
|
|
*/
|
|
int
|
|
hpfs_cpinit (
|
|
struct mount *mp,
|
|
struct hpfsmount *hpmp)
|
|
{
|
|
struct buf *bp;
|
|
int error, i;
|
|
lsn_t lsn;
|
|
int cpicnt;
|
|
struct cpisec * cpisp;
|
|
struct cpiblk * cpibp;
|
|
struct cpdblk * cpdbp;
|
|
|
|
dprintf(("hpfs_cpinit: \n"));
|
|
|
|
error = vfs_copyopt(mp->mnt_optnew, "d2u", hpmp->hpm_d2u,
|
|
sizeof hpmp->hpm_d2u);
|
|
if (error == ENOENT)
|
|
for (i=0x0; i<0x80;i++)
|
|
hpmp->hpm_d2u[i] = i + 0x80;
|
|
else if (error)
|
|
return (error);
|
|
|
|
error = vfs_copyopt(mp->mnt_optnew, "u2d", hpmp->hpm_u2d,
|
|
sizeof hpmp->hpm_u2d);
|
|
if (error == ENOENT)
|
|
for (i=0x0; i<0x80;i++)
|
|
hpmp->hpm_u2d[i] = i + 0x80;
|
|
else if (error)
|
|
return (error);
|
|
|
|
cpicnt = hpmp->hpm_sp.sp_cpinum;
|
|
|
|
MALLOC(hpmp->hpm_cpdblk, struct cpdblk *,
|
|
cpicnt * sizeof(struct cpdblk), M_HPFSMNT, M_WAITOK);
|
|
|
|
cpdbp = hpmp->hpm_cpdblk;
|
|
lsn = hpmp->hpm_sp.sp_cpi;
|
|
|
|
while (cpicnt > 0) {
|
|
error = bread(hpmp->hpm_devvp, lsn, DEV_BSIZE, NOCRED, &bp);
|
|
if (error) {
|
|
brelse(bp);
|
|
return (error);
|
|
}
|
|
|
|
cpisp = (struct cpisec *)bp->b_data;
|
|
|
|
cpibp = cpisp->s_cpi;
|
|
for (i=0; i<cpisp->s_cpicnt; i++, cpicnt --, cpdbp++, cpibp++) {
|
|
dprintf(("hpfs_cpinit: Country: %d, CP: %d (%d)\n",
|
|
cpibp->b_country, cpibp->b_cpid,
|
|
cpibp->b_vcpid));
|
|
|
|
error = hpfs_cpload(hpmp, cpibp, cpdbp);
|
|
if (error) {
|
|
brelse(bp);
|
|
return (error);
|
|
}
|
|
}
|
|
lsn = cpisp->s_next;
|
|
brelse(bp);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
hpfs_cpdeinit (
|
|
struct hpfsmount *hpmp)
|
|
{
|
|
dprintf(("hpmp_cpdeinit: "));
|
|
FREE(hpmp->hpm_cpdblk,M_HPFSMNT);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Lookup for a run of blocks.
|
|
*/
|
|
int
|
|
hpfs_bmlookup (
|
|
struct hpfsmount *hpmp,
|
|
u_long flags, /* 1 means we want right len blocks in run, not less */
|
|
lsn_t lsn, /* We want near this one */
|
|
u_long len, /* We want such long */
|
|
lsn_t *lsnp, /* We got here */
|
|
u_long *lenp) /* We got this long */
|
|
{
|
|
u_int32_t * bitmap;
|
|
register u_int32_t mask;
|
|
int i,k;
|
|
int cband, vcband;
|
|
u_int bandsz;
|
|
int count;
|
|
|
|
dprintf(("hpfs_bmlookup: lsn: 0x%x, len 0x%lx | Step1\n", lsn, len));
|
|
|
|
if (lsn > hpmp->hpm_su.su_btotal) {
|
|
printf("hpfs_bmlookup: OUT OF VOLUME\n");
|
|
return ENOSPC;
|
|
}
|
|
if (len > hpmp->hpm_bavail) {
|
|
printf("hpfs_bmlookup: OUT OF SPACE\n");
|
|
return ENOSPC;
|
|
}
|
|
i = lsn >> 5;
|
|
k = lsn & 0x1F;
|
|
mask = 1 << k;
|
|
bitmap = (u_int32_t *)hpmp->hpm_bitmap + i;
|
|
|
|
if (*bitmap & mask) {
|
|
*lsnp = lsn;
|
|
*lenp = 0;
|
|
for (; k < 32; k++, mask<<=1) {
|
|
if (*bitmap & mask)
|
|
(*lenp) ++;
|
|
else {
|
|
if (flags & 1)
|
|
goto step2;
|
|
else
|
|
return (0);
|
|
}
|
|
|
|
if (*lenp == len)
|
|
return (0);
|
|
}
|
|
|
|
bitmap++;
|
|
i++;
|
|
for (; i < hpmp->hpm_su.su_btotal >> 5; i++, bitmap++) {
|
|
for (k=0, mask=1; k < 32; k++, mask<<=1) {
|
|
if (*bitmap & mask)
|
|
(*lenp) ++;
|
|
else {
|
|
if (flags & 1)
|
|
goto step2;
|
|
else
|
|
return (0);
|
|
}
|
|
|
|
if (*lenp == len)
|
|
return (0);
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
step2:
|
|
/*
|
|
* Lookup all bands begining from cband, lookup for first block
|
|
*/
|
|
cband = (lsn >> 14);
|
|
dprintf(("hpfs_bmlookup: Step2: band 0x%x (0x%lx)\n",
|
|
cband, hpmp->hpm_dbnum));
|
|
for (vcband = 0; vcband < hpmp->hpm_dbnum; vcband ++, cband++) {
|
|
cband = cband % hpmp->hpm_dbnum;
|
|
bandsz = min (hpmp->hpm_su.su_btotal - (cband << 14), 0x4000);
|
|
dprintf(("hpfs_bmlookup: band: %d, sz: 0x%x\n", cband, bandsz));
|
|
|
|
bitmap = (u_int32_t *)hpmp->hpm_bitmap + (cband << 9);
|
|
*lsnp = cband << 14;
|
|
*lenp = 0;
|
|
count = 0;
|
|
for (i=0; i < bandsz >> 5; i++, bitmap++) {
|
|
for (k=0, mask=1; k < 32; k++, mask<<=1) {
|
|
if (*bitmap & mask) {
|
|
if (count) {
|
|
(*lenp) ++;
|
|
} else {
|
|
count = 1;
|
|
*lsnp = (cband << 14) + (i << 5) + k;
|
|
*lenp = 1;
|
|
}
|
|
} else {
|
|
if ((*lenp) && !(flags & 1)) {
|
|
return (0);
|
|
} else {
|
|
count = 0;
|
|
}
|
|
}
|
|
|
|
if (*lenp == len)
|
|
return (0);
|
|
}
|
|
}
|
|
if (cband == hpmp->hpm_dbnum - 1) {
|
|
if ((*lenp) && !(flags & 1)) {
|
|
return (0);
|
|
} else {
|
|
count = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (ENOSPC);
|
|
}
|
|
|
|
/*
|
|
* Lookup a single free block. XXX Need locking on BitMap operations
|
|
* VERY STUPID ROUTINE!!!
|
|
*/
|
|
int
|
|
hpfs_bmfblookup (
|
|
struct hpfsmount *hpmp,
|
|
lsn_t *lp)
|
|
{
|
|
u_int32_t * bitmap;
|
|
int i,k;
|
|
|
|
dprintf(("hpfs_bmfblookup: "));
|
|
|
|
bitmap = (u_int32_t *)hpmp->hpm_bitmap;
|
|
for (i=0; i < hpmp->hpm_su.su_btotal >> 5; i++, bitmap++) {
|
|
k = ffs(*bitmap);
|
|
if (k) {
|
|
*lp = (i << 5) + k - 1;
|
|
dprintf((" found: 0x%x\n",*lp));
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
return (ENOSPC);
|
|
}
|
|
|
|
/*
|
|
* Mark contignous block of blocks.
|
|
*/
|
|
int
|
|
hpfs_bmmark (
|
|
struct hpfsmount *hpmp,
|
|
lsn_t bn,
|
|
u_long bl,
|
|
int state)
|
|
{
|
|
u_int32_t * bitmap;
|
|
int i, didprint = 0;
|
|
|
|
dprintf(("hpfs_bmmark(0x%x, 0x%lx, %d): \n",bn,bl, state));
|
|
|
|
if ((bn > hpmp->hpm_su.su_btotal) || (bn+bl > hpmp->hpm_su.su_btotal)) {
|
|
printf("hpfs_bmmark: MARKING OUT OF VOLUME\n");
|
|
return 0;
|
|
}
|
|
bitmap = (u_int32_t *)hpmp->hpm_bitmap;
|
|
bitmap += bn >> 5;
|
|
|
|
while (bl > 0) {
|
|
for (i = bn & 0x1F; (i < 0x20) && (bl > 0) ; i++, bl--) {
|
|
if (state) {
|
|
if ( *bitmap & (1 << i)) {
|
|
if (!didprint) {
|
|
printf("hpfs_bmmark: ALREADY FREE\n");
|
|
didprint = 1;
|
|
}
|
|
} else
|
|
hpmp->hpm_bavail++;
|
|
|
|
*bitmap |= (1 << i);
|
|
} else {
|
|
if ((~(*bitmap)) & (1 << i)) {
|
|
if (!didprint) {
|
|
printf("hpfs_bmmark: ALREADY BUSY\n");
|
|
didprint = 1;
|
|
}
|
|
} else
|
|
hpmp->hpm_bavail--;
|
|
|
|
*bitmap &= ~(1 << i);
|
|
}
|
|
}
|
|
bn = 0;
|
|
bitmap++;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
int
|
|
hpfs_validateparent (
|
|
struct hpfsnode *hp)
|
|
{
|
|
struct hpfsnode *dhp;
|
|
struct vnode *dvp;
|
|
struct hpfsmount *hpmp = hp->h_hpmp;
|
|
struct buf *bp;
|
|
struct dirblk *dp;
|
|
struct hpfsdirent *dep;
|
|
lsn_t lsn, olsn;
|
|
int level, error;
|
|
|
|
dprintf(("hpfs_validatetimes(0x%x): [parent: 0x%x] ",
|
|
hp->h_no, hp->h_fn.fn_parent));
|
|
|
|
if (hp->h_no == hp->h_fn.fn_parent) {
|
|
dhp = hp;
|
|
} else {
|
|
error = VFS_VGET(hpmp->hpm_mp, hp->h_fn.fn_parent,
|
|
LK_EXCLUSIVE, &dvp);
|
|
if (error)
|
|
return (error);
|
|
dhp = VTOHP(dvp);
|
|
}
|
|
|
|
lsn = ((alleaf_t *)dhp->h_fn.fn_abd)->al_lsn;
|
|
|
|
olsn = 0;
|
|
level = 1;
|
|
bp = NULL;
|
|
|
|
dive:
|
|
dprintf(("[dive 0x%x] ", lsn));
|
|
if (bp != NULL)
|
|
brelse(bp);
|
|
error = bread(dhp->h_devvp, lsn, D_BSIZE, NOCRED, &bp);
|
|
if (error)
|
|
goto failed;
|
|
|
|
dp = (struct dirblk *) bp->b_data;
|
|
if (dp->d_magic != D_MAGIC) {
|
|
printf("hpfs_validatetimes: magic doesn't match\n");
|
|
error = EINVAL;
|
|
goto failed;
|
|
}
|
|
|
|
dep = D_DIRENT(dp);
|
|
|
|
if (olsn) {
|
|
dprintf(("[restore 0x%x] ", olsn));
|
|
|
|
while(!(dep->de_flag & DE_END) ) {
|
|
if((dep->de_flag & DE_DOWN) &&
|
|
(olsn == DE_DOWNLSN(dep)))
|
|
break;
|
|
dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
|
|
}
|
|
|
|
if((dep->de_flag & DE_DOWN) && (olsn == DE_DOWNLSN(dep))) {
|
|
if (dep->de_flag & DE_END)
|
|
goto blockdone;
|
|
|
|
if (hp->h_no == dep->de_fnode) {
|
|
dprintf(("[found] "));
|
|
goto readdone;
|
|
}
|
|
|
|
dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
|
|
} else {
|
|
printf("hpfs_validatetimes: ERROR! oLSN not found\n");
|
|
error = EINVAL;
|
|
goto failed;
|
|
}
|
|
}
|
|
|
|
olsn = 0;
|
|
|
|
while(!(dep->de_flag & DE_END)) {
|
|
if(dep->de_flag & DE_DOWN) {
|
|
lsn = DE_DOWNLSN(dep);
|
|
level++;
|
|
goto dive;
|
|
}
|
|
|
|
if (hp->h_no == dep->de_fnode) {
|
|
dprintf(("[found] "));
|
|
goto readdone;
|
|
}
|
|
|
|
dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
|
|
}
|
|
|
|
if(dep->de_flag & DE_DOWN) {
|
|
dprintf(("[enddive] "));
|
|
lsn = DE_DOWNLSN(dep);
|
|
level++;
|
|
goto dive;
|
|
}
|
|
|
|
blockdone:
|
|
dprintf(("[EOB] "));
|
|
olsn = lsn;
|
|
lsn = dp->d_parent;
|
|
level--;
|
|
dprintf(("[level %d] ", level));
|
|
if (level > 0)
|
|
goto dive; /* undive really */
|
|
|
|
goto failed;
|
|
|
|
readdone:
|
|
bcopy(dep->de_name,hp->h_name,dep->de_namelen);
|
|
hp->h_name[dep->de_namelen] = '\0';
|
|
hp->h_namelen = dep->de_namelen;
|
|
hp->h_ctime = dep->de_ctime;
|
|
hp->h_atime = dep->de_atime;
|
|
hp->h_mtime = dep->de_mtime;
|
|
hp->h_flag |= H_PARVALID;
|
|
|
|
dprintf(("[readdone]"));
|
|
|
|
failed:
|
|
dprintf(("\n"));
|
|
if (bp != NULL)
|
|
brelse(bp);
|
|
if (hp != dhp)
|
|
vput(dvp);
|
|
|
|
return (error);
|
|
}
|
|
|
|
struct timespec
|
|
hpfstimetounix (
|
|
u_long hptime)
|
|
{
|
|
struct timespec t;
|
|
|
|
t.tv_nsec = 0;
|
|
t.tv_sec = hptime;
|
|
|
|
return t;
|
|
}
|
|
|
|
/*
|
|
* Write down changes done to parent dir, these are only times for now.
|
|
* hpfsnode have to be locked.
|
|
*/
|
|
int
|
|
hpfs_updateparent (
|
|
struct hpfsnode *hp)
|
|
{
|
|
struct hpfsnode *dhp;
|
|
struct vnode *dvp;
|
|
struct hpfsdirent *dep;
|
|
struct buf * bp;
|
|
int error;
|
|
|
|
dprintf(("hpfs_updateparent(0x%x): \n", hp->h_no));
|
|
|
|
if (!(hp->h_flag & H_PARCHANGE))
|
|
return (0);
|
|
|
|
if (!(hp->h_flag & H_PARVALID)) {
|
|
error = hpfs_validateparent (hp);
|
|
if (error)
|
|
return (error);
|
|
}
|
|
|
|
if (hp->h_no == hp->h_fn.fn_parent) {
|
|
dhp = hp;
|
|
} else {
|
|
error = VFS_VGET(hp->h_hpmp->hpm_mp, hp->h_fn.fn_parent,
|
|
LK_EXCLUSIVE, &dvp);
|
|
if (error)
|
|
return (error);
|
|
dhp = VTOHP(dvp);
|
|
}
|
|
|
|
error = hpfs_genlookupbyname (dhp, hp->h_name, hp->h_namelen,
|
|
&bp, &dep);
|
|
if (error) {
|
|
goto failed;
|
|
}
|
|
|
|
dep->de_atime = hp->h_atime;
|
|
dep->de_mtime = hp->h_mtime;
|
|
dep->de_size = hp->h_fn.fn_size;
|
|
|
|
bdwrite (bp);
|
|
|
|
hp->h_flag &= ~H_PARCHANGE;
|
|
|
|
error = 0;
|
|
failed:
|
|
if (hp != dhp)
|
|
vput(dvp);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Write down on disk changes done to fnode. hpfsnode have to be locked.
|
|
*/
|
|
int
|
|
hpfs_update (
|
|
struct hpfsnode *hp)
|
|
{
|
|
struct buf * bp;
|
|
|
|
dprintf(("hpfs_update(0x%x): \n", hp->h_no));
|
|
|
|
if (!(hp->h_flag & H_CHANGE))
|
|
return (0);
|
|
|
|
bp = getblk(hp->h_devvp, hp->h_no, FNODESIZE, 0, 0, 0);
|
|
clrbuf(bp);
|
|
|
|
bcopy (&hp->h_fn, bp->b_data, sizeof(struct fnode));
|
|
bdwrite (bp);
|
|
|
|
hp->h_flag &= ~H_CHANGE;
|
|
|
|
if (hp->h_flag & H_PARCHANGE)
|
|
return (hpfs_updateparent(hp));
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Truncate file to specifed size. hpfsnode have to be locked.
|
|
*/
|
|
int
|
|
hpfs_truncate (
|
|
struct hpfsnode *hp,
|
|
u_long size)
|
|
{
|
|
struct hpfsmount *hpmp = hp->h_hpmp;
|
|
lsn_t newblen, oldblen;
|
|
int error, pf;
|
|
|
|
dprintf(("hpfs_truncate(0x%x, 0x%x -> 0x%lx): ",
|
|
hp->h_no, hp->h_fn.fn_size, size));
|
|
|
|
newblen = (size + DEV_BSIZE - 1) >> DEV_BSHIFT;
|
|
oldblen = (hp->h_fn.fn_size + DEV_BSIZE - 1) >> DEV_BSHIFT;
|
|
|
|
dprintf(("blen: 0x%x -> 0x%x\n", oldblen, newblen));
|
|
|
|
error = hpfs_truncatealblk (hpmp, &hp->h_fn.fn_ab, newblen, &pf);
|
|
if (error)
|
|
return (error);
|
|
if (pf) {
|
|
hp->h_fn.fn_ab.ab_flag = 0;
|
|
hp->h_fn.fn_ab.ab_freecnt = 0x8;
|
|
hp->h_fn.fn_ab.ab_busycnt = 0x0;
|
|
hp->h_fn.fn_ab.ab_freeoff = sizeof(alblk_t);
|
|
}
|
|
|
|
hp->h_fn.fn_size = size;
|
|
|
|
hp->h_flag |= (H_CHANGE | H_PARCHANGE);
|
|
|
|
dprintf(("hpfs_truncate: successful\n"));
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Enlarge file to specifed size. hpfsnode have to be locked.
|
|
*/
|
|
int
|
|
hpfs_extend (
|
|
struct hpfsnode *hp,
|
|
u_long size)
|
|
{
|
|
struct hpfsmount *hpmp = hp->h_hpmp;
|
|
lsn_t newblen, oldblen;
|
|
int error;
|
|
|
|
dprintf(("hpfs_extend(0x%x, 0x%x -> 0x%lx): ",
|
|
hp->h_no, hp->h_fn.fn_size, size));
|
|
|
|
if (hpmp->hpm_bavail < 0x10)
|
|
return (ENOSPC);
|
|
|
|
newblen = (size + DEV_BSIZE - 1) >> DEV_BSHIFT;
|
|
oldblen = (hp->h_fn.fn_size + DEV_BSIZE - 1) >> DEV_BSHIFT;
|
|
|
|
dprintf(("blen: 0x%x -> 0x%x\n", oldblen, newblen));
|
|
|
|
error = hpfs_addextent(hpmp, hp, newblen - oldblen);
|
|
if (error) {
|
|
printf("hpfs_extend: FAILED TO ADD EXTENT %d\n", error);
|
|
return (error);
|
|
}
|
|
|
|
hp->h_fn.fn_size = size;
|
|
|
|
hp->h_flag |= (H_CHANGE | H_PARCHANGE);
|
|
|
|
dprintf(("hpfs_extend: successful\n"));
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Read AlSec structure, and check if magic is valid.
|
|
* You don't need to brelse buf on error.
|
|
*/
|
|
int
|
|
hpfs_breadstruct (
|
|
struct hpfsmount *hpmp,
|
|
lsn_t lsn,
|
|
u_int len,
|
|
u_int32_t magic,
|
|
struct buf **bpp)
|
|
{
|
|
struct buf *bp;
|
|
u_int32_t *mp;
|
|
int error;
|
|
|
|
dprintf(("hpfs_breadstruct: reading at 0x%x\n", lsn));
|
|
|
|
*bpp = NULL;
|
|
|
|
error = bread(hpmp->hpm_devvp, lsn, len, NOCRED, &bp);
|
|
if (error) {
|
|
brelse(bp);
|
|
return (error);
|
|
}
|
|
mp = (u_int32_t *) bp->b_data;
|
|
if (*mp != magic) {
|
|
brelse(bp);
|
|
printf("hpfs_breadstruct: MAGIC DOESN'T MATCH (0x%08x != 0x%08x)\n",
|
|
*mp, magic);
|
|
return (EINVAL);
|
|
}
|
|
|
|
*bpp = bp;
|
|
|
|
return (0);
|
|
}
|
|
|