Date: Tue, 22 May 2001 18:24:03 +0300 From: "Eli Zaretskii" Sender: halo1 AT zahav DOT net DOT il To: djgpp-workers AT delorie DOT com Message-Id: <1659-Tue22May2001182402+0300-eliz@is.elta.co.il> X-Mailer: Emacs 20.6 (via feedmail 8.3.emacs20_6 I) and Blat ver 1.8.9 Subject: Add d_type member to struct dirent Reply-To: djgpp-workers AT delorie DOT com Please see if the changes below look good. Fileutils 4.1 looks for this feature and if it is available, `ls' runs much faster (or so we are told in NEWS). Perhaps someone who have Fileutils 4.1 on their disk could actually test this (I didn't have time). The diffs are against stock v2.03, so you might need to tweak them a bit for the CVS. They do mean to support symlinks, though, so please see if the design decision I made in that respect makes sense. Thanks in advance for any comments. Btw, Richard, is it perhaps a good idea to retrofit your changes to Filutils to v4.1? If the changes between 4.0 and 4.1 are not large, this will gain us the latest version, when the testing is finished. --- src/libc/posix/dirent/readdir.c~0 Sun Nov 15 08:47:22 1998 +++ src/libc/posix/dirent/readdir.c Tue May 22 09:33:12 2001 @@ -26,6 +26,10 @@ readdir(DIR *dir) else strcpy(dir->de.d_name, ".."); dir->de.d_namlen = strlen(dir->de.d_name); + if ((__opendir_flags & __OPENDIR_NO_D_TYPE) == 0) + dir->de.d_type = DT_DIR; + else + dir->de.d_type = DT_UNKNOWN; return &(dir->de); } @@ -71,6 +75,27 @@ readdir(DIR *dir) } strcpy(dir->de.d_name, dir->ff.ff_name); dir->de.d_namlen = strlen(dir->de.d_name); + if ((__opendir_flags & __OPENDIR_NO_D_TYPE) == 0) + { + unsigned char attrib = dir->ff.ff_attrib; + + if ((attrib & FA_DIREC) == FA_DIREC) + dir->de.d_type = DT_DIR; + else if ((attrib & FA_LABEL) == FA_LABEL) + dir->de.d_type = DT_LABEL; + else if ((attrib & 0x40) == 0x40) + dir->de.d_type = DT_CHR; + else if (dir->ff.ff_fsize == 510) + /* This could or could not be a symlink. Since we don't want + to pay the price of finding out, we return DT_UNKNOWN, and + the application is supposed to stat the file in response. */ + dir->de.d_type = DT_UNKNOWN; + /* FIXME: anything else DOS can return? */ + else + dir->de.d_type = DT_REG; + } + else + dir->de.d_type = DT_UNKNOWN; return &dir->de; } --- src/libc/posix/dirent/readdir.t~0 Sun Nov 15 08:47:22 1998 +++ src/libc/posix/dirent/readdir.txh Tue May 22 09:46:22 2001 @@ -17,6 +17,7 @@ this format: struct dirent @{ unsigned short d_namlen; /* The length of the name (like strlen) */ char d_name[MAXNAMLEN+1]; /* The name */ + mode_t d_type; /* The file's type */ @}; @end example @@ -24,6 +25,38 @@ Note that some directory entries might b depending on the bits set in the global variable @code{__opendir_flags}. @xref{opendir, __opendir_flags, opendir}. +The possible values of the @code{d_type} member are: + +@table @code +@item DT_REG +This is a regular file. +@item DT_BLK +The file is a block device. +@item DT_CHR +The file is a character device. +@item DT_DIR +The file is a directory. +@item DT_FIFO +This is a pipe (never happens in DJGPP). +@item DT_LABEL +The file is a volume label. +@item DT_LNK +The file is a symlink. +@item DT_SOCK +The file is a socket. +@item DT_UNKNOWN +The file's type is unknown. This value is put into the @code{d_type} +member if the exact file's type is too expensive to compute (one notable +case is when the file could be a symlink). If the +@code{__OPENDIR_NO_D_TYPE} flag is set in the global variable +@code{__opendir_flags}, @emph{all} files get marked with +@code{DT_UNKNOWN}. +@end table + +The macro @code{DTTOIF} (@pxref{DTTOIF}) can be used to convert the +@code{d_type} member to the equivalent value of the @code{st_mode} +member of @code{struct stat}, see @ref{stat}. + @subheading Return Value A pointer to a static buffer that is overwritten with each call. @@ -31,6 +64,7 @@ A pointer to a static buffer that is ove @subheading Portability @port-note posix The @code{__opendir_flags} variable is DJGPP-specific. +@port-note posix The @code{d_type} member is an extension available on some systems such as GNU/Linux. @portability !ansi, posix @subheading Example @@ -43,3 +77,32 @@ while (de = readdir(d)) closedir(d); @end example +@c ------------------------------------------------- +@node DTTOIF, file system +@subheading Syntax + +@example +#include + +struct dirent *de; +mode_t file_mode = DTTOIF(de->d_type) +@end example + +@subheading Description + +This macro converts the @code{d_type} member of a @code{struct dirent} +variable to an equivalent value of the @code{st_mode} member of a +@code{struct stat} variable (@pxref{stat}). + +Note that the access rights are not set in the result returned by this +macro. Only the file-type information is copied. + +@subheading Return Value + +The file's mode bits are returned. If the argument has the value +@code{DT_UNKNOWN}, the result will be @code{S_IFREG}. + +@subheading Portability + +@port-note posix This macro is available on systems which support the @code{d_type} member in @code{struct dirent}. +@portability !ansi, !posix --- src/libc/posix/dirent/opendir.t~0 Sun Nov 15 08:47:22 1998 +++ src/libc/posix/dirent/opendir.txh Tue May 22 09:50:20 2001 @@ -21,7 +21,6 @@ following values to control the operatio @table @code @item __OPENDIR_PRESERVE_CASE - Do not change the case of files to lower case. Just in case Micros*ft decides to support case-sensitive file systems some day. @@ -32,20 +31,21 @@ other ways of achieving this and for mor automatic letter-case conversion by DJGPP library functions. @item __OPENDIR_NO_HIDDEN - Do not include hidden files and directories in the search. By default, all files and directories are included. @item __OPENDIR_FIND_HIDDEN - Provided for back-compatibility with previous DJGPP versions, where hidden files and directories were by default skipped. In versions 2.02 and later, this flag has no effect. @item __OPENDIR_FIND_LABEL - Include volume labels in the search. By default, these are skipped. +@item __OPENDIR_NO_D_TYPE +Do not compute the @code{d_type} member of @code{struct dirent}. If +this flag is set, all files will get @code{DT_UNKNOWN} in the +@code{d_type} member. By default, this flag is reset. @xref{readdir}. @end table You can simply put @samp{int __opendir_flags = ...;} in your code. The --- include/dirent.h~0 Sun Nov 15 08:48:38 1998 +++ include/dirent.h Tue May 22 09:01:16 2001 @@ -10,14 +10,28 @@ #ifndef __dj_ENFORCE_ANSI_FREESTANDING #ifndef __STRICT_ANSI__ +#include /* Definition of DIR requires many other headers; not included here to avoid namespace pollution. */ typedef struct __dj_DIR DIR; +#define DT_REG 0x1 +#define DT_BLK 0x2 +#define DT_CHR 0x3 +#define DT_DIR 0x4 +#define DT_FIFO 0x5 +#define DT_LABEL 0x6 +#define DT_LNK 0x7 +#define DT_SOCK 0x8 +#define DT_UNKNOWN 0xf + +#define DTTOIF(dt) ((dt) == DT_UNKNOWN ? 0 : (dt) - 1) + struct dirent { char d_namlen; char d_name[256]; + mode_t d_type; }; int closedir(DIR *dirp); @@ -32,6 +46,7 @@ #define __OPENDIR_FIND_HIDDEN 0002 /* ignored; on by default */ #define __OPENDIR_FIND_LABEL 0004 #define __OPENDIR_NO_HIDDEN 0x08 /* NOT 0002 for back-compatibility */ +#define __OPENDIR_NO_D_TYPE 0x10 void seekdir(DIR *_dir, long _loc); long telldir(DIR *_dir);