diff options
author | Geoff Voelker <voelker@cs.washington.edu> | 1996-03-29 04:24:58 +0000 |
---|---|---|
committer | Geoff Voelker <voelker@cs.washington.edu> | 1996-03-29 04:24:58 +0000 |
commit | 3ea352c948c927357775d652ae8304d858608d36 (patch) | |
tree | 566e4d9145a12831c712bf2fdab990a62cb684a9 /src/w32.c | |
parent | 7752abb01f10bccbd36021638e540c3d2625df02 (diff) | |
download | emacs-3ea352c948c927357775d652ae8304d858608d36.tar.gz |
(rename): New function.
Diffstat (limited to 'src/w32.c')
-rw-r--r-- | src/w32.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/src/w32.c b/src/w32.c index 36c11cc9abb..c6338b2a677 100644 --- a/src/w32.c +++ b/src/w32.c @@ -218,6 +218,108 @@ nt_sleep (int seconds) 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. */ |