diff options
Diffstat (limited to 'unix/tclUnixFCmd.c')
| -rw-r--r-- | unix/tclUnixFCmd.c | 419 | 
1 files changed, 306 insertions, 113 deletions
| diff --git a/unix/tclUnixFCmd.c b/unix/tclUnixFCmd.c index a1ed50f..3b1b6ca 100644 --- a/unix/tclUnixFCmd.c +++ b/unix/tclUnixFCmd.c @@ -10,8 +10,6 @@   * 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.74 2009/11/25 14:25:57 stwo Exp $ - *   * Portions of this code were derived from NetBSD source code which has the   * following copyright notice:   * @@ -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.   * @@ -53,7 +47,7 @@  #ifndef NO_FSTATFS  #include <sys/statfs.h>  #endif -#endif +#endif /* !HAVE_STRUCT_STAT_ST_BLKSIZE */  #ifdef HAVE_FTS  #include <fts.h>  #endif @@ -68,6 +62,16 @@  #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.   */ @@ -87,10 +91,10 @@ static int		SetPermissionsAttribute(Tcl_Interp *interp,  			    Tcl_Obj *attributePtr);  static int		GetModeFromPermString(Tcl_Interp *interp,  			    const char *modeStringPtr, mode_t *modePtr); -#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) -static int		GetReadOnlyAttribute(Tcl_Interp *interp, int objIndex, +#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 @@ -118,12 +122,22 @@ typedef int (TraversalProc)(Tcl_DString *srcPtr, Tcl_DString *dstPtr,  extern TclFileAttrProcs tclpFileAttrProcs[];  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, @@ -133,10 +147,20 @@ enum {  MODULE_SCOPE const char *const tclpFileAttrStrings[];  const char *const tclpFileAttrStrings[] = { -    "-group", "-owner", "-permissions", -#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) +#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 @@ -145,11 +169,20 @@ const char *const tclpFileAttrStrings[] = {  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,7 +191,7 @@ const TclFileAttrProcs tclpFileAttrProcs[] = {      {TclMacOSXGetFileAttribute,	TclMacOSXSetFileAttribute},  #endif  }; -#endif +#endif /* DJGPP */  /*   * This is the maximum number of consecutive readdir/unlink calls that can be @@ -189,11 +222,13 @@ static int		DoRemoveDirectory(Tcl_DString *pathPtr,  			    int recursive, Tcl_DString *errorPtr);  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); @@ -217,8 +252,8 @@ Realpath(      return realpath(path, resolved);  }  #else -#define Realpath realpath -#endif +#   define Realpath	realpath +#endif /* PURIFY */  #ifndef NO_REALPATH  #if defined(__APPLE__) && defined(TCL_THREADS) && \ @@ -231,16 +266,16 @@ 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 -#ifdef HAVE_STRUCT_STAT64 +#if defined(HAVE_STRUCT_STAT64) && !defined(__APPLE__)  /* fts doesn't do stat64 */ -#define noFtsStat 1 +#   define noFtsStat	1  #elif defined(__APPLE__) && defined(__LP64__) && \  	defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \  	MAC_OS_X_VERSION_MIN_REQUIRED < 1050 @@ -251,9 +286,9 @@ MODULE_SCOPE long tclMacOSXDarwinRelease;   */  MODULE_SCOPE long tclMacOSXDarwinRelease; -#define noFtsStat (tclMacOSXDarwinRelease < 9) +#   define noFtsStat	(tclMacOSXDarwinRelease < 9)  #else -#define noFtsStat 0 +#   define noFtsStat	0  #endif  #endif /* HAVE_FTS */ @@ -456,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 @@ -472,7 +508,7 @@ DoCopyFile(  #endif  	break;      } -#endif +#endif /* !DJGPP */      case S_IFBLK:      case S_IFCHR:  	if (mknod(dst, statBufPtr->st_mode,		/* INTL: Native. */ @@ -526,7 +562,7 @@ TclUnixCopyFile(  #define BINMODE |O_BINARY  #else  #define BINMODE -#endif +#endif /* DJGPP */  #define DEFAULT_COPY_BLOCK_SIZE 4069 @@ -553,7 +589,7 @@ TclUnixCopyFile(      {  	struct statfs fs; -	if (fstatfs(srcFd, &fs, sizeof(fs), 0) == 0) { +	if (fstatfs(srcFd, &fs) == 0) {  	    blockSize = fs.f_bsize;  	} else {  	    blockSize = DEFAULT_COPY_BLOCK_SIZE; @@ -635,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; @@ -970,11 +1006,11 @@ TraverseUnixTree(  	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);      } @@ -1042,7 +1078,7 @@ TraverseUnixTree(      }  #else /* HAVE_FTS */      paths[0] = source; -    fts = fts_open((char**)paths, FTS_PHYSICAL | FTS_NOCHDIR | +    fts = fts_open((char **) paths, FTS_PHYSICAL | FTS_NOCHDIR |  	    (noFtsStat || doRewind ? FTS_NOSTAT : 0), NULL);      if (fts == NULL) {  	errfile = source; @@ -1101,7 +1137,7 @@ TraverseUnixTree(  	    Tcl_DStringSetLength(targetPtr, targetLen);  	}      } -#endif /* HAVE_FTS */ +#endif /* !HAVE_FTS */    end:      if (errfile != NULL) { @@ -1323,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;      } @@ -1377,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;      } @@ -1390,11 +1426,9 @@ 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);      }      return TCL_OK;  } @@ -1430,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;      } @@ -1483,9 +1517,12 @@ SetGroupAttribute(  	if (groupPtr == NULL) {  	    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;  	} @@ -1497,9 +1534,9 @@ SetGroupAttribute(      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;      } @@ -1547,9 +1584,12 @@ SetOwnerAttribute(  	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;  	} @@ -1561,9 +1601,9 @@ SetOwnerAttribute(      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;      } @@ -1631,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;  	} @@ -1641,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;  	} @@ -1652,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;      } @@ -1907,10 +1949,10 @@ TclpObjNormalizePath(      int pathLen;      char cur;      const char *path = Tcl_GetStringFromObj(pathPtr, &pathLen); -#ifndef NO_REALPATH -    char normPath[MAXPATHLEN];      Tcl_DString ds;      const char *nativePath; +#ifndef NO_REALPATH +    char normPath[MAXPATHLEN];  #endif      /* @@ -1962,8 +2004,6 @@ TclpObjNormalizePath(  	     * Reached directory separator.  	     */ -	    Tcl_DString ds; -	    const char *nativePath;  	    int accessOk;  	    nativePath = Tcl_UtfToExternalDString(NULL, path, @@ -2014,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; @@ -2092,7 +2132,7 @@ TclpObjNormalizePath(  /*   *----------------------------------------------------------------------   * - * TclpOpenTemporaryFile -- + * TclpOpenTemporaryFile, TclUnixOpenTemporaryFile --   *   *	Creates a temporary file, possibly based on the supplied bits and   *	pieces of template supplied in the first three arguments. If the @@ -2102,7 +2142,12 @@ TclpObjNormalizePath(   *	file to go away once it is no longer needed.   *   * Results: - *	A read-write Tcl Channel open on the file. + *	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).   *   *----------------------------------------------------------------------   */ @@ -2114,11 +2159,30 @@ TclpOpenTemporaryFile(      Tcl_Obj *extensionObj,      Tcl_Obj *resultingNameObj)  { -    Tcl_Channel chan; +    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); @@ -2127,24 +2191,24 @@ TclpOpenTemporaryFile(  	Tcl_DStringAppend(&template, DefaultTempDir(), -1); /* INTL: native */      } -    Tcl_DStringAppend(&template, "/", -1); +    TclDStringAppendLiteral(&template, "/");      if (basenameObj) {  	string = Tcl_GetStringFromObj(basenameObj, &len);  	Tcl_UtfToExternalDString(NULL, string, len, &tmp); -	Tcl_DStringAppend(&template, Tcl_DStringValue(&tmp), -1); +	TclDStringAppendDString(&template, &tmp);  	Tcl_DStringFree(&tmp);      } else { -	Tcl_DStringAppend(&template, "tcl", -1); +	TclDStringAppendLiteral(&template, "tcl");      } -    Tcl_DStringAppend(&template, "_XXXXXX", -1); +    TclDStringAppendLiteral(&template, "_XXXXXX");  #ifdef HAVE_MKSTEMPS      if (extensionObj) {  	string = Tcl_GetStringFromObj(extensionObj, &len);  	Tcl_UtfToExternalDString(NULL, string, len, &tmp); -	Tcl_DStringAppend(&template, Tcl_DStringValue(&tmp), -1); +	TclDStringAppendDString(&template, &tmp);  	fd = mkstemps(Tcl_DStringValue(&template), Tcl_DStringLength(&tmp));  	Tcl_DStringFree(&tmp);      } else @@ -2154,9 +2218,10 @@ TclpOpenTemporaryFile(      }      if (fd == -1) { -	return NULL; +	Tcl_DStringFree(&template); +	return -1;      } -    chan = Tcl_MakeFileChannel(INT2PTR(fd), TCL_READABLE|TCL_WRITABLE); +      if (resultingNameObj) {  	Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&template),  		Tcl_DStringLength(&template), &tmp); @@ -2175,7 +2240,7 @@ TclpOpenTemporaryFile(      }      Tcl_DStringFree(&template); -    return chan; +    return fd;  }  /* @@ -2190,30 +2255,158 @@ DefaultTempDir(void)      dir = getenv("TMPDIR");      if (dir && dir[0] && stat(dir, &buf) == 0 && S_ISDIR(buf.st_mode) -	    && access(dir, W_OK)) { +	    && 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)) { +    if (stat(dir, &buf)==0 && S_ISDIR(buf.st_mode) && access(dir, W_OK)==0) {  	return dir;      }  #endif      /* -     * Assume that "/tmp" is always an existing writable directory; we've no -     * recovery mechanism if it isn't. +     * 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 "/tmp"; +    return TCL_TEMPORARY_FILE_DIRECTORY;  } -#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) +#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)  /*   *----------------------------------------------------------------------   * - * GetReadOnlyAttribute + * GetUnixFileAttributes   *   *	Gets the readonly attribute (user immutable flag) of a file.   * @@ -2228,7 +2421,7 @@ DefaultTempDir(void)   */  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). */ @@ -2241,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;  } @@ -2256,7 +2449,7 @@ GetReadOnlyAttribute(  /*   *---------------------------------------------------------------------------   * - * SetReadOnlyAttribute + * SetUnixFileAttributes   *   *	Sets the readonly attribute (user immutable flag) of a file.   * @@ -2270,7 +2463,7 @@ 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). */ @@ -2288,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;      } @@ -2305,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;      } | 
