+2008-11-29 Jim Meyering <meyering@redhat.com>
+
+ fts: provide dirent.d_type via FTSENT.fts_statp, when possible
+ * lib/fts.c (D_TYPE): Define.
+ (DT_UNKNOWN, DT_BLK, DT_CHR) [HAVE_STRUCT_DIRENT_D_TYPE]: Define.
+ (DT_DIR, DT_FIFO, DT_LNK, DT_REG, DT_SOCK): Likewise.
+ (s_ifmt_shift_bits): New function.
+ (set_stat_type): New function.
+ (fts_build): When not calling fts_stat, call set_stat_type
+ to propagate dirent.d_type info to fts_read caller.
+ * lib/fts_.h (FTSENT) [FTS_DEFER_STAT]: Mention that
+ fts_statp->st_mode type information may be valid.
+
2008-11-28 Simon Josefsson <simon@josefsson.org>
* lib/sys_time.in.h: Add extern "C" block for C++. Suggested by
Reported by Albert Chin <bug-gnulib@mlists.thewrittenword.com>.
2008-11-18 Alexandre Duret-Lutz <adl@lrde.epita.fr>
- Bruno Haible <bruno@clisp.org>
+ Bruno Haible <bruno@clisp.org>
* lib/stdint.in.h: Define all type macros so that their expansion is
a single typedef'ed token. Fixes a compilation failure in Boost which
# define DT_IS_KNOWN(d) ((d)->d_type != DT_UNKNOWN)
/* True if the type of the directory entry D must be T. */
# define DT_MUST_BE(d, t) ((d)->d_type == (t))
+# define D_TYPE(d) ((d)->d_type)
#else
# define DT_IS_KNOWN(d) false
# define DT_MUST_BE(d, t) false
+# define D_TYPE(d) DT_UNKNOWN
+
+# undef DT_UNKNOWN
+# define DT_UNKNOWN 0
+
+/* Any nonzero values will do here, so long as they're distinct.
+ Undef any existing macros out of the way. */
+# undef DT_BLK
+# undef DT_CHR
+# undef DT_DIR
+# undef DT_FIFO
+# undef DT_LNK
+# undef DT_REG
+# undef DT_SOCK
+# define DT_BLK 1
+# define DT_CHR 2
+# define DT_DIR 3
+# define DT_FIFO 4
+# define DT_LNK 5
+# define DT_REG 6
+# define DT_SOCK 7
#endif
enum
: b[0]->fts_statp->st_ino < a[0]->fts_statp->st_ino ? 1 : 0);
}
+/* Return the number of bits by which a d_type value must be shifted
+ left in order to put it into the S_IFMT bits of stat.st_mode. */
+static int
+s_ifmt_shift_bits (void)
+{
+ unsigned int v = S_IFMT; /* usually, 0170000 */
+ static const int MultiplyDeBruijnBitPosition[32] =
+ {
+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
+ };
+
+ /* Find the smallest power of two, P (e.g., 0010000) such that P & V == P. */
+ unsigned int p = v ^ (v & (v - 1));
+
+ /* Compute and return r = log2 (p), using code from
+ http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn */
+ return MultiplyDeBruijnBitPosition[(uint32_t) (p * 0x077CB531UL) >> 27];
+}
+
+/* Map the dirent.d_type value, DTYPE, to the corresponding stat.st_mode
+ S_IF* bit and set ST.st_mode, thus clearing all other bits in that field. */
+static void
+set_stat_type (struct stat *st, unsigned int dtype)
+{
+ mode_t type;
+ switch (dtype)
+ {
+ case DT_BLK:
+ type = S_IFBLK;
+ break;
+ case DT_CHR:
+ type = S_IFCHR;
+ break;
+ case DT_DIR:
+ type = S_IFDIR;
+ break;
+ case DT_FIFO:
+ type = S_IFIFO;
+ break;
+ case DT_LNK:
+ type = S_IFLNK;
+ break;
+ case DT_REG:
+ type = S_IFREG;
+ break;
+ case DT_SOCK:
+ type = S_IFSOCK;
+ break;
+ default:
+ type = 0;
+ }
+ st->st_mode = dtype << s_ifmt_shift_bits ();
+}
+
/*
* This is the tricky part -- do not casually change *anything* in here. The
* idea is to build the linked list of entries that are used by fts_children
&& DT_IS_KNOWN(dp)
&& ! DT_MUST_BE(dp, DT_DIR));
p->fts_info = FTS_NSOK;
+ /* Propagate dirent.d_type information back
+ to caller, when possible. */
+ set_stat_type (p->fts_statp, D_TYPE (dp));
fts_set_stat_required(p, !skip_stat);
is_dir = (ISSET(FTS_PHYSICAL) && ISSET(FTS_NOSTAT)
&& DT_MUST_BE(dp, DT_DIR));
Use this flag to make fts_open and fts_read defer the stat/lstat/fststat
of each entry until it is actually processed. However, note that if you
use this option and also specify a comparison function, that function may
- not examine any data via fts_statp. */
+ not examine any data via fts_statp. However, when fts_statp->st_mode is
+ nonzero, the S_IFMT type bits are valid, with mapped dirent.d_type data.
+ Of course, that happens only on file systems that provide useful
+ dirent.d_type data. */
# define FTS_DEFER_STAT 0x0400
# define FTS_OPTIONMASK 0x07ff /* valid user option mask */