bug-glibc
[Top][All Lists]
Advanced

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

ftw must *not* strip trailing slashes


From: Jim Meyering
Subject: ftw must *not* strip trailing slashes
Date: Sat, 25 Jan 2003 21:32:08 +0100

Currently, ftw and nftw strip trailing slashes.
Isn't that contrary to POSIX?  In the section on pathname resolution,
it says that a symlink to a directory that is specified with a trailing
slash must be treated as if `.' were appended.

Accordingly, these commands

  mkdir -p d/x
  ln -s d slink
  a.out slink/

should produce output like this:

  slink/
  slink/x

given that a.out calls nftw/FTW_PHYS|FTW_CHDIR with its command line
argument and the callback simply prints the name of each file.

Without the following change, the program prints only `slink'.

I don't see a simple patch to give the desired behavior,
but using the base_name function (e.g. from coreutils or gnulib),
it's easy:

2003-01-25  Jim Meyering  <address@hidden>

        * ftw.c [_LIBC] (ISSLASH, FILESYSTEM_PREFIX_LEN): Define.
        (base_name): New function.
        (ftw_startup): Don't strip trailing slashes.
        Use base_name to find the offset of the basename.

Index: ftw.c
===================================================================
RCS file: /fetish/cu/lib/ftw.c,v
retrieving revision 1.10
diff -u -p -u -p -r1.10 ftw.c
--- ftw.c       25 Jan 2003 16:44:07 -0000      1.10
+++ ftw.c       25 Jan 2003 18:17:03 -0000
@@ -561,6 +561,51 @@ ftw_dir (struct ftw_data *data, struct S
 }
 
 
+#ifdef _LIBC
+# define ISSLASH(C) ((C) == '/')
+# define FILESYSTEM_PREFIX_LEN(Filename) 0
+#endif
+
+/* In general, we can't use the builtin `basename' function if available,
+   since it has different meanings in different environments.
+   In some environments the builtin `basename' modifies its argument.
+
+   Return the address of the last file name component of NAME.  If
+   NAME has no file name components because it is all slashes, return
+   NAME if it is empty, the address of its last slash otherwise.  */
+
+static char *
+base_name (char const *name)
+{
+  char const *base = name + FILESYSTEM_PREFIX_LEN (name);
+  char const *p;
+
+  for (p = base; *p; p++)
+    {
+      if (ISSLASH (*p))
+       {
+         /* Treat multiple adjacent slashes like a single slash.  */
+         do p++;
+         while (ISSLASH (*p));
+
+         /* If the file name ends in slash, use the trailing slash as
+            the basename if no non-slashes have been found.  */
+         if (! *p)
+           {
+             if (ISSLASH (*base))
+               base = p - 1;
+             break;
+           }
+
+         /* *P is a non-slash preceded by a slash.  */
+         base = p;
+       }
+    }
+
+  return (char *) base;
+}
+
+
 static int
 internal_function
 ftw_startup (const char *dir, int is_nftw, void *func, int descriptors,
@@ -571,7 +616,7 @@ ftw_startup (const char *dir, int is_nft
   int result = 0;
   int save_err;
   char *cwd = NULL;
-  char *cp;
+  size_t dir_len;
 
   /* First make sure the parameters are reasonable.  */
   if (dir[0] == '\0')
@@ -586,26 +631,21 @@ ftw_startup (const char *dir, int is_nft
                                                 * sizeof (struct dir_data *));
   memset (data.dirstreams, '\0', data.maxdir * sizeof (struct dir_data *));
 
+  dir_len = strlen (dir);
 #ifdef PATH_MAX
-  data.dirbufsize = MAX (2 * strlen (dir), PATH_MAX);
+  data.dirbufsize = MAX (2 * dir_len, PATH_MAX);
 #else
-  data.dirbufsize = 2 * strlen (dir);
+  data.dirbufsize = 2 * dir_len;
 #endif
   data.dirbuf = (char *) malloc (data.dirbufsize);
   if (data.dirbuf == NULL)
     return -1;
-  cp = __stpcpy (data.dirbuf, dir);
-  /* Strip trailing slashes.  */
-  while (cp > data.dirbuf + 1 && cp[-1] == '/')
-    --cp;
-  *cp = '\0';
+  memcpy (data.dirbuf, dir, dir_len + 1);
 
   data.ftw.level = 0;
 
-  /* Find basename.  */
-  while (cp > data.dirbuf && cp[-1] != '/')
-    --cp;
-  data.ftw.base = cp - data.dirbuf;
+  /* Find offset of basename.  */
+  data.ftw.base = base_name (data.dirbuf) - data.dirbuf;
 
   data.flags = flags;
 

Attachment: pgpZmltFSAj5j.pgp
Description: PGP signature


reply via email to

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