summaryrefslogtreecommitdiffstats
path: root/win/tclWinFCmd.c
diff options
context:
space:
mode:
authorvincentdarley <vincentdarley>2002-06-12 09:28:58 (GMT)
committervincentdarley <vincentdarley>2002-06-12 09:28:58 (GMT)
commit85fa4c1014f2115447bba5458e877fe974f04f1b (patch)
tree0c1a8deaa9b8d015e4714b9ce7fb77926a4d499c /win/tclWinFCmd.c
parentc1e47417bf2cab1cb467c456f990114f78ad1680 (diff)
downloadtcl-85fa4c1014f2115447bba5458e877fe974f04f1b.zip
tcl-85fa4c1014f2115447bba5458e877fe974f04f1b.tar.gz
tcl-85fa4c1014f2115447bba5458e877fe974f04f1b.tar.bz2
fs clarification and windows fixes
Diffstat (limited to 'win/tclWinFCmd.c')
-rw-r--r--win/tclWinFCmd.c311
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;
-}