changeset 14912:8d25697cc14b

(rename): New function.
author Geoff Voelker <voelker@cs.washington.edu>
date Fri, 29 Mar 1996 04:24:58 +0000
parents f736e9cb067e
children c32eccfde8a2
files src/w32.c
diffstat 1 files changed, 102 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/w32.c	Fri Mar 29 01:49:55 1996 +0000
+++ b/src/w32.c	Fri Mar 29 04:24:58 1996 +0000
@@ -218,6 +218,108 @@
   Sleep (seconds * 1000);
 }
 
+/* Emulate rename. */
+
+#ifndef ENOENT
+#define ENOENT 2
+#endif
+#ifndef EXDEV
+#define EXDEV 18
+#endif
+#ifndef EINVAL
+#define EINVAL 22
+#endif
+
+int
+rename (const char *oldname, const char *newname)
+{
+#ifdef WINDOWS95
+  int i, len, len0, len1;
+  char *dirs[2], *names[2], *ptr;
+
+  /* A bug in MoveFile under Windows 95 incorrectly renames files in
+     some cases.  If the old name is of the form FILENAME or
+     FILENAME.SUF, and the new name is of the form FILENAME~ or
+     FILENAME.SUF~, and both the source and target are in the same
+     directory, then MoveFile renames the long form of the filename to
+     FILENAME~ (FILENAME.SUF~) but leaves the DOS short form as
+     FILENAME (FILENAME.SUF).  The result is that the two different
+     filenames refer to the same file.  In this case, rename the
+     source to a temporary name that can then successfully be renamed
+     to the target.  */
+
+  dirs[0] = names[0] = oldname;
+  dirs[1] = names[1] = newname;
+  for (i = 0; i < 2; i++)
+    {
+      /* Canonicalize and remove prefix.  */
+      len = strlen (names[i]);
+      for (ptr = names[i] + len - 1; ptr > names[i]; ptr--)
+	{
+	  if (IS_ANY_SEP (ptr[0]) && ptr[1] != '\0')
+	    {
+	      names[i] = ptr + 1;
+	      break;
+	    }
+	}
+    }
+
+  len0 = strlen (names[0]);
+  len1 = strlen (names[1]);
+
+  /* The predicate is whether the file is being renamed to a filename
+     with ~ appended.  This is conservative, but should be correct.  */
+  if ((len0 == len1 - 1)
+      && (names[1][len0] == '~')
+      && (!strnicmp (names[0], names[1], len0)))
+    {
+      /* Rename the source to a temporary name that can succesfully be
+	 renamed to the target.  The temporary name is in the directory
+	 of the target.  */
+      char *tmp, *fulltmp;
+
+      tmp = "eXXXXXX";
+      fulltmp = alloca (strlen (dirs[1]) + strlen (tmp) + 1);
+      fulltmp[0] = '\0';
+      if (dirs[1] != names[1])
+	{
+	  len = names[1] - dirs[1];
+	  strncpy (fulltmp, dirs[1], len);
+	  fulltmp[len] = '\0';
+	}
+      strcat (fulltmp, tmp);
+      mktemp (fulltmp);
+
+      if (rename (oldname, fulltmp) < 0)
+	return -1;
+      
+      oldname = fulltmp;
+    }
+#endif
+
+  if (!MoveFile (oldname, newname))
+    {
+      switch (GetLastError ())
+	{
+	case ERROR_FILE_NOT_FOUND:
+	  errno = ENOENT;
+	  break;
+	case ERROR_ACCESS_DENIED:
+	  /* This gets returned when going across devices.  */
+	  errno = EXDEV;
+	  break;
+	case ERROR_FILE_EXISTS:
+	case ERROR_ALREADY_EXISTS:
+	default:
+	  errno = EINVAL;
+	  break;
+	}
+      return -1;
+    }
+  errno = 0;
+  return 0;
+}
+
 /* Emulate the Unix directory procedures opendir, closedir, 
    and readdir.  We can't use the procedures supplied in sysdep.c,
    so we provide them here.  */