summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authorvincentdarley <vincentdarley>2003-10-13 16:48:05 (GMT)
committervincentdarley <vincentdarley>2003-10-13 16:48:05 (GMT)
commit8eb669eea67550509d7223f16753001c943d3ee3 (patch)
treeccb9c39961e0f152b829dff8a1e6b47fcc6d99a3 /generic
parent805e2ca6c7ac542dd65701379332c399bde0dd1d (diff)
downloadtcl-8eb669eea67550509d7223f16753001c943d3ee3.zip
tcl-8eb669eea67550509d7223f16753001c943d3ee3.tar.gz
tcl-8eb669eea67550509d7223f16753001c943d3ee3.tar.bz2
filesystem bug fixes
Diffstat (limited to 'generic')
-rw-r--r--generic/tcl.h5
-rw-r--r--generic/tclFileName.c12
-rw-r--r--generic/tclIOUtil.c177
-rw-r--r--generic/tclPathObj.c16
-rw-r--r--generic/tclTest.c20
5 files changed, 208 insertions, 22 deletions
diff --git a/generic/tcl.h b/generic/tcl.h
index 692cbf3..e89690d 100644
--- a/generic/tcl.h
+++ b/generic/tcl.h
@@ -13,7 +13,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tcl.h,v 1.165 2003/09/04 16:44:12 dgp Exp $
+ * RCS: @(#) $Id: tcl.h,v 1.166 2003/10/13 16:48:06 vincentdarley Exp $
*/
#ifndef _TCL
@@ -1615,6 +1615,7 @@ typedef struct Tcl_GlobTypeData {
#define TCL_GLOB_TYPE_FILE (1<<4)
#define TCL_GLOB_TYPE_LINK (1<<5)
#define TCL_GLOB_TYPE_SOCK (1<<6)
+#define TCL_GLOB_TYPE_MOUNT (1<<7)
#define TCL_GLOB_PERM_RONLY (1<<0)
#define TCL_GLOB_PERM_HIDDEN (1<<1)
@@ -1790,7 +1791,7 @@ typedef struct Tcl_Filesystem {
* 'Tcl_FSLink()' call. Should be
* implemented only if the filesystem supports
* links (reading or creating). */
- Tcl_FSListVolumesProc *listVolumesProc;
+ Tcl_FSListVolumesProc *listVolumesProc;
/* Function to list any filesystem volumes
* added by this filesystem. Should be
* implemented only if the filesystem adds
diff --git a/generic/tclFileName.c b/generic/tclFileName.c
index f607def..c9995f6 100644
--- a/generic/tclFileName.c
+++ b/generic/tclFileName.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: tclFileName.c,v 1.43 2003/07/17 00:20:41 hobbs Exp $
+ * RCS: @(#) $Id: tclFileName.c,v 1.44 2003/10/13 16:48:06 vincentdarley Exp $
*/
#include "tclInt.h"
@@ -1380,17 +1380,19 @@ Tcl_TranslateFileName(interp, name, bufferPtr)
* with name after tilde substitution. */
{
Tcl_Obj *path = Tcl_NewStringObj(name, -1);
- CONST char *result;
+ Tcl_Obj *transPtr;
Tcl_IncrRefCount(path);
- result = Tcl_FSGetTranslatedStringPath(interp, path);
- if (result == NULL) {
+ transPtr = Tcl_FSGetTranslatedPath(interp, path);
+ if (transPtr == NULL) {
Tcl_DecrRefCount(path);
return NULL;
}
+
Tcl_DStringInit(bufferPtr);
- Tcl_DStringAppend(bufferPtr, result, -1);
+ Tcl_DStringAppend(bufferPtr, Tcl_GetString(transPtr), -1);
Tcl_DecrRefCount(path);
+ Tcl_DecrRefCount(transPtr);
/*
* Convert forward slashes to backslashes in Windows paths because
diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c
index 43f68e0..8586eb3 100644
--- a/generic/tclIOUtil.c
+++ b/generic/tclIOUtil.c
@@ -17,7 +17,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclIOUtil.c,v 1.85 2003/10/10 15:50:35 dkf Exp $
+ * RCS: @(#) $Id: tclIOUtil.c,v 1.86 2003/10/13 16:48:06 vincentdarley Exp $
*/
#include "tclInt.h"
@@ -35,9 +35,13 @@
* Prototypes for procedures defined later in this file.
*/
-static FilesystemRecord* FsGetFirstFilesystem(void);
-static void FsThrExitProc(ClientData cd);
-
+static FilesystemRecord* FsGetFirstFilesystem _ANSI_ARGS_((void));
+static void FsThrExitProc _ANSI_ARGS_((ClientData cd));
+static Tcl_Obj* FsListMounts _ANSI_ARGS_((Tcl_Obj *pathPtr,
+ CONST char *pattern));
+static Tcl_Obj* FsAddMountsToGlobResult _ANSI_ARGS_((Tcl_Obj *result,
+ Tcl_Obj *pathPtr, CONST char *pattern, Tcl_GlobTypeData *types));
+
#ifdef TCL_THREADS
static void FsRecacheFilesystemList(void);
#endif
@@ -922,7 +926,12 @@ Tcl_FSMatchInDirectory(interp, result, pathPtr, pattern, types)
if (fsPtr != NULL) {
Tcl_FSMatchInDirectoryProc *proc = fsPtr->matchInDirectoryProc;
if (proc != NULL) {
- return (*proc)(interp, result, pathPtr, pattern, types);
+ int ret = (*proc)(interp, result, pathPtr, pattern, types);
+ if (ret == TCL_OK && pattern != NULL) {
+ result = FsAddMountsToGlobResult(result, pathPtr,
+ pattern, types);
+ }
+ return ret;
}
} else {
Tcl_Obj* cwd;
@@ -967,6 +976,9 @@ Tcl_FSMatchInDirectory(interp, result, pathPtr, pattern, types)
if (ret == TCL_OK) {
int resLength;
+ tmpResultPtr = FsAddMountsToGlobResult(tmpResultPtr, cwd,
+ pattern, types);
+
ret = Tcl_ListObjLength(interp, tmpResultPtr, &resLength);
if (ret == TCL_OK) {
int i;
@@ -993,6 +1005,92 @@ Tcl_FSMatchInDirectory(interp, result, pathPtr, pattern, types)
/*
*----------------------------------------------------------------------
*
+ * FsAddMountsToGlobResult --
+ *
+ * This routine is used by the globbing code to take the results
+ * of a directory listing and add any mounted paths to that
+ * listing. This is required so that simple things like
+ * 'glob *' merge mounts and listings correctly.
+ *
+ * Results:
+ *
+ * The passed in 'result' may be modified (in place, if
+ * necessary), and the correct list is returned.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+static Tcl_Obj*
+FsAddMountsToGlobResult(result, pathPtr, pattern, types)
+ Tcl_Obj *result; /* The current list of matching paths */
+ Tcl_Obj *pathPtr; /* The directory in question */
+ CONST char *pattern;
+ Tcl_GlobTypeData *types;
+{
+ int mLength, gLength, i;
+ int dir = (types == NULL || (types->type & TCL_GLOB_TYPE_DIR));
+ Tcl_Obj *mounts = FsListMounts(pathPtr, pattern);
+
+ if (mounts == NULL) return result;
+
+ if (Tcl_ListObjLength(NULL, mounts, &mLength) != TCL_OK || mLength == 0) {
+ goto endOfMounts;
+ }
+ if (Tcl_ListObjLength(NULL, result, &gLength) != TCL_OK) {
+ goto endOfMounts;
+ }
+ for (i = 0; i < mLength; i++) {
+ Tcl_Obj *mElt;
+ int j;
+ int found = 0;
+
+ Tcl_ListObjIndex(NULL, mounts, i, &mElt);
+
+ for (j = 0; j < gLength; j++) {
+ Tcl_Obj *gElt;
+ Tcl_ListObjIndex(NULL, result, j, &gElt);
+ if (Tcl_FSEqualPaths(mElt, gElt)) {
+ found = 1;
+ if (!dir) {
+ /* We don't want to list this */
+ if (Tcl_IsShared(result)) {
+ Tcl_Obj *newList;
+ newList = Tcl_DuplicateObj(result);
+ Tcl_DecrRefCount(result);
+ result = newList;
+ }
+ Tcl_ListObjReplace(NULL, result, j, 1, 0, NULL);
+ gLength--;
+ }
+ /* Break out of for loop */
+ break;
+ }
+ }
+ if (!found && dir) {
+ if (Tcl_IsShared(result)) {
+ Tcl_Obj *newList;
+ newList = Tcl_DuplicateObj(result);
+ Tcl_DecrRefCount(result);
+ result = newList;
+ }
+ Tcl_ListObjAppendElement(NULL, result, mElt);
+ /*
+ * No need to increment gLength, since we
+ * don't want to compare mounts against
+ * mounts.
+ */
+ }
+ }
+ endOfMounts:
+ Tcl_DecrRefCount(mounts);
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* Tcl_FSMountsChanged --
*
* Notify the filesystem that the available mounted filesystems
@@ -1627,6 +1725,9 @@ Tcl_FSStat(pathPtr, buf)
retVal = (*statProcPtr->proc)(path, &oldStyleStatBuffer);
statProcPtr = statProcPtr->nextPtr;
}
+ if (transPtr != NULL) {
+ Tcl_DecrRefCount(transPtr);
+ }
}
Tcl_MutexUnlock(&obsoleteFsHookMutex);
@@ -1754,6 +1855,9 @@ Tcl_FSAccess(pathPtr, mode)
retVal = (*accessProcPtr->proc)(path, mode);
accessProcPtr = accessProcPtr->nextPtr;
}
+ if (transPtr != NULL) {
+ Tcl_DecrRefCount(transPtr);
+ }
}
Tcl_MutexUnlock(&obsoleteFsHookMutex);
@@ -1831,6 +1935,9 @@ Tcl_FSOpenFileChannel(interp, pathPtr, modeString, permissions)
modeString, permissions);
openFileChannelProcPtr = openFileChannelProcPtr->nextPtr;
}
+ if (transPtr != NULL) {
+ Tcl_DecrRefCount(transPtr);
+ }
}
Tcl_MutexUnlock(&obsoleteFsHookMutex);
if (retVal != NULL) {
@@ -2816,7 +2923,7 @@ Tcl_FSListVolumes(void)
* a list of all drives from all filesystems.
*/
- fsRecPtr = FsGetFirstFilesystem();
+ fsRecPtr = FsGetFirstFilesystem();
while (fsRecPtr != NULL) {
Tcl_FSListVolumesProc *proc = fsRecPtr->fsPtr->listVolumesProc;
if (proc != NULL) {
@@ -2835,6 +2942,59 @@ Tcl_FSListVolumes(void)
/*
*---------------------------------------------------------------------------
*
+ * FsListMounts --
+ *
+ * List all mounts within the given directory, which match the
+ * given pattern.
+ *
+ * Results:
+ * The list of mounts, in a list object which has refCount 0, or
+ * NULL if we didn't even find any filesystems to try to list
+ * mounts.
+ *
+ * Side effects:
+ * None
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static Tcl_Obj*
+FsListMounts(pathPtr, pattern)
+ Tcl_Obj *pathPtr; /* Contains path to directory to search. */
+ CONST char *pattern; /* Pattern to match against. */
+{
+ FilesystemRecord *fsRecPtr;
+ Tcl_GlobTypeData mountsOnly = { TCL_GLOB_TYPE_MOUNT, 0, NULL, NULL };
+ Tcl_Obj *resultPtr = NULL;
+
+ /*
+ * Call each of the "listMounts" functions in succession.
+ * A non-NULL return value indicates the particular function has
+ * succeeded. We call all the functions registered, since we want
+ * a list from each filesystems.
+ */
+
+ fsRecPtr = FsGetFirstFilesystem();
+ while (fsRecPtr != NULL) {
+ if (fsRecPtr != &nativeFilesystemRecord) {
+ Tcl_FSMatchInDirectoryProc *proc =
+ fsRecPtr->fsPtr->matchInDirectoryProc;
+ if (proc != NULL) {
+ if (resultPtr == NULL) {
+ resultPtr = Tcl_NewObj();
+ }
+ (*proc)(NULL, resultPtr, pathPtr, pattern, &mountsOnly);
+ }
+ }
+ fsRecPtr = fsRecPtr->nextPtr;
+ }
+
+ return resultPtr;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
* Tcl_FSSplitPath --
*
* This function takes the given Tcl_Obj, which should be a valid
@@ -3431,6 +3591,11 @@ Tcl_FSGetFileSystemForPath(pathObjPtr)
FilesystemRecord *fsRecPtr;
Tcl_Filesystem* retVal = NULL;
+ if (pathObjPtr == NULL) {
+ panic("Tcl_FSGetFileSystemForPath called with NULL object");
+ return NULL;
+ }
+
/*
* If the object has a refCount of zero, we reject it. This
* is to avoid possible segfaults or nondeterministic memory
diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c
index 18d3dd4..8fa73d5 100644
--- a/generic/tclPathObj.c
+++ b/generic/tclPathObj.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: tclPathObj.c,v 1.11 2003/10/10 15:50:35 dkf Exp $
+ * RCS: @(#) $Id: tclPathObj.c,v 1.12 2003/10/13 16:48:06 vincentdarley Exp $
*/
#include "tclInt.h"
@@ -377,6 +377,7 @@ Tcl_FSJoinPath(listObj, elements)
* '/'. There's no need to return a special path
* object, when the base itself is just fine!
*/
+ Tcl_DecrRefCount(res);
return elt;
}
/*
@@ -390,6 +391,7 @@ Tcl_FSJoinPath(listObj, elements)
*/
if (str[0] != '.' && ((tclPlatform != TCL_PLATFORM_WINDOWS)
|| (strchr(str, '\\') == NULL))) {
+ Tcl_DecrRefCount(res);
return TclNewFSPathObj(elt, str, len);
}
/*
@@ -399,6 +401,7 @@ Tcl_FSJoinPath(listObj, elements)
*/
} else {
if (tclPlatform == TCL_PLATFORM_UNIX) {
+ Tcl_DecrRefCount(res);
return tail;
} else {
CONST char *str;
@@ -406,10 +409,12 @@ Tcl_FSJoinPath(listObj, elements)
str = Tcl_GetStringFromObj(tail,&len);
if (tclPlatform == TCL_PLATFORM_WINDOWS) {
if (strchr(str, '\\') == NULL) {
+ Tcl_DecrRefCount(res);
return tail;
}
} else if (tclPlatform == TCL_PLATFORM_MAC) {
if (strchr(str, '/') == NULL) {
+ Tcl_DecrRefCount(res);
return tail;
}
}
@@ -965,6 +970,7 @@ Tcl_FSGetTranslatedPath(interp, pathPtr)
retObj = srcFsPathPtr->translatedPathPtr;
}
+ Tcl_IncrRefCount(retObj);
return retObj;
}
@@ -995,7 +1001,13 @@ Tcl_FSGetTranslatedStringPath(interp, pathPtr)
Tcl_Obj *transPtr = Tcl_FSGetTranslatedPath(interp, pathPtr);
if (transPtr != NULL) {
- return Tcl_GetString(transPtr);
+ int len;
+ CONST char *result, *orig;
+ orig = Tcl_GetStringFromObj(transPtr, &len);
+ result = (char*) ckalloc((unsigned)(len+1));
+ memcpy((VOID*) result, (VOID*) orig, (size_t) (len+1));
+ Tcl_DecrRefCount(transPtr);
+ return result;
}
return NULL;
diff --git a/generic/tclTest.c b/generic/tclTest.c
index 8f322fc..effa8a3 100644
--- a/generic/tclTest.c
+++ b/generic/tclTest.c
@@ -14,7 +14,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclTest.c,v 1.68 2003/10/08 14:24:41 dkf Exp $
+ * RCS: @(#) $Id: tclTest.c,v 1.69 2003/10/13 16:48:06 vincentdarley Exp $
*/
#define TCL_TEST
@@ -6080,17 +6080,23 @@ TestReportOpenFileChannel(interp, fileName, mode, permissions)
static int
TestReportMatchInDirectory(interp, resultPtr, dirPtr, pattern, types)
- Tcl_Interp *interp; /* Interpreter to receive results. */
- Tcl_Obj *resultPtr; /* Directory separators to pass to TclDoGlob. */
+ Tcl_Interp *interp; /* Interpreter for error
+ * messages. */
+ Tcl_Obj *resultPtr; /* Object to lappend results. */
Tcl_Obj *dirPtr; /* Contains path to directory to search. */
CONST char *pattern; /* Pattern to match against. */
Tcl_GlobTypeData *types; /* Object containing list of acceptable types.
* May be NULL. */
{
- TestReport("matchindirectory",dirPtr, NULL);
- return Tcl_FSMatchInDirectory(interp, resultPtr,
- TestReportGetNativePath(dirPtr), pattern,
- types);
+ if (types != NULL && types->type & TCL_GLOB_TYPE_MOUNT) {
+ TestReport("matchmounts",dirPtr, NULL);
+ return TCL_OK;
+ } else {
+ TestReport("matchindirectory",dirPtr, NULL);
+ return Tcl_FSMatchInDirectory(interp, resultPtr,
+ TestReportGetNativePath(dirPtr), pattern,
+ types);
+ }
}
static int
TestReportChdir(dirName)