Attachment "tclFCmd.diff" to
ticket [591647ffff]
added by
vincentdarley
2002-08-06 23:51:19.
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;
}