int TclpCopyDirectory( char *src, /* Pathname of directory to be copied. */ char *dst, /* Pathname of target directory. */ Tcl_DString *errorPtr) /* If non-NULL, initialized DString for * error reporting. */ { int result; Tcl_DString srcBuffer; Tcl_DString dstBuffer; Tcl_DStringInit(&srcBuffer); Tcl_DStringInit(&dstBuffer); Tcl_DStringAppend(&srcBuffer, src, -1); Tcl_DStringAppend(&dstBuffer, dst, -1); result = TraverseWinTree(TraversalCopy, &srcBuffer, &dstBuffer, errorPtr); Tcl_DStringFree(&srcBuffer); Tcl_DStringFree(&dstBuffer); return result; }
int TclpCopyDirectory( CONST char *src, /* Pathname of directory to be copied * (UTF-8). */ CONST char *dst, /* Pathname of target directory (UTF-8). */ Tcl_DString *errorPtr) /* If non-NULL, uninitialized or free * DString filled with UTF-8 name of file * causing error. */ { int result; Tcl_DString srcString, dstString; Tcl_WinUtfToTChar(src, -1, &srcString); Tcl_WinUtfToTChar(dst, -1, &dstString); result = TraverseWinTree(TraversalCopy, &srcString, &dstString, errorPtr); Tcl_DStringFree(&srcString); Tcl_DStringFree(&dstString); return result; }
static int TraverseWinTree( TraversalProc *traverseProc,/* Function to call for every file and * directory in source hierarchy. */ Tcl_DString *sourcePtr, /* Pathname of source directory to be * traversed. */ Tcl_DString *targetPtr, /* Pathname of directory to traverse in * parallel with source directory. */ Tcl_DString *errorPtr) /* If non-NULL, an initialized DString for * error reporting. */ { DWORD sourceAttr; char *source, *target, *errfile; int result, sourceLen, targetLen, sourceLenOriginal, targetLenOriginal; HANDLE handle; WIN32_FIND_DATA data; result = TCL_OK; source = Tcl_DStringValue(sourcePtr); sourceLenOriginal = Tcl_DStringLength(sourcePtr); if (targetPtr != NULL) { target = Tcl_DStringValue(targetPtr); targetLenOriginal = Tcl_DStringLength(targetPtr); } else { target = NULL; targetLenOriginal = 0; } errfile = NULL; sourceAttr = GetFileAttributes(source); if (sourceAttr == (DWORD) -1) { errfile = source; goto end; } if ((sourceAttr & FILE_ATTRIBUTE_DIRECTORY) == 0) { /* * Process the regular file */ return (*traverseProc)(source, target, sourceAttr, DOTREE_F, errorPtr); } /* * When given the pathname of the form "c:\" (one that already ends * with a backslash), must make sure not to add another "\" to the end * otherwise it will try to access a network drive. */ sourceLen = sourceLenOriginal; if ((sourceLen > 0) && (source[sourceLen - 1] != '\\')) { Tcl_DStringAppend(sourcePtr, "\\", 1); sourceLen++; } source = Tcl_DStringAppend(sourcePtr, "*.*", 3); handle = FindFirstFile(source, &data); Tcl_DStringSetLength(sourcePtr, sourceLen); if (handle == INVALID_HANDLE_VALUE) { /* * Can't read directory */ TclWinConvertError(GetLastError()); errfile = source; goto end; } result = (*traverseProc)(source, target, sourceAttr, DOTREE_PRED, errorPtr); if (result != TCL_OK) { FindClose(handle); return result; } if (targetPtr != NULL) { targetLen = targetLenOriginal; if ((targetLen > 0) && (target[targetLen - 1] != '\\')) { target = Tcl_DStringAppend(targetPtr, "\\", 1); targetLen++; } } while (1) { if ((strcmp(data.cFileName, ".") != 0) && (strcmp(data.cFileName, "..") != 0)) { /* * Append name after slash, and recurse on the file. */ Tcl_DStringAppend(sourcePtr, data.cFileName, -1); if (targetPtr != NULL) { Tcl_DStringAppend(targetPtr, data.cFileName, -1); } result = TraverseWinTree(traverseProc, sourcePtr, targetPtr, errorPtr); if (result != TCL_OK) { break; } /* * Remove name after slash. */ Tcl_DStringSetLength(sourcePtr, sourceLen); if (targetPtr != NULL) { Tcl_DStringSetLength(targetPtr, targetLen); } } if (FindNextFile(handle, &data) == FALSE) { break; } } FindClose(handle); /* * Strip off the trailing slash we added */ Tcl_DStringSetLength(sourcePtr, sourceLenOriginal); source = Tcl_DStringValue(sourcePtr); if (targetPtr != NULL) { Tcl_DStringSetLength(targetPtr, targetLenOriginal); target = Tcl_DStringValue(targetPtr); } if (result == TCL_OK) { /* * Call traverseProc() on a directory after visiting all the * files in that directory. */ result = (*traverseProc)(source, target, sourceAttr, DOTREE_POSTD, errorPtr); } end: if (errfile != NULL) { TclWinConvertError(GetLastError()); if (errorPtr != NULL) { Tcl_DStringAppend(errorPtr, errfile, -1); } result = TCL_ERROR; } return result; }
int TclpRemoveDirectory( char *path, /* Pathname of directory to be removed. */ int recursive, /* If non-zero, removes directories that * are nonempty. Otherwise, will only remove * empty directories. */ Tcl_DString *errorPtr) /* If non-NULL, initialized DString for * error reporting. */ { int result; Tcl_DString buffer; DWORD attr; if (RemoveDirectory(path) != FALSE) { return TCL_OK; } TclWinConvertError(GetLastError()); if (path[0] == '\0') { /* * Win32s thinks that "" is the same as "." and then reports EACCES * instead of ENOENT. */ errno = ENOENT; } if (errno == EACCES) { attr = GetFileAttributes(path); if (attr != (DWORD) -1) { if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) { /* * Windows 95 reports calling RemoveDirectory on a file as an * EACCES, not an ENOTDIR. */ errno = ENOTDIR; goto end; } if (attr & FILE_ATTRIBUTE_READONLY) { attr &= ~FILE_ATTRIBUTE_READONLY; if (SetFileAttributes(path, attr) == FALSE) { goto end; } if (RemoveDirectory(path) != FALSE) { return TCL_OK; } TclWinConvertError(GetLastError()); SetFileAttributes(path, attr | FILE_ATTRIBUTE_READONLY); } /* * Windows 95 and Win32s report removing a non-empty directory * as EACCES, not EEXIST. If the directory is not empty, * change errno so caller knows what's going on. */ if (TclWinGetPlatformId() != VER_PLATFORM_WIN32_NT) { HANDLE handle; WIN32_FIND_DATA data; Tcl_DString buffer; char *find; int len; Tcl_DStringInit(&buffer); find = Tcl_DStringAppend(&buffer, path, -1); len = Tcl_DStringLength(&buffer); if ((len > 0) && (find[len - 1] != '\\')) { Tcl_DStringAppend(&buffer, "\\", 1); } find = Tcl_DStringAppend(&buffer, "*.*", 3); handle = FindFirstFile(find, &data); if (handle != INVALID_HANDLE_VALUE) { while (1) { if ((strcmp(data.cFileName, ".") != 0) && (strcmp(data.cFileName, "..") != 0)) { /* * Found something in this directory. */ errno = EEXIST; break; } if (FindNextFile(handle, &data) == FALSE) { break; } } FindClose(handle); } Tcl_DStringFree(&buffer); } } } if (errno == ENOTEMPTY) { /* * The caller depends on EEXIST to signify that the directory is * not empty, not ENOTEMPTY. */ errno = EEXIST; } if ((recursive != 0) && (errno == EEXIST)) { /* * The directory is nonempty, but the recursive flag has been * specified, so we recursively remove all the files in the directory. */ Tcl_DStringInit(&buffer); Tcl_DStringAppend(&buffer, path, -1); result = TraverseWinTree(TraversalDelete, &buffer, NULL, errorPtr); Tcl_DStringFree(&buffer); return result; } end: if (errorPtr != NULL) { Tcl_DStringAppend(errorPtr, path, -1); } return TCL_ERROR; }
static int TraverseWinTree( TraversalProc *traverseProc,/* Function to call for every file and * directory in source hierarchy. */ Tcl_DString *sourcePtr, /* Pathname of source directory to be * traversed (native). */ Tcl_DString *targetPtr, /* Pathname of directory to traverse in * parallel with source directory (native). */ Tcl_DString *errorPtr) /* If non-NULL, uninitialized or free * DString filled with UTF-8 name of file * causing error. */ { DWORD sourceAttr; TCHAR *nativeSource, *nativeErrfile; int result, found, sourceLen, targetLen, oldSourceLen, oldTargetLen; HANDLE handle; WIN32_FIND_DATAT data; nativeErrfile = NULL; result = TCL_OK; oldTargetLen = 0; /* lint. */ nativeSource = (TCHAR *) Tcl_DStringValue(sourcePtr); oldSourceLen = Tcl_DStringLength(sourcePtr); sourceAttr = (*tclWinProcs->getFileAttributesProc)(nativeSource); if (sourceAttr == 0xffffffff) { nativeErrfile = nativeSource; goto end; } if ((sourceAttr & FILE_ATTRIBUTE_DIRECTORY) == 0) { /* * Process the regular file */ return (*traverseProc)(sourcePtr, targetPtr, DOTREE_F, errorPtr); } if (tclWinProcs->useWide) { Tcl_DStringAppend(sourcePtr, (char *) L"\\*.*", 4 * sizeof(WCHAR) + 1); Tcl_DStringSetLength(sourcePtr, Tcl_DStringLength(sourcePtr) - 1); } else { Tcl_DStringAppend(sourcePtr, "\\*.*", 4); } nativeSource = (TCHAR *) Tcl_DStringValue(sourcePtr); handle = (*tclWinProcs->findFirstFileProc)(nativeSource, &data); if (handle == INVALID_HANDLE_VALUE) { /* * Can't read directory */ TclWinConvertError(GetLastError()); nativeErrfile = nativeSource; goto end; } nativeSource[oldSourceLen + 1] = '\0'; Tcl_DStringSetLength(sourcePtr, oldSourceLen); result = (*traverseProc)(sourcePtr, targetPtr, DOTREE_PRED, errorPtr); if (result != TCL_OK) { FindClose(handle); return result; } sourceLen = oldSourceLen; if (tclWinProcs->useWide) { sourceLen += sizeof(WCHAR); Tcl_DStringAppend(sourcePtr, (char *) L"\\", sizeof(WCHAR) + 1); Tcl_DStringSetLength(sourcePtr, sourceLen); } else { sourceLen += 1; Tcl_DStringAppend(sourcePtr, "\\", 1); } if (targetPtr != NULL) { oldTargetLen = Tcl_DStringLength(targetPtr); targetLen = oldTargetLen; if (tclWinProcs->useWide) { targetLen += sizeof(WCHAR); Tcl_DStringAppend(targetPtr, (char *) L"\\", sizeof(WCHAR) + 1); Tcl_DStringSetLength(targetPtr, targetLen); } else { targetLen += 1; Tcl_DStringAppend(targetPtr, "\\", 1); } } found = 1; for ( ; found; found = (*tclWinProcs->findNextFileProc)(handle, &data)) { TCHAR *nativeName; int len; if (tclWinProcs->useWide) { WCHAR *wp; wp = data.w.cFileName; if (*wp == '.') { wp++; if (*wp == '.') { wp++; } if (*wp == '\0') { continue; } } nativeName = (TCHAR *) data.w.cFileName; len = Tcl_UniCharLen(data.w.cFileName) * sizeof(WCHAR); } else { if ((strcmp(data.a.cFileName, ".") == 0) || (strcmp(data.a.cFileName, "..") == 0)) { continue; } nativeName = (TCHAR *) data.a.cFileName; len = strlen(data.a.cFileName); } /* * Append name after slash, and recurse on the file. */ Tcl_DStringAppend(sourcePtr, (char *) nativeName, len + 1); Tcl_DStringSetLength(sourcePtr, Tcl_DStringLength(sourcePtr) - 1); if (targetPtr != NULL) { Tcl_DStringAppend(targetPtr, (char *) nativeName, len + 1); Tcl_DStringSetLength(targetPtr, Tcl_DStringLength(targetPtr) - 1); } result = TraverseWinTree(traverseProc, sourcePtr, targetPtr, errorPtr); if (result != TCL_OK) { break; } /* * Remove name after slash. */ Tcl_DStringSetLength(sourcePtr, sourceLen); if (targetPtr != NULL) { Tcl_DStringSetLength(targetPtr, targetLen); } } FindClose(handle); /* * Strip off the trailing slash we added */ Tcl_DStringSetLength(sourcePtr, oldSourceLen + 1); Tcl_DStringSetLength(sourcePtr, oldSourceLen); if (targetPtr != NULL) { Tcl_DStringSetLength(targetPtr, oldTargetLen + 1); Tcl_DStringSetLength(targetPtr, oldTargetLen); } if (result == TCL_OK) { /* * Call traverseProc() on a directory after visiting all the * files in that directory. */ result = (*traverseProc)(sourcePtr, targetPtr, DOTREE_POSTD, errorPtr); } end: if (nativeErrfile != NULL) { TclWinConvertError(GetLastError()); if (errorPtr != NULL) { Tcl_WinTCharToUtf(nativeErrfile, -1, errorPtr); } result = TCL_ERROR; } return result; }
static int DoRemoveDirectory( Tcl_DString *pathPtr, /* Pathname of directory to be removed * (native). */ int recursive, /* If non-zero, removes directories that * are nonempty. Otherwise, will only remove * empty directories. */ Tcl_DString *errorPtr) /* If non-NULL, uninitialized or free * DString filled with UTF-8 name of file * causing error. */ { CONST TCHAR *nativePath; DWORD attr; nativePath = (TCHAR *) Tcl_DStringValue(pathPtr); if ((*tclWinProcs->removeDirectoryProc)(nativePath) != FALSE) { return TCL_OK; } TclWinConvertError(GetLastError()); /* * Win32s thinks that "" is the same as "." and then reports EACCES * instead of ENOENT. */ if (tclWinProcs->useWide) { if (((WCHAR *) nativePath)[0] == '\0') { Tcl_SetErrno(ENOENT); return TCL_ERROR; } } else { if (((char *) nativePath)[0] == '\0') { Tcl_SetErrno(ENOENT); return TCL_ERROR; } } if (Tcl_GetErrno() == EACCES) { attr = (*tclWinProcs->getFileAttributesProc)(nativePath); if (attr != 0xffffffff) { if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) { /* * Windows 95 reports calling RemoveDirectory on a file as an * EACCES, not an ENOTDIR. */ Tcl_SetErrno(ENOTDIR); goto end; } if (attr & FILE_ATTRIBUTE_READONLY) { attr &= ~FILE_ATTRIBUTE_READONLY; if ((*tclWinProcs->setFileAttributesProc)(nativePath, attr) == FALSE) { goto end; } if ((*tclWinProcs->removeDirectoryProc)(nativePath) != FALSE) { return TCL_OK; } TclWinConvertError(GetLastError()); (*tclWinProcs->setFileAttributesProc)(nativePath, attr | FILE_ATTRIBUTE_READONLY); } /* * Windows 95 and Win32s report removing a non-empty directory * as EACCES, not EEXIST. If the directory is not empty, * change errno so caller knows what's going on. */ if (TclWinGetPlatformId() != VER_PLATFORM_WIN32_NT) { char *path, *find; HANDLE handle; WIN32_FIND_DATAA data; Tcl_DString buffer; int len; path = (char *) nativePath; Tcl_DStringInit(&buffer); len = strlen(path); find = Tcl_DStringAppend(&buffer, path, len); if ((len > 0) && (find[len - 1] != '\\')) { Tcl_DStringAppend(&buffer, "\\", 1); } find = Tcl_DStringAppend(&buffer, "*.*", 3); handle = FindFirstFileA(find, &data); if (handle != INVALID_HANDLE_VALUE) { while (1) { if ((strcmp(data.cFileName, ".") != 0) && (strcmp(data.cFileName, "..") != 0)) { /* * Found something in this directory. */ Tcl_SetErrno(EEXIST); break; } if (FindNextFileA(handle, &data) == FALSE) { break; } } FindClose(handle); } Tcl_DStringFree(&buffer); } } } if (Tcl_GetErrno() == ENOTEMPTY) { /* * The caller depends on EEXIST to signify that the directory is * not empty, not ENOTEMPTY. */ Tcl_SetErrno(EEXIST); } if ((recursive != 0) && (Tcl_GetErrno() == EEXIST)) { /* * The directory is nonempty, but the recursive flag has been * specified, so we recursively remove all the files in the directory. */ return TraverseWinTree(TraversalDelete, pathPtr, NULL, errorPtr); } end: if (errorPtr != NULL) { Tcl_WinTCharToUtf(nativePath, -1, errorPtr); } return TCL_ERROR; }