--- generic/tclIOUtil.c.orig	Thu Jan  1 01:13:01 1970
+++ generic/tclIOUtil.c	Fri Mar 28 17:08:35 2003
@@ -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.77 2003/03/03 20:22:41 das Exp $
+ * RCS: @(#) $Id: tclIOUtil.c,v 1.1.1.1 2003/03/08 14:12:47 zoran Exp $
  */
 
 #include "tclInt.h"
@@ -514,11 +514,22 @@
 
 #define TCLPATH_APPENDED 1
 #define TCLPATH_RELATIVE 2
+
 /* 
  * Used to implement Tcl_FSGetCwd in a file-system independent way.
  * This is protected by the cwdMutex below.
+ *
+ * We deliberately use string instead of Tcl_Obj because it is
+ * not allowed to bounce Tcl_Obj between threads. Furthermore,
+ * Tcl_Obj duplication machinery does not always produce deep
+ * object copies, leaving internal references to other objects,
+ * thus jeopardizing the overall stability if such object ever
+ * crosses the thread boundary.
+ *
+ * Potential limitation of the above is that OS-paths should
+ * really never contain NULL-bytes. Hm...
  */
-static Tcl_Obj* cwdPathPtr = NULL;
+char *cwdPathPtr = NULL;
 TCL_DECLARE_MUTEX(cwdMutex)
 
 /* 
@@ -546,20 +557,51 @@
 /* Now move on to the basic filesystem implementation */
 
 
+static void
+FsCwdPointerUpdateInner(objPtr)
+    Tcl_Obj* objPtr;
+{
+    size_t len;
+    char *path = Tcl_GetStringFromObj(objPtr, (int *)&len);
+
+    if (cwdPathPtr != NULL) {
+        Tcl_Free(cwdPathPtr);
+    }
+    cwdPathPtr = memcpy(Tcl_Alloc(len+1), path, len);
+    *(cwdPathPtr + len) = 0;
+}
+
 static int 
-FsCwdPointerEquals(objPtr)
+FsCwdPointerEqualsInner(objPtr)
     Tcl_Obj* objPtr;
 {
-    Tcl_MutexLock(&cwdMutex);
-    if (cwdPathPtr == objPtr) {
-	Tcl_MutexUnlock(&cwdMutex);
-	return 1;
+    if (objPtr == NULL) {
+        return cwdPathPtr ? 0 : 1;
     } else {
-	Tcl_MutexUnlock(&cwdMutex);
-	return 0;
+        size_t strLen, cwdLen = cwdPathPtr ? strlen(cwdPathPtr) : 0;
+        char *str = Tcl_GetStringFromObj(objPtr, (int *)&strLen);
+        if (strLen != cwdLen) {
+            return 0;
+        } else {
+            return strncmp(str, cwdPathPtr, cwdLen) == 0;
+        }
     }
+
+    return 0; /* Never reached */
+}
+
+static int 
+FsCwdPointerEquals(objPtr)
+    Tcl_Obj* objPtr;
+{
+    int ret = 0;
+
+    Tcl_MutexLock(&cwdMutex);
+    ret = FsCwdPointerEqualsInner(objPtr);
+    Tcl_MutexUnlock(&cwdMutex);
+
+    return ret;
 }
-        
 
 static FilesystemRecord* 
 FsGetIterator(void) {
@@ -612,7 +654,7 @@
      */
     
     if (cwdPathPtr != NULL) {
-	Tcl_DecrRefCount(cwdPathPtr);
+	Tcl_Free(cwdPathPtr);
 	cwdPathPtr = NULL;
     }
 
@@ -2015,7 +2057,7 @@
  *	This function replaces the library version of getcwd().
  *	
  *	Most VFS's will *not* implement a 'cwdProc'.  Tcl now maintains
- *	its own record (in a Tcl_Obj) of the cwd, and an attempt
+ *	its own record (in a char *) of the cwd, and an attempt
  *	is made to synchronise this with the cwd's containing filesystem,
  *	if that filesystem provides a cwdProc (e.g. the native filesystem).
  *	
@@ -2039,13 +2081,6 @@
  *	
  *	The result already has its refCount incremented for the caller.
  *	When it is no longer needed, that refCount should be decremented.
- *	This is needed for thread-safety purposes, to allow multiple
- *	threads to access this and related functions, while ensuring the
- *	results are always valid.
- *	
- *	Of course it is probably a bad idea for multiple threads to
- *	be *setting* the cwd anyway, but we can at least try to 
- *	help the case of multiple reads with occasional sets.
  *
  * Side effects:
  *	Various objects may be freed and allocated.
@@ -2057,9 +2092,11 @@
 Tcl_FSGetCwd(interp)
     Tcl_Interp *interp;
 {
-    Tcl_Obj *cwdToReturn;
+    Tcl_Obj *cwdToReturn = NULL;
     
-    if (FsCwdPointerEquals(NULL)) {
+    Tcl_MutexLock(&cwdMutex);
+
+    if (FsCwdPointerEqualsInner(NULL)) {
 	FilesystemRecord *fsRecPtr;
 	Tcl_Obj *retVal = NULL;
 
@@ -2103,14 +2140,7 @@
 		 * we'll always be in the 'else' branch below which
 		 * is simpler.
 		 */
-		Tcl_MutexLock(&cwdMutex);
-		/* Just in case the pointer has been set by another
-		 * thread between now and the test above */
-		if (cwdPathPtr != NULL) {
-		    Tcl_DecrRefCount(cwdPathPtr);
-		}
-		cwdPathPtr = norm;
-		Tcl_MutexUnlock(&cwdMutex);
+                FsCwdPointerUpdateInner(norm);
 	    }
 	    Tcl_DecrRefCount(retVal);
 	}
@@ -2122,7 +2152,14 @@
 	 * allows an error to be thrown if, say, the permissions on
 	 * that directory have changed.
 	 */
-	Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(cwdPathPtr);
+	Tcl_Filesystem *fsPtr;
+        Tcl_Obj *cwdObj;
+
+        cwdObj = Tcl_NewStringObj(cwdPathPtr, -1); 
+        Tcl_IncrRefCount(cwdObj);
+        fsPtr  = Tcl_FSGetFileSystemForPath(cwdObj);
+        Tcl_DecrRefCount(cwdObj);
+
 	/* 
 	 * If the filesystem couldn't be found, or if no cwd function
 	 * exists for this filesystem, then we simply assume the cached
@@ -2137,15 +2174,22 @@
 	    if (proc != NULL) {
 		Tcl_Obj *retVal = (*proc)(interp);
 		if (retVal != NULL) {
+                    int pathEq = 0;
 		    Tcl_Obj *norm = FSNormalizeAbsolutePath(interp, retVal);
 		    /* 
 		     * Check whether cwd has changed from the value
 		     * previously stored in cwdPathPtr.  Really 'norm'
 		     * shouldn't be null, but we are careful.
 		     */
+                    if (norm != NULL) {
+                        cwdObj = Tcl_NewStringObj(cwdPathPtr, -1);
+                        Tcl_IncrRefCount(cwdObj);
+                        pathEq = Tcl_FSEqualPaths(cwdObj, norm);
+                        Tcl_DecrRefCount(cwdObj);
+                    }
 		    if (norm == NULL) {
 			/* Do nothing */
-		    } else if (Tcl_FSEqualPaths(cwdPathPtr, norm)) {
+		    } else if (pathEq) {
 		        /* 
 		         * If the paths were equal, we can be more
 		         * efficient and retain the old path object
@@ -2155,21 +2199,14 @@
 		         */
 		        Tcl_DecrRefCount(norm);
 		    } else {
-			/* The cwd has in fact changed, so we must
-			 * lock down the cwdMutex to modify. */
-			Tcl_MutexLock(&cwdMutex);
-			Tcl_DecrRefCount(cwdPathPtr);
-			cwdPathPtr = norm;
-			Tcl_MutexUnlock(&cwdMutex);
+                        FsCwdPointerUpdateInner(norm);
 		    }
 		    Tcl_DecrRefCount(retVal);
 		} else {
 		    /* The 'cwd' function returned an error, so we
-		     * reset the cwd after locking down the mutex. */
-		    Tcl_MutexLock(&cwdMutex);
-		    Tcl_DecrRefCount(cwdPathPtr);
+		     * reset the cwd */ 
+		    Tcl_Free(cwdPathPtr);
 		    cwdPathPtr = NULL;
-		    Tcl_MutexUnlock(&cwdMutex);
 		}
 	    }
 	}
@@ -2183,12 +2220,16 @@
      * and reading the cwd, and that behaviour is always going to be
      * a little suspect.
      */
-    Tcl_MutexLock(&cwdMutex);
-    cwdToReturn = cwdPathPtr;
+
+    if (cwdPathPtr != NULL) {
+        cwdToReturn = Tcl_NewStringObj(cwdPathPtr, -1);
+    }
+
+    Tcl_MutexUnlock(&cwdMutex);
+
     if (cwdToReturn != NULL) {
         Tcl_IncrRefCount(cwdToReturn);
     }
-    Tcl_MutexUnlock(&cwdMutex);
     
     return (cwdToReturn);
 }
