diff options
Diffstat (limited to 'macosx/tclMacOSXFCmd.c')
-rw-r--r-- | macosx/tclMacOSXFCmd.c | 762 |
1 files changed, 511 insertions, 251 deletions
diff --git a/macosx/tclMacOSXFCmd.c b/macosx/tclMacOSXFCmd.c index 0416dac..8ecfd0b 100644 --- a/macosx/tclMacOSXFCmd.c +++ b/macosx/tclMacOSXFCmd.c @@ -1,15 +1,13 @@ /* * tclMacOSXFCmd.c * - * This file implements the MacOSX specific portion of file manipulation - * subcommands of the "file" command. + * This file implements the MacOSX specific portion of file manipulation + * subcommands of the "file" command. * - * Copyright (c) 2003 Tcl Core Team. + * Copyright (c) 2003-2007 Daniel A. Steffen <das@users.sourceforge.net> * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tclMacOSXFCmd.c,v 1.2 2004/04/06 22:25:56 dgp Exp $ + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" @@ -17,11 +15,49 @@ #ifdef HAVE_GETATTRLIST #include <sys/attr.h> #include <sys/paths.h> +#include <libkern/OSByteOrder.h> +#endif + +/* Darwin 8 copyfile API. */ +#ifdef HAVE_COPYFILE +#ifdef HAVE_COPYFILE_H +#include <copyfile.h> +#if defined(HAVE_WEAK_IMPORT) && (MAC_OS_X_VERSION_MIN_REQUIRED < 1040) +/* Support for weakly importing copyfile. */ +#define WEAK_IMPORT_COPYFILE +extern int copyfile(const char *from, const char *to, + copyfile_state_t state, copyfile_flags_t flags) + WEAK_IMPORT_ATTRIBUTE; +#endif /* HAVE_WEAK_IMPORT */ +#else /* HAVE_COPYFILE_H */ +int copyfile(const char *from, const char *to, + void *state, uint32_t flags); +#define COPYFILE_ACL (1<<0) +#define COPYFILE_XATTR (1<<2) +#define COPYFILE_NOFOLLOW_SRC (1<<18) +#if defined(HAVE_WEAK_IMPORT) && (MAC_OS_X_VERSION_MIN_REQUIRED < 1040) +/* Support for weakly importing copyfile. */ +#define WEAK_IMPORT_COPYFILE +extern int copyfile(const char *from, const char *to, + void *state, uint32_t flags) + WEAK_IMPORT_ATTRIBUTE; +#endif /* HAVE_WEAK_IMPORT */ +#endif /* HAVE_COPYFILE_H */ +#endif /* HAVE_COPYFILE */ + +#ifdef WEAK_IMPORT_COPYFILE +#define MayUseCopyFile() (copyfile != NULL) +#elif defined(HAVE_COPYFILE) +#define MayUseCopyFile() (1) +#else +#define MayUseCopyFile() (0) #endif +#include <libkern/OSByteOrder.h> + /* - * Constants for file attributes subcommand. - * Need to be kept in sync with tclUnixFCmd.c ! + * Constants for file attributes subcommand. Need to be kept in sync with + * tclUnixFCmd.c ! */ enum { @@ -41,26 +77,38 @@ enum { typedef u_int32_t OSType; -static int Tcl_GetOSTypeFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, - OSType *osTypePtr); -static Tcl_Obj *Tcl_NewOSTypeStringObj(CONST OSType newOSType); +static int GetOSTypeFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, OSType *osTypePtr); +static Tcl_Obj * NewOSTypeObj(const OSType newOSType); +static int SetOSTypeFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr); +static void UpdateStringOfOSType(Tcl_Obj *objPtr); + +static const Tcl_ObjType tclOSTypeType = { + "osType", /* name */ + NULL, /* freeIntRepProc */ + NULL, /* dupIntRepProc */ + UpdateStringOfOSType, /* updateStringProc */ + SetOSTypeFromAny /* setFromAnyProc */ +}; enum { - kFinfoIsInvisible = 0x4000, + kIsInvisible = 0x4000, }; +#define kFinfoIsInvisible (OSSwapHostToBigConstInt16(kIsInvisible)) + +typedef struct finderinfo { + u_int32_t type; + u_int32_t creator; + u_int16_t fdFlags; + u_int32_t location; + u_int16_t reserved; + u_int32_t extendedFileInfo[4]; +} __attribute__ ((__packed__)) finderinfo; + typedef struct fileinfobuf { - u_int32_t info_length; - union { - struct { - u_int32_t type; - u_int32_t creator; - u_int16_t fdFlags; - u_int16_t location; - u_int32_t padding[4]; - } finder; - off_t rsrcForkSize; - } data; + u_int32_t info_length; + u_int32_t data[8]; } fileinfobuf; /* @@ -68,88 +116,96 @@ typedef struct fileinfobuf { * * TclMacOSXGetFileAttribute * - * Gets a MacOSX attribute of a file. Which attribute is - * controlled by objIndex. The object will have ref count 0. + * Gets a MacOSX attribute of a file. Which attribute is controlled by + * objIndex. The object will have ref count 0. * * Results: - * Standard TCL result. Returns a new Tcl_Obj in attributePtrPtr - * if there is no error. + * Standard TCL result. Returns a new Tcl_Obj in attributePtrPtr if there + * is no error. * * Side effects: - * A new object is allocated. - * + * A new object is allocated. + * *---------------------------------------------------------------------- */ int -TclMacOSXGetFileAttribute(interp, objIndex, fileName, attributePtrPtr) - Tcl_Interp *interp; /* The interp we are using for errors. */ - int objIndex; /* The index of the attribute. */ - Tcl_Obj *fileName; /* The name of the file (UTF-8). */ - Tcl_Obj **attributePtrPtr; /* A pointer to return the object with. */ +TclMacOSXGetFileAttribute( + Tcl_Interp *interp, /* The interp we are using for errors. */ + int objIndex, /* The index of the attribute. */ + Tcl_Obj *fileName, /* The name of the file (UTF-8). */ + Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */ { #ifdef HAVE_GETATTRLIST int result; Tcl_StatBuf statBuf; struct attrlist alist; fileinfobuf finfo; - CONST char *native; - + finderinfo *finder = (finderinfo *) &finfo.data; + off_t *rsrcForkSize = (off_t *) &finfo.data; + const char *native; + result = TclpObjStat(fileName, &statBuf); - + if (result != 0) { - Tcl_AppendResult(interp, "could not read \"", - Tcl_GetString(fileName), "\": ", - Tcl_PosixError(interp), (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); return TCL_ERROR; } if (S_ISDIR(statBuf.st_mode) && objIndex != MACOSX_HIDDEN_ATTRIBUTE) { - /* Directories only support attribute "-hidden" */ - errno = EISDIR; - Tcl_AppendResult(interp, "invalid attribute: ", - Tcl_PosixError(interp), (char *) NULL); - return TCL_ERROR; + /* + * Directories only support attribute "-hidden". + */ + + errno = EISDIR; + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid attribute: %s", Tcl_PosixError(interp))); + return TCL_ERROR; } - memset(&alist, 0, sizeof(struct attrlist)); + bzero(&alist, sizeof(struct attrlist)); alist.bitmapcount = ATTR_BIT_MAP_COUNT; - if(objIndex == MACOSX_RSRCLENGTH_ATTRIBUTE) { - alist.fileattr = ATTR_FILE_RSRCLENGTH; + if (objIndex == MACOSX_RSRCLENGTH_ATTRIBUTE) { + alist.fileattr = ATTR_FILE_RSRCLENGTH; } else { - alist.commonattr = ATTR_CMN_FNDRINFO; + alist.commonattr = ATTR_CMN_FNDRINFO; } native = Tcl_FSGetNativePath(fileName); result = getattrlist(native, &alist, &finfo, sizeof(fileinfobuf), 0); if (result != 0) { - Tcl_AppendResult(interp, "could not read attributes of \"", - Tcl_GetString(fileName), "\": ", - Tcl_PosixError(interp), (char *) NULL); - return TCL_ERROR; + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read attributes of \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); + return TCL_ERROR; } switch (objIndex) { - case MACOSX_CREATOR_ATTRIBUTE: - *attributePtrPtr = Tcl_NewOSTypeStringObj(finfo.data.finder.creator); - break; - case MACOSX_TYPE_ATTRIBUTE: - *attributePtrPtr = Tcl_NewOSTypeStringObj(finfo.data.finder.type); - break; - case MACOSX_HIDDEN_ATTRIBUTE: - *attributePtrPtr = Tcl_NewBooleanObj( (finfo.data.finder.fdFlags - & kFinfoIsInvisible) != 0); - break; - case MACOSX_RSRCLENGTH_ATTRIBUTE: - *attributePtrPtr = Tcl_NewWideIntObj(finfo.data.rsrcForkSize); - break; + case MACOSX_CREATOR_ATTRIBUTE: + *attributePtrPtr = NewOSTypeObj( + OSSwapBigToHostInt32(finder->creator)); + break; + case MACOSX_TYPE_ATTRIBUTE: + *attributePtrPtr = NewOSTypeObj( + OSSwapBigToHostInt32(finder->type)); + break; + case MACOSX_HIDDEN_ATTRIBUTE: + *attributePtrPtr = Tcl_NewBooleanObj( + (finder->fdFlags & kFinfoIsInvisible) != 0); + break; + case MACOSX_RSRCLENGTH_ATTRIBUTE: + *attributePtrPtr = Tcl_NewWideIntObj(*rsrcForkSize); + break; } return TCL_OK; #else - Tcl_AppendResult(interp, "Mac OS X file attributes not supported", - (char *) NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "Mac OS X file attributes not supported", -1)); + Tcl_SetErrorCode(interp, "TCL", "UNSUPPORTED", NULL); return TCL_ERROR; -#endif +#endif /* HAVE_GETATTRLIST */ } /* @@ -157,146 +213,170 @@ TclMacOSXGetFileAttribute(interp, objIndex, fileName, attributePtrPtr) * * TclMacOSXSetFileAttribute -- * - * Sets a MacOSX attribute of a file. Which attribute is - * controlled by objIndex. + * Sets a MacOSX attribute of a file. Which attribute is controlled by + * objIndex. * * Results: - * Standard TCL result. + * Standard TCL result. * * Side effects: - * As above. - * + * As above. + * *--------------------------------------------------------------------------- */ int -TclMacOSXSetFileAttribute(interp, objIndex, fileName, attributePtr) - Tcl_Interp *interp; /* The interp for error reporting. */ - int objIndex; /* The index of the attribute. */ - Tcl_Obj *fileName; /* The name of the file (UTF-8). */ - Tcl_Obj *attributePtr; /* New owner for file. */ +TclMacOSXSetFileAttribute( + Tcl_Interp *interp, /* The interp for error reporting. */ + int objIndex, /* The index of the attribute. */ + Tcl_Obj *fileName, /* The name of the file (UTF-8). */ + Tcl_Obj *attributePtr) /* New owner for file. */ { #ifdef HAVE_GETATTRLIST int result; Tcl_StatBuf statBuf; struct attrlist alist; fileinfobuf finfo; - CONST char *native; - + finderinfo *finder = (finderinfo *) &finfo.data; + off_t *rsrcForkSize = (off_t *) &finfo.data; + const char *native; + result = TclpObjStat(fileName, &statBuf); - + if (result != 0) { - Tcl_AppendResult(interp, "could not read \"", - Tcl_GetString(fileName), "\": ", - Tcl_PosixError(interp), (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); return TCL_ERROR; } if (S_ISDIR(statBuf.st_mode) && objIndex != MACOSX_HIDDEN_ATTRIBUTE) { - /* Directories only support attribute "-hidden" */ - errno = EISDIR; - Tcl_AppendResult(interp, "invalid attribute: ", - Tcl_PosixError(interp), (char *) NULL); - return TCL_ERROR; + /* + * Directories only support attribute "-hidden". + */ + + errno = EISDIR; + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid attribute: %s", Tcl_PosixError(interp))); + return TCL_ERROR; } - memset(&alist, 0, sizeof(struct attrlist)); + bzero(&alist, sizeof(struct attrlist)); alist.bitmapcount = ATTR_BIT_MAP_COUNT; - if(objIndex == MACOSX_RSRCLENGTH_ATTRIBUTE) { - alist.fileattr = ATTR_FILE_RSRCLENGTH; + if (objIndex == MACOSX_RSRCLENGTH_ATTRIBUTE) { + alist.fileattr = ATTR_FILE_RSRCLENGTH; } else { - alist.commonattr = ATTR_CMN_FNDRINFO; + alist.commonattr = ATTR_CMN_FNDRINFO; } native = Tcl_FSGetNativePath(fileName); result = getattrlist(native, &alist, &finfo, sizeof(fileinfobuf), 0); if (result != 0) { - Tcl_AppendResult(interp, "could not read attributes of \"", - Tcl_GetString(fileName), "\": ", - Tcl_PosixError(interp), (char *) NULL); - return TCL_ERROR; + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read attributes of \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); + return TCL_ERROR; } if (objIndex != MACOSX_RSRCLENGTH_ATTRIBUTE) { - switch (objIndex) { - case MACOSX_CREATOR_ATTRIBUTE: - if (Tcl_GetOSTypeFromObj(interp, attributePtr, - &finfo.data.finder.creator) != TCL_OK) { - return TCL_ERROR; - } - break; - case MACOSX_TYPE_ATTRIBUTE: - if (Tcl_GetOSTypeFromObj(interp, attributePtr, - &finfo.data.finder.type) != TCL_OK) { - return TCL_ERROR; - } - break; - case MACOSX_HIDDEN_ATTRIBUTE: - { - int hidden; - if (Tcl_GetBooleanFromObj(interp, attributePtr, &hidden) - != TCL_OK) { - return TCL_ERROR; - } - if (hidden) { - finfo.data.finder.fdFlags |= kFinfoIsInvisible; - } else { - finfo.data.finder.fdFlags &= ~kFinfoIsInvisible; - } - } - break; - } - result = setattrlist(native, &alist, &finfo.data, sizeof(finfo.data), 0); - - if (result != 0) { - Tcl_AppendResult(interp, "could not set attributes of \"", - Tcl_GetString(fileName), "\": ", - Tcl_PosixError(interp), (char *) NULL); - return TCL_ERROR; - } + OSType t; + int h; + + switch (objIndex) { + case MACOSX_CREATOR_ATTRIBUTE: + if (GetOSTypeFromObj(interp, attributePtr, &t) != TCL_OK) { + return TCL_ERROR; + } + finder->creator = OSSwapHostToBigInt32(t); + break; + case MACOSX_TYPE_ATTRIBUTE: + if (GetOSTypeFromObj(interp, attributePtr, &t) != TCL_OK) { + return TCL_ERROR; + } + finder->type = OSSwapHostToBigInt32(t); + break; + case MACOSX_HIDDEN_ATTRIBUTE: + if (Tcl_GetBooleanFromObj(interp, attributePtr, &h) != TCL_OK) { + return TCL_ERROR; + } + if (h) { + finder->fdFlags |= kFinfoIsInvisible; + } else { + finder->fdFlags &= ~kFinfoIsInvisible; + } + break; + } + + result = setattrlist(native, &alist, + &finfo.data, sizeof(finfo.data), 0); + + if (result != 0) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not set attributes of \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); + return TCL_ERROR; + } } else { - off_t newRsrcForkSize; - - if (Tcl_GetWideIntFromObj(interp, attributePtr, - &newRsrcForkSize) != TCL_OK) { - return TCL_ERROR; - } - - if(newRsrcForkSize != finfo.data.rsrcForkSize) { - Tcl_DString ds; - /* - * Only setting rsrclength to 0 to strip - * a file's resource fork is supported. - */ - if(newRsrcForkSize != 0) { - Tcl_AppendResult(interp, - "setting nonzero rsrclength not supported", - (char *) NULL); - return TCL_ERROR; - } - - /* construct path to resource fork */ - Tcl_DStringInit(&ds); - Tcl_DStringAppend(&ds, native, -1); - Tcl_DStringAppend(&ds, _PATH_RSRCFORKSPEC, -1); - - result = truncate(Tcl_DStringValue(&ds), (off_t)0); - - Tcl_DStringFree(&ds); - - if (result != 0) { - Tcl_AppendResult(interp, - "could not truncate resource fork of \"", - Tcl_GetString(fileName), "\": ", - Tcl_PosixError(interp), (char *) NULL); - return TCL_ERROR; - } - } + Tcl_WideInt newRsrcForkSize; + + if (Tcl_GetWideIntFromObj(interp, attributePtr, + &newRsrcForkSize) != TCL_OK) { + return TCL_ERROR; + } + + if (newRsrcForkSize != *rsrcForkSize) { + Tcl_DString ds; + + /* + * Only setting rsrclength to 0 to strip a file's resource fork is + * supported. + */ + + if (newRsrcForkSize != 0) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "setting nonzero rsrclength not supported", -1)); + Tcl_SetErrorCode(interp, "TCL", "UNSUPPORTED", NULL); + return TCL_ERROR; + } + + /* + * Construct path to resource fork. + */ + + Tcl_DStringInit(&ds); + Tcl_DStringAppend(&ds, native, -1); + Tcl_DStringAppend(&ds, _PATH_RSRCFORKSPEC, -1); + + result = truncate(Tcl_DStringValue(&ds), (off_t)0); + if (result != 0) { + /* + * truncate() on a valid resource fork path may fail with a + * permission error in some OS releases, try truncating with + * open() instead: + */ + + int fd = open(Tcl_DStringValue(&ds), O_WRONLY | O_TRUNC); + + if (fd > 0) { + result = close(fd); + } + } + + Tcl_DStringFree(&ds); + + if (result != 0) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not truncate resource fork of \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); + return TCL_ERROR; + } + } } return TCL_OK; #else - Tcl_AppendResult(interp, "Mac OS X file attributes not supported", - (char *) NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "Mac OS X file attributes not supported", -1)); + Tcl_SetErrorCode(interp, "TCL", "UNSUPPORTED", NULL); return TCL_ERROR; #endif } @@ -313,83 +393,175 @@ TclMacOSXSetFileAttribute(interp, objIndex, fileName, attributePtr) * Standard Tcl result. * * Side effects: - * MacOSX attributes and resource fork are updated in the new file - * to reflect the old file. + * MacOSX attributes and resource fork are updated in the new file to + * reflect the old file. * *--------------------------------------------------------------------------- */ int -TclMacOSXCopyFileAttributes(src, dst, statBufPtr) - CONST char *src; /* Path name of source file (native). */ - CONST char *dst; /* Path name of target file (native). */ - CONST Tcl_StatBuf *statBufPtr; +TclMacOSXCopyFileAttributes( + const char *src, /* Path name of source file (native). */ + const char *dst, /* Path name of target file (native). */ + const Tcl_StatBuf *statBufPtr) /* Stat info for source file */ { + if (MayUseCopyFile()) { +#ifdef HAVE_COPYFILE + if (0 == copyfile(src, dst, NULL, (S_ISLNK(statBufPtr->st_mode) + ? COPYFILE_XATTR | COPYFILE_NOFOLLOW_SRC + : COPYFILE_XATTR | COPYFILE_ACL))) { + return TCL_OK; + } +#endif /* HAVE_COPYFILE */ + } else { +#if (!defined(HAVE_COPYFILE) || defined(WEAK_IMPORT_COPYFILE)) && defined(HAVE_GETATTRLIST) + struct attrlist alist; + fileinfobuf finfo; + off_t *rsrcForkSize = (off_t *) &finfo.data; + Tcl_DString srcBuf, dstBuf; + int result; + + bzero(&alist, sizeof(struct attrlist)); + alist.bitmapcount = ATTR_BIT_MAP_COUNT; + alist.commonattr = ATTR_CMN_FNDRINFO; + + if (getattrlist(src, &alist, &finfo, sizeof(fileinfobuf), 0)) { + return TCL_ERROR; + } + if (setattrlist(dst, &alist, &finfo.data, sizeof(finfo.data), 0)) { + return TCL_ERROR; + } + + /* + * If we're a directory, we're done as they never have resource forks. + */ + + if (S_ISDIR(statBufPtr->st_mode)) { + return TCL_OK; + } + + /* + * We only copy a non-empty resource fork, so determine if that's the + * case first. + */ + + alist.commonattr = 0; + alist.fileattr = ATTR_FILE_RSRCLENGTH; + if (getattrlist(src, &alist, &finfo, sizeof(fileinfobuf), 0)) { + return TCL_ERROR; + } else if (*rsrcForkSize == 0) { + return TCL_OK; + } + + /* + * Construct paths to resource forks. + */ + + Tcl_DStringInit(&srcBuf); + Tcl_DStringAppend(&srcBuf, src, -1); + Tcl_DStringAppend(&srcBuf, _PATH_RSRCFORKSPEC, -1); + Tcl_DStringInit(&dstBuf); + Tcl_DStringAppend(&dstBuf, dst, -1); + Tcl_DStringAppend(&dstBuf, _PATH_RSRCFORKSPEC, -1); + + /* + * Do the copy. + */ + + result = TclUnixCopyFile(Tcl_DStringValue(&srcBuf), + Tcl_DStringValue(&dstBuf), statBufPtr, 1); + Tcl_DStringFree(&srcBuf); + Tcl_DStringFree(&dstBuf); + if (result == 0) { + return TCL_OK; + } +#endif /* (!HAVE_COPYFILE || WEAK_IMPORT_COPYFILE) && HAVE_GETATTRLIST */ + } + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * TclMacOSXMatchType -- + * + * This routine is used by the globbing code to check if a file matches a + * given mac type and/or creator code. + * + * Results: + * The return value is 1, 0 or -1 indicating whether the file matches the + * given criteria, does not match them, or an error occurred (in wich + * case an error is left in interp). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclMacOSXMatchType( + Tcl_Interp *interp, /* Interpreter to receive errors. */ + const char *pathName, /* Native path to check. */ + const char *fileName, /* Native filename to check. */ + Tcl_StatBuf *statBufPtr, /* Stat info for file to check */ + Tcl_GlobTypeData *types) /* Type description to match against. */ +{ #ifdef HAVE_GETATTRLIST struct attrlist alist; fileinfobuf finfo; - - memset(&alist, 0, sizeof(struct attrlist)); - alist.bitmapcount = ATTR_BIT_MAP_COUNT; - alist.commonattr = ATTR_CMN_FNDRINFO; + finderinfo *finder = (finderinfo *) &finfo.data; + OSType osType; - if (getattrlist(src, &alist, &finfo, sizeof(fileinfobuf), 0)) { - return TCL_ERROR; + bzero(&alist, sizeof(struct attrlist)); + alist.bitmapcount = ATTR_BIT_MAP_COUNT; + alist.commonattr = ATTR_CMN_FNDRINFO; + if (getattrlist(pathName, &alist, &finfo, sizeof(fileinfobuf), 0) != 0) { + return 0; } - - if (setattrlist(dst, &alist, &finfo.data, sizeof(finfo.data), 0)) { - return TCL_ERROR; + if ((types->perm & TCL_GLOB_PERM_HIDDEN) && + !((finder->fdFlags & kFinfoIsInvisible) || (*fileName == '.'))) { + return 0; } + if (S_ISDIR(statBufPtr->st_mode) + && (types->macType || types->macCreator)) { + /* + * Directories don't support types or creators. + */ - if (!S_ISDIR(statBufPtr->st_mode)) { - /* only copy non-empty resource fork */ - alist.commonattr = 0; - alist.fileattr = ATTR_FILE_RSRCLENGTH; - - if (getattrlist(src, &alist, &finfo, sizeof(fileinfobuf), 0)) { - return TCL_ERROR; + return 0; + } + if (types->macType) { + if (GetOSTypeFromObj(interp, types->macType, &osType) != TCL_OK) { + return -1; + } + if (osType != OSSwapBigToHostInt32(finder->type)) { + return 0; + } + } + if (types->macCreator) { + if (GetOSTypeFromObj(interp, types->macCreator, &osType) != TCL_OK) { + return -1; + } + if (osType != OSSwapBigToHostInt32(finder->creator)) { + return 0; } - - if(finfo.data.rsrcForkSize > 0) { - int result; - Tcl_DString ds_src, ds_dst; - - /* construct paths to resource forks */ - Tcl_DStringInit(&ds_src); - Tcl_DStringAppend(&ds_src, src, -1); - Tcl_DStringAppend(&ds_src, _PATH_RSRCFORKSPEC, -1); - Tcl_DStringInit(&ds_dst); - Tcl_DStringAppend(&ds_dst, dst, -1); - Tcl_DStringAppend(&ds_dst, _PATH_RSRCFORKSPEC, -1); - - result = TclUnixCopyFile(Tcl_DStringValue(&ds_src), - Tcl_DStringValue(&ds_dst), statBufPtr, 1); - - Tcl_DStringFree(&ds_src); - Tcl_DStringFree(&ds_dst); - - if (result != 0) { - return TCL_ERROR; - } - } } - return TCL_OK; -#else - return TCL_ERROR; #endif + return 1; } /* *---------------------------------------------------------------------- * - * Tcl_GetOSTypeFromObj -- + * GetOSTypeFromObj -- * * Attempt to return an OSType from the Tcl object "objPtr". * * Results: - * Standard TCL result. If an error occurs during conversion, - * an error message is left in interp->objResult. + * Standard TCL result. If an error occurs during conversion, an error + * message is left in interp->objResult. * * Side effects: * The string representation of objPtr will be updated if necessary. @@ -398,12 +570,72 @@ TclMacOSXCopyFileAttributes(src, dst, statBufPtr) */ static int -Tcl_GetOSTypeFromObj( - Tcl_Interp *interp, /* Used for error reporting if not NULL. */ - Tcl_Obj *objPtr, /* The object from which to get an OSType. */ - OSType *osTypePtr) /* Place to store resulting OSType. */ +GetOSTypeFromObj( + Tcl_Interp *interp, /* Used for error reporting if not NULL. */ + Tcl_Obj *objPtr, /* The object from which to get an OSType. */ + OSType *osTypePtr) /* Place to store resulting OSType. */ +{ + int result = TCL_OK; + + if (objPtr->typePtr != &tclOSTypeType) { + result = SetOSTypeFromAny(interp, objPtr); + } + *osTypePtr = (OSType) objPtr->internalRep.longValue; + return result; +} + +/* + *---------------------------------------------------------------------- + * + * NewOSTypeObj -- + * + * Create a new OSType object. + * + * Results: + * The newly created OSType object is returned, it has ref count 0. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Tcl_Obj * +NewOSTypeObj( + const OSType osType) /* OSType used to initialize the new + * object. */ +{ + Tcl_Obj *objPtr; + + TclNewObj(objPtr); + TclInvalidateStringRep(objPtr); + objPtr->internalRep.longValue = (long) osType; + objPtr->typePtr = &tclOSTypeType; + return objPtr; +} + +/* + *---------------------------------------------------------------------- + * + * SetOSTypeFromAny -- + * + * Attempts to force the internal representation for a Tcl object to + * tclOSTypeType, specifically. + * + * Results: + * The return value is a standard object Tcl result. If an error occurs + * during conversion, an error message is left in the interpreter's + * result unless "interp" is NULL. + * + *---------------------------------------------------------------------- + */ + +static int +SetOSTypeFromAny( + Tcl_Interp *interp, /* Tcl interpreter */ + Tcl_Obj *objPtr) /* Pointer to the object to convert */ { - char *string; + const char *string; int length, result = TCL_OK; Tcl_DString ds; Tcl_Encoding encoding = Tcl_GetEncoding(NULL, "macRoman"); @@ -411,15 +643,25 @@ Tcl_GetOSTypeFromObj( string = Tcl_GetStringFromObj(objPtr, &length); Tcl_UtfToExternalDString(encoding, string, length, &ds); - if (Tcl_DStringLength(&ds) > sizeof(OSType)) { - Tcl_AppendResult(interp, - "expected Macintosh OS type but got \"", - string, "\": ", (char *) NULL); - result = TCL_ERROR; + if (Tcl_DStringLength(&ds) > 4) { + if (interp) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "expected Macintosh OS type but got \"%s\": ", string)); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "MAC_OSTYPE", NULL); + } + result = TCL_ERROR; } else { - memset(osTypePtr, 0, sizeof(OSType)); - memcpy(osTypePtr, Tcl_DStringValue(&ds), - (size_t) Tcl_DStringLength(&ds)); + OSType osType; + char bytes[4] = {'\0','\0','\0','\0'}; + + memcpy(bytes, Tcl_DStringValue(&ds), (size_t)Tcl_DStringLength(&ds)); + osType = (OSType) bytes[0] << 24 | + (OSType) bytes[1] << 16 | + (OSType) bytes[2] << 8 | + (OSType) bytes[3]; + TclFreeIntRep(objPtr); + objPtr->internalRep.longValue = (long) osType; + objPtr->typePtr = &tclOSTypeType; } Tcl_DStringFree(&ds); Tcl_FreeEncoding(encoding); @@ -429,33 +671,51 @@ Tcl_GetOSTypeFromObj( /* *---------------------------------------------------------------------- * - * Tcl_NewOSTypeStringObj -- + * UpdateStringOfOSType -- * - * Create a new OSType string object. + * Update the string representation for an OSType object. Note: This + * function does not free an existing old string rep so storage will be + * lost if this has not already been done. * * Results: - * The newly created string object is returned, it has ref count 0. + * None. * * Side effects: - * None. + * The object's string is set to a valid string that results from the + * OSType-to-string conversion. * *---------------------------------------------------------------------- */ -static Tcl_Obj * -Tcl_NewOSTypeStringObj( - CONST OSType newOSType) /* OSType used to initialize the new object. */ +static void +UpdateStringOfOSType( + register Tcl_Obj *objPtr) /* OSType object whose string rep to + * update. */ { - char string[sizeof(OSType)+1]; - Tcl_Obj *resultPtr; + char string[5]; + OSType osType = (OSType) objPtr->internalRep.longValue; Tcl_DString ds; Tcl_Encoding encoding = Tcl_GetEncoding(NULL, "macRoman"); + unsigned len; - memcpy(string, &newOSType, sizeof(OSType)); - string[sizeof(OSType)] = '\0'; + string[0] = (char) (osType >> 24); + string[1] = (char) (osType >> 16); + string[2] = (char) (osType >> 8); + string[3] = (char) (osType); + string[4] = '\0'; Tcl_ExternalToUtfDString(encoding, string, -1, &ds); - resultPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); + len = (unsigned) Tcl_DStringLength(&ds) + 1; + objPtr->bytes = ckalloc(len); + memcpy(objPtr->bytes, Tcl_DStringValue(&ds), len); + objPtr->length = Tcl_DStringLength(&ds); Tcl_DStringFree(&ds); Tcl_FreeEncoding(encoding); - return resultPtr; } + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |