a0595d0249
locking flags when acquiring a vnode. The immediate purpose is to allow polling lock requests (LK_NOWAIT) needed by soft updates to avoid deadlock when enlisting other processes to help with the background cleanup. For the future it will allow the use of shared locks for read access to vnodes. This change touches a lot of files as it affects most filesystems within the system. It has been well tested on FFS, loopback, and CD-ROM filesystems. only lightly on the others, so if you find a problem there, please let me (mckusick@mckusick.com) know.
864 lines
17 KiB
C
864 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);
|
|
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 hpfsmount *hpmp,
|
|
struct hpfs_args *argsp)
|
|
{
|
|
struct buf *bp;
|
|
int error, i;
|
|
lsn_t lsn;
|
|
int cpicnt;
|
|
struct cpisec * cpisp;
|
|
struct cpiblk * cpibp;
|
|
struct cpdblk * cpdbp;
|
|
|
|
dprintf(("hpfs_cpinit: \n"));
|
|
|
|
if (argsp->flags & HPFSMNT_TABLES) {
|
|
bcopy(argsp->d2u, hpmp->hpm_d2u, sizeof(u_char) * 0x80);
|
|
bcopy(argsp->u2d, hpmp->hpm_u2d, sizeof(u_char) * 0x80);
|
|
} else {
|
|
for (i=0x0; i<0x80;i++) {
|
|
hpmp->hpm_d2u[i] = i + 0x80;
|
|
hpmp->hpm_u2d[i] = i + 0x80;
|
|
}
|
|
}
|
|
|
|
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);
|
|
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);
|
|
}
|
|
|