Tcl Source Code

Check-in [02224b9ef6]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:[Bug 2893771] Teach [file stat] to handle locked files. This stops [file exists] from returning false for files that exist but are locked by resorting to FindFirstFile when GetFileAttributes fails.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 02224b9ef68c29ea42fef039fb0f0ba4f03004e3
User & Date: patthoyts 2009-11-24 00:08:26
Context
2009-11-24
12:00
Ensure that destroying an object in a constructor doesn't crash. [Bug 2903011] check-in: 56012b12ec user: dkf tags: trunk
00:08
[Bug 2893771] Teach [file stat] to handle locked files. This stops [file exists] from returning fals... check-in: 02224b9ef6 user: patthoyts tags: trunk
2009-11-23
23:06
library/tclIndex (regenerated) to reflect various changes in safe.tcl and other library files. check-in: 11ccf25491 user: nijtmans tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ChangeLog.






1
2
3
4
5
6
7





2009-11-23  Jan Nijtmans  <[email protected]>

	* library/tclIndex  (regenerated) to reflect various changes
	                    in safe.tcl and other files.

2009-11-23  Kevin Kenny  <[email protected]>

>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
2009-11-24  Pat Thoyts  <[email protected]>

	* tests/fCmd.test:  [Bug 2893771] Teach [file stat] to handle locked
	* win/tclWinFile.c: files so that [file exists] no longer lies.

2009-11-23  Jan Nijtmans  <[email protected]>

	* library/tclIndex  (regenerated) to reflect various changes
	                    in safe.tcl and other files.

2009-11-23  Kevin Kenny  <[email protected]>

Changes to tests/fCmd.test.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# This file tests the tclFCmd.c file.
#
# This file contains a collection of tests for one or more of the Tcl built-in
# commands. Sourcing this file into Tcl runs the tests and generates output
# for errors. No output means no errors were found.
#
# Copyright (c) 1996-1997 Sun Microsystems, Inc.
# Copyright (c) 1999 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: fCmd.test,v 1.69 2009/11/23 22:14:27 kennykb Exp $
#

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# This file tests the tclFCmd.c file.
#
# This file contains a collection of tests for one or more of the Tcl built-in
# commands. Sourcing this file into Tcl runs the tests and generates output
# for errors. No output means no errors were found.
#
# Copyright (c) 1996-1997 Sun Microsystems, Inc.
# Copyright (c) 1999 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: fCmd.test,v 1.70 2009/11/24 00:08:27 patthoyts Exp $
#

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560




2561
2562

2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574

test fCmd-30.1 {file writable on 'My Documents'} -setup {
    # Get the localized version of the folder name by looking in the registry.
    set mydocsname [registry get {HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders} Personal]
} -constraints {2000orNewer reg} -body {
    file writable $mydocsname
} -result 1
test fCmd-30.2 {file readable on 'NTUSER.DAT'} -constraints {2000orNewer knownBug} -body {
    # Apparently the OS has this file open with exclusive permissions Windows
    # doesn't provide any way to determine that fact without actually trying
    # to open the file (open NTUSER.dat r), which fails. Hence this isn't
    # really a knownBug in Tcl, but an OS limitation. But, perhaps in the
    # future that limitation will be lifted.




    if {[file exists "~/NTUSER.DAT"]} {
	return [file readable "~/NTUSER.DAT"]

    }
    return 0
} -result {0}

# cleanup
cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:







|
|
|
|
|
|
>
>
>
>
|
|
>

|
|









2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579

test fCmd-30.1 {file writable on 'My Documents'} -setup {
    # Get the localized version of the folder name by looking in the registry.
    set mydocsname [registry get {HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders} Personal]
} -constraints {2000orNewer reg} -body {
    file writable $mydocsname
} -result 1
test fCmd-30.2 {file readable on 'NTUSER.DAT'} -constraints {2000orNewer} -body {
    expr {[info exists env(USERPROFILE)]
          && [file exists $env(USERPROFILE)/NTUSER.DAT]
          && [file readable $env(USERPROFILE)/NTUSER.DAT]}

} -result {1}
test fCmd-30.3 {file readable on 'pagefile.sys'} -constraints {2000orNewer} -body {
    set r {}
    if {[info exists env(SystemDrive)]} {
        set path $env(SystemDrive)/pagefile.sys
        lappend r exists [file exists $path]
        lappend r readable [file readable $path]
        lappend r stat [catch {file stat $path a} e] $e
    }
    return $r
} -result {exists 1 readable 0 stat 0 {}}

