diff options
Diffstat (limited to 'win/tclWinFCmd.c')
-rw-r--r-- | win/tclWinFCmd.c | 209 |
1 files changed, 167 insertions, 42 deletions
diff --git a/win/tclWinFCmd.c b/win/tclWinFCmd.c index 86fea7e..ad4bae1 100644 --- a/win/tclWinFCmd.c +++ b/win/tclWinFCmd.c @@ -145,8 +145,8 @@ TclpObjRenameFile( Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr) { - return DoRenameFile(Tcl_FSGetNativePath(srcPathPtr), - Tcl_FSGetNativePath(destPathPtr)); + return DoRenameFile((const WCHAR *)Tcl_FSGetNativePath(srcPathPtr), + (const WCHAR *)Tcl_FSGetNativePath(destPathPtr)); } static int @@ -163,7 +163,7 @@ DoRenameFile( int retval = -1; /* - * The MoveFileW API acts differently under Win95/98 and NT WRT NULL and + * The MoveFile API acts differently under Win95/98 and NT WRT NULL and * "". Avoid passing these values. */ @@ -174,7 +174,7 @@ DoRenameFile( } /* - * The MoveFileW API would throw an exception under NT if one of the + * The MoveFile API would throw an exception under NT if one of the * arguments is a char block device. */ @@ -195,7 +195,7 @@ DoRenameFile( /* * Construct an TCLEXCEPTION_REGISTRATION to protect the call to - * MoveFileW. + * MoveFile. */ "leal %[registration], %%edx" "\n\t" @@ -224,7 +224,7 @@ DoRenameFile( /* * Come here on normal exit. Recover the TCLEXCEPTION_REGISTRATION and - * put the status return from MoveFileW into it. + * put the status return from MoveFile into it. */ "movl %%fs:0, %%edx" "\n\t" @@ -328,8 +328,10 @@ DoRenameFile( CharLowerW(nativeSrcPath); CharLowerW(nativeDstPath); - src = Tcl_WinTCharToUtf((TCHAR *)nativeSrcPath, -1, &srcString); - dst = Tcl_WinTCharToUtf((TCHAR *)nativeDstPath, -1, &dstString); + Tcl_DStringInit(&srcString); + Tcl_DStringInit(&dstString); + src = Tcl_WCharToUtfDString(nativeSrcPath, -1, &srcString); + dst = Tcl_WCharToUtfDString(nativeDstPath, -1, &dstString); /* * Check whether the destination path is actually inside the @@ -369,7 +371,7 @@ DoRenameFile( * errno should be EXDEV. It is very important to get this * behavior, so that the caller can respond to a cross * filesystem rename by simulating it with copy and delete. - * The MoveFileW system call already handles the case of moving + * The MoveFile system call already handles the case of moving * a file between filesystems. */ @@ -455,15 +457,15 @@ DoRenameFile( return TCL_ERROR; } nativeTmp = (WCHAR *) tempBuf; - nativeRest[0] = L'\0'; + nativeRest[0] = '\0'; result = TCL_ERROR; - nativePrefix = (WCHAR *) L"tclr"; + nativePrefix = (WCHAR *)L"tclr"; if (GetTempFileNameW(nativeTmp, nativePrefix, 0, tempBuf) != 0) { /* * Strictly speaking, need the following DeleteFile and - * MoveFileW to be joined as an atomic operation so no + * MoveFile to be joined as an atomic operation so no * other app comes along in the meantime and creates the * same temp file. */ @@ -534,8 +536,8 @@ TclpObjCopyFile( Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr) { - return DoCopyFile(Tcl_FSGetNativePath(srcPathPtr), - Tcl_FSGetNativePath(destPathPtr)); + return DoCopyFile((const WCHAR *)Tcl_FSGetNativePath(srcPathPtr), + (const WCHAR *)Tcl_FSGetNativePath(destPathPtr)); } static int @@ -749,7 +751,7 @@ TclpDeleteFile( const void *nativePath) /* Pathname of file to be removed (native). */ { DWORD attr; - const WCHAR *path = nativePath; + const WCHAR *path = (const WCHAR *)nativePath; /* * The DeleteFile API acts differently under Win95/98 and NT WRT NULL and @@ -854,7 +856,7 @@ int TclpObjCreateDirectory( Tcl_Obj *pathPtr) { - return DoCreateDirectory(Tcl_FSGetNativePath(pathPtr)); + return DoCreateDirectory((const WCHAR *)Tcl_FSGetNativePath(pathPtr)); } static int @@ -911,8 +913,10 @@ TclpObjCopyDirectory( return TCL_ERROR; } - Tcl_WinUtfToTChar(Tcl_GetString(normSrcPtr), -1, &srcString); - Tcl_WinUtfToTChar(Tcl_GetString(normDestPtr), -1, &dstString); + Tcl_DStringInit(&srcString); + Tcl_DStringInit(&dstString); + Tcl_UtfToWCharDString(Tcl_GetString(normSrcPtr), -1, &srcString); + Tcl_UtfToWCharDString(Tcl_GetString(normDestPtr), -1, &dstString); ret = TraverseWinTree(TraversalCopy, &srcString, &dstString, &ds); @@ -984,11 +988,12 @@ TclpObjRemoveDirectory( if (normPtr == NULL) { return TCL_ERROR; } - Tcl_WinUtfToTChar(Tcl_GetString(normPtr), -1, &native); + Tcl_DStringInit(&native); + Tcl_UtfToWCharDString(Tcl_GetString(normPtr), -1, &native); ret = DoRemoveDirectory(&native, recursive, &ds); Tcl_DStringFree(&native); } else { - ret = DoRemoveJustDirectory(Tcl_FSGetNativePath(pathPtr), 0, &ds); + ret = DoRemoveJustDirectory((const WCHAR *)Tcl_FSGetNativePath(pathPtr), 0, &ds); } if (ret != TCL_OK) { @@ -1109,7 +1114,10 @@ DoRemoveJustDirectory( end: if (errorPtr != NULL) { - char *p = Tcl_WinTCharToUtf((TCHAR *)nativePath, -1, errorPtr); + char *p; + + Tcl_DStringInit(errorPtr); + p = Tcl_WCharToUtfDString(nativePath, -1, errorPtr); for (; *p; ++p) { if (*p == '\\') *p = '/'; } @@ -1187,7 +1195,7 @@ TraverseWinTree( nativeErrfile = NULL; result = TCL_OK; - oldTargetLen = 0; /* lint. */ + oldTargetLen = 0; nativeSource = (WCHAR *) Tcl_DStringValue(sourcePtr); nativeTarget = (WCHAR *) @@ -1256,7 +1264,7 @@ TraverseWinTree( found = 1; for (; found; found = FindNextFileW(handle, &data)) { WCHAR *nativeName; - size_t len; + int len; WCHAR *wp = data.cFileName; if (*wp == '.') { @@ -1323,7 +1331,8 @@ TraverseWinTree( if (nativeErrfile != NULL) { TclWinConvertError(GetLastError()); if (errorPtr != NULL) { - Tcl_WinTCharToUtf((TCHAR *)nativeErrfile, -1, errorPtr); + Tcl_DStringInit(errorPtr); + Tcl_WCharToUtfDString(nativeErrfile, -1, errorPtr); } result = TCL_ERROR; } @@ -1388,7 +1397,8 @@ TraversalCopy( */ if (errorPtr != NULL) { - Tcl_WinTCharToUtf((TCHAR *)nativeDst, -1, errorPtr); + Tcl_DStringInit(errorPtr); + Tcl_WCharToUtfDString(nativeDst, -1, errorPtr); } return TCL_ERROR; } @@ -1417,7 +1427,7 @@ TraversalCopy( static int TraversalDelete( const WCHAR *nativeSrc, /* Source pathname to delete. */ - const WCHAR *dstPtr, /* Not used. */ + TCL_UNUSED(const WCHAR *) /*dstPtr*/, int type, /* Reason for call - see TraverseWinTree() */ Tcl_DString *errorPtr) /* If non-NULL, initialized DString filled * with UTF-8 name of file causing error. */ @@ -1443,7 +1453,8 @@ TraversalDelete( } if (errorPtr != NULL) { - Tcl_WinTCharToUtf((TCHAR *)nativeSrc, -1, errorPtr); + Tcl_DStringInit(errorPtr); + Tcl_WCharToUtfDString(nativeSrc, -1, errorPtr); } return TCL_ERROR; } @@ -1506,7 +1517,7 @@ GetWinFileAttributes( const WCHAR *nativeName; int attr; - nativeName = Tcl_FSGetNativePath(fileName); + nativeName = (const WCHAR *)Tcl_FSGetNativePath(fileName); result = GetFileAttributesW(nativeName); if (result == 0xFFFFFFFF) { @@ -1525,7 +1536,7 @@ GetWinFileAttributes( */ int len; - const char *str = Tcl_GetStringFromObj(fileName,&len); + const char *str = TclGetStringFromObj(fileName, &len); if (len < 4) { if (len == 0) { @@ -1549,7 +1560,7 @@ GetWinFileAttributes( } } - *attributePtrPtr = Tcl_NewBooleanObj(attr); + TclNewIntObj(*attributePtrPtr, attr != 0); return TCL_OK; } @@ -1579,7 +1590,7 @@ GetWinFileAttributes( static int ConvertFileNameFormat( Tcl_Interp *interp, /* The interp we are using for errors. */ - int objIndex, /* The index of the attribute. */ + TCL_UNUSED(int) /*objIndex*/, Tcl_Obj *fileName, /* The name of the file. */ int longShort, /* 0 to short name, 1 to long name. */ Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */ @@ -1610,12 +1621,12 @@ ConvertFileNameFormat( for (i = 0; i < pathc; i++) { Tcl_Obj *elt; char *pathv; - int pathLen; + int length; Tcl_ListObjIndex(NULL, splitPath, i, &elt); - pathv = Tcl_GetStringFromObj(elt, &pathLen); - if ((pathv[0] == '/') || ((pathLen == 3) && (pathv[1] == ':')) + pathv = TclGetStringFromObj(elt, &length); + if ((pathv[0] == '/') || ((length == 3) && (pathv[1] == ':')) || (strcmp(pathv, ".") == 0) || (strcmp(pathv, "..") == 0)) { /* * Handle "/", "//machine/export", "c:/", "." or ".." by just @@ -1638,7 +1649,6 @@ ConvertFileNameFormat( Tcl_DString dsTemp; const WCHAR *nativeName; const char *tempString; - int tempLen; WIN32_FIND_DATAW data; HANDLE handle; DWORD attr; @@ -1651,9 +1661,9 @@ ConvertFileNameFormat( * likely to lead to infinite loops. */ + tempString = TclGetStringFromObj(tempPath, &length); Tcl_DStringInit(&ds); - tempString = Tcl_GetStringFromObj(tempPath,&tempLen); - nativeName = (WCHAR *)Tcl_WinUtfToTChar(tempString, tempLen, &ds); + nativeName = Tcl_UtfToWCharDString(tempString, length, &ds); Tcl_DecrRefCount(tempPath); handle = FindFirstFileW(nativeName, &data); if (handle == INVALID_HANDLE_VALUE) { @@ -1690,7 +1700,7 @@ ConvertFileNameFormat( } /* - * Purify reports a extraneous UMR in Tcl_WinTCharToUtf() trying + * Purify reports a extraneous UMR in Tcl_WCharToUtfDString() trying * to dereference nativeName as a Unicode string. I have proven to * myself that purify is wrong by running the following example * when nativeName == data.w.cAlternateFileName and noting that @@ -1702,7 +1712,7 @@ ConvertFileNameFormat( */ Tcl_DStringInit(&dsTemp); - Tcl_WinTCharToUtf((TCHAR *)nativeName, -1, &dsTemp); + Tcl_WCharToUtfDString(nativeName, -1, &dsTemp); Tcl_DStringFree(&ds); /* @@ -1833,7 +1843,7 @@ SetWinFileAttributes( int yesNo, result; const WCHAR *nativeName; - nativeName = Tcl_FSGetNativePath(fileName); + nativeName = (const WCHAR *)Tcl_FSGetNativePath(fileName); fileAttributes = old = GetFileAttributesW(nativeName); if (fileAttributes == 0xFFFFFFFF) { @@ -1882,7 +1892,7 @@ CannotSetAttribute( 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. */ - Tcl_Obj *attributePtr) /* The new value of the attribute. */ + TCL_UNUSED(Tcl_Obj *) /*attributePtr*/) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "cannot set attribute \"%s\" for file \"%s\": attribute is readonly", @@ -1926,7 +1936,7 @@ TclpObjListVolumes(void) if (GetLogicalDriveStringsA(sizeof(buf), buf) == 0) { /* - * GetVolumeInformationW() will detect all drives, but causes + * GetVolumeInformationW() will detects all drives, but causes * chattering on empty floppy drives. We only do this if * GetLogicalDriveStrings() didn't work. It has also been reported * that on some laptops it takes a while for GetVolumeInformationW() to @@ -1959,6 +1969,121 @@ TclpObjListVolumes(void) } /* + *---------------------------------------------------------------------- + * + * TclpCreateTemporaryDirectory -- + * + * Creates a temporary directory, possibly based on the supplied bits and + * pieces of template supplied in the arguments. + * + * Results: + * An object (refcount 0) containing the name of the newly-created + * directory, or NULL on failure. + * + * Side effects: + * Accesses the native filesystem. Makes a directory. + * + *---------------------------------------------------------------------- + */ + +Tcl_Obj * +TclpCreateTemporaryDirectory( + Tcl_Obj *dirObj, + Tcl_Obj *basenameObj) +{ + Tcl_DString base, name; /* Contains WCHARs */ + int baseLen; + DWORD error; + WCHAR tempBuf[MAX_PATH + 1]; + DWORD len = GetTempPathW(MAX_PATH, tempBuf); + + /* + * Build the path in writable memory from the user-supplied pieces and + * some defaults. First, the parent temporary directory. + */ + + if (dirObj) { + Tcl_GetString(dirObj); + if (dirObj->length < 1) { + goto useSystemTemp; + } + Tcl_DStringInit(&base); + Tcl_UtfToWCharDString(Tcl_GetString(dirObj), -1, &base); + if (dirObj->bytes[dirObj->length - 1] != '\\') { + Tcl_UtfToWCharDString("\\", -1, &base); + } + } else { + useSystemTemp: + Tcl_DStringInit(&base); + Tcl_DStringAppend(&base, (char *) tempBuf, len * sizeof(WCHAR)); + } + + /* + * Next, the base of the directory name. + */ + +#define DEFAULT_TEMP_DIR_PREFIX "tcl" +#define SUFFIX_LENGTH 8 + + if (basenameObj) { + Tcl_UtfToWCharDString(Tcl_GetString(basenameObj), -1, &base); + } else { + Tcl_UtfToWCharDString(DEFAULT_TEMP_DIR_PREFIX, -1, &base); + } + Tcl_UtfToWCharDString("_", -1, &base); + + /* + * Now we keep on trying random suffixes until we get one that works + * (i.e., that doesn't trigger the ERROR_ALREADY_EXISTS error). Note that + * SUFFIX_LENGTH is longer than on Unix because we expect to be not on a + * case-sensitive filesystem. + */ + + baseLen = Tcl_DStringLength(&base); + do { + char tempbuf[SUFFIX_LENGTH + 1]; + int i; + static const char randChars[] = + "QWERTYUIOPASDFGHJKLZXCVBNM1234567890"; + static const int numRandChars = sizeof(randChars) - 1; + + /* + * Put a random suffix on the end. + */ + + error = ERROR_SUCCESS; + tempbuf[SUFFIX_LENGTH] = '\0'; + for (i = 0 ; i < SUFFIX_LENGTH; i++) { + tempbuf[i] = randChars[(int) (rand() % numRandChars)]; + } + Tcl_DStringSetLength(&base, baseLen); + Tcl_UtfToWCharDString(tempbuf, -1, &base); + } while (!CreateDirectoryW((LPCWSTR) Tcl_DStringValue(&base), NULL) + && (error = GetLastError()) == ERROR_ALREADY_EXISTS); + + /* + * Check for other errors. The big ones are ERROR_PATH_NOT_FOUND and + * ERROR_ACCESS_DENIED. + */ + + if (error != ERROR_SUCCESS) { + TclWinConvertError(error); + Tcl_DStringFree(&base); + return NULL; + } + + /* + * We actually made the directory, so we're done! Report what we made back + * as a (clean) Tcl_Obj. + */ + + Tcl_DStringInit(&name); + Tcl_WCharToUtfDString((LPCWSTR) Tcl_DStringValue(&base), -1, &name); + Tcl_DStringFree(&base); + return TclDStringToObj(&name); +} + +/* * Local Variables: * mode: c * c-basic-offset: 4 |