changeset 16524:84440bd95727

[__DJGPP_MINOR__ == 0] (_rename): New function, a substitute for library low-level file-renaming function which works around Windows 95 bug.
author Richard M. Stallman <rms@gnu.org>
date Wed, 06 Nov 1996 19:51:38 +0000
parents 53306ee8953d
children 521d5794ac2b
files src/msdos.c
diffstat 1 files changed, 116 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/msdos.c	Wed Nov 06 19:03:53 1996 +0000
+++ b/src/msdos.c	Wed Nov 06 19:51:38 1996 +0000
@@ -2327,6 +2327,122 @@
     }
 }
 
+/* A low-level file-renaming function which works around Windows 95 bug.
+   This is pulled directly out of DJGPP v2.01 library sources, and only
+   used when you compile with DJGPP v2.0.  */
+
+#include <io.h>
+ 
+int _rename(const char *old, const char *new)
+{
+  __dpmi_regs r;
+  int olen    = strlen(old) + 1;
+  int i;
+  int use_lfn = _USE_LFN;
+  char tempfile[FILENAME_MAX];
+  const char *orig = old;
+  int lfn_fd = -1;
+
+  r.x.dx = __tb_offset;
+  r.x.di = __tb_offset + olen;
+  r.x.ds = r.x.es = __tb_segment;
+
+  if (use_lfn)
+    {
+      /* Windows 95 bug: for some filenames, when you rename
+	 file -> file~ (as in Emacs, to leave a backup), the
+	 short 8+3 alias doesn't change, which effectively
+	 makes OLD and NEW the same file.  We must rename
+	 through a temporary file to work around this.  */
+
+      char *pbase = 0, *p;
+      static char try_char[] = "abcdefghijklmnopqrstuvwxyz012345789";
+      int idx = sizeof(try_char) - 1;
+
+      /* Generate a temporary name.  Can't use `tmpnam', since $TMPDIR
+	 might point to another drive, which will fail the DOS call.  */
+      strcpy(tempfile, old);
+      for (p = tempfile; *p; p++) /* ensure temporary is on the same drive */
+	if (*p == '/' || *p == '\\' || *p == ':')
+	  pbase = p;
+      if (pbase)
+	pbase++;
+      else
+	pbase = tempfile;
+      strcpy(pbase, "X$$djren$$.$$temp$$");
+
+      do
+	{
+	  if (idx <= 0)
+	    return -1;
+	  *pbase = try_char[--idx];
+	} while (_chmod(tempfile, 0) != -1);
+
+      r.x.ax = 0x7156;
+      _put_path2(tempfile, olen);
+      _put_path(old);
+      __dpmi_int(0x21, &r);
+      if (r.x.flags & 1)
+	{
+	  errno = __doserr_to_errno(r.x.ax);
+	  return -1;
+	}
+
+      /* Now create a file with the original name.  This will
+	 ensure that NEW will always have a 8+3 alias
+	 different from that of OLD.  (Seems to be required
+	 when NameNumericTail in the Registry is set to 0.)  */
+      lfn_fd = _creat(old, 0);
+
+      olen = strlen(tempfile) + 1;
+      old  = tempfile;
+      r.x.di = __tb_offset + olen;
+    }
+
+  for (i=0; i<2; i++)
+    {
+      if(use_lfn)
+	r.x.ax = 0x7156;
+      else
+	r.h.ah = 0x56;
+      _put_path2(new, olen);
+      _put_path(old);
+      __dpmi_int(0x21, &r);
+      if(r.x.flags & 1)
+	{
+	  if (r.x.ax == 5 && i == 0) /* access denied */
+	    remove(new);		 /* and try again */
+	  else
+	    {
+	      errno = __doserr_to_errno(r.x.ax);
+
+	      /* Restore to original name if we renamed it to temporary.  */
+	      if (use_lfn)
+		{
+		  if (lfn_fd != -1)
+		    {
+		      _close (lfn_fd);
+		      remove (orig);
+		    }
+		  _put_path2(orig, olen);
+		  _put_path(tempfile);
+		  r.x.ax = 0x7156;
+		  __dpmi_int(0x21, &r);
+		}
+	      return -1;
+	    }
+	}
+      else
+	break;
+    }
+
+  /* Success.  Delete the file possibly created to work
+     around the Windows 95 bug.  */
+  if (lfn_fd != -1)
+    return (_close (lfn_fd) == 0) ? remove (orig) : -1;
+  return 0;
+}
+
 #endif /* __DJGPP__ == 2 && __DJGPP_MINOR__ == 0 */
 
 DEFUN ("msdos-long-file-names", Fmsdos_long_file_names, Smsdos_long_file_names,