# cleanup
cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:

Changes to win/tclWinFile.c.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * tclWinFile.c --
 *
 *	This file contains temporary wrappers around UNIX file handling
 *	functions. These wrappers map the UNIX functions to Win32 HANDLE-style
 *	files, which can be manipulated through the Win32 console redirection
 *	interfaces.
 *
 * Copyright (c) 1995-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: tclWinFile.c,v 1.98 2009/03/18 17:08:11 dgp Exp $
 */

/* #define _WIN32_WINNT	0x0500 */

#include "tclWinInt.h"
#include "tclFileSystem.h"
#include <winioctl.h>













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * tclWinFile.c --
 *
 *	This file contains temporary wrappers around UNIX file handling
 *	functions. These wrappers map the UNIX functions to Win32 HANDLE-style
 *	files, which can be manipulated through the Win32 console redirection
 *	interfaces.
 *
 * Copyright (c) 1995-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: tclWinFile.c,v 1.99 2009/11/24 00:08:27 patthoyts Exp $
 */

/* #define _WIN32_WINNT	0x0500 */

#include "tclWinInt.h"
#include "tclFileSystem.h"
#include <winioctl.h>
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
    }

    /*
     * Make sure source file doesn't exist.
     */

    attr = tclWinProcs->getFileAttributesProc(linkSourcePath);
    if (attr != 0xffffffff) {
	Tcl_SetErrno(EEXIST);
	return -1;
    }

    /*
     * Get the full path referenced by the source file/directory.
     */







|







