diff options
author | vincentdarley <vincentdarley> | 2003-12-17 17:47:27 (GMT) |
---|---|---|
committer | vincentdarley <vincentdarley> | 2003-12-17 17:47:27 (GMT) |
commit | 298b0c4ef39a21c71fcb823f41bb903203d8430b (patch) | |
tree | 90eee000212ab783686879d39d2836490e8198c8 /unix/tclUnixFile.c | |
parent | 1e34c25106c2c1a8713ef0aef0ffc4d2eccdbeeb (diff) | |
download | tcl-298b0c4ef39a21c71fcb823f41bb903203d8430b.zip tcl-298b0c4ef39a21c71fcb823f41bb903203d8430b.tar.gz tcl-298b0c4ef39a21c71fcb823f41bb903203d8430b.tar.bz2 |
fix to file normalization with relative links
Diffstat (limited to 'unix/tclUnixFile.c')
-rw-r--r-- | unix/tclUnixFile.c | 58 |
1 files changed, 47 insertions, 11 deletions
diff --git a/unix/tclUnixFile.c b/unix/tclUnixFile.c index 66c31b9..96d2fda 100644 --- a/unix/tclUnixFile.c +++ b/unix/tclUnixFile.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclUnixFile.c,v 1.35 2003/12/12 17:09:34 vincentdarley Exp $ + * RCS: @(#) $Id: tclUnixFile.c,v 1.36 2003/12/17 17:47:28 vincentdarley Exp $ */ #include "tclInt.h" @@ -715,21 +715,57 @@ TclpObjLink(pathPtr, toPtr, linkAction) { if (toPtr != NULL) { CONST char *src = Tcl_FSGetNativePath(pathPtr); - CONST char *target = Tcl_FSGetNativePath(toPtr); + CONST char *target = NULL; + if (src == NULL) return NULL; - if (src == NULL || target == NULL) { - return NULL; + /* + * If we're making a symbolic link and the path is relative, + * then we must check whether it exists _relative_ to the + * directory in which the src is found (not relative to the + * current cwd which is just not relevant in this case). + * + * If we're making a hard link, then a relative path is + * just converted to absolute relative to the cwd. + */ + if ((linkAction & TCL_CREATE_SYMBOLIC_LINK) + && (Tcl_FSGetPathType(toPtr) == TCL_PATH_RELATIVE)) { + Tcl_Obj *dirPtr, *absPtr; + dirPtr = TclFileDirname(NULL, pathPtr); + if (dirPtr == NULL) { + return NULL; + } + absPtr = Tcl_FSJoinToPath(dirPtr, 1, &toPtr); + Tcl_IncrRefCount(absPtr); + if (Tcl_FSAccess(absPtr, F_OK) == -1) { + Tcl_DecrRefCount(absPtr); + Tcl_DecrRefCount(dirPtr); + /* target doesn't exist */ + errno = ENOENT; + return NULL; + } + /* + * Target exists; we'll construct the relative + * path we want below. + */ + Tcl_DecrRefCount(absPtr); + Tcl_DecrRefCount(dirPtr); + } else { + target = Tcl_FSGetNativePath(toPtr); + if (access(target, F_OK) == -1) { + /* target doesn't exist */ + errno = ENOENT; + return NULL; + } + if (target == NULL) { + return NULL; + } } + if (access(src, F_OK) != -1) { /* src exists */ errno = EEXIST; return NULL; } - if (access(target, F_OK) == -1) { - /* target doesn't exist */ - errno = ENOENT; - return NULL; - } /* * Check symbolic link flag first, since we prefer to * create these. @@ -740,8 +776,8 @@ TclpObjLink(pathPtr, toPtr, linkAction) Tcl_Obj *transPtr; /* * Now we don't want to link to the absolute, normalized path. - * Relative links are quite acceptable, as are links to '~user', - * for example. + * Relative links are quite acceptable (but links to ~user + * are not -- these must be expanded first). */ transPtr = Tcl_FSGetTranslatedPath(NULL, toPtr); if (transPtr == NULL) { |