changeset 7477:80672a16f597

* lib/rename-dest-slash.c: Include stdbool.h but not string.h. (has_trailing_slash): Omit size arg; all callers changed. Omit 'inline', since it doesn't help performance and we'd need to configure it. Don't count //, ///, etc. as having a trailing slash. As a side effect, this removes a C99ism reported by Matthew Woehlke. (rpl_rename_dest_slash): On failure, use rename's errno rather than (in some cases) an incorrect or junk errno. Simplify code by removing need to compute length; this does cause it to make two passes instead of one over the file name, but it's worth it.
author Paul Eggert <eggert@cs.ucla.edu>
date Thu, 12 Oct 2006 05:36:20 +0000
parents 2c5420bfcf6e
children eeed6338b68d
files ChangeLog lib/rename-dest-slash.c
diffstat 2 files changed, 40 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
 2006-10-11  Paul Eggert  <eggert@cs.ucla.edu>
 
+	* lib/rename-dest-slash.c: Include stdbool.h but not string.h.
+	(has_trailing_slash): Omit size arg; all callers changed.
+	Omit 'inline', since it doesn't help performance and we'd
+	need to configure it.
+	Don't count //, ///, etc. as having a trailing slash.
+	As a side effect, this removes a C99ism reported by Matthew Woehlke.
+	(rpl_rename_dest_slash): On failure, use rename's errno rather
+	than (in some cases) an incorrect or junk errno.
+	Simplify code by removing need to compute length; this does
+	cause it to make two passes instead of one over the file name,
+	but it's worth it.
+
 	* m4/extensions.m4 (gl_USE_SYSTEM_EXTENSIONS): Undo previous
 	change, since Autoconf's version may no longer be appropriate now
 	that we are using CVS Autoconf's version.  Add support for Tandem.
--- a/lib/rename-dest-slash.c
+++ b/lib/rename-dest-slash.c
@@ -31,22 +31,27 @@
 #include <sys/stat.h>
 #include <errno.h>
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 
 #include "dirname.h"
 #include "xalloc.h"
 
-static inline bool
-has_trailing_slash (char const *file, size_t len)
+static bool
+has_trailing_slash (char const *file)
 {
-  /* Don't count "/" as having a trailing slash.  */
-  if (len <= FILE_SYSTEM_PREFIX_LEN (file) + 1)
-    return false;
+  /* Don't count "/", "//", etc., as having a trailing slash.  */
+  bool has_non_slash = false;
+  bool ends_in_slash = false;
 
-  char last = file[len - 1];
-  return ISSLASH (last);
+  for (file += FILE_SYSTEM_PREFIX_LEN (file); *file; file++)
+    {
+      ends_in_slash = ISSLASH (*file);
+      has_non_slash |= ~ ends_in_slash;
+    }
+
+  return has_non_slash & ends_in_slash;
 }
 
 /* This is a rename wrapper for systems where the rename syscall
@@ -59,31 +64,25 @@
 int
 rpl_rename_dest_slash (char const *src, char const *dst)
 {
-  size_t d_len;
   int ret_val = rename (src, dst);
-  if (ret_val == 0 || errno != ENOENT)
-    return ret_val;
 
-  /* Don't call rename again if there are no trailing slashes.  */
-  d_len = strlen (dst);
-  if ( ! has_trailing_slash (dst, d_len))
-    return ret_val;
+  if (ret_val != 0 && errno == ENOENT && has_trailing_slash (dst))
+    {
+      int rename_errno = ENOENT;
 
-  {
-    /* Fail now, unless SRC is a directory.  */
-    struct stat sb;
-    if (lstat (src, &sb) != 0 || ! S_ISDIR (sb.st_mode))
-      return ret_val;
-  }
+      /* Fail now, unless SRC is a directory.  */
+      struct stat sb;
+      if (lstat (src, &sb) == 0 && S_ISDIR (sb.st_mode))
+	{
+	  char *dst_temp = xstrdup (dst);
+	  strip_trailing_slashes (dst_temp);
+	  ret_val = rename (src, dst_temp);
+	  rename_errno = errno;
+	  free (dst_temp);
+	}
 
-  {
-    char *dst_temp;
-    dst_temp = xmemdup (dst, d_len + 1);
-    strip_trailing_slashes (dst_temp);
-
-    ret_val = rename (src, dst_temp);
-    free (dst_temp);
-  }
+      errno = rename_errno;
+    }
 
   return ret_val;
 }