243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
    }

    /*
     * Make sure source file doesn't exist.
     */

    attr = tclWinProcs->getFileAttributesProc(linkSourcePath);
    if (attr != INVALID_FILE_ATTRIBUTES) {
	Tcl_SetErrno(EEXIST);
	return -1;
    }

    /*
     * Get the full path referenced by the source file/directory.
     */
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
    }

    /*
     * Check the target.
     */

    attr = tclWinProcs->getFileAttributesProc(linkTargetPath);
    if (attr == 0xffffffff) {
	/*
	 * The target doesn't exist.
	 */

	TclWinConvertError(GetLastError());
	return -1;








|







267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
    }

    /*
     * Check the target.
     */

    attr = tclWinProcs->getFileAttributesProc(linkTargetPath);
    if (attr == INVALID_FILE_ATTRIBUTES) {
	/*
	 * The target doesn't exist.
	 */

	TclWinConvertError(GetLastError());
	return -1;

364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
    }

    /*
     * Make sure source file does exist.
     */

    attr = tclWinProcs->getFileAttributesProc(linkSourcePath);
    if (attr == 0xffffffff) {
	/*
	 * The source doesn't exist.
	 */

	TclWinConvertError(GetLastError());
	return NULL;








|







364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
    }

    /*
     * Make sure source file does exist.
     */

    attr = tclWinProcs->getFileAttributesProc(linkSourcePath);
    if (attr == INVALID_FILE_ATTRIBUTES) {
	/*
	 * The source doesn't exist.
	 */

	TclWinConvertError(GetLastError());
	return NULL;

908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
	    DWORD attr;
	    const char *str = Tcl_GetStringFromObj(norm,&len);

	    native = (const TCHAR *) Tcl_FSGetNativePath(pathPtr);

	    if (tclWinProcs->getFileAttributesExProc == NULL) {
		attr = tclWinProcs->getFileAttributesProc(native);
		if (attr == 0xffffffff) {
		    return TCL_OK;
		}
	    } else {
		WIN32_FILE_ATTRIBUTE_DATA data;

		if (tclWinProcs->getFileAttributesExProc(native,
			GetFileExInfoStandard, &data) != TRUE) {







|







908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
	    DWORD attr;
	    const char *str = Tcl_GetStringFromObj(norm,&len);

	    native = (const TCHAR *) Tcl_FSGetNativePath(pathPtr);

	    if (tclWinProcs->getFileAttributesExProc == NULL) {
		attr = tclWinProcs->getFileAttributesProc(native);
		if (attr == INVALID_FILE_ATTRIBUTES) {
		    return TCL_OK;
		}
	    } else {
		WIN32_FILE_ATTRIBUTE_DATA data;

		if (tclWinProcs->getFileAttributesExProc(native,
			GetFileExInfoStandard, &data) != TRUE) {
960
961
962
963
964
965
966

967
968
969
970
971
972
973
974

	native = Tcl_FSGetNativePath(pathPtr);
	if (native == NULL) {
	    return TCL_OK;
	}
	attr = tclWinProcs->getFileAttributesProc(native);


	if ((attr == 0xffffffff) || ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
	    return TCL_OK;
	}

	/*
	 * Build up the directory name for searching, including a trailing
	 * directory separator.
	 */







>
|







960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975

	native = Tcl_FSGetNativePath(pathPtr);
	if (native == NULL) {
	    return TCL_OK;
	}
	attr = tclWinProcs->getFileAttributesProc(native);

	if ((attr == INVALID_FILE_ATTRIBUTES) 
	    || ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
	    return TCL_OK;
	}

	/*
	 * Build up the directory name for searching, including a trailing
	 * directory separator.
	 */
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554







1555
1556

1557
1558
1559
1560
1561
1562
1563
    const TCHAR *nativePath,	/* Path of file to access, native encoding. */
    int mode)			/* Permission setting. */
{
    DWORD attr;

    attr = tclWinProcs->getFileAttributesProc(nativePath);

    if (attr == 0xffffffff) {
	/*
	 * File doesn't exist.
	 */








	TclWinConvertError(GetLastError());
	return -1;

    }

    if ((mode & W_OK)
	    && (tclWinProcs->getFileSecurityProc == NULL)
	    && (attr & FILE_ATTRIBUTE_READONLY)) {
	/*
	 * We don't have the advanced 'getFileSecurityProc', and our







|

|


>
>
>
>
>
>
>
|
|
>







1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
    const TCHAR *nativePath,	/* Path of file to access, native encoding. */
    int mode)			/* Permission setting. */
{
    DWORD attr;

    attr = tclWinProcs->getFileAttributesProc(nativePath);

    if (attr == INVALID_FILE_ATTRIBUTES) {
	/*
	 * File might not exist.
	 */

	WIN32_FIND_DATAT ffd;
	HANDLE hFind;
	hFind = tclWinProcs->findFirstFileProc(nativePath, &ffd);
	if (hFind != INVALID_HANDLE_VALUE) {
	    attr = ffd.w.dwFileAttributes;
	    FindClose(hFind);
	} else {
	    TclWinConvertError(GetLastError());
	    return -1;
	}
    }

    if ((mode & W_OK)
	    && (tclWinProcs->getFileSecurityProc == NULL)
	    && (attr & FILE_ATTRIBUTE_READONLY)) {
	/*
	 * We don't have the advanced 'getFileSecurityProc', and our
2089
2090
2091
2092
2093
2094
2095












2096
2097

2098
2099
2100
2101
2102
2103
2104
	 * Fall back on the less capable routines. This means no nlink or ino.
	 */

	WIN32_FILE_ATTRIBUTE_DATA data;

	if (tclWinProcs->getFileAttributesExProc(nativePath,
		GetFileExInfoStandard, &data) != TRUE) {












	    Tcl_SetErrno(ENOENT);
	    return -1;

	}

	attr = data.dwFileAttributes;

	statPtr->st_size = ((Tcl_WideInt) data.nFileSizeLow) |
		(((Tcl_WideInt) data.nFileSizeHigh) << 32);
	statPtr->st_atime = ToCTime(data.ftLastAccessTime);







>
>
>
>
>
>
>
>
>
>
>
>
|
|
>







2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
	 * Fall back on the less capable routines. This means no nlink or ino.
	 */

	WIN32_FILE_ATTRIBUTE_DATA data;

	if (tclWinProcs->getFileAttributesExProc(nativePath,
		GetFileExInfoStandard, &data) != TRUE) {

	    /*
	     * We might have just been denied access
	     */
	    
	    WIN32_FIND_DATAT ffd;
	    HANDLE hFind;
	    hFind = tclWinProcs->findFirstFileProc(nativePath, &ffd);
	    if (hFind != INVALID_HANDLE_VALUE) {
		memcpy(&data, &ffd, sizeof(data));
		FindClose(hFind);
	    } else {
		Tcl_SetErrno(ENOENT);
		return -1;
	    }
	}

	attr = data.dwFileAttributes;

	statPtr->st_size = ((Tcl_WideInt) data.nFileSizeLow) |
		(((Tcl_WideInt) data.nFileSizeHigh) << 32);
	statPtr->st_atime = ToCTime(data.ftLastAccessTime);