Index: tclFCmd.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclFCmd.c,v
retrieving revision 1.18
diff -b -u -r1.18 tclFCmd.c
--- tclFCmd.c	18 Jul 2002 16:17:48 -0000	1.18
+++ tclFCmd.c	6 Aug 2002 16:50:21 -0000
@@ -448,6 +448,8 @@
 {
     int result;
     Tcl_Obj *errfile, *errorBuffer;
+    /* If source is a link, then this is the real file/directory */
+    Tcl_Obj *actualSource = NULL;
     Tcl_StatBuf sourceStatBuf, targetStatBuf;
 
     if (Tcl_FSConvertToPathType(interp, source) != TCL_OK) {
@@ -549,8 +551,58 @@
 	 */
     }
 
+#ifdef S_ISLNK
+    /* 
+     * To add a flag to make 'copy' copy links instead of files, we could
+     * add a condition to ignore this 'if' here.
+     */
+    if (copyFlag && S_ISLNK(sourceStatBuf.st_mode)) {
+	/* 
+	 * We want to copy files not links.  Therefore we must follow the
+	 * link.  There are two purposes to this 'stat' call here.  First
+	 * we want to know if the linked-file/dir actually exists, and
+	 * second, in the block of code which follows, some 20 lines
+	 * down, we want to check if the thing is a file or directory.
+	 */
+	if (Tcl_FSStat(source, &sourceStatBuf) != 0) {
+	    /* Actual file doesn't exist */
+	    Tcl_AppendResult(interp, 
+			     "error copying \"", Tcl_GetString(source), 
+			     "\": the target of this link doesn't exist",
+			     (char *) NULL);
+	    goto done;
+	} else {
+	    int counter = 0;
+	    actualSource = source;
+	    Tcl_IncrRefCount(actualSource);
+	    while (1) {
+		Tcl_Obj *path = Tcl_FSLink(actualSource,NULL,0);
+		if (path == NULL) {
+		    break;
+		}
+		Tcl_DecrRefCount(actualSource);
+		actualSource = path;
+		counter++;
+		/* Arbitrary limit of 20 links to follow */
+		if (counter > 20) {
+		    /* Too many links */
+		    Tcl_SetErrno(EMLINK);
+		    errfile = source;
+		    goto done;
+		}
+	    }
+	    /* Now 'actualSource' is the correct file */
+	}
+    } else {
+	actualSource = source;
+	Tcl_IncrRefCount(actualSource);
+    }
+#else
+    actualSource = source;
+    Tcl_IncrRefCount(actualSource);
+#endif
     if (S_ISDIR(sourceStatBuf.st_mode)) {
-	result = Tcl_FSCopyDirectory(source, target, &errorBuffer);
+	result = Tcl_FSCopyDirectory(actualSource, target, &errorBuffer);
 	if (result != TCL_OK) {
 	    if (errno == EXDEV) {
 		/* 
@@ -598,7 +650,7 @@
 	    }
 	}
     } else {
-	result = Tcl_FSCopyFile(source, target);
+	result = Tcl_FSCopyFile(actualSource, target);
 	if ((result != TCL_OK) && (errno == EXDEV)) {
 	    result = TclCrossFilesystemCopy(interp, source, target);
 	}
@@ -651,6 +703,9 @@
     }
     if (errorBuffer != NULL) {
         Tcl_DecrRefCount(errorBuffer);
+    }
+    if (actualSource != NULL) {
+        Tcl_DecrRefCount(actualSource);
     }
     return result;
 }
