Attachment "nlink.diff" to
ticket [1325803fff]
added by
vincentdarley
2005-10-14 05:09:51.
? nlink.diff
? win/config.status.lineno
Index: tests/fCmd.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/fCmd.test,v
retrieving revision 1.47
diff -b -u -r1.47 fCmd.test
--- tests/fCmd.test 7 Oct 2005 22:35:33 -0000 1.47
+++ tests/fCmd.test 13 Oct 2005 22:06:51 -0000
@@ -2181,6 +2181,16 @@
cd [workingDirectory]
set res
} {0 abc.file}
+test fCmd-28.9.1 {file link: success with file} {linkFile win} {
+ cd [temporaryDirectory]
+ file delete -force abc.link
+ set res {}
+ file stat abc.file arr ; lappend res $arr(nlink)
+ lappend res [catch {file link abc.link abc.file} msg] $msg
+ file stat abc.file arr ; lappend res $arr(nlink)
+ cd [workingDirectory]
+ set res
+} {1 0 abc.file 2}
cd [temporaryDirectory]
catch {file delete -force abc.link}
cd [workingDirectory]
Index: win/tclWinFile.c
===================================================================
RCS file: /cvsroot/tcl/tcl/win/tclWinFile.c,v
retrieving revision 1.77
diff -b -u -r1.77 tclWinFile.c
--- win/tclWinFile.c 31 Aug 2005 15:12:18 -0000 1.77
+++ win/tclWinFile.c 13 Oct 2005 22:07:02 -0000
@@ -182,6 +182,7 @@
*/
static int NativeAccess(CONST TCHAR *path, int mode);
+static int NativeDev(CONST TCHAR *path);
static int NativeStat(CONST TCHAR *path, Tcl_StatBuf *statPtr,
int checkLinks);
static unsigned short NativeStatMode(DWORD attr, int checkLinks, int isExec);
@@ -1954,25 +1955,6 @@
Tcl_Obj *pathPtr; /* Path of file to stat. */
Tcl_StatBuf *statPtr; /* Filled with results of stat call. */
{
-#ifdef OLD_API
- Tcl_Obj *transPtr;
-
- /*
- * Eliminate file names containing wildcard characters, or subsequent call
- * to FindFirstFile() will expand them, matching some other file.
- */
-
- transPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr);
- if (transPtr == NULL || (strpbrk(Tcl_GetString(transPtr), "?*") != NULL)) {
- if (transPtr != NULL) {
- Tcl_DecrRefCount(transPtr);
- }
- Tcl_SetErrno(ENOENT);
- return -1;
- }
- Tcl_DecrRefCount(transPtr);
-#endif
-
/*
* Ensure correct file sizes by forcing the OS to write any pending data
* to disk. This is done only for channels which are dirty, i.e. have been
@@ -2013,18 +1995,68 @@
Tcl_StatBuf *statPtr; /* Filled with results of stat call. */
int checkLinks; /* If non-zero, behave like 'lstat' */
{
- Tcl_DString ds;
DWORD attr;
- WCHAR nativeFullPath[MAX_PATH];
- TCHAR *nativePart;
- CONST char *fullPath;
int dev;
unsigned short mode;
+ int nlink = 1;
+ int inode = 0;
+ HANDLE fileHandle;
- if (tclWinProcs->getFileAttributesExProc == NULL) {
/*
- * We don't have the faster attributes proc, so we're probably running
- * on Win95.
+ * 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 = (tclWinProcs->createFileProc) (
+ nativePath, GENERIC_READ, 0, 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) {
+ CloseHandle(fileHandle);
+ Tcl_SetErrno(ENOENT);
+ return -1;
+ }
+ CloseHandle(fileHandle);
+
+ attr = data.dwFileAttributes;
+
+ statPtr->st_size = ((Tcl_WideInt)data.nFileSizeLow) |
+ (((Tcl_WideInt)data.nFileSizeHigh) << 32);
+ statPtr->st_atime = ToCTime(data.ftLastAccessTime);
+ statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
+ statPtr->st_ctime = ToCTime(data.ftCreationTime);
+
+ nlink = data.nNumberOfLinks;
+ inode = data.nFileIndexHigh | data.nFileIndexLow;
+ } else if (tclWinProcs->getFileAttributesExProc != NULL) {
+ /*
+ * 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);
+ statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
+ statPtr->st_ctime = ToCTime(data.ftCreationTime);
+ } else {
+ /*
+ * We don't have the faster attributes proc, so we're probably
+ * running on Win95.
*/
WIN32_FIND_DATAT data;
@@ -2044,8 +2076,8 @@
}
/*
- * Make up some fake information for this file. It has the correct
- * file attributes and a time of 0.
+ * Make up some fake information for this file. It has the
+ * correct file attributes and a time of 0.
*/
memset(&data, 0, sizeof(data));
@@ -2054,51 +2086,6 @@
FindClose(handle);
}
- (*tclWinProcs->getFullPathNameProc)(nativePath, MAX_PATH,
- nativeFullPath, &nativePart);
-
- fullPath = Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds);
-
- dev = -1;
- if ((fullPath[0] == '\\') && (fullPath[1] == '\\')) {
- CONST char *p;
- DWORD dw;
- CONST TCHAR *nativeVol;
- Tcl_DString volString;
-
- p = strchr(fullPath + 2, '\\');
- p = strchr(p + 1, '\\');
- if (p == NULL) {
- /*
- * Add terminating backslash to fullpath or
- * GetVolumeInformation() won't work.
- */
-
- fullPath = Tcl_DStringAppend(&ds, "\\", 1);
- p = fullPath + Tcl_DStringLength(&ds);
- } else {
- p++;
- }
- nativeVol = Tcl_WinUtfToTChar(fullPath, p - fullPath, &volString);
- dw = (DWORD) -1;
- (*tclWinProcs->getVolumeInformationProc)(nativeVol, NULL, 0, &dw,
- NULL, NULL, NULL, 0);
-
- /*
- * GetFullPathName() turns special devices like "NUL" into
- * "\\.\NUL", but GetVolumeInformation() returns failure for
- * "\\.\NUL". This will cause "NUL" to get a drive number of -1,
- * which makes about as much sense as anything since the special
- * devices don't live on any drive.
- */
-
- dev = dw;
- Tcl_DStringFree(&volString);
- } else if ((fullPath[0] != '\0') && (fullPath[1] == ':')) {
- dev = Tcl_UniCharToLower(fullPath[0]) - 'a';
- }
- Tcl_DStringFree(&ds);
-
attr = data.a.dwFileAttributes;
statPtr->st_size = ((Tcl_WideInt)data.a.nFileSizeLow) |
@@ -2106,21 +2093,45 @@
statPtr->st_atime = ToCTime(data.a.ftLastAccessTime);
statPtr->st_mtime = ToCTime(data.a.ftLastWriteTime);
statPtr->st_ctime = ToCTime(data.a.ftCreationTime);
- } else {
- WIN32_FILE_ATTRIBUTE_DATA data;
-
- if ((*tclWinProcs->getFileAttributesExProc)(nativePath,
- GetFileExInfoStandard, &data) != TRUE) {
- Tcl_SetErrno(ENOENT);
- return -1;
}
+ 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;
+ statPtr->st_rdev = (dev_t) dev;
+ return 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * NativeDev --
+ *
+ * Calculate just the 'st_dev' field of a 'stat' structure.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+NativeDev(nativePath)
+ CONST TCHAR *nativePath; /* Full path of file to stat */
+{
+ int dev;
+ Tcl_DString ds;
+ WCHAR nativeFullPath[MAX_PATH];
+ TCHAR *nativePart;
+ CONST char *fullPath;
+
(*tclWinProcs->getFullPathNameProc)(nativePath, MAX_PATH,
nativeFullPath, &nativePart);
- fullPath = Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds);
+ fullPath = Tcl_WinTCharToUtf((TCHAR*)nativeFullPath, -1, &ds);
- dev = -1;
if ((fullPath[0] == '\\') && (fullPath[1] == '\\')) {
CONST char *p;
DWORD dw;
@@ -2157,28 +2168,12 @@
Tcl_DStringFree(&volString);
} else if ((fullPath[0] != '\0') && (fullPath[1] == ':')) {
dev = Tcl_UniCharToLower(fullPath[0]) - 'a';
+ } else {
+ dev = -1;
}
Tcl_DStringFree(&ds);
- attr = data.dwFileAttributes;
-
- statPtr->st_size = ((Tcl_WideInt)data.nFileSizeLow) |
- (((Tcl_WideInt)data.nFileSizeHigh) << 32);
- statPtr->st_atime = ToCTime(data.ftLastAccessTime);
- statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
- statPtr->st_ctime = ToCTime(data.ftCreationTime);
- }
-
- mode = NativeStatMode(attr, checkLinks, NativeIsExec(nativePath));
-
- statPtr->st_dev = (dev_t) dev;
- statPtr->st_ino = 0;
- statPtr->st_mode = mode;
- statPtr->st_nlink = 1;
- statPtr->st_uid = 0;
- statPtr->st_gid = 0;
- statPtr->st_rdev = (dev_t) dev;
- return 0;
+ return dev;
}
/*