📄 tclmacfcmd.c
字号:
/* * tclMacFCmd.c -- * * Implements the Macintosh specific portions of the file manipulation * subcommands of the "file" command. * * Copyright (c) 1996-1998 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: tclMacFCmd.c,v 1.19 2003/02/04 17:06:51 vincentdarley Exp $ */#include "tclInt.h"#include "tclMac.h"#include "tclMacInt.h"#include "tclPort.h"#include <FSpCompat.h>#include <MoreFilesExtras.h>#include <Strings.h>#include <Errors.h>#include <FileCopy.h>#include <DirectoryCopy.h>#include <Script.h>#include <string.h>#include <Finder.h>#include <Aliases.h>/* * Callback for the file attributes code. */static int GetFileFinderAttributes _ANSI_ARGS_((Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr));static int GetFileReadOnly _ANSI_ARGS_((Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj **readOnlyPtrPtr));static int SetFileFinderAttributes _ANSI_ARGS_((Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj *attributePtr));static int SetFileReadOnly _ANSI_ARGS_((Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj *readOnlyPtr));/* * These are indeces into the tclpFileAttrsStrings table below. */#define MAC_CREATOR_ATTRIBUTE 0#define MAC_HIDDEN_ATTRIBUTE 1#define MAC_READONLY_ATTRIBUTE 2#define MAC_TYPE_ATTRIBUTE 3/* * Global variables for the file attributes code. */CONST char *tclpFileAttrStrings[] = {"-creator", "-hidden", "-readonly", "-type", (char *) NULL};CONST TclFileAttrProcs tclpFileAttrProcs[] = { {GetFileFinderAttributes, SetFileFinderAttributes}, {GetFileFinderAttributes, SetFileFinderAttributes}, {GetFileReadOnly, SetFileReadOnly}, {GetFileFinderAttributes, SetFileFinderAttributes}};/* * File specific static data */static long startSeed = 248923489;/* * Prototypes for procedure only used in this file */static pascal Boolean CopyErrHandler _ANSI_ARGS_((OSErr error, short failedOperation, short srcVRefNum, long srcDirID, ConstStr255Param srcName, short dstVRefNum, long dstDirID,ConstStr255Param dstName));static int DoCopyDirectory _ANSI_ARGS_((CONST char *src, CONST char *dst, Tcl_DString *errorPtr));static int DoCopyFile _ANSI_ARGS_((CONST char *src, CONST char *dst));static int DoCreateDirectory _ANSI_ARGS_((CONST char *path));static int DoRemoveDirectory _ANSI_ARGS_((CONST char *path, int recursive, Tcl_DString *errorPtr));static int DoRenameFile _ANSI_ARGS_((CONST char *src, CONST char *dst));OSErr FSpGetFLockCompat _ANSI_ARGS_((const FSSpec *specPtr, Boolean *lockedPtr));static OSErr GetFileSpecs _ANSI_ARGS_((CONST char *path, FSSpec *pathSpecPtr, FSSpec *dirSpecPtr, Boolean *pathExistsPtr, Boolean *pathIsDirectoryPtr));static OSErr MoveRename _ANSI_ARGS_((const FSSpec *srcSpecPtr, const FSSpec *dstSpecPtr, StringPtr copyName));static int Pstrequal _ANSI_ARGS_((ConstStr255Param stringA, ConstStr255Param stringB)); /* *--------------------------------------------------------------------------- * * TclpObjRenameFile, DoRenameFile -- * * Changes the name of an existing file or directory, from src to dst. * If src and dst refer to the same file or directory, does nothing * and returns success. Otherwise if dst already exists, it will be * deleted and replaced by src subject to the following conditions: * If src is a directory, dst may be an empty directory. * If src is a file, dst may be a file. * In any other situation where dst already exists, the rename will * fail. * * Results: * If the directory was successfully created, returns TCL_OK. * Otherwise the return value is TCL_ERROR and errno is set to * indicate the error. Some possible values for errno are: * * EACCES: src or dst parent directory can't be read and/or written. * EEXIST: dst is a non-empty directory. * EINVAL: src is a root directory or dst is a subdirectory of src. * EISDIR: dst is a directory, but src is not. * ENOENT: src doesn't exist. src or dst is "". * ENOTDIR: src is a directory, but dst is not. * EXDEV: src and dst are on different filesystems. * * Side effects: * The implementation of rename may allow cross-filesystem renames, * but the caller should be prepared to emulate it with copy and * delete if errno is EXDEV. * *--------------------------------------------------------------------------- */int TclpObjRenameFile(srcPathPtr, destPathPtr) Tcl_Obj *srcPathPtr; Tcl_Obj *destPathPtr;{ return DoRenameFile(Tcl_FSGetNativePath(srcPathPtr), Tcl_FSGetNativePath(destPathPtr));}static intDoRenameFile( CONST char *src, /* Pathname of file or dir to be renamed * (native). */ CONST char *dst) /* New pathname of file or directory * (native). */{ FSSpec srcFileSpec, dstFileSpec, dstDirSpec; OSErr err; long srcID, dummy; Boolean srcIsDirectory, dstIsDirectory, dstExists, dstLocked; err = FSpLLocationFromPath(strlen(src), src, &srcFileSpec); if (err == noErr) { FSpGetDirectoryID(&srcFileSpec, &srcID, &srcIsDirectory); } if (err == noErr) { err = GetFileSpecs(dst, &dstFileSpec, &dstDirSpec, &dstExists, &dstIsDirectory); } if (err == noErr) { if (dstExists == 0) { err = MoveRename(&srcFileSpec, &dstDirSpec, dstFileSpec.name); goto end; } err = FSpGetFLockCompat(&dstFileSpec, &dstLocked); if (dstLocked) { FSpRstFLockCompat(&dstFileSpec); } } if (err == noErr) { if (srcIsDirectory) { if (dstIsDirectory) { /* * The following call will remove an empty directory. If it * fails, it's because it wasn't empty. */ if (DoRemoveDirectory(dst, 0, NULL) != TCL_OK) { return TCL_ERROR; } /* * Now that that empty directory is gone, we can try * renaming src. If that fails, we'll put this empty * directory back, for completeness. */ err = MoveRename(&srcFileSpec, &dstDirSpec, dstFileSpec.name); if (err != noErr) { FSpDirCreateCompat(&dstFileSpec, smSystemScript, &dummy); if (dstLocked) { FSpSetFLockCompat(&dstFileSpec); } } } else { errno = ENOTDIR; return TCL_ERROR; } } else { if (dstIsDirectory) { errno = EISDIR; return TCL_ERROR; } else { /* * Overwrite existing file by: * * 1. Rename existing file to temp name. * 2. Rename old file to new name. * 3. If success, delete temp file. If failure, * put temp file back to old name. */ Str31 tmpName; FSSpec tmpFileSpec; err = GenerateUniqueName(dstFileSpec.vRefNum, &startSeed, dstFileSpec.parID, dstFileSpec.parID, tmpName); if (err == noErr) { err = FSpRenameCompat(&dstFileSpec, tmpName); } if (err == noErr) { err = FSMakeFSSpecCompat(dstFileSpec.vRefNum, dstFileSpec.parID, tmpName, &tmpFileSpec); } if (err == noErr) { err = MoveRename(&srcFileSpec, &dstDirSpec, dstFileSpec.name); } if (err == noErr) { FSpDeleteCompat(&tmpFileSpec); } else { FSpDeleteCompat(&dstFileSpec); FSpRenameCompat(&tmpFileSpec, dstFileSpec.name); if (dstLocked) { FSpSetFLockCompat(&dstFileSpec); } } } } } end: if (err != noErr) { errno = TclMacOSErrorToPosixError(err); return TCL_ERROR; } return TCL_OK;}/* *-------------------------------------------------------------------------- * * MoveRename -- * * Helper function for TclpRenameFile. Renames a file or directory * into the same directory or another directory. The target name * must not already exist in the destination directory. * * Don't use FSpMoveRenameCompat because it doesn't work with * directories or with locked files. * * Results: * Returns a mac error indicating the cause of the failure. * * Side effects: * Creates a temp file in the target directory to handle a rename * between directories. * *-------------------------------------------------------------------------- */ static OSErr MoveRename( const FSSpec *srcFileSpecPtr, /* Source object. */ const FSSpec *dstDirSpecPtr, /* Destination directory. */ StringPtr copyName) /* New name for object in destination * directory. */{ OSErr err; long srcID, dstID; Boolean srcIsDir, dstIsDir; Str31 tmpName; FSSpec dstFileSpec, srcDirSpec, tmpSrcFileSpec, tmpDstFileSpec; Boolean locked; if (srcFileSpecPtr->parID == 1) { /* * Trying to rename a volume. */ return badMovErr; } if (srcFileSpecPtr->vRefNum != dstDirSpecPtr->vRefNum) { /* * Renaming across volumes. */ return diffVolErr; } err = FSpGetFLockCompat(srcFileSpecPtr, &locked); if (locked) { FSpRstFLockCompat(srcFileSpecPtr); } if (err == noErr) { err = FSpGetDirectoryID(dstDirSpecPtr, &dstID, &dstIsDir); } if (err == noErr) { if (srcFileSpecPtr->parID == dstID) { /* * Renaming object within directory. */ err = FSpRenameCompat(srcFileSpecPtr, copyName); goto done; } if (Pstrequal(srcFileSpecPtr->name, copyName)) { /* * Moving object to another directory (under same name). */ err = FSpCatMoveCompat(srcFileSpecPtr, dstDirSpecPtr); goto done; } err = FSpGetDirectoryID(srcFileSpecPtr, &srcID, &srcIsDir); } if (err == noErr) { /* * Fullblown: rename source object to temp name, move temp to * dest directory, and rename temp to target. */ err = GenerateUniqueName(srcFileSpecPtr->vRefNum, &startSeed, srcFileSpecPtr->parID, dstID, tmpName); FSMakeFSSpecCompat(srcFileSpecPtr->vRefNum, srcFileSpecPtr->parID, tmpName, &tmpSrcFileSpec); FSMakeFSSpecCompat(dstDirSpecPtr->vRefNum, dstID, tmpName, &tmpDstFileSpec); } if (err == noErr) { err = FSpRenameCompat(srcFileSpecPtr, tmpName); } if (err == noErr) { err = FSpCatMoveCompat(&tmpSrcFileSpec, dstDirSpecPtr); if (err == noErr) { err = FSpRenameCompat(&tmpDstFileSpec, copyName); if (err == noErr) { goto done; } FSMakeFSSpecCompat(srcFileSpecPtr->vRefNum, srcFileSpecPtr->parID, NULL, &srcDirSpec); FSpCatMoveCompat(&tmpDstFileSpec, &srcDirSpec); } FSpRenameCompat(&tmpSrcFileSpec, srcFileSpecPtr->name); } done: if (locked != false) { if (err == noErr) { FSMakeFSSpecCompat(dstDirSpecPtr->vRefNum, dstID, copyName, &dstFileSpec); FSpSetFLockCompat(&dstFileSpec); } else { FSpSetFLockCompat(srcFileSpecPtr); } } return err;} /* *--------------------------------------------------------------------------- * * TclpObjCopyFile, DoCopyFile -- * * Copy a single file (not a directory). If dst already exists and * is not a directory, it is removed. * * Results: * If the file was successfully copied, returns TCL_OK. Otherwise * the return value is TCL_ERROR and errno is set to indicate the * error. Some possible values for errno are: * * EACCES: src or dst parent directory can't be read and/or written. * EISDIR: src or dst is a directory. * ENOENT: src doesn't exist. src or dst is "". * * Side effects: * This procedure will also copy symbolic links, block, and * character devices, and fifos. For symbolic links, the links * themselves will be copied and not what they point to. For the * other special file types, the directory entry will be copied and * not the contents of the device that it refers to. * *--------------------------------------------------------------------------- */ int TclpObjCopyFile(srcPathPtr, destPathPtr) Tcl_Obj *srcPathPtr; Tcl_Obj *destPathPtr;{ return DoCopyFile(Tcl_FSGetNativePath(srcPathPtr), Tcl_FSGetNativePath(destPathPtr));}static intDoCopyFile( CONST char *src, /* Pathname of file to be copied (native). */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -