bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

fts: expose dirent.d_type data when possible


From: Jim Meyering
Subject: fts: expose dirent.d_type data when possible
Date: Sat, 29 Nov 2008 12:00:34 +0100

As discussed here,
  http://lists.gnu.org/archive/html/bug-gnulib/2008-11/index.html

I've just pushed the following:
(one minor difference: updated comments in fts_.h, too)

>From 3270695f352a7ff69ba58424329ccbb0f91b47f3 Mon Sep 17 00:00:00 2001
From: Jim Meyering <address@hidden>
Date: Fri, 28 Nov 2008 18:40:08 +0100
Subject: [PATCH] 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.
---
 ChangeLog  |   15 ++++++++++-
 lib/fts.c  |   80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/fts_.h |    5 +++-
 3 files changed, 98 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 583e4cb..9a4ae1f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2008-11-29  Jim Meyering  <address@hidden>
+
+       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  <address@hidden>

        * lib/sys_time.in.h: Add extern "C" block for C++.  Suggested by
@@ -16,7 +29,7 @@
        Reported by Albert Chin <address@hidden>.

 2008-11-18  Alexandre Duret-Lutz  <address@hidden>
-            Bruno Haible  <address@hidden>
+           Bruno Haible  <address@hidden>

        * 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
diff --git a/lib/fts.c b/lib/fts.c
index 2054864..35def60 100644
--- a/lib/fts.c
+++ b/lib/fts.c
@@ -84,9 +84,31 @@ static char sccsid[] = "@(#)fts.c    8.6 (Berkeley) 8/14/94";
 # 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
@@ -989,6 +1011,61 @@ fts_compare_ino (struct _ftsent const **a, struct _ftsent 
const **b)
          : 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
@@ -1218,6 +1295,9 @@ mem1:                             saved_errno = errno;
                                          && 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));
diff --git a/lib/fts_.h b/lib/fts_.h
index 0fb0f99..b9554f2 100644
--- a/lib/fts_.h
+++ b/lib/fts_.h
@@ -131,7 +131,10 @@ typedef struct {
      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 */
--
1.6.0.4.1101.g642f8




reply via email to

[Prev in Thread] Current Thread [Next in Thread]