diff options
Diffstat (limited to 'win/tclWinFCmd.c')
-rw-r--r-- | win/tclWinFCmd.c | 311 |
1 files changed, 26 insertions, 285 deletions
diff --git a/win/tclWinFCmd.c b/win/tclWinFCmd.c index 098a409..35c241f 100644 --- a/win/tclWinFCmd.c +++ b/win/tclWinFCmd.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclWinFCmd.c,v 1.29 2002/04/22 22:51:19 hobbs Exp $ + * RCS: @(#) $Id: tclWinFCmd.c,v 1.30 2002/06/12 09:28:58 vincentdarley Exp $ */ #include "tclWinInt.h" @@ -90,7 +90,7 @@ typedef int (TraversalProc)(CONST TCHAR *srcPtr, CONST TCHAR *dstPtr, */ static void StatError(Tcl_Interp *interp, Tcl_Obj *fileName); -static int ConvertFileNameFormat(Tcl_Interp *interp, +int ConvertFileNameFormat(Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, int longShort, Tcl_Obj **attributePtrPtr); static int DoCopyFile(CONST TCHAR *srcPtr, CONST TCHAR *dstPtr); @@ -566,6 +566,12 @@ DoCopyFile( } if ((srcAttr & FILE_ATTRIBUTE_DIRECTORY) || (dstAttr & FILE_ATTRIBUTE_DIRECTORY)) { + if (srcAttr & FILE_ATTRIBUTE_REPARSE_POINT) { + /* Source is a symbolic link -- copy it */ + if (TclWinSymLinkCopyDirectory(nativeSrc, nativeDst) == 0) { + return TCL_OK; + } + } Tcl_SetErrno(EISDIR); } if (dstAttr & FILE_ATTRIBUTE_READONLY) { @@ -659,7 +665,16 @@ DoDeleteFile( attr = (*tclWinProcs->getFileAttributesProc)(nativePath); if (attr != 0xffffffff) { if (attr & FILE_ATTRIBUTE_DIRECTORY) { - /* + if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { + /* It is a symbolic link -- remove it */ + if (TclWinSymLinkDelete(nativePath, 0) == 0) { + return TCL_OK; + } + } + + /* + * If we fall through here, it is a directory. + * * Windows NT reports removing a directory as EACCES instead * of EISDIR. */ @@ -903,6 +918,13 @@ DoRemoveJustDirectory( goto end; } + if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { + /* It is a symbolic link -- remove it */ + if (TclWinSymLinkDelete(nativePath, 1) != 0) { + goto end; + } + } + if (attr & FILE_ATTRIBUTE_READONLY) { attr &= ~FILE_ATTRIBUTE_READONLY; if ((*tclWinProcs->setFileAttributesProc)(nativePath, attr) == FALSE) { @@ -1444,7 +1466,7 @@ GetWinFileAttributes( *---------------------------------------------------------------------- */ -static int +int ConvertFileNameFormat( Tcl_Interp *interp, /* The interp we are using for errors. */ int objIndex, /* The index of the attribute. */ @@ -1812,284 +1834,3 @@ TclpObjListVolumes(void) Tcl_IncrRefCount(resultPtr); return resultPtr; } - -/* - * This function could be thoroughly tested and then substituted in - * below to speed up file normalization on Windows NT/2000/XP - */ -#if 0 - -void WinGetLongPathName(CONST TCHAR* origPath, Tcl_DString *dsPtr); - -#define IsDirSep(a) (a == '/' || a == '\\') - -void WinGetLongPathName(CONST TCHAR* pszOriginal, Tcl_DString *dsPtr) { - TCHAR szResult[_MAX_PATH * 2 + 1]; - - TCHAR* pchResult = szResult; - const TCHAR* pchScan = pszOriginal; - WIN32_FIND_DATA wfd; - - /* Do Drive Letter check... */ - if (pchScan[0] && pchScan[1] == ':') { - /* Copy drive letter and colon, ensuring drive is upper case. */ - char drive = *pchScan++; - *pchResult++ = (drive < 97 ? drive : drive - 32); - *pchResult++ = *pchScan++; - } else if (IsDirSep(pchScan[0]) && IsDirSep(pchScan[1])) { - /* Copy \\ and machine name. */ - *pchResult++ = *pchScan++; - *pchResult++ = *pchScan++; - while (*pchScan && !IsDirSep(*pchScan)) { - *pchResult++ = *pchScan++; - } - /* - * Note that the code below will fail since FindFirstFile - * on a UNC path seems not to work on directory name searches? - */ - } - - if (!IsDirSep(*pchScan)) { - while ((*pchResult++ = *pchScan++) != '\0'); - } else { - /* Now loop through directories and files... */ - while (IsDirSep(*pchScan)) { - char* pchReplace; - const TCHAR* pchEnd; - HANDLE hFind; - - *pchResult++ = *pchScan++; - pchReplace = pchResult; - - pchEnd = pchScan; - while (*pchEnd && !IsDirSep(*pchEnd)) { - *pchResult++ = *pchEnd++; - } - - *pchResult = '\0'; - - /* Now run this through FindFirstFile... */ - hFind = FindFirstFileA(szResult, &wfd); - if (hFind != INVALID_HANDLE_VALUE) { - FindClose(hFind); - strcpy(pchReplace, wfd.cFileName); - pchResult = pchReplace + strlen(pchReplace); - } else { - /* Copy rest of input path & end. */ - strcat(pchResult, pchEnd); - break; - } - pchScan = pchEnd; - } - } - /* Copy it over */ - Tcl_ExternalToUtfDString(NULL, szResult, -1, dsPtr); -} - -#endif - - -/* - *--------------------------------------------------------------------------- - * - * TclpObjNormalizePath -- - * - * This function scans through a path specification and replaces - * it, in place, with a normalized version. On windows this - * means using the 'longname'. - * - * Results: - * The new 'nextCheckpoint' value, giving as far as we could - * understand in the path. - * - * Side effects: - * The pathPtr string, which must contain a valid path, is - * possibly modified in place. - * - *--------------------------------------------------------------------------- - */ - -int -TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) - Tcl_Interp *interp; - Tcl_Obj *pathPtr; - int nextCheckpoint; -{ - char *lastValidPathEnd = NULL; - Tcl_DString ds; - int pathLen; - - char *path = Tcl_GetStringFromObj(pathPtr, &pathLen); - - if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_WINDOWS) { - Tcl_DString eDs; - char *nativePath; - int nativeLen; - - Tcl_UtfToExternalDString(NULL, path, -1, &ds); - nativePath = Tcl_DStringValue(&ds); - nativeLen = Tcl_DStringLength(&ds); - - /* We're on Windows 95/98 */ - lastValidPathEnd = nativePath + Tcl_DStringLength(&ds); - - while (1) { - DWORD res = GetShortPathNameA(nativePath, nativePath, 1+nativeLen); - if (res != 0) { - /* We found an ok path */ - break; - } - /* Undo the null-termination we put in before */ - if (lastValidPathEnd != (nativePath + nativeLen)) { - *lastValidPathEnd = '/'; - } - /* - * The path doesn't exist. Back up the path, one component - * (directory/file) at a time, until one does exist. - */ - while (1) { - char cur; - lastValidPathEnd--; - if (lastValidPathEnd == nativePath) { - /* We didn't accept any of the path */ - Tcl_DStringFree(&ds); - return nextCheckpoint; - } - cur = *(lastValidPathEnd); - if (cur == '/' || cur == '\\') { - /* Reached directory separator */ - break; - } - } - /* Temporarily terminate the string */ - *lastValidPathEnd = '\0'; - } - /* - * If we get here, we found a valid path, which we've converted to - * short form, and the valid string ends at or before 'lastValidPathEnd' - * and the invalid string starts at 'lastValidPathEnd'. - */ - - /* Copy over the valid part of the path and find its length */ - Tcl_ExternalToUtfDString(NULL, nativePath, -1, &eDs); - path = Tcl_DStringValue(&eDs); - if (path[1] == ':') { - if (path[0] >= 'a' && path[0] <= 'z') { - /* Make uppercase */ - path[0] -= 32; - } - } - nextCheckpoint = Tcl_DStringLength(&eDs); - Tcl_SetStringObj(pathPtr, path, Tcl_DStringLength(&eDs)); - Tcl_DStringFree(&eDs); - if (lastValidPathEnd != (nativePath + nativeLen)) { - CONST char *tmp; - *lastValidPathEnd = '/'; - /* Now copy over the invalid (i.e. non-existent) part of the path */ - tmp = Tcl_ExternalToUtfDString(NULL, lastValidPathEnd, -1, &eDs); - Tcl_AppendToObj(pathPtr, tmp, Tcl_DStringLength(&eDs)); - Tcl_DStringFree(&eDs); - } - Tcl_DStringFree(&ds); - } else { - /* We're on WinNT or 2000 or XP */ - CONST char *nativePath; -#if 0 - /* - * We don't use this simpler version, because the speed - * increase does not seem significant at present and the version - * below is thoroughly debugged. - */ - int nativeLen; - Tcl_DString eDs; - nativePath = Tcl_UtfToExternalDString(NULL, path, -1, &ds); - nativeLen = Tcl_DStringLength(&ds); - WinGetLongPathName(nativePath, &eDs); - /* - * We need to add code here to calculate the new value of - * 'nextCheckpoint' -- i.e. the longest part of the path - * which is an existing file. - */ - Tcl_SetStringObj(pathPtr, Tcl_DStringValue(&eDs), Tcl_DStringLength(&eDs)); - Tcl_DStringFree(&eDs); - Tcl_DStringFree(&ds); -#else - char *currentPathEndPosition; - WIN32_FILE_ATTRIBUTE_DATA data; - nativePath = Tcl_WinUtfToTChar(path, -1, &ds); - - if ((*tclWinProcs->getFileAttributesExProc)(nativePath, - GetFileExInfoStandard, - &data) == TRUE) { - currentPathEndPosition = path + pathLen; - nextCheckpoint = pathLen; - lastValidPathEnd = currentPathEndPosition; - Tcl_DStringFree(&ds); - } else { - Tcl_DStringFree(&ds); - currentPathEndPosition = path + nextCheckpoint; - while (1) { - char cur = *currentPathEndPosition; - if ((cur == '/' || cur == 0) && (path != currentPathEndPosition)) { - /* Reached directory separator, or end of string */ - nativePath = Tcl_WinUtfToTChar(path, currentPathEndPosition - path, - &ds); - if ((*tclWinProcs->getFileAttributesExProc)(nativePath, - GetFileExInfoStandard, &data) != TRUE) { - /* File doesn't exist */ - Tcl_DStringFree(&ds); - break; - } - Tcl_DStringFree(&ds); - - lastValidPathEnd = currentPathEndPosition; - /* File does exist */ - if (cur == 0) { - break; - } - } - currentPathEndPosition++; - } - nextCheckpoint = currentPathEndPosition - path; - } - if (lastValidPathEnd != NULL) { - Tcl_Obj *tmpPathPtr; - /* - * The leading end of the path description was acceptable to - * us. We therefore convert it to its long form, and return - * that. - */ - Tcl_Obj* objPtr = NULL; - int endOfString; - int useLength = lastValidPathEnd - path; - if (*lastValidPathEnd == 0) { - tmpPathPtr = Tcl_NewStringObj(path, useLength); - endOfString = 1; - } else { - tmpPathPtr = Tcl_NewStringObj(path, useLength + 1); - endOfString = 0; - } - /* - * If this returns an error, we have a strange situation; the - * file exists, but we can't get its long name. We will have - * to assume the name we have is ok. - */ - Tcl_IncrRefCount(tmpPathPtr); - if (ConvertFileNameFormat(interp, 0, tmpPathPtr, 1, &objPtr) == TCL_OK) { - int len; - (void) Tcl_GetStringFromObj(objPtr,&len); - if (!endOfString) { - /* Be nice and fix the string before we clear it */ - Tcl_AppendToObj(objPtr, lastValidPathEnd, -1); - } - nextCheckpoint += (len - useLength); - path = Tcl_GetStringFromObj(objPtr,&len); - Tcl_SetStringObj(pathPtr,path, len); - Tcl_DecrRefCount(objPtr); - } - Tcl_DecrRefCount(tmpPathPtr); - } -#endif - } - return nextCheckpoint; -} |