summaryrefslogtreecommitdiffstats
path: root/sys/gnu/fs
diff options
context:
space:
mode:
authorbde <bde@FreeBSD.org>2000-01-05 19:31:26 +0000
committerbde <bde@FreeBSD.org>2000-01-05 19:31:26 +0000
commit1d4db591699eec37b0408973d227ac7a5b8b1727 (patch)
treef5b7b6320a699f99fca923b4dc47cf881fbe9822 /sys/gnu/fs
parent90aaf7aa8318de04f7dbb5e6f4b42b20a26517cd (diff)
downloadFreeBSD-src-1d4db591699eec37b0408973d227ac7a5b8b1727.zip
FreeBSD-src-1d4db591699eec37b0408973d227ac7a5b8b1727.tar.gz
Support filesystems with the not-so-new "filetype" feature. This
feature gives the d_type field for struct dirent. We used to panic in ext2_readdir() for filesystems with this feature.
Diffstat (limited to 'sys/gnu/fs')
-rw-r--r--sys/gnu/fs/ext2fs/ext2_lookup.c161
1 files changed, 95 insertions, 66 deletions
diff --git a/sys/gnu/fs/ext2fs/ext2_lookup.c b/sys/gnu/fs/ext2fs/ext2_lookup.c
index 9df8fd6..79eb7cd 100644
--- a/sys/gnu/fs/ext2fs/ext2_lookup.c
+++ b/sys/gnu/fs/ext2fs/ext2_lookup.c
@@ -3,6 +3,8 @@
*
* Aug 1995, Godmar Back (gback@cs.utah.edu)
* University of Utah, Department of Computer Science
+ *
+ * $FreeBSD$
*/
/*
* Copyright (c) 1989, 1993
@@ -44,6 +46,8 @@
* @(#)ufs_lookup.c 8.6 (Berkeley) 4/1/94
*/
+#include <stddef.h>
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/namei.h>
@@ -72,54 +76,44 @@
extern int dirchk;
-static void ext2_dirconv2ffs __P((struct ext2_dir_entry *e2dir,
- struct dirent *ffsdir));
-static int ext2_dirbadentry __P((struct vnode *dp,
- struct ext2_dir_entry *de,
- int entryoffsetinblock));
-
-/*
- * the problem that is tackled below is the fact that FFS
- * includes the terminating zero on disk while EXT2FS doesn't
- * this implies that we need to introduce some padding.
- * For instance, a filename "sbin" has normally a reclen 12
- * in EXT2, but 16 in FFS.
- * This reminds me of that Pepsi commercial: 'Kid saved a lousy nine cents...'
- * If it wasn't for that, the complete ufs code for directories would
- * have worked w/o changes (except for the difference in DIRBLKSIZ)
- */
-static void
-ext2_dirconv2ffs( e2dir, ffsdir)
- struct ext2_dir_entry *e2dir;
- struct dirent *ffsdir;
-{
- struct dirent de;
-
- bzero(&de, sizeof(struct dirent));
- de.d_fileno = e2dir->inode;
- de.d_namlen = e2dir->name_len;
+static u_char ext2_ft_to_dt[] = {
+ DT_UNKNOWN, /* EXT2_FT_UNKNOWN */
+ DT_REG, /* EXT2_FT_REG_FILE */
+ DT_DIR, /* EXT2_FT_DIR */
+ DT_CHR, /* EXT2_FT_CHRDEV */
+ DT_BLK, /* EXT2_FT_BLKDEV */
+ DT_FIFO, /* EXT2_FT_FIFO */
+ DT_SOCK, /* EXT2_FT_SOCK */
+ DT_LNK, /* EXT2_FT_SYMLINK */
+};
+#define FTTODT(ft) \
+ ((ft) > sizeof(ext2_ft_to_dt) / sizeof(ext2_ft_to_dt[0]) ? \
+ DT_UNKNOWN : ext2_ft_to_dt[(ft)])
-#ifndef NO_HARDWIRED_CONSTANTS
- if(e2dir->name_len + 8 == e2dir->rec_len)
- de.d_reclen += 4;
+static u_char dt_to_ext2_ft[] = {
+ EXT2_FT_UNKNOWN, /* DT_UNKNOWN */
+ EXT2_FT_FIFO, /* DT_FIFO */
+ EXT2_FT_CHRDEV, /* DT_CHR */
+ EXT2_FT_UNKNOWN, /* unused */
+ EXT2_FT_DIR, /* DT_DIR */
+ EXT2_FT_UNKNOWN, /* unused */
+ EXT2_FT_BLKDEV, /* DT_BLK */
+ EXT2_FT_UNKNOWN, /* unused */
+ EXT2_FT_REG_FILE, /* DT_REG */
+ EXT2_FT_UNKNOWN, /* unused */
+ EXT2_FT_SYMLINK, /* DT_LNK */
+ EXT2_FT_UNKNOWN, /* unused */
+ EXT2_FT_SOCK, /* DT_SOCK */
+ EXT2_FT_UNKNOWN, /* unused */
+ EXT2_FT_UNKNOWN, /* DT_WHT */
+};
+#define DTTOFT(dt) \
+ ((dt) > sizeof(dt_to_ext2_ft) / sizeof(dt_to_ext2_ft[0]) ? \
+ EXT2_FT_UNKNOWN : dt_to_ext2_ft[(dt)])
- de.d_type = DT_UNKNOWN; /* don't know more here */
- strncpy(de.d_name, e2dir->name, e2dir->name_len);
- de.d_name[de.d_namlen] = '\0';
- /* Godmar thinks: since e2dir->rec_len can be big and means
- nothing anyway, we compute our own reclen according to what
- we think is right
- */
- de.d_reclen = (de.d_namlen+8+1+3) & ~3;
- bcopy(&de, ffsdir, de.d_reclen);
-#endif
-
-#if 0
- printf("dirconv: ino %d rec old %d rec new %d nam %d name %s\n",
- ffsdir->d_fileno, e2dir->rec_len, ffsdir->d_reclen,
- ffsdir->d_namlen, ffsdir->d_name);
-#endif
-}
+static int ext2_dirbadentry __P((struct vnode *dp,
+ struct ext2_dir_entry_2 *de,
+ int entryoffsetinblock));
/*
* Vnode op for reading directories.
@@ -150,7 +144,7 @@ ext2_readdir(ap)
register struct uio *uio = ap->a_uio;
int count, error;
- struct ext2_dir_entry *edp, *dp;
+ struct ext2_dir_entry_2 *edp, *dp;
int ncookies;
struct dirent dstdp;
struct uio auio;
@@ -178,15 +172,40 @@ printf("ext2_readdir called uio->uio_offset %d uio->uio_resid %d count %d \n",
error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
if (error == 0) {
readcnt = count - auio.uio_resid;
- edp = (struct ext2_dir_entry *)&dirbuf[readcnt];
+ edp = (struct ext2_dir_entry_2 *)&dirbuf[readcnt];
ncookies = 0;
- for (dp = (struct ext2_dir_entry *)dirbuf;
- !error && uio->uio_resid > 0 && dp < edp; ) {
- ext2_dirconv2ffs(dp, &dstdp);
+ bzero(&dstdp, offsetof(struct dirent, d_name));
+ for (dp = (struct ext2_dir_entry_2 *)dirbuf;
+ !error && uio->uio_resid > 0 && dp < edp; ) {
+ /*-
+ * "New" ext2fs directory entries differ in 3 ways
+ * from ufs on-disk ones:
+ * - the name is not necessarily NUL-terminated.
+ * - the file type field always exists and always
+ * follows the name length field.
+ * - the file type is encoded in a different way.
+ *
+ * "Old" ext2fs directory entries need no special
+ * conversions, since they binary compatible with
+ * "new" entries having a file type of 0 (i.e.,
+ * EXT2_FT_UNKNOWN). Splitting the old name length
+ * field didn't make a mess like it did in ufs,
+ * because ext2fs uses a machine-dependent disk
+ * layout.
+ */
+ dstdp.d_fileno = dp->inode;
+ dstdp.d_type = FTTODT(dp->file_type);
+ dstdp.d_namlen = dp->name_len;
+ dstdp.d_reclen = GENERIC_DIRSIZ(&dstdp);
+ bcopy(dp->name, dstdp.d_name, dstdp.d_namlen);
+ bzero(dstdp.d_name + dstdp.d_namlen,
+ dstdp.d_reclen - offsetof(struct dirent, d_name) -
+ dstdp.d_namlen);
+
if (dp->rec_len > 0) {
if(dstdp.d_reclen <= uio->uio_resid) {
/* advance dp */
- dp = (struct ext2_dir_entry *)
+ dp = (struct ext2_dir_entry_2 *)
((char *)dp + dp->rec_len);
error =
uiomove((caddr_t)&dstdp,
@@ -213,9 +232,9 @@ printf("ext2_readdir called uio->uio_offset %d uio->uio_resid %d count %d \n",
MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
M_WAITOK);
off = startoffset;
- for (dp = (struct ext2_dir_entry *)dirbuf, cookiep = cookies;
+ for (dp = (struct ext2_dir_entry_2 *)dirbuf, cookiep = cookies;
dp < edp;
- dp = (struct ext2_dir_entry *)((caddr_t) dp + dp->rec_len)) {
+ dp = (struct ext2_dir_entry_2 *)((caddr_t) dp + dp->rec_len)) {
off += dp->rec_len;
*cookiep++ = (u_long) off;
}
@@ -270,7 +289,7 @@ ext2_lookup(ap)
register struct vnode *vdp; /* vnode for directory being searched */
register struct inode *dp; /* inode for directory being searched */
struct buf *bp; /* a buffer of directory entries */
- register struct ext2_dir_entry *ep; /* the current directory entry */
+ register struct ext2_dir_entry_2 *ep; /* the current directory entry */
int entryoffsetinblock; /* offset of ep in bp's buffer */
enum {NONE, COMPACT, FOUND} slotstatus;
doff_t slotoffset; /* offset of area with free space */
@@ -383,7 +402,7 @@ searchloop:
* directory. Complete checks can be run by patching
* "dirchk" to be true.
*/
- ep = (struct ext2_dir_entry *)
+ ep = (struct ext2_dir_entry_2 *)
((char *)bp->b_data + entryoffsetinblock);
if (ep->rec_len == 0 ||
(dirchk && ext2_dirbadentry(vdp, ep, entryoffsetinblock))) {
@@ -682,7 +701,7 @@ found:
static int
ext2_dirbadentry(dp, de, entryoffsetinblock)
struct vnode *dp;
- register struct ext2_dir_entry *de;
+ register struct ext2_dir_entry_2 *de;
int entryoffsetinblock;
{
int DIRBLKSIZ = VTOI(dp)->i_e2fs->s_blocksize;
@@ -725,10 +744,10 @@ ext2_direnter(ip, dvp, cnp)
struct vnode *dvp;
register struct componentname *cnp;
{
- register struct ext2_dir_entry *ep, *nep;
+ register struct ext2_dir_entry_2 *ep, *nep;
register struct inode *dp;
struct buf *bp;
- struct ext2_dir_entry newdir;
+ struct ext2_dir_entry_2 newdir;
struct iovec aiov;
struct uio auio;
u_int dsize;
@@ -744,6 +763,11 @@ ext2_direnter(ip, dvp, cnp)
dp = VTOI(dvp);
newdir.inode = ip->i_number;
newdir.name_len = cnp->cn_namelen;
+ if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ newdir.file_type = DTTOFT(IFTODT(ip->i_mode));
+ else
+ newdir.file_type = EXT2_FT_UNKNOWN;
bcopy(cnp->cn_nameptr, newdir.name, (unsigned)cnp->cn_namelen + 1);
newentrysize = EXT2_DIR_REC_LEN(newdir.name_len);
if (dp->i_count == 0) {
@@ -807,15 +831,15 @@ ext2_direnter(ip, dvp, cnp)
* dp->i_offset + dp->i_count would yield the
* space.
*/
- ep = (struct ext2_dir_entry *)dirbuf;
+ ep = (struct ext2_dir_entry_2 *)dirbuf;
dsize = EXT2_DIR_REC_LEN(ep->name_len);
spacefree = ep->rec_len - dsize;
for (loc = ep->rec_len; loc < dp->i_count; ) {
- nep = (struct ext2_dir_entry *)(dirbuf + loc);
+ nep = (struct ext2_dir_entry_2 *)(dirbuf + loc);
if (ep->inode) {
/* trim the existing slot */
ep->rec_len = dsize;
- ep = (struct ext2_dir_entry *)((char *)ep + dsize);
+ ep = (struct ext2_dir_entry_2 *)((char *)ep + dsize);
} else {
/* overwrite; nothing there; header is ours */
spacefree += dsize;
@@ -838,7 +862,7 @@ ext2_direnter(ip, dvp, cnp)
panic("ext2_direnter: compact2");
newdir.rec_len = spacefree;
ep->rec_len = dsize;
- ep = (struct ext2_dir_entry *)((char *)ep + dsize);
+ ep = (struct ext2_dir_entry_2 *)((char *)ep + dsize);
}
bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize);
error = VOP_BWRITE(bp->b_vp, bp);
@@ -867,7 +891,7 @@ ext2_dirremove(dvp, cnp)
struct componentname *cnp;
{
register struct inode *dp;
- struct ext2_dir_entry *ep;
+ struct ext2_dir_entry_2 *ep;
struct buf *bp;
int error;
@@ -907,13 +931,18 @@ ext2_dirrewrite(dp, ip, cnp)
struct componentname *cnp;
{
struct buf *bp;
- struct ext2_dir_entry *ep;
+ struct ext2_dir_entry_2 *ep;
struct vnode *vdp = ITOV(dp);
int error;
if ((error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0)
return (error);
ep->inode = ip->i_number;
+ if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ ep->file_type = DTTOFT(IFTODT(ip->i_mode));
+ else
+ ep->file_type = EXT2_FT_UNKNOWN;
error = VOP_BWRITE(bp->b_vp, bp);
dp->i_flag |= IN_CHANGE | IN_UPDATE;
return (error);
@@ -936,7 +965,7 @@ ext2_dirempty(ip, parentino, cred)
{
register off_t off;
struct dirtemplate dbuf;
- register struct ext2_dir_entry *dp = (struct ext2_dir_entry *)&dbuf;
+ register struct ext2_dir_entry_2 *dp = (struct ext2_dir_entry_2 *)&dbuf;
int error, count, namlen;
#define MINDIRSIZ (sizeof (struct dirtemplate) / 2)
OpenPOWER on IntegriCloud