c84b_rename.patchh¼¿è³¼¿èïmBINzÖIndex: tests/fCmd.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/fCmd.test,v
retrieving revision 1.26.2.4
diff -u -p -r1.26.2.4 fCmd.test
--- tests/fCmd.test	7 Oct 2003 15:57:36 -0000	1.26.2.4
+++ tests/fCmd.test	6 May 2004 16:33:56 -0000
@@ -1778,6 +1778,106 @@ test fCmd-18.16 {TclFileRenameCmd: renam
 } {1}
 
 
+#can not overwrite a symlink with symlink; places symlink inside new name's original
+test fCmd-18.17 {TclFileRenameCmd: rename symlink with symlink fails -force} {unixOnly notRoot} {
+    catch {file delete -force -- tfa1 tfalink tfa3}
+	
+    file mkdir tfa1
+    createfile [file join tfa1/tfa2]
+    file link -symbolic tfalink tfa1
+    file link -symbolic tfa3 tfa1
+    file rename -force tfalink tfa3
+    set result [expr [string compare [file type tfa3] "link"] == 0]
+    file delete tfa1/tfa2
+    file delete -force tfa3
+    set result
+} {1}
+
+#same as above "-force" no effect
+test fCmd-18.18 {TclFileRenameCmd: rename symlink with symlink fails no -force} {unixOnly notRoot} {
+    catch {file delete -force -- tfa1 tfalink tfa3}
+	
+    file mkdir tfa1
+    createfile [file join tfa1/tfa2]
+    file link -symbolic tfalink tfa1
+    file link -symbolic tfa3 tfa1
+    list [catch {file rename tfalink tfa3} msg] $msg
+    file delete tfa1/tfa2
+    file delete -force tfa3
+    set msg
+} {}
+
+#can not overwrite a symlink with dir; places symlink inside new name
+test fCmd-18.19 {TclFileRenameCmd: rename symlink with dir fails -force} {unixOnly notRoot} {
+    catch {file delete -force -- tfa1 tfalink tfa3}
+	
+    file mkdir tfa1
+    createfile [file join tfa1/tfa2]
+    file link -symbolic tfalink tfa1
+    file mkdir tfa3
+    file rename -force tfalink tfa3
+    set result [expr [string compare [file type tfa3] "link"] == 0]
+    file delete tfa1/tfa2
+    file delete -force tfalink
+    set result
+} {0}
+
+#same as above "-force" no effect
+test fCmd-18.20 {TclFileRenameCmd: rename symlink with dir fails no -force} {unixOnly notRoot} {
+    catch {file delete -force -- tfa1 tfalink tfa3}
+	
+    file mkdir tfa1
+    createfile [file join tfa1/tfa2]
+    file link -symbolic tfalink tfa1
+    file mkdir tfa3
+    list [catch {file rename tfalink tfa3} msg] $msg
+    file delete tfa1/tfa2
+    file delete -force tfa3
+    set msg
+} {}
+
+#can overwrite a symlink with file; destroys file;  -force works
+test fCmd-18.21 {TclFileRenameCmd: rename symlink with file -force} {unixOnly notRoot} {
+    catch {file delete -force -- tfa1 tfalink tfa3}
+	
+    file mkdir tfa1
+    createfile [file join tfa1/tfa2]
+    file link -symbolic tfalink tfa1
+    createfile tfa3
+    file rename -force tfalink tfa3
+    set result [expr [string compare [file type tfa3] "link"] == 0]
+    file delete tfa1/tfa2
+    file delete tfa3
+    set result
+} {1}
+
+#can not overwrite a symlink with file
+test fCmd-18.22 {TclFileRenameCmd: rename symlink with file no -force} {unixOnly notRoot} {
+    catch {file delete -force -- tfa1 tfalink tfa3}
+	
+    file mkdir tfa1
+    createfile [file join tfa1/tfa2]
+    file link -symbolic tfalink tfa1
+    createfile tfa3
+    list [catch {file rename tfalink tfa3} msg] $msg
+    file delete tfa1/tfa2
+    file delete tfa3
+    set msg
+} {error renaming "tfalink" to "tfa3": file already exists}
+
+test fCmd-18.23 {TclFileRenameCmd: rename symlink with contents} {unixOnly notRoot} {
+    catch {file delete -force -- tfa1 tfalink}
+	
+    file mkdir tfa1
+    createfile [file join tfa1/tfa2]
+    file link -symbolic tfalink tfa1
+    file rename tfalink tfa3
+    set result [expr [string compare [file type tfa3] "link"] == 0]
+    file delete tfa1/tfa2
+    file delete tfa3
+    set result
+} {1}
+
 #
 # Coverage tests for TclUnixRmdir
 #
