Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Bugfix [ae61a67192]. file {stat, type, size} etc. support for built-in special Windows files/devices like CON. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | core-8-6-branch |
Files: | files | file ages | folders |
SHA1: |
5e0bded74856ca53550700ef3181fd6e |
User & Date: | ashok 2016-07-09 08:27:00 |
References
2018-07-16
| ||
10:33 | • Ticket [525ccacaef] win: strange discrepancy regarding Tcl_FSStat (all file sub-commands using GetStatBuf) corresponding path by "built-in Windows names with dir path and extension" status still Open with 3 other changes artifact: 2627bf86e2 user: sebres | |
2016-07-09
| ||
08:30 | • Ticket [ae61a67192] file type on Windows generates error for built-in file names like CON status still Open with 3 other changes artifact: e6265268a9 user: apnadkarni | |
Context
2016-07-09
| ||
11:13 | Bugfix [3613671]. file owned implementation for Windows. check-in: 4fe9800f92 user: ashok tags: core-8-6-branch | |
08:27 | Bugfix [ae61a67192]. file {stat, type, size} etc. support for built-in special Windows files/devices... check-in: 5e0bded748 user: ashok tags: core-8-6-branch | |
2016-07-08
| ||
14:19 | Repair some memory corruption problems in EnsembleCmdRep. check-in: 65348900a8 user: dgp tags: core-8-6-branch | |
Changes
Changes to generic/tclCmdAH.c.
︙ | ︙ | |||
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 | if (objc < 2 || objc > 3) { Tcl_WrongNumArgs(interp, 1, objv, "name ?time?"); return TCL_ERROR; } if (GetStatBuf(interp, objv[1], Tcl_FSStat, &buf) != TCL_OK) { return TCL_ERROR; } if (objc == 3) { /* * Need separate variable for reading longs from an object on 64-bit * platforms. [Bug 698146] */ long newTime; | > > > > > > > > > > | 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 | if (objc < 2 || objc > 3) { Tcl_WrongNumArgs(interp, 1, objv, "name ?time?"); return TCL_ERROR; } if (GetStatBuf(interp, objv[1], Tcl_FSStat, &buf) != TCL_OK) { return TCL_ERROR; } #if defined(_WIN32) /* We use a value of 0 to indicate the access time not available */ if (buf.st_atime == 0) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "could not get access time for file \"%s\"", TclGetString(objv[1]))); return TCL_ERROR; } #endif if (objc == 3) { /* * Need separate variable for reading longs from an object on 64-bit * platforms. [Bug 698146] */ long newTime; |
︙ | ︙ | |||
1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 | if (objc < 2 || objc > 3) { Tcl_WrongNumArgs(interp, 1, objv, "name ?time?"); return TCL_ERROR; } if (GetStatBuf(interp, objv[1], Tcl_FSStat, &buf) != TCL_OK) { return TCL_ERROR; } if (objc == 3) { /* * Need separate variable for reading longs from an object on 64-bit * platforms. [Bug 698146] */ long newTime; | > > > > > > > > > | 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 | if (objc < 2 || objc > 3) { Tcl_WrongNumArgs(interp, 1, objv, "name ?time?"); return TCL_ERROR; } if (GetStatBuf(interp, objv[1], Tcl_FSStat, &buf) != TCL_OK) { return TCL_ERROR; } #if defined(_WIN32) /* We use a value of 0 to indicate the modification time not available */ if (buf.st_mtime == 0) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "could not get modification time for file \"%s\"", TclGetString(objv[1]))); return TCL_ERROR; } #endif if (objc == 3) { /* * Need separate variable for reading longs from an object on 64-bit * platforms. [Bug 698146] */ long newTime; |
︙ | ︙ |
Changes to tests/cmdAH.test.
︙ | ︙ | |||
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 | cd $old set atime [file atime $file] after 1100; # pause a sec to notice change in atime set newatime [clock seconds] set modatime [file atime $file $newatime] expr {$newatime == $modatime ? 1 : "$newatime != $modatime"} } -result 1 if {[testConstraint unix] && [file exists /tmp]} { removeFile touch.me /tmp } else { removeFile touch.me } | > > > > > > > > > > | 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 | cd $old set atime [file atime $file] after 1100; # pause a sec to notice change in atime set newatime [clock seconds] set modatime [file atime $file $newatime] expr {$newatime == $modatime ? 1 : "$newatime != $modatime"} } -result 1 test cmdAH-20.7 { Tcl_FileObjCmd: atime (built-in Windows names) } -constraints {win} -body { file atime con } -result "could not get access time for file \"con\"" -returnCodes error test cmdAH-20.7.1 { Tcl_FileObjCmd: atime (built-in Windows names with dir path and extension) } -constraints {win} -body { file atime [file join [temporaryDirectory] CON.txt] } -result "could not get access time for file \"[file join [temporaryDirectory] CON.txt]\"" -returnCodes error if {[testConstraint unix] && [file exists /tmp]} { removeFile touch.me /tmp } else { removeFile touch.me } |
︙ | ︙ | |||
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 | set old [file mtime $dirname] file mtime $dirname 0 set new [file mtime $dirname] list $new [expr {$old != $new}] } -cleanup { file delete -force $dirname } -result {0 1} # owned test cmdAH-25.1 {Tcl_FileObjCmd: owned} -returnCodes error -body { file owned a b } -result {wrong # args: should be "file owned name"} test cmdAH-25.2 {Tcl_FileObjCmd: owned} -constraints win -body { file owned $gorpfile | > > > > > > > > > > | 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 | set old [file mtime $dirname] file mtime $dirname 0 set new [file mtime $dirname] list $new [expr {$old != $new}] } -cleanup { file delete -force $dirname } -result {0 1} test cmdAH-24.14 { Tcl_FileObjCmd: mtime (built-in Windows names) } -constraints {win} -body { file mtime con } -result "could not get modification time for file \"con\"" -returnCodes error test cmdAH-24.14.1 { Tcl_FileObjCmd: mtime (built-in Windows names with dir path and extension) } -constraints {win} -body { file mtime [file join [temporaryDirectory] CON.txt] } -result "could not get modification time for file \"[file join [temporaryDirectory] CON.txt]\"" -returnCodes error # owned test cmdAH-25.1 {Tcl_FileObjCmd: owned} -returnCodes error -body { file owned a b } -result {wrong # args: should be "file owned name"} test cmdAH-25.2 {Tcl_FileObjCmd: owned} -constraints win -body { file owned $gorpfile |
︙ | ︙ | |||
1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 | puts $f "More text" close $f expr {[file size $gorpfile] - $oldsize} } {10} test cmdAH-27.3 {Tcl_FileObjCmd: size} { list [catch {file size _bogus_} msg] [string tolower $msg] $errorCode } {1 {could not read "_bogus_": no such file or directory} {POSIX ENOENT {no such file or directory}}} catch {testsetplatform $platform} removeFile $gorpfile set gorpfile [makeFile "Test string" gorp.file] catch {file attributes $gorpfile -permissions 0765} # stat | > > > > > > > > > > | 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 | puts $f "More text" close $f expr {[file size $gorpfile] - $oldsize} } {10} test cmdAH-27.3 {Tcl_FileObjCmd: size} { list [catch {file size _bogus_} msg] [string tolower $msg] $errorCode } {1 {could not read "_bogus_": no such file or directory} {POSIX ENOENT {no such file or directory}}} test cmdAH-27.4 { Tcl_FileObjCmd: size (built-in Windows names) } -constraints {win} -body { file size con } -result 0 test cmdAH-27.4.1 { Tcl_FileObjCmd: size (built-in Windows names with dir path and extension) } -constraints {win} -body { file size [file join [temporaryDirectory] con.txt] } -result 0 catch {testsetplatform $platform} removeFile $gorpfile set gorpfile [makeFile "Test string" gorp.file] catch {file attributes $gorpfile -permissions 0765} # stat |
︙ | ︙ | |||
1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 | # stat(mode) with S_IFREG flag was returned as a negative number if mode_t # was a short instead of an unsigned short. file stat $filename stat expr {$stat(mode) > 0} } -cleanup { removeFile $filename } -result 1 unset -nocomplain stat # type test cmdAH-29.1 {Tcl_FileObjCmd: type} -returnCodes error -body { | > > > > > > > > > > > > | | | 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 | # stat(mode) with S_IFREG flag was returned as a negative number if mode_t # was a short instead of an unsigned short. file stat $filename stat expr {$stat(mode) > 0} } -cleanup { removeFile $filename } -result 1 test cmdAH-28.13 {Tcl_FileObjCmd: stat (built-in Windows names)} -setup { unset -nocomplain stat } -body { file stat con stat lmap elem {atime ctime dev gid ino mode mtime nlink size type uid} {set stat($elem)} } -result {0 0 -1 0 0 8630 0 0 0 characterSpecial 0} test cmdAH-28.13.1 {Tcl_FileObjCmd: stat (built-in Windows names)} -setup { unset -nocomplain stat } -body { file stat [file join [temporaryDirectory] CON.txt] stat lmap elem {atime ctime dev gid ino mode mtime nlink size type uid} {set stat($elem)} } -result {0 0 -1 0 0 8630 0 0 0 characterSpecial 0} unset -nocomplain stat # type test cmdAH-29.1 {Tcl_FileObjCmd: type} -returnCodes error -body { file type a b } -result {wrong # args: should be "file type name"} test cmdAH-29.2 {Tcl_FileObjCmd: type} { file type $dirfile } directory test cmdAH-29.3.0 {Tcl_FileObjCmd: delete removes link not file} {unix nonPortable} { set exists [list [file exists $linkfile] [file exists $gorpfile]] file delete $linkfile set exists2 [list [file exists $linkfile] [file exists $gorpfile]] |
︙ | ︙ | |||
1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 | } -cleanup { file delete $linkdir removeDirectory $tempdir } -result link test cmdAH-29.5 {Tcl_FileObjCmd: type} { list [catch {file type _bogus_} msg] [string tolower $msg] $errorCode } {1 {could not read "_bogus_": no such file or directory} {POSIX ENOENT {no such file or directory}}} # Error conditions test cmdAH-30.1 {Tcl_FileObjCmd: error conditions} -returnCodes error -body { file gorp x } -result {unknown or ambiguous subcommand "gorp": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, link, lstat, mkdir, mtime, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, tempfile, type, volumes, or writable} test cmdAH-30.2 {Tcl_FileObjCmd: error conditions} -returnCodes error -body { file ex x | > > > > > > > > > > | 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 | } -cleanup { file delete $linkdir removeDirectory $tempdir } -result link test cmdAH-29.5 {Tcl_FileObjCmd: type} { list [catch {file type _bogus_} msg] [string tolower $msg] $errorCode } {1 {could not read "_bogus_": no such file or directory} {POSIX ENOENT {no such file or directory}}} test cmdAH-29.6 { Tcl_FileObjCmd: type (built-in Windows names) } -constraints {win} -body { file type con } -result "characterSpecial" test cmdAH-29.6.1 { Tcl_FileObjCmd: type (built-in Windows names, with dir path and extension) } -constraints {win} -body { file type [file join [temporaryDirectory] CON.txt] } -result "characterSpecial" # Error conditions test cmdAH-30.1 {Tcl_FileObjCmd: error conditions} -returnCodes error -body { file gorp x } -result {unknown or ambiguous subcommand "gorp": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, link, lstat, mkdir, mtime, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, tempfile, type, volumes, or writable} test cmdAH-30.2 {Tcl_FileObjCmd: error conditions} -returnCodes error -body { file ex x |
︙ | ︙ |
Changes to win/tclWinFile.c.
︙ | ︙ | |||
1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 | int checkLinks) /* If non-zero, behave like 'lstat' */ { DWORD attr; int dev, nlink = 1; unsigned short mode; unsigned int inode = 0; HANDLE fileHandle; /* * If we can use 'createFile' on this, then we can use the resulting * fileHandle to read more information (nlink, ino) than we can get from * other attributes reading APIs. If not, then we try to fall back on the * 'getFileAttributesExProc', and if that isn't available, then on even * simpler routines. */ fileHandle = CreateFile(nativePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); if (fileHandle != INVALID_HANDLE_VALUE) { BY_HANDLE_FILE_INFORMATION data; if (GetFileInformationByHandle(fileHandle,&data) != TRUE) { | > > > > > > > > > > | > | | | > > > > > > | > > > | < < < < | 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 | int checkLinks) /* If non-zero, behave like 'lstat' */ { DWORD attr; int dev, nlink = 1; unsigned short mode; unsigned int inode = 0; HANDLE fileHandle; DWORD fileType = FILE_TYPE_UNKNOWN; /* * If we can use 'createFile' on this, then we can use the resulting * fileHandle to read more information (nlink, ino) than we can get from * other attributes reading APIs. If not, then we try to fall back on the * 'getFileAttributesExProc', and if that isn't available, then on even * simpler routines. * * Special consideration must be given to Windows hardcoded names * like CON, NULL, COM1, LPT1 etc. For these, we still need to * do the CreateFile as some may not exist (e.g. there is no CON * in wish by default). However the subsequent GetFileInformationByHandle * will fail. We do a WinIsReserved to see if it is one of the special * names, and if successful, mock up a BY_HANDLE_FILE_INFORMATION * structure. */ fileHandle = CreateFile(nativePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); if (fileHandle != INVALID_HANDLE_VALUE) { BY_HANDLE_FILE_INFORMATION data; if (GetFileInformationByHandle(fileHandle,&data) != TRUE) { fileType = GetFileType(fileHandle); CloseHandle(fileHandle); if (fileType != FILE_TYPE_CHAR && fileType != FILE_TYPE_DISK) { Tcl_SetErrno(ENOENT); return -1; } /* Mock up the expected structure */ memset(&data, 0, sizeof(data)); statPtr->st_atime = 0; statPtr->st_mtime = 0; statPtr->st_ctime = 0; } else { CloseHandle(fileHandle); statPtr->st_atime = ToCTime(data.ftLastAccessTime); statPtr->st_mtime = ToCTime(data.ftLastWriteTime); statPtr->st_ctime = ToCTime(data.ftCreationTime); } attr = data.dwFileAttributes; statPtr->st_size = ((Tcl_WideInt) data.nFileSizeLow) | (((Tcl_WideInt) data.nFileSizeHigh) << 32); /* * On Unix, for directories, nlink apparently depends on the number of * files in the directory. We could calculate that, but it would be a * bit of a performance penalty, I think. Hence we just use what * Windows gives us, which is the same as Unix for files, at least. */ |
︙ | ︙ | |||
2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 | statPtr->st_atime = ToCTime(data.ftLastAccessTime); statPtr->st_mtime = ToCTime(data.ftLastWriteTime); statPtr->st_ctime = ToCTime(data.ftCreationTime); } dev = NativeDev(nativePath); mode = NativeStatMode(attr, checkLinks, NativeIsExec(nativePath)); statPtr->st_dev = (dev_t) dev; statPtr->st_ino = inode; statPtr->st_mode = mode; statPtr->st_nlink = nlink; statPtr->st_uid = 0; statPtr->st_gid = 0; | > > > > > > > | 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 | statPtr->st_atime = ToCTime(data.ftLastAccessTime); statPtr->st_mtime = ToCTime(data.ftLastWriteTime); statPtr->st_ctime = ToCTime(data.ftCreationTime); } dev = NativeDev(nativePath); mode = NativeStatMode(attr, checkLinks, NativeIsExec(nativePath)); if (fileType == FILE_TYPE_CHAR) { mode &= ~S_IFMT; mode |= S_IFCHR; } else if (fileType == FILE_TYPE_DISK) { mode &= ~S_IFMT; mode |= S_IFBLK; } statPtr->st_dev = (dev_t) dev; statPtr->st_ino = inode; statPtr->st_mode = mode; statPtr->st_nlink = nlink; statPtr->st_uid = 0; statPtr->st_gid = 0; |
︙ | ︙ |
Changes to win/tclWinPort.h.
︙ | ︙ | |||
356 357 358 359 360 361 362 363 364 365 366 367 368 369 | * defined. */ #ifndef S_IFLNK # define S_IFLNK 0120000 /* Symbolic Link */ #endif #ifndef S_ISREG # ifdef S_IFREG # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) # else # define S_ISREG(m) 0 # endif #endif /* !S_ISREG */ | > > > > > > > > > > > > > > | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | * defined. */ #ifndef S_IFLNK # define S_IFLNK 0120000 /* Symbolic Link */ #endif /* * Windows compilers do not define S_IFBLK. However, Tcl uses it in * GetTypeFromMode to identify blockSpecial devices based on the * value in the statsbuf st_mode field. We have no other way to pass this * from NativeStat on Windows so are forced to define it here. * The definition here is essentially what is seen on Linux and MingW. * XXX - the root problem is Tcl using Unix definitions instead of * abstracting the structure into a platform independent one. Sigh - perhaps * Tcl 9 */ #ifndef S_IFBLK # define S_IFBLK (S_IFDIR | S_IFCHR) #endif #ifndef S_ISREG # ifdef S_IFREG # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) # else # define S_ISREG(m) 0 # endif #endif /* !S_ISREG */ |
︙ | ︙ |