[PATCH] Return file types from readdir()

From: Jamie Lokier (lfs@tantalophile.demon.co.uk)
Date: Sun Mar 05 2000 - 20:57:01 EST


With the addition of type info to ext2 a few months ago, I decided to
let the kernel return d_type info and see if it makes "find" faster.
It does: about twice as fast, with my own version of find that's also
optimised in other ways.

The Glibc struct dirent, derived from BSD, looks like this:

        ino_t d_ino;
        off_t d_off;
        unsigned short d_reclen;
        unsigned char d_type; <-- The interesting part
        char d_name [256];

The d_type field is used by some BSD programs, mainly to tell when an
entry is not a directory so that "find" style searches don't have to
call stat(). Therefore fewer inodes are read from disk.

Glibc currently always stores DT_UNKNOWN in d_type.

The obvious change is to the readdir callback the kernel. While
updating every filesystem's readdir function, I was surprised to find
that most filesystems can generate useful d_type info.

The attached patch for 2.3.49:

     - adds a "type" parameter to readdir() callbacks.
     - updates all filesystems. Most of the patch is this.
     - makes sys_getdents() return the info in a way which
       Glibc and applications can use, while being binary
       backward compatible. (I don't like new syscalls).

You might prefer a new syscall or open() flag to the method I use for
returning the info. If that's the case, ask and I'll write. Search
for "By storing a 0" to see how it's returned at the moment.

You can see the information using my treescan program like this:
`treescan -silent -d_type'. It's found at
  http://www.tantalophile.demon.co.uk/treescan/treescan-0.6.tar.gz
  http://www.tantalophile.demon.co.uk/treescan/treescan-0.6-1.i686.rpm

Here's a summary of the level of support in filesystem. I've tested
the ones I can test with various file types. They've all been compiled.

    autofs [FULL SUPPORT, TESTED]
    autofs4 [FULL SUPPORT, TESTED]
    cramfs [FULL SUPPORT, TESTED]
    devpts [FULL SUPPORT, TESTED]
    devfs [FULL SUPPORT, TESTED]
    ext2 [FULL SUPPORT, TESTED]
    isofs/norock [FULL SUPPORT, TESTED]
    isofs/rock [FULL SUPPORT, TESTED]
    msdos [FULL SUPPORT, TESTED]
    procfs [FULL SUPPORT, TESTED]
    vfat [FULL SUPPORT, TESTED]
    umsdos [FULL SUPPORT, TESTED]
    usbdevfs [FULL SUPPORT, TESTED]

    adfs [FULL SUPPORT, compiled]
    coda [FULL SUPPORT, compiled]
    ncpfs [FULL SUPPORT, compiled]
    qnx4 [FULL SUPPORT, compiled]
    romfs [FULL SUPPORT, compiled]
    ufs [FULL SUPPORT, compiled]

    hpfs [DIR and REG only, compiled] # More support may be possible.
    udf [DIR only, compiled] # More support may be possible.
    hfs [some, compiled] # More support may be possible.

    affs [return DT_UNKNOWN, compiled] # More support may be possible.
    bfs [return DT_UNKNOWN, compiled] # No support possible.
    efs [return DT_UNKNOWN, compiled] # No support possible.
    minix [return DT_UNKNOWN, compiled] # No support possible.
    nfs [return DT_UNKNOWN, compiled] # No support possible.
    nfsd [return DT_UNKNOWN, compiled] # filldir() extra argument.
    ntfs [return DT_UNKNOWN, compiled] # Code too scary to add support.
    openpromfs [return DT_UNKNOWN, compiled] # More support may be possible.
    smbfs [return DT_UNKNOWN, compiled] # More support may be possible.
    sysv [return DT_UNKNOWN, compiled] # No support possible.

IMO the patch is ready for inclusion in the kernel, if you are happy
with the method for returning the data to user space.

Enjoy,
-- Jamie

diff -u linux-2.3/arch/alpha/kernel/osf_sys.c.d_type linux-2.3/arch/alpha/kernel/osf_sys.c
--- linux-2.3/arch/alpha/kernel/osf_sys.c.d_type Fri Feb 11 23:55:37 2000
+++ linux-2.3/arch/alpha/kernel/osf_sys.c Sun Mar 5 23:13:57 2000
@@ -105,7 +105,7 @@
         int error;
 };
 
-static int osf_filldir(void *__buf, const char *name, int namlen, off_t offset, ino_t ino)
+static int osf_filldir(void *__buf, unsigned char type, const char *name, int namlen, off_t offset, ino_t ino)
 {
         struct osf_dirent *dirent;
         struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf;
diff -u linux-2.3/arch/mips/kernel/sysirix.c.d_type linux-2.3/arch/mips/kernel/sysirix.c
--- linux-2.3/arch/mips/kernel/sysirix.c.d_type Sun Mar 5 18:30:45 2000
+++ linux-2.3/arch/mips/kernel/sysirix.c Sun Mar 5 23:17:32 2000
@@ -1991,8 +1991,8 @@
 #define NAME_OFFSET32(de) ((int) ((de)->d_name - (char *) (de)))
 #define ROUND_UP32(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
 
-static int irix_filldir32(void *__buf, const char *name, int namlen,
- off_t offset, ino_t ino)
+static int irix_filldir32(void *__buf, unsigned char type, const char *name,
+ int namlen, off_t offset, ino_t ino)
 {
         struct irix_dirent32 *dirent;
         struct irix_dirent32_callback *buf =
@@ -2104,8 +2104,8 @@
 #define NAME_OFFSET64(de) ((int) ((de)->d_name - (char *) (de)))
 #define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
 
-static int irix_filldir64(void * __buf, const char * name, int namlen,
- off_t offset, ino_t ino)
+static int irix_filldir64(void * __buf, unsigned char type, const char * name,
+ int namlen, off_t offset, ino_t ino)
 {
         struct irix_dirent64 *dirent;
         struct irix_dirent64_callback * buf =
diff -u linux-2.3/arch/sparc/kernel/sys_sunos.c.d_type linux-2.3/arch/sparc/kernel/sys_sunos.c
--- linux-2.3/arch/sparc/kernel/sys_sunos.c.d_type Sun Mar 5 18:30:06 2000
+++ linux-2.3/arch/sparc/kernel/sys_sunos.c Sun Mar 5 23:15:40 2000
@@ -403,8 +403,8 @@
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
 #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
 
-static int sunos_filldir(void * __buf, const char * name, int namlen,
- off_t offset, ino_t ino)
+static int sunos_filldir(void * __buf, unsigned char type, const char * name,
+ int namlen, off_t offset, ino_t ino)
 {
         struct sunos_dirent * dirent;
         struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf;
@@ -494,7 +494,8 @@
     int error;
 };
 
-static int sunos_filldirentry(void * __buf, const char * name, int namlen,
+static int sunos_filldirentry(void * __buf, unsigned char type,
+ const char * name, int namlen,
                               off_t offset, ino_t ino)
 {
         struct sunos_direntry * dirent;
diff -u linux-2.3/arch/sparc64/kernel/sys_sparc32.c.d_type linux-2.3/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.3/arch/sparc64/kernel/sys_sparc32.c.d_type Sun Mar 5 21:01:52 2000
+++ linux-2.3/arch/sparc64/kernel/sys_sparc32.c Sun Mar 5 23:18:58 2000
@@ -1235,8 +1235,8 @@
         int count;
 };
 
-static int fillonedir(void * __buf, const char * name, int namlen,
- off_t offset, ino_t ino)
+static int fillonedir(void * __buf, unsigned char type, const char * name,
+ int namlen, off_t offset, ino_t ino)
 {
         struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf;
         struct old_linux_dirent32 * dirent;
@@ -1301,7 +1301,7 @@
         int error;
 };
 
-static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
+static int filldir(void * __buf, unsigned char type, const char * name, int namlen, off_t offset, ino_t ino)
 {
         struct linux_dirent32 * dirent;
         struct getdents_callback32 * buf = (struct getdents_callback32 *) __buf;
diff -u linux-2.3/arch/sparc64/kernel/sys_sunos32.c.d_type linux-2.3/arch/sparc64/kernel/sys_sunos32.c
--- linux-2.3/arch/sparc64/kernel/sys_sunos32.c.d_type Sun Mar 5 18:30:07 2000
+++ linux-2.3/arch/sparc64/kernel/sys_sunos32.c Sun Mar 5 23:19:30 2000
@@ -359,8 +359,8 @@
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
 #define ROUND_UP(x) (((x)+sizeof(s32)-1) & ~(sizeof(s32)-1))
 
-static int sunos_filldir(void * __buf, const char * name, int namlen,
- off_t offset, ino_t ino)
+static int sunos_filldir(void * __buf, unsigned char type, const char * name,
+ int namlen, off_t offset, ino_t ino)
 {
         struct sunos_dirent * dirent;
         struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf;
@@ -451,7 +451,8 @@
     int error;
 };
 
-static int sunos_filldirentry(void * __buf, const char * name, int namlen,
+static int sunos_filldirentry(void * __buf, unsigned char type,
+ const char * name, int namlen,
                               off_t offset, ino_t ino)
 {
         struct sunos_direntry * dirent;
diff -u linux-2.3/drivers/usb/inode.c.d_type linux-2.3/drivers/usb/inode.c
--- linux-2.3/drivers/usb/inode.c.d_type Sun Mar 5 21:01:57 2000
+++ linux-2.3/drivers/usb/inode.c Sun Mar 5 23:04:28 2000
@@ -24,6 +24,7 @@
  *
  * History:
  * 0.1 04.01.2000 Created
+ * 05.03.2000 Filldir requires DT_REG/DT_DIR
  */
 
 /*****************************************************************************/
@@ -31,6 +32,7 @@
 #define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/fs.h>
+#include <linux/dirent.h>
 #include <linux/sched.h>
 #include <linux/smp_lock.h>
 #include <linux/locks.h>
@@ -292,14 +294,14 @@
         i = filp->f_pos;
         switch (i) {
         case 0:
- if (filldir(dirent, ".", 1, i, IROOT) < 0)
+ if (filldir(dirent, DT_DIR, ".", 1, i, IROOT) < 0)
                         return 0;
                 filp->f_pos++;
                 i++;
                 /* fall through */
 
         case 1:
- if (filldir(dirent, "..", 2, i, IROOT) < 0)
+ if (filldir(dirent, DT_DIR, "..", 2, i, IROOT) < 0)
                         return 0;
                 filp->f_pos++;
                 i++;
@@ -309,7 +311,7 @@
                 
                 while (i >= 2 && i < 2+NRSPECIAL) {
                         spec = &special[filp->f_pos-2];
- if (filldir(dirent, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT)) < 0)
+ if (filldir(dirent, DT_REG, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT)) < 0)
                                 return 0;
                         filp->f_pos++;
                         i++;
@@ -325,7 +327,7 @@
                         }
                         bus = list_entry(list, struct usb_bus, bus_list);
                         sprintf(numbuf, "%03d", bus->busnum);
- if (filldir(dirent, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8)) < 0)
+ if (filldir(dirent, DT_DIR, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8)) < 0)
                                 break;
                         filp->f_pos++;
                 }
@@ -345,7 +347,7 @@
         if (pos > 0)
                 pos--;
         else {
- if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff)) < 0)
+ if (filldir(dirent, DT_REG, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff)) < 0)
                         return -1;
                 filp->f_pos++;
         }
@@ -370,13 +372,13 @@
                 return -EINVAL;
         switch ((unsigned int)filp->f_pos) {
         case 0:
- if (filldir(dirent, ".", 1, filp->f_pos, ino) < 0)
+ if (filldir(dirent, DT_DIR, ".", 1, filp->f_pos, ino) < 0)
                         return 0;
                 filp->f_pos++;
                 /* fall through */
 
         case 1:
- if (filldir(dirent, "..", 2, filp->f_pos, IROOT) < 0)
+ if (filldir(dirent, DT_DIR, "..", 2, filp->f_pos, IROOT) < 0)
                         return 0;
                 filp->f_pos++;
                 /* fall through */
diff -u linux-2.3/fs/adfs/dir.c.d_type linux-2.3/fs/adfs/dir.c
--- linux-2.3/fs/adfs/dir.c.d_type Sun Mar 5 20:59:01 2000
+++ linux-2.3/fs/adfs/dir.c Sun Mar 5 21:04:26 2000
@@ -11,6 +11,7 @@
 #include <linux/adfs_fs.h>
 #include <linux/sched.h>
 #include <linux/stat.h>
+#include <linux/dirent.h>
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
 #include <linux/spinlock.h>
@@ -41,12 +42,12 @@
 
         switch (filp->f_pos) {
         case 0:
- if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0)
+ if (filldir(dirent, DT_DIR, ".", 1, 0, inode->i_ino) < 0)
                         goto free_out;
                 filp->f_pos += 1;
 
         case 1:
- if (filldir(dirent, "..", 2, 1, dir.parent_id) < 0)
+ if (filldir(dirent, DT_DIR, "..", 2, 1, dir.parent_id) < 0)
                         goto free_out;
                 filp->f_pos += 1;
 
@@ -60,7 +61,12 @@
         if (ret)
                 goto unlock_out;
         while (ops->getnext(&dir, &obj) == 0) {
- if (filldir(dirent, obj.name, obj.name_len,
+ unsigned char type = DT_REG;
+ if (obj.attr & ADFS_NDA_DIRECTORY)
+ type = DT_DIR;
+ else if ((obj.loadaddr & 0xffffff00) == 0xffffc000)
+ type = DT_LNK; /* LinkFS */
+ if (filldir(dirent, type, obj.name, obj.name_len,
                             filp->f_pos, obj.file_id) < 0)
                         goto unlock_out;
                 filp->f_pos += 1;
diff -u linux-2.3/fs/affs/dir.c.d_type linux-2.3/fs/affs/dir.c
--- linux-2.3/fs/affs/dir.c.d_type Sun Mar 5 20:59:01 2000
+++ linux-2.3/fs/affs/dir.c Sun Mar 5 21:04:26 2000
@@ -23,6 +23,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/amigaffs.h>
+#include <linux/dirent.h>
 
 static int affs_readdir(struct file *, void *, filldir_t);
 
@@ -72,14 +73,14 @@
 
         if (filp->f_pos == 0) {
                 filp->private_data = (void *)0;
- if (filldir(dirent,".",1,filp->f_pos,inode->i_ino) < 0) {
+ if (filldir(dirent,DT_DIR,".",1,filp->f_pos,inode->i_ino) < 0) {
                         return 0;
                 }
                 ++filp->f_pos;
                 stored++;
         }
         if (filp->f_pos == 1) {
- if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) {
+ if (filldir(dirent,DT_DIR,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) {
                         return stored;
                 }
                 filp->f_pos = 2;
@@ -135,7 +136,7 @@
                         pr_debug("AFFS: readdir(): filldir(\"%.*s\",ino=%lu), i=%d\n",
                                  namelen,name,ino,i);
                         filp->private_data = (void *)ino;
- if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0)
+ if (filldir(dirent,DT_UNKNOWN,name,namelen,filp->f_pos,ino) < 0)
                                 goto readdir_done;
                         filp->private_data = (void *)i;
                         affs_brelse(fh_bh);
diff -u linux-2.3/fs/autofs/dir.c.d_type linux-2.3/fs/autofs/dir.c
--- linux-2.3/fs/autofs/dir.c.d_type Sun Mar 5 20:59:02 2000
+++ linux-2.3/fs/autofs/dir.c Sun Mar 5 23:10:27 2000
@@ -10,6 +10,7 @@
  *
  * ------------------------------------------------------------------------- */
 
+#include <linux/dirent.h>
 #include "autofs_i.h"
 
 static int autofs_dir_readdir(struct file *filp,
@@ -20,12 +21,12 @@
         switch((unsigned long) filp->f_pos)
         {
         case 0:
- if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0)
+ if (filldir(dirent, DT_DIR, ".", 1, 0, inode->i_ino) < 0)
                         return 0;
                 filp->f_pos++;
                 /* fall through */
         case 1:
- if (filldir(dirent, "..", 2, 1, AUTOFS_ROOT_INO) < 0)
+ if (filldir(dirent, DT_DIR, "..", 2, 1, AUTOFS_ROOT_INO) < 0)
                         return 0;
                 filp->f_pos++;
                 /* fall through */
diff -u linux-2.3/fs/autofs/root.c.d_type linux-2.3/fs/autofs/root.c
--- linux-2.3/fs/autofs/root.c.d_type Sun Mar 5 20:59:02 2000
+++ linux-2.3/fs/autofs/root.c Sun Mar 5 22:26:13 2000
@@ -13,6 +13,7 @@
 #include <linux/errno.h>
 #include <linux/stat.h>
 #include <linux/param.h>
+#include <linux/dirent.h>
 #include "autofs_i.h"
 
 static int autofs_root_readdir(struct file *,void *,filldir_t);
@@ -52,19 +53,22 @@
         switch(nr)
         {
         case 0:
- if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0)
+ if (filldir(dirent, DT_DIR, ".", 1, nr, inode->i_ino) < 0)
                         return 0;
                 filp->f_pos = ++nr;
                 /* fall through */
         case 1:
- if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0)
+ if (filldir(dirent, DT_DIR, "..", 2, nr, inode->i_ino) < 0)
                         return 0;
                 filp->f_pos = ++nr;
                 /* fall through */
         default:
                 while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent) ) {
                         if ( !ent->dentry || ent->dentry->d_mounts != ent->dentry ) {
- if (filldir(dirent,ent->name,ent->len,onr,ent->ino) < 0)
+ unsigned char type = DT_DIR;
+ if (ent->ino < AUTOFS_FIRST_DIR_INO)
+ type = DT_LNK;
+ if (filldir(dirent,type,ent->name,ent->len,onr,ent->ino) < 0)
                                         return 0;
                                 filp->f_pos = nr;
                         }
diff -u linux-2.3/fs/autofs4/root.c.d_type linux-2.3/fs/autofs4/root.c
--- linux-2.3/fs/autofs4/root.c.d_type Sun Mar 5 20:59:02 2000
+++ linux-2.3/fs/autofs4/root.c Sun Mar 5 22:02:57 2000
@@ -14,6 +14,7 @@
 #include <linux/errno.h>
 #include <linux/stat.h>
 #include <linux/param.h>
+#include <linux/dirent.h>
 #include "autofs_i.h"
 
 static int autofs4_dir_readdir(struct file *,void *,filldir_t);
@@ -82,12 +83,12 @@
         switch(nr)
         {
         case 0:
- if (filldir(dirent, ".", 1, nr, dir->i_ino) < 0)
+ if (filldir(dirent, DT_DIR, ".", 1, nr, dir->i_ino) < 0)
                         return 0;
                 filp->f_pos = ++nr;
                 /* fall through */
         case 1:
- if (filldir(dirent, "..", 2, nr, dentry->d_covers->d_parent->d_inode->i_ino) < 0)
+ if (filldir(dirent, DT_DIR, "..", 2, nr, dentry->d_covers->d_parent->d_inode->i_ino) < 0)
                         return 0;
                 filp->f_pos = ++nr;
                 /* fall through */
@@ -101,7 +102,8 @@
                 while(cursor != &dentry->d_subdirs) {
                         dent_ptr = list_entry(cursor, struct dentry, d_child);
                         if (dent_ptr->d_inode &&
- filldir(dirent, dent_ptr->d_name.name, dent_ptr->d_name.len, nr,
+ filldir(dirent, IFTODT (dent_ptr->d_inode->i_mode),
+ dent_ptr->d_name.name, dent_ptr->d_name.len, nr,
                                     dent_ptr->d_inode->i_ino) < 0)
                                 return 0;
                         filp->f_pos = ++nr;
diff -u linux-2.3/fs/bfs/dir.c.d_type linux-2.3/fs/bfs/dir.c
--- linux-2.3/fs/bfs/dir.c.d_type Sun Mar 5 20:59:02 2000
+++ linux-2.3/fs/bfs/dir.c Sun Mar 5 21:04:26 2000
@@ -8,6 +8,7 @@
 #include <linux/string.h>
 #include <linux/bfs_fs.h>
 #include <linux/locks.h>
+#include <linux/dirent.h>
 
 #include "bfs_defs.h"
 
@@ -55,7 +56,7 @@
                         de = (struct bfs_dirent *)(bh->b_data + offset);
                         if (de->ino) {
                                 int size = strnlen(de->name, BFS_NAMELEN);
- if (filldir(dirent, de->name, size, f->f_pos, de->ino) < 0) {
+ if (filldir(dirent, DT_UNKNOWN, de->name, size, f->f_pos, de->ino) < 0) {
                                         brelse(bh);
                                         return 0;
                                 }
diff -u linux-2.3/fs/coda/dir.c.d_type linux-2.3/fs/coda/dir.c
--- linux-2.3/fs/coda/dir.c.d_type Sun Mar 5 20:59:02 2000
+++ linux-2.3/fs/coda/dir.c Sun Mar 5 21:04:26 2000
@@ -18,6 +18,7 @@
 #include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
+#include <linux/dirent.h>
 
 #include <linux/coda.h>
 #include <linux/coda_linux.h>
@@ -725,8 +726,10 @@
                         off_t offs = filp->f_pos;
                         ino_t ino = vdirent->d_fileno;
                         char *name = vdirent->d_name;
+ /* CDT_* types are the same as DT_* types. */
+ unsigned char type = vdirent->d_type;
 
- errfill = filldir(getdent, name, namlen,
+ errfill = filldir(getdent, type, name, namlen,
                                           offs, ino);
 CDEBUG(D_FILE, "entry %d: ino %ld, namlen %d, reclen %d, type %d, pos %d, string_offs %d, name %*s, offset %d, result: %d, errfill: %d.\n", i,vdirent->d_fileno, vdirent->d_namlen, vdirent->d_reclen, vdirent->d_type, pos, string_offset, vdirent->d_namlen, vdirent->d_name, (u_int) offs, result, errfill);
                         /* errfill means no space for filling in this round */
diff -u linux-2.3/fs/cramfs/inode.c.d_type linux-2.3/fs/cramfs/inode.c
--- linux-2.3/fs/cramfs/inode.c.d_type Sun Mar 5 20:59:02 2000
+++ linux-2.3/fs/cramfs/inode.c Sun Mar 5 21:04:26 2000
@@ -13,6 +13,7 @@
 
 #include <linux/module.h>
 #include <linux/fs.h>
+#include <linux/dirent.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
 #include <linux/string.h>
@@ -266,7 +267,8 @@
                                 break;
                         namelen--;
                 }
- error = filldir(dirent, name, namelen, offset, CRAMINO(de));
+ error = filldir(dirent, IFTODT(de->mode),
+ name, namelen, offset, CRAMINO(de));
                 if (error)
                         break;
 
diff -u linux-2.3/fs/devfs/base.c.d_type linux-2.3/fs/devfs/base.c
--- linux-2.3/fs/devfs/base.c.d_type Sun Mar 5 20:59:02 2000
+++ linux-2.3/fs/devfs/base.c Sun Mar 5 21:04:26 2000
@@ -445,6 +445,7 @@
 #include <linux/init.h>
 #include <linux/locks.h>
 #include <linux/kdev_t.h>
+#include <linux/dirent.h>
 #include <linux/devfs_fs.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/smp_lock.h>
@@ -2393,7 +2394,7 @@
     {
       case 0:
         scan_dir_for_removable (parent);
- err = (*filldir) (dirent, "..", 2, file->f_pos,
+ err = (*filldir) (dirent, DT_DIR, "..", 2, file->f_pos,
                           file->f_dentry->d_parent->d_inode->i_ino);
         if (err == -EINVAL) break;
         if (err < 0) return err;
@@ -2401,7 +2402,7 @@
         ++stored;
         /* Fall through */
       case 1:
- err = (*filldir) (dirent, ".", 1, file->f_pos, inode->i_ino);
+ err = (*filldir) (dirent, DT_DIR, ".", 1, file->f_pos, inode->i_ino);
         if (err == -EINVAL) break;
         if (err < 0) return err;
         file->f_pos++;
@@ -2443,7 +2444,7 @@
                 if (di == NULL) return -ENOMEM;
             }
             else if (di->ctime == 0) update_devfs_inode_from_entry (di);
- err = (*filldir) (dirent, de->name, de->namelen,
+ err = (*filldir) (dirent, IFTODT (di->mode), de->name, de->namelen,
                               file->f_pos, di->ino);
             if (err == -EINVAL) break;
             if (err < 0) return err;
diff -u linux-2.3/fs/devpts/root.c.d_type linux-2.3/fs/devpts/root.c
--- linux-2.3/fs/devpts/root.c.d_type Sun Mar 5 20:59:02 2000
+++ linux-2.3/fs/devpts/root.c Sun Mar 5 21:04:26 2000
@@ -14,6 +14,7 @@
 #include <linux/stat.h>
 #include <linux/param.h>
 #include <linux/string.h>
+#include <linux/dirent.h>
 #include "devpts_i.h"
 
 static int devpts_root_readdir(struct file *,void *,filldir_t);
@@ -54,12 +55,12 @@
         switch(nr)
         {
         case 0:
- if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0)
+ if (filldir(dirent, DT_DIR, ".", 1, nr, inode->i_ino) < 0)
                         return 0;
                 filp->f_pos = ++nr;
                 /* fall through */
         case 1:
- if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0)
+ if (filldir(dirent, DT_DIR, "..", 2, nr, inode->i_ino) < 0)
                         return 0;
                 filp->f_pos = ++nr;
                 /* fall through */
@@ -68,7 +69,7 @@
                         int ptynr = nr - 2;
                         if ( sbi->inodes[ptynr] ) {
                                 genptsname(numbuf, ptynr);
- if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 )
+ if ( filldir(dirent, DT_CHR, numbuf, strlen(numbuf), nr, nr) < 0 )
                                         return 0;
                         }
                         filp->f_pos = ++nr;
diff -u linux-2.3/fs/efs/dir.c.d_type linux-2.3/fs/efs/dir.c
--- linux-2.3/fs/efs/dir.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/efs/dir.c Sun Mar 5 21:04:26 2000
@@ -5,6 +5,7 @@
  */
 
 #include <linux/efs_fs.h>
+#include <linux/dirent.h>
 
 static int efs_readdir(struct file *, void *, filldir_t);
 
@@ -78,7 +79,7 @@
                                 filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
 
                                 /* copy filename and data in dirslot */
- filldir(dirent, nameptr, namelen, filp->f_pos, inodenum);
+ filldir(dirent, DT_UNKNOWN, nameptr, namelen, filp->f_pos, inodenum);
 
                                 /* sanity check */
                                 if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) {
diff -u linux-2.3/fs/ext2/dir.c.d_type linux-2.3/fs/ext2/dir.c
--- linux-2.3/fs/ext2/dir.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/ext2/dir.c Sun Mar 5 21:04:26 2000
@@ -19,6 +19,7 @@
  */
 
 #include <linux/fs.h>
+#include <linux/dirent.h>
 
 static int ext2_readdir(struct file *, void *, filldir_t);
 
@@ -57,6 +58,17 @@
         return error_msg == NULL ? 1 : 0;
 }
 
+static const char ext2_file_types [EXT2_FT_MAX] = {
+ 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 */
+};
+
 static int ext2_readdir(struct file * filp,
                          void * dirent, filldir_t filldir)
 {
@@ -152,9 +164,13 @@
                                  * during the copy operation.
                                  */
                                 unsigned long version = inode->i_version;
+ unsigned char type = DT_UNKNOWN;
+
+ if (de->file_type < EXT2_FT_MAX)
+ type = ext2_file_types [de->file_type];
 
- error = filldir(dirent, de->name,
- de->name_len,
+ error = filldir(dirent, type,
+ de->name, de->name_len,
                                                 filp->f_pos, le32_to_cpu(de->inode));
                                 if (error)
                                         break;
diff -u linux-2.3/fs/fat/dir.c.d_type linux-2.3/fs/fat/dir.c
--- linux-2.3/fs/fat/dir.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/fat/dir.c Sun Mar 5 21:04:28 2000
@@ -296,7 +296,7 @@
         struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
         struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
         struct nls_unicode bufuname[14], *ptuname = &bufuname[0];
- unsigned char long_slots, *unicode = NULL;
+ unsigned char long_slots, *unicode = NULL, type;
         char c, bufname[56], *ptname = bufname;
         unsigned long lpos, dummy, *furrfu = &lpos;
         int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
@@ -309,7 +309,7 @@
 /* Fake . and .. for the root directory. */
         if (inode->i_ino == MSDOS_ROOT_INO) {
                 while (cpos < 2) {
- if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO) < 0)
+ if (filldir(dirent, DT_DIR, "..", cpos+1, cpos, MSDOS_ROOT_INO) < 0)
                                 return 0;
                         cpos++;
                         filp->f_pos++;
@@ -438,6 +438,10 @@
 
         i = last + dotoffset;
 
+ type = DT_REG;
+ if ((de->attr & ATTR_DIR) && !IS_FREE(de->name))
+ type = DT_DIR;
+
         lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry);
         if (!memcmp(de->name,MSDOS_DOT,11))
                 inum = inode->i_ino;
@@ -463,7 +467,7 @@
         if (!long_slots||shortnames) {
                 if (both)
                         bufname[i] = '\0';
- if (filldir(dirent, bufname, i, *furrfu, inum) < 0)
+ if (filldir(dirent, type, bufname, i, *furrfu, inum) < 0)
                         goto FillFailed;
         } else {
                 char longname[275];
@@ -474,7 +478,8 @@
                         memcpy(&longname[long_len+1], bufname, i);
                         long_len += i;
                 }
- if (filldir(dirent, longname, long_len, *furrfu, inum) < 0)
+ if (filldir(dirent, type, longname, long_len,
+ *furrfu, inum) < 0)
                         goto FillFailed;
         }
 
@@ -501,13 +506,14 @@
 
 static int vfat_ioctl_fill(
         void * buf,
+ unsigned char type,
         const char * name,
         int name_len,
         off_t offset,
         ino_t ino)
 {
- struct dirent *d1 = (struct dirent *)buf;
- struct dirent *d2 = d1 + 1;
+ struct getdents_dirent *d1 = (struct getdents_dirent *)buf;
+ struct getdents_dirent *d2 = d1 + 1;
         int len, slen;
         int dotdir;
 
@@ -559,8 +565,9 @@
          */
         switch (cmd) {
         case VFAT_IOCTL_READDIR_BOTH: {
- struct dirent *d1 = (struct dirent *)arg;
- err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
+ struct getdents_dirent *d1 = (struct getdents_dirent *)arg;
+ err = verify_area(VERIFY_WRITE, d1,
+ sizeof(struct getdents_dirent[2]));
                 if (err)
                         return err;
                 put_user(0, &d1->d_reclen);
@@ -568,9 +575,10 @@
                                     vfat_ioctl_fill, 0, 1);
         }
         case VFAT_IOCTL_READDIR_SHORT: {
- struct dirent *d1 = (struct dirent *)arg;
+ struct getdents_dirent *d1 = (struct getdents_dirent *) arg;
                 put_user(0, &d1->d_reclen);
- err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
+ err = verify_area(VERIFY_WRITE, d1,
+ sizeof(struct getdents_dirent[2]));
                 if (err)
                         return err;
                 return fat_readdirx(inode,filp,(void *)arg,
diff -u linux-2.3/fs/hfs/dir_cap.c.d_type linux-2.3/fs/hfs/dir_cap.c
--- linux-2.3/fs/hfs/dir_cap.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/hfs/dir_cap.c Sun Mar 5 21:04:28 2000
@@ -24,6 +24,7 @@
 #include <linux/hfs_fs_sb.h>
 #include <linux/hfs_fs_i.h>
 #include <linux/hfs_fs.h>
+#include <linux/dirent.h>
 
 /*================ Forward declarations ================*/
 
@@ -190,7 +191,7 @@
 
         if (filp->f_pos == 0) {
                 /* Entry 0 is for "." */
- if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino)) {
+ if (filldir(dirent, DT_DIR, DOT->Name, DOT_LEN, 0, dir->i_ino)) {
                         return 0;
                 }
                 filp->f_pos = 1;
@@ -206,7 +207,7 @@
                         cnid = entry->cnid;
                 }
 
- if (filldir(dirent, DOT_DOT->Name,
+ if (filldir(dirent, DT_DIR, DOT_DOT->Name,
                             DOT_DOT_LEN, 1, ntohl(cnid))) {
                         return 0;
                 }
@@ -233,7 +234,7 @@
                                 ino = ntohl(cnid) | HFS_I(dir)->file_type;
                                 len = hfs_namein(dir, tmp_name,
                                     &((struct hfs_cat_key *)brec.key)->CName);
- if (filldir(dirent, tmp_name, len,
+ if (filldir(dirent, DT_UNKNOWN, tmp_name, len,
                                             filp->f_pos, ino)) {
                                         hfs_cat_close(entry, &brec);
                                         return 0;
@@ -248,7 +249,7 @@
                 if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
                     (type == HFS_CAP_NDIR)) {
                         /* In root dir last-2 entry is for ".rootinfo" */
- if (filldir(dirent, DOT_ROOTINFO->Name,
+ if (filldir(dirent, DT_UNKNOWN, DOT_ROOTINFO->Name,
                                     DOT_ROOTINFO_LEN, filp->f_pos,
                                     ntohl(entry->cnid) | HFS_CAP_FNDR)) {
                                 return 0;
@@ -260,7 +261,7 @@
         if (filp->f_pos == (dir->i_size - 2)) {
                 if (type == HFS_CAP_NDIR) {
                         /* In normal dirs last-1 entry is for ".finderinfo" */
- if (filldir(dirent, DOT_FINDERINFO->Name,
+ if (filldir(dirent, DT_UNKNOWN, DOT_FINDERINFO->Name,
                                     DOT_FINDERINFO_LEN, filp->f_pos,
                                     ntohl(entry->cnid) | HFS_CAP_FDIR)) {
                                 return 0;
@@ -272,7 +273,7 @@
         if (filp->f_pos == (dir->i_size - 1)) {
                 if (type == HFS_CAP_NDIR) {
                         /* In normal dirs last entry is for ".resource" */
- if (filldir(dirent, DOT_RESOURCE->Name,
+ if (filldir(dirent, DT_UNKNOWN, DOT_RESOURCE->Name,
                                     DOT_RESOURCE_LEN, filp->f_pos,
                                     ntohl(entry->cnid) | HFS_CAP_RDIR)) {
                                 return 0;
diff -u linux-2.3/fs/hfs/dir_dbl.c.d_type linux-2.3/fs/hfs/dir_dbl.c
--- linux-2.3/fs/hfs/dir_dbl.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/hfs/dir_dbl.c Sun Mar 5 21:04:28 2000
@@ -20,6 +20,7 @@
 #include <linux/hfs_fs_sb.h>
 #include <linux/hfs_fs_i.h>
 #include <linux/hfs_fs.h>
+#include <linux/dirent.h>
 
 /*================ Forward declarations ================*/
 
@@ -183,7 +184,7 @@
 
         if (filp->f_pos == 0) {
                 /* Entry 0 is for "." */
- if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino)) {
+ if (filldir(dirent, DT_DIR, DOT->Name, DOT_LEN, 0, dir->i_ino)) {
                         return 0;
                 }
                 filp->f_pos = 1;
@@ -191,7 +192,7 @@
 
         if (filp->f_pos == 1) {
                 /* Entry 1 is for ".." */
- if (filldir(dirent, DOT_DOT->Name, DOT_DOT_LEN, 1,
+ if (filldir(dirent, DT_DIR, DOT_DOT->Name, DOT_DOT_LEN, 1,
                             hfs_get_hl(entry->key.ParID))) {
                         return 0;
                 }
@@ -229,7 +230,7 @@
                                     &((struct hfs_cat_key *)brec.key)->CName);
                         }
 
- if (filldir(dirent, tmp_name, len, filp->f_pos, ino)) {
+ if (filldir(dirent, DT_UNKNOWN, tmp_name, len, filp->f_pos, ino)) {
                                 hfs_cat_close(entry, &brec);
                                 return 0;
                         }
@@ -241,7 +242,7 @@
         if (filp->f_pos == (dir->i_size - 1)) {
                 if (entry->cnid == htonl(HFS_ROOT_CNID)) {
                         /* In root dir last entry is for "%RootInfo" */
- if (filldir(dirent, PCNT_ROOTINFO->Name,
+ if (filldir(dirent, DT_UNKNOWN, PCNT_ROOTINFO->Name,
                                     PCNT_ROOTINFO_LEN, filp->f_pos,
                                     ntohl(entry->cnid) | HFS_DBL_HDR)) {
                                 return 0;
diff -u linux-2.3/fs/hfs/dir_nat.c.d_type linux-2.3/fs/hfs/dir_nat.c
--- linux-2.3/fs/hfs/dir_nat.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/hfs/dir_nat.c Sun Mar 5 21:04:28 2000
@@ -26,6 +26,7 @@
 #include <linux/hfs_fs_sb.h>
 #include <linux/hfs_fs_i.h>
 #include <linux/hfs_fs.h>
+#include <linux/dirent.h>
 
 /*================ Forward declarations ================*/
 
@@ -191,7 +192,8 @@
 
         if (filp->f_pos == 0) {
                 /* Entry 0 is for "." */
- if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino)) {
+ if (filldir(dirent, DT_DIR, DOT->Name, DOT_LEN,
+ 0, dir->i_ino)) {
                         return 0;
                 }
                 filp->f_pos = 1;
@@ -207,8 +209,8 @@
                         cnid = entry->cnid;
                 }
 
- if (filldir(dirent, DOT_DOT->Name,
- DOT_DOT_LEN, 1, ntohl(cnid))) {
+ if (filldir(dirent, DT_DIR, DOT_DOT->Name, DOT_DOT_LEN,
+ 1, ntohl(cnid))) {
                         return 0;
                 }
                 filp->f_pos = 2;
@@ -234,7 +236,7 @@
                                 ino = ntohl(cnid) | HFS_I(dir)->file_type;
                                 len = hfs_namein(dir, tmp_name,
                                     &((struct hfs_cat_key *)brec.key)->CName);
- if (filldir(dirent, tmp_name, len,
+ if (filldir(dirent, DT_UNKNOWN, tmp_name, len,
                                             filp->f_pos, ino)) {
                                         hfs_cat_close(entry, &brec);
                                         return 0;
@@ -248,14 +250,14 @@
         if (filp->f_pos == (dir->i_size - 2)) {
                 if (type == HFS_NAT_NDIR) {
                         /* In normal dirs entry 2 is for ".AppleDouble" */
- if (filldir(dirent, DOT_APPLEDOUBLE->Name,
+ if (filldir(dirent, DT_DIR, DOT_APPLEDOUBLE->Name,
                                     DOT_APPLEDOUBLE_LEN, filp->f_pos,
                                     ntohl(entry->cnid) | HFS_NAT_HDIR)) {
                                 return 0;
                         }
                 } else if (type == HFS_NAT_HDIR) {
                         /* In .AppleDouble entry 2 is for ".Parent" */
- if (filldir(dirent, DOT_PARENT->Name,
+ if (filldir(dirent, DT_UNKNOWN, DOT_PARENT->Name,
                                     DOT_PARENT_LEN, filp->f_pos,
                                     ntohl(entry->cnid) | HFS_NAT_HDR)) {
                                 return 0;
@@ -268,7 +270,7 @@
                 /* handle ROOT/.AppleDouble/RootInfo as the last entry. */
                 if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
                     (type == HFS_NAT_HDIR)) {
- if (filldir(dirent, ROOTINFO->Name,
+ if (filldir(dirent, DT_UNKNOWN, ROOTINFO->Name,
                                     ROOTINFO_LEN, filp->f_pos,
                                     ntohl(entry->cnid) | HFS_NAT_HDR)) {
                                 return 0;
diff -u linux-2.3/fs/hpfs/dir.c.d_type linux-2.3/fs/hpfs/dir.c
--- linux-2.3/fs/hpfs/dir.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/hpfs/dir.c Sun Mar 5 21:04:28 2000
@@ -7,6 +7,7 @@
  */
 
 #include "hpfs_fn.h"
+#include <linux/dirent.h>
 
 int hpfs_dir_release(struct inode *inode, struct file *filp)
 {
@@ -104,14 +105,14 @@
                         return 0;
                 }
                 if (filp->f_pos == 0) {
- if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0) {
+ if (filldir(dirent, DT_DIR, ".", 1, filp->f_pos, inode->i_ino) < 0) {
                                 hpfs_unlock_inode(inode);
                                 return 0;
                         }
                         filp->f_pos = 11;
                 }
                 if (filp->f_pos == 11) {
- if (filldir(dirent, "..", 2, filp->f_pos, inode->i_hpfs_parent_dir) < 0) {
+ if (filldir(dirent, DT_DIR, "..", 2, filp->f_pos, inode->i_hpfs_parent_dir) < 0) {
                                 hpfs_unlock_inode(inode);
                                 return 0;
                         }
@@ -140,7 +141,10 @@
                                 goto again;
                         }
                         tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3);
- if (filldir(dirent, tempname, de->namelen, old_pos, de->fnode) < 0) {
+ if (filldir(dirent, (de->directory ? DT_DIR
+ : !de->has_ea ? DT_REG
+ : DT_UNKNOWN),
+ tempname, de->namelen, old_pos, de->fnode) < 0) {
                                 filp->f_pos = old_pos;
                                 if (tempname != (char *)de->name) kfree(tempname);
                                 hpfs_brelse4(&qbh);
diff -u linux-2.3/fs/isofs/dir.c.d_type linux-2.3/fs/isofs/dir.c
--- linux-2.3/fs/isofs/dir.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/isofs/dir.c Sun Mar 5 21:04:28 2000
@@ -21,6 +21,7 @@
 #include <linux/sched.h>
 #include <linux/locks.h>
 #include <linux/config.h>
+#include <linux/dirent.h>
 
 #include <asm/uaccess.h>
 
@@ -112,6 +113,7 @@
         int first_de = 1;
         char *p = NULL; /* Quiet GCC */
         struct iso_directory_record *de;
+ unsigned char type;
 
          if (filp->f_pos >= inode->i_size)
                 return 0;
@@ -191,7 +193,7 @@
 
                 /* Handle the case of the '.' directory */
                 if (de->name_len[0] == 1 && de->name[0] == 0) {
- if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
+ if (filldir(dirent, DT_DIR, ".", 1, filp->f_pos, inode->i_ino) < 0)
                                 break;
                         filp->f_pos += de_len;
                         continue;
@@ -202,7 +204,7 @@
                 /* Handle the case of the '..' directory */
                 if (de->name_len[0] == 1 && de->name[0] == 1) {
                         inode_number = filp->f_dentry->d_parent->d_inode->i_ino;
- if (filldir(dirent, "..", 2, filp->f_pos, inode_number) < 0)
+ if (filldir(dirent, DT_DIR, "..", 2, filp->f_pos, inode_number) < 0)
                                 break;
                         filp->f_pos += de_len;
                         continue;
@@ -219,8 +221,9 @@
                 }
 
                 map = 1;
+ type = (de->flags[-high_sierra] & 2) ? DT_DIR : DT_REG;
                 if (inode->i_sb->u.isofs_sb.s_rock) {
- len = get_rock_ridge_filename(de, tmpname, inode);
+ len = get_rock_ridge_filename(de, tmpname, inode, &type);
                         if (len != 0) {
                                 p = tmpname;
                                 map = 0;
@@ -247,7 +250,7 @@
                         }
                 }
                 if (len > 0) {
- if (filldir(dirent, p, len, filp->f_pos, inode_number) < 0)
+ if (filldir(dirent, type, p, len, filp->f_pos, inode_number) < 0)
                                 break;
                 }
                 filp->f_pos += de_len;
diff -u linux-2.3/fs/isofs/namei.c.d_type linux-2.3/fs/isofs/namei.c
--- linux-2.3/fs/isofs/namei.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/isofs/namei.c Sun Mar 5 21:04:28 2000
@@ -169,7 +169,7 @@
                         }
                 }
                 if (dir->i_sb->u.isofs_sb.s_rock &&
- ((i = get_rock_ridge_filename(de, page, dir)))) {
+ ((i = get_rock_ridge_filename(de, page, dir, 0)))) {
                         dlen = i;
                         dpnt = page;
 #ifdef CONFIG_JOLIET
diff -u linux-2.3/fs/isofs/rock.c.d_type linux-2.3/fs/isofs/rock.c
--- linux-2.3/fs/isofs/rock.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/isofs/rock.c Sun Mar 5 21:04:28 2000
@@ -13,15 +13,16 @@
 #include <linux/mm.h>
 #include <linux/malloc.h>
 #include <linux/pagemap.h>
+#include <linux/dirent.h>
 
 #include "rock.h"
 
 /* These functions are designed to read the system areas of a directory record
  * and extract relevant information. There are different functions provided
  * depending upon what information we need at the time. One function fills
- * out an inode structure, a second one extracts a filename, a third one
- * returns a symbolic link name, and a fourth one returns the extent number
- * for the file. */
+ * out an inode structure, a second one extracts a filename and d_type value,
+ * a third one returns a symbolic link name, and a fourth one returns the
+ * extent number for the file. */
 
 #define SIG(A,B) ((A << 8) | B)
 
@@ -152,7 +153,8 @@
 }
 
 int get_rock_ridge_filename(struct iso_directory_record * de,
- char * retname, struct inode * inode)
+ char * retname, struct inode * inode,
+ unsigned char * rettype)
 {
   int len;
   unsigned char * chr;
@@ -215,6 +217,34 @@
 #endif
         if (buffer) kfree(buffer);
         return -1;
+ case SIG('C','L'):
+#ifdef DEBUG
+ printk("RR: CL (%x)\n",inode->i_ino);
+#endif
+ /* Mode is set from relocated entry. Don't look it up as that misses
+ the point of the DT_* optimisation. */
+ if (rettype)
+ *rettype = DT_UNKNOWN;
+ break;
+ case SIG('P','X'):
+ /*
+ * Merge mode with previous type byte. It was either DT_DIR, DT_REG,
+ * or set by a previous PX record (should never repeat but hey...).
+ *
+ * Some RR directories have 0 (unknown) for the type here and
+ * are not flagged as directories in the base record. If you
+ * mount with norock, they look like empty files. But with
+ * RR, they are directories. This code sets the type to
+ * DT_UNKNOWN in that case (it would be DT_REG otherwise).
+ */
+ if (rettype) {
+ mode_t mode = isonum_733(rr->u.PX.mode);
+ if (!S_ISDIR(mode) && *rettype == DT_REG)
+ *rettype = IFTODT(mode);
+ else if (*rettype != IFTODT(mode))
+ *rettype = DT_UNKNOWN;
+ }
+ break;
       default:
         break;
       }
diff -u linux-2.3/fs/minix/dir.c.d_type linux-2.3/fs/minix/dir.c
--- linux-2.3/fs/minix/dir.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/minix/dir.c Sun Mar 5 21:04:28 2000
@@ -11,6 +11,7 @@
 #include <linux/fs.h>
 #include <linux/minix_fs.h>
 #include <linux/stat.h>
+#include <linux/dirent.h>
 
 static int minix_readdir(struct file *, void *, filldir_t);
 
@@ -43,7 +44,7 @@
                         de = (struct minix_dir_entry *) (offset + bh->b_data);
                         if (de->inode) {
                                 int size = strnlen(de->name, info->s_namelen);
- if (filldir(dirent, de->name, size, filp->f_pos, de->inode) < 0) {
+ if (filldir(dirent, DT_UNKNOWN, de->name, size, filp->f_pos, de->inode) < 0) {
                                         brelse(bh);
                                         return 0;
                                 }
diff -u linux-2.3/fs/ncpfs/dir.c.d_type linux-2.3/fs/ncpfs/dir.c
--- linux-2.3/fs/ncpfs/dir.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/ncpfs/dir.c Sun Mar 5 21:04:28 2000
@@ -21,6 +21,7 @@
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 #include <linux/locks.h>
+#include <linux/dirent.h>
 
 #include <linux/ncp_fs.h>
 
@@ -433,12 +434,12 @@
 
         result = 0;
         if (filp->f_pos == 0) {
- if (filldir(dirent, ".", 1, 0, inode->i_ino))
+ if (filldir(dirent, DT_DIR, ".", 1, 0, inode->i_ino))
                         goto out;
                 filp->f_pos = 1;
         }
         if (filp->f_pos == 1) {
- if (filldir(dirent, "..", 2, 1,
+ if (filldir(dirent, DT_DIR, "..", 2, 1,
                                 dentry->d_parent->d_inode->i_ino))
                         goto out;
                 filp->f_pos = 2;
@@ -488,9 +489,9 @@
                                                 dentry, filp->f_pos);
                         if (!dent)
                                 goto invalid_cache;
- res = filldir(dirent, dent->d_name.name,
- dent->d_name.len, filp->f_pos,
- dent->d_inode->i_ino);
+ res = filldir(dirent, IFTODT (dent->d_inode->i_mode),
+ dent->d_name.name, dent->d_name.len,
+ filp->f_pos, dent->d_inode->i_ino);
                         dput(dent);
                         if (res)
                                 goto finished;
@@ -567,6 +568,7 @@
         struct qstr qname;
         int valid = 0;
         ino_t ino = 0;
+ unsigned char type = DT_UNKNOWN;
         __u8 __name[256];
 
         qname.len = 256;
@@ -605,6 +607,7 @@
 
         if (newdent->d_inode) {
                 ino = newdent->d_inode->i_ino;
+ type = IFTODT (newdent->d_inode->i_mode);
                 newdent->d_fsdata = (void *) ctl.fpos;
                 ncp_new_dentry(newdent);
         }
@@ -636,7 +639,7 @@
                         ino = find_inode_number(dentry, &qname);
                 if (!ino)
                         ino = iunique(inode->i_sb, 2);
- ctl.filled = filldir(dirent, qname.name, qname.len,
+ ctl.filled = filldir(dirent, type, qname.name, qname.len,
                                                         filp->f_pos, ino);
                 if (!ctl.filled)
                         filp->f_pos += 1;
diff -u linux-2.3/fs/nfs/dir.c.d_type linux-2.3/fs/nfs/dir.c
--- linux-2.3/fs/nfs/dir.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/nfs/dir.c Sun Mar 5 21:04:28 2000
@@ -30,6 +30,7 @@
 #include <linux/nfs_fs.h>
 #include <linux/nfs.h>
 #include <linux/pagemap.h>
+#include <linux/dirent.h>
 
 #include <asm/segment.h> /* for fs functions */
 
@@ -379,7 +380,7 @@
                         continue;
 
                 cookie = this_cookie;
- if (filldir(dirent, name, len, cookie, fileid) < 0)
+ if (filldir(dirent, DT_UNKNOWN, name, len, cookie, fileid) < 0)
                         break;
         }
 
diff -u linux-2.3/fs/nfsd/nfs3xdr.c.d_type linux-2.3/fs/nfsd/nfs3xdr.c
--- linux-2.3/fs/nfsd/nfs3xdr.c.d_type Sun Mar 5 21:01:59 2000
+++ linux-2.3/fs/nfsd/nfs3xdr.c Sun Mar 5 21:04:28 2000
@@ -736,15 +736,17 @@
 }
 
 int
-nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
- int namlen, off_t offset, ino_t ino)
+nfs3svc_encode_entry(struct readdir_cd *cd, unsigned char type,
+ const char *name, int namlen,
+ off_t offset, ino_t ino)
 {
         return encode_entry(cd, name, namlen, offset, ino, 0);
 }
 
 int
-nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
- int namlen, off_t offset, ino_t ino)
+nfs3svc_encode_entry_plus(struct readdir_cd *cd, unsigned char type,
+ const char *name, int namlen,
+ off_t offset, ino_t ino)
 {
         return encode_entry(cd, name, namlen, offset, ino, 1);
 }
diff -u linux-2.3/fs/nfsd/nfsfh.c.d_type linux-2.3/fs/nfsd/nfsfh.c
--- linux-2.3/fs/nfsd/nfsfh.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/nfsd/nfsfh.c Sun Mar 5 21:04:28 2000
@@ -40,8 +40,8 @@
  * A rather strange filldir function to capture
  * the name matching the specified inode number.
  */
-static int filldir_one(void * __buf, const char * name, int len,
- off_t pos, ino_t ino)
+static int filldir_one(void * __buf, unsigned char type,
+ const char * name, int len, off_t pos, ino_t ino)
 {
         struct nfsd_getdents_callback *buf = __buf;
         struct qstr *qs = buf->name;
diff -u linux-2.3/fs/nfsd/nfsxdr.c.d_type linux-2.3/fs/nfsd/nfsxdr.c
--- linux-2.3/fs/nfsd/nfsxdr.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/nfsd/nfsxdr.c Sun Mar 5 21:04:28 2000
@@ -442,7 +442,7 @@
 }
 
 int
-nfssvc_encode_entry(struct readdir_cd *cd, const char *name,
+nfssvc_encode_entry(struct readdir_cd *cd, unsigned char type, const char *name,
                                         int namlen, off_t offset, ino_t ino)
 {
         u32 *p = cd->buffer;
diff -u linux-2.3/fs/ntfs/fs.c.d_type linux-2.3/fs/ntfs/fs.c
--- linux-2.3/fs/ntfs/fs.c.d_type Sun Mar 5 21:01:59 2000
+++ linux-2.3/fs/ntfs/fs.c Sun Mar 5 21:04:34 2000
@@ -28,6 +28,7 @@
 #include <linux/nls.h>
 #include <linux/locks.h>
 #include <linux/init.h>
+#include <linux/dirent.h>
 
 /* Forward declarations */
 static struct inode_operations ntfs_dir_inode_operations;
@@ -197,7 +198,7 @@
         ntfs_debug(DEBUG_OTHER, "readdir got %s,len %d\n",nf->name,nf->namelen);
         /* filldir expects an off_t rather than an loff_t.
            Hope we don't have more than 65535 index records */
- error=nf->filldir(nf->dirent,nf->name,nf->namelen,
+ error=nf->filldir(nf->dirent,DT_UNKNOWN,nf->name,nf->namelen,
                         (nf->ph<<16)|nf->pl,inum);
         ntfs_free(nf->name);
         /* Linux filldir errors are negative, other errors positive */
@@ -224,11 +225,11 @@
         if(cb.ph==0xFFFF){
                 /* FIXME: Maybe we can return those with the previous call */
                 switch(cb.pl){
- case 0: filldir(dirent,".",1,filp->f_pos,dir->i_ino);
+ case 0: filldir(dirent,DT_DIR,".",1,filp->f_pos,dir->i_ino);
                         filp->f_pos=0xFFFF0001;
                         return 0;
                         /* FIXME: parent directory */
- case 1: filldir(dirent,"..",2,filp->f_pos,0);
+ case 1: filldir(dirent,DT_DIR,"..",2,filp->f_pos,0);
                         filp->f_pos=0xFFFF0002;
                         return 0;
                 }
diff -u linux-2.3/fs/openpromfs/inode.c.d_type linux-2.3/fs/openpromfs/inode.c
--- linux-2.3/fs/openpromfs/inode.c.d_type Sun Mar 5 21:01:59 2000
+++ linux-2.3/fs/openpromfs/inode.c Sun Mar 5 21:04:34 2000
@@ -9,6 +9,7 @@
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/fs.h>
+#include <linux/dirent.h>
 #include <linux/openprom_fs.h>
 #include <linux/locks.h>
 #include <linux/init.h>
@@ -754,12 +755,12 @@
         i = filp->f_pos;
         switch (i) {
         case 0:
- if (filldir(dirent, ".", 1, i, ino) < 0) return 0;
+ if (filldir(dirent, DT_DIR, ".", 1, i, ino) < 0) return 0;
                 i++;
                 filp->f_pos++;
                 /* fall thru */
         case 1:
- if (filldir(dirent, "..", 2, i,
+ if (filldir(dirent, DT_DIR, "..", 2, i,
                         (NODE(ino).parent == 0xffff) ?
                         OPENPROM_ROOT_INO : NODE2INO(NODE(ino).parent)) < 0)
                         return 0;
@@ -784,7 +785,8 @@
                 }
                 j = NODEP2INO(NODE(ino).first_prop);
                 if (!i) {
- if (filldir(dirent, ".node", 5, filp->f_pos, j) < 0)
+ if (filldir(dirent, DT_UNKNOWN, ".node", 5,
+ filp->f_pos, j) < 0)
                                 return 0;
                         filp->f_pos++;
                 } else
@@ -793,7 +795,8 @@
                 if (ino == OPENPROM_FIRST_INO + aliases) {
                         for (j++; i < aliases_nodes; i++, j++) {
                                 if (alias_names [i]) {
- if (filldir (dirent, alias_names [i],
+ if (filldir (dirent, DT_UNKNOWN,
+ alias_names [i],
                                                 strlen (alias_names [i]),
                                                 filp->f_pos, j) < 0) return 0;
                                         filp->f_pos++;
@@ -806,7 +809,8 @@
                                 j++;
                                 if (i) i--;
                                 else {
- if (filldir(dirent, p, strlen(p),
+ if (filldir(dirent, DT_UNKNOWN,
+ p, strlen(p),
                                                     filp->f_pos, j) < 0)
                                                 return 0;
                                         filp->f_pos++;
diff -u linux-2.3/fs/proc/base.c.d_type linux-2.3/fs/proc/base.c
--- linux-2.3/fs/proc/base.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/proc/base.c Sun Mar 5 21:04:34 2000
@@ -19,6 +19,7 @@
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
+#include <linux/dirent.h>
 #include <linux/init.h>
 #include <linux/file.h>
 
@@ -491,12 +492,12 @@
         fd = filp->f_pos;
         switch (fd) {
                 case 0:
- if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0)
+ if (filldir(dirent, DT_DIR, ".", 1, 0, inode->i_ino) < 0)
                                 goto out;
                         filp->f_pos++;
                 case 1:
                         ino = fake_ino(pid, PROC_PID_INO);
- if (filldir(dirent, "..", 2, 1, ino) < 0)
+ if (filldir(dirent, DT_DIR, "..", 2, 1, ino) < 0)
                                 goto out;
                         filp->f_pos++;
                 default:
@@ -517,7 +518,7 @@
                                 } while (i);
 
                                 ino = fake_ino(pid, PROC_PID_FD_DIR + fd);
- if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino) < 0)
+ if (filldir(dirent, DT_LNK, buf+j, NUMBUF-j, fd+2, ino) < 0)
                                         break;
 
                         }
@@ -540,13 +541,13 @@
         i = filp->f_pos;
         switch (i) {
                 case 0:
- if (filldir(dirent, ".", 1, i, inode->i_ino) < 0)
+ if (filldir(dirent, DT_DIR, ".", 1, i, inode->i_ino) < 0)
                                 return 0;
                         i++;
                         filp->f_pos++;
                         /* fall through */
                 case 1:
- if (filldir(dirent, "..", 2, i, PROC_ROOT_INO) < 0)
+ if (filldir(dirent, DT_DIR, "..", 2, i, PROC_ROOT_INO) < 0)
                                 return 0;
                         i++;
                         filp->f_pos++;
@@ -557,7 +558,7 @@
                                 return 1;
                         p = base_stuff + i;
                         while (p->name) {
- if (filldir(dirent, p->name, p->len, filp->f_pos, fake_ino(pid, p->type)) < 0)
+ if (filldir(dirent, IFTODT (p->mode), p->name, p->len, filp->f_pos, fake_ino(pid, p->type)) < 0)
                                         return 0;
                                 filp->f_pos++;
                                 p++;
@@ -936,7 +937,7 @@
                         pid /= 10;
                 } while (pid);
 
- if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino) < 0)
+ if (filldir(dirent, DT_DIR, buf+j, PROC_NUMBUF-j, filp->f_pos, ino) < 0)
                         break;
                 filp->f_pos++;
         }
diff -u linux-2.3/fs/proc/generic.c.d_type linux-2.3/fs/proc/generic.c
--- linux-2.3/fs/proc/generic.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/proc/generic.c Sun Mar 5 21:04:34 2000
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
+#include <linux/dirent.h>
 #include <asm/bitops.h>
 
 static ssize_t proc_file_read(struct file * file, char * buf,
@@ -292,13 +293,13 @@
         i = filp->f_pos;
         switch (i) {
                 case 0:
- if (filldir(dirent, ".", 1, i, ino) < 0)
+ if (filldir(dirent, DT_DIR, ".", 1, i, ino) < 0)
                                 return 0;
                         i++;
                         filp->f_pos++;
                         /* fall through */
                 case 1:
- if (filldir(dirent, "..", 2, i,
+ if (filldir(dirent, DT_DIR, "..", 2, i,
                                     filp->f_dentry->d_parent->d_inode->i_ino
                                    ) < 0)
                                 return 0;
@@ -318,7 +319,7 @@
                         }
 
                         do {
- if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino) < 0)
+ if (filldir(dirent, IFTODT (de->mode), de->name, de->namelen, filp->f_pos, de->low_ino) < 0)
                                         return 0;
                                 filp->f_pos++;
                                 de = de->next;
diff -u linux-2.3/fs/qnx4/dir.c.d_type linux-2.3/fs/qnx4/dir.c
--- linux-2.3/fs/qnx4/dir.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/qnx4/dir.c Sun Mar 5 21:04:34 2000
@@ -17,6 +17,7 @@
 #include <linux/fs.h>
 #include <linux/qnx4_fs.h>
 #include <linux/stat.h>
+#include <linux/dirent.h>
 
 #include <asm/segment.h>
 
@@ -62,7 +63,7 @@
                                                         QNX4_INODES_PER_BLOCK +
                                                         le->dl_inode_ndx;
                                         }
- if (filldir(dirent, de->di_fname, size, filp->f_pos, ino) < 0) {
+ if (filldir(dirent, IFTODT (de->di_mode), de->di_fname, size, filp->f_pos, ino) < 0) {
                                                 brelse(bh);
                                                 return 0;
                                         }
diff -u linux-2.3/fs/readdir.c.d_type linux-2.3/fs/readdir.c
--- linux-2.3/fs/readdir.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/readdir.c Sun Mar 5 21:04:34 2000
@@ -9,6 +9,7 @@
 #include <linux/errno.h>
 #include <linux/stat.h>
 #include <linux/file.h>
+#include <linux/dirent.h>
 #include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
@@ -24,22 +25,15 @@
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
 #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
 
-struct old_linux_dirent {
- unsigned long d_ino;
- unsigned long d_offset;
- unsigned short d_namlen;
- char d_name[1];
-};
-
 struct readdir_callback {
- struct old_linux_dirent * dirent;
+ struct readdir_dirent * dirent;
         int count;
 };
 
-static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
+static int fillonedir(void * __buf, unsigned char type, const char * name, int namlen, off_t offset, ino_t ino)
 {
         struct readdir_callback * buf = (struct readdir_callback *) __buf;
- struct old_linux_dirent * dirent;
+ struct readdir_dirent * dirent;
 
         if (buf->count)
                 return -EINVAL;
@@ -104,26 +98,21 @@
  * New, all-improved, singing, dancing, iBCS2-compliant getdents()
  * interface.
  */
-struct linux_dirent {
- unsigned long d_ino;
- unsigned long d_off;
- unsigned short d_reclen;
- char d_name[1];
-};
-
 struct getdents_callback {
- struct linux_dirent * current_dir;
- struct linux_dirent * previous;
+ struct getdents_dirent * current_dir;
+ struct getdents_dirent * previous;
         int count;
         int error;
 };
 
-static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
+static int filldir(void * __buf, unsigned char type, const char * name, int namlen, off_t offset, ino_t ino)
 {
- struct linux_dirent * dirent;
+ struct getdents_dirent * dirent;
         struct getdents_callback * buf = (struct getdents_callback *) __buf;
         int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
 
+ if (type != DT_UNKNOWN)
+ reclen += sizeof(long);
         buf->error = -EINVAL; /* only used if we fail.. */
         if (reclen > buf->count)
                 return -EINVAL;
@@ -136,6 +125,17 @@
         put_user(reclen, &dirent->d_reclen);
         copy_to_user(dirent->d_name, name, namlen);
         put_user(0, dirent->d_name + namlen);
+ if (type != DT_UNKNOWN) {
+ /*
+ * By storing a 0 at reclen-1-sizeof(long), we clearly
+ * distinguish this record from one which doesn't have
+ * a type. It is also binary backward compatible.
+ */
+ put_user(0, (unsigned char *) dirent + reclen - (1 + sizeof (long)));
+ put_user(type, (unsigned char *) dirent + reclen - 2);
+ put_user(0, (unsigned char *) dirent + reclen - 1);
+ }
+
         ((char *) dirent) += reclen;
         buf->current_dir = dirent;
         buf->count -= reclen;
@@ -147,7 +147,7 @@
         struct file * file;
         struct dentry * dentry;
         struct inode * inode;
- struct linux_dirent * lastdirent;
+ struct getdents_dirent * lastdirent;
         struct getdents_callback buf;
         int error;
 
@@ -165,7 +165,7 @@
         if (!inode)
                 goto out_putf;
 
- buf.current_dir = (struct linux_dirent *) dirent;
+ buf.current_dir = (struct getdents_dirent *) dirent;
         buf.previous = NULL;
         buf.count = count;
         buf.error = 0;
diff -u linux-2.3/fs/romfs/inode.c.d_type linux-2.3/fs/romfs/inode.c
--- linux-2.3/fs/romfs/inode.c.d_type Sun Mar 5 20:59:03 2000
+++ linux-2.3/fs/romfs/inode.c Sun Mar 5 21:04:34 2000
@@ -73,6 +73,7 @@
 #include <linux/locks.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
+#include <linux/dirent.h>
 
 #include <asm/uaccess.h>
 
@@ -273,6 +274,12 @@
         return res;
 }
 
+static mode_t romfs_modemap[] =
+{
+ 0, S_IFDIR+0644, S_IFREG+0644, S_IFLNK+0777,
+ S_IFBLK+0600, S_IFCHR+0600, S_IFSOCK+0644, S_IFIFO+0644
+};
+
 static int
 romfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
@@ -280,6 +287,7 @@
         struct romfs_inode ri;
         unsigned long offset, maxoff;
         int j, ino, nextfh;
+ unsigned char type;
         int stored = 0;
         char fsname[ROMFS_MAXFN]; /* XXX dynamic? */
 
@@ -317,7 +325,8 @@
                 nextfh = ntohl(ri.next);
                 if ((nextfh & ROMFH_TYPE) == ROMFH_HRD)
                         ino = ntohl(ri.spec);
- if (filldir(dirent, fsname, j, offset, ino) < 0) {
+ type = IFTODT (romfs_modemap [nextfh & ROMFH_TYPE]);
+ if (filldir(dirent, type, fsname, j, offset, ino) < 0) {
                         return stored;
                 }
                 stored++;
@@ -457,12 +466,6 @@
 
 static struct inode_operations romfs_dir_inode_operations = {
         lookup: romfs_lookup,
-};
-
-static mode_t romfs_modemap[] =
-{
- 0, S_IFDIR+0644, S_IFREG+0644, S_IFLNK+0777,
- S_IFBLK+0600, S_IFCHR+0600, S_IFSOCK+0644, S_IFIFO+0644
 };
 
 static void
diff -u linux-2.3/fs/smbfs/dir.c.d_type linux-2.3/fs/smbfs/dir.c
--- linux-2.3/fs/smbfs/dir.c.d_type Sun Mar 5 20:59:04 2000
+++ linux-2.3/fs/smbfs/dir.c Sun Mar 5 21:04:34 2000
@@ -9,6 +9,7 @@
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
+#include <linux/dirent.h>
 
 #include <linux/smb_fs.h>
 #include <linux/smbno.h>
@@ -88,11 +89,11 @@
         switch ((unsigned int) filp->f_pos)
         {
         case 0:
- if (filldir(dirent, ".", 1, 0, dir->i_ino) < 0)
+ if (filldir(dirent, DT_DIR, ".", 1, 0, dir->i_ino) < 0)
                         goto out_free;
                 filp->f_pos = 1;
         case 1:
- if (filldir(dirent, "..", 2, 1,
+ if (filldir(dirent, DT_DIR, "..", 2, 1,
                                 dentry->d_parent->d_inode->i_ino) < 0)
                         goto out_free;
                 filp->f_pos = 2;
@@ -117,7 +118,7 @@
                                 entry->ino = smb_invent_inos(1);
                 }
 
- if (filldir(dirent, entry->name, entry->len,
+ if (filldir(dirent, DT_UNKNOWN, entry->name, entry->len,
                                     filp->f_pos, entry->ino) < 0)
                         break;
                 filp->f_pos += 1;
diff -u linux-2.3/fs/sysv/dir.c.d_type linux-2.3/fs/sysv/dir.c
--- linux-2.3/fs/sysv/dir.c.d_type Sun Mar 5 20:59:04 2000
+++ linux-2.3/fs/sysv/dir.c Sun Mar 5 21:04:34 2000
@@ -18,6 +18,7 @@
 #include <linux/sysv_fs.h>
 #include <linux/stat.h>
 #include <linux/string.h>
+#include <linux/dirent.h>
 
 static int sysv_readdir(struct file *, void *, filldir_t);
 
@@ -61,7 +62,7 @@
                                                inode->i_ino, (off_t) filp->f_pos, sde.inode);
 
                                 i = strnlen(sde.name, SYSV_NAMELEN);
- if (filldir(dirent, sde.name, i, filp->f_pos, sde.inode) < 0) {
+ if (filldir(dirent, DT_UNKNOWN, sde.name, i, filp->f_pos, sde.inode) < 0) {
                                         brelse(bh);
                                         return 0;
                                 }
diff -u linux-2.3/fs/udf/dir.c.d_type linux-2.3/fs/udf/dir.c
--- linux-2.3/fs/udf/dir.c.d_type Sun Mar 5 21:01:59 2000
+++ linux-2.3/fs/udf/dir.c Sun Mar 5 21:04:37 2000
@@ -40,6 +40,7 @@
 #include <linux/mm.h>
 #include <linux/malloc.h>
 #include <linux/udf_fs.h>
+#include <linux/dirent.h>
 #endif
 
 /* Prototypes for file operations */
@@ -94,7 +95,7 @@
 
         if ( filp->f_pos == 0 )
         {
- if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino))
+ if (filldir(dirent, DT_DIR, ".", 1, filp->f_pos, dir->i_ino))
                         return 0;
         }
  
@@ -111,6 +112,7 @@
         struct FileIdentDesc cfi;
         int block, iblock;
         loff_t nf_pos = filp->f_pos;
+ unsigned char ftype;
         int flen;
         char fname[255];
         char *nameptr;
@@ -202,11 +204,15 @@
                                 continue;
                 }
 
+ ftype = DT_DIR;
+ if ( (cfi.fileCharacteristics & FILE_DIRECTORY) == 0 )
+ ftype = DT_UNKNOWN;
+
                 iblock = udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0);
  
                  if (!lfi) /* parent directory */
                  {
- if (filldir(dirent, "..", 2, filp->f_pos, filp->f_dentry->d_parent->d_inode->i_ino))
+ if (filldir(dirent, DT_DIR, "..", 2, filp->f_pos, filp->f_dentry->d_parent->d_inode->i_ino))
                         {
                                 if (fibh.sbh != fibh.ebh)
                                         udf_release_data(fibh.ebh);
@@ -219,7 +225,7 @@
                 {
                         if ((flen = udf_get_filename(nameptr, fname, lfi)))
                         {
- if (filldir(dirent, fname, flen, filp->f_pos, iblock))
+ if (filldir(dirent, ftype, fname, flen, filp->f_pos, iblock))
                                 {
                                         if (fibh.sbh != fibh.ebh)
                                                 udf_release_data(fibh.ebh);
diff -u linux-2.3/fs/ufs/dir.c.d_type linux-2.3/fs/ufs/dir.c
--- linux-2.3/fs/ufs/dir.c.d_type Sun Mar 5 20:59:04 2000
+++ linux-2.3/fs/ufs/dir.c Sun Mar 5 21:04:37 2000
@@ -15,6 +15,7 @@
 
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
+#include <linux/dirent.h>
 
 #include "swab.h"
 #include "util.h"
@@ -125,7 +126,8 @@
 
                                 UFSD(("filldir(%s,%u)\n", de->d_name, SWAB32(de->d_ino)))
                                 UFSD(("namlen %u\n", ufs_get_de_namlen(de)))
- error = filldir(dirent, de->d_name, ufs_get_de_namlen(de),
+ error = filldir(dirent, ufs_get_de_type (de),
+ de->d_name, ufs_get_de_namlen(de),
                                                 filp->f_pos, SWAB32(de->d_ino));
                                 if (error)
                                         break;
diff -u linux-2.3/fs/ufs/util.h.d_type linux-2.3/fs/ufs/util.h
--- linux-2.3/fs/ufs/util.h.d_type Sun Mar 5 20:59:04 2000
+++ linux-2.3/fs/ufs/util.h Sun Mar 5 21:04:37 2000
@@ -126,6 +126,11 @@
         ? (de->d_u.d_namlen = SWAB16(value)) \
         : (de->d_u.d_44.d_namlen = value))
 
+#define ufs_get_de_type(de) \
+ (((flags & UFS_DE_MASK) == UFS_DE_OLD) \
+ ? DT_UNKNOWN \
+ : de->d_u.d_44.d_type)
+
 #define ufs_set_de_type(de,mode) _ufs_set_de_type_(de,mode,flags,swab)
 static inline void _ufs_set_de_type_(struct ufs_dir_entry * de, int mode,
         unsigned flags, unsigned swab)
diff -u linux-2.3/fs/umsdos/dir.c.d_type linux-2.3/fs/umsdos/dir.c
--- linux-2.3/fs/umsdos/dir.c.d_type Sun Mar 5 20:59:04 2000
+++ linux-2.3/fs/umsdos/dir.c Sun Mar 5 21:04:37 2000
@@ -16,6 +16,7 @@
 #include <linux/limits.h>
 #include <linux/umsdos_fs.h>
 #include <linux/malloc.h>
+#include <linux/dirent.h>
 
 #include <asm/uaccess.h>
 
@@ -66,6 +67,7 @@
  */
 
 static int umsdos_dir_once ( void *buf,
+ unsigned char type,
                                 const char *name,
                                 int len,
                                 off_t offset,
@@ -77,7 +79,7 @@
         if (d->count == 0) {
                 PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n",
                         len, name, offset));
- ret = d->filldir (d->dirbuf, name, len, offset, ino);
+ ret = d->filldir (d->dirbuf, type, name, len, offset, ino);
                 d->stop = ret < 0;
                 d->count = 1;
         }
@@ -122,7 +124,7 @@
                  */
 
                 Printk ((KERN_WARNING "umsdos_readdir_x: pseudo_root thing UMSDOS_SPECIAL_DIRFPOS\n"));
- if (filldir (dirbuf, "DOS", 3,
+ if (filldir (dirbuf, DT_DIR, "DOS", 3,
                                 UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO) == 0) {
                         filp->f_pos++;
                 }
@@ -241,7 +243,8 @@
                  */
                 if (inode != pseudo_root &&
                     (internal_read || !(entry.flags & UMSDOS_HIDDEN))) {
- if (filldir (dirbuf, entry.name, entry.name_len,
+ if (filldir (dirbuf, IFTODT (entry.mode),
+ entry.name, entry.name_len,
                                  cur_f_pos, inode->i_ino) < 0) {
                                 new_filp.f_pos = cur_f_pos;
                         }
diff -u linux-2.3/fs/umsdos/ioctl.c.d_type linux-2.3/fs/umsdos/ioctl.c
--- linux-2.3/fs/umsdos/ioctl.c.d_type Sun Mar 5 20:59:04 2000
+++ linux-2.3/fs/umsdos/ioctl.c Sun Mar 5 21:04:37 2000
@@ -14,9 +14,10 @@
 #include <linux/fs.h>
 #include <linux/msdos_fs.h>
 #include <linux/umsdos_fs.h>
+#include <linux/dirent.h>
 
 struct UMSDOS_DIR_ONCE {
- struct dirent *ent;
+ struct getdents_dirent *ent;
         int count;
 };
 
@@ -26,6 +27,7 @@
  */
 static int umsdos_ioctl_fill (
                                      void *buf,
+ unsigned char type,
                                      const char *name,
                                      int name_len,
                                      off_t offset,
diff -u linux-2.3/fs/umsdos/rdir.c.d_type linux-2.3/fs/umsdos/rdir.c
--- linux-2.3/fs/umsdos/rdir.c.d_type Sun Mar 5 20:59:04 2000
+++ linux-2.3/fs/umsdos/rdir.c Sun Mar 5 21:04:37 2000
@@ -15,6 +15,7 @@
 #include <linux/limits.h>
 #include <linux/umsdos_fs.h>
 #include <linux/malloc.h>
+#include <linux/dirent.h>
 
 #include <asm/uaccess.h>
 
@@ -30,6 +31,7 @@
 };
 
 static int rdir_filldir ( void *buf,
+ unsigned char type,
                                 const char *name,
                                 int name_len,
                                 off_t offset,
@@ -48,11 +50,11 @@
                                 /* Make sure the .. entry points back to the pseudo_root */
                                 ino = pseudo_root->i_ino;
                         }
- ret = d->filldir (d->dirbuf, name, name_len, offset, ino);
+ ret = d->filldir (d->dirbuf, type, name, name_len, offset, ino);
                 }
         } else {
                 /* Any DOS directory */
- ret = d->filldir (d->dirbuf, name, name_len, offset, ino);
+ ret = d->filldir (d->dirbuf, type, name, name_len, offset, ino);
         }
         return ret;
 }
diff -u linux-2.3/include/linux/dirent.h.d_type linux-2.3/include/linux/dirent.h
--- linux-2.3/include/linux/dirent.h.d_type Sun Mar 5 20:59:04 2000
+++ linux-2.3/include/linux/dirent.h Sun Mar 5 21:04:37 2000
@@ -1,11 +1,66 @@
+/*
+ * API for reading directories.
+ *
+ * Changed dirent types to match what we've always returned
+ * and DT_* support added by Jamie Lokier, 1999-2000.
+ */
+
 #ifndef _LINUX_DIRENT_H
 #define _LINUX_DIRENT_H
 
-struct dirent {
- long d_ino;
- __kernel_off_t d_off;
+/*
+ * Structure returned by sys_readdir.
+ */
+struct readdir_dirent {
+ unsigned long d_ino;
+ unsigned long d_offset;
+ unsigned short d_namlen;
+ char d_name[256]; /* NAME_MAX + 1. */
+};
+
+/*
+ * Structure returned by sys_getdents.
+ */
+struct getdents_dirent {
+ unsigned long d_ino;
+ unsigned long d_off;
         unsigned short d_reclen;
- char d_name[256]; /* We must not include limits.h! */
+ char d_name[256]; /* NAME_MAX + 1. */
 };
 
-#endif
+/*
+ * Backward compatibility (umsdos tools, libc5).
+ */
+#define dirent getdents_dirent
+
+/*
+ * Returns the "d_type" value from a struct getdents_dirent. This is
+ * backward compatible with older kernels: it will return DT_UNKNOWN.
+ * It is also forward compatible: more information can be added in future.
+ */
+#define GETDENTS_DIRENT_D_TYPE(dent) \
+ (((dent)->d_reclen > ((dent)->d_name - (char *) (dent) + sizeof (long)) \
+ && !*((unsigned char *) (dent) + (dent)->d_reclen - (1 + sizeof (long)))) \
+ ? *((unsigned char *) (dent) + (dent)->d_reclen - 2) : DT_UNKNOWN)
+
+/*
+ * "d_type" type code. DT_UNKNOWN when no type is available.
+ * These values are quite standard.
+ */
+#define DT_UNKNOWN 0
+#define DT_FIFO 1
+#define DT_CHR 2
+#define DT_DIR 4
+#define DT_BLK 6
+#define DT_REG 8
+#define DT_LNK 10
+#define DT_SOCK 12
+#define DT_WHT 14
+
+/*
+ * Convert to and from S_IFREG etc.
+ */
+#define DTTOIF(dirtype) ((dirtype) << 12)
+#define IFTODT(mode) (((mode) & 0170000) >> 12)
+
+#endif /* _LINUX_DIRENT_H */
diff -u linux-2.3/include/linux/fs.h.d_type linux-2.3/include/linux/fs.h
--- linux-2.3/include/linux/fs.h.d_type Sun Mar 5 20:59:04 2000
+++ linux-2.3/include/linux/fs.h Sun Mar 5 21:14:39 2000
@@ -640,7 +640,7 @@
  * This allows the kernel to read directories into kernel space or
  * to have different dirent layouts depending on the binary type.
  */
-typedef int (*filldir_t)(void *, const char *, int, off_t, ino_t);
+typedef int (*filldir_t)(void *, unsigned char, const char *, int, off_t, ino_t);
 
 struct block_device_operations {
         int (*open) (struct inode *, struct file *);
diff -u linux-2.3/include/linux/iso_fs.h.d_type linux-2.3/include/linux/iso_fs.h
--- linux-2.3/include/linux/iso_fs.h.d_type Sun Mar 5 20:59:04 2000
+++ linux-2.3/include/linux/iso_fs.h Sun Mar 5 21:04:37 2000
@@ -176,7 +176,7 @@
 extern int iso_date(char *, int);
 
 extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *);
-extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *);
+extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *, unsigned char *);
 
 extern int find_rock_ridge_relocation(struct iso_directory_record *, struct inode *);
 
diff -u linux-2.3/include/linux/msdos_fs.h.d_type linux-2.3/include/linux/msdos_fs.h
--- linux-2.3/include/linux/msdos_fs.h.d_type Sun Mar 5 20:59:04 2000
+++ linux-2.3/include/linux/msdos_fs.h Sun Mar 5 21:25:03 2000
@@ -85,8 +85,8 @@
 /*
  * ioctl commands
  */
-#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
-#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
+#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct getdents_dirent [2])
+#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct getdents_dirent [2])
 
 /*
  * Conversion from and to little-endian byte order. (no-op on i386/i486)
diff -u linux-2.3/include/linux/nfsd/nfsd.h.d_type linux-2.3/include/linux/nfsd/nfsd.h
--- linux-2.3/include/linux/nfsd/nfsd.h.d_type Sun Mar 5 21:02:06 2000
+++ linux-2.3/include/linux/nfsd/nfsd.h Sun Mar 5 21:04:37 2000
@@ -56,8 +56,8 @@
         char eob; /* end of buffer */
         char dotonly;
 };
-typedef int (*encode_dent_fn)(struct readdir_cd *, const char *,
- int, off_t, ino_t);
+typedef int (*encode_dent_fn)(struct readdir_cd *, unsigned char,
+ const char *, int, off_t, ino_t);
 typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int);
 
 /*
diff -u linux-2.3/include/linux/nfsd/xdr.h.d_type linux-2.3/include/linux/nfsd/xdr.h
--- linux-2.3/include/linux/nfsd/xdr.h.d_type Sun Mar 5 20:59:04 2000
+++ linux-2.3/include/linux/nfsd/xdr.h Sun Mar 5 21:04:37 2000
@@ -151,8 +151,8 @@
 int nfssvc_encode_statfsres(struct svc_rqst *, u32 *, struct nfsd_statfsres *);
 int nfssvc_encode_readdirres(struct svc_rqst *, u32 *, struct nfsd_readdirres *);
 
-int nfssvc_encode_entry(struct readdir_cd *, const char *name,
- int namlen, off_t offset, ino_t ino);
+int nfssvc_encode_entry(struct readdir_cd *, unsigned char type,
+ const char *name, int namlen, off_t offset, ino_t ino);
 
 int nfssvc_release_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *);
 
diff -u linux-2.3/include/linux/nfsd/xdr3.h.d_type linux-2.3/include/linux/nfsd/xdr3.h
--- linux-2.3/include/linux/nfsd/xdr3.h.d_type Sun Mar 5 20:59:04 2000
+++ linux-2.3/include/linux/nfsd/xdr3.h Sun Mar 5 21:04:37 2000
@@ -291,10 +291,12 @@
                                 struct nfsd3_attrstat *);
 int nfs3svc_release_fhandle2(struct svc_rqst *, u32 *,
                                 struct nfsd3_fhandle_pair *);
-int nfs3svc_encode_entry(struct readdir_cd *, const char *name,
- int namlen, off_t offset, ino_t ino);
-int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name,
- int namlen, off_t offset, ino_t ino);
+int nfs3svc_encode_entry(struct readdir_cd *, unsigned char type,
+ const char *name, int namlen,
+ off_t offset, ino_t ino);
+int nfs3svc_encode_entry_plus(struct readdir_cd *, unsigned char type,
+ const char *name, int namlen,
+ off_t offset, ino_t ino);
 
 
 #endif /* _LINUX_NFSD_XDR3_H */
diff -u linux-2.3/include/linux/umsdos_fs.h.d_type linux-2.3/include/linux/umsdos_fs.h
--- linux-2.3/include/linux/umsdos_fs.h.d_type Sun Mar 5 20:59:04 2000
+++ linux-2.3/include/linux/umsdos_fs.h Sun Mar 5 21:25:03 2000
@@ -127,7 +127,7 @@
 #define UMSDOS_RENAME_DOS _IO(0x04,220) /* rename a file/directory in the DOS
                                                  * directory only */
 struct umsdos_ioctl {
- struct dirent dos_dirent;
+ struct getdents_dirent dos_dirent;
         struct umsdos_dirent umsdos_dirent;
         /* The following structure is used to exchange some data
          * with utilities (umsdos_progs/util/umsdosio.c). The first

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Mar 07 2000 - 21:00:19 EST