Index: unix/tclUnixFCmd.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixFCmd.c,v
retrieving revision 1.28.2.2
diff -u -p -r1.28.2.2 tclUnixFCmd.c
--- unix/tclUnixFCmd.c	3 Oct 2003 17:45:37 -0000	1.28.2.2
+++ unix/tclUnixFCmd.c	6 May 2004 16:34:10 -0000
@@ -223,76 +223,32 @@ DoRenameFile(src, dst)
     CONST char *dst;		/* New pathname of file or directory
 				 * (native). */
 {
-    if (rename(src, dst) == 0) {			/* INTL: Native. */
-	return TCL_OK;
-    }
-    if (errno == ENOTEMPTY) {
-	errno = EEXIST;
-    }
-
-    /*
-     * IRIX returns EIO when you attept to move a directory into
-     * itself.  We just map EIO to EINVAL get the right message on SGI.
-     * Most platforms don't return EIO except in really strange cases.
-     */
-    
-    if (errno == EIO) {
-	errno = EINVAL;
-    }
+    int exists;
+    struct stat dstSB;
     
-#ifndef NO_REALPATH
-    /*
-     * SunOS 4.1.4 reports overwriting a non-empty directory with a
-     * directory as EINVAL instead of EEXIST (first rule out the correct
-     * EINVAL result code for moving a directory into itself).  Must be
-     * conditionally compiled because realpath() not defined on all systems.
-     */
-
-    if (errno == EINVAL) {
-	char srcPath[MAXPATHLEN], dstPath[MAXPATHLEN];
-	DIR *dirPtr;
-	Tcl_DirEntry *dirEntPtr;
-
-	if ((Realpath((char *) src, srcPath) != NULL)	/* INTL: Native. */
-		&& (Realpath((char *) dst, dstPath) != NULL) /* INTL: Native. */
-		&& (strncmp(srcPath, dstPath, strlen(srcPath)) != 0)) {
-	    dirPtr = opendir(dst);			/* INTL: Native. */
-	    if (dirPtr != NULL) {
-		while (1) {
-		    dirEntPtr = TclOSreaddir(dirPtr); /* INTL: Native. */
-		    if (dirEntPtr == NULL) {
-			break;
-		    }
-		    if ((strcmp(dirEntPtr->d_name, ".") != 0) &&
-			    (strcmp(dirEntPtr->d_name, "..") != 0)) {
-			errno = EEXIST;
-			closedir(dirPtr);
-			return TCL_ERROR;
-		    }
-		}
-		closedir(dirPtr);
-	    }
-	}
-	errno = EINVAL;
-    }
-#endif	/* !NO_REALPATH */
-
     if (strcmp(src, "/") == 0) {
-	/*
-	 * Alpha reports renaming / as EBUSY and Linux reports it as EACCES,
-	 * instead of EINVAL.
-	 */
-	 
-	errno = EINVAL;
+        /* Alpha reports renaming / as EBUSY, Linux reports it as EACCES,
+         * and OSX reports it as EISDIR instead of EINVAL. */
+        errno = EINVAL;
+        return TCL_ERROR;
+    }
+    exists = (lstat(dst, &dstSB) == 0);
+    /* dst non-exsistant or a normal file */
+    if (!exists || (!S_ISLNK(dstSB.st_mode) && dstSB.st_nlink == 1)) {
+        if (rename(src, dst) == 0) {
+            return TCL_OK;
+         }
+    } else {
+        /* copy
+         * overwriting a non-empty directory checked with rmdir() */
+        if (rmdir(dst) == 0) {
+            rename(src, dst);
+            return TCL_OK;
+        }
+        if (errno == ENOTEMPTY) {
+            errno = EEXIST;
+        }
     }
-
-    /*
-     * DEC Alpha OSF1 V3.0 returns EACCES when attempting to move a
-     * file across filesystems and the parent directory of that file is
-     * not writable.  Most other systems return EXDEV.  Does nothing to
-     * correct this behavior.
-     */
-
     return TCL_ERROR;
 }
 
