📄 tclioutil.c
字号:
/* * tclIOUtil.c -- * * This file contains the implementation of Tcl's generic * filesystem code, which supports a pluggable filesystem * architecture allowing both platform specific filesystems and * 'virtual filesystems'. All filesystem access should go through * the functions defined in this file. Most of this code was * contributed by Vince Darley. * * Parts of this file are based on code contributed by Karl * Lehenbauer, Mark Diekhans and Peter da Silva. * * Copyright (c) 1991-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * 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 $ */#include "tclInt.h"#include "tclPort.h"#ifdef MAC_TCL#include "tclMacInt.h"#endif#ifdef __WIN32__/* for tclWinProcs->useWide */#include "tclWinInt.h"#endif/* * Prototypes for procedures defined later in this file. */static void DupFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr, Tcl_Obj *copyPtr));static void FreeFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *listPtr));static void UpdateStringOfFsPath _ANSI_ARGS_((Tcl_Obj *objPtr));static int SetFsPathFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr));static Tcl_Obj* MakeFsPathFromRelative _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj *cwdPtr));static Tcl_Obj* FSNormalizeAbsolutePath _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj *pathPtr));static int TclNormalizeToUniquePath _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr, int startAt));static int SetFsPathFromAbsoluteNormalized _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr));static int FindSplitPos _ANSI_ARGS_((char *path, char *separator));static Tcl_PathType FSGetPathType _ANSI_ARGS_((Tcl_Obj *pathObjPtr, Tcl_Filesystem **filesystemPtrPtr, int *driveNameLengthPtr));static Tcl_PathType GetPathType _ANSI_ARGS_((Tcl_Obj *pathObjPtr, Tcl_Filesystem **filesystemPtrPtr, int *driveNameLengthPtr, Tcl_Obj **driveNameRef));/* * Define the 'path' object type, which Tcl uses to represent * file paths internally. */Tcl_ObjType tclFsPathType = { "path", /* name */ FreeFsPathInternalRep, /* freeIntRepProc */ DupFsPathInternalRep, /* dupIntRepProc */ UpdateStringOfFsPath, /* updateStringProc */ SetFsPathFromAny /* setFromAnyProc */};/* * These form part of the native filesystem support. They are needed * here because we have a few native filesystem functions (which are * the same for mac/win/unix) in this file. There is no need to place * them in tclInt.h, because they are not (and should not be) used * anywhere else. */extern CONST char * tclpFileAttrStrings[];extern CONST TclFileAttrProcs tclpFileAttrProcs[];/* * The following functions are obsolete string based APIs, and should * be removed in a future release (Tcl 9 would be a good time). *//* Obsolete */intTcl_Stat(path, oldStyleBuf) CONST char *path; /* Path of file to stat (in current CP). */ struct stat *oldStyleBuf; /* Filled with results of stat call. */{ int ret; Tcl_StatBuf buf; Tcl_Obj *pathPtr = Tcl_NewStringObj(path,-1); Tcl_IncrRefCount(pathPtr); ret = Tcl_FSStat(pathPtr, &buf); Tcl_DecrRefCount(pathPtr); if (ret != -1) {#ifndef TCL_WIDE_INT_IS_LONG# define OUT_OF_RANGE(x) \ (((Tcl_WideInt)(x)) < Tcl_LongAsWide(LONG_MIN) || \ ((Tcl_WideInt)(x)) > Tcl_LongAsWide(LONG_MAX))# define OUT_OF_URANGE(x) \ (((Tcl_WideUInt)(x)) > (Tcl_WideUInt)ULONG_MAX) /* * Perform the result-buffer overflow check manually. * * Note that ino_t/ino64_t is unsigned... */ if (OUT_OF_URANGE(buf.st_ino) || OUT_OF_RANGE(buf.st_size)#ifdef HAVE_ST_BLOCKS || OUT_OF_RANGE(buf.st_blocks)#endif ) {#ifdef EFBIG errno = EFBIG;#else# ifdef EOVERFLOW errno = EOVERFLOW;# else# error "What status should be returned for file size out of range?"# endif#endif return -1; }# undef OUT_OF_RANGE# undef OUT_OF_URANGE#endif /* !TCL_WIDE_INT_IS_LONG */ /* * Copy across all supported fields, with possible type * coercions on those fields that change between the normal * and lf64 versions of the stat structure (on Solaris at * least.) This is slow when the structure sizes coincide, * but that's what you get for using an obsolete interface. */ oldStyleBuf->st_mode = buf.st_mode; oldStyleBuf->st_ino = (ino_t) buf.st_ino; oldStyleBuf->st_dev = buf.st_dev; oldStyleBuf->st_rdev = buf.st_rdev; oldStyleBuf->st_nlink = buf.st_nlink; oldStyleBuf->st_uid = buf.st_uid; oldStyleBuf->st_gid = buf.st_gid; oldStyleBuf->st_size = (off_t) buf.st_size; oldStyleBuf->st_atime = buf.st_atime; oldStyleBuf->st_mtime = buf.st_mtime; oldStyleBuf->st_ctime = buf.st_ctime;#ifdef HAVE_ST_BLOCKS oldStyleBuf->st_blksize = buf.st_blksize; oldStyleBuf->st_blocks = (blkcnt_t) buf.st_blocks;#endif } return ret;}/* Obsolete */intTcl_Access(path, mode) CONST char *path; /* Path of file to access (in current CP). */ int mode; /* Permission setting. */{ int ret; Tcl_Obj *pathPtr = Tcl_NewStringObj(path,-1); Tcl_IncrRefCount(pathPtr); ret = Tcl_FSAccess(pathPtr,mode); Tcl_DecrRefCount(pathPtr); return ret;}/* Obsolete */Tcl_ChannelTcl_OpenFileChannel(interp, path, modeString, permissions) Tcl_Interp *interp; /* Interpreter for error reporting; * can be NULL. */ CONST char *path; /* Name of file to open. */ CONST char *modeString; /* A list of POSIX open modes or * a string such as "rw". */ int permissions; /* If the open involves creating a * file, with what modes to create * it? */{ Tcl_Channel ret; Tcl_Obj *pathPtr = Tcl_NewStringObj(path,-1); Tcl_IncrRefCount(pathPtr); ret = Tcl_FSOpenFileChannel(interp, pathPtr, modeString, permissions); Tcl_DecrRefCount(pathPtr); return ret;}/* Obsolete */intTcl_Chdir(dirName) CONST char *dirName;{ int ret; Tcl_Obj *pathPtr = Tcl_NewStringObj(dirName,-1); Tcl_IncrRefCount(pathPtr); ret = Tcl_FSChdir(pathPtr); Tcl_DecrRefCount(pathPtr); return ret;}/* Obsolete */char *Tcl_GetCwd(interp, cwdPtr) Tcl_Interp *interp; Tcl_DString *cwdPtr;{ Tcl_Obj *cwd; cwd = Tcl_FSGetCwd(interp); if (cwd == NULL) { return NULL; } else { Tcl_DStringInit(cwdPtr); Tcl_DStringAppend(cwdPtr, Tcl_GetString(cwd), -1); Tcl_DecrRefCount(cwd); return Tcl_DStringValue(cwdPtr); }}/* Obsolete */intTcl_EvalFile(interp, fileName) Tcl_Interp *interp; /* Interpreter in which to process file. */ CONST char *fileName; /* Name of file to process. Tilde-substitution * will be performed on this name. */{ int ret; Tcl_Obj *pathPtr = Tcl_NewStringObj(fileName,-1); Tcl_IncrRefCount(pathPtr); ret = Tcl_FSEvalFile(interp, pathPtr); Tcl_DecrRefCount(pathPtr); return ret;}/* * The 3 hooks for Stat, Access and OpenFileChannel are obsolete. The * complete, general hooked filesystem APIs should be used instead. * This define decides whether to include the obsolete hooks and * related code. If these are removed, we'll also want to remove them * from stubs/tclInt. The only known users of these APIs are prowrap * and mktclapp. New code/extensions should not use them, since they * do not provide as full support as the full filesystem API. * * As soon as prowrap and mktclapp are updated to use the full * filesystem support, I suggest all these hooks are removed. */#define USE_OBSOLETE_FS_HOOKS#ifdef USE_OBSOLETE_FS_HOOKS/* * The following typedef declarations allow for hooking into the chain * of functions maintained for 'Tcl_Stat(...)', 'Tcl_Access(...)' & * 'Tcl_OpenFileChannel(...)'. Basically for each hookable function * a linked list is defined. */typedef struct StatProc { TclStatProc_ *proc; /* Function to process a 'stat()' call */ struct StatProc *nextPtr; /* The next 'stat()' function to call */} StatProc;typedef struct AccessProc { TclAccessProc_ *proc; /* Function to process a 'access()' call */ struct AccessProc *nextPtr; /* The next 'access()' function to call */} AccessProc;typedef struct OpenFileChannelProc { TclOpenFileChannelProc_ *proc; /* Function to process a * 'Tcl_OpenFileChannel()' call */ struct OpenFileChannelProc *nextPtr; /* The next 'Tcl_OpenFileChannel()' * function to call */} OpenFileChannelProc;/* * For each type of (obsolete) hookable function, a static node is * declared to hold the function pointer for the "built-in" routine * (e.g. 'TclpStat(...)') and the respective list is initialized as a * pointer to that node. * * The "delete" functions (e.g. 'TclStatDeleteProc(...)') ensure that * these statically declared list entry cannot be inadvertently removed. * * This method avoids the need to call any sort of "initialization" * function. * * All three lists are protected by a global obsoleteFsHookMutex. */static StatProc *statProcList = NULL;static AccessProc *accessProcList = NULL;static OpenFileChannelProc *openFileChannelProcList = NULL;TCL_DECLARE_MUTEX(obsoleteFsHookMutex)#endif /* USE_OBSOLETE_FS_HOOKS *//* * A filesystem record is used to keep track of each * filesystem currently registered with the core, * in a linked list. */typedef struct FilesystemRecord { ClientData clientData; /* Client specific data for the new * filesystem (can be NULL) */ Tcl_Filesystem *fsPtr; /* Pointer to filesystem dispatch * table. */ int fileRefCount; /* How many Tcl_Obj's use this * filesystem. */ struct FilesystemRecord *nextPtr; /* The next filesystem registered * to Tcl, or NULL if no more. */} FilesystemRecord;static FilesystemRecord* GetFilesystemRecord _ANSI_ARGS_((Tcl_Filesystem *fromFilesystem, int *epoch));/* * Declare the native filesystem support. These functions should * be considered private to Tcl, and should really not be called * directly by any code other than this file (i.e. neither by * Tcl's core nor by extensions). Similarly, the old string-based * Tclp... native filesystem functions should not be called. * * The correct API to use now is the Tcl_FS... set of functions, * which ensure correct and complete virtual filesystem support. * * We cannot make all of these static, since some of them * are implemented in the platform-specific directories. */static Tcl_FSPathInFilesystemProc NativePathInFilesystem;static Tcl_FSFilesystemSeparatorProc NativeFilesystemSeparator;static Tcl_FSFreeInternalRepProc NativeFreeInternalRep;static Tcl_FSDupInternalRepProc NativeDupInternalRep;static Tcl_FSCreateInternalRepProc NativeCreateNativeRep;static Tcl_FSFileAttrStringsProc NativeFileAttrStrings;static Tcl_FSFileAttrsGetProc NativeFileAttrsGet;static Tcl_FSFileAttrsSetProc NativeFileAttrsSet;/* * The only reason these functions are not static is that they * are either called by code in the native (win/unix/mac) directories * or they are actually implemented in those directories. They * should simply not be called by code outside Tcl's native * filesystem core. i.e. they should be considered 'static' to * Tcl's filesystem code (if we ever built the native filesystem * support into a separate code library, this could actually be * enforced). */Tcl_FSFilesystemPathTypeProc TclpFilesystemPathType;Tcl_FSInternalToNormalizedProc TclpNativeToNormalized;Tcl_FSStatProc TclpObjStat;Tcl_FSAccessProc TclpObjAccess; Tcl_FSMatchInDirectoryProc TclpMatchInDirectory; Tcl_FSGetCwdProc TclpObjGetCwd; Tcl_FSChdirProc TclpObjChdir; Tcl_FSLstatProc TclpObjLstat; Tcl_FSCopyFileProc TclpObjCopyFile; Tcl_FSDeleteFileProc TclpObjDeleteFile; Tcl_FSRenameFileProc TclpObjRenameFile; Tcl_FSCreateDirectoryProc TclpObjCreateDirectory; Tcl_FSCopyDirectoryProc TclpObjCopyDirectory; Tcl_FSRemoveDirectoryProc TclpObjRemoveDirectory; Tcl_FSUnloadFileProc TclpUnloadFile; Tcl_FSLinkProc TclpObjLink; Tcl_FSListVolumesProc TclpObjListVolumes; /* * Define the native filesystem dispatch table. If necessary, it * is ok to make this non-static, but it should only be accessed * by the functions actually listed within it (or perhaps other * helper functions of them). Anything which is not part of this * 'native filesystem implementation' should not be delving inside * here! */static Tcl_Filesystem tclNativeFilesystem = { "native", sizeof(Tcl_Filesystem), TCL_FILESYSTEM_VERSION_1, &NativePathInFilesystem, &NativeDupInternalRep, &NativeFreeInternalRep, &TclpNativeToNormalized, &NativeCreateNativeRep, &TclpObjNormalizePath, &TclpFilesystemPathType, &NativeFilesystemSeparator, &TclpObjStat, &TclpObjAccess, &TclpOpenFileChannel, &TclpMatchInDirectory, &TclpUtime,#ifndef S_IFLNK NULL,#else &TclpObjLink,#endif /* S_IFLNK */ &TclpObjListVolumes, &NativeFileAttrStrings, &NativeFileAttrsGet, &NativeFileAttrsSet, &TclpObjCreateDirectory, &TclpObjRemoveDirectory, &TclpObjDeleteFile, &TclpObjCopyFile, &TclpObjRenameFile, &TclpObjCopyDirectory, &TclpObjLstat, &TclpDlopen, &TclpObjGetCwd, &TclpObjChdir};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -