diff options
Diffstat (limited to 'unix/tclUnixFCmd.c')
-rw-r--r-- | unix/tclUnixFCmd.c | 794 |
1 files changed, 566 insertions, 228 deletions
diff --git a/unix/tclUnixFCmd.c b/unix/tclUnixFCmd.c index 13a2a6e..3b1b6ca 100644 --- a/unix/tclUnixFCmd.c +++ b/unix/tclUnixFCmd.c @@ -2,7 +2,7 @@ * tclUnixFCmd.c * * This file implements the unix specific portion of file manipulation - * subcommands of the "file" command. All filename arguments should + * subcommands of the "file" command. All filename arguments should * already be translated to native format. * * Copyright (c) 1996-1998 Sun Microsystems, Inc. @@ -10,13 +10,11 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclUnixFCmd.c,v 1.60 2006/11/15 20:08:45 dgp Exp $ - * * Portions of this code were derived from NetBSD source code which has the * following copyright notice: * * Copyright (c) 1988, 1993, 1994 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,11 +23,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors may + * 3. Neither the name of the University nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -49,11 +43,11 @@ #include "tclInt.h" #include <utime.h> #include <grp.h> -#ifndef HAVE_ST_BLKSIZE +#ifndef HAVE_STRUCT_STAT_ST_BLKSIZE #ifndef NO_FSTATFS #include <sys/statfs.h> #endif -#endif +#endif /* !HAVE_STRUCT_STAT_ST_BLKSIZE */ #ifdef HAVE_FTS #include <fts.h> #endif @@ -63,11 +57,21 @@ * TraverseUnixTree() calls the traverseProc() */ -#define DOTREE_PRED 1 /* pre-order directory */ +#define DOTREE_PRED 1 /* pre-order directory */ #define DOTREE_POSTD 2 /* post-order directory */ #define DOTREE_F 3 /* regular file */ /* + * Fallback temporary file location the temporary file generation code. Can be + * overridden at compile time for when it is known that temp files can't be + * written to /tmp (hello, iOS!). + */ + +#ifndef TCL_TEMPORARY_FILE_DIRECTORY +#define TCL_TEMPORARY_FILE_DIRECTORY "/tmp" +#endif + +/* * Callbacks for file attributes code. */ @@ -86,11 +90,11 @@ static int SetPermissionsAttribute(Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj *attributePtr); static int GetModeFromPermString(Tcl_Interp *interp, - char *modeStringPtr, mode_t *modePtr); -#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) -static int GetReadOnlyAttribute(Tcl_Interp *interp, int objIndex, + const char *modeStringPtr, mode_t *modePtr); +#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) || defined(__CYGWIN__) +static int GetUnixFileAttributes(Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr); -static int SetReadOnlyAttribute(Tcl_Interp *interp, int objIndex, +static int SetUnixFileAttributes(Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj *attributePtr); #endif @@ -99,7 +103,7 @@ static int SetReadOnlyAttribute(Tcl_Interp *interp, int objIndex, */ typedef int (TraversalProc)(Tcl_DString *srcPtr, Tcl_DString *dstPtr, - CONST Tcl_StatBuf *statBufPtr, int type, Tcl_DString *errorPtr); + const Tcl_StatBuf *statBufPtr, int type, Tcl_DString *errorPtr); /* * Constants and variables necessary for file attributes subcommand. @@ -116,14 +120,24 @@ typedef int (TraversalProc)(Tcl_DString *srcPtr, Tcl_DString *dstPtr, */ extern TclFileAttrProcs tclpFileAttrProcs[]; -extern char *tclpFileAttrStrings[]; +extern const char *const tclpFileAttrStrings[]; -#else +#else /* !DJGPP */ enum { - UNIX_GROUP_ATTRIBUTE, UNIX_OWNER_ATTRIBUTE, UNIX_PERMISSIONS_ATTRIBUTE, -#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) +#if defined(__CYGWIN__) + UNIX_ARCHIVE_ATTRIBUTE, +#endif + UNIX_GROUP_ATTRIBUTE, +#if defined(__CYGWIN__) + UNIX_HIDDEN_ATTRIBUTE, +#endif + UNIX_OWNER_ATTRIBUTE, UNIX_PERMISSIONS_ATTRIBUTE, +#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) || defined(__CYGWIN__) UNIX_READONLY_ATTRIBUTE, #endif +#if defined(__CYGWIN__) + UNIX_SYSTEM_ATTRIBUTE, +#endif #ifdef MAC_OSX_TCL MACOSX_CREATOR_ATTRIBUTE, MACOSX_TYPE_ATTRIBUTE, MACOSX_HIDDEN_ATTRIBUTE, MACOSX_RSRCLENGTH_ATTRIBUTE, @@ -131,25 +145,44 @@ enum { UNIX_INVALID_ATTRIBUTE /* lint - last enum value needs no trailing , */ }; -MODULE_SCOPE CONST char *tclpFileAttrStrings[]; -CONST char *tclpFileAttrStrings[] = { - "-group", "-owner", "-permissions", -#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) +MODULE_SCOPE const char *const tclpFileAttrStrings[]; +const char *const tclpFileAttrStrings[] = { +#if defined(__CYGWIN__) + "-archive", +#endif + "-group", +#if defined(__CYGWIN__) + "-hidden", +#endif + "-owner", "-permissions", +#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) || defined(__CYGWIN__) "-readonly", #endif +#if defined(__CYGWIN__) + "-system", +#endif #ifdef MAC_OSX_TCL "-creator", "-type", "-hidden", "-rsrclength", #endif NULL }; -MODULE_SCOPE CONST TclFileAttrProcs tclpFileAttrProcs[]; -CONST TclFileAttrProcs tclpFileAttrProcs[] = { +MODULE_SCOPE const TclFileAttrProcs tclpFileAttrProcs[]; +const TclFileAttrProcs tclpFileAttrProcs[] = { +#if defined(__CYGWIN__) + {GetUnixFileAttributes, SetUnixFileAttributes}, +#endif {GetGroupAttribute, SetGroupAttribute}, +#if defined(__CYGWIN__) + {GetUnixFileAttributes, SetUnixFileAttributes}, +#endif {GetOwnerAttribute, SetOwnerAttribute}, {GetPermissionsAttribute, SetPermissionsAttribute}, -#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) - {GetReadOnlyAttribute, SetReadOnlyAttribute}, +#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) || defined(__CYGWIN__) + {GetUnixFileAttributes, SetUnixFileAttributes}, +#endif +#if defined(__CYGWIN__) + {GetUnixFileAttributes, SetUnixFileAttributes}, #endif #ifdef MAC_OSX_TCL {TclMacOSXGetFileAttribute, TclMacOSXSetFileAttribute}, @@ -158,17 +191,17 @@ CONST TclFileAttrProcs tclpFileAttrProcs[] = { {TclMacOSXGetFileAttribute, TclMacOSXSetFileAttribute}, #endif }; -#endif +#endif /* DJGPP */ /* * This is the maximum number of consecutive readdir/unlink calls that can be * made (with no intervening rewinddir or closedir/opendir) before triggering * a bug that makes readdir return NULL even though some directory entries - * have not been processed. The bug afflicts SunOS's readdir when applied to - * ufs file systems and Darwin 6.5's (and OSX v.10.3.8's) HFS+. JH found the - * Darwin readdir to reset at 147, so 130 is chosen to be conservative. We + * have not been processed. The bug afflicts SunOS's readdir when applied to + * ufs file systems and Darwin 6.5's (and OSX v.10.3.8's) HFS+. JH found the + * Darwin readdir to reset at 147, so 130 is chosen to be conservative. We * can't do a general rewind on failure as NFS can create special files that - * recreate themselves when you try and delete them. 8.4.8 added a solution + * recreate themselves when you try and delete them. 8.4.8 added a solution * that was affected by a single such NFS file, this solution should not be * affected by less than THRESHOLD such files. [Bug 1034337] */ @@ -179,20 +212,23 @@ CONST TclFileAttrProcs tclpFileAttrProcs[] = { * Declarations for local procedures defined in this file: */ -static int CopyFileAtts(CONST char *src, - CONST char *dst, CONST Tcl_StatBuf *statBufPtr); -static int DoCopyFile(CONST char *srcPtr, CONST char *dstPtr, - CONST Tcl_StatBuf *statBufPtr); -static int DoCreateDirectory(CONST char *pathPtr); +static int CopyFileAtts(const char *src, + const char *dst, const Tcl_StatBuf *statBufPtr); +static const char * DefaultTempDir(void); +static int DoCopyFile(const char *srcPtr, const char *dstPtr, + const Tcl_StatBuf *statBufPtr); +static int DoCreateDirectory(const char *pathPtr); static int DoRemoveDirectory(Tcl_DString *pathPtr, int recursive, Tcl_DString *errorPtr); -static int DoRenameFile(CONST char *src, CONST char *dst); +static int DoRenameFile(const char *src, const char *dst); static int TraversalCopy(Tcl_DString *srcPtr, - Tcl_DString *dstPtr, CONST Tcl_StatBuf *statBufPtr, - int type, Tcl_DString *errorPtr); + Tcl_DString *dstPtr, + const Tcl_StatBuf *statBufPtr, int type, + Tcl_DString *errorPtr); static int TraversalDelete(Tcl_DString *srcPtr, - Tcl_DString *dstPtr, CONST Tcl_StatBuf *statBufPtr, - int type, Tcl_DString *errorPtr); + Tcl_DString *dstPtr, + const Tcl_StatBuf *statBufPtr, int type, + Tcl_DString *errorPtr); static int TraverseUnixTree(TraversalProc *traversalProc, Tcl_DString *sourcePtr, Tcl_DString *destPtr, Tcl_DString *errorPtr, int doRewind); @@ -205,43 +241,64 @@ static int TraverseUnixTree(TraversalProc *traversalProc, * passing the standard MAXPATHLEN size resolved arg. */ -static char * Realpath(CONST char *path, char *resolved); +static char * Realpath(const char *path, char *resolved); char * Realpath( - CONST char *path, + const char *path, char *resolved) { memset(resolved, 0, MAXPATHLEN); return realpath(path, resolved); } #else -#define Realpath realpath -#endif +# define Realpath realpath +#endif /* PURIFY */ #ifndef NO_REALPATH #if defined(__APPLE__) && defined(TCL_THREADS) && \ defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ MAC_OS_X_VERSION_MIN_REQUIRED < 1030 /* - * prior to Darwin 7, realpath is not threadsafe, c.f. bug 711232; - * if we might potentially be running on pre-10.3 OSX, - * check Darwin release at runtime before using realpath. + * Prior to Darwin 7, realpath is not thread-safe, c.f. Bug 711232; if we + * might potentially be running on pre-10.3 OSX, check Darwin release at + * runtime before using realpath. */ + MODULE_SCOPE long tclMacOSXDarwinRelease; -#define haveRealpath (tclMacOSXDarwinRelease >= 7) +# define haveRealpath (tclMacOSXDarwinRelease >= 7) #else -#define haveRealpath 1 +# define haveRealpath 1 #endif #endif /* NO_REALPATH */ + +#ifdef HAVE_FTS +#if defined(HAVE_STRUCT_STAT64) && !defined(__APPLE__) +/* fts doesn't do stat64 */ +# define noFtsStat 1 +#elif defined(__APPLE__) && defined(__LP64__) && \ + defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ + MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +/* + * Prior to Darwin 9, 64bit fts_open() without FTS_NOSTAT may crash (due to a + * 64bit-unsafe ALIGN macro); if we could be running on pre-10.5 OSX, check + * Darwin release at runtime and do a separate stat() if necessary. + */ + +MODULE_SCOPE long tclMacOSXDarwinRelease; +# define noFtsStat (tclMacOSXDarwinRelease < 9) +#else +# define noFtsStat 0 +#endif +#endif /* HAVE_FTS */ /* *--------------------------------------------------------------------------- * * 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 + * 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. @@ -249,7 +306,7 @@ MODULE_SCOPE long tclMacOSXDarwinRelease; * In any other situation where dst already exists, the rename will fail. * * Results: - * If the directory was successfully created, returns TCL_OK. Otherwise + * 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: * @@ -280,9 +337,9 @@ TclpObjRenameFile( static int DoRenameFile( - CONST char *src, /* Pathname of file or dir to be renamed + const char *src, /* Pathname of file or dir to be renamed * (native). */ - CONST char *dst) /* New pathname of file or directory + const char *dst) /* New pathname of file or directory * (native). */ { if (rename(src, dst) == 0) { /* INTL: Native. */ @@ -368,12 +425,12 @@ DoRenameFile( * * 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: + * 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 "". + * ENOENT: src doesn't exist. src or dst is "". * * Side effects: * This procedure will also copy symbolic links, block, and character @@ -390,7 +447,7 @@ TclpObjCopyFile( Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr) { - CONST char *src = Tcl_FSGetNativePath(srcPathPtr); + const char *src = Tcl_FSGetNativePath(srcPathPtr); Tcl_StatBuf srcStatBuf; if (TclOSlstat(src, &srcStatBuf) != 0) { /* INTL: Native. */ @@ -402,9 +459,9 @@ TclpObjCopyFile( static int DoCopyFile( - CONST char *src, /* Pathname of file to be copied (native). */ - CONST char *dst, /* Pathname of file to copy to (native). */ - CONST Tcl_StatBuf *statBufPtr) + const char *src, /* Pathname of file to be copied (native). */ + const char *dst, /* Pathname of file to copy to (native). */ + const Tcl_StatBuf *statBufPtr) /* Used to determine filetype. */ { Tcl_StatBuf dstStatBuf; @@ -415,7 +472,7 @@ DoCopyFile( } /* - * symlink, and some of the other calls will fail if the target exists, so + * Symlink, and some of the other calls will fail if the target exists, so * we remove it first. */ @@ -434,15 +491,16 @@ DoCopyFile( switch ((int) (statBufPtr->st_mode & S_IFMT)) { #ifndef DJGPP case S_IFLNK: { - char link[MAXPATHLEN]; + char linkBuf[MAXPATHLEN+1]; int length; - length = readlink(src, link, sizeof(link)); /* INTL: Native. */ + length = readlink(src, linkBuf, MAXPATHLEN); + /* INTL: Native. */ if (length == -1) { return TCL_ERROR; } - link[length] = '\0'; - if (symlink(link, dst) < 0) { /* INTL: Native. */ + linkBuf[length] = '\0'; + if (symlink(linkBuf, dst) < 0) { /* INTL: Native. */ return TCL_ERROR; } #ifdef MAC_OSX_TCL @@ -450,7 +508,7 @@ DoCopyFile( #endif break; } -#endif +#endif /* !DJGPP */ case S_IFBLK: case S_IFCHR: if (mknod(dst, statBufPtr->st_mode, /* INTL: Native. */ @@ -481,17 +539,17 @@ DoCopyFile( * A standard Tcl result. * * Side effects: - * A file is copied. Dst will be overwritten if it exists. + * A file is copied. Dst will be overwritten if it exists. * *---------------------------------------------------------------------- */ int TclUnixCopyFile( - CONST char *src, /* Pathname of file to copy (native). */ - CONST char *dst, /* Pathname of file to create/overwrite + const char *src, /* Pathname of file to copy (native). */ + const char *dst, /* Pathname of file to create/overwrite * (native). */ - CONST Tcl_StatBuf *statBufPtr, + const Tcl_StatBuf *statBufPtr, /* Used to determine mode and blocksize. */ int dontCopyAtts) /* If flag set, don't copy attributes. */ { @@ -504,7 +562,9 @@ TclUnixCopyFile( #define BINMODE |O_BINARY #else #define BINMODE -#endif +#endif /* DJGPP */ + +#define DEFAULT_COPY_BLOCK_SIZE 4069 if ((srcFd = TclOSopen(src, O_RDONLY BINMODE, 0)) < 0) { /* INTL: Native */ return TCL_ERROR; @@ -523,33 +583,32 @@ TclUnixCopyFile( * that's likely to be fairly efficient anyway. */ -#ifdef HAVE_ST_BLKSIZE +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE blockSize = statBufPtr->st_blksize; -#else -#ifndef NO_FSTATFS +#elif !defined(NO_FSTATFS) { struct statfs fs; - if (fstatfs(srcFd, &fs, sizeof(fs), 0) == 0) { + if (fstatfs(srcFd, &fs) == 0) { blockSize = fs.f_bsize; } else { - blockSize = 4096; + blockSize = DEFAULT_COPY_BLOCK_SIZE; } } #else - blockSize = 4096; -#endif -#endif + blockSize = DEFAULT_COPY_BLOCK_SIZE; +#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ - /* [SF Tcl Bug 1586470] Even if we HAVE_ST_BLKSIZE, there are - * filesystems which report a bogus value for the blocksize. An - * example is the Andrew Filesystem (afs), reporting a blocksize - * of 0. When detecting such a situation we now simply fall back - * to a hardwired default size. + /* + * [SF Tcl Bug 1586470] Even if we HAVE_STRUCT_STAT_ST_BLKSIZE, there are + * filesystems which report a bogus value for the blocksize. An example + * is the Andrew Filesystem (afs), reporting a blocksize of 0. When + * detecting such a situation we now simply fall back to a hardwired + * default size. */ if (blockSize <= 0) { - blockSize = 4096; + blockSize = DEFAULT_COPY_BLOCK_SIZE; } buffer = ckalloc(blockSize); while (1) { @@ -590,8 +649,8 @@ TclUnixCopyFile( * * Results: * If the file was successfully deleted, returns TCL_OK. Otherwise the - * return value is TCL_ERROR and errno is set to indicate the error. - * Some possible values for errno are: + * return value is TCL_ERROR and errno is set to indicate the error. Some + * possible values for errno are: * * EACCES: a parent directory can't be read and/or written. * EISDIR: path is a directory. @@ -612,9 +671,9 @@ TclpObjDeleteFile( int TclpDeleteFile( - CONST char *path) /* Pathname of file to be removed (native). */ + const void *path) /* Pathname of file to be removed (native). */ { - if (unlink(path) != 0) { /* INTL: Native. */ + if (unlink((const char *)path) != 0) { return TCL_ERROR; } return TCL_OK; @@ -655,7 +714,7 @@ TclpObjCreateDirectory( static int DoCreateDirectory( - CONST char *path) /* Pathname of directory to create (native). */ + const char *path) /* Pathname of directory to create (native). */ { mode_t mode; @@ -736,7 +795,6 @@ TclpObjCopyDirectory( } return ret; } - /* *--------------------------------------------------------------------------- @@ -803,7 +861,7 @@ DoRemoveDirectory( * filled with UTF-8 name of file causing * error. */ { - CONST char *path; + const char *path; mode_t oldPerm = 0; int result; @@ -901,7 +959,7 @@ TraverseUnixTree( * files. */ { Tcl_StatBuf statBuf; - CONST char *source, *errfile; + const char *source, *errfile; int result, sourceLen; int targetLen; #ifndef HAVE_FTS @@ -909,7 +967,7 @@ TraverseUnixTree( Tcl_DirEntry *dirEntPtr; DIR *dirPtr; #else - CONST char *paths[2] = {NULL, NULL}; + const char *paths[2] = {NULL, NULL}; FTS *fts = NULL; FTSENT *ent; #endif @@ -928,7 +986,7 @@ TraverseUnixTree( * Process the regular file */ - return (*traverseProc)(sourcePtr, targetPtr, &statBuf, DOTREE_F, + return traverseProc(sourcePtr, targetPtr, &statBuf, DOTREE_F, errorPtr); } #ifndef HAVE_FTS @@ -941,18 +999,18 @@ TraverseUnixTree( errfile = source; goto end; } - result = (*traverseProc)(sourcePtr, targetPtr, &statBuf, DOTREE_PRED, + result = traverseProc(sourcePtr, targetPtr, &statBuf, DOTREE_PRED, errorPtr); if (result != TCL_OK) { closedir(dirPtr); return result; } - Tcl_DStringAppend(sourcePtr, "/", 1); + TclDStringAppendLiteral(sourcePtr, "/"); sourceLen = Tcl_DStringLength(sourcePtr); if (targetPtr != NULL) { - Tcl_DStringAppend(targetPtr, "/", 1); + TclDStringAppendLiteral(targetPtr, "/"); targetLen = Tcl_DStringLength(targetPtr); } @@ -990,8 +1048,8 @@ TraverseUnixTree( if (doRewind && (numProcessed > MAX_READDIR_UNLINK_THRESHOLD)) { /* * Call rewinddir if we've called unlink or rmdir so many times - * (since the opendir or the previous rewinddir), to avoid - * a NULL-return that may a symptom of a buggy readdir. + * (since the opendir or the previous rewinddir), to avoid a + * NULL-return that may a symptom of a buggy readdir. */ rewinddir(dirPtr); @@ -1015,18 +1073,13 @@ TraverseUnixTree( * that directory. */ - result = (*traverseProc)(sourcePtr, targetPtr, &statBuf, DOTREE_POSTD, + result = traverseProc(sourcePtr, targetPtr, &statBuf, DOTREE_POSTD, errorPtr); } #else /* HAVE_FTS */ paths[0] = source; - fts = fts_open((char**)paths, FTS_PHYSICAL|FTS_NOCHDIR| -#ifdef HAVE_STRUCT_STAT64 - FTS_NOSTAT, /* fts doesn't do stat64 */ -#else - (doRewind ? FTS_NOSTAT : 0), /* no need to stat for delete */ -#endif - NULL); + fts = fts_open((char **) paths, FTS_PHYSICAL | FTS_NOCHDIR | + (noFtsStat || doRewind ? FTS_NOSTAT : 0), NULL); if (fts == NULL) { errfile = source; goto end; @@ -1039,11 +1092,11 @@ TraverseUnixTree( while ((ent = fts_read(fts)) != NULL) { unsigned short info = ent->fts_info; - char * path = ent->fts_path + sourceLen; + char *path = ent->fts_path + sourceLen; unsigned short pathlen = ent->fts_pathlen - sourceLen; int type; Tcl_StatBuf *statBufPtr = NULL; - + if (info == FTS_DNR || info == FTS_ERR || info == FTS_NS) { errfile = ent->fts_path; break; @@ -1053,28 +1106,28 @@ TraverseUnixTree( Tcl_DStringAppend(targetPtr, path, pathlen); } switch (info) { - case FTS_D: - type = DOTREE_PRED; - break; - case FTS_DP: - type = DOTREE_POSTD; - break; - default: - type = DOTREE_F; - break; + case FTS_D: + type = DOTREE_PRED; + break; + case FTS_DP: + type = DOTREE_POSTD; + break; + default: + type = DOTREE_F; + break; } if (!doRewind) { /* no need to stat for delete */ -#ifdef HAVE_STRUCT_STAT64 - statBufPtr = &statBuf; - if (TclOSlstat(ent->fts_path, statBufPtr) != 0) { - errfile = ent->fts_path; - break; + if (noFtsStat) { + statBufPtr = &statBuf; + if (TclOSlstat(ent->fts_path, statBufPtr) != 0) { + errfile = ent->fts_path; + break; + } + } else { + statBufPtr = (Tcl_StatBuf *) ent->fts_statp; } -#else - statBufPtr = ent->fts_statp; -#endif } - result = (*traverseProc)(sourcePtr, targetPtr, statBufPtr, type, + result = traverseProc(sourcePtr, targetPtr, statBufPtr, type, errorPtr); if (result != TCL_OK) { break; @@ -1084,7 +1137,7 @@ TraverseUnixTree( Tcl_DStringSetLength(targetPtr, targetLen); } } -#endif /* HAVE_FTS */ +#endif /* !HAVE_FTS */ end: if (errfile != NULL) { @@ -1124,7 +1177,7 @@ static int TraversalCopy( Tcl_DString *srcPtr, /* Source pathname to copy (native). */ Tcl_DString *dstPtr, /* Destination pathname of copy (native). */ - CONST Tcl_StatBuf *statBufPtr, + const Tcl_StatBuf *statBufPtr, /* Stat info for file specified by srcPtr. */ int type, /* Reason for call - see TraverseUnixTree(). */ Tcl_DString *errorPtr) /* If non-NULL, uninitialized or free DString @@ -1188,7 +1241,7 @@ static int TraversalDelete( Tcl_DString *srcPtr, /* Source pathname (native). */ Tcl_DString *ignore, /* Destination pathname (not used). */ - CONST Tcl_StatBuf *statBufPtr, + const Tcl_StatBuf *statBufPtr, /* Stat info for file specified by srcPtr. */ int type, /* Reason for call - see TraverseUnixTree(). */ Tcl_DString *errorPtr) /* If non-NULL, uninitialized or free DString @@ -1236,9 +1289,9 @@ TraversalDelete( static int CopyFileAtts( - CONST char *src, /* Path name of source file (native). */ - CONST char *dst, /* Path name of target file (native). */ - CONST Tcl_StatBuf *statBufPtr) + 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 */ { struct utimbuf tval; @@ -1273,7 +1326,6 @@ CopyFileAtts( #endif return TCL_OK; } - /* *---------------------------------------------------------------------- @@ -1296,7 +1348,7 @@ static int GetGroupAttribute( 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 *fileName, /* The name of the file (UTF-8). */ Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */ { Tcl_StatBuf statBuf; @@ -1307,9 +1359,9 @@ GetGroupAttribute( if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not read \"", - TclGetString(fileName), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1320,13 +1372,12 @@ GetGroupAttribute( *attributePtrPtr = Tcl_NewIntObj((int) statBuf.st_gid); } else { Tcl_DString ds; - CONST char *utf; + const char *utf; utf = Tcl_ExternalToUtfDString(NULL, groupPtr->gr_name, -1, &ds); *attributePtrPtr = Tcl_NewStringObj(utf, -1); Tcl_DStringFree(&ds); } - endgrent(); return TCL_OK; } @@ -1351,7 +1402,7 @@ static int GetOwnerAttribute( 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 *fileName, /* The name of the file (UTF-8). */ Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */ { Tcl_StatBuf statBuf; @@ -1362,9 +1413,9 @@ GetOwnerAttribute( if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not read \"", - TclGetString(fileName), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1375,13 +1426,10 @@ GetOwnerAttribute( *attributePtrPtr = Tcl_NewIntObj((int) statBuf.st_uid); } else { Tcl_DString ds; - CONST char *utf; - utf = Tcl_ExternalToUtfDString(NULL, pwPtr->pw_name, -1, &ds); - *attributePtrPtr = Tcl_NewStringObj(utf, Tcl_DStringLength(&ds)); - Tcl_DStringFree(&ds); + (void) Tcl_ExternalToUtfDString(NULL, pwPtr->pw_name, -1, &ds); + *attributePtrPtr = TclDStringToObj(&ds); } - endpwent(); return TCL_OK; } @@ -1406,7 +1454,7 @@ static int GetPermissionsAttribute( 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 *fileName, /* The name of the file (UTF-8). */ Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */ { Tcl_StatBuf statBuf; @@ -1416,9 +1464,9 @@ GetPermissionsAttribute( if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not read \"", - TclGetString(fileName), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1453,12 +1501,12 @@ SetGroupAttribute( { long gid; int result; - CONST char *native; + const char *native; if (Tcl_GetLongFromObj(NULL, attributePtr, &gid) != TCL_OK) { Tcl_DString ds; struct group *groupPtr = NULL; - CONST char *string; + const char *string; int length; string = Tcl_GetStringFromObj(attributePtr, &length); @@ -1468,11 +1516,13 @@ SetGroupAttribute( Tcl_DStringFree(&ds); if (groupPtr == NULL) { - endgrent(); if (interp != NULL) { - Tcl_AppendResult(interp, "could not set group for file \"", - TclGetString(fileName), "\": group \"", string, - "\" does not exist", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not set group for file \"%s\":" + " group \"%s\" does not exist", + TclGetString(fileName), string)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SETGRP", + "NO_GROUP", NULL); } return TCL_ERROR; } @@ -1482,12 +1532,11 @@ SetGroupAttribute( native = Tcl_FSGetNativePath(fileName); result = chown(native, (uid_t) -1, (gid_t) gid); /* INTL: Native. */ - endgrent(); if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not set group for file \"", - TclGetString(fileName), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not set group for file \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1519,25 +1568,28 @@ SetOwnerAttribute( { long uid; int result; - CONST char *native; + const char *native; if (Tcl_GetLongFromObj(NULL, attributePtr, &uid) != TCL_OK) { Tcl_DString ds; struct passwd *pwPtr = NULL; - CONST char *string; + const char *string; int length; string = Tcl_GetStringFromObj(attributePtr, &length); native = Tcl_UtfToExternalDString(NULL, string, length, &ds); - pwPtr = TclpGetPwNam(native); /* INTL: Native. */ + pwPtr = TclpGetPwNam(native); /* INTL: Native. */ Tcl_DStringFree(&ds); if (pwPtr == NULL) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not set owner for file \"", - TclGetString(fileName), "\": user \"", string, - "\" does not exist", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not set owner for file \"%s\":" + " user \"%s\" does not exist", + TclGetString(fileName), string)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SETOWN", + "NO_USER", NULL); } return TCL_ERROR; } @@ -1545,13 +1597,13 @@ SetOwnerAttribute( } native = Tcl_FSGetNativePath(fileName); - result = chown(native, (uid_t) uid, (gid_t) -1); /* INTL: Native. */ + result = chown(native, (uid_t) uid, (gid_t) -1); /* INTL: Native. */ if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not set owner for file \"", - TclGetString(fileName), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not set owner for file \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1583,18 +1635,31 @@ SetPermissionsAttribute( { long mode; mode_t newMode; - int result; - CONST char *native; + int result = TCL_ERROR; + const char *native; + const char *modeStringPtr = TclGetString(attributePtr); + int scanned = TclParseAllWhiteSpace(modeStringPtr, -1); /* - * First try if the string is a number + * First supply support for octal number format */ - if (Tcl_GetLongFromObj(NULL, attributePtr, &mode) == TCL_OK) { + if ((modeStringPtr[scanned] == '0') + && (modeStringPtr[scanned+1] >= '0') + && (modeStringPtr[scanned+1] <= '7')) { + /* Leading zero - attempt octal interpretation */ + Tcl_Obj *modeObj; + + TclNewLiteralStringObj(modeObj, "0o"); + Tcl_AppendToObj(modeObj, modeStringPtr+scanned+1, -1); + result = Tcl_GetLongFromObj(NULL, modeObj, &mode); + Tcl_DecrRefCount(modeObj); + } + if (result == TCL_OK + || Tcl_GetLongFromObj(NULL, attributePtr, &mode) == TCL_OK) { newMode = (mode_t) (mode & 0x00007FFF); } else { Tcl_StatBuf buf; - char *modeStringPtr = TclGetString(attributePtr); /* * Try the forms "rwxrwxrwx" and "ugo=rwx" @@ -1606,9 +1671,9 @@ SetPermissionsAttribute( result = TclpObjStat(fileName, &buf); if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not read \"", - TclGetString(fileName), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1616,8 +1681,10 @@ SetPermissionsAttribute( if (GetModeFromPermString(NULL, modeStringPtr, &newMode) != TCL_OK) { if (interp != NULL) { - Tcl_AppendResult(interp, "unknown permission string format \"", - modeStringPtr, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown permission string format \"%s\"", + modeStringPtr)); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "PERMISSION", NULL); } return TCL_ERROR; } @@ -1627,9 +1694,9 @@ SetPermissionsAttribute( result = chmod(native, newMode); /* INTL: Native. */ if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not set permissions for file \"", - TclGetString(fileName), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not set permissions for file \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1656,7 +1723,8 @@ SetPermissionsAttribute( Tcl_Obj * TclpObjListVolumes(void) { - Tcl_Obj *resultPtr = Tcl_NewStringObj("/", 1); + Tcl_Obj *resultPtr; + TclNewLiteralStringObj(resultPtr, "/"); Tcl_IncrRefCount(resultPtr); return resultPtr; @@ -1684,7 +1752,7 @@ TclpObjListVolumes(void) static int GetModeFromPermString( Tcl_Interp *interp, /* The interp we are using for errors. */ - char *modeStringPtr, /* Permissions string */ + const char *modeStringPtr, /* Permissions string */ mode_t *modePtr) /* pointer to the mode value */ { mode_t newMode; @@ -1837,13 +1905,13 @@ GetModeFromPermString( } } switch (op) { - case 1 : + case 1: *modePtr = oldMode | (who & what); continue; - case 2 : + case 2: *modePtr = oldMode & ~(who & what); continue; - case 3 : + case 3: *modePtr = (oldMode & ~who) | (who & what); continue; } @@ -1877,14 +1945,14 @@ TclpObjNormalizePath( Tcl_Obj *pathPtr, int nextCheckpoint) { - char *currentPathEndPosition; + const char *currentPathEndPosition; int pathLen; char cur; - char *path = Tcl_GetStringFromObj(pathPtr, &pathLen); + const char *path = Tcl_GetStringFromObj(pathPtr, &pathLen); + Tcl_DString ds; + const char *nativePath; #ifndef NO_REALPATH char normPath[MAXPATHLEN]; - Tcl_DString ds; - CONST char *nativePath; #endif /* @@ -1936,8 +2004,6 @@ TclpObjNormalizePath( * Reached directory separator. */ - Tcl_DString ds; - CONST char *nativePath; int accessOk; nativePath = Tcl_UtfToExternalDString(NULL, path, @@ -1988,7 +2054,7 @@ TclpObjNormalizePath( return 0; } - nativePath = Tcl_UtfToExternalDString(NULL, path, nextCheckpoint, &ds); + nativePath = Tcl_UtfToExternalDString(NULL, path,nextCheckpoint, &ds); if (Realpath(nativePath, normPath) != NULL) { int newNormLen; @@ -2003,12 +2069,12 @@ TclpObjNormalizePath( Tcl_DStringFree(&ds); /* - * Enable this to have the native FS claim normalization of the - * whole path for existing files. That would permit the caller - * to declare normalization complete without calls to additional - * filesystems. Saving lots of calls is probably worth the extra - * access() time here. When no other FS's are registered though, - * things are less clear. + * Enable this to have the native FS claim normalization of + * the whole path for existing files. That would permit the + * caller to declare normalization complete without calls to + * additional filesystems. Saving lots of calls is probably + * worth the extra access() time here. When no other FS's are + * registered though, things are less clear. * if (0 == access(normPath, F_OK)) { return pathLen; @@ -2063,11 +2129,284 @@ TclpObjNormalizePath( return nextCheckpoint; } -#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) /* *---------------------------------------------------------------------- * - * GetReadOnlyAttribute + * TclpOpenTemporaryFile, TclUnixOpenTemporaryFile -- + * + * Creates a temporary file, possibly based on the supplied bits and + * pieces of template supplied in the first three arguments. If the + * fourth argument is non-NULL, it contains a Tcl_Obj to store the name + * of the temporary file in (and it is caller's responsibility to clean + * up). If the fourth argument is NULL, try to arrange for the temporary + * file to go away once it is no longer needed. + * + * Results: + * A read-write Tcl Channel open on the file for TclpOpenTemporaryFile, + * or a file descriptor (or -1 on failure) for TclUnixOpenTemporaryFile. + * + * Side effects: + * Accesses the filesystem. Will set the contents of the Tcl_Obj fourth + * argument (if that is non-NULL). + * + *---------------------------------------------------------------------- + */ + +Tcl_Channel +TclpOpenTemporaryFile( + Tcl_Obj *dirObj, + Tcl_Obj *basenameObj, + Tcl_Obj *extensionObj, + Tcl_Obj *resultingNameObj) +{ + int fd = TclUnixOpenTemporaryFile(dirObj, basenameObj, extensionObj, + resultingNameObj); + + if (fd == -1) { + return NULL; + } + return Tcl_MakeFileChannel(INT2PTR(fd), TCL_READABLE|TCL_WRITABLE); +} + +int +TclUnixOpenTemporaryFile( + Tcl_Obj *dirObj, + Tcl_Obj *basenameObj, + Tcl_Obj *extensionObj, + Tcl_Obj *resultingNameObj) +{ + Tcl_DString template, tmp; + const char *string; + int len, fd; + + /* + * We should also check against making more then TMP_MAX of these. + */ + + if (dirObj) { + string = Tcl_GetStringFromObj(dirObj, &len); + Tcl_UtfToExternalDString(NULL, string, len, &template); + } else { + Tcl_DStringInit(&template); + Tcl_DStringAppend(&template, DefaultTempDir(), -1); /* INTL: native */ + } + + TclDStringAppendLiteral(&template, "/"); + + if (basenameObj) { + string = Tcl_GetStringFromObj(basenameObj, &len); + Tcl_UtfToExternalDString(NULL, string, len, &tmp); + TclDStringAppendDString(&template, &tmp); + Tcl_DStringFree(&tmp); + } else { + TclDStringAppendLiteral(&template, "tcl"); + } + + TclDStringAppendLiteral(&template, "_XXXXXX"); + +#ifdef HAVE_MKSTEMPS + if (extensionObj) { + string = Tcl_GetStringFromObj(extensionObj, &len); + Tcl_UtfToExternalDString(NULL, string, len, &tmp); + TclDStringAppendDString(&template, &tmp); + fd = mkstemps(Tcl_DStringValue(&template), Tcl_DStringLength(&tmp)); + Tcl_DStringFree(&tmp); + } else +#endif + { + fd = mkstemp(Tcl_DStringValue(&template)); + } + + if (fd == -1) { + Tcl_DStringFree(&template); + return -1; + } + + if (resultingNameObj) { + Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&template), + Tcl_DStringLength(&template), &tmp); + Tcl_SetStringObj(resultingNameObj, Tcl_DStringValue(&tmp), + Tcl_DStringLength(&tmp)); + Tcl_DStringFree(&tmp); + } else { + /* + * Try to delete the file immediately since we're not reporting the + * name to anyone. Note that we're *not* handling any errors from + * this! + */ + + unlink(Tcl_DStringValue(&template)); + errno = 0; + } + Tcl_DStringFree(&template); + + return fd; +} + +/* + * Helper that does *part* of what tempnam() does. + */ + +static const char * +DefaultTempDir(void) +{ + const char *dir; + struct stat buf; + + dir = getenv("TMPDIR"); + if (dir && dir[0] && stat(dir, &buf) == 0 && S_ISDIR(buf.st_mode) + && access(dir, W_OK) == 0) { + return dir; + } + +#ifdef P_tmpdir + dir = P_tmpdir; + if (stat(dir, &buf)==0 && S_ISDIR(buf.st_mode) && access(dir, W_OK)==0) { + return dir; + } +#endif + + /* + * Assume that the default location ("/tmp" if not overridden) is always + * an existing writable directory; we've no recovery mechanism if it + * isn't. + */ + + return TCL_TEMPORARY_FILE_DIRECTORY; +} + +#if defined(__CYGWIN__) + +static void +StatError( + Tcl_Interp *interp, /* The interp that has the error */ + Tcl_Obj *fileName) /* The name of the file which caused the + * error. */ +{ + TclWinConvertError(GetLastError()); + Tcl_SetObjResult(interp, Tcl_ObjPrintf("could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); +} + +static WCHAR * +winPathFromObj( + Tcl_Obj *fileName) +{ + int size; + const char *native = Tcl_FSGetNativePath(fileName); + WCHAR *winPath; + + size = cygwin_conv_path(1, native, NULL, 0); + winPath = ckalloc(size); + cygwin_conv_path(1, native, winPath, size); + + return winPath; +} + +static const int attributeArray[] = { + 0x20, 0, 2, 0, 0, 1, 4}; + +/* + *---------------------------------------------------------------------- + * + * GetUnixFileAttributes + * + * Gets the readonly attribute of a file. + * + * Results: + * Standard TCL result. Returns a new Tcl_Obj in attributePtrPtr if there + * is no error. The object will have ref count 0. + * + * Side effects: + * A new object is allocated. + * + *---------------------------------------------------------------------- + */ + +static int +GetUnixFileAttributes( + 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. */ +{ + int fileAttributes; + WCHAR *winPath = winPathFromObj(fileName); + + fileAttributes = GetFileAttributesW(winPath); + ckfree(winPath); + + if (fileAttributes == -1) { + StatError(interp, fileName); + return TCL_ERROR; + } + + *attributePtrPtr = Tcl_NewIntObj((fileAttributes&attributeArray[objIndex])!=0); + + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * SetUnixFileAttributes + * + * Sets the readonly attribute of a file. + * + * Results: + * Standard TCL result. + * + * Side effects: + * The readonly attribute of the file is changed. + * + *--------------------------------------------------------------------------- + */ + +static int +SetUnixFileAttributes( + 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 *attributePtr) /* The attribute to set. */ +{ + int yesNo, fileAttributes, old; + WCHAR *winPath; + + if (Tcl_GetBooleanFromObj(interp, attributePtr, &yesNo) != TCL_OK) { + return TCL_ERROR; + } + + winPath = winPathFromObj(fileName); + + fileAttributes = old = GetFileAttributesW(winPath); + + if (fileAttributes == -1) { + ckfree(winPath); + StatError(interp, fileName); + return TCL_ERROR; + } + + if (yesNo) { + fileAttributes |= attributeArray[objIndex]; + } else { + fileAttributes &= ~attributeArray[objIndex]; + } + + if ((fileAttributes != old) + && !SetFileAttributesW(winPath, fileAttributes)) { + ckfree(winPath); + StatError(interp, fileName); + return TCL_ERROR; + } + + ckfree(winPath); + return TCL_OK; +} +#elif defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) +/* + *---------------------------------------------------------------------- + * + * GetUnixFileAttributes * * Gets the readonly attribute (user immutable flag) of a file. * @@ -2082,7 +2421,7 @@ TclpObjNormalizePath( */ static int -GetReadOnlyAttribute( +GetUnixFileAttributes( 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). */ @@ -2095,14 +2434,14 @@ GetReadOnlyAttribute( if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not read \"", - TclGetString(fileName), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } - *attributePtrPtr = Tcl_NewBooleanObj((statBuf.st_flags&UF_IMMUTABLE) != 0); + *attributePtrPtr = Tcl_NewBooleanObj(statBuf.st_flags&UF_IMMUTABLE); return TCL_OK; } @@ -2110,7 +2449,7 @@ GetReadOnlyAttribute( /* *--------------------------------------------------------------------------- * - * SetReadOnlyAttribute + * SetUnixFileAttributes * * Sets the readonly attribute (user immutable flag) of a file. * @@ -2124,16 +2463,15 @@ GetReadOnlyAttribute( */ static int -SetReadOnlyAttribute( +SetUnixFileAttributes( 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 *attributePtr) /* The attribute to set. */ { Tcl_StatBuf statBuf; - int result; - int readonly; - CONST char *native; + int result, readonly; + const char *native; if (Tcl_GetBooleanFromObj(interp, attributePtr, &readonly) != TCL_OK) { return TCL_ERROR; @@ -2143,9 +2481,9 @@ SetReadOnlyAttribute( if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not read \"", - TclGetString(fileName), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -2160,9 +2498,9 @@ SetReadOnlyAttribute( result = chflags(native, statBuf.st_flags); /* INTL: Native. */ if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not set flags for file \"", - TclGetString(fileName), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not set flags for file \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } |