📄 tclwinfcmd.c
字号:
/* * Win32s thinks that "" is the same as "." and then reports EISDIR * instead of ENOENT. */ errno = ENOENT; } else if (errno == EACCES) { attr = GetFileAttributes(path); if (attr != (DWORD) -1) { if (attr & FILE_ATTRIBUTE_DIRECTORY) { /* * Windows NT reports removing a directory as EACCES instead * of EISDIR. */ errno = EISDIR; } else if (attr & FILE_ATTRIBUTE_READONLY) { SetFileAttributes(path, attr & ~FILE_ATTRIBUTE_READONLY); if (DeleteFile(path) != FALSE) { return TCL_OK; } TclWinConvertError(GetLastError()); SetFileAttributes(path, attr); } } } else if (errno == ENOENT) { attr = GetFileAttributes(path); if (attr != (DWORD) -1) { if (attr & FILE_ATTRIBUTE_DIRECTORY) { /* * Windows 95 reports removing a directory as ENOENT instead * of EISDIR. */ errno = EISDIR; } } } else if (errno == EINVAL) { /* * Windows NT reports removing a char device as EINVAL instead of * EACCES. */ errno = EACCES; } return TCL_ERROR;}/* *--------------------------------------------------------------------------- * * TclpCreateDirectory -- * * Creates the specified directory. All parent directories of the * specified directory must already exist. The directory is * automatically created with permissions so that user can access * the new directory and create new files or subdirectories in it. * * Results: * If the directory was successfully created, returns TCL_OK. * Otherwise the return value is TCL_ERROR and errno is set to * indicate the error. Some possible values for errno are: * * EACCES: a parent directory can't be read and/or written. * EEXIST: path already exists. * ENOENT: a parent directory doesn't exist. * * Side effects: * A directory is created. * *--------------------------------------------------------------------------- */intTclpCreateDirectory( char *path) /* Pathname of directory to create */{ int error; if (CreateDirectory(path, NULL) == 0) { error = GetLastError(); if (TclWinGetPlatformId() == VER_PLATFORM_WIN32s) { if ((error == ERROR_ACCESS_DENIED) && (GetFileAttributes(path) != (DWORD) -1)) { error = ERROR_FILE_EXISTS; } } TclWinConvertError(error); return TCL_ERROR; } return TCL_OK;}/* *--------------------------------------------------------------------------- * * TclpCopyDirectory -- * * Recursively copies a directory. The target directory dst must * not already exist. Note that this function does not merge two * directory hierarchies, even if the target directory is an an * empty directory. * * Results: * If the directory was successfully copied, returns TCL_OK. * Otherwise the return value is TCL_ERROR, errno is set to indicate * the error, and the pathname of the file that caused the error * is stored in errorPtr. See TclpCreateDirectory and TclpCopyFile * for a description of possible values for errno. * * Side effects: * An exact copy of the directory hierarchy src will be created * with the name dst. If an error occurs, the error will * be returned immediately, and remaining files will not be * processed. * *--------------------------------------------------------------------------- */intTclpCopyDirectory( 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;}/* *---------------------------------------------------------------------- * * TclpRemoveDirectory -- * * Removes directory (and its contents, if the recursive flag is set). * * Results: * If the directory was successfully removed, returns TCL_OK. * Otherwise the return value is TCL_ERROR, errno is set to indicate * the error, and the pathname of the file that caused the error * is stored in errorPtr. Some possible values for errno are: * * EACCES: path directory can't be read and/or written. * EEXIST: path is a non-empty directory. * EINVAL: path is root directory or current directory. * ENOENT: path doesn't exist or is "". * ENOTDIR: path is not a directory. * * EACCES: path is a char device (nul:, com1:, etc.) (95) * EINVAL: path is a char device (nul:, com1:, etc.) (NT) * * Side effects: * Directory removed. If an error occurs, the error will be returned * immediately, and remaining files will not be deleted. * *---------------------------------------------------------------------- */intTclpRemoveDirectory( 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;}/* *--------------------------------------------------------------------------- * * TraverseWinTree -- * * Traverse directory tree specified by sourcePtr, calling the function * traverseProc for each file and directory encountered. If destPtr * is non-null, each of name in the sourcePtr directory is appended to * the directory specified by destPtr and passed as the second argument * to traverseProc() . * * Results: * Standard Tcl result. * * Side effects: * None caused by TraverseWinTree, however the user specified * traverseProc() may change state. If an error occurs, the error will * be returned immediately, and remaining files will not be processed. * *--------------------------------------------------------------------------- */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;}/* *---------------------------------------------------------------------- * * TraversalCopy * * Called from TraverseUnixTree in order to execute a recursive * copy of a directory. * * Results: * Standard Tcl result.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -