From 2dff694c415bcb05ec35723e1d67c61c07d7bfaa Mon Sep 17 00:00:00 2001 From: vincentdarley Date: Tue, 31 Aug 2004 09:20:07 +0000 Subject: two bugs fixed in filesystem docs and tests --- ChangeLog | 11 ++ doc/FileSystem.3 | 22 +++- generic/tclIOUtil.c | 300 +++++++++++++++++++++++++++------------------------- tests/fCmd.test | 4 +- 4 files changed, 183 insertions(+), 154 deletions(-) diff --git a/ChangeLog b/ChangeLog index e4e72df..a0ba17d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2004-08-31 Vince Darley + + * doc/FileSystem.3: + * generic/tclIOUtil.c: Clarified documentation regarding ability + of a filesystem to say that it doesn't support a given operation + using the EXDEV posix error code (copyFileProc, renameFileProc, + etc), and updated one piece of code to ensure correct behaviour + when an operation is not supported [Bug 1017072] + + * tests/fCmd.test: fix to test suite problem [Bug 1002884] + 2004-08-31 Daniel Steffen * unix/Makefile.in (install-libraries): portable sh fix. diff --git a/doc/FileSystem.3 b/doc/FileSystem.3 index 6820c46..0792b14 100644 --- a/doc/FileSystem.3 +++ b/doc/FileSystem.3 @@ -4,7 +4,7 @@ '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: FileSystem.3,v 1.44 2004/07/17 12:18:21 vincentdarley Exp $ +'\" RCS: @(#) $Id: FileSystem.3,v 1.45 2004/08/31 09:20:09 vincentdarley Exp $ '\" .so man.macros .TH Filesystem 3 8.4 Tcl "Tcl Library Procedures" @@ -1306,7 +1306,10 @@ copied (i.e. the function is much simpler than the Tcl level 'file copy' subcommand). Note that, if the filesystem supports symbolic links, Tcl will always call this function and not Tcl_FSCopyDirectoryProc when needed to copy them -(even if they are symbolic links to directories). +(even if they are symbolic links to directories). Finally, if the +filesystem determines it cannot support the file copy action, +calling \fBTcl_SetErrno(EXDEV)\fR and returning a non +TCL_OK result will tell Tcl to use its standard fallback mechanisms. .SH RENAMEFILEPROC .PP Function to process a \fBTcl_FSRenameFile()\fR call. If not implemented, @@ -1321,7 +1324,10 @@ typedef int Tcl_FSRenameFileProc( .CE .PP The return value is a standard Tcl result indicating whether an error -occurred in the renaming process. +occurred in the renaming process. If the +filesystem determines it cannot support the file rename action, +calling \fBTcl_SetErrno(EXDEV)\fR and returning a non +TCL_OK result will tell Tcl to use its standard fallback mechanisms. .SH COPYDIRECTORYPROC .PP Function to process a \fBTcl_FSCopyDirectory()\fR call. If not @@ -1343,7 +1349,10 @@ the file or directory which caused the error should be placed in directory-name which should become the mirror-image of \fIsrcPathPtr\fR. It is not the name of a directory into which \fIsrcPathPtr\fR should be copied (i.e. the function is much simpler -than the Tcl level 'file copy' subcommand). +than the Tcl level 'file copy' subcommand). Finally, if the +filesystem determines it cannot support the directory copy action, +calling \fBTcl_SetErrno(EXDEV)\fR and returning a non +TCL_OK result will tell Tcl to use its standard fallback mechanisms. .SH LOADFILEPROC .PP Function to process a \fBTcl_FSLoadFile()\fR call. If not implemented, Tcl @@ -1371,7 +1380,10 @@ only parameter when Tcl needs to unload the file. For example, for the native filesystem, the \fBTcl_LoadHandle\fR returned is currently a token which can be used in the private \fBTclpFindSymbol\fR to access functions in the new code. Each filesystem is free to define the -\fBTcl_LoadHandle\fR as it requires. +\fBTcl_LoadHandle\fR as it requires. Finally, if the +filesystem determines it cannot support the file load action, +calling \fBTcl_SetErrno(EXDEV)\fR and returning a non +TCL_OK result will tell Tcl to use its standard fallback mechanisms. .SH UNLOADFILEPROC .PP Function to unload a previously successfully loaded file. If load was diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c index 3f1749d..18dfc58 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.107 2004/07/17 12:18:22 vincentdarley Exp $ + * RCS: @(#) $Id: tclIOUtil.c,v 1.108 2004/08/31 09:20:09 vincentdarley Exp $ */ #include "tclInt.h" @@ -2875,173 +2875,179 @@ TclLoadFile(interp, pathPtr, symc, symbols, procPtrs, Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSLoadFileProc *proc = fsPtr->loadFileProc; + Tcl_Filesystem *copyFsPtr; + Tcl_Obj *copyToPtr; + if (proc != NULL) { - int i; int retVal = (*proc)(interp, pathPtr, handlePtr, unloadProcPtr); - if (retVal != TCL_OK) { + if (retVal == TCL_OK) { + int i; + if (*handlePtr == NULL) { + return TCL_ERROR; + } + for (i = 0;i < symc;i++) { + if (symbols[i] != NULL) { + *procPtrs[i] = TclpFindSymbol(interp, *handlePtr, + symbols[i]); + } + } + /* Copy this across, since both are equal for the native fs */ + *clientDataPtr = (ClientData)*handlePtr; return retVal; } - if (*handlePtr == NULL) { - return TCL_ERROR; + if (Tcl_GetErrno() != EXDEV) { + return retVal; } - for (i = 0;i < symc;i++) { - if (symbols[i] != NULL) { - *procPtrs[i] = TclpFindSymbol(interp, *handlePtr, - symbols[i]); - } - } - /* Copy this across, since both are equal for the native fs */ - *clientDataPtr = (ClientData)*handlePtr; - return retVal; - } else { - Tcl_Filesystem *copyFsPtr; - Tcl_Obj *copyToPtr; + } + /* + * The filesystem doesn't support 'load', so we fall back on + * the following technique: + */ + + /* First check if it is readable -- and exists! */ + if (Tcl_FSAccess(pathPtr, R_OK) != 0) { + Tcl_AppendResult(interp, "couldn't load library \"", + Tcl_GetString(pathPtr), "\": ", + Tcl_PosixError(interp), (char *) NULL); + return TCL_ERROR; + } + + /* + * Get a temporary filename to use, first to + * copy the file into, and then to load. + */ + copyToPtr = TclpTempFileName(); + if (copyToPtr == NULL) { + return -1; + } + Tcl_IncrRefCount(copyToPtr); + + copyFsPtr = Tcl_FSGetFileSystemForPath(copyToPtr); + if ((copyFsPtr == NULL) || (copyFsPtr == fsPtr)) { + /* + * We already know we can't use Tcl_FSLoadFile from + * this filesystem, and we must avoid a possible + * infinite loop. Try to delete the file we + * probably created, and then exit. + */ + Tcl_FSDeleteFile(copyToPtr); + Tcl_DecrRefCount(copyToPtr); + return -1; + } + + if (TclCrossFilesystemCopy(interp, pathPtr, + copyToPtr) == TCL_OK) { + Tcl_LoadHandle newLoadHandle = NULL; + ClientData newClientData = NULL; + Tcl_FSUnloadFileProc *newUnloadProcPtr = NULL; + FsDivertLoad *tvdlPtr; + int retVal; + +#if !defined(__WIN32__) + /* + * Do we need to set appropriate permissions + * on the file? This may be required on some + * systems. On Unix we could loop over + * the file attributes, and set any that are + * called "-permissions" to 0700. However, + * we just do this directly, like this: + */ - /* First check if it is readable -- and exists! */ - if (Tcl_FSAccess(pathPtr, R_OK) != 0) { - Tcl_AppendResult(interp, "couldn't load library \"", - Tcl_GetString(pathPtr), "\": ", - Tcl_PosixError(interp), (char *) NULL); - return TCL_ERROR; - } + Tcl_Obj* perm = Tcl_NewStringObj("0700",-1); + Tcl_IncrRefCount(perm); + Tcl_FSFileAttrsSet(NULL, 2, copyToPtr, perm); + Tcl_DecrRefCount(perm); +#endif /* - * Get a temporary filename to use, first to - * copy the file into, and then to load. + * We need to reset the result now, because the cross- + * filesystem copy may have stored the number of bytes + * in the result */ - copyToPtr = TclpTempFileName(); - if (copyToPtr == NULL) { - return -1; - } - Tcl_IncrRefCount(copyToPtr); + Tcl_ResetResult(interp); - copyFsPtr = Tcl_FSGetFileSystemForPath(copyToPtr); - if ((copyFsPtr == NULL) || (copyFsPtr == fsPtr)) { - /* - * We already know we can't use Tcl_FSLoadFile from - * this filesystem, and we must avoid a possible - * infinite loop. Try to delete the file we - * probably created, and then exit. - */ + retVal = TclLoadFile(interp, copyToPtr, symc, symbols, + procPtrs, &newLoadHandle, + &newClientData, + &newUnloadProcPtr); + if (retVal != TCL_OK) { + /* The file didn't load successfully */ Tcl_FSDeleteFile(copyToPtr); Tcl_DecrRefCount(copyToPtr); - return -1; + return retVal; } - - if (TclCrossFilesystemCopy(interp, pathPtr, - copyToPtr) == TCL_OK) { - Tcl_LoadHandle newLoadHandle = NULL; - ClientData newClientData = NULL; - Tcl_FSUnloadFileProc *newUnloadProcPtr = NULL; - FsDivertLoad *tvdlPtr; - int retVal; - -#if !defined(__WIN32__) - /* - * Do we need to set appropriate permissions - * on the file? This may be required on some - * systems. On Unix we could loop over - * the file attributes, and set any that are - * called "-permissions" to 0700. However, - * we just do this directly, like this: - */ - - Tcl_Obj* perm = Tcl_NewStringObj("0700",-1); - Tcl_IncrRefCount(perm); - Tcl_FSFileAttrsSet(NULL, 2, copyToPtr, perm); - Tcl_DecrRefCount(perm); -#endif - - /* - * We need to reset the result now, because the cross- - * filesystem copy may have stored the number of bytes - * in the result - */ - Tcl_ResetResult(interp); - - retVal = TclLoadFile(interp, copyToPtr, symc, symbols, - procPtrs, &newLoadHandle, - &newClientData, - &newUnloadProcPtr); - if (retVal != TCL_OK) { - /* The file didn't load successfully */ - Tcl_FSDeleteFile(copyToPtr); - Tcl_DecrRefCount(copyToPtr); - return retVal; - } - /* - * Try to delete the file immediately -- this is - * possible in some OSes, and avoids any worries - * about leaving the copy laying around on exit. - */ - if (Tcl_FSDeleteFile(copyToPtr) == TCL_OK) { - Tcl_DecrRefCount(copyToPtr); - /* - * We tell our caller about the real shared - * library which was loaded. Note that this - * does mean that the package list maintained - * by 'load' will store the original (vfs) - * path alongside the temporary load handle - * and unload proc ptr. - */ - (*handlePtr) = newLoadHandle; - (*clientDataPtr) = newClientData; - (*unloadProcPtr) = newUnloadProcPtr; - return TCL_OK; - } - /* - * When we unload this file, we need to divert the - * unloading so we can unload and cleanup the - * temporary file correctly. - */ - tvdlPtr = (FsDivertLoad*) ckalloc(sizeof(FsDivertLoad)); - + /* + * Try to delete the file immediately -- this is + * possible in some OSes, and avoids any worries + * about leaving the copy laying around on exit. + */ + if (Tcl_FSDeleteFile(copyToPtr) == TCL_OK) { + Tcl_DecrRefCount(copyToPtr); /* - * Remember three pieces of information. This allows - * us to cleanup the diverted load completely, on - * platforms which allow proper unloading of code. + * We tell our caller about the real shared + * library which was loaded. Note that this + * does mean that the package list maintained + * by 'load' will store the original (vfs) + * path alongside the temporary load handle + * and unload proc ptr. */ - tvdlPtr->loadHandle = newLoadHandle; - tvdlPtr->unloadProcPtr = newUnloadProcPtr; + (*handlePtr) = newLoadHandle; + (*clientDataPtr) = newClientData; + (*unloadProcPtr) = newUnloadProcPtr; + return TCL_OK; + } + /* + * When we unload this file, we need to divert the + * unloading so we can unload and cleanup the + * temporary file correctly. + */ + tvdlPtr = (FsDivertLoad*) ckalloc(sizeof(FsDivertLoad)); - if (copyFsPtr != &tclNativeFilesystem) { - /* copyToPtr is already incremented for this reference */ - tvdlPtr->divertedFile = copyToPtr; + /* + * Remember three pieces of information. This allows + * us to cleanup the diverted load completely, on + * platforms which allow proper unloading of code. + */ + tvdlPtr->loadHandle = newLoadHandle; + tvdlPtr->unloadProcPtr = newUnloadProcPtr; - /* - * This is the filesystem we loaded it into. Since - * we have a reference to 'copyToPtr', we already - * have a refCount on this filesystem, so we don't - * need to worry about it disappearing on us. - */ - tvdlPtr->divertedFilesystem = copyFsPtr; - tvdlPtr->divertedFileNativeRep = NULL; - } else { - /* We need the native rep */ - tvdlPtr->divertedFileNativeRep = - TclNativeDupInternalRep(Tcl_FSGetInternalRep(copyToPtr, - copyFsPtr)); - /* - * We don't need or want references to the copied - * Tcl_Obj or the filesystem if it is the native - * one. - */ - tvdlPtr->divertedFile = NULL; - tvdlPtr->divertedFilesystem = NULL; - Tcl_DecrRefCount(copyToPtr); - } + if (copyFsPtr != &tclNativeFilesystem) { + /* copyToPtr is already incremented for this reference */ + tvdlPtr->divertedFile = copyToPtr; - copyToPtr = NULL; - (*handlePtr) = newLoadHandle; - (*clientDataPtr) = (ClientData)tvdlPtr; - (*unloadProcPtr) = &FSUnloadTempFile; - return retVal; + /* + * This is the filesystem we loaded it into. Since + * we have a reference to 'copyToPtr', we already + * have a refCount on this filesystem, so we don't + * need to worry about it disappearing on us. + */ + tvdlPtr->divertedFilesystem = copyFsPtr; + tvdlPtr->divertedFileNativeRep = NULL; } else { - /* Cross-platform copy failed */ - Tcl_FSDeleteFile(copyToPtr); + /* We need the native rep */ + tvdlPtr->divertedFileNativeRep = + TclNativeDupInternalRep(Tcl_FSGetInternalRep(copyToPtr, + copyFsPtr)); + /* + * We don't need or want references to the copied + * Tcl_Obj or the filesystem if it is the native + * one. + */ + tvdlPtr->divertedFile = NULL; + tvdlPtr->divertedFilesystem = NULL; Tcl_DecrRefCount(copyToPtr); - return TCL_ERROR; } + + copyToPtr = NULL; + (*handlePtr) = newLoadHandle; + (*clientDataPtr) = (ClientData)tvdlPtr; + (*unloadProcPtr) = &FSUnloadTempFile; + return retVal; + } else { + /* Cross-platform copy failed */ + Tcl_FSDeleteFile(copyToPtr); + Tcl_DecrRefCount(copyToPtr); + return TCL_ERROR; } } Tcl_SetErrno(ENOENT); diff --git a/tests/fCmd.test b/tests/fCmd.test index 38c3d46..8722826 100644 --- a/tests/fCmd.test +++ b/tests/fCmd.test @@ -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: fCmd.test,v 1.41 2004/06/23 15:36:56 dkf Exp $ +# RCS: @(#) $Id: fCmd.test,v 1.42 2004/08/31 09:20:10 vincentdarley Exp $ # if {[lsearch [namespace children] ::tcltest] == -1} { @@ -2382,7 +2382,7 @@ test fCmd-28.16 {file link: glob inside link} {linkDirectory} { file link abc.link abc.dir set res [glob -dir abc.link -tails *] cd [workingDirectory] - set res + lsort $res } {abc.file abc2.file} test fCmd-28.17 {file link: glob -type l} {linkDirectory} { -- cgit v0.12