Message-ID: <39A43803.BE3B531E@softhome.net> Date: Wed, 23 Aug 2000 22:45:55 +0200 From: Laurynas Biveinis X-Mailer: Mozilla 4.74 [en] (Win98; U) X-Accept-Language: lt,en MIME-Version: 1.0 To: DJGPP Workers Subject: Patch: symlinks in rename() Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Reply-To: djgpp-workers AT delorie DOT com This one together with patch for lstat() keeps 'mv' in shape. Any comments? Laurynas Index: rename.c =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/ansi/stdio/rename.c,v retrieving revision 1.6 diff -u -p -r1.6 rename.c --- rename.c 1999/06/14 14:55:24 1.6 +++ rename.c 2000/08/23 20:39:33 @@ -27,6 +27,7 @@ */ #include +#include #include #include #include @@ -254,6 +255,8 @@ rename(const char *old, const char *new) int e = errno; int simple_should_do = 0; /* _rename() enough? */ int target_exists = 0; + char real_old[FILENAME_MAX]; + char real_new[FILENAME_MAX]; /* Much of the following quite tedious administrivia is necessary to return a meaningful code in errno. Otherwise, for most of @@ -270,9 +273,14 @@ rename(const char *old, const char *new) return -1; } + /* Handle symlinks */ + if (!__solve_dir_symlinks(old, real_old) || + !__solve_dir_symlinks(new, real_new)) + return -1; + /* Fail with ENAMETOOLONG if either OLD or NEW are too long. This is explicitly checked so that DOS filename truncation won't fool us. */ - if (strlen(old) > FILENAME_MAX || strlen(new) > FILENAME_MAX) + if (strlen(real_old) > FILENAME_MAX || strlen(real_new) > FILENAME_MAX) { errno = ENAMETOOLONG; return -1; @@ -280,16 +288,16 @@ rename(const char *old, const char *new) /* Fail with ENOENT if OLD doesn't exist or is otherwise inaccessible. */ - if ((source_attr = _chmod(old, 0)) == -1) + if ((source_attr = _chmod(real_old, 0)) == -1) return -1; /* errno set by _chmod() */ /* Fail with EXDEV, if old and new aren't on the same device. */ - if (old[1] == ':') - old_dev = toupper((unsigned char)old[0]) - 'A'; + if (real_old[1] == ':') + old_dev = toupper((unsigned char)real_old[0]) - 'A'; else old_dev = getdisk(); - if (new[1] == ':') - new_dev = toupper((unsigned char)new[0]) - 'A'; + if (real_new[1] == ':') + new_dev = toupper((unsigned char)real_new[0]) - 'A'; else new_dev = getdisk(); if (old_dev != new_dev) @@ -299,8 +307,9 @@ rename(const char *old, const char *new) } /* Refuse to rename `.' or `..' or `d:.' or `d:..' */ - if ((old[0] == '.' && (old[1] == '\0' || (old[1] == '.' && old[2] == '\0'))) || - (old[1] == ':' && old[2] == '.' && (old[3] == '\0' || (old[3] == '.' && old[4] == '\0')))) + if ((real_old[0] == '.' && (real_old[1] == '\0' || (real_old[1] == '.' && + real_old[2] == '\0'))) || (real_old[1] == ':' && real_old[2] == '.' && + (real_old[3] == '\0' || (real_old[3] == '.' && real_old[4] == '\0')))) { errno = EINVAL; return -1; @@ -308,7 +317,7 @@ rename(const char *old, const char *new) /* Some problems can only happen if NEW already exists. */ errno = 0; - target_attr = _chmod(new, 0); + target_attr = _chmod(real_new, 0); if (errno != ENOENT) { int old_is_dir = (source_attr & 0x10) == 0x10; @@ -334,7 +343,8 @@ rename(const char *old, const char *new) /* Fail if both OLD and NEW are directories and OLD is parent of NEW. */ errno = 0; - if (is_parent(_truename(old, old_true), _truename(new, new_true))) + if (is_parent(_truename(real_old, old_true), + _truename(real_new, new_true))) { errno = EINVAL; return -1; @@ -366,7 +376,8 @@ rename(const char *old, const char *new) char new_true[FILENAME_MAX], old_true[FILENAME_MAX]; errno = 0; - if (is_parent(_truename(old, old_true), _truename(new, new_true))) + if (is_parent(_truename(real_old, old_true), + _truename(real_new, new_true))) { errno = EINVAL; return -1; @@ -385,7 +396,7 @@ rename(const char *old, const char *new) moving a regular file, or renaming a directory. Note that on Windows 95 this will also move a directory to a subtree of another parent directory. */ - if ((status = _rename(old, new)) == 0) + if ((status = _rename(real_old, real_new)) == 0) { errno = e; /* restore errno we inherited */ return 0; @@ -395,7 +406,7 @@ rename(const char *old, const char *new) and return -1 with whatever errno we have. */ return -1; else if (errno == EACCES && target_exists && (target_attr & 0x10) && - _chmod(new, 0) != -1) + _chmod(real_new, 0) != -1) { /* If target still exists (i.e., it wasn't removed inside _rename()) and is a directory, assume it's not empty. @@ -414,10 +425,10 @@ rename(const char *old, const char *new) int retval; - strcpy(source, old); + strcpy(source, real_old); last = strlen(source) - 1; - strcpy(target, new); + strcpy(target, real_new); if (strchr(target, '\\')) for (p = target; *p; p++) { @@ -430,7 +441,7 @@ rename(const char *old, const char *new) ++last; /* Create NEW and push it onto the stack. */ - if (mkdir(new, source_attr & 0xffe7) == -1 || + if (mkdir(real_new, source_attr & 0xffe7) == -1 || init_stack() == 0 || push_dir(old) == 0) return -1;