summaryrefslogtreecommitdiffstats
path: root/win/tclWinFCmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinFCmd.c')
-rw-r--r--win/tclWinFCmd.c1629
1 files changed, 784 insertions, 845 deletions
diff --git a/win/tclWinFCmd.c b/win/tclWinFCmd.c
index 1821f8f..52ea8c6 100644
--- a/win/tclWinFCmd.c
+++ b/win/tclWinFCmd.c
@@ -1,15 +1,13 @@
/*
* tclWinFCmd.c
*
- * This file implements the Windows specific portion of file manipulation
- * subcommands of the "file" command.
+ * This file implements the Windows specific portion of file manipulation
+ * subcommands of the "file" command.
*
* Copyright (c) 1996-1998 Sun Microsystems, Inc.
*
- * 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.43 2004/10/06 16:37:18 dgp Exp $
+ * See the file "license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclWinInt.h"
@@ -19,30 +17,25 @@
* TraverseWinTree() calls the traverseProc()
*/
-#define DOTREE_PRED 1 /* pre-order directory */
-#define DOTREE_POSTD 2 /* post-order directory */
-#define DOTREE_F 3 /* regular file */
-#define DOTREE_LINK 4 /* symbolic link */
+#define DOTREE_PRED 1 /* pre-order directory */
+#define DOTREE_POSTD 2 /* post-order directory */
+#define DOTREE_F 3 /* regular file */
+#define DOTREE_LINK 4 /* symbolic link */
/*
* Callbacks for file attributes code.
*/
-static int GetWinFileAttributes _ANSI_ARGS_((Tcl_Interp *interp,
- int objIndex, Tcl_Obj *fileName,
- Tcl_Obj **attributePtrPtr));
-static int GetWinFileLongName _ANSI_ARGS_((Tcl_Interp *interp,
- int objIndex, Tcl_Obj *fileName,
- Tcl_Obj **attributePtrPtr));
-static int GetWinFileShortName _ANSI_ARGS_((Tcl_Interp *interp,
- int objIndex, Tcl_Obj *fileName,
- Tcl_Obj **attributePtrPtr));
-static int SetWinFileAttributes _ANSI_ARGS_((Tcl_Interp *interp,
- int objIndex, Tcl_Obj *fileName,
- Tcl_Obj *attributePtr));
-static int CannotSetAttribute _ANSI_ARGS_((Tcl_Interp *interp,
- int objIndex, Tcl_Obj *fileName,
- Tcl_Obj *attributePtr));
+static int GetWinFileAttributes(Tcl_Interp *interp, int objIndex,
+ Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr);
+static int GetWinFileLongName(Tcl_Interp *interp, int objIndex,
+ Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr);
+static int GetWinFileShortName(Tcl_Interp *interp, int objIndex,
+ Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr);
+static int SetWinFileAttributes(Tcl_Interp *interp, int objIndex,
+ Tcl_Obj *fileName, Tcl_Obj *attributePtr);
+static int CannotSetAttribute(Tcl_Interp *interp, int objIndex,
+ Tcl_Obj *fileName, Tcl_Obj *attributePtr);
/*
* Constants and variables necessary for file attributes subcommand.
@@ -57,16 +50,16 @@ enum {
WIN_SYSTEM_ATTRIBUTE
};
-static int attributeArray[] = {FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_HIDDEN,
+static const int attributeArray[] = {FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_HIDDEN,
0, FILE_ATTRIBUTE_READONLY, 0, FILE_ATTRIBUTE_SYSTEM};
-CONST char *tclpFileAttrStrings[] = {
+const char *const tclpFileAttrStrings[] = {
"-archive", "-hidden", "-longname", "-readonly",
"-shortname", "-system", (char *) NULL
};
-CONST TclFileAttrProcs tclpFileAttrProcs[] = {
+const TclFileAttrProcs tclpFileAttrProcs[] = {
{GetWinFileAttributes, SetWinFileAttributes},
{GetWinFileAttributes, SetWinFileAttributes},
{GetWinFileLongName, CannotSetAttribute},
@@ -74,131 +67,104 @@ CONST TclFileAttrProcs tclpFileAttrProcs[] = {
{GetWinFileShortName, CannotSetAttribute},
{GetWinFileAttributes, SetWinFileAttributes}};
-#if defined(HAVE_NO_SEH) && defined(TCL_MEM_DEBUG)
-static void *INITIAL_ESP,
- *INITIAL_EBP,
- *INITIAL_HANDLER,
- *RESTORED_ESP,
- *RESTORED_EBP,
- *RESTORED_HANDLER;
-#endif /* HAVE_NO_SEH && TCL_MEM_DEBUG */
-
-#ifdef HAVE_NO_SEH
-static
-__attribute__ ((cdecl))
-EXCEPTION_DISPOSITION
-_except_dorenamefile_handler(
- struct _EXCEPTION_RECORD *ExceptionRecord,
- void *EstablisherFrame,
- struct _CONTEXT *ContextRecord,
- void *DispatcherContext);
-
-static
-__attribute__ ((cdecl))
-EXCEPTION_DISPOSITION
-_except_docopyfile_handler(
- struct _EXCEPTION_RECORD *ExceptionRecord,
- void *EstablisherFrame,
- struct _CONTEXT *ContextRecord,
- void *DispatcherContext);
-
-#endif /* HAVE_NO_SEH */
-
/*
* Prototype for the TraverseWinTree callback function.
*/
-typedef int (TraversalProc)(CONST TCHAR *srcPtr, CONST TCHAR *dstPtr,
+typedef int (TraversalProc)(const TCHAR *srcPtr, const TCHAR *dstPtr,
int type, Tcl_DString *errorPtr);
/*
- * Declarations for local procedures defined in this file:
+ * Declarations for local functions defined in this file:
*/
static void StatError(Tcl_Interp *interp, Tcl_Obj *fileName);
-static int ConvertFileNameFormat(Tcl_Interp *interp,
+static int ConvertFileNameFormat(Tcl_Interp *interp,
int objIndex, Tcl_Obj *fileName, int longShort,
Tcl_Obj **attributePtrPtr);
-static int DoCopyFile(CONST TCHAR *srcPtr, CONST TCHAR *dstPtr);
-static int DoCreateDirectory(CONST TCHAR *pathPtr);
-static int DoRemoveJustDirectory(CONST TCHAR *nativeSrc,
+static int DoCopyFile(const TCHAR *srcPtr, const TCHAR *dstPtr);
+static int DoCreateDirectory(const TCHAR *pathPtr);
+static int DoRemoveJustDirectory(const TCHAR *nativeSrc,
int ignoreError, Tcl_DString *errorPtr);
-static int DoRemoveDirectory(Tcl_DString *pathPtr, int recursive,
+static int DoRemoveDirectory(Tcl_DString *pathPtr, int recursive,
Tcl_DString *errorPtr);
-static int DoRenameFile(CONST TCHAR *nativeSrc, CONST TCHAR *dstPtr);
-static int TraversalCopy(CONST TCHAR *srcPtr, CONST TCHAR *dstPtr,
- int type, Tcl_DString *errorPtr);
-static int TraversalDelete(CONST TCHAR *srcPtr, CONST TCHAR *dstPtr,
+static int DoRenameFile(const TCHAR *nativeSrc,
+ const TCHAR *dstPtr);
+static int TraversalCopy(const TCHAR *srcPtr, const TCHAR *dstPtr,
int type, Tcl_DString *errorPtr);
+static int TraversalDelete(const TCHAR *srcPtr,
+ const TCHAR *dstPtr, int type,
+ Tcl_DString *errorPtr);
static int TraverseWinTree(TraversalProc *traverseProc,
- Tcl_DString *sourcePtr, Tcl_DString *dstPtr,
+ Tcl_DString *sourcePtr, Tcl_DString *dstPtr,
Tcl_DString *errorPtr);
-
/*
*---------------------------------------------------------------------------
*
* TclpObjRenameFile, DoRenameFile --
*
- * Changes the name of an existing file or directory, from src to dst.
- * If src and dst refer to the same file or directory, does nothing
- * and returns success. Otherwise if dst already exists, it will be
- * deleted and replaced by src subject to the following conditions:
+ * Changes the name of an existing file or directory, from src to dst.
+ * If src and dst refer to the same file or directory, does nothing and
+ * returns success. Otherwise if dst already exists, it will be deleted
+ * and replaced by src subject to the following conditions:
* If src is a directory, dst may be an empty directory.
* If src is a file, dst may be a file.
- * In any other situation where dst already exists, the rename will
- * fail.
+ * In any other situation where dst already exists, the rename will fail.
*
* Results:
* If the file or directory was successfully renamed, returns TCL_OK.
- * Otherwise the return value is TCL_ERROR and errno is set to
- * indicate the error. Some possible values for errno are:
+ * Otherwise the return value is TCL_ERROR and errno is set to indicate
+ * the error. Some possible values for errno are:
*
* ENAMETOOLONG: src or dst names are too long.
- * EACCES: src or dst parent directory can't be read and/or written.
+ * EACCES: src or dst parent directory can't be read and/or written.
* EEXIST: dst is a non-empty directory.
* EINVAL: src is a root directory or dst is a subdirectory of src.
* EISDIR: dst is a directory, but src is not.
- * ENOENT: src doesn't exist. src or dst is "".
- * ENOTDIR: src is a directory, but dst is not.
+ * ENOENT: src doesn't exist. src or dst is "".
+ * ENOTDIR: src is a directory, but dst is not.
* EXDEV: src and dst are on different filesystems.
*
- * EACCES: exists an open file already referring to src or dst.
- * EACCES: src or dst specify the current working directory (NT).
- * EACCES: src specifies a char device (nul:, com1:, etc.)
+ * EACCES: exists an open file already referring to src or dst.
+ * EACCES: src or dst specify the current working directory (NT).
+ * EACCES: src specifies a char device (nul:, com1:, etc.)
* EEXIST: dst specifies a char device (nul:, com1:, etc.) (NT)
* EACCES: dst specifies a char device (nul:, com1:, etc.) (95)
- *
+ *
* Side effects:
- * The implementation supports cross-filesystem renames of files,
- * but the caller should be prepared to emulate cross-filesystem
- * renames of directories if errno is EXDEV.
+ * The implementation supports cross-filesystem renames of files, but the
+ * caller should be prepared to emulate cross-filesystem renames of
+ * directories if errno is EXDEV.
*
*---------------------------------------------------------------------------
*/
-int
-TclpObjRenameFile(srcPathPtr, destPathPtr)
- Tcl_Obj *srcPathPtr;
- Tcl_Obj *destPathPtr;
+int
+TclpObjRenameFile(
+ Tcl_Obj *srcPathPtr,
+ Tcl_Obj *destPathPtr)
{
- return DoRenameFile(Tcl_FSGetNativePath(srcPathPtr),
- Tcl_FSGetNativePath(destPathPtr));
+ return DoRenameFile(Tcl_FSGetNativePath(srcPathPtr),
+ Tcl_FSGetNativePath(destPathPtr));
}
static int
DoRenameFile(
- CONST TCHAR *nativeSrc, /* Pathname of file or dir to be renamed
- * (native). */
- CONST TCHAR *nativeDst) /* New pathname for file or directory
+ const TCHAR *nativeSrc, /* Pathname of file or dir to be renamed
+ * (native). */
+ const TCHAR *nativeDst) /* New pathname for file or directory
* (native). */
-{
+{
+#if defined(HAVE_NO_SEH) && !defined(_WIN64)
+ TCLEXCEPTION_REGISTRATION registration;
+#endif
DWORD srcAttr, dstAttr;
int retval = -1;
/*
- * The MoveFile API acts differently under Win95/98 and NT
- * WRT NULL and "". Avoid passing these values.
+ * The MoveFile API acts differently under Win95/98 and NT WRT NULL and
+ * "". Avoid passing these values.
*/
if (nativeSrc == NULL || nativeSrc[0] == '\0' ||
@@ -208,93 +174,126 @@ DoRenameFile(
}
/*
- * The MoveFile API would throw an exception under NT
- * if one of the arguments is a char block device.
+ * The MoveFile API would throw an exception under NT if one of the
+ * arguments is a char block device.
*/
-#ifdef HAVE_NO_SEH
-# ifdef TCL_MEM_DEBUG
- __asm__ __volatile__ (
- "movl %%esp, %0" "\n\t"
- "movl %%ebp, %1" "\n\t"
- "movl %%fs:0, %2" "\n\t"
- : "=m"(INITIAL_ESP),
- "=m"(INITIAL_EBP),
- "=r"(INITIAL_HANDLER) );
-# endif /* TCL_MEM_DEBUG */
+#if defined(HAVE_NO_SEH) && !defined(_WIN64)
+ /*
+ * Don't have SEH available, do things the hard way. Note that this needs
+ * to be one block of asm, to avoid stack imbalance; also, it is illegal
+ * for one asm block to contain a jump to another.
+ */
__asm__ __volatile__ (
- "pushl %%ebp" "\n\t"
- "pushl %0" "\n\t"
- "pushl %%fs:0" "\n\t"
- "movl %%esp, %%fs:0"
- :
- : "r" (_except_dorenamefile_handler)
- );
+ /*
+ * Pick up params before messing with the stack.
+ */
+
+ "movl %[nativeDst], %%ebx" "\n\t"
+ "movl %[nativeSrc], %%ecx" "\n\t"
+
+ /*
+ * Construct an TCLEXCEPTION_REGISTRATION to protect the call to
+ * MoveFile.
+ */
+
+ "leal %[registration], %%edx" "\n\t"
+ "movl %%fs:0, %%eax" "\n\t"
+ "movl %%eax, 0x0(%%edx)" "\n\t" /* link */
+ "leal 1f, %%eax" "\n\t"
+ "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
+ "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
+ "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */
+ "movl $0, 0x10(%%edx)" "\n\t" /* status */
+
+ /*
+ * Link the TCLEXCEPTION_REGISTRATION on the chain.
+ */
+
+ "movl %%edx, %%fs:0" "\n\t"
+
+ /*
+ * Call MoveFile(nativeSrc, nativeDst)
+ */
+
+ "pushl %%ebx" "\n\t"
+ "pushl %%ecx" "\n\t"
+ "movl %[moveFile], %%eax" "\n\t"
+ "call *%%eax" "\n\t"
+
+ /*
+ * Come here on normal exit. Recover the TCLEXCEPTION_REGISTRATION and
+ * put the status return from MoveFile into it.
+ */
+
+ "movl %%fs:0, %%edx" "\n\t"
+ "movl %%eax, 0x10(%%edx)" "\n\t"
+ "jmp 2f" "\n"
+
+ /*
+ * Come here on an exception. Recover the TCLEXCEPTION_REGISTRATION
+ */
+
+ "1:" "\t"
+ "movl %%fs:0, %%edx" "\n\t"
+ "movl 0x8(%%edx), %%edx" "\n\t"
+
+ /*
+ * Come here however we exited. Restore context from the
+ * TCLEXCEPTION_REGISTRATION in case the stack is unbalanced.
+ */
+
+ "2:" "\t"
+ "movl 0xc(%%edx), %%esp" "\n\t"
+ "movl 0x8(%%edx), %%ebp" "\n\t"
+ "movl 0x0(%%edx), %%eax" "\n\t"
+ "movl %%eax, %%fs:0" "\n\t"
+
+ :
+ /* No outputs */
+ :
+ [registration] "m" (registration),
+ [nativeDst] "m" (nativeDst),
+ [nativeSrc] "m" (nativeSrc),
+ [moveFile] "r" (MoveFile)
+ :
+ "%eax", "%ebx", "%ecx", "%edx", "memory"
+ );
+ if (registration.status != FALSE) {
+ retval = TCL_OK;
+ }
#else
+#ifndef HAVE_NO_SEH
__try {
-#endif /* HAVE_NO_SEH */
- if ((*tclWinProcs->moveFileProc)(nativeSrc, nativeDst) != FALSE) {
+#endif
+ if ((*MoveFile)(nativeSrc, nativeDst) != FALSE) {
retval = TCL_OK;
}
-#ifdef HAVE_NO_SEH
- __asm__ __volatile__ (
- "jmp dorenamefile_pop" "\n"
- "dorenamefile_reentry:" "\n\t"
- "movl %%fs:0, %%eax" "\n\t"
- "movl 0x8(%%eax), %%esp" "\n\t"
- "movl 0x8(%%esp), %%ebp" "\n"
- "dorenamefile_pop:" "\n\t"
- "movl (%%esp), %%eax" "\n\t"
- "movl %%eax, %%fs:0" "\n\t"
- "add $12, %%esp" "\n\t"
- :
- :
- : "%eax");
-
-# ifdef TCL_MEM_DEBUG
- __asm__ __volatile__ (
- "movl %%esp, %0" "\n\t"
- "movl %%ebp, %1" "\n\t"
- "movl %%fs:0, %2" "\n\t"
- : "=m"(RESTORED_ESP),
- "=m"(RESTORED_EBP),
- "=r"(RESTORED_HANDLER) );
-
- if (INITIAL_ESP != RESTORED_ESP) {
- Tcl_Panic("ESP restored incorrectly");
- }
- if (INITIAL_EBP != RESTORED_EBP) {
- Tcl_Panic("EBP restored incorrectly");
- }
- if (INITIAL_HANDLER != RESTORED_HANDLER) {
- Tcl_Panic("HANDLER restored incorrectly");
- }
-# endif /* TCL_MEM_DEBUG */
-#else
+#ifndef HAVE_NO_SEH
} __except (EXCEPTION_EXECUTE_HANDLER) {}
-#endif /* HAVE_NO_SEH */
+#endif
+#endif
- /*
- * Avoid using control flow statements in the SEH guarded block!
- */
if (retval != -1) {
- return retval;
+ return retval;
}
TclWinConvertError(GetLastError());
- srcAttr = (*tclWinProcs->getFileAttributesProc)(nativeSrc);
- dstAttr = (*tclWinProcs->getFileAttributesProc)(nativeDst);
+ srcAttr = GetFileAttributes(nativeSrc);
+ dstAttr = GetFileAttributes(nativeDst);
if (srcAttr == 0xffffffff) {
- if ((*tclWinProcs->getFullPathNameProc)(nativeSrc, 0, NULL, NULL) >= MAX_PATH) {
+ if (GetFullPathName(nativeSrc, 0, NULL,
+ NULL) >= MAX_PATH) {
errno = ENAMETOOLONG;
return TCL_ERROR;
}
srcAttr = 0;
}
if (dstAttr == 0xffffffff) {
- if ((*tclWinProcs->getFullPathNameProc)(nativeDst, 0, NULL, NULL) >= MAX_PATH) {
+ if (GetFullPathName(nativeDst, 0, NULL,
+ NULL) >= MAX_PATH) {
errno = ENAMETOOLONG;
return TCL_ERROR;
}
@@ -306,37 +305,39 @@ DoRenameFile(
return TCL_ERROR;
}
if (errno == EACCES) {
- decode:
+ decode:
if (srcAttr & FILE_ATTRIBUTE_DIRECTORY) {
TCHAR *nativeSrcRest, *nativeDstRest;
- CONST char **srcArgv, **dstArgv;
+ const char **srcArgv, **dstArgv;
int size, srcArgc, dstArgc;
- WCHAR nativeSrcPath[MAX_PATH];
- WCHAR nativeDstPath[MAX_PATH];
+ TCHAR nativeSrcPath[MAX_PATH];
+ TCHAR nativeDstPath[MAX_PATH];
Tcl_DString srcString, dstString;
- CONST char *src, *dst;
+ const char *src, *dst;
- size = (*tclWinProcs->getFullPathNameProc)(nativeSrc, MAX_PATH,
+ size = GetFullPathName(nativeSrc, MAX_PATH,
nativeSrcPath, &nativeSrcRest);
if ((size == 0) || (size > MAX_PATH)) {
return TCL_ERROR;
}
- size = (*tclWinProcs->getFullPathNameProc)(nativeDst, MAX_PATH,
+ size = GetFullPathName(nativeDst, MAX_PATH,
nativeDstPath, &nativeDstRest);
if ((size == 0) || (size > MAX_PATH)) {
return TCL_ERROR;
}
- (*tclWinProcs->charLowerProc)((TCHAR *) nativeSrcPath);
- (*tclWinProcs->charLowerProc)((TCHAR *) nativeDstPath);
+ CharLower(nativeSrcPath);
+ CharLower(nativeDstPath);
+
+ src = Tcl_WinTCharToUtf(nativeSrcPath, -1, &srcString);
+ dst = Tcl_WinTCharToUtf(nativeDstPath, -1, &dstString);
- src = Tcl_WinTCharToUtf((TCHAR *) nativeSrcPath, -1, &srcString);
- dst = Tcl_WinTCharToUtf((TCHAR *) nativeDstPath, -1, &dstString);
/*
* Check whether the destination path is actually inside the
- * source path. This is true if the prefix matches, and the next
+ * source path. This is true if the prefix matches, and the next
* character is either end-of-string or a directory separator
*/
- if ((strncmp(src, dst, (size_t) Tcl_DStringLength(&srcString))==0)
+
+ if ((strncmp(src, dst, (size_t) Tcl_DStringLength(&srcString))==0)
&& (dst[Tcl_DStringLength(&srcString)] == '\\'
|| dst[Tcl_DStringLength(&srcString)] == '/'
|| dst[Tcl_DStringLength(&srcString)] == '\0')) {
@@ -356,71 +357,70 @@ DoRenameFile(
if (srcArgc == 1) {
/*
- * They are trying to move a root directory. Whether
- * or not it is across filesystems, this cannot be
- * done.
+ * They are trying to move a root directory. Whether or not it
+ * is across filesystems, this cannot be done.
*/
Tcl_SetErrno(EINVAL);
} else if ((srcArgc > 0) && (dstArgc > 0) &&
(strcmp(srcArgv[0], dstArgv[0]) != 0)) {
/*
- * If src is a directory and dst filesystem != src
- * filesystem, 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 MoveFile
- * system call already handles the case of moving a
- * file between filesystems.
+ * If src is a directory and dst filesystem != src filesystem,
+ * 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 MoveFile system call already handles the case of moving
+ * a file between filesystems.
*/
Tcl_SetErrno(EXDEV);
}
- ckfree((char *) srcArgv);
- ckfree((char *) dstArgv);
+ ckfree(srcArgv);
+ ckfree(dstArgv);
}
/*
* Other types of access failure is that dst is a read-only
- * filesystem, that an open file referred to src or dest, or that
- * src or dest specified the current working directory on the
- * current filesystem. EACCES is returned for those cases.
+ * filesystem, that an open file referred to src or dest, or that src
+ * or dest specified the current working directory on the current
+ * filesystem. EACCES is returned for those cases.
*/
} else if (Tcl_GetErrno() == EEXIST) {
/*
- * Reports EEXIST any time the target already exists. If it makes
+ * Reports EEXIST any time the target already exists. If it makes
* sense, remove the old file and try renaming again.
*/
if (srcAttr & FILE_ATTRIBUTE_DIRECTORY) {
if (dstAttr & FILE_ATTRIBUTE_DIRECTORY) {
/*
- * Overwrite empty dst directory with src directory. The
- * following call will remove an empty directory. If it
- * fails, it's because it wasn't empty.
+ * Overwrite empty dst directory with src directory. The
+ * following call will remove an empty directory. If it fails,
+ * it's because it wasn't empty.
*/
if (DoRemoveJustDirectory(nativeDst, 0, NULL) == TCL_OK) {
/*
* Now that that empty directory is gone, we can try
- * renaming again. If that fails, we'll put this empty
+ * renaming again. If that fails, we'll put this empty
* directory back, for completeness.
*/
- if ((*tclWinProcs->moveFileProc)(nativeSrc, nativeDst) != FALSE) {
+ if (MoveFile(nativeSrc,
+ nativeDst) != FALSE) {
return TCL_OK;
}
/*
- * Some new error has occurred. Don't know what it
- * could be, but report this one.
+ * Some new error has occurred. Don't know what it could
+ * be, but report this one.
*/
TclWinConvertError(GetLastError());
- (*tclWinProcs->createDirectoryProc)(nativeDst, NULL);
- (*tclWinProcs->setFileAttributesProc)(nativeDst, dstAttr);
+ CreateDirectory(nativeDst, NULL);
+ SetFileAttributes(nativeDst, dstAttr);
if (Tcl_GetErrno() == EACCES) {
/*
* Decode the EACCES to a more meaningful error.
@@ -438,55 +438,52 @@ DoRenameFile(
} else {
/*
* Overwrite existing file by:
- *
+ *
* 1. Rename existing file to temp name.
* 2. Rename old file to new name.
- * 3. If success, delete temp file. If failure,
- * put temp file back to old name.
+ * 3. If success, delete temp file. If failure, put temp file
+ * back to old name.
*/
TCHAR *nativeRest, *nativeTmp, *nativePrefix;
int result, size;
- WCHAR tempBuf[MAX_PATH];
-
- size = (*tclWinProcs->getFullPathNameProc)(nativeDst, MAX_PATH,
+ TCHAR tempBuf[MAX_PATH];
+
+ size = GetFullPathName(nativeDst, MAX_PATH,
tempBuf, &nativeRest);
if ((size == 0) || (size > MAX_PATH) || (nativeRest == NULL)) {
return TCL_ERROR;
}
nativeTmp = (TCHAR *) tempBuf;
- ((char *) nativeRest)[0] = '\0';
- ((char *) nativeRest)[1] = '\0'; /* In case it's Unicode. */
+ nativeRest[0] = L'\0';
result = TCL_ERROR;
- nativePrefix = (tclWinProcs->useWide)
- ? (TCHAR *) L"tclr" : (TCHAR *) "tclr";
- if ((*tclWinProcs->getTempFileNameProc)(nativeTmp,
- nativePrefix, 0, tempBuf) != 0) {
+ nativePrefix = (TCHAR *) L"tclr";
+ if (GetTempFileName(nativeTmp, nativePrefix,
+ 0, tempBuf) != 0) {
/*
* Strictly speaking, need the following DeleteFile and
* MoveFile to be joined as an atomic operation so no
* other app comes along in the meantime and creates the
* same temp file.
*/
-
- nativeTmp = (TCHAR *) tempBuf;
- (*tclWinProcs->deleteFileProc)(nativeTmp);
- if ((*tclWinProcs->moveFileProc)(nativeDst, nativeTmp) != FALSE) {
- if ((*tclWinProcs->moveFileProc)(nativeSrc, nativeDst) != FALSE) {
- (*tclWinProcs->setFileAttributesProc)(nativeTmp,
- FILE_ATTRIBUTE_NORMAL);
- (*tclWinProcs->deleteFileProc)(nativeTmp);
+
+ nativeTmp = tempBuf;
+ DeleteFile(nativeTmp);
+ if (MoveFile(nativeDst, nativeTmp) != FALSE) {
+ if (MoveFile(nativeSrc, nativeDst) != FALSE) {
+ SetFileAttributes(nativeTmp, FILE_ATTRIBUTE_NORMAL);
+ DeleteFile(nativeTmp);
return TCL_OK;
} else {
- (*tclWinProcs->deleteFileProc)(nativeDst);
- (*tclWinProcs->moveFileProc)(nativeTmp, nativeDst);
+ DeleteFile(nativeDst);
+ MoveFile(nativeTmp, nativeDst);
}
- }
+ }
/*
- * Can't backup dst file or move src file. Return that
- * error. Could happen if an open file refers to dst.
+ * Can't backup dst file or move src file. Return that
+ * error. Could happen if an open file refers to dst.
*/
TclWinConvertError(GetLastError());
@@ -506,54 +503,23 @@ DoRenameFile(
}
/*
- *----------------------------------------------------------------------
- *
- * _except_dorenamefile_handler --
- *
- * SEH exception handler for DoRenameFile.
- *
- * Results:
- * See DoRenameFile.
- *
- * Side effects:
- * See DoRenameFile.
- *
- *----------------------------------------------------------------------
- */
-#ifdef HAVE_NO_SEH
-static
-__attribute__ ((cdecl))
-EXCEPTION_DISPOSITION
-_except_dorenamefile_handler(
- struct _EXCEPTION_RECORD *ExceptionRecord,
- void *EstablisherFrame,
- struct _CONTEXT *ContextRecord,
- void *DispatcherContext)
-{
- __asm__ __volatile__ (
- "jmp dorenamefile_reentry");
- return 0; /* Function does not return */
-}
-#endif /* HAVE_NO_SEH */
-
-/*
*---------------------------------------------------------------------------
*
* TclpObjCopyFile, DoCopyFile --
*
- * Copy a single file (not a directory). If dst already exists and
- * is not a directory, it is removed.
+ * Copy a single file (not a directory). If dst already exists and is not
+ * a directory, it is removed.
*
* Results:
- * If the file was successfully copied, returns TCL_OK. Otherwise
- * the return value is TCL_ERROR and errno is set to indicate the
- * error. Some possible values for errno are:
+ * If the file was successfully copied, 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: src or dst parent directory can't be read and/or written.
+ * EACCES: src or dst parent directory can't be read and/or written.
* EISDIR: src or dst is a directory.
- * ENOENT: src doesn't exist. src or dst is "".
+ * ENOENT: src doesn't exist. src or dst is "".
*
- * EACCES: exists an open file already referring to dst (95).
+ * EACCES: exists an open file already referring to dst (95).
* EACCES: src specifies a char device (nul:, com1:, etc.) (NT)
* ENOENT: src specifies a char device (nul:, com1:, etc.) (95)
*
@@ -563,25 +529,28 @@ _except_dorenamefile_handler(
*---------------------------------------------------------------------------
*/
-int
-TclpObjCopyFile(srcPathPtr, destPathPtr)
- Tcl_Obj *srcPathPtr;
- Tcl_Obj *destPathPtr;
+int
+TclpObjCopyFile(
+ Tcl_Obj *srcPathPtr,
+ Tcl_Obj *destPathPtr)
{
return DoCopyFile(Tcl_FSGetNativePath(srcPathPtr),
- Tcl_FSGetNativePath(destPathPtr));
+ Tcl_FSGetNativePath(destPathPtr));
}
static int
DoCopyFile(
- CONST TCHAR *nativeSrc, /* Pathname of file to be copied (native). */
- CONST TCHAR *nativeDst) /* Pathname of file to copy to (native). */
+ const TCHAR *nativeSrc, /* Pathname of file to be copied (native). */
+ const TCHAR *nativeDst) /* Pathname of file to copy to (native). */
{
+#if defined(HAVE_NO_SEH) && !defined(_WIN64)
+ TCLEXCEPTION_REGISTRATION registration;
+#endif
int retval = -1;
/*
- * The CopyFile API acts differently under Win95/98 and NT
- * WRT NULL and "". Avoid passing these values.
+ * The CopyFile API acts differently under Win95/98 and NT WRT NULL and
+ * "". Avoid passing these values.
*/
if (nativeSrc == NULL || nativeSrc[0] == '\0' ||
@@ -589,80 +558,113 @@ DoCopyFile(
Tcl_SetErrno(ENOENT);
return TCL_ERROR;
}
-
+
/*
- * The CopyFile API would throw an exception under NT if one
- * of the arguments is a char block device.
+ * The CopyFile API would throw an exception under NT if one of the
+ * arguments is a char block device.
*/
-#ifdef HAVE_NO_SEH
-# ifdef TCL_MEM_DEBUG
- __asm__ __volatile__ (
- "movl %%esp, %0" "\n\t"
- "movl %%ebp, %1" "\n\t"
- "movl %%fs:0, %2" "\n\t"
- : "=m"(INITIAL_ESP),
- "=m"(INITIAL_EBP),
- "=r"(INITIAL_HANDLER) );
-# endif /* TCL_MEM_DEBUG */
+#if defined(HAVE_NO_SEH) && !defined(_WIN64)
+ /*
+ * Don't have SEH available, do things the hard way. Note that this needs
+ * to be one block of asm, to avoid stack imbalance; also, it is illegal
+ * for one asm block to contain a jump to another.
+ */
__asm__ __volatile__ (
- "pushl %%ebp" "\n\t"
- "pushl %0" "\n\t"
- "pushl %%fs:0" "\n\t"
- "movl %%esp, %%fs:0"
- :
- : "r" (_except_docopyfile_handler)
- );
+
+ /*
+ * Pick up parameters before messing with the stack
+ */
+
+ "movl %[nativeDst], %%ebx" "\n\t"
+ "movl %[nativeSrc], %%ecx" "\n\t"
+
+ /*
+ * Construct an TCLEXCEPTION_REGISTRATION to protect the call to
+ * CopyFile.
+ */
+
+ "leal %[registration], %%edx" "\n\t"
+ "movl %%fs:0, %%eax" "\n\t"
+ "movl %%eax, 0x0(%%edx)" "\n\t" /* link */
+ "leal 1f, %%eax" "\n\t"
+ "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
+ "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
+ "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */
+ "movl $0, 0x10(%%edx)" "\n\t" /* status */
+
+ /*
+ * Link the TCLEXCEPTION_REGISTRATION on the chain.
+ */
+
+ "movl %%edx, %%fs:0" "\n\t"
+
+ /*
+ * Call CopyFile(nativeSrc, nativeDst, 0)
+ */
+
+ "movl %[copyFile], %%eax" "\n\t"
+ "pushl $0" "\n\t"
+ "pushl %%ebx" "\n\t"
+ "pushl %%ecx" "\n\t"
+ "call *%%eax" "\n\t"
+
+ /*
+ * Come here on normal exit. Recover the TCLEXCEPTION_REGISTRATION and
+ * put the status return from CopyFile into it.
+ */
+
+ "movl %%fs:0, %%edx" "\n\t"
+ "movl %%eax, 0x10(%%edx)" "\n\t"
+ "jmp 2f" "\n"
+
+ /*
+ * Come here on an exception. Recover the TCLEXCEPTION_REGISTRATION
+ */
+
+ "1:" "\t"
+ "movl %%fs:0, %%edx" "\n\t"
+ "movl 0x8(%%edx), %%edx" "\n\t"
+
+ /*
+ * Come here however we exited. Restore context from the
+ * TCLEXCEPTION_REGISTRATION in case the stack is unbalanced.
+ */
+
+ "2:" "\t"
+ "movl 0xc(%%edx), %%esp" "\n\t"
+ "movl 0x8(%%edx), %%ebp" "\n\t"
+ "movl 0x0(%%edx), %%eax" "\n\t"
+ "movl %%eax, %%fs:0" "\n\t"
+
+ :
+ /* No outputs */
+ :
+ [registration] "m" (registration),
+ [nativeDst] "m" (nativeDst),
+ [nativeSrc] "m" (nativeSrc),
+ [copyFile] "r" (CopyFile)
+ :
+ "%eax", "%ebx", "%ecx", "%edx", "memory"
+ );
+ if (registration.status != FALSE) {
+ retval = TCL_OK;
+ }
#else
+#ifndef HAVE_NO_SEH
__try {
-#endif /* HAVE_NO_SEH */
- if ((*tclWinProcs->copyFileProc)(nativeSrc, nativeDst, 0) != FALSE) {
+#endif
+ if (CopyFile(nativeSrc, nativeDst, 0) != FALSE) {
retval = TCL_OK;
}
-#ifdef HAVE_NO_SEH
- __asm__ __volatile__ (
- "jmp docopyfile_pop" "\n"
- "docopyfile_reentry:" "\n\t"
- "movl %%fs:0, %%eax" "\n\t"
- "movl 0x8(%%eax), %%esp" "\n\t"
- "movl 0x8(%%esp), %%ebp" "\n"
- "docopyfile_pop:" "\n\t"
- "movl (%%esp), %%eax" "\n\t"
- "movl %%eax, %%fs:0" "\n\t"
- "add $12, %%esp" "\n\t"
- :
- :
- : "%eax");
-
-# ifdef TCL_MEM_DEBUG
- __asm__ __volatile__ (
- "movl %%esp, %0" "\n\t"
- "movl %%ebp, %1" "\n\t"
- "movl %%fs:0, %2" "\n\t"
- : "=m"(RESTORED_ESP),
- "=m"(RESTORED_EBP),
- "=r"(RESTORED_HANDLER) );
-
- if (INITIAL_ESP != RESTORED_ESP) {
- Tcl_Panic("ESP restored incorrectly");
- }
- if (INITIAL_EBP != RESTORED_EBP) {
- Tcl_Panic("EBP restored incorrectly");
- }
- if (INITIAL_HANDLER != RESTORED_HANDLER) {
- Tcl_Panic("HANDLER restored incorrectly");
- }
-# endif /* TCL_MEM_DEBUG */
-#else
+#ifndef HAVE_NO_SEH
} __except (EXCEPTION_EXECUTE_HANDLER) {}
-#endif /* HAVE_NO_SEH */
+#endif
+#endif
- /*
- * Avoid using control flow statements in the SEH guarded block!
- */
if (retval != -1) {
- return retval;
+ return retval;
}
TclWinConvertError(GetLastError());
@@ -673,8 +675,8 @@ DoCopyFile(
if (Tcl_GetErrno() == EACCES) {
DWORD srcAttr, dstAttr;
- srcAttr = (*tclWinProcs->getFileAttributesProc)(nativeSrc);
- dstAttr = (*tclWinProcs->getFileAttributesProc)(nativeDst);
+ srcAttr = GetFileAttributes(nativeSrc);
+ dstAttr = GetFileAttributes(nativeDst);
if (srcAttr != 0xffffffff) {
if (dstAttr == 0xffffffff) {
dstAttr = 0;
@@ -683,25 +685,27 @@ DoCopyFile(
(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;
+ if (TclWinSymLinkCopyDirectory(nativeSrc, nativeDst)==0) {
+ return TCL_OK;
}
}
Tcl_SetErrno(EISDIR);
}
if (dstAttr & FILE_ATTRIBUTE_READONLY) {
- (*tclWinProcs->setFileAttributesProc)(nativeDst,
+ SetFileAttributes(nativeDst,
dstAttr & ~((DWORD)FILE_ATTRIBUTE_READONLY));
- if ((*tclWinProcs->copyFileProc)(nativeSrc, nativeDst, 0) != FALSE) {
+ if (CopyFile(nativeSrc, nativeDst,
+ 0) != FALSE) {
return TCL_OK;
}
+
/*
- * Still can't copy onto dst. Return that error, and
- * restore attributes of dst.
+ * Still can't copy onto dst. Return that error, and restore
+ * attributes of dst.
*/
TclWinConvertError(GetLastError());
- (*tclWinProcs->setFileAttributesProc)(nativeDst, dstAttr);
+ SetFileAttributes(nativeDst, dstAttr);
}
}
}
@@ -709,128 +713,101 @@ DoCopyFile(
}
/*
- *----------------------------------------------------------------------
- *
- * _except_docopyfile_handler --
- *
- * SEH exception handler for DoCopyFile.
- *
- * Results:
- * See DoCopyFile.
- *
- * Side effects:
- * See DoCopyFile.
- *
- *----------------------------------------------------------------------
- */
-#ifdef HAVE_NO_SEH
-static
-__attribute__ ((cdecl))
-EXCEPTION_DISPOSITION
-_except_docopyfile_handler(
- struct _EXCEPTION_RECORD *ExceptionRecord,
- void *EstablisherFrame,
- struct _CONTEXT *ContextRecord,
- void *DispatcherContext)
-{
- __asm__ __volatile__ (
- "jmp docopyfile_reentry");
- return 0; /* Function does not return */
-}
-#endif /* HAVE_NO_SEH */
-
-/*
*---------------------------------------------------------------------------
*
* TclpObjDeleteFile, TclpDeleteFile --
*
- * Removes a single file (not a directory).
+ * Removes a single file (not a directory).
*
* Results:
- * If the file was successfully deleted, returns TCL_OK. Otherwise
- * the return value is TCL_ERROR and errno is set to indicate the
- * error. Some possible values for errno are:
+ * If the file was successfully deleted, 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.
+ * EACCES: a parent directory can't be read and/or written.
* EISDIR: path is a directory.
* ENOENT: path doesn't exist or is "".
*
- * EACCES: exists an open file already referring to path.
+ * EACCES: exists an open file already referring to path.
* EACCES: path is a char device (nul:, com1:, etc.)
*
* Side effects:
- * The file is deleted, even if it is read-only.
+ * The file is deleted, even if it is read-only.
*
*---------------------------------------------------------------------------
*/
-int
-TclpObjDeleteFile(pathPtr)
- Tcl_Obj *pathPtr;
+int
+TclpObjDeleteFile(
+ Tcl_Obj *pathPtr)
{
return TclpDeleteFile(Tcl_FSGetNativePath(pathPtr));
}
int
TclpDeleteFile(
- CONST TCHAR *nativePath) /* Pathname of file to be removed (native). */
+ const void *nativePath) /* Pathname of file to be removed (native). */
{
DWORD attr;
+ const TCHAR *path = nativePath;
/*
- * The DeleteFile API acts differently under Win95/98 and NT
- * WRT NULL and "". Avoid passing these values.
+ * The DeleteFile API acts differently under Win95/98 and NT WRT NULL and
+ * "". Avoid passing these values.
*/
- if (nativePath == NULL || nativePath[0] == '\0') {
+ if (path == NULL || path[0] == '\0') {
Tcl_SetErrno(ENOENT);
return TCL_ERROR;
}
- if ((*tclWinProcs->deleteFileProc)(nativePath) != FALSE) {
+ if (DeleteFile(path) != FALSE) {
return TCL_OK;
}
TclWinConvertError(GetLastError());
if (Tcl_GetErrno() == EACCES) {
- attr = (*tclWinProcs->getFileAttributesProc)(nativePath);
+ attr = GetFileAttributes(path);
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;
+ /*
+ * It is a symbolic link - remove it.
+ */
+ if (TclWinSymLinkDelete(path, 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.
*/
Tcl_SetErrno(EISDIR);
} else if (attr & FILE_ATTRIBUTE_READONLY) {
- int res = (*tclWinProcs->setFileAttributesProc)(nativePath,
- attr & ~((DWORD)FILE_ATTRIBUTE_READONLY));
- if ((res != 0) && ((*tclWinProcs->deleteFileProc)(nativePath)
- != FALSE)) {
+ int res = SetFileAttributes(path,
+ attr & ~((DWORD) FILE_ATTRIBUTE_READONLY));
+
+ if ((res != 0) &&
+ (DeleteFile(path) != FALSE)) {
return TCL_OK;
}
TclWinConvertError(GetLastError());
if (res != 0) {
- (*tclWinProcs->setFileAttributesProc)(nativePath, attr);
+ SetFileAttributes(path, attr);
}
}
}
} else if (Tcl_GetErrno() == ENOENT) {
- attr = (*tclWinProcs->getFileAttributesProc)(nativePath);
+ attr = GetFileAttributes(path);
if (attr != 0xffffffff) {
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
- /*
- * Windows 95 reports removing a directory as ENOENT instead
- * of EISDIR.
+ /*
+ * Windows 95 reports removing a directory as ENOENT instead
+ * of EISDIR.
*/
Tcl_SetErrno(EISDIR);
@@ -853,43 +830,43 @@ TclpDeleteFile(
*
* TclpObjCreateDirectory --
*
- * 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.
+ * 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:
+ * 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.
+ * 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.
+ * A directory is created.
*
*---------------------------------------------------------------------------
*/
-int
-TclpObjCreateDirectory(pathPtr)
- Tcl_Obj *pathPtr;
+int
+TclpObjCreateDirectory(
+ Tcl_Obj *pathPtr)
{
return DoCreateDirectory(Tcl_FSGetNativePath(pathPtr));
}
static int
DoCreateDirectory(
- CONST TCHAR *nativePath) /* Pathname of directory to create (native). */
+ const TCHAR *nativePath) /* Pathname of directory to create (native). */
{
- DWORD error;
- if ((*tclWinProcs->createDirectoryProc)(nativePath, NULL) == 0) {
- error = GetLastError();
+ if (CreateDirectory(nativePath, NULL) == 0) {
+ DWORD error = GetLastError();
+
TclWinConvertError(error);
return TCL_ERROR;
- }
+ }
return TCL_OK;
}
@@ -898,32 +875,30 @@ DoCreateDirectory(
*
* TclpObjCopyDirectory --
*
- * 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.
+ * 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.
+ * 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.
+ * 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.
*
*---------------------------------------------------------------------------
*/
-int
-TclpObjCopyDirectory(srcPathPtr, destPathPtr, errorPtr)
- Tcl_Obj *srcPathPtr;
- Tcl_Obj *destPathPtr;
- Tcl_Obj **errorPtr;
+int
+TclpObjCopyDirectory(
+ Tcl_Obj *srcPathPtr,
+ Tcl_Obj *destPathPtr,
+ Tcl_Obj **errorPtr)
{
Tcl_DString ds;
Tcl_DString srcString, dstString;
@@ -931,8 +906,12 @@ TclpObjCopyDirectory(srcPathPtr, destPathPtr, errorPtr)
int ret;
normSrcPtr = Tcl_FSGetNormalizedPath(NULL,srcPathPtr);
- Tcl_WinUtfToTChar(Tcl_GetString(normSrcPtr), -1, &srcString);
normDestPtr = Tcl_FSGetNormalizedPath(NULL,destPathPtr);
+ if ((normSrcPtr == NULL) || (normDestPtr == NULL)) {
+ return TCL_ERROR;
+ }
+
+ Tcl_WinUtfToTChar(Tcl_GetString(normSrcPtr), -1, &srcString);
Tcl_WinUtfToTChar(Tcl_GetString(normDestPtr), -1, &dstString);
ret = TraverseWinTree(TraversalCopy, &srcString, &dstString, &ds);
@@ -941,9 +920,9 @@ TclpObjCopyDirectory(srcPathPtr, destPathPtr, errorPtr)
Tcl_DStringFree(&dstString);
if (ret != TCL_OK) {
- if (!strcmp(Tcl_DStringValue(&ds), Tcl_GetString(normSrcPtr))) {
+ if (!strcmp(Tcl_DStringValue(&ds), TclGetString(normSrcPtr))) {
*errorPtr = srcPathPtr;
- } else if (!strcmp(Tcl_DStringValue(&ds), Tcl_GetString(normDestPtr))) {
+ } else if (!strcmp(Tcl_DStringValue(&ds), TclGetString(normDestPtr))) {
*errorPtr = destPathPtr;
} else {
*errorPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1);
@@ -957,87 +936,92 @@ TclpObjCopyDirectory(srcPathPtr, destPathPtr, errorPtr)
/*
*----------------------------------------------------------------------
*
- * TclpObjRemoveDirectory, DoRemoveDirectory --
+ * TclpObjRemoveDirectory, DoRemoveDirectory --
*
* 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:
+ * 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.
+ * 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.
+ * 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
+ * Directory removed. If an error occurs, the error will be returned
* immediately, and remaining files will not be deleted.
*
*----------------------------------------------------------------------
*/
-int
-TclpObjRemoveDirectory(pathPtr, recursive, errorPtr)
- Tcl_Obj *pathPtr;
- int recursive;
- Tcl_Obj **errorPtr;
+int
+TclpObjRemoveDirectory(
+ Tcl_Obj *pathPtr,
+ int recursive,
+ Tcl_Obj **errorPtr)
{
Tcl_DString ds;
Tcl_Obj *normPtr = NULL;
int ret;
+
if (recursive) {
- /*
+ /*
* In the recursive case, the string rep is used to construct a
- * Tcl_DString which may be used extensively, so we can't
- * optimize this case easily.
+ * Tcl_DString which may be used extensively, so we can't optimize
+ * this case easily.
*/
+
Tcl_DString native;
normPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr);
+ if (normPtr == NULL) {
+ return TCL_ERROR;
+ }
Tcl_WinUtfToTChar(Tcl_GetString(normPtr), -1, &native);
ret = DoRemoveDirectory(&native, recursive, &ds);
Tcl_DStringFree(&native);
} else {
- ret = DoRemoveJustDirectory(Tcl_FSGetNativePath(pathPtr),
- 0, &ds);
+ ret = DoRemoveJustDirectory(Tcl_FSGetNativePath(pathPtr), 0, &ds);
}
+
if (ret != TCL_OK) {
- int len = Tcl_DStringLength(&ds);
- if (len > 0) {
+ if (Tcl_DStringLength(&ds) > 0) {
if (normPtr != NULL &&
!strcmp(Tcl_DStringValue(&ds), TclGetString(normPtr))) {
*errorPtr = pathPtr;
} else {
- *errorPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1);
+ *errorPtr = TclDStringToObj(&ds);
}
Tcl_IncrRefCount(*errorPtr);
}
Tcl_DStringFree(&ds);
}
+
return ret;
}
static int
DoRemoveJustDirectory(
- CONST TCHAR *nativePath, /* Pathname of directory to be removed
+ const TCHAR *nativePath, /* Pathname of directory to be removed
* (native). */
- int ignoreError, /* If non-zero, don't initialize the
- * errorPtr under some circumstances
- * on return. */
- Tcl_DString *errorPtr) /* If non-NULL, uninitialized or free
- * DString filled with UTF-8 name of file
- * causing error. */
+ int ignoreError, /* If non-zero, don't initialize the errorPtr
+ * under some circumstances on return. */
+ Tcl_DString *errorPtr) /* If non-NULL, uninitialized or free DString
+ * filled with UTF-8 name of file causing
+ * error. */
{
DWORD attr;
+
/*
- * The RemoveDirectory API acts differently under Win95/98 and NT
- * WRT NULL and "". Avoid passing these values.
+ * The RemoveDirectory API acts differently under Win95/98 and NT WRT NULL
+ * and "". Avoid passing these values.
*/
if (nativePath == NULL || nativePath[0] == '\0') {
@@ -1045,120 +1029,91 @@ DoRemoveJustDirectory(
goto end;
}
- attr = (*tclWinProcs->getFileAttributesProc)(nativePath);
+ attr = GetFileAttributes(nativePath);
if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
- /* It is a symbolic link -- remove it */
+ /*
+ * It is a symbolic link - remove it.
+ */
if (TclWinSymLinkDelete(nativePath, 0) == 0) {
return TCL_OK;
}
} else {
- /* Ordinary directory */
- if ((*tclWinProcs->removeDirectoryProc)(nativePath) != FALSE) {
+ /*
+ * Ordinary directory.
+ */
+
+ if (RemoveDirectory(nativePath) != FALSE) {
return TCL_OK;
}
}
-
+
TclWinConvertError(GetLastError());
if (Tcl_GetErrno() == EACCES) {
- attr = (*tclWinProcs->getFileAttributesProc)(nativePath);
+ attr = GetFileAttributes(nativePath);
if (attr != 0xffffffff) {
if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
- /*
- * Windows 95 reports calling RemoveDirectory on a file as an
+ /*
+ * Windows 95 reports calling RemoveDirectory on a file as an
* EACCES, not an ENOTDIR.
*/
-
+
Tcl_SetErrno(ENOTDIR);
goto end;
}
if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
- /* It is a symbolic link -- remove it */
+ /*
+ * 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) {
+ if (SetFileAttributes(nativePath,
+ attr) == FALSE) {
goto end;
}
- if ((*tclWinProcs->removeDirectoryProc)(nativePath) != FALSE) {
+ if (RemoveDirectory(nativePath) != FALSE) {
return TCL_OK;
}
TclWinConvertError(GetLastError());
- (*tclWinProcs->setFileAttributesProc)(nativePath,
+ SetFileAttributes(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) {
- CONST char *path, *find;
- HANDLE handle;
- WIN32_FIND_DATAA data;
- Tcl_DString buffer;
- int len;
-
- path = (CONST 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.
+ /*
+ * The caller depends on EEXIST to signify that the directory is not
+ * empty, not ENOTEMPTY.
*/
Tcl_SetErrno(EEXIST);
}
+
if ((ignoreError != 0) && (Tcl_GetErrno() == EEXIST)) {
- /*
- * If we're being recursive, this error may actually
- * be ok, so we don't want to initialise the errorPtr
- * yet.
+ /*
+ * If we're being recursive, this error may actually be ok, so we
+ * don't want to initialise the errorPtr yet.
*/
return TCL_ERROR;
}
- end:
+ end:
if (errorPtr != NULL) {
+ char *p;
Tcl_WinTCharToUtf(nativePath, -1, errorPtr);
+ p = Tcl_DStringValue(errorPtr);
+ for (; *p; ++p) {
+ if (*p == '\\') *p = '/';
+ }
}
return TCL_ERROR;
@@ -1168,21 +1123,22 @@ 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. */
+ 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. */
{
- int res = DoRemoveJustDirectory(Tcl_DStringValue(pathPtr), recursive,
- errorPtr);
-
+ int res = DoRemoveJustDirectory((const TCHAR *)Tcl_DStringValue(pathPtr), recursive,
+ errorPtr);
+
if ((res == TCL_ERROR) && (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);
} else {
return res;
@@ -1194,24 +1150,24 @@ DoRemoveDirectory(
*
* 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() .
+ * 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.
+ * 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.
+ * 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
+static int
TraverseWinTree(
TraversalProc *traverseProc,/* Function to call for every file and
* directory in source hierarchy. */
@@ -1220,59 +1176,56 @@ TraverseWinTree(
Tcl_DString *targetPtr, /* Pathname of directory to traverse in
* parallel with source directory (native),
* may be NULL. */
- Tcl_DString *errorPtr) /* If non-NULL, uninitialized or free
- * DString filled with UTF-8 name of file
- * causing error. */
+ Tcl_DString *errorPtr) /* If non-NULL, uninitialized or free DString
+ * filled with UTF-8 name of file causing
+ * error. */
{
DWORD sourceAttr;
TCHAR *nativeSource, *nativeTarget, *nativeErrfile;
- int result, found, sourceLen, targetLen, oldSourceLen, oldTargetLen;
+ int result, found, sourceLen, targetLen = 0, oldSourceLen, oldTargetLen;
HANDLE handle;
- WIN32_FIND_DATAT data;
+ WIN32_FIND_DATA data;
nativeErrfile = NULL;
result = TCL_OK;
oldTargetLen = 0; /* lint. */
nativeSource = (TCHAR *) Tcl_DStringValue(sourcePtr);
- nativeTarget = (TCHAR *) (targetPtr == NULL
- ? NULL : Tcl_DStringValue(targetPtr));
-
+ nativeTarget = (TCHAR *)
+ (targetPtr == NULL ? NULL : Tcl_DStringValue(targetPtr));
+
oldSourceLen = Tcl_DStringLength(sourcePtr);
- sourceAttr = (*tclWinProcs->getFileAttributesProc)(nativeSource);
+ sourceAttr = GetFileAttributes(nativeSource);
if (sourceAttr == 0xffffffff) {
nativeErrfile = nativeSource;
goto end;
}
-
+
if (sourceAttr & FILE_ATTRIBUTE_REPARSE_POINT) {
/*
* Process the symbolic link
*/
- return (*traverseProc)(nativeSource, nativeTarget,
- DOTREE_LINK, errorPtr);
+ return traverseProc(nativeSource, nativeTarget, DOTREE_LINK,
+ errorPtr);
}
-
+
if ((sourceAttr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
/*
* Process the regular file
*/
- return (*traverseProc)(nativeSource, nativeTarget, DOTREE_F, errorPtr);
+ return traverseProc(nativeSource, nativeTarget, 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);
- }
+ Tcl_DStringAppend(sourcePtr, (char *) TEXT("\\*.*"), 4 * sizeof(TCHAR) + 1);
+ Tcl_DStringSetLength(sourcePtr, Tcl_DStringLength(sourcePtr) - 1);
+
nativeSource = (TCHAR *) Tcl_DStringValue(sourcePtr);
- handle = (*tclWinProcs->findFirstFileProc)(nativeSource, &data);
+ handle = FindFirstFile(nativeSource, &data);
if (handle == INVALID_HANDLE_VALUE) {
- /*
- * Can't read directory
+ /*
+ * Can't read directory.
*/
TclWinConvertError(GetLastError());
@@ -1280,69 +1233,47 @@ TraverseWinTree(
goto end;
}
- nativeSource[oldSourceLen + 1] = '\0';
+ Tcl_DStringSetLength(sourcePtr, oldSourceLen + 1);
Tcl_DStringSetLength(sourcePtr, oldSourceLen);
- result = (*traverseProc)(nativeSource, nativeTarget, DOTREE_PRED, errorPtr);
+ result = traverseProc(nativeSource, nativeTarget, 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);
- }
+ sourceLen = oldSourceLen + sizeof(TCHAR);
+ Tcl_DStringAppend(sourcePtr, (char *) TEXT("\\"), sizeof(TCHAR) + 1);
+ Tcl_DStringSetLength(sourcePtr, sourceLen);
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);
- }
+ targetLen += sizeof(TCHAR);
+ Tcl_DStringAppend(targetPtr, (char *) TEXT("\\"), sizeof(TCHAR) + 1);
+ Tcl_DStringSetLength(targetPtr, targetLen);
}
found = 1;
- for ( ; found; found = (*tclWinProcs->findNextFileProc)(handle, &data)) {
+ for (; found; found = FindNextFile(handle, &data)) {
TCHAR *nativeName;
int len;
- if (tclWinProcs->useWide) {
- WCHAR *wp;
-
- wp = data.w.cFileName;
+ TCHAR *wp = data.cFileName;
+ if (*wp == '.') {
+ wp++;
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)) {
+ if (*wp == '\0') {
continue;
}
- nativeName = (TCHAR *) data.a.cFileName;
- len = strlen(data.a.cFileName);
}
+ nativeName = (TCHAR *) data.cFileName;
+ len = _tcslen(data.cFileName) * sizeof(TCHAR);
- /*
- * Append name after slash, and recurse on the file.
+ /*
+ * Append name after slash, and recurse on the file.
*/
Tcl_DStringAppend(sourcePtr, (char *) nativeName, len + 1);
@@ -1351,7 +1282,7 @@ TraverseWinTree(
Tcl_DStringAppend(targetPtr, (char *) nativeName, len + 1);
Tcl_DStringSetLength(targetPtr, Tcl_DStringLength(targetPtr) - 1);
}
- result = TraverseWinTree(traverseProc, sourcePtr, targetPtr,
+ result = TraverseWinTree(traverseProc, sourcePtr, targetPtr,
errorPtr);
if (result != TCL_OK) {
break;
@@ -1369,7 +1300,7 @@ TraverseWinTree(
FindClose(handle);
/*
- * Strip off the trailing slash we added
+ * Strip off the trailing slash we added.
*/
Tcl_DStringSetLength(sourcePtr, oldSourceLen + 1);
@@ -1384,11 +1315,12 @@ TraverseWinTree(
* files in that directory.
*/
- result = (*traverseProc)(Tcl_DStringValue(sourcePtr),
- (targetPtr == NULL ? NULL : Tcl_DStringValue(targetPtr)),
- DOTREE_POSTD, errorPtr);
+ result = traverseProc((const TCHAR *)Tcl_DStringValue(sourcePtr),
+ (const TCHAR *)(targetPtr == NULL ? NULL : Tcl_DStringValue(targetPtr)),
+ DOTREE_POSTD, errorPtr);
}
- end:
+
+ end:
if (nativeErrfile != NULL) {
TclWinConvertError(GetLastError());
if (errorPtr != NULL) {
@@ -1396,7 +1328,7 @@ TraverseWinTree(
}
result = TCL_ERROR;
}
-
+
return result;
}
@@ -1405,58 +1337,55 @@ TraverseWinTree(
*
* TraversalCopy
*
- * Called from TraverseUnixTree in order to execute a recursive
- * copy of a directory.
+ * Called from TraverseUnixTree in order to execute a recursive copy of a
+ * directory.
*
* Results:
- * Standard Tcl result.
+ * Standard Tcl result.
*
* Side effects:
- * Depending on the value of type, src may be copied to dst.
- *
+ * Depending on the value of type, src may be copied to dst.
+ *
*----------------------------------------------------------------------
*/
-static int
+static int
TraversalCopy(
- CONST TCHAR *nativeSrc, /* Source pathname to copy. */
- CONST TCHAR *nativeDst, /* Destination pathname of copy. */
+ const TCHAR *nativeSrc, /* Source pathname to copy. */
+ const TCHAR *nativeDst, /* Destination pathname of copy. */
int type, /* Reason for call - see TraverseWinTree() */
Tcl_DString *errorPtr) /* If non-NULL, initialized DString filled
* with UTF-8 name of file causing error. */
{
switch (type) {
- case DOTREE_F: {
- if (DoCopyFile(nativeSrc, nativeDst) == TCL_OK) {
- return TCL_OK;
- }
- break;
+ case DOTREE_F:
+ if (DoCopyFile(nativeSrc, nativeDst) == TCL_OK) {
+ return TCL_OK;
}
- case DOTREE_LINK: {
- if (TclWinSymLinkCopyDirectory(nativeSrc, nativeDst) == TCL_OK) {
- return TCL_OK;
- }
- break;
+ break;
+ case DOTREE_LINK:
+ if (TclWinSymLinkCopyDirectory(nativeSrc, nativeDst) == TCL_OK) {
+ return TCL_OK;
}
- case DOTREE_PRED: {
- if (DoCreateDirectory(nativeDst) == TCL_OK) {
- DWORD attr = (*tclWinProcs->getFileAttributesProc)(nativeSrc);
- if ((*tclWinProcs->setFileAttributesProc)(nativeDst, attr)
- != FALSE) {
- return TCL_OK;
- }
- TclWinConvertError(GetLastError());
+ break;
+ case DOTREE_PRED:
+ if (DoCreateDirectory(nativeDst) == TCL_OK) {
+ DWORD attr = GetFileAttributes(nativeSrc);
+
+ if (SetFileAttributes(nativeDst,
+ attr) != FALSE) {
+ return TCL_OK;
}
- break;
- }
- case DOTREE_POSTD: {
- return TCL_OK;
+ TclWinConvertError(GetLastError());
}
+ break;
+ case DOTREE_POSTD:
+ return TCL_OK;
}
/*
- * There shouldn't be a problem with src, because we already
- * checked it to get here.
+ * There shouldn't be a problem with src, because we already checked it to
+ * get here.
*/
if (errorPtr != NULL) {
@@ -1470,52 +1399,48 @@ TraversalCopy(
*
* TraversalDelete --
*
- * Called by procedure TraverseWinTree for every file and
- * directory that it encounters in a directory hierarchy. This
- * procedure unlinks files, and removes directories after all the
- * containing files have been processed.
+ * Called by function TraverseWinTree for every file and directory that
+ * it encounters in a directory hierarchy. This function unlinks files,
+ * and removes directories after all the containing files have been
+ * processed.
*
* Results:
- * Standard Tcl result.
+ * Standard Tcl result.
*
* Side effects:
- * Files or directory specified by src will be deleted. If an
- * error occurs, the windows error is converted to a Posix error
- * and errno is set accordingly.
+ * Files or directory specified by src will be deleted. If an error
+ * occurs, the windows error is converted to a Posix error and errno is
+ * set accordingly.
*
*----------------------------------------------------------------------
*/
static int
-TraversalDelete(
- CONST TCHAR *nativeSrc, /* Source pathname to delete. */
- CONST TCHAR *dstPtr, /* Not used. */
+TraversalDelete(
+ const TCHAR *nativeSrc, /* Source pathname to delete. */
+ const TCHAR *dstPtr, /* Not used. */
int type, /* Reason for call - see TraverseWinTree() */
Tcl_DString *errorPtr) /* If non-NULL, initialized DString filled
* with UTF-8 name of file causing error. */
{
switch (type) {
- case DOTREE_F: {
- if (TclpDeleteFile(nativeSrc) == TCL_OK) {
- return TCL_OK;
- }
- break;
- }
- case DOTREE_LINK: {
- if (DoRemoveJustDirectory(nativeSrc, 0, NULL) == TCL_OK) {
- return TCL_OK;
- }
- break;
+ case DOTREE_F:
+ if (TclpDeleteFile(nativeSrc) == TCL_OK) {
+ return TCL_OK;
}
- case DOTREE_PRED: {
+ break;
+ case DOTREE_LINK:
+ if (DoRemoveJustDirectory(nativeSrc, 0, NULL) == TCL_OK) {
return TCL_OK;
}
- case DOTREE_POSTD: {
- if (DoRemoveJustDirectory(nativeSrc, 0, NULL) == TCL_OK) {
- return TCL_OK;
- }
- break;
+ break;
+ case DOTREE_PRED:
+ return TCL_OK;
+ case DOTREE_POSTD:
+ if (DoRemoveJustDirectory(nativeSrc, 0, NULL) == TCL_OK) {
+ return TCL_OK;
}
+ break;
}
if (errorPtr != NULL) {
@@ -1532,11 +1457,11 @@ TraversalDelete(
* Sets the object result with the appropriate error.
*
* Results:
- * None.
+ * None.
*
* Side effects:
- * The interp's object result is set with an error message
- * based on the objIndex, fileName and errno.
+ * The interp's object result is set with an error message based on the
+ * objIndex, fileName and errno.
*
*----------------------------------------------------------------------
*/
@@ -1544,12 +1469,12 @@ TraversalDelete(
static void
StatError(
Tcl_Interp *interp, /* The interp that has the error */
- Tcl_Obj *fileName) /* The name of the file which caused the
+ Tcl_Obj *fileName) /* The name of the file which caused the
* error. */
{
TclWinConvertError(GetLastError());
- Tcl_AppendResult(interp, "could not read \"", Tcl_GetString(fileName),
- "\": ", Tcl_PosixError(interp), (char *) NULL);
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf("could not read \"%s\": %s",
+ TclGetString(fileName), Tcl_PosixError(interp)));
}
/*
@@ -1557,16 +1482,16 @@ StatError(
*
* GetWinFileAttributes --
*
- * Returns a Tcl_Obj containing the value of a file attribute.
- * This routine gets the -hidden, -readonly or -system attribute.
+ * Returns a Tcl_Obj containing the value of a file attribute. This
+ * routine gets the -hidden, -readonly or -system attribute.
*
* Results:
- * Standard Tcl result and a Tcl_Obj in attributePtrPtr. The object
- * will have ref count 0. If the return value is not TCL_OK,
- * attributePtrPtr is not touched.
+ * Standard Tcl result and a Tcl_Obj in attributePtrPtr. The object will
+ * have ref count 0. If the return value is not TCL_OK, attributePtrPtr
+ * is not touched.
*
* Side effects:
- * A new object is allocated if the file is valid.
+ * A new object is allocated if the file is valid.
*
*----------------------------------------------------------------------
*/
@@ -1575,15 +1500,15 @@ static int
GetWinFileAttributes(
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 *fileName, /* The name of the file. */
Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */
{
DWORD result;
- CONST TCHAR *nativeName;
+ const TCHAR *nativeName;
int attr;
-
+
nativeName = Tcl_FSGetNativePath(fileName);
- result = (*tclWinProcs->getFileAttributesProc)(nativeName);
+ result = GetFileAttributes(nativeName);
if (result == 0xffffffff) {
StatError(interp, fileName);
@@ -1592,31 +1517,39 @@ GetWinFileAttributes(
attr = (int)(result & attributeArray[objIndex]);
if ((objIndex == WIN_HIDDEN_ATTRIBUTE) && (attr != 0)) {
- /*
- * It is hidden. However there is a bug on some Windows
- * OSes in which root volumes (drives) formatted as NTFS
- * are declared hidden when they are not (and cannot be).
- *
+ /*
+ * It is hidden. However there is a bug on some Windows OSes in which
+ * root volumes (drives) formatted as NTFS are declared hidden when
+ * they are not (and cannot be).
+ *
* We test for, and fix that case, here.
*/
+
int len;
- char *str = Tcl_GetStringFromObj(fileName,&len);
+ const char *str = Tcl_GetStringFromObj(fileName,&len);
+
if (len < 4) {
if (len == 0) {
- /*
- * Not sure if this is possible, but we pass it on
- * anyway
+ /*
+ * Not sure if this is possible, but we pass it on anyway.
*/
} else if (len == 1 && (str[0] == '/' || str[0] == '\\')) {
- /* Path is pointing to the root volume */
+ /*
+ * Path is pointing to the root volume.
+ */
+
attr = 0;
- } else if ((str[1] == ':')
+ } else if ((str[1] == ':')
&& (len == 2 || (str[2] == '/' || str[2] == '\\'))) {
- /* Path is of the form 'x:' or 'x:/' or 'x:\' */
+ /*
+ * Path is of the form 'x:' or 'x:/' or 'x:\'
+ */
+
attr = 0;
}
}
}
+
*attributePtrPtr = Tcl_NewBooleanObj(attr);
return TCL_OK;
}
@@ -1626,21 +1559,20 @@ GetWinFileAttributes(
*
* ConvertFileNameFormat --
*
- * Returns a Tcl_Obj containing either the long or short version of the
+ * Returns a Tcl_Obj containing either the long or short version of the
* file name.
*
* Results:
- * Standard Tcl result and a Tcl_Obj in attributePtrPtr. The object
- * will have ref count 0. If the return value is not TCL_OK,
- * attributePtrPtr is not touched.
- *
- * Warning: if you pass this function a drive name like 'c:' it
- * will actually return the current working directory on that
- * drive. To avoid this, make sure the drive name ends in a
- * slash, like this 'c:/'.
+ * Standard Tcl result and a Tcl_Obj in attributePtrPtr. The object will
+ * have ref count 0. If the return value is not TCL_OK, attributePtrPtr
+ * is not touched.
+ *
+ * Warning: if you pass this function a drive name like 'c:' it will
+ * actually return the current working directory on that drive. To avoid
+ * this, make sure the drive name ends in a slash, like this 'c:/'.
*
* Side effects:
- * A new object is allocated if the file is valid.
+ * A new object is allocated if the file is valid.
*
*----------------------------------------------------------------------
*/
@@ -1649,7 +1581,7 @@ static int
ConvertFileNameFormat(
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 *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. */
{
@@ -1657,75 +1589,84 @@ ConvertFileNameFormat(
Tcl_Obj *splitPath;
splitPath = Tcl_FSSplitPath(fileName, &pathc);
-
+
if (splitPath == NULL || pathc == 0) {
if (interp != NULL) {
- Tcl_AppendResult(interp, "could not read \"",
- Tcl_GetString(fileName), "\": no such file or directory",
- (char *) NULL);
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "could not read \"%s\": no such file or directory",
+ Tcl_GetString(fileName)));
+ errno = ENOENT;
+ Tcl_PosixError(interp);
}
goto cleanup;
}
-
+
/*
- * We will decrement this again at the end. It is safer to
- * do this in case any of the calls below retain a reference
- * to splitPath.
+ * We will decrement this again at the end. It is safer to do this in
+ * case any of the calls below retain a reference to splitPath.
*/
+
Tcl_IncrRefCount(splitPath);
for (i = 0; i < pathc; i++) {
Tcl_Obj *elt;
char *pathv;
int pathLen;
+
Tcl_ListObjIndex(NULL, splitPath, i, &elt);
-
+
pathv = Tcl_GetStringFromObj(elt, &pathLen);
if ((pathv[0] == '/') || ((pathLen == 3) && (pathv[1] == ':'))
|| (strcmp(pathv, ".") == 0) || (strcmp(pathv, "..") == 0)) {
/*
* Handle "/", "//machine/export", "c:/", "." or ".." by just
- * copying the string literally. Uppercase the drive letter,
- * just because it looks better under Windows to do so.
+ * copying the string literally. Uppercase the drive letter, just
+ * because it looks better under Windows to do so.
+ */
+
+ simple:
+ /*
+ * Here we are modifying the string representation in place.
+ *
+ * I believe this is legal, since this won't affect any file
+ * representation this thing may have.
*/
- simple:
- /* Here we are modifying the string representation in place */
- /* I believe this is legal, since this won't affect any
- * file representation this thing may have. */
pathv[0] = (char) Tcl_UniCharToUpper(UCHAR(pathv[0]));
} else {
Tcl_Obj *tempPath;
Tcl_DString ds;
Tcl_DString dsTemp;
- TCHAR *nativeName;
- char *tempString;
+ const TCHAR *nativeName;
+ const char *tempString;
int tempLen;
- WIN32_FIND_DATAT data;
+ WIN32_FIND_DATA data;
HANDLE handle;
DWORD attr;
tempPath = Tcl_FSJoinPath(splitPath, i+1);
Tcl_IncrRefCount(tempPath);
- /*
- * We'd like to call Tcl_FSGetNativePath(tempPath)
- * but that is likely to lead to infinite loops
+
+ /*
+ * We'd like to call Tcl_FSGetNativePath(tempPath) but that is
+ * likely to lead to infinite loops.
*/
+
Tcl_DStringInit(&ds);
tempString = Tcl_GetStringFromObj(tempPath,&tempLen);
nativeName = Tcl_WinUtfToTChar(tempString, tempLen, &ds);
Tcl_DecrRefCount(tempPath);
- handle = (*tclWinProcs->findFirstFileProc)(nativeName, &data);
+ handle = FindFirstFile(nativeName, &data);
if (handle == INVALID_HANDLE_VALUE) {
/*
- * FindFirstFile() doesn't like root directories. We
- * would only get a root directory here if the caller
- * specified "c:" or "c:." and the current directory on the
- * drive was the root directory
+ * FindFirstFile() doesn't like root directories. We would
+ * only get a root directory here if the caller specified "c:"
+ * or "c:." and the current directory on the drive was the
+ * root directory
*/
- attr = (*tclWinProcs->getFileAttributesProc)(nativeName);
- if ((attr != 0xFFFFFFFF) && (attr & FILE_ATTRIBUTE_DIRECTORY)) {
+ attr = GetFileAttributes(nativeName);
+ if ((attr!=0xFFFFFFFF) && (attr & FILE_ATTRIBUTE_DIRECTORY)) {
Tcl_DStringFree(&ds);
goto simple;
}
@@ -1738,37 +1679,24 @@ ConvertFileNameFormat(
}
goto cleanup;
}
- if (tclWinProcs->useWide) {
- nativeName = (TCHAR *) data.w.cAlternateFileName;
- if (longShort) {
- if (data.w.cFileName[0] != '\0') {
- nativeName = (TCHAR *) data.w.cFileName;
- }
- } else {
- if (data.w.cAlternateFileName[0] == '\0') {
- nativeName = (TCHAR *) data.w.cFileName;
- }
+ nativeName = data.cAlternateFileName;
+ if (longShort) {
+ if (data.cFileName[0] != '\0') {
+ nativeName = data.cFileName;
}
} else {
- nativeName = (TCHAR *) data.a.cAlternateFileName;
- if (longShort) {
- if (data.a.cFileName[0] != '\0') {
- nativeName = (TCHAR *) data.a.cFileName;
- }
- } else {
- if (data.a.cAlternateFileName[0] == '\0') {
- nativeName = (TCHAR *) data.a.cFileName;
- }
+ if (data.cAlternateFileName[0] == '\0') {
+ nativeName = (TCHAR *) data.cFileName;
}
}
/*
- * Purify reports a extraneous UMR in Tcl_WinTCharToUtf() 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 purify doesn't complain about the first line,
- * but does complain about the second.
+ * Purify reports a extraneous UMR in Tcl_WinTCharToUtf() 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
+ * purify doesn't complain about the first line, but does complain
+ * about the second.
*
* fprintf(stderr, "%d\n", data.w.cAlternateFileName[0]);
* fprintf(stderr, "%d\n", ((WCHAR *) nativeName)[0]);
@@ -1776,32 +1704,36 @@ ConvertFileNameFormat(
Tcl_DStringInit(&dsTemp);
Tcl_WinTCharToUtf(nativeName, -1, &dsTemp);
- /* Deal with issues of tildes being absolute */
+ Tcl_DStringFree(&ds);
+
+ /*
+ * Deal with issues of tildes being absolute.
+ */
+
if (Tcl_DStringValue(&dsTemp)[0] == '~') {
- tempPath = Tcl_NewStringObj("./",2);
- Tcl_AppendToObj(tempPath, Tcl_DStringValue(&dsTemp),
- Tcl_DStringLength(&dsTemp));
+ TclNewLiteralStringObj(tempPath, "./");
+ Tcl_AppendToObj(tempPath, Tcl_DStringValue(&dsTemp),
+ Tcl_DStringLength(&dsTemp));
+ Tcl_DStringFree(&dsTemp);
} else {
- tempPath = Tcl_NewStringObj(Tcl_DStringValue(&dsTemp),
- Tcl_DStringLength(&dsTemp));
+ tempPath = TclDStringToObj(&dsTemp);
}
Tcl_ListObjReplace(NULL, splitPath, i, 1, 1, &tempPath);
- Tcl_DStringFree(&ds);
- Tcl_DStringFree(&dsTemp);
FindClose(handle);
}
}
*attributePtrPtr = Tcl_FSJoinPath(splitPath, -1);
-
+
if (splitPath != NULL) {
- /*
- * Unfortunately, the object we will return may have its only
- * refCount as part of the list splitPath. This means if
- * we free splitPath, the object will disappear. So, we
- * have to be very careful here. Unfortunately this means
- * we must manipulate the object's refCount directly.
+ /*
+ * Unfortunately, the object we will return may have its only refCount
+ * as part of the list splitPath. This means if we free splitPath, the
+ * object will disappear. So, we have to be very careful here.
+ * Unfortunately this means we must manipulate the object's refCount
+ * directly.
*/
+
Tcl_IncrRefCount(*attributePtrPtr);
Tcl_DecrRefCount(splitPath);
--(*attributePtrPtr)->refCount;
@@ -1812,7 +1744,7 @@ ConvertFileNameFormat(
if (splitPath != NULL) {
Tcl_DecrRefCount(splitPath);
}
-
+
return TCL_ERROR;
}
@@ -1821,16 +1753,15 @@ ConvertFileNameFormat(
*
* GetWinFileLongName --
*
- * Returns a Tcl_Obj containing the long version of the file
- * name.
+ * Returns a Tcl_Obj containing the long version of the file name.
*
* Results:
- * Standard Tcl result and a Tcl_Obj in attributePtrPtr. The object
- * will have ref count 0. If the return value is not TCL_OK,
- * attributePtrPtr is not touched.
+ * Standard Tcl result and a Tcl_Obj in attributePtrPtr. The object will
+ * have ref count 0. If the return value is not TCL_OK, attributePtrPtr
+ * is not touched.
*
* Side effects:
- * A new object is allocated if the file is valid.
+ * A new object is allocated if the file is valid.
*
*----------------------------------------------------------------------
*/
@@ -1839,10 +1770,11 @@ static int
GetWinFileLongName(
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 *fileName, /* The name of the file. */
Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */
{
- return ConvertFileNameFormat(interp, objIndex, fileName, 1, attributePtrPtr);
+ return ConvertFileNameFormat(interp, objIndex, fileName, 1,
+ attributePtrPtr);
}
/*
@@ -1850,16 +1782,15 @@ GetWinFileLongName(
*
* GetWinFileShortName --
*
- * Returns a Tcl_Obj containing the short version of the file
- * name.
+ * Returns a Tcl_Obj containing the short version of the file name.
*
* Results:
- * Standard Tcl result and a Tcl_Obj in attributePtrPtr. The object
- * will have ref count 0. If the return value is not TCL_OK,
- * attributePtrPtr is not touched.
+ * Standard Tcl result and a Tcl_Obj in attributePtrPtr. The object will
+ * have ref count 0. If the return value is not TCL_OK, attributePtrPtr
+ * is not touched.
*
* Side effects:
- * A new object is allocated if the file is valid.
+ * A new object is allocated if the file is valid.
*
*----------------------------------------------------------------------
*/
@@ -1868,10 +1799,11 @@ static int
GetWinFileShortName(
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 *fileName, /* The name of the file. */
Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */
{
- return ConvertFileNameFormat(interp, objIndex, fileName, 0, attributePtrPtr);
+ return ConvertFileNameFormat(interp, objIndex, fileName, 0,
+ attributePtrPtr);
}
/*
@@ -1879,14 +1811,14 @@ GetWinFileShortName(
*
* SetWinFileAttributes --
*
- * Set the file attributes to the value given by attributePtr.
- * This routine sets the -hidden, -readonly, or -system attributes.
+ * Set the file attributes to the value given by attributePtr. This
+ * routine sets the -hidden, -readonly, or -system attributes.
*
* Results:
- * Standard TCL error.
+ * Standard TCL error.
*
* Side effects:
- * The file's attribute is set.
+ * The file's attribute is set.
*
*----------------------------------------------------------------------
*/
@@ -1895,16 +1827,15 @@ static int
SetWinFileAttributes(
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 *fileName, /* The name of the file. */
Tcl_Obj *attributePtr) /* The new value of the attribute. */
{
- DWORD fileAttributes;
- int yesNo;
- int result;
- CONST TCHAR *nativeName;
+ DWORD fileAttributes, old;
+ int yesNo, result;
+ const TCHAR *nativeName;
nativeName = Tcl_FSGetNativePath(fileName);
- fileAttributes = (*tclWinProcs->getFileAttributesProc)(nativeName);
+ fileAttributes = old = GetFileAttributes(nativeName);
if (fileAttributes == 0xffffffff) {
StatError(interp, fileName);
@@ -1922,7 +1853,8 @@ SetWinFileAttributes(
fileAttributes &= ~(attributeArray[objIndex]);
}
- if (!(*tclWinProcs->setFileAttributesProc)(nativeName, fileAttributes)) {
+ if ((fileAttributes != old)
+ && !SetFileAttributes(nativeName, fileAttributes)) {
StatError(interp, fileName);
return TCL_ERROR;
}
@@ -1935,14 +1867,13 @@ SetWinFileAttributes(
*
* SetWinFileLongName --
*
- * The attribute in question is a readonly attribute and cannot
- * be set.
+ * The attribute in question is a readonly attribute and cannot be set.
*
* Results:
- * TCL_ERROR
+ * TCL_ERROR
*
* Side effects:
- * The object result is set to a pertinent error message.
+ * The object result is set to a pertinent error message.
*
*----------------------------------------------------------------------
*/
@@ -1951,16 +1882,16 @@ static int
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 *fileName, /* The name of the file. */
Tcl_Obj *attributePtr) /* The new value of the attribute. */
{
- Tcl_AppendResult(interp, "cannot set attribute \"",
- tclpFileAttrStrings[objIndex], "\" for file \"",
- Tcl_GetString(fileName), "\": attribute is readonly",
- (char *) NULL);
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "cannot set attribute \"%s\" for file \"%s\": attribute is readonly",
+ tclpFileAttrStrings[objIndex], Tcl_GetString(fileName)));
+ errno = EINVAL;
+ Tcl_PosixError(interp);
return TCL_ERROR;
}
-
/*
*---------------------------------------------------------------------------
@@ -1978,7 +1909,7 @@ CannotSetAttribute(
*---------------------------------------------------------------------------
*/
-Tcl_Obj*
+Tcl_Obj *
TclpObjListVolumes(void)
{
Tcl_Obj *resultPtr, *elemPtr;
@@ -1997,11 +1928,11 @@ TclpObjListVolumes(void)
if (GetLogicalDriveStringsA(sizeof(buf), buf) == 0) {
/*
* GetVolumeInformation() 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 GetVolumeInformation()
- * to return when pinging an empty floppy drive, another reason to
- * try to avoid calling it.
+ * 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 GetVolumeInformation() to
+ * return when pinging an empty floppy drive, another reason to try to
+ * avoid calling it.
*/
buf[1] = ':';
@@ -2023,7 +1954,15 @@ TclpObjListVolumes(void)
Tcl_ListObjAppendElement(NULL, resultPtr, elemPtr);
}
}
-
+
Tcl_IncrRefCount(resultPtr);
return resultPtr;
}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 78
+ * End:
+ */