summaryrefslogtreecommitdiffstats
path: root/sys/msdosfs/msdosfs_denode.c
diff options
context:
space:
mode:
authorjkh <jkh@FreeBSD.org>1998-02-18 09:28:47 +0000
committerjkh <jkh@FreeBSD.org>1998-02-18 09:28:47 +0000
commit90f90fc3470f6725b317b359c1b3149995b822b7 (patch)
treea41d30021bc38cb8b60af8e616a1a634111adecc /sys/msdosfs/msdosfs_denode.c
parent4430df5b848751ab6f0d04b584f8c0921f47d494 (diff)
downloadFreeBSD-src-90f90fc3470f6725b317b359c1b3149995b822b7.zip
FreeBSD-src-90f90fc3470f6725b317b359c1b3149995b822b7.tar.gz
Update MSDOSFS code using NetBSD's msdosfs as a guide to support
FAT32 partitions. Unfortunately, we looked around here at Walnut Creek CDROM for any newer FAT32-supporting versions of Win95 and we were unsuccessful; only the older stuff here. So this is untested beyond simply making sure it compiles and someone with access to an actual FAT32 fs will have to let us know how well it actually works. Submitted by: Dmitrij Tejblum <dima@tejblum.dnttm.rssi.ru> Obtained from: NetBSD
Diffstat (limited to 'sys/msdosfs/msdosfs_denode.c')
-rw-r--r--sys/msdosfs/msdosfs_denode.c285
1 files changed, 117 insertions, 168 deletions
diff --git a/sys/msdosfs/msdosfs_denode.c b/sys/msdosfs/msdosfs_denode.c
index 81e0699..6feabbb 100644
--- a/sys/msdosfs/msdosfs_denode.c
+++ b/sys/msdosfs/msdosfs_denode.c
@@ -1,9 +1,9 @@
-/* $Id: msdosfs_denode.c,v 1.30 1998/02/06 12:13:46 eivind Exp $ */
-/* $NetBSD: msdosfs_denode.c,v 1.9 1994/08/21 18:44:00 ws Exp $ */
+/* $Id: msdosfs_denode.c,v 1.31 1998/02/09 06:09:51 eivind Exp $ */
+/* $NetBSD: msdosfs_denode.c,v 1.28 1998/02/10 14:10:00 mrg Exp $ */
/*-
- * Copyright (C) 1994 Wolfgang Solfrank.
- * Copyright (C) 1994 TooLs GmbH.
+ * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
+ * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
* All rights reserved.
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
*
@@ -69,8 +69,9 @@
static MALLOC_DEFINE(M_MSDOSFSNODE, "MSDOSFS node", "MSDOSFS vnode private part");
static struct denode **dehashtbl;
-static u_long dehash; /* size of hash table - 1 */
-#define DEHASH(dev, deno) (dehashtbl[((dev) + (deno)) & dehash])
+static u_long dehash; /* size of hash table - 1 */
+#define DEHASH(dev, dcl, doff) (dehashtbl[((dev) + (dcl) + (doff) / \
+ sizeof(struct direntry)) & dehash])
static struct simplelock dehash_slock;
union _qcvt {
@@ -96,12 +97,14 @@ static struct denode *
static void msdosfs_hashins __P((struct denode *dep));
static void msdosfs_hashrem __P((struct denode *dep));
-int msdosfs_init(vfsp)
+/*ARGSUSED*/
+int
+msdosfs_init(vfsp)
struct vfsconf *vfsp;
{
dehashtbl = hashinit(desiredvnodes/2, M_MSDOSFSMNT, &dehash);
simple_lock_init(&dehash_slock);
- return 0;
+ return (0);
}
static struct denode *
@@ -116,7 +119,7 @@ msdosfs_hashget(dev, dirclust, diroff)
loop:
simple_lock(&dehash_slock);
- for (dep = DEHASH(dev, dirclust + diroff); dep; dep = dep->de_next) {
+ for (dep = DEHASH(dev, dirclust, diroff); dep; dep = dep->de_next) {
if (dirclust == dep->de_dirclust
&& diroff == dep->de_diroffset
&& dev == dep->de_dev
@@ -140,7 +143,7 @@ msdosfs_hashins(dep)
struct denode **depp, *deq;
simple_lock(&dehash_slock);
- depp = &DEHASH(dep->de_dev, dep->de_dirclust + dep->de_diroffset);
+ depp = &DEHASH(dep->de_dev, dep->de_dirclust, dep->de_diroffset);
deq = *depp;
if (deq)
deq->de_prev = &dep->de_next;
@@ -178,48 +181,41 @@ msdosfs_hashrem(dep)
* diroffset is relative to the beginning of the root directory,
* otherwise it is cluster relative.
* diroffset - offset past begin of cluster of denode we want
- * direntptr - address of the direntry structure of interest. If direntptr is
- * NULL, the block is read if necessary.
* depp - returns the address of the gotten denode.
*/
int
-deget(pmp, dirclust, diroffset, direntptr, depp)
+deget(pmp, dirclust, diroffset, depp)
struct msdosfsmount *pmp; /* so we know the maj/min number */
u_long dirclust; /* cluster this dir entry came from */
u_long diroffset; /* index of entry within the cluster */
- struct direntry *direntptr;
struct denode **depp; /* returns the addr of the gotten denode */
{
int error;
dev_t dev = pmp->pm_dev;
struct mount *mntp = pmp->pm_mountp;
+ struct direntry *direntptr;
struct denode *ldep;
struct vnode *nvp;
struct buf *bp;
struct proc *p = curproc; /* XXX */
#ifdef MSDOSFS_DEBUG
- printf("deget(pmp %p, dirclust %ld, diroffset %x, direntptr %p, depp %p)\n",
- pmp, dirclust, diroffset, direntptr, depp);
+ printf("deget(pmp %p, dirclust %lu, diroffset %lx, depp %p)\n",
+ pmp, dirclust, diroffset, depp);
#endif
/*
- * If dir entry is given and refers to a directory, convert to
- * canonical form
+ * On FAT32 filesystems, root is a (more or less) normal
+ * directory
*/
- if (direntptr && (direntptr->deAttributes & ATTR_DIRECTORY)) {
- dirclust = getushort(direntptr->deStartCluster);
- if (dirclust == MSDOSFSROOT)
- diroffset = MSDOSFSROOT_OFS;
- else
- diroffset = 0;
- }
+ if (FAT32(pmp) && dirclust == MSDOSFSROOT)
+ dirclust = pmp->pm_rootdirblk;
/*
* See if the denode is in the denode cache. Use the location of
* the directory entry to compute the hash value. For subdir use
- * address of "." entry. for root dir use cluster MSDOSFSROOT,
- * offset MSDOSFSROOT_OFS
+ * address of "." entry. For root dir (if not FAT32) use cluster
+ * MSDOSFSROOT, offset MSDOSFSROOT_OFS
*
* NOTE: The check for de_refcnt > 0 below insures the denode being
* examined does not represent an unlinked but still open file.
@@ -230,7 +226,7 @@ deget(pmp, dirclust, diroffset, direntptr, depp)
ldep = msdosfs_hashget(dev, dirclust, diroffset);
if (ldep) {
*depp = ldep;
- return 0;
+ return (0);
}
/*
@@ -277,10 +273,15 @@ deget(pmp, dirclust, diroffset, direntptr, depp)
*/
msdosfs_hashins(ldep);
+ ldep->de_pmp = pmp;
+ ldep->de_devvp = pmp->pm_devvp;
+ ldep->de_refcnt = 1;
/*
* Copy the directory entry into the denode area of the vnode.
*/
- if (dirclust == MSDOSFSROOT && diroffset == MSDOSFSROOT_OFS) {
+ if ((dirclust == MSDOSFSROOT
+ || (FAT32(pmp) && dirclust == pmp->pm_rootdirblk))
+ && diroffset == MSDOSFSROOT_OFS) {
/*
* Directory entry for the root directory. There isn't one,
* so we manufacture one. We should probably rummage
@@ -288,39 +289,42 @@ deget(pmp, dirclust, diroffset, direntptr, depp)
* exists), and then use the time and date from that entry
* as the time and date for the root denode.
*/
+ nvp->v_flag |= VROOT; /* should be further down XXX */
+
ldep->de_Attributes = ATTR_DIRECTORY;
- ldep->de_StartCluster = MSDOSFSROOT;
- ldep->de_FileSize = pmp->pm_rootdirsize * pmp->pm_BytesPerSec;
+ if (FAT32(pmp))
+ ldep->de_StartCluster = pmp->pm_rootdirblk;
+ /* de_FileSize will be filled in further down */
+ else {
+ ldep->de_StartCluster = MSDOSFSROOT;
+ ldep->de_FileSize = pmp->pm_rootdirsize * pmp->pm_BytesPerSec;
+ }
/*
* fill in time and date so that dos2unixtime() doesn't
* spit up when called from msdosfs_getattr() with root
* denode
*/
- ldep->de_Time = 0x0000; /* 00:00:00 */
- ldep->de_Date = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT)
+ ldep->de_CHun = 0;
+ ldep->de_CTime = 0x0000; /* 00:00:00 */
+ ldep->de_CDate = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT)
| (1 << DD_DAY_SHIFT);
/* Jan 1, 1980 */
+ ldep->de_ADate = ldep->de_CDate;
+ ldep->de_MTime = ldep->de_CTime;
+ ldep->de_MDate = ldep->de_CDate;
/* leave the other fields as garbage */
} else {
- bp = NULL;
- if (!direntptr) {
- error = readep(pmp, dirclust, diroffset, &bp,
- &direntptr);
- if (error)
- return error;
- }
+ error = readep(pmp, dirclust, diroffset, &bp, &direntptr);
+ if (error)
+ return (error);
DE_INTERNALIZE(ldep, direntptr);
- if (bp)
- brelse(bp);
+ brelse(bp);
}
/*
* Fill in a few fields of the vnode and finish filling in the
* denode. Then return the address of the found denode.
*/
- ldep->de_pmp = pmp;
- ldep->de_devvp = pmp->pm_devvp;
- ldep->de_refcnt = 1;
if (ldep->de_Attributes & ATTR_DIRECTORY) {
/*
* Since DOS directory entries that describe directories
@@ -331,12 +335,10 @@ deget(pmp, dirclust, diroffset, direntptr, depp)
u_long size;
nvp->v_type = VDIR;
- if (ldep->de_StartCluster == MSDOSFSROOT)
- nvp->v_flag |= VROOT;
- else {
- error = pcbmap(ldep, 0xffff, 0, &size);
+ if (ldep->de_StartCluster != MSDOSFSROOT) {
+ error = pcbmap(ldep, 0xffff, 0, &size, 0);
if (error == E2BIG) {
- ldep->de_FileSize = size << pmp->pm_cnshift;
+ ldep->de_FileSize = de_cn2off(pmp, size);
error = 0;
} else
printf("deget(): pcbmap returned %d\n", error);
@@ -347,78 +349,40 @@ deget(pmp, dirclust, diroffset, direntptr, depp)
SETLOW(ldep->de_modrev, mono_time.tv_usec * 4294);
VREF(ldep->de_devvp);
*depp = ldep;
- return 0;
+ return (0);
}
int
-deupdat(dep, tp, waitfor)
+deupdat(dep, waitfor)
struct denode *dep;
- struct timespec *tp;
int waitfor;
{
int error;
struct buf *bp;
struct direntry *dirp;
- struct vnode *vp = DETOV(dep);
-
-#ifdef MSDOSFS_DEBUG
- printf("deupdat(): dep %p\n", dep);
-#endif
-
- /*
- * If the denode-modified and update-mtime bits are off,
- * or this denode is from a readonly filesystem,
- * or this denode is for a directory,
- * or the denode represents an open but unlinked file,
- * then don't do anything. DOS directory
- * entries that describe a directory do not ever get
- * updated. This is the way DOS treats them.
- */
- if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 ||
- vp->v_mount->mnt_flag & MNT_RDONLY ||
- dep->de_Attributes & ATTR_DIRECTORY ||
- dep->de_refcnt <= 0)
- return 0;
+ struct timespec ts;
- /*
- * Read in the cluster containing the directory entry we want to
- * update.
- */
+ if (DETOV(dep)->v_mount->mnt_flag & MNT_RDONLY)
+ return (0);
+ TIMEVAL_TO_TIMESPEC(&time, &ts);
+ DETIMES(dep, &ts, &ts, &ts);
+ if ((dep->de_flag & DE_MODIFIED) == 0)
+ return (0);
+ dep->de_flag &= ~DE_MODIFIED;
+ if (dep->de_Attributes & ATTR_DIRECTORY)
+ return (0);
+ if (dep->de_refcnt <= 0)
+ return (0);
error = readde(dep, &bp, &dirp);
if (error)
- return error;
-
- /*
- * If the mtime is to be updated, put the passed in time into the
- * directory entry.
- */
- if (dep->de_flag & DE_UPDATE) {
- dep->de_Attributes |= ATTR_ARCHIVE;
- unix2dostime(tp, &dep->de_Date, &dep->de_Time);
- }
-
- /*
- * The mtime is now up to date. The denode will be unmodifed soon.
- */
- dep->de_flag &= ~(DE_MODIFIED | DE_UPDATE);
-
- /*
- * Copy the directory entry out of the denode into the cluster it
- * came from.
- */
+ return (error);
DE_EXTERNALIZE(dirp, dep);
-
- /*
- * Write the cluster back to disk. If they asked for us to wait
- * for the write to complete, then use bwrite() otherwise use
- * bdwrite().
- */
- error = 0; /* note that error is 0 from above, but ... */
if (waitfor)
- error = bwrite(bp);
- else
+ return (bwrite(bp));
+ else {
bdwrite(bp);
- return error;
+ return (0);
+ }
}
/*
@@ -445,7 +409,7 @@ detrunc(dep, length, flags, cred, p)
struct timespec ts;
#ifdef MSDOSFS_DEBUG
- printf("detrunc(): file %s, length %d, flags %d\n", dep->de_Name, length, flags);
+ printf("detrunc(): file %s, length %lu, flags %x\n", dep->de_Name, length, flags);
#endif
/*
@@ -456,11 +420,10 @@ detrunc(dep, length, flags, cred, p)
* recognize the root directory at this point in a file or
* directory's life.
*/
- if (DETOV(dep)->v_flag & VROOT) {
- printf(
- "detrunc(): can't truncate root directory, clust %ld, offset %ld\n",
+ if ((DETOV(dep)->v_flag & VROOT) && !FAT32(pmp)) {
+ printf("detrunc(): can't truncate root directory, clust %ld, offset %ld\n",
dep->de_dirclust, dep->de_diroffset);
- return EINVAL;
+ return (EINVAL);
}
@@ -483,16 +446,17 @@ detrunc(dep, length, flags, cred, p)
dep->de_StartCluster = 0;
eofentry = ~0;
} else {
- error = pcbmap(dep, de_clcount(pmp, length) - 1, 0, &eofentry);
+ error = pcbmap(dep, de_clcount(pmp, length) - 1, 0,
+ &eofentry, 0);
if (error) {
#ifdef MSDOSFS_DEBUG
printf("detrunc(): pcbmap fails %d\n", error);
#endif
- return error;
+ return (error);
}
}
- fc_purge(dep, (length + pmp->pm_crbomask) >> pmp->pm_cnshift);
+ fc_purge(dep, de_clcount(pmp, length));
/*
* If the new length is not a multiple of the cluster size then we
@@ -500,10 +464,6 @@ detrunc(dep, length, flags, cred, p)
* becomes part of the file again because of a seek.
*/
if ((boff = length & pmp->pm_crbomask) != 0) {
- /*
- * should read from file vnode or filesystem vnode
- * depending on if file or dir
- */
if (isadir) {
bn = cntobn(pmp, eofentry);
error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
@@ -521,10 +481,11 @@ detrunc(dep, length, flags, cred, p)
NOCRED, &bp);
}
if (error) {
+ brelse(bp);
#ifdef MSDOSFS_DEBUG
printf("detrunc(): bread fails %d\n", error);
#endif
- return error;
+ return (error);
}
/*
* is this the right place for it?
@@ -541,14 +502,14 @@ detrunc(dep, length, flags, cred, p)
* we free the trailing clusters.
*/
dep->de_FileSize = length;
- dep->de_flag |= DE_UPDATE;
+ if (!isadir)
+ dep->de_flag |= DE_UPDATE|DE_MODIFIED;
vflags = (length > 0 ? V_SAVE : 0) | V_SAVEMETA;
vinvalbuf(DETOV(dep), vflags, cred, p, 0, 0);
vnode_pager_setsize(DETOV(dep), length);
- TIMEVAL_TO_TIMESPEC(&time, &ts);
- allerror = deupdat(dep, &ts, 1);
+ allerror = deupdat(dep, 1);
#ifdef MSDOSFS_DEBUG
- printf("detrunc(): allerror %d, eofentry %d\n",
+ printf("detrunc(): allerror %d, eofentry %lu\n",
allerror, eofentry);
#endif
@@ -563,9 +524,9 @@ detrunc(dep, length, flags, cred, p)
#ifdef MSDOSFS_DEBUG
printf("detrunc(): fatentry errors %d\n", error);
#endif
- return error;
+ return (error);
}
- fc_setcache(dep, FC_LASTFC, (length - 1) >> pmp->pm_cnshift,
+ fc_setcache(dep, FC_LASTFC, de_cluster(pmp, length - 1),
eofentry);
}
@@ -573,10 +534,10 @@ detrunc(dep, length, flags, cred, p)
* Now free the clusters removed from the file because of the
* truncation.
*/
- if (chaintofree != 0 && !MSDOSFSEOF(chaintofree))
+ if (chaintofree != 0 && !MSDOSFSEOF(pmp, chaintofree))
freeclusterchain(pmp, chaintofree);
- return allerror;
+ return (allerror);
}
/*
@@ -585,7 +546,7 @@ detrunc(dep, length, flags, cred, p)
int
deextend(dep, length, cred)
struct denode *dep;
- off_t length;
+ u_long length;
struct ucred *cred;
{
struct msdosfsmount *pmp = dep->de_pmp;
@@ -596,18 +557,14 @@ deextend(dep, length, cred)
/*
* The root of a DOS filesystem cannot be extended.
*/
- if (DETOV(dep)->v_flag & VROOT)
- return EINVAL;
+ if ((DETOV(dep)->v_flag & VROOT) && !FAT32(pmp))
+ return (EINVAL);
/*
- * Directories can only be extended by the superuser.
- * Is this really important?
+ * Directories cannot be extended.
*/
- if (dep->de_Attributes & ATTR_DIRECTORY) {
- error = suser(cred, NULL);
- if (error)
- return error;
- }
+ if (dep->de_Attributes & ATTR_DIRECTORY)
+ return (EISDIR);
if (length <= dep->de_FileSize)
panic("deextend: file too large");
@@ -618,26 +575,25 @@ deextend(dep, length, cred)
count = de_clcount(pmp, length) - de_clcount(pmp, dep->de_FileSize);
if (count > 0) {
if (count > pmp->pm_freeclustercount)
- return ENOSPC;
+ return (ENOSPC);
error = extendfile(dep, count, NULL, NULL, DE_CLEAR);
if (error) {
/* truncate the added clusters away again */
(void) detrunc(dep, dep->de_FileSize, 0, cred, NULL);
- return error;
+ return (error);
}
}
-
- dep->de_flag |= DE_UPDATE;
dep->de_FileSize = length;
- TIMEVAL_TO_TIMESPEC(&time, &ts);
- return deupdat(dep, &ts, 1);
+ dep->de_flag |= DE_UPDATE|DE_MODIFIED;
+ return (deupdat(dep, 1));
}
/*
* Move a denode to its correct hash queue after the file it represents has
* been moved to a new directory.
*/
-int reinsert(dep)
+void
+reinsert(dep)
struct denode *dep;
{
/*
@@ -648,11 +604,10 @@ int reinsert(dep)
* so we must remove it from the cache and re-enter it with the
* hash based on the new location of the directory entry.
*/
- if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
- msdosfs_hashrem(dep);
- msdosfs_hashins(dep);
- }
- return 0;
+ if (dep->de_Attributes & ATTR_DIRECTORY)
+ return;
+ msdosfs_hashrem(dep);
+ msdosfs_hashins(dep);
}
int
@@ -671,27 +626,25 @@ msdosfs_reclaim(ap)
if (prtactive && vp->v_usecount != 0)
vprint("msdosfs_reclaim(): pushing active", vp);
-
/*
- * Remove the denode from the denode hash chain we are in.
+ * Remove the denode from its hash chain.
*/
msdosfs_hashrem(dep);
-
- cache_purge(vp);
/*
- * Indicate that one less file on the filesystem is open.
+ * Purge old data structures associated with the denode.
*/
+ cache_purge(vp);
if (dep->de_devvp) {
vrele(dep->de_devvp);
dep->de_devvp = 0;
}
-
+#if 0 /* XXX */
dep->de_flag = 0;
-
+#endif
FREE(dep, M_MSDOSFSNODE);
vp->v_data = NULL;
- return 0;
+ return (0);
}
int
@@ -715,7 +668,7 @@ msdosfs_inactive(ap)
vprint("msdosfs_inactive(): pushing active", vp);
/*
- * Ignore inodes related to stale file handles.
+ * Ignore denodes related to stale file handles.
*/
if (dep->de_Name[0] == SLOT_DELETED)
goto out;
@@ -734,17 +687,13 @@ msdosfs_inactive(ap)
dep->de_flag |= DE_UPDATE;
dep->de_Name[0] = SLOT_DELETED;
}
- if (dep->de_flag & (DE_MODIFIED | DE_UPDATE)) {
- TIMEVAL_TO_TIMESPEC(&time, &ts);
- deupdat(dep, &ts, 0);
- }
+ deupdat(dep, 0);
+
out:
VOP_UNLOCK(vp, 0, p);
- dep->de_flag = 0;
-
/*
- * If we are done with the denode, then reclaim it so that it can
- * be reused now.
+ * If we are done with the denode, reclaim it
+ * so that it can be reused immediately.
*/
#ifdef MSDOSFS_DEBUG
printf("msdosfs_inactive(): v_usecount %d, de_Name[0] %x\n", vp->v_usecount,
@@ -752,5 +701,5 @@ out:
#endif
if (dep->de_Name[0] == SLOT_DELETED)
vrecycle(vp, (struct simplelock *)0, p);
- return error;
+ return (error);
}
OpenPOWER on IntegriCloud