diff options
Diffstat (limited to 'unix/tclUnixFCmd.c')
| -rw-r--r-- | unix/tclUnixFCmd.c | 349 | 
1 files changed, 271 insertions, 78 deletions
| diff --git a/unix/tclUnixFCmd.c b/unix/tclUnixFCmd.c index e3d9022..3b1b6ca 100644 --- a/unix/tclUnixFCmd.c +++ b/unix/tclUnixFCmd.c @@ -62,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.   */ @@ -81,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 @@ -114,10 +124,20 @@ extern const char *const tclpFileAttrStrings[];  #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, @@ -127,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 @@ -139,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}, @@ -234,7 +273,7 @@ MODULE_SCOPE long tclMacOSXDarwinRelease;  #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  #elif defined(__APPLE__) && defined(__LP64__) && \ @@ -452,10 +491,10 @@ DoCopyFile(      switch ((int) (statBufPtr->st_mode & S_IFMT)) {  #ifndef DJGPP      case S_IFLNK: { -	char linkBuf[MAXPATHLEN]; +	char linkBuf[MAXPATHLEN+1];  	int length; -	length = readlink(src, linkBuf, sizeof(linkBuf)); +	length = readlink(src, linkBuf, MAXPATHLEN);  							/* INTL: Native. */  	if (length == -1) {  	    return TCL_ERROR; @@ -967,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);      } @@ -1320,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;      } @@ -1374,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;      } @@ -1387,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;  } @@ -1427,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;      } @@ -1480,9 +1517,10 @@ 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);  	    } @@ -1496,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;      } @@ -1546,9 +1584,10 @@ 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);  	    } @@ -1562,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;      } @@ -1632,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;  	} @@ -1642,8 +1681,9 @@ 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; @@ -1654,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;      } @@ -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;      } | 
