summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixFCmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tclUnixFCmd.c')
-rw-r--r--unix/tclUnixFCmd.c80
1 files changed, 64 insertions, 16 deletions
diff --git a/unix/tclUnixFCmd.c b/unix/tclUnixFCmd.c
index 80383d8..49131de 100644
--- a/unix/tclUnixFCmd.c
+++ b/unix/tclUnixFCmd.c
@@ -10,7 +10,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclUnixFCmd.c,v 1.17 2002/02/15 14:28:50 dkf Exp $
+ * RCS: @(#) $Id: tclUnixFCmd.c,v 1.18 2002/03/24 11:41:51 vincentdarley Exp $
*
* Portions of this code were derived from NetBSD source code which has
* the following copyright notice:
@@ -191,7 +191,7 @@ TclpObjRenameFile(srcPathPtr, destPathPtr)
Tcl_Obj *srcPathPtr;
Tcl_Obj *destPathPtr;
{
- return DoRenameFile(Tcl_FSGetNativePath(srcPathPtr),
+ return DoRenameFile(Tcl_FSGetNativePath(srcPathPtr),
Tcl_FSGetNativePath(destPathPtr));
}
@@ -308,7 +308,7 @@ TclpObjCopyFile(srcPathPtr, destPathPtr)
Tcl_Obj *srcPathPtr;
Tcl_Obj *destPathPtr;
{
- return DoCopyFile(Tcl_FSGetNativePath(srcPathPtr),
+ return DoCopyFile(Tcl_FSGetNativePath(srcPathPtr),
Tcl_FSGetNativePath(destPathPtr));
}
@@ -1618,17 +1618,17 @@ GetModeFromPermString(interp, modeStringPtr, modePtr)
* TclpObjNormalizePath --
*
* This function scans through a path specification and replaces
- * it, in place, with a normalized version. On unix, this simply
- * ascertains where the valid path ends, and makes no change in
- * place.
+ * it, in place, with a normalized version. A normalized version
+ * is one in which all symlinks in the path are replaced with
+ * their expanded form (except a symlink at the very end of the
+ * path).
*
* Results:
* The new 'nextCheckpoint' value, giving as far as we could
* understand in the path.
*
* Side effects:
- * The pathPtr string, which must contain a valid path, is
- * not modified (unlike Windows, MacOS versions).
+ * The pathPtr string, is modified.
*
*---------------------------------------------------------------------------
*/
@@ -1640,13 +1640,15 @@ TclpObjNormalizePath(interp, pathPtr, nextCheckpoint)
int nextCheckpoint;
{
char *currentPathEndPosition;
- char *path = Tcl_GetString(pathPtr);
+ int pathLen;
+ char cur;
+ char *path = Tcl_GetStringFromObj(pathPtr, &pathLen);
currentPathEndPosition = path + nextCheckpoint;
while (1) {
- char cur = *currentPathEndPosition;
- if ((cur == '/' || cur == 0) && (path != currentPathEndPosition)) {
+ cur = *currentPathEndPosition;
+ if ((cur == '/') && (path != currentPathEndPosition)) {
/* Reached directory separator, or end of string */
Tcl_DString ds;
CONST char *nativePath;
@@ -1660,13 +1662,59 @@ TclpObjNormalizePath(interp, pathPtr, nextCheckpoint)
/* File doesn't exist */
break;
}
- if (cur == 0) {
- break;
- }
+ /* Update the acceptable point */
+ nextCheckpoint = currentPathEndPosition - path;
+ } else if (cur == 0) {
+ break;
}
currentPathEndPosition++;
}
- nextCheckpoint = currentPathEndPosition - path;
- /* We should really now convert this to a canonical path */
+ /*
+ * We should really now convert this to a canonical path. We do
+ * that with 'realpath' if we have it available. Otherwise we could
+ * step through every single path component, checking whether it is a
+ * symlink, but that would be a lot of work, and most modern OSes
+ * have 'realpath'.
+ */
+#ifndef NO_REALPATH
+ if (1) {
+ char normPath[MAXPATHLEN];
+ Tcl_DString ds;
+ CONST char *nativePath = Tcl_UtfToExternalDString(NULL, path,
+ nextCheckpoint, &ds);
+
+ if (realpath((char *) nativePath, normPath) != NULL) {
+ /*
+ * Free up the native path and put in its place the
+ * converted, normalized path.
+ */
+ Tcl_DStringFree(&ds);
+ Tcl_ExternalToUtfDString(NULL,normPath,
+ strlen(normPath),&ds);
+
+ if (path[nextCheckpoint] != '\0') {
+ /* not at end, append remaining path */
+ int normLen = Tcl_DStringLength(&ds);
+ Tcl_DStringAppend(&ds, path + nextCheckpoint,
+ pathLen - nextCheckpoint);
+ /*
+ * We recognise up to and including the directory
+ * separator.
+ */
+ nextCheckpoint = normLen + 1;
+ } else {
+ /* We recognise the whole string */
+ nextCheckpoint = Tcl_DStringLength(&ds);
+ }
+ /*
+ * Overwrite with the normalized path.
+ */
+ Tcl_SetStringObj(pathPtr,Tcl_DStringValue(&ds),
+ Tcl_DStringLength(&ds));
+ }
+ Tcl_DStringFree(&ds);
+ }
+#endif /* !NO_REALPATH */
+
return nextCheckpoint;
}