@@ -2467,8 +2508,11 @@
     Tcl_Filesystem *fsPtr;
     int retVal = -1;
     
+    Tcl_MutexLock(&cwdMutex);
+
     if (Tcl_FSGetNormalizedPath(NULL, pathPtr) == NULL) {
-        return TCL_ERROR;
+        Tcl_MutexUnlock(&cwdMutex);
+        return retVal;
     }
     
     fsPtr = Tcl_FSGetFileSystemForPath(pathPtr);
@@ -2511,24 +2555,15 @@
 	     */
 	    Tcl_Obj *normDirName = Tcl_FSGetNormalizedPath(NULL, pathPtr);
 	    if (normDirName == NULL) {
-	        return TCL_ERROR;
-	    }
-	    /* 
-	     * We will be adding a reference to this object when
-	     * we store it in the cwdPathPtr.
-	     */
-	    Tcl_IncrRefCount(normDirName);
-	    /* Get a lock on the cwd while we modify it */
-	    Tcl_MutexLock(&cwdMutex);
-	    /* Free up the previous cwd we stored */
-	    if (cwdPathPtr != NULL) {
-		Tcl_DecrRefCount(cwdPathPtr);
-	    }
-	    /* Now remember the current cwd */
-	    cwdPathPtr = normDirName;
-	    Tcl_MutexUnlock(&cwdMutex);
+                retVal = -1; 
+	    } else {
+                FsCwdPointerUpdateInner(normDirName);
+                retVal = 0;
+            }
 	}
     }
+
+    Tcl_MutexUnlock(&cwdMutex);
     
     return (retVal);
 }
@@ -4833,7 +4868,7 @@
 
 	    /* Get a quick, temporary lock on the cwd while we copy it */
 	    Tcl_MutexLock(&cwdMutex);
-	    fsPathPtr->cwdPtr = cwdPathPtr;
+	    fsPathPtr->cwdPtr = Tcl_NewStringObj(cwdPathPtr, -1);
 	    Tcl_IncrRefCount(fsPathPtr->cwdPtr);
 	    Tcl_MutexUnlock(&cwdMutex);
 	}
