diff options
Diffstat (limited to 'generic/tclPathObj.c')
| -rw-r--r-- | generic/tclPathObj.c | 547 |
1 files changed, 262 insertions, 285 deletions
diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c index 205c301..95c57bf 100644 --- a/generic/tclPathObj.c +++ b/generic/tclPathObj.c @@ -27,13 +27,15 @@ static int SetFsPathFromAny(Tcl_Interp *interp, Tcl_Obj *pathPtr); static int FindSplitPos(const char *path, int separator); static int IsSeparatorOrNull(int ch); static Tcl_Obj * GetExtension(Tcl_Obj *pathPtr); +static int MakePathFromNormalized(Tcl_Interp *interp, + Tcl_Obj *pathPtr); /* * Define the 'path' object type, which Tcl uses to represent file paths * internally. */ -static const Tcl_ObjType tclFsPathType = { +static Tcl_ObjType tclFsPathType = { "path", /* name */ FreeFsPathInternalRep, /* freeIntRepProc */ DupFsPathInternalRep, /* dupIntRepProc */ @@ -92,9 +94,7 @@ typedef struct FsPath { * generated during the correct filesystem * epoch. The epoch changes when * filesystem-mounts are changed. */ - struct FilesystemRecord *fsRecPtr; - /* Pointer to the filesystem record entry to - * use for this path. */ + Tcl_Filesystem *fsPtr; /* The Tcl_Filesystem that claims this path */ } FsPath; /* @@ -109,9 +109,9 @@ typedef struct FsPath { * fields. */ -#define PATHOBJ(pathPtr) ((FsPath *) (pathPtr)->internalRep.otherValuePtr) +#define PATHOBJ(pathPtr) ((FsPath *) (pathPtr)->internalRep.twoPtrValue.ptr1) #define SETPATHOBJ(pathPtr,fsPathPtr) \ - ((pathPtr)->internalRep.otherValuePtr = (void *) (fsPathPtr)) + ((pathPtr)->internalRep.twoPtrValue.ptr1 = (void *) (fsPathPtr)) #define PATHFLAGS(pathPtr) (PATHOBJ(pathPtr)->flags) /* @@ -152,14 +152,8 @@ typedef struct FsPath { Tcl_Obj * TclFSNormalizeAbsolutePath( Tcl_Interp *interp, /* Interpreter to use */ - Tcl_Obj *pathPtr, /* Absolute path to normalize */ - ClientData *clientDataPtr) /* If non-NULL, then may be set to the - * fs-specific clientData for this path. This - * will happen when that extra information can - * be calculated efficiently as a side-effect - * of normalization. */ + Tcl_Obj *pathPtr) /* Absolute path to normalize */ { - ClientData clientData = NULL; const char *dirSep, *oldDirSep; int first = 1; /* Set to zero once we've passed the first * directory separator - we can't use '..' to @@ -237,7 +231,7 @@ TclFSNormalizeAbsolutePath( retVal = Tcl_NewStringObj(path, dirSep - path); Tcl_IncrRefCount(retVal); } - Tcl_GetStringFromObj(retVal, &curLen); + (void) Tcl_GetStringFromObj(retVal, &curLen); if (curLen == 0) { Tcl_AppendToObj(retVal, dirSep, 1); } @@ -249,7 +243,7 @@ TclFSNormalizeAbsolutePath( continue; } if (dirSep[2] == '.' && IsSeparatorOrNull(dirSep[3])) { - Tcl_Obj *linkObj; + Tcl_Obj *link; int curLen; char *linkStr; @@ -263,22 +257,29 @@ TclFSNormalizeAbsolutePath( retVal = Tcl_NewStringObj(path, dirSep - path); Tcl_IncrRefCount(retVal); } - Tcl_GetStringFromObj(retVal, &curLen); + (void) Tcl_GetStringFromObj(retVal, &curLen); if (curLen == 0) { Tcl_AppendToObj(retVal, dirSep, 1); } if (!first || (tclPlatform == TCL_PLATFORM_UNIX)) { - linkObj = Tcl_FSLink(retVal, NULL, 0); - if (linkObj != NULL) { + link = Tcl_FSLink(retVal, NULL, 0); + + /* Safety check in case driver caused sharing */ + if (Tcl_IsShared(retVal)) { + TclDecrRefCount(retVal); + retVal = Tcl_DuplicateObj(retVal); + Tcl_IncrRefCount(retVal); + } + + if (link != NULL) { /* * Got a link. Need to check if the link is relative * or absolute, for those platforms where relative * links exist. */ - if (tclPlatform != TCL_PLATFORM_WINDOWS - && Tcl_FSGetPathType(linkObj) - == TCL_PATH_RELATIVE) { + if (tclPlatform != TCL_PLATFORM_WINDOWS && + Tcl_FSGetPathType(link) == TCL_PATH_RELATIVE) { /* * We need to follow this link which is relative * to retVal's directory. This means concatenating @@ -293,19 +294,14 @@ TclFSNormalizeAbsolutePath( break; } } - if (Tcl_IsShared(retVal)) { - TclDecrRefCount(retVal); - retVal = Tcl_DuplicateObj(retVal); - Tcl_IncrRefCount(retVal); - } /* * We want the trailing slash. */ Tcl_SetObjLength(retVal, curLen+1); - Tcl_AppendObjToObj(retVal, linkObj); - TclDecrRefCount(linkObj); + Tcl_AppendObjToObj(retVal, link); + TclDecrRefCount(link); linkStr = Tcl_GetStringFromObj(retVal, &curLen); } else { /* @@ -313,7 +309,12 @@ TclFSNormalizeAbsolutePath( */ TclDecrRefCount(retVal); - retVal = linkObj; + if (Tcl_IsShared(link)) { + retVal = Tcl_DuplicateObj(link); + TclDecrRefCount(link); + } else { + retVal = link; + } linkStr = Tcl_GetStringFromObj(retVal, &curLen); /* @@ -335,8 +336,8 @@ TclFSNormalizeAbsolutePath( } /* - * Either way, we now remove the last path element (but - * not the first character of the path). + * Either way, we now remove the last path element. + * (but not the first character of the path) */ while (--curLen >= 0) { @@ -397,7 +398,7 @@ TclFSNormalizeAbsolutePath( } /* - * Ensure a windows drive like C:/ has a trailing separator. + * Ensure a windows drive like C:/ has a trailing separator */ if (tclPlatform == TCL_PLATFORM_WINDOWS) { @@ -425,17 +426,14 @@ TclFSNormalizeAbsolutePath( * for normalizing a path. */ - TclFSNormalizeToUniquePath(interp, retVal, 0, &clientData); + TclFSNormalizeToUniquePath(interp, retVal, 0); /* * Since we know it is a normalized path, we can actually convert this * object into an FsPath for greater efficiency */ - TclFSMakePathFromNormalized(interp, retVal, clientData); - if (clientDataPtr != NULL) { - *clientDataPtr = clientData; - } + MakePathFromNormalized(interp, retVal); /* * This has a refCount of 1 for the caller, unlike many Tcl_Obj APIs. @@ -495,7 +493,7 @@ Tcl_FSGetPathType( Tcl_PathType TclFSGetPathType( Tcl_Obj *pathPtr, - const Tcl_Filesystem **filesystemPtrPtr, + Tcl_Filesystem **filesystemPtrPtr, int *driveNameLengthPtr) { FsPath *fsPathPtr; @@ -567,8 +565,7 @@ TclPathPart( if (pathPtr->typePtr == &tclFsPathType) { FsPath *fsPathPtr = PATHOBJ(pathPtr); - if (TclFSEpochOk(fsPathPtr->filesystemEpoch) - && (PATHFLAGS(pathPtr) != 0)) { + if (PATHFLAGS(pathPtr) != 0) { switch (portion) { case TCL_PATH_DIRNAME: { /* @@ -832,7 +829,7 @@ Tcl_FSJoinPath( { Tcl_Obj *res; int i; - const Tcl_Filesystem *fsPtr = NULL; + Tcl_Filesystem *fsPtr = NULL; if (elements < 0) { if (Tcl_ListObjLength(NULL, listObj, &elements) != TCL_OK) { @@ -878,18 +875,17 @@ Tcl_FSJoinPath( * could expand that in the future. */ - if ((i == (elements-2)) && (i == 0) - && (elt->typePtr == &tclFsPathType) - && !((elt->bytes != NULL) && (elt->bytes[0] == '\0'))) { - Tcl_Obj *tailObj; + if ((i == (elements-2)) && (i == 0) && (elt->typePtr == &tclFsPathType) + && !(elt->bytes != NULL && (elt->bytes[0] == '\0'))) { + Tcl_Obj *tail; - Tcl_ListObjIndex(NULL, listObj, i+1, &tailObj); - type = TclGetPathType(tailObj, NULL, NULL, NULL); + Tcl_ListObjIndex(NULL, listObj, i+1, &tail); + type = TclGetPathType(tail, NULL, NULL, NULL); if (type == TCL_PATH_RELATIVE) { const char *str; int len; - str = Tcl_GetStringFromObj(tailObj, &len); + str = Tcl_GetStringFromObj(tail, &len); if (len == 0) { /* * This happens if we try to handle the root volume '/'. @@ -937,16 +933,16 @@ Tcl_FSJoinPath( if (res != NULL) { TclDecrRefCount(res); } - return tailObj; + return tail; } else { - const char *str = TclGetString(tailObj); + const char *str = TclGetString(tail); if (tclPlatform == TCL_PLATFORM_WINDOWS) { if (strchr(str, '\\') == NULL) { if (res != NULL) { TclDecrRefCount(res); } - return tailObj; + return tail; } } } @@ -1023,8 +1019,8 @@ Tcl_FSJoinPath( } /* - * This element is just what we want to return already; no further - * manipulation is requred. + * This element is just what we want to return already - no + * further manipulation is requred. */ return elt; @@ -1070,16 +1066,22 @@ Tcl_FSJoinPath( int needsSep = 0; if (fsPtr->filesystemSeparatorProc != NULL) { - Tcl_Obj *sep = fsPtr->filesystemSeparatorProc(res); + Tcl_Obj *sep = (*fsPtr->filesystemSeparatorProc)(res); if (sep != NULL) { separator = TclGetString(sep)[0]; } + /* Safety check in case the VFS driver caused sharing */ + if (Tcl_IsShared(res)) { + TclDecrRefCount(res); + res = Tcl_DuplicateObj(res); + Tcl_IncrRefCount(res); + } } if (length > 0 && ptr[length -1] != '/') { Tcl_AppendToObj(res, &separator, 1); - length++; + Tcl_GetStringFromObj(res, &length); } Tcl_SetObjLength(res, length + (int) strlen(strElt)); @@ -1266,7 +1268,6 @@ TclNewFSPathObj( { FsPath *fsPathPtr; Tcl_Obj *pathPtr; - ThreadSpecificData *tsdPtr; const char *p; int state = 0, count = 0; @@ -1294,10 +1295,8 @@ TclNewFSPathObj( return pathPtr; } - tsdPtr = TCL_TSD_INIT(&tclFsDataKey); - pathPtr = Tcl_NewObj(); - fsPathPtr = ckalloc(sizeof(FsPath)); + fsPathPtr = (FsPath *) ckalloc(sizeof(FsPath)); /* * Set up the path. @@ -1309,8 +1308,8 @@ TclNewFSPathObj( fsPathPtr->cwdPtr = dirPtr; Tcl_IncrRefCount(dirPtr); fsPathPtr->nativePathPtr = NULL; - fsPathPtr->fsRecPtr = NULL; - fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; + fsPathPtr->fsPtr = NULL; + fsPathPtr->filesystemEpoch = 0; SETPATHOBJ(pathPtr, fsPathPtr); PATHFLAGS(pathPtr) = TCLPATH_APPENDED; @@ -1320,41 +1319,41 @@ TclNewFSPathObj( /* * Look for path components made up of only "." - * This is overly conservative analysis to keep simple. It may mark some - * things as needing more aggressive normalization that don't actually - * need it. No harm done. + * This is overly conservative analysis to keep simple. It may + * mark some things as needing more aggressive normalization + * that don't actually need it. No harm done. */ for (p = addStrRep; len > 0; p++, len--) { - switch (state) { - case 0: /* So far only "." since last dirsep or start */ - switch (*p) { - case '.': - count++; - break; - case '/': - case '\\': - case ':': - if (count) { - PATHFLAGS(pathPtr) |= TCLPATH_NEEDNORM; - len = 0; - } - break; - default: - count = 0; - state = 1; - } - case 1: /* Scanning for next dirsep */ - switch (*p) { - case '/': - case '\\': - case ':': - state = 0; - break; - } - } + switch (state) { + case 0: /* So far only "." since last dirsep or start */ + switch (*p) { + case '.': + count++; + break; + case '/': + case '\\': + case ':': + if (count) { + PATHFLAGS(pathPtr) |= TCLPATH_NEEDNORM; + len = 0; + } + break; + default: + count = 0; + state = 1; + } + case 1: /* Scanning for next dirsep */ + switch (*p) { + case '/': + case '\\': + case ':': + state = 0; + break; + } + } } if (len == 0 && count) { - PATHFLAGS(pathPtr) |= TCLPATH_NEEDNORM; + PATHFLAGS(pathPtr) |= TCLPATH_NEEDNORM; } return pathPtr; @@ -1369,37 +1368,20 @@ AppendPath( const char *bytes; Tcl_Obj *copy = Tcl_DuplicateObj(head); - bytes = Tcl_GetStringFromObj(copy, &numBytes); - /* - * Should we perhaps use 'Tcl_FSPathSeparator'? But then what about the - * Windows special case? Perhaps we should just check if cwd is a root - * volume. We should never get numBytes == 0 in this code path. + * This is likely buggy when dealing with virtual filesystem drivers + * that use some character other than "/" as a path separator. I know + * of no evidence that such a foolish thing exists. This solution was + * chosen so that "JoinPath" operations that pass through either path + * intrep produce the same results; that is, bugward compatibility. If + * we need to fix that bug here, it needs fixing in Tcl_FSJoinPath() too. */ - - switch (tclPlatform) { - case TCL_PLATFORM_UNIX: - if (bytes[numBytes-1] != '/') { - Tcl_AppendToObj(copy, "/", 1); - } - break; - - case TCL_PLATFORM_WINDOWS: - /* - * We need the extra 'numBytes != 2', and ':' checks because a volume - * relative path doesn't get a '/'. For example 'glob C:*cat*.exe' - * will return 'C:cat32.exe' - */ - - if (bytes[numBytes-1] != '/' && bytes[numBytes-1] != '\\') { - if (numBytes!= 2 || bytes[1] != ':') { - Tcl_AppendToObj(copy, "/", 1); - } - } - break; + bytes = Tcl_GetStringFromObj(tail, &numBytes); + if (numBytes == 0) { + Tcl_AppendToObj(copy, "/", 1); + } else { + TclpNativeJoinPath(copy, bytes); } - - Tcl_AppendObjToObj(copy, tail); return copy; } @@ -1439,7 +1421,70 @@ TclFSMakePathRelative( if (PATHFLAGS(pathPtr) != 0 && fsPathPtr->cwdPtr == cwdPtr) { - return fsPathPtr->normPathPtr; + pathPtr = fsPathPtr->normPathPtr; + + /* TODO: Determine how much, if any, of this forcing + * the relative path tail into the "path" Tcl_ObjType + * with a recorded cwdPtr context has any actual value. + * + * Nothing is getting cached. Not normPathPtr, not nativePathPtr, + * nor fsPtr, so storing the cwdPtr context against which such + * cached values might later be validated appears to be of no + * value. Take that away, and all this code is just a mildly + * optimized equivalent of a call to SetFsPathFromAny(). That + * optimization may have some value, *if* these value in fact + * get used as "path" values before used as something else. + * If not, though, whatever cost we pay below to convert to + * one of the "path" intreps is just a waste, it seems. The + * usual convention in the core is to delay ObjType conversion + * until it is needed and demanded, and I don't see why this + * section of code should be an exception to that. Leaving it + * in place for the rest of the 8.5.* releases just for sake + * of stability. + */ + + /* + * Free old representation. + */ + + if (pathPtr->typePtr != NULL) { + if (pathPtr->bytes == NULL) { + if (pathPtr->typePtr->updateStringProc == NULL) { + if (interp != NULL) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "can't find object" + "string representation", NULL); + } + return NULL; + } + pathPtr->typePtr->updateStringProc(pathPtr); + } + TclFreeIntRep(pathPtr); + } + + /* + * Now pathPtr is a string object. + */ + + fsPathPtr = (FsPath *) ckalloc(sizeof(FsPath)); + + /* + * Circular reference, by design. + */ + + fsPathPtr->translatedPathPtr = pathPtr; + fsPathPtr->normPathPtr = NULL; + fsPathPtr->cwdPtr = cwdPtr; + Tcl_IncrRefCount(cwdPtr); + fsPathPtr->nativePathPtr = NULL; + fsPathPtr->fsPtr = NULL; + fsPathPtr->filesystemEpoch = 0; + + SETPATHOBJ(pathPtr, fsPathPtr); + PATHFLAGS(pathPtr) = 0; + pathPtr->typePtr = &tclFsPathType; + + return pathPtr; } } @@ -1482,7 +1527,7 @@ TclFSMakePathRelative( /* *--------------------------------------------------------------------------- * - * TclFSMakePathFromNormalized -- + * MakePathFromNormalized -- * * Like SetFsPathFromAny, but assumes the given object is an absolute * normalized path. Only for internal use. @@ -1496,15 +1541,12 @@ TclFSMakePathRelative( *--------------------------------------------------------------------------- */ -int -TclFSMakePathFromNormalized( +static int +MakePathFromNormalized( Tcl_Interp *interp, /* Used for error reporting if not NULL. */ - Tcl_Obj *pathPtr, /* The object to convert. */ - ClientData nativeRep) /* The native rep for the object, if known - * else NULL. */ + Tcl_Obj *pathPtr) /* The object to convert. */ { FsPath *fsPathPtr; - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); if (pathPtr->typePtr == &tclFsPathType) { return TCL_OK; @@ -1521,8 +1563,6 @@ TclFSMakePathFromNormalized( Tcl_ResetResult(interp); Tcl_AppendResult(interp, "can't find object" "string representation", NULL); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "PATH", "WTF", - NULL); } return TCL_ERROR; } @@ -1531,7 +1571,7 @@ TclFSMakePathFromNormalized( TclFreeIntRep(pathPtr); } - fsPathPtr = ckalloc(sizeof(FsPath)); + fsPathPtr = (FsPath *) ckalloc(sizeof(FsPath)); /* * It's a pure normalized absolute path. @@ -1545,9 +1585,10 @@ TclFSMakePathFromNormalized( fsPathPtr->normPathPtr = pathPtr; fsPathPtr->cwdPtr = NULL; - fsPathPtr->nativePathPtr = nativeRep; - fsPathPtr->fsRecPtr = NULL; - fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; + fsPathPtr->nativePathPtr = NULL; + fsPathPtr->fsPtr = NULL; + /* Remember the epoch under which we decided pathPtr was normalized */ + fsPathPtr->filesystemEpoch = TclFSEpoch(); SETPATHOBJ(pathPtr, fsPathPtr); PATHFLAGS(pathPtr) = 0; @@ -1583,17 +1624,16 @@ TclFSMakePathFromNormalized( Tcl_Obj * Tcl_FSNewNativePath( - const Tcl_Filesystem *fromFilesystem, + Tcl_Filesystem *fromFilesystem, ClientData clientData) { - Tcl_Obj *pathPtr; + Tcl_Obj *pathPtr = NULL; FsPath *fsPathPtr; - FilesystemRecord *fsFromPtr; - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); - pathPtr = TclFSInternalToNormalized(fromFilesystem, clientData, - &fsFromPtr); + if (fromFilesystem->internalToNormalizedProc != NULL) { + pathPtr = (*fromFilesystem->internalToNormalizedProc)(clientData); + } if (pathPtr == NULL) { return NULL; } @@ -1613,7 +1653,7 @@ Tcl_FSNewNativePath( TclFreeIntRep(pathPtr); } - fsPathPtr = ckalloc(sizeof(FsPath)); + fsPathPtr = (FsPath *) ckalloc(sizeof(FsPath)); fsPathPtr->translatedPathPtr = NULL; @@ -1624,9 +1664,8 @@ Tcl_FSNewNativePath( fsPathPtr->normPathPtr = pathPtr; fsPathPtr->cwdPtr = NULL; fsPathPtr->nativePathPtr = clientData; - fsPathPtr->fsRecPtr = fsFromPtr; - fsPathPtr->fsRecPtr->fileRefCount++; - fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; + fsPathPtr->fsPtr = fromFilesystem; + fsPathPtr->filesystemEpoch = TclFSEpoch(); SETPATHOBJ(pathPtr, fsPathPtr); PATHFLAGS(pathPtr) = 0; @@ -1682,8 +1721,14 @@ Tcl_FSGetTranslatedPath( } retObj = Tcl_FSJoinToPath(translatedCwdPtr, 1, - &srcFsPathPtr->normPathPtr); + &(srcFsPathPtr->normPathPtr)); srcFsPathPtr->translatedPathPtr = retObj; + if (translatedCwdPtr->typePtr == &tclFsPathType) { + srcFsPathPtr->filesystemEpoch + = PATHOBJ(translatedCwdPtr)->filesystemEpoch; + } else { + srcFsPathPtr->filesystemEpoch = 0; + } Tcl_IncrRefCount(retObj); Tcl_DecrRefCount(translatedCwdPtr); } else { @@ -1738,7 +1783,7 @@ Tcl_FSGetTranslatedStringPath( if (transPtr != NULL) { int len; const char *orig = Tcl_GetStringFromObj(transPtr, &len); - char *result = ckalloc(len+1); + char *result = (char *) ckalloc((unsigned) len+1); memcpy(result, orig, (size_t) len+1); TclDecrRefCount(transPtr); @@ -1786,8 +1831,7 @@ Tcl_FSGetNormalizedPath( */ Tcl_Obj *dir, *copy; - int cwdLen, pathType; - ClientData clientData = NULL; + int tailLen, cwdLen, pathType; pathType = Tcl_FSGetPathType(fsPathPtr->cwdPtr); dir = Tcl_FSGetNormalizedPath(interp, fsPathPtr->cwdPtr); @@ -1799,7 +1843,12 @@ Tcl_FSGetNormalizedPath( UpdateStringOfFsPath(pathPtr); } - copy = AppendPath(dir, fsPathPtr->normPathPtr); + Tcl_GetStringFromObj(fsPathPtr->normPathPtr, &tailLen); + if (tailLen) { + copy = AppendPath(dir, fsPathPtr->normPathPtr); + } else { + copy = Tcl_DuplicateObj(dir); + } Tcl_IncrRefCount(dir); Tcl_IncrRefCount(copy); @@ -1814,29 +1863,28 @@ Tcl_FSGetNormalizedPath( if (PATHFLAGS(pathPtr) & TCLPATH_NEEDNORM) { /* - * If the "tail" part has components (like /../) that cause the - * combined path to need more complete normalizing, call on the - * more powerful routine to accomplish that so we avoid [Bug - * 2385549] ... + * If the "tail" part has components (like /../) that cause + * the combined path to need more complete normalizing, + * call on the more powerful routine to accomplish that so + * we avoid [Bug 2385549] ... */ - Tcl_Obj *newCopy = TclFSNormalizeAbsolutePath(interp, copy, NULL); - + Tcl_Obj *newCopy = TclFSNormalizeAbsolutePath(interp, copy); Tcl_DecrRefCount(copy); copy = newCopy; } else { /* - * ... but in most cases where we join a trouble free tail to a - * normalized head, we can more efficiently normalize the combined - * path by passing over only the unnormalized tail portion. When - * this is sufficient, prior developers claim this should be much - * faster. We use 'cwdLen-1' so that we are already pointing at - * the dir-separator that we know about. The normalization code - * will actually start off directly after that separator. + * ... but in most cases where we join a trouble free tail + * to a normalized head, we can more efficiently normalize the + * combined path by passing over only the unnormalized tail + * portion. When this is sufficient, prior developers claim + * this should be much faster. We use 'cwdLen-1' so that we are + * already pointing at the dir-separator that we know about. + * The normalization code will actually start off directly + * after that separator. */ - TclFSNormalizeToUniquePath(interp, copy, cwdLen-1, - (fsPathPtr->nativePathPtr == NULL ? &clientData : NULL)); + TclFSNormalizeToUniquePath(interp, copy, cwdLen-1); } /* Now we need to construct the new path object. */ @@ -1846,11 +1894,11 @@ Tcl_FSGetNormalizedPath( /* * NOTE: here we are (dangerously?) assuming that origDir points - * to a Tcl_Obj with Tcl_ObjType == &tclFsPathType. The + * to a Tcl_Obj with Tcl_ObjType == &tclFsPathType . The * pathType = Tcl_FSGetPathType(fsPathPtr->cwdPtr); - * above that set the pathType value should have established that, - * but it's far less clear on what basis we know there's been no - * shimmering since then. + * above that set the pathType value should have established + * that, but it's far less clear on what basis we know there's + * been no shimmering since then. */ FsPath *origDirFsPathPtr = PATHOBJ(origDir); @@ -1879,15 +1927,6 @@ Tcl_FSGetNormalizedPath( TclDecrRefCount(dir); } - if (clientData != NULL) { - /* - * This may be unnecessary. It appears that the - * TclFSNormalizeToUniquePath call above should have already set - * this up. Not changing out of fear of the unknown. - */ - - fsPathPtr->nativePathPtr = clientData; - } PATHFLAGS(pathPtr) = 0; } @@ -1908,7 +1947,6 @@ Tcl_FSGetNormalizedPath( } else if (fsPathPtr->normPathPtr == NULL) { int cwdLen; Tcl_Obj *copy; - ClientData clientData = NULL; copy = AppendPath(fsPathPtr->cwdPtr, pathPtr); @@ -1920,17 +1958,12 @@ Tcl_FSGetNormalizedPath( * of the previously normalized 'dir'. This should be much faster! */ - TclFSNormalizeToUniquePath(interp, copy, cwdLen-1, - (fsPathPtr->nativePathPtr == NULL ? &clientData : NULL)); + TclFSNormalizeToUniquePath(interp, copy, cwdLen-1); fsPathPtr->normPathPtr = copy; Tcl_IncrRefCount(fsPathPtr->normPathPtr); - if (clientData != NULL) { - fsPathPtr->nativePathPtr = clientData; - } } } if (fsPathPtr->normPathPtr == NULL) { - ClientData clientData = NULL; Tcl_Obj *useThisCwd = NULL; int pureNormalized = 1; @@ -1953,11 +1986,11 @@ Tcl_FSGetNormalizedPath( if (path[0] == '\0') { /* - * Special handling for the empty string value. This one is very - * weird with [file normalize {}] => {}. (The reasoning supporting - * this is unknown to DGP, but he fears changing it.) Attempt here - * to keep the expectations of other parts of Tcl_Filesystem code - * about state of the FsPath fields satisfied. + * Special handling for the empty string value. This one is + * very weird with [file normalize {}] => {}. (The reasoning + * supporting this is unknown to DGP, but he fears changing it.) + * Attempt here to keep the expectations of other parts of + * Tcl_Filesystem code about state of the FsPath fields satisfied. * * In particular, capture the cwd value and save so it can be * stored in the cwdPtr field below. @@ -2012,12 +2045,7 @@ Tcl_FSGetNormalizedPath( */ fsPathPtr->normPathPtr = TclFSNormalizeAbsolutePath(interp, - absolutePath, - (fsPathPtr->nativePathPtr == NULL ? &clientData : NULL)); - if (0 && (clientData != NULL)) { - fsPathPtr->nativePathPtr = - fsPathPtr->fsRecPtr->fsPtr->dupInternalRepProc(clientData); - } + absolutePath); /* * Check if path is pure normalized (this can only be the case if it @@ -2025,12 +2053,8 @@ Tcl_FSGetNormalizedPath( */ if (pureNormalized) { - int normPathLen, pathLen; - const char *normPath; - - path = TclGetStringFromObj(pathPtr, &pathLen); - normPath = TclGetStringFromObj(fsPathPtr->normPathPtr, &normPathLen); - if ((pathLen == normPathLen) && !memcmp(path, normPath, pathLen)) { + if (!strcmp(TclGetString(fsPathPtr->normPathPtr), + TclGetString(pathPtr))) { /* * The path was already normalized. Get rid of the duplicate. */ @@ -2085,7 +2109,7 @@ Tcl_FSGetNormalizedPath( ClientData Tcl_FSGetInternalRep( Tcl_Obj *pathPtr, - const Tcl_Filesystem *fsPtr) + Tcl_Filesystem *fsPtr) { FsPath *srcFsPathPtr; @@ -2108,7 +2132,7 @@ Tcl_FSGetInternalRep( * not easily achievable with the current implementation. */ - if (srcFsPathPtr->fsRecPtr == NULL) { + if (srcFsPathPtr->fsPtr == NULL) { /* * This only usually happens in wrappers like TclpStat which create a * string object and pass it to TclpObjStat. Code which calls the @@ -2128,7 +2152,7 @@ Tcl_FSGetInternalRep( */ srcFsPathPtr = PATHOBJ(pathPtr); - if (srcFsPathPtr->fsRecPtr == NULL) { + if (srcFsPathPtr->fsPtr == NULL) { return NULL; } } @@ -2140,7 +2164,7 @@ Tcl_FSGetInternalRep( * for this is we ask what filesystem this path belongs to. */ - if (fsPtr != srcFsPathPtr->fsRecPtr->fsPtr) { + if (fsPtr != srcFsPathPtr->fsPtr) { const Tcl_Filesystem *actualFs = Tcl_FSGetFileSystemForPath(pathPtr); if (actualFs == fsPtr) { @@ -2153,12 +2177,12 @@ Tcl_FSGetInternalRep( Tcl_FSCreateInternalRepProc *proc; char *nativePathPtr; - proc = srcFsPathPtr->fsRecPtr->fsPtr->createInternalRepProc; + proc = srcFsPathPtr->fsPtr->createInternalRepProc; if (proc == NULL) { return NULL; } - nativePathPtr = proc(pathPtr); + nativePathPtr = (*proc)(pathPtr); srcFsPathPtr = PATHOBJ(pathPtr); srcFsPathPtr->nativePathPtr = nativePathPtr; } @@ -2187,7 +2211,7 @@ Tcl_FSGetInternalRep( int TclFSEnsureEpochOk( Tcl_Obj *pathPtr, - const Tcl_Filesystem **fsPtrPtr) + Tcl_Filesystem **fsPtrPtr) { FsPath *srcFsPathPtr; @@ -2221,8 +2245,8 @@ TclFSEnsureEpochOk( * Check whether the object is already assigned to a fs. */ - if (srcFsPathPtr->fsRecPtr != NULL) { - *fsPtrPtr = srcFsPathPtr->fsRecPtr->fsPtr; + if (srcFsPathPtr->fsPtr != NULL) { + *fsPtrPtr = srcFsPathPtr->fsPtr; } return TCL_OK; } @@ -2246,10 +2270,9 @@ TclFSEnsureEpochOk( void TclFSSetPathDetails( Tcl_Obj *pathPtr, - FilesystemRecord *fsRecPtr, + Tcl_Filesystem *fsPtr, ClientData clientData) { - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); FsPath *srcFsPathPtr; /* @@ -2263,10 +2286,9 @@ TclFSSetPathDetails( } srcFsPathPtr = PATHOBJ(pathPtr); - srcFsPathPtr->fsRecPtr = fsRecPtr; + srcFsPathPtr->fsPtr = fsPtr; srcFsPathPtr->nativePathPtr = clientData; - srcFsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; - fsRecPtr->fileRefCount++; + srcFsPathPtr->filesystemEpoch = TclFSEpoch(); } /* @@ -2291,7 +2313,7 @@ Tcl_FSEqualPaths( Tcl_Obj *firstPtr, Tcl_Obj *secondPtr) { - const char *firstStr, *secondStr; + char *firstStr, *secondStr; int firstLen, secondLen, tempErrno; if (firstPtr == secondPtr) { @@ -2301,9 +2323,9 @@ Tcl_FSEqualPaths( if (firstPtr == NULL || secondPtr == NULL) { return 0; } - firstStr = TclGetStringFromObj(firstPtr, &firstLen); - secondStr = TclGetStringFromObj(secondPtr, &secondLen); - if ((firstLen == secondLen) && !memcmp(firstStr, secondStr, firstLen)) { + firstStr = Tcl_GetStringFromObj(firstPtr, &firstLen); + secondStr = Tcl_GetStringFromObj(secondPtr, &secondLen); + if ((firstLen == secondLen) && (strcmp(firstStr, secondStr) == 0)) { return 1; } @@ -2321,9 +2343,9 @@ Tcl_FSEqualPaths( return 0; } - firstStr = TclGetStringFromObj(firstPtr, &firstLen); - secondStr = TclGetStringFromObj(secondPtr, &secondLen); - return ((firstLen == secondLen) && !memcmp(firstStr, secondStr, firstLen)); + firstStr = Tcl_GetStringFromObj(firstPtr, &firstLen); + secondStr = Tcl_GetStringFromObj(secondPtr, &secondLen); + return (firstLen == secondLen) && (strcmp(firstStr, secondStr) == 0); } /* @@ -2355,10 +2377,6 @@ SetFsPathFromAny( FsPath *fsPathPtr; Tcl_Obj *transPtr; char *name; -#if defined(__CYGWIN__) && defined(__WIN32__) - int copied = 0; -#endif - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); if (pathPtr->typePtr == &tclFsPathType) { return TCL_OK; @@ -2421,8 +2439,6 @@ SetFsPathFromAny( Tcl_ResetResult(interp); Tcl_AppendResult(interp, "couldn't find HOME environment " "variable to expand path", NULL); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "PATH", - "HOMELESS", NULL); } return TCL_ERROR; } @@ -2440,8 +2456,6 @@ SetFsPathFromAny( Tcl_ResetResult(interp); Tcl_AppendResult(interp, "user \"", name+1, "\" doesn't exist", NULL); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "PATH", "NOUSER", - NULL); } Tcl_DStringFree(&temp); if (split != len) { @@ -2502,49 +2516,31 @@ SetFsPathFromAny( } Tcl_DStringFree(&temp); } else { + /* Bug 3479689: protect 0-refcount pathPth from getting freed */ + pathPtr->refCount++; transPtr = Tcl_FSJoinToPath(pathPtr, 0, NULL); + pathPtr->refCount--; } -#if defined(__CYGWIN__) && defined(__WIN32__) - { - char winbuf[MAX_PATH+1]; - - /* - * In the Cygwin world, call conv_to_win32_path in order to use the - * mount table to translate the file name into something Windows will - * understand. Take care when converting empty strings! - */ - - name = Tcl_GetStringFromObj(transPtr, &len); - if (len > 0) { - cygwin_conv_to_win32_path(name, winbuf); - TclWinNoBackslash(winbuf); - if (Tcl_IsShared(transPtr)) { - copied = 1; - transPtr = Tcl_DuplicateObj(transPtr); - Tcl_IncrRefCount(transPtr); - } - Tcl_SetStringObj(transPtr, winbuf, -1); - } - } -#endif /* __CYGWIN__ && __WIN32__ */ - /* * Now we have a translated filename in 'transPtr'. This will have forward * slashes on Windows, and will not contain any ~user sequences. */ - fsPathPtr = ckalloc(sizeof(FsPath)); + fsPathPtr = (FsPath *) ckalloc(sizeof(FsPath)); fsPathPtr->translatedPathPtr = transPtr; if (transPtr != pathPtr) { Tcl_IncrRefCount(fsPathPtr->translatedPathPtr); + /* Redo translation when $env(HOME) changes */ + fsPathPtr->filesystemEpoch = TclFSEpoch(); + } else { + fsPathPtr->filesystemEpoch = 0; } fsPathPtr->normPathPtr = NULL; fsPathPtr->cwdPtr = NULL; fsPathPtr->nativePathPtr = NULL; - fsPathPtr->fsRecPtr = NULL; - fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; + fsPathPtr->fsPtr = NULL; /* * Free old representation before installing our new one. @@ -2554,12 +2550,6 @@ SetFsPathFromAny( SETPATHOBJ(pathPtr, fsPathPtr); PATHFLAGS(pathPtr) = 0; pathPtr->typePtr = &tclFsPathType; -#if defined(__CYGWIN__) && defined(__WIN32__) - if (copied) { - Tcl_DecrRefCount(transPtr); - } -#endif - return TCL_OK; } @@ -2583,27 +2573,17 @@ FreeFsPathInternalRep( if (fsPathPtr->cwdPtr != NULL) { TclDecrRefCount(fsPathPtr->cwdPtr); } - if (fsPathPtr->nativePathPtr != NULL && fsPathPtr->fsRecPtr != NULL) { + if (fsPathPtr->nativePathPtr != NULL && fsPathPtr->fsPtr != NULL) { Tcl_FSFreeInternalRepProc *freeProc = - fsPathPtr->fsRecPtr->fsPtr->freeInternalRepProc; + fsPathPtr->fsPtr->freeInternalRepProc; if (freeProc != NULL) { - freeProc(fsPathPtr->nativePathPtr); + (*freeProc)(fsPathPtr->nativePathPtr); fsPathPtr->nativePathPtr = NULL; } } - if (fsPathPtr->fsRecPtr != NULL) { - fsPathPtr->fsRecPtr->fileRefCount--; - if (fsPathPtr->fsRecPtr->fileRefCount <= 0) { - /* - * It has been unregistered already. - */ - ckfree(fsPathPtr->fsRecPtr); - } - } - - ckfree(fsPathPtr); + ckfree((char *) fsPathPtr); pathPtr->typePtr = NULL; } @@ -2613,7 +2593,7 @@ DupFsPathInternalRep( Tcl_Obj *copyPtr) /* Path obj with internal rep to set. */ { FsPath *srcFsPathPtr = PATHOBJ(srcPtr); - FsPath *copyFsPathPtr = ckalloc(sizeof(FsPath)); + FsPath *copyFsPathPtr = (FsPath *) ckalloc(sizeof(FsPath)); SETPATHOBJ(copyPtr, copyFsPathPtr); @@ -2644,25 +2624,22 @@ DupFsPathInternalRep( copyFsPathPtr->flags = srcFsPathPtr->flags; - if (srcFsPathPtr->fsRecPtr != NULL + if (srcFsPathPtr->fsPtr != NULL && srcFsPathPtr->nativePathPtr != NULL) { Tcl_FSDupInternalRepProc *dupProc = - srcFsPathPtr->fsRecPtr->fsPtr->dupInternalRepProc; + srcFsPathPtr->fsPtr->dupInternalRepProc; if (dupProc != NULL) { copyFsPathPtr->nativePathPtr = - dupProc(srcFsPathPtr->nativePathPtr); + (*dupProc)(srcFsPathPtr->nativePathPtr); } else { copyFsPathPtr->nativePathPtr = NULL; } } else { copyFsPathPtr->nativePathPtr = NULL; } - copyFsPathPtr->fsRecPtr = srcFsPathPtr->fsRecPtr; + copyFsPathPtr->fsPtr = srcFsPathPtr->fsPtr; copyFsPathPtr->filesystemEpoch = srcFsPathPtr->filesystemEpoch; - if (copyFsPathPtr->fsRecPtr != NULL) { - copyFsPathPtr->fsRecPtr->fileRefCount++; - } copyPtr->typePtr = &tclFsPathType; } |
