Date: Sun, 03 Aug 2003 16:12:38 +0100 From: "Richard Dawe" Sender: rich AT phekda DOT freeserve DOT co DOT uk To: djgpp-workers AT delorie DOT com X-Mailer: Emacs 21.3.50 (via feedmail 8.3.emacs20_6 I) and Blat ver 1.8.6 Subject: Fix for rename bug: moving a directory into itself [PATCH] Message-Id: Reply-To: djgpp-workers AT delorie DOT com Hello. Below is a patch to fix the problem with rename and moving a directory into itself. It looks like _truename will generate an SFN for a non-existing file. The patch below adds a version of _truename that should always return SFNs. Imaginatively it's called _truename_sfn. Better suggestions are welcome. ;) Now rename will use this function to generate the filenames for comparison with is_parent. This seems to fix the problem on Windows '98 SE. The patch will probably apply with some fuzz. I've hacked out a couple of chunks from my last fstat patch. I've put a version of mv from fileutils 4.1 release 6 for testing here: http://www.phekda.freeserve.co.uk/richdawe/djgpp/2.04/ The binary is stripped and gzip'd. (Sorry, I don't have enough space for an unstripped version.) The binary was built against my development tree, which is mostly clean. It has an fstat patch applied, but I don't think that will make any difference to this problem. Please test on other platforms and let me know how it goes. OK to commit? Thanks, bye, Rich =] Index: include/sys/stat.h =================================================================== RCS file: /cvs/djgpp/djgpp/include/sys/stat.h,v retrieving revision 1.9 diff -p -u -3 -r1.9 stat.h --- include/sys/stat.h 8 Mar 2003 00:40:39 -0000 1.9 +++ include/sys/stat.h 3 Aug 2003 14:45:53 -0000 @@ -96,6 +98,7 @@ int _is_executable(const cha int lstat(const char * _path, struct stat * _buf); int mknod(const char *_path, mode_t _mode, dev_t _dev); char * _truename(const char *, char *); +char * _truename_sfn(const char *, char *); /* Bit-mapped variable _djstat_flags describes what expensive f?stat() features our application needs. If you don't need a Index: src/libc/dos/dos/truename.c =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/dos/dos/truename.c,v retrieving revision 1.4 diff -p -u -3 -r1.4 truename.c --- src/libc/dos/dos/truename.c 14 Jun 1999 16:20:40 -0000 1.4 +++ src/libc/dos/dos/truename.c 3 Aug 2003 14:45:54 -0000 @@ -1,3 +1,4 @@ +/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ /* @@ -46,8 +47,8 @@ In case of any failure, returns a NULL pointer and sets errno. */ -char * -_truename(const char *file, char *buf) +static char * +_truename_internal(const char *file, char *buf, const int try_lfn) { __dpmi_regs regs; unsigned short dos_mem_selector = _dos_ds; @@ -106,7 +107,8 @@ _truename(const char *file, char *buf) /* Call DOS INT 21H undocumented function 60h. */ if(use_lfn) { regs.x.ax = 0x7160; - regs.x.cx = 2; /* Get Long Path Name (if there is one) */ + /* Get Long Path Name (if there is one) and we want it. */ + regs.x.cx = try_lfn ? 2 : 0; } else regs.x.ax = 0x6000; @@ -150,6 +152,23 @@ _truename(const char *file, char *buf) } return buf; } +} + +char * +_truename(const char *file, char *buf) +{ + return _truename_internal(file, buf, 1); +} + +/* Sometimes we want the truename for a file that doesn't exist yet. + In those cases Windows '98 seems to prefer returning an SFN truename. + So if you want to use truenames in a comparison, it's safer to use + the SFN truenames. + */ +char * +_truename_sfn(const char *file, char *buf) +{ + return _truename_internal(file, buf, 0); } #ifdef TEST Index: src/libc/dos/dos/truename.txh =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/dos/dos/truename.txh,v retrieving revision 1.4 diff -p -u -3 -r1.4 truename.txh --- src/libc/dos/dos/truename.txh 1 Apr 2003 20:47:28 -0000 1.4 +++ src/libc/dos/dos/truename.txh 3 Aug 2003 14:46:02 -0000 @@ -29,6 +29,14 @@ or (2) contains only the drive letter (e whitespace. It will also fail if it couldn't allocate memory required for its communication with DOS or for @var{true_path} (see below). +@code{_truename} may not return what you expect for files that don't exist. +For instance, if the current directory was entered using a short +filename (@samp{c:\thisis~1} instead of @samp{c:\thisisalongname}, say), +then the truename of an existing file will be a long filename, +but the truename of an non-existing file will be a short filename. +This can cause problems when comparing filenames. Use +@code{_truename_sfn} (@pxref{_truename_sfn}) instead in this case. + Upon success, the function will place the result in @var{true_path}, if that's non-NULL; the buffer should be large enough to contain the largest possible pathname (PATH_MAX characters). If @var{true_path} @@ -52,3 +60,35 @@ a NULL pointer is returned, and @code{er "True name of %s is %s\n", path, _truename(path, (char *)0)); @end example +@node _truename_sfn, stdio +@findex _truename_sfn +@subheading Syntax + +@example +#include + +char * _truename_sfn(const char *path, char *true_path); +@end example + +@subheading Description + +@code{_truename_sfn} is like @code{_truename}, except that it always +returns a short filename. See the documentation for @code{_truename} +for more details (@pxref{_truename}). + +@subheading Return Value + +The function returns the pointer to the result. In case of any failure, +a NULL pointer is returned, and @code{errno} is set. + +@subheading Portability + +@portability !ansi, !posix + +@subheading Example + +@example + fprintf(stderr, + "True short name of %s is %s\n", path, + _truename_sfn(path, (char *)0)); +@end example Index: src/libc/ansi/stdio/rename.c =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/ansi/stdio/rename.c,v retrieving revision 1.8 diff -p -u -3 -r1.8 rename.c --- src/libc/ansi/stdio/rename.c 17 Oct 2002 23:00:24 -0000 1.8 +++ src/libc/ansi/stdio/rename.c 3 Aug 2003 14:46:04 -0000 @@ -1,3 +1,4 @@ +/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */ @@ -344,8 +345,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(real_old, old_true), - _truename(real_new, new_true))) + if (is_parent(_truename_sfn(real_old, old_true), + _truename_sfn(real_new, new_true))) { errno = EINVAL; return -1; @@ -377,8 +378,8 @@ rename(const char *old, const char *new) char new_true[FILENAME_MAX], old_true[FILENAME_MAX]; errno = 0; - if (is_parent(_truename(real_old, old_true), - _truename(real_new, new_true))) + if (is_parent(_truename_sfn(real_old, old_true), + _truename_sfn(real_new, new_true))) { errno = EINVAL; return -1; Index: src/docs/kb/wc204.txi =================================================================== RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v retrieving revision 1.158 diff -p -u -3 -r1.158 wc204.txi --- src/docs/kb/wc204.txi 10 May 2003 17:12:53 -0000 1.158 +++ src/docs/kb/wc204.txi 3 Aug 2003 14:46:16 -0000 @@ -990,3 +996,13 @@ The functions @code{strtod}, @code{strto @code{_strtold} now understand ``Inf'', ``Infinity'', ``NaN'', ``NaN()'', ``NaN(@var{hex-number})'' and any variations of case in the input string. + +@findex _truename_sfn +The @code{_truename_sfn} function was added. Please use +@code{_truename_sfn} when comparing truenames, to avoid problems +when comparing the truenames of existing and non-existing files. + +@findex rename AT r{, and moving directories into themselves} +Fix a bug in moving directories into themselves. Previously +@code{rename} failed to detect that a subdirectory was being moved +into itself, when the current directory was a short filename.