Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(19074)

Delta Between Two Patch Sets: Modules/posixmodule.c

Issue 10027: os.lstat/os.stat don't set st_nlink on Windows
Left Patch Set: Created 8 years, 11 months ago
Right Patch Set: Created 8 years, 10 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 1
2 /* POSIX module implementation */ 2 /* POSIX module implementation */
3 3
4 /* This file is also used for Windows NT/MS-Win and OS/2. In that case the 4 /* This file is also used for Windows NT/MS-Win and OS/2. In that case the
5 module actually calls itself 'nt' or 'os2', not 'posix', and a few 5 module actually calls itself 'nt' or 'os2', not 'posix', and a few
6 functions are either unimplemented or implemented differently. The source 6 functions are either unimplemented or implemented differently. The source
7 assumes that for Windows NT, the macro 'MS_WINDOWS' is defined independent 7 assumes that for Windows NT, the macro 'MS_WINDOWS' is defined independent
8 of the compiler used. Different compilers define their own feature 8 of the compiler used. Different compilers define their own feature
9 test macro, e.g. '__BORLANDC__' or '_MSC_VER'. For OS/2, the compiler 9 test macro, e.g. '__BORLANDC__' or '_MSC_VER'. For OS/2, the compiler
10 independent macro PYOS_OS2 should be defined. On OS/2 the default 10 independent macro PYOS_OS2 should be defined. On OS/2 the default
(...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 if ((unsigned)fd2 < _NHANDLE_) 430 if ((unsigned)fd2 < _NHANDLE_)
431 return 1; 431 return 1;
432 else 432 else
433 return 0; 433 return 0;
434 } 434 }
435 #else 435 #else
436 /* dummy version. _PyVerify_fd() is already defined in fileobject.h */ 436 /* dummy version. _PyVerify_fd() is already defined in fileobject.h */
437 #define _PyVerify_fd_dup2(A, B) (1) 437 #define _PyVerify_fd_dup2(A, B) (1)
438 #endif 438 #endif
439 439
440 /* The following structure was copied from
441 http://msdn.microsoft.com/en-us/library/ms791514.aspx as the required
442 include doesn't seem to be present in the Windows SDK (at least as included
443 with Visual Studio Express). */
444 typedef struct _REPARSE_DATA_BUFFER {
445 ULONG ReparseTag;
446 USHORT ReparseDataLength;
447 USHORT Reserved;
448 union {
449 struct {
450 USHORT SubstituteNameOffset;
451 USHORT SubstituteNameLength;
452 USHORT PrintNameOffset;
453 USHORT PrintNameLength;
454 ULONG Flags;
455 WCHAR PathBuffer[1];
456 } SymbolicLinkReparseBuffer;
457
458 struct {
459 USHORT SubstituteNameOffset;
460 USHORT SubstituteNameLength;
461 USHORT PrintNameOffset;
462 USHORT PrintNameLength;
463 WCHAR PathBuffer[1];
464 } MountPointReparseBuffer;
465
466 struct {
467 UCHAR DataBuffer[1];
468 } GenericReparseBuffer;
469 };
470 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
471
472 #define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER,\
473 GenericReparseBuffer)
474 #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )
475
476 static int
477 _Py_ReadLink(HANDLE reparse_point_handle, ULONG *reparse_tag, wchar_t **target_p ath)
478 {
479 char target_buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
480 REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER *)target_buffer;
481 DWORD n_bytes_returned;
482 const wchar_t *ptr;
483 wchar_t *buf;
484 size_t len;
485
486 if (0 == DeviceIoControl(
487 reparse_point_handle,
488 FSCTL_GET_REPARSE_POINT,
489 NULL, 0, /* in buffer */
490 target_buffer, sizeof(target_buffer),
491 &n_bytes_returned,
492 NULL)) /* we're not using OVERLAPPED_IO */
493 return 0;
494
495 if (reparse_tag)
496 *reparse_tag = rdb->ReparseTag;
497
498 if (target_path) {
499 switch (rdb->ReparseTag) {
500 case IO_REPARSE_TAG_SYMLINK:
501 /* XXX: Maybe should use SubstituteName? */
502 ptr = rdb->SymbolicLinkReparseBuffer.PathBuffer +
503 rdb->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
504 len = rdb->SymbolicLinkReparseBuffer.PrintNameLength/sizeof(WCHAR);
505 break;
506 case IO_REPARSE_TAG_MOUNT_POINT:
507 ptr = rdb->MountPointReparseBuffer.PathBuffer +
508 rdb->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR );
509 len = rdb->MountPointReparseBuffer.SubstituteNameLength/sizeof(WCHAR );
510 break;
511 default:
512 SetLastError(ERROR_REPARSE_TAG_MISMATCH); /* XXX: Proper error code? */
513 return 0;
514 }
515 buf = (wchar_t *)malloc(sizeof(wchar_t)*(len+1));
516 if (!buf) {
517 SetLastError(ERROR_OUTOFMEMORY);
518 return 0;
519 }
520 wcsncpy(buf, ptr, len);
521 buf[len] = L'\0';
522 if (wcsncmp(buf, L"\\??\\", 4) == 0)
523 buf[1] = L'\\';
524 *target_path = buf;
525 }
526
527 return 1;
528 }
529
440 /* Return a dictionary corresponding to the POSIX environment table */ 530 /* Return a dictionary corresponding to the POSIX environment table */
441 #ifdef WITH_NEXT_FRAMEWORK 531 #ifdef WITH_NEXT_FRAMEWORK
442 /* On Darwin/MacOSX a shared library or framework has no access to 532 /* On Darwin/MacOSX a shared library or framework has no access to
443 ** environ directly, we must obtain it with _NSGetEnviron(). 533 ** environ directly, we must obtain it with _NSGetEnviron().
444 */ 534 */
445 #include <crt_externs.h> 535 #include <crt_externs.h>
446 static char **environ; 536 static char **environ;
447 #elif !defined(_MSC_VER) && ( !defined(__WATCOMC__) || defined(__QNX__) ) 537 #elif !defined(_MSC_VER) && ( !defined(__WATCOMC__) || defined(__QNX__) )
448 extern char **environ; 538 extern char **environ;
449 #endif /* !_MSC_VER */ 539 #endif /* !_MSC_VER */
(...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after
927 else 1017 else
928 m |= _S_IFREG; 1018 m |= _S_IFREG;
929 if (attr & FILE_ATTRIBUTE_READONLY) 1019 if (attr & FILE_ATTRIBUTE_READONLY)
930 m |= 0444; 1020 m |= 0444;
931 else 1021 else
932 m |= 0666; 1022 m |= 0666;
933 return m; 1023 return m;
934 } 1024 }
935 1025
936 static int 1026 static int
937 attribute_data_to_stat(WIN32_FILE_ATTRIBUTE_DATA *info, struct win32_stat *resul t) 1027 attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, struct win32_stat *resu lt)
938 { 1028 {
939 memset(result, 0, sizeof(*result)); 1029 memset(result, 0, sizeof(*result));
940 result->st_mode = attributes_to_mode(info->dwFileAttributes); 1030 result->st_mode = attributes_to_mode(info->dwFileAttributes);
941 result->st_size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow; 1031 result->st_size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow;
942 FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_ctime, &result-> st_ctime_nsec); 1032 FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_ctime, &result-> st_ctime_nsec);
943 FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result- >st_mtime_nsec); 1033 FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result- >st_mtime_nsec);
944 FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result ->st_atime_nsec); 1034 FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result ->st_atime_nsec);
1035 result->st_nlink = info->nNumberOfLinks;
945 1036
946 return 0; 1037 return 0;
947 } 1038 }
948 1039
949 static BOOL 1040 static BOOL
950 attributes_from_dir(LPCSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad) 1041 attributes_from_dir(LPCSTR pszFile, BY_HANDLE_FILE_INFORMATION *info)
951 { 1042 {
952 HANDLE hFindFile; 1043 HANDLE hFindFile;
953 WIN32_FIND_DATAA FileData; 1044 WIN32_FIND_DATAA FileData;
954 hFindFile = FindFirstFileA(pszFile, &FileData); 1045 hFindFile = FindFirstFileA(pszFile, &FileData);
955 if (hFindFile == INVALID_HANDLE_VALUE) 1046 if (hFindFile == INVALID_HANDLE_VALUE)
956 return FALSE; 1047 return FALSE;
957 FindClose(hFindFile); 1048 FindClose(hFindFile);
958 pfad->dwFileAttributes = FileData.dwFileAttributes; 1049 memset(info, 0, sizeof(*info));
959 pfad->ftCreationTime = FileData.ftCreationTime; 1050 info->dwFileAttributes = FileData.dwFileAttributes;
960 pfad->ftLastAccessTime = FileData.ftLastAccessTime; 1051 info->ftCreationTime = FileData.ftCreationTime;
961 pfad->ftLastWriteTime = FileData.ftLastWriteTime; 1052 info->ftLastAccessTime = FileData.ftLastAccessTime;
962 pfad->nFileSizeHigh = FileData.nFileSizeHigh; 1053 info->ftLastWriteTime = FileData.ftLastWriteTime;
963 pfad->nFileSizeLow = FileData.nFileSizeLow; 1054 info->nFileSizeHigh = FileData.nFileSizeHigh;
1055 info->nFileSizeLow = FileData.nFileSizeLow;
1056 /* info->nNumberOfLinks = 1; */
964 return TRUE; 1057 return TRUE;
965 } 1058 }
966 1059
967 static BOOL 1060 static BOOL
968 attributes_from_dir_w(LPCWSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad) 1061 attributes_from_dir_w(LPCWSTR pszFile, BY_HANDLE_FILE_INFORMATION *info)
969 { 1062 {
970 HANDLE hFindFile; 1063 HANDLE hFindFile;
971 WIN32_FIND_DATAW FileData; 1064 WIN32_FIND_DATAW FileData;
972 hFindFile = FindFirstFileW(pszFile, &FileData); 1065 hFindFile = FindFirstFileW(pszFile, &FileData);
973 if (hFindFile == INVALID_HANDLE_VALUE) 1066 if (hFindFile == INVALID_HANDLE_VALUE)
974 return FALSE; 1067 return FALSE;
975 FindClose(hFindFile); 1068 FindClose(hFindFile);
976 pfad->dwFileAttributes = FileData.dwFileAttributes; 1069 memset(info, 0, sizeof(*info));
977 pfad->ftCreationTime = FileData.ftCreationTime; 1070 info->dwFileAttributes = FileData.dwFileAttributes;
978 pfad->ftLastAccessTime = FileData.ftLastAccessTime; 1071 info->ftCreationTime = FileData.ftCreationTime;
979 pfad->ftLastWriteTime = FileData.ftLastWriteTime; 1072 info->ftLastAccessTime = FileData.ftLastAccessTime;
980 pfad->nFileSizeHigh = FileData.nFileSizeHigh; 1073 info->ftLastWriteTime = FileData.ftLastWriteTime;
981 pfad->nFileSizeLow = FileData.nFileSizeLow; 1074 info->nFileSizeHigh = FileData.nFileSizeHigh;
1075 info->nFileSizeLow = FileData.nFileSizeLow;
1076 /* info->nNumberOfLinks = 1; */
982 return TRUE; 1077 return TRUE;
983 } 1078 }
984 1079
985 /* About the following functions: win32_lstat, win32_lstat_w, win32_stat, 1080 #ifndef SYMLOOP_MAX
986 win32_stat_w 1081 #define SYMLOOP_MAX ( 88 )
987 1082 #endif
988 In Posix, stat automatically traverses symlinks and returns the stat
989 structure for the target. In Windows, the equivalent GetFileAttributes by
990 default does not traverse symlinks and instead returns attributes for
991 the symlink.
992
993 Therefore, win32_lstat will get the attributes traditionally, and
994 win32_stat will first explicitly resolve the symlink target and then will
995 call win32_lstat on that result.
996
997 The _w represent Unicode equivalents of the aformentioned ANSI functions. */
998 1083
999 static int 1084 static int
1000 win32_osfstat(HANDLE h, struct win32_stat *result) 1085 win32_xstat_for_handle(HANDLE hFile, struct win32_stat *result, BOOL traverse, i nt depth);
1001 {
1002 BY_HANDLE_FILE_INFORMATION info;
1003 int type;
1004
1005 /* Protocol violation: we explicitly clear errno, instead of
1006 setting it to a POSIX error. Callers should use GetLastError. */
1007 errno = 0;
1008
1009 if (h == INVALID_HANDLE_VALUE) {
1010 /* This is really a C library error (invalid file handle).
1011 We set the Win32 error to the closes one matching. */
1012 SetLastError(ERROR_INVALID_HANDLE);
1013 return -1;
1014 }
1015 memset(result, 0, sizeof(*result));
1016
1017 type = GetFileType(h);
1018 if (type == FILE_TYPE_UNKNOWN) {
1019 DWORD error = GetLastError();
1020 if (error != 0) {
1021 return -1;
1022 }
1023 /* else: valid but unknown file */
1024 }
1025
1026 if (type != FILE_TYPE_DISK) {
1027 if (type == FILE_TYPE_CHAR)
1028 result->st_mode = _S_IFCHR;
1029 else if (type == FILE_TYPE_PIPE)
1030 result->st_mode = _S_IFIFO;
1031 return 0;
1032 }
1033
1034 if (!GetFileInformationByHandle(h, &info)) {
1035 return -1;
1036 }
1037
1038 /* similar to stat() */
1039 result->st_mode = attributes_to_mode(info.dwFileAttributes);
1040 result->st_size = (((__int64)info.nFileSizeHigh)<<32) + info.nFileSizeLow;
1041 FILE_TIME_to_time_t_nsec(&info.ftCreationTime, &result->st_ctime,
1042 &result->st_ctime_nsec);
1043 FILE_TIME_to_time_t_nsec(&info.ftLastWriteTime, &result->st_mtime,
1044 &result->st_mtime_nsec);
1045 FILE_TIME_to_time_t_nsec(&info.ftLastAccessTime, &result->st_atime,
1046 &result->st_atime_nsec);
1047 /* specific to fstat() */
1048 result->st_nlink = info.nNumberOfLinks;
1049 result->st_ino = (((__int64)info.nFileIndexHigh)<<32) + info.nFileIndexLow;
1050 return 0;
1051 }
1052 1086
1053 static int 1087 static int
1054 _win32_stat(const char* path, DWORD flag, struct win32_stat *result) 1088 win32_xstat(const char *path, struct win32_stat *result, BOOL traverse, int dept h)
1055 { 1089 {
1056 /* Traverse the symlink to the target using
1057 GetFinalPathNameByHandle()
1058 */
1059 int code; 1090 int code;
1060 HANDLE hFile; 1091 HANDLE hFile;
1061 WIN32_FILE_ATTRIBUTE_DATA info; 1092 BY_HANDLE_FILE_INFORMATION info;
1093 const char *dot;
1062 1094
1063 hFile = CreateFileA( 1095 hFile = CreateFileA(
1064 path, 1096 path,
1065 0, /* desired access */ 1097 0, /* desired access */
1066 0, /* share mode */ 1098 0, /* share mode */
1067 NULL, /* security attributes */ 1099 NULL, /* security attributes */
1068 OPEN_EXISTING, 1100 OPEN_EXISTING,
1069 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */ 1101 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
1070 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS|flag, 1102 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_ POINT,
1071 NULL); 1103 NULL);
1072 1104
1073 if(hFile == INVALID_HANDLE_VALUE) { 1105 if(hFile == INVALID_HANDLE_VALUE) {
1074 /* Either the target doesn't exist, or we don't have access to 1106 /* Either the target doesn't exist, or we don't have access to
1075 get a handle to it. If the former, we need to return an error. 1107 get a handle to it. If the former, we need to return an error.
1076 If the latter, we can use attributes_from_dir. */ 1108 If the latter, we can use attributes_from_dir. */
1077 if (GetLastError() != ERROR_SHARING_VIOLATION) { 1109 if (GetLastError() != ERROR_SHARING_VIOLATION)
1078 /* Protocol violation: we explicitly clear errno, instead of 1110 goto err;
1079 setting it to a POSIX error. Callers should use GetLastError. */ 1111 else {
1080 errno = 0;
1081 return -1;
1082 } else {
1083 /* Could not get attributes on open file. Fall back to 1112 /* Could not get attributes on open file. Fall back to
1084 reading the directory. */ 1113 reading the directory. */
1085 if (!attributes_from_dir(path, &info)) { 1114 if (!attributes_from_dir(path, &info))
1086 /* Very strange. This should not fail now */ 1115 /* Very strange. This should not fail now */
1087 errno = 0; 1116 goto err;
1088 return -1; 1117 if (traverse && (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POIN T)) {
1118 /* Should traverse, but cannot open reparse point handle */
1119 SetLastError(ERROR_SHARING_VIOLATION);
1120 goto err;
1089 } 1121 }
1122 attribute_data_to_stat(&info, result);
1090 } 1123 }
1091 code = attribute_data_to_stat(&info, result);
1092 } 1124 }
1093 else { 1125 else {
1094 code = win32_osfstat(hFile, result); 1126 code = win32_xstat_for_handle(hFile, result, traverse, depth);
1095 CloseHandle(hFile); 1127 CloseHandle(hFile);
1096 } 1128 if (code != 0)
1097 1129 return code;
1098 return code; 1130 }
1099 } 1131
1100 1132 /* Set S_IEXEC if it is an .exe, .bat, ... */
1101 static int 1133 dot = strrchr(path, '.');
1102 _win32_stat_w(const wchar_t* path, DWORD flag, struct win32_stat *result) 1134 if (dot) {
1103 { 1135 if (stricmp(dot, ".bat") == 0 || stricmp(dot, ".cmd") == 0 ||
1104 /* Traverse the symlink to the target using GetFinalPathNameByHandle() */ 1136 stricmp(dot, ".exe") == 0 || stricmp(dot, ".com") == 0)
1137 result->st_mode |= 0111;
1138 }
1139 return 0;
1140
1141 err:
1142 /* Protocol violation: we explicitly clear errno, instead of
1143 setting it to a POSIX error. Callers should use GetLastError. */
1144 errno = 0;
1145 return -1;
1146 }
1147
1148 static int
1149 win32_xstat_w(const wchar_t *path, struct win32_stat *result, BOOL traverse, int depth)
1150 {
1105 int code; 1151 int code;
1106 HANDLE hFile; 1152 HANDLE hFile;
1107 WIN32_FILE_ATTRIBUTE_DATA info; 1153 BY_HANDLE_FILE_INFORMATION info;
1154 const wchar_t *dot;
1108 1155
1109 hFile = CreateFileW( 1156 hFile = CreateFileW(
1110 path, 1157 path,
1111 0, /* desired access */ 1158 0, /* desired access */
1112 0, /* share mode */ 1159 0, /* share mode */
1113 NULL, /* security attributes */ 1160 NULL, /* security attributes */
1114 OPEN_EXISTING, 1161 OPEN_EXISTING,
1115 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */ 1162 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
1116 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS|flag, 1163 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_ POINT,
1117 NULL); 1164 NULL);
1118 1165
1119 if(hFile == INVALID_HANDLE_VALUE) { 1166 if(hFile == INVALID_HANDLE_VALUE) {
1120 /* Either the target doesn't exist, or we don't have access to 1167 /* Either the target doesn't exist, or we don't have access to
1121 get a handle to it. If the former, we need to return an error. 1168 get a handle to it. If the former, we need to return an error.
1122 If the latter, we can use attributes_from_dir. */ 1169 If the latter, we can use attributes_from_dir. */
1123 if (GetLastError() != ERROR_SHARING_VIOLATION) { 1170 if (GetLastError() != ERROR_SHARING_VIOLATION)
1124 /* Protocol violation: we explicitly clear errno, instead of 1171 goto err;
1125 setting it to a POSIX error. Callers should use GetLastError. */ 1172 else {
1126 errno = 0;
1127 return -1;
1128 } else {
1129 /* Could not get attributes on open file. Fall back to 1173 /* Could not get attributes on open file. Fall back to
1130 reading the directory. */ 1174 reading the directory. */
1131 if (!attributes_from_dir_w(path, &info)) { 1175 if (!attributes_from_dir_w(path, &info))
1132 /* Very strange. This should not fail now */ 1176 /* Very strange. This should not fail now */
1133 errno = 0; 1177 goto err;
1178 if (traverse && (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POIN T)) {
1179 /* Should traverse, but cannot open reparse point handle */
1180 SetLastError(ERROR_SHARING_VIOLATION);
1181 goto err;
1182 }
1183 attribute_data_to_stat(&info, result);
1184 }
1185 }
1186 else {
1187 code = win32_xstat_for_handle(hFile, result, traverse, depth);
1188 CloseHandle(hFile);
1189 if (code != 0)
1190 return code;
1191 }
1192
1193 /* Set S_IEXEC if it is an .exe, .bat, ... */
1194 dot = wcsrchr(path, '.');
1195 if (dot) {
1196 if (_wcsicmp(dot, L".bat") == 0 || _wcsicmp(dot, L".cmd") == 0 ||
1197 _wcsicmp(dot, L".exe") == 0 || _wcsicmp(dot, L".com") == 0)
1198 result->st_mode |= 0111;
1199 }
1200 return 0;
1201
1202 err:
1203 /* Protocol violation: we explicitly clear errno, instead of
1204 setting it to a POSIX error. Callers should use GetLastError. */
1205 errno = 0;
1206 return -1;
1207 }
1208
1209 static int
1210 win32_xstat_for_handle(HANDLE hFile, struct win32_stat *result, BOOL traverse, i nt depth)
1211 {
1212 int code;
1213 BOOL reparse_tag;
1214 wchar_t *target_path;
1215 BY_HANDLE_FILE_INFORMATION info;
1216
1217 if (!GetFileInformationByHandle(hFile, &info))
1218 return -1;
1219
1220 if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1221 if (traverse) {
1222 if (depth + 1 > SYMLOOP_MAX) {
1223 SetLastError(ERROR_CANT_RESOLVE_FILENAME); /* XXX: ELOOP? */
1134 return -1; 1224 return -1;
1135 } 1225 }
1226 if (!_Py_ReadLink(hFile, NULL, &target_path))
1227 return -1;
1228 code = win32_xstat_w(target_path, result, traverse, depth + 1);
1229 free(target_path);
1230 return code;
1231 } else {
1232 if (!_Py_ReadLink(hFile, &reparse_tag, NULL))
1233 return -1;
1234 attribute_data_to_stat(&info, result);
1235 if (reparse_tag == IO_REPARSE_TAG_SYMLINK) {
1236 /* first clear the S_IFMT bits */
1237 result->st_mode ^= (result->st_mode & 0170000);
1238 /* now set the bits that make this a symlink */
1239 result->st_mode |= 0120000;
1240 }
1136 } 1241 }
1137 code = attribute_data_to_stat(&info, result); 1242 } else {
1138 } 1243 attribute_data_to_stat(&info, result);
1139 else { 1244 }
1140 code = win32_osfstat(hFile, result); 1245 return 0;
1141 CloseHandle(hFile); 1246 }
1142 } 1247
1143 1248 /* About the following functions: win32_lstat, win32_lstat_w, win32_stat,
1144 return code; 1249 win32_stat_w
1145 } 1250
1251 In Posix, stat automatically traverses symlinks and returns the stat
1252 structure for the target. In Windows, the equivalent GetFileAttributes by
1253 default does not traverse symlinks and instead returns attributes for
1254 the symlink.
1255
1256 Therefore, win32_lstat will get the attributes traditionally, and
1257 win32_stat will first explicitly resolve the symlink target and then will
1258 call win32_lstat on that result.
1259
1260 The _w represent Unicode equivalents of the aformentioned ANSI functions. */
1146 1261
1147 static int 1262 static int
1148 win32_lstat(const char* path, struct win32_stat *result) 1263 win32_lstat(const char* path, struct win32_stat *result)
1149 { 1264 {
1150 return _win32_stat(path, FILE_FLAG_OPEN_REPARSE_POINT, result); 1265 return win32_xstat(path, result, FALSE, 0);
1151 } 1266 }
1152 1267
1153 static int 1268 static int
1154 win32_lstat_w(const wchar_t* path, struct win32_stat *result) 1269 win32_lstat_w(const wchar_t* path, struct win32_stat *result)
1155 { 1270 {
1156 return _win32_stat_w(path, FILE_FLAG_OPEN_REPARSE_POINT, result); 1271 return win32_xstat_w(path, result, FALSE, 0);
1157 }
1158
1159 /* Grab GetFinalPathNameByHandle dynamically from kernel32 */
1160 static int has_GetFinalPathNameByHandle = 0;
1161 static DWORD (CALLBACK *Py_GetFinalPathNameByHandleA)(HANDLE, LPSTR, DWORD,
1162 DWORD);
1163 static DWORD (CALLBACK *Py_GetFinalPathNameByHandleW)(HANDLE, LPWSTR, DWORD,
1164 DWORD);
1165 static int
1166 check_GetFinalPathNameByHandle()
1167 {
1168 HINSTANCE hKernel32;
1169 /* only recheck */
1170 if (!has_GetFinalPathNameByHandle)
1171 {
1172 hKernel32 = GetModuleHandle("KERNEL32");
1173 *(FARPROC*)&Py_GetFinalPathNameByHandleA = GetProcAddress(hKernel32,
1174 "GetFinalPathNameByHandleA");
1175 *(FARPROC*)&Py_GetFinalPathNameByHandleW = GetProcAddress(hKernel32,
1176 "GetFinalPathNameByHandleW");
1177 has_GetFinalPathNameByHandle = Py_GetFinalPathNameByHandleA &&
1178 Py_GetFinalPathNameByHandleW;
1179 }
1180 return has_GetFinalPathNameByHandle;
1181 } 1272 }
1182 1273
1183 static int 1274 static int
1184 win32_stat(const char* path, struct win32_stat *result) 1275 win32_stat(const char* path, struct win32_stat *result)
1185 { 1276 {
1186 return _win32_stat(path, 0, result); 1277 return win32_xstat(path, result, TRUE, 0);
1187 } 1278 }
1188 1279
1189 static int 1280 static int
1190 win32_stat_w(const wchar_t* path, struct win32_stat *result) 1281 win32_stat_w(const wchar_t* path, struct win32_stat *result)
1191 { 1282 {
1192 return _win32_stat_w(path, 0, result); 1283 return win32_xstat_w(path, result, TRUE, 0);
1193 } 1284 }
1194 1285
1195 static int 1286 static int
1196 win32_fstat(int file_number, struct win32_stat *result) 1287 win32_fstat(int file_number, struct win32_stat *result)
1197 { 1288 {
1289 BY_HANDLE_FILE_INFORMATION info;
1198 HANDLE h; 1290 HANDLE h;
1291 int type;
1199 1292
1200 h = (HANDLE)_get_osfhandle(file_number); 1293 h = (HANDLE)_get_osfhandle(file_number);
1201 1294
1202 return win32_osfstat(h, result); 1295 /* Protocol violation: we explicitly clear errno, instead of
1296 setting it to a POSIX error. Callers should use GetLastError. */
1297 errno = 0;
1298
1299 if (h == INVALID_HANDLE_VALUE) {
1300 /* This is really a C library error (invalid file handle).
1301 We set the Win32 error to the closes one matching. */
1302 SetLastError(ERROR_INVALID_HANDLE);
1303 return -1;
1304 }
1305 memset(result, 0, sizeof(*result));
1306
1307 type = GetFileType(h);
1308 if (type == FILE_TYPE_UNKNOWN) {
1309 DWORD error = GetLastError();
1310 if (error != 0) {
1311 return -1;
1312 }
1313 /* else: valid but unknown file */
1314 }
1315
1316 if (type != FILE_TYPE_DISK) {
1317 if (type == FILE_TYPE_CHAR)
1318 result->st_mode = _S_IFCHR;
1319 else if (type == FILE_TYPE_PIPE)
1320 result->st_mode = _S_IFIFO;
1321 return 0;
1322 }
1323
1324 if (!GetFileInformationByHandle(h, &info)) {
1325 return -1;
1326 }
1327
1328 attribute_data_to_stat(&info, result);
1329 /* specific to fstat() */
1330 result->st_ino = (((__int64)info.nFileIndexHigh)<<32) + info.nFileIndexLow;
1331 return 0;
1203 } 1332 }
1204 1333
1205 #endif /* MS_WINDOWS */ 1334 #endif /* MS_WINDOWS */
1206 1335
1207 PyDoc_STRVAR(stat_result__doc__, 1336 PyDoc_STRVAR(stat_result__doc__,
1208 "stat_result: Result from stat or lstat.\n\n\ 1337 "stat_result: Result from stat or lstat.\n\n\
1209 This object may be accessed either as a tuple of\n\ 1338 This object may be accessed either as a tuple of\n\
1210 (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)\n\ 1339 (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)\n\
1211 or via the attributes st_mode, st_ino, st_dev, st_nlink, st_uid, and so on.\n\ 1340 or via the attributes st_mode, st_ino, st_dev, st_nlink, st_uid, and so on.\n\
1212 \n\ 1341 \n\
(...skipping 1285 matching lines...) Expand 10 before | Expand all | Expand 10 after
2498 return NULL; 2627 return NULL;
2499 } 2628 }
2500 Py_DECREF(opath); 2629 Py_DECREF(opath);
2501 if (PyUnicode_Check(PyTuple_GetItem(args, 0))) { 2630 if (PyUnicode_Check(PyTuple_GetItem(args, 0))) {
2502 return PyUnicode_Decode(outbuf, strlen(outbuf), 2631 return PyUnicode_Decode(outbuf, strlen(outbuf),
2503 Py_FileSystemDefaultEncoding, NULL); 2632 Py_FileSystemDefaultEncoding, NULL);
2504 } 2633 }
2505 return PyBytes_FromString(outbuf); 2634 return PyBytes_FromString(outbuf);
2506 } /* end of posix__getfullpathname */ 2635 } /* end of posix__getfullpathname */
2507 2636
2637 /* Grab GetFinalPathNameByHandle dynamically from kernel32 */
2638 static int has_GetFinalPathNameByHandle = 0;
2639 static DWORD (CALLBACK *Py_GetFinalPathNameByHandleA)(HANDLE, LPSTR, DWORD,
2640 DWORD);
2641 static DWORD (CALLBACK *Py_GetFinalPathNameByHandleW)(HANDLE, LPWSTR, DWORD,
2642 DWORD);
2643 static int
2644 check_GetFinalPathNameByHandle()
2645 {
2646 HINSTANCE hKernel32;
2647 /* only recheck */
2648 if (!has_GetFinalPathNameByHandle)
2649 {
2650 hKernel32 = GetModuleHandle("KERNEL32");
2651 *(FARPROC*)&Py_GetFinalPathNameByHandleA = GetProcAddress(hKernel32,
2652 "GetFinalPathNameByHandleA");
2653 *(FARPROC*)&Py_GetFinalPathNameByHandleW = GetProcAddress(hKernel32,
2654 "GetFinalPathNameByHandleW");
2655 has_GetFinalPathNameByHandle = Py_GetFinalPathNameByHandleA &&
2656 Py_GetFinalPathNameByHandleW;
2657 }
2658 return has_GetFinalPathNameByHandle;
2659 }
2660
2508 /* A helper function for samepath on windows */ 2661 /* A helper function for samepath on windows */
2509 static PyObject * 2662 static PyObject *
2510 posix__getfinalpathname(PyObject *self, PyObject *args) 2663 posix__getfinalpathname(PyObject *self, PyObject *args)
2511 { 2664 {
2512 HANDLE hFile; 2665 HANDLE hFile;
2513 int buf_size; 2666 int buf_size;
2514 wchar_t *target_path; 2667 wchar_t *target_path;
2515 int result_length; 2668 int result_length;
2516 PyObject *result; 2669 PyObject *result;
2517 wchar_t *path; 2670 wchar_t *path;
(...skipping 2379 matching lines...) Expand 10 before | Expand all | Expand 10 after
4897 { 5050 {
4898 return posix_2str(args, "O&O&:symlink", symlink); 5051 return posix_2str(args, "O&O&:symlink", symlink);
4899 } 5052 }
4900 #endif /* HAVE_SYMLINK */ 5053 #endif /* HAVE_SYMLINK */
4901 5054
4902 #if !defined(HAVE_READLINK) && defined(MS_WINDOWS) 5055 #if !defined(HAVE_READLINK) && defined(MS_WINDOWS)
4903 5056
4904 PyDoc_STRVAR(win_readlink__doc__, 5057 PyDoc_STRVAR(win_readlink__doc__,
4905 "readlink(path) -> path\n\n\ 5058 "readlink(path) -> path\n\n\
4906 Return a string representing the path to which the symbolic link points."); 5059 Return a string representing the path to which the symbolic link points.");
4907
4908 /* The following structure was copied from
4909 http://msdn.microsoft.com/en-us/library/ms791514.aspx as the required
4910 include doesn't seem to be present in the Windows SDK (at least as included
4911 with Visual Studio Express). */
4912 typedef struct _REPARSE_DATA_BUFFER {
4913 ULONG ReparseTag;
4914 USHORT ReparseDataLength;
4915 USHORT Reserved;
4916 union {
4917 struct {
4918 USHORT SubstituteNameOffset;
4919 USHORT SubstituteNameLength;
4920 USHORT PrintNameOffset;
4921 USHORT PrintNameLength;
4922 ULONG Flags;
4923 WCHAR PathBuffer[1];
4924 } SymbolicLinkReparseBuffer;
4925
4926 struct {
4927 USHORT SubstituteNameOffset;
4928 USHORT SubstituteNameLength;
4929 USHORT PrintNameOffset;
4930 USHORT PrintNameLength;
4931 WCHAR PathBuffer[1];
4932 } MountPointReparseBuffer;
4933
4934 struct {
4935 UCHAR DataBuffer[1];
4936 } GenericReparseBuffer;
4937 };
4938 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
4939
4940 #define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER,\
4941 GenericReparseBuffer)
4942
4943 #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )
4944 5060
4945 /* Windows readlink implementation */ 5061 /* Windows readlink implementation */
4946 static PyObject * 5062 static PyObject *
4947 win_readlink(PyObject *self, PyObject *args) 5063 win_readlink(PyObject *self, PyObject *args)
4948 { 5064 {
4949 wchar_t *path; 5065 wchar_t *path;
4950 DWORD n_bytes_returned; 5066 DWORD n_bytes_returned;
4951 DWORD io_result; 5067 DWORD io_result;
4952 PyObject *result; 5068 PyObject *result;
4953 HANDLE reparse_point_handle; 5069 HANDLE reparse_point_handle;
(...skipping 3291 matching lines...) Expand 10 before | Expand all | Expand 10 after
8245 8361
8246 8362
8247 #endif /* __APPLE__ */ 8363 #endif /* __APPLE__ */
8248 return m; 8364 return m;
8249 8365
8250 } 8366 }
8251 8367
8252 #ifdef __cplusplus 8368 #ifdef __cplusplus
8253 } 8369 }
8254 #endif 8370 #endif
LEFTRIGHT
« no previous file | no next file » | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+