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

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, 10 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 486 matching lines...) Expand 10 before | Expand all | Expand 10 after
936 static int 1026 static int
937 attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, struct win32_stat *resu lt) 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);
945 result->st_nlink = info->nNumberOfLinks; 1035 result->st_nlink = info->nNumberOfLinks;
1036
946 return 0; 1037 return 0;
947 } 1038 }
948 1039
949 static BOOL 1040 static BOOL
950 attributes_from_dir(LPCSTR pszFile, BY_HANDLE_FILE_INFORMATION *info) 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)
(...skipping 23 matching lines...) Expand all
979 info->dwFileAttributes = FileData.dwFileAttributes; 1070 info->dwFileAttributes = FileData.dwFileAttributes;
980 info->ftCreationTime = FileData.ftCreationTime; 1071 info->ftCreationTime = FileData.ftCreationTime;
981 info->ftLastAccessTime = FileData.ftLastAccessTime; 1072 info->ftLastAccessTime = FileData.ftLastAccessTime;
982 info->ftLastWriteTime = FileData.ftLastWriteTime; 1073 info->ftLastWriteTime = FileData.ftLastWriteTime;
983 info->nFileSizeHigh = FileData.nFileSizeHigh; 1074 info->nFileSizeHigh = FileData.nFileSizeHigh;
984 info->nFileSizeLow = FileData.nFileSizeLow; 1075 info->nFileSizeLow = FileData.nFileSizeLow;
985 /* info->nNumberOfLinks = 1; */ 1076 /* info->nNumberOfLinks = 1; */
986 return TRUE; 1077 return TRUE;
987 } 1078 }
988 1079
989 /* About the following functions: win32_lstat, win32_lstat_w, win32_stat, 1080 #ifndef SYMLOOP_MAX
990 win32_stat_w 1081 #define SYMLOOP_MAX ( 88 )
991 1082 #endif
992 In Posix, stat automatically traverses symlinks and returns the stat 1083
993 structure for the target. In Windows, the equivalent GetFileAttributes by 1084 static int
994 default does not traverse symlinks and instead returns attributes for 1085 win32_xstat_for_handle(HANDLE hFile, struct win32_stat *result, BOOL traverse, i nt depth);
995 the symlink. 1086
996 1087 static int
997 Therefore, win32_lstat will get the attributes traditionally, and 1088 win32_xstat(const char *path, struct win32_stat *result, BOOL traverse, int dept h)
998 win32_stat will first explicitly resolve the symlink target and then will 1089 {
999 call win32_lstat on that result. 1090 int code;
1000
1001 The _w represent Unicode equivalents of the aformentioned ANSI functions. */
1002
1003 static int
1004 win32_lstat(const char* path, struct win32_stat *result)
1005 {
1006 BOOL res;
1007 HANDLE hFile; 1091 HANDLE hFile;
1008 BY_HANDLE_FILE_INFORMATION info; 1092 BY_HANDLE_FILE_INFORMATION info;
1009 const char *dot; 1093 const char *dot;
1010 WIN32_FIND_DATAA find_data;
1011 HANDLE find_data_handle;
1012 1094
1013 hFile = CreateFileA( 1095 hFile = CreateFileA(
1014 path, 1096 path,
1015 0, /* desired access */ 1097 0, /* desired access */
1016 0, /* share mode */ 1098 0, /* share mode */
1017 NULL, /* security attributes */ 1099 NULL, /* security attributes */
1018 OPEN_EXISTING, 1100 OPEN_EXISTING,
1019 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */ 1101 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
1020 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, 1102 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_ POINT,
1021 NULL); 1103 NULL);
1022 1104
1023 if(hFile == INVALID_HANDLE_VALUE) { 1105 if(hFile == INVALID_HANDLE_VALUE) {
1024 /* 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
1025 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.
1026 If the latter, we can use attributes_from_dir. */ 1108 If the latter, we can use attributes_from_dir. */
1027 if (GetLastError() != ERROR_SHARING_VIOLATION) 1109 if (GetLastError() != ERROR_SHARING_VIOLATION)
1028 goto err; 1110 goto err;
1029 else { 1111 else {
1030 /* Could not get attributes on open file. Fall back to 1112 /* Could not get attributes on open file. Fall back to
1031 reading the directory. */ 1113 reading the directory. */
1032 if (!attributes_from_dir(path, &info)) 1114 if (!attributes_from_dir(path, &info))
1033 /* Very strange. This should not fail now */ 1115 /* Very strange. This should not fail now */
1034 goto err; 1116 goto err;
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;
1121 }
1122 attribute_data_to_stat(&info, result);
1035 } 1123 }
1036 } 1124 }
1037 else { 1125 else {
1038 res = GetFileInformationByHandle(hFile, &info); 1126 code = win32_xstat_for_handle(hFile, result, traverse, depth);
1039 CloseHandle(hFile); 1127 CloseHandle(hFile);
1040 if (!res) 1128 if (code != 0)
1041 goto err; 1129 return code;
1042 } 1130 }
1043 1131
1044 attribute_data_to_stat(&info, result); 1132 /* Set S_IEXEC if it is an .exe, .bat, ... */
1045
1046 /* Get WIN32_FIND_DATA structure for the path to determine if
1047 it is a symlink */
1048 if(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1049 find_data_handle = FindFirstFileA(path, &find_data);
1050 if(find_data_handle != INVALID_HANDLE_VALUE) {
1051 if(find_data.dwReserved0 == IO_REPARSE_TAG_SYMLINK) {
1052 /* first clear the S_IFMT bits */
1053 result->st_mode ^= (result->st_mode & 0170000);
1054 /* now set the bits that make this a symlink */
1055 result->st_mode |= 0120000;
1056 }
1057 FindClose(find_data_handle);
1058 }
1059 }
1060
1061 /* Set S_IFEXEC if it is an .exe, .bat, ... */
1062 dot = strrchr(path, '.'); 1133 dot = strrchr(path, '.');
1063 if (dot) { 1134 if (dot) {
1064 if (stricmp(dot, ".bat") == 0 || stricmp(dot, ".cmd") == 0 || 1135 if (stricmp(dot, ".bat") == 0 || stricmp(dot, ".cmd") == 0 ||
1065 stricmp(dot, ".exe") == 0 || stricmp(dot, ".com") == 0) 1136 stricmp(dot, ".exe") == 0 || stricmp(dot, ".com") == 0)
1066 result->st_mode |= 0111; 1137 result->st_mode |= 0111;
1067 } 1138 }
1068 return 0; 1139 return 0;
1069 1140
1070 err: 1141 err:
1071 /* Protocol violation: we explicitly clear errno, instead of 1142 /* Protocol violation: we explicitly clear errno, instead of
1072 setting it to a POSIX error. Callers should use GetLastError. */ 1143 setting it to a POSIX error. Callers should use GetLastError. */
1073 errno = 0; 1144 errno = 0;
1074 return -1; 1145 return -1;
1075 } 1146 }
1076 1147
1077 static int 1148 static int
1078 win32_lstat_w(const wchar_t* path, struct win32_stat *result) 1149 win32_xstat_w(const wchar_t *path, struct win32_stat *result, BOOL traverse, int depth)
1079 { 1150 {
1080 BOOL res; 1151 int code;
1081 HANDLE hFile; 1152 HANDLE hFile;
1082 BY_HANDLE_FILE_INFORMATION info; 1153 BY_HANDLE_FILE_INFORMATION info;
1083 const wchar_t *dot; 1154 const wchar_t *dot;
1084 WIN32_FIND_DATAW find_data;
1085 HANDLE find_data_handle;
1086 1155
1087 hFile = CreateFileW( 1156 hFile = CreateFileW(
1088 path, 1157 path,
1089 0, /* desired access */ 1158 0, /* desired access */
1090 0, /* share mode */ 1159 0, /* share mode */
1091 NULL, /* security attributes */ 1160 NULL, /* security attributes */
1092 OPEN_EXISTING, 1161 OPEN_EXISTING,
1093 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */ 1162 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
1094 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_ POINT, 1163 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_ POINT,
1095 NULL); 1164 NULL);
1096 1165
1097 if(hFile == INVALID_HANDLE_VALUE) { 1166 if(hFile == INVALID_HANDLE_VALUE) {
1098 /* 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
1099 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.
1100 If the latter, we can use attributes_from_dir. */ 1169 If the latter, we can use attributes_from_dir. */
1101 if (GetLastError() != ERROR_SHARING_VIOLATION) 1170 if (GetLastError() != ERROR_SHARING_VIOLATION)
1102 goto err; 1171 goto err;
1103 else { 1172 else {
1104 /* Could not get attributes on open file. Fall back to 1173 /* Could not get attributes on open file. Fall back to
1105 reading the directory. */ 1174 reading the directory. */
1106 if (!attributes_from_dir_w(path, &info)) 1175 if (!attributes_from_dir_w(path, &info))
1107 /* Very strange. This should not fail now */ 1176 /* Very strange. This should not fail now */
1108 goto err; 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);
1109 } 1184 }
1110 } 1185 }
1111 else { 1186 else {
1112 res = GetFileInformationByHandle(hFile, &info); 1187 code = win32_xstat_for_handle(hFile, result, traverse, depth);
1113 CloseHandle(hFile); 1188 CloseHandle(hFile);
1114 if (!res) 1189 if (code != 0)
1115 goto err; 1190 return code;
1116 } 1191 }
1117 1192
1118 attribute_data_to_stat(&info, result); 1193 /* Set S_IEXEC if it is an .exe, .bat, ... */
1119 1194 dot = wcsrchr(path, '.');
1120 /* Get WIN32_FIND_DATA structure for the path to determine if 1195 if (dot) {
1121 it is a symlink */ 1196 if (_wcsicmp(dot, L".bat") == 0 || _wcsicmp(dot, L".cmd") == 0 ||
1122 if(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { 1197 _wcsicmp(dot, L".exe") == 0 || _wcsicmp(dot, L".com") == 0)
1123 find_data_handle = FindFirstFileW(path, &find_data); 1198 result->st_mode |= 0111;
1124 if(find_data_handle != INVALID_HANDLE_VALUE) { 1199 }
1125 if(find_data.dwReserved0 == IO_REPARSE_TAG_SYMLINK) { 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? */
1224 return -1;
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) {
1126 /* first clear the S_IFMT bits */ 1236 /* first clear the S_IFMT bits */
1127 result->st_mode ^= (result->st_mode & 0170000); 1237 result->st_mode ^= (result->st_mode & 0170000);
1128 /* now set the bits that make this a symlink */ 1238 /* now set the bits that make this a symlink */
1129 result->st_mode |= 0120000; 1239 result->st_mode |= 0120000;
1130 } 1240 }
1131 FindClose(find_data_handle);
1132 } 1241 }
1133 } 1242 } else {
1134 1243 attribute_data_to_stat(&info, result);
1135 /* Set IFEXEC if it is an .exe, .bat, ... */
1136 dot = wcsrchr(path, '.');
1137 if (dot) {
1138 if (_wcsicmp(dot, L".bat") == 0 || _wcsicmp(dot, L".cmd") == 0 ||
1139 _wcsicmp(dot, L".exe") == 0 || _wcsicmp(dot, L".com") == 0)
1140 result->st_mode |= 0111;
1141 } 1244 }
1142 return 0; 1245 return 0;
1143 1246 }
1144 err: 1247
1145 /* Protocol violation: we explicitly clear errno, instead of 1248 /* About the following functions: win32_lstat, win32_lstat_w, win32_stat,
1146 setting it to a POSIX error. Callers should use GetLastError. */ 1249 win32_stat_w
1147 errno = 0; 1250
1148 return -1; 1251 In Posix, stat automatically traverses symlinks and returns the stat
1149 } 1252 structure for the target. In Windows, the equivalent GetFileAttributes by
1150 1253 default does not traverse symlinks and instead returns attributes for
1151 /* Grab GetFinalPathNameByHandle dynamically from kernel32 */ 1254 the symlink.
1152 static int has_GetFinalPathNameByHandle = 0; 1255
1153 static DWORD (CALLBACK *Py_GetFinalPathNameByHandleA)(HANDLE, LPSTR, DWORD, 1256 Therefore, win32_lstat will get the attributes traditionally, and
1154 DWORD); 1257 win32_stat will first explicitly resolve the symlink target and then will
1155 static DWORD (CALLBACK *Py_GetFinalPathNameByHandleW)(HANDLE, LPWSTR, DWORD, 1258 call win32_lstat on that result.
1156 DWORD); 1259
1260 The _w represent Unicode equivalents of the aformentioned ANSI functions. */
1261
1262 static int
1263 win32_lstat(const char* path, struct win32_stat *result)
1264 {
1265 return win32_xstat(path, result, FALSE, 0);
1266 }
1267
1157 static int 1268 static int
1158 check_GetFinalPathNameByHandle() 1269 win32_lstat_w(const wchar_t* path, struct win32_stat *result)
1159 { 1270 {
1160 HINSTANCE hKernel32; 1271 return win32_xstat_w(path, result, FALSE, 0);
1161 /* only recheck */
1162 if (!has_GetFinalPathNameByHandle)
1163 {
1164 hKernel32 = GetModuleHandle("KERNEL32");
1165 *(FARPROC*)&Py_GetFinalPathNameByHandleA = GetProcAddress(hKernel32,
1166 "GetFinalPathNameByHandleA");
1167 *(FARPROC*)&Py_GetFinalPathNameByHandleW = GetProcAddress(hKernel32,
1168 "GetFinalPathNameByHandleW");
1169 has_GetFinalPathNameByHandle = Py_GetFinalPathNameByHandleA &&
1170 Py_GetFinalPathNameByHandleW;
1171 }
1172 return has_GetFinalPathNameByHandle;
1173 } 1272 }
1174 1273
1175 static int 1274 static int
1176 win32_stat(const char* path, struct win32_stat *result) 1275 win32_stat(const char* path, struct win32_stat *result)
1177 { 1276 {
1178 /* Traverse the symlink to the target using 1277 return win32_xstat(path, result, TRUE, 0);
1179 GetFinalPathNameByHandle()
1180 */
1181 int code;
1182 HANDLE hFile;
1183 int buf_size;
1184 char *target_path;
1185 int result_length;
1186 BY_HANDLE_FILE_INFORMATION info;
1187
1188 if(!check_GetFinalPathNameByHandle()) {
1189 /* if the OS doesn't have GetFinalPathNameByHandle, it doesn't
1190 have symlinks, so just fall back to the traditional behavior
1191 found in lstat. */
1192 return win32_lstat(path, result);
1193 }
1194
1195 hFile = CreateFileA(
1196 path,
1197 0, /* desired access */
1198 0, /* share mode */
1199 NULL, /* security attributes */
1200 OPEN_EXISTING,
1201 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
1202 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS,
1203 NULL);
1204
1205 if(hFile == INVALID_HANDLE_VALUE) {
1206 /* Either the target doesn't exist, or we don't have access to
1207 get a handle to it. If the former, we need to return an error.
1208 If the latter, we can use attributes_from_dir. */
1209 if (GetLastError() != ERROR_SHARING_VIOLATION) {
1210 /* Protocol violation: we explicitly clear errno, instead of
1211 setting it to a POSIX error. Callers should use GetLastError. */
1212 errno = 0;
1213 return -1;
1214 } else {
1215 /* Could not get attributes on open file. Fall back to
1216 reading the directory. */
1217 if (!attributes_from_dir(path, &info)) {
1218 /* Very strange. This should not fail now */
1219 errno = 0;
1220 return -1;
1221 }
1222 }
1223 code = attribute_data_to_stat(&info, result);
1224 }
1225 else {
1226 /* We have a good handle to the target, use it to determine the target
1227 path name (then we'll call lstat on it). */
1228 buf_size = Py_GetFinalPathNameByHandleA(hFile, 0, 0, VOLUME_NAME_DOS);
1229 if(!buf_size) return -1;
1230 /* Due to a slight discrepancy between GetFinalPathNameByHandleA
1231 and GetFinalPathNameByHandleW, we must allocate one more byte
1232 than reported. */
1233 target_path = (char *)malloc((buf_size+2)*sizeof(char));
1234 result_length = Py_GetFinalPathNameByHandleA(hFile, target_path,
1235 buf_size+1, VOLUME_NAME_DOS );
1236
1237 if(!result_length) {
1238 free(target_path);
1239 return -1;
1240 }
1241
1242 if(!CloseHandle(hFile)) {
1243 free(target_path);
1244 return -1;
1245 }
1246
1247 target_path[result_length] = 0;
1248 code = win32_lstat(target_path, result);
1249 free(target_path);
1250 }
1251
1252 return code;
1253 } 1278 }
1254 1279
1255 static int 1280 static int
1256 win32_stat_w(const wchar_t* path, struct win32_stat *result) 1281 win32_stat_w(const wchar_t* path, struct win32_stat *result)
1257 { 1282 {
1258 /* Traverse the symlink to the target using GetFinalPathNameByHandle() */ 1283 return win32_xstat_w(path, result, TRUE, 0);
1259 int code;
1260 HANDLE hFile;
1261 int buf_size;
1262 wchar_t *target_path;
1263 int result_length;
1264 BY_HANDLE_FILE_INFORMATION info;
1265
1266 if(!check_GetFinalPathNameByHandle()) {
1267 /* If the OS doesn't have GetFinalPathNameByHandle, it doesn't have
1268 symlinks, so just fall back to the traditional behavior found
1269 in lstat. */
1270 return win32_lstat_w(path, result);
1271 }
1272
1273 hFile = CreateFileW(
1274 path,
1275 0, /* desired access */
1276 0, /* share mode */
1277 NULL, /* security attributes */
1278 OPEN_EXISTING,
1279 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
1280 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS,
1281 NULL);
1282
1283 if(hFile == INVALID_HANDLE_VALUE) {
1284 /* Either the target doesn't exist, or we don't have access to
1285 get a handle to it. If the former, we need to return an error.
1286 If the latter, we can use attributes_from_dir. */
1287 if (GetLastError() != ERROR_SHARING_VIOLATION) {
1288 /* Protocol violation: we explicitly clear errno, instead of
1289 setting it to a POSIX error. Callers should use GetLastError. */
1290 errno = 0;
1291 return -1;
1292 } else {
1293 /* Could not get attributes on open file. Fall back to
1294 reading the directory. */
1295 if (!attributes_from_dir_w(path, &info)) {
1296 /* Very strange. This should not fail now */
1297 errno = 0;
1298 return -1;
1299 }
1300 }
1301 code = attribute_data_to_stat(&info, result);
1302 }
1303 else {
1304 /* We have a good handle to the target, use it to determine the target
1305 path name (then we'll call lstat on it). */
1306 buf_size = Py_GetFinalPathNameByHandleW(hFile, 0, 0, VOLUME_NAME_DOS);
1307 if(!buf_size)
1308 return -1;
1309
1310 target_path = (wchar_t *)malloc((buf_size+1)*sizeof(wchar_t));
1311 result_length = Py_GetFinalPathNameByHandleW(hFile, target_path,
1312 buf_size, VOLUME_NAME_DOS);
1313
1314 if(!result_length) {
1315 free(target_path);
1316 return -1;
1317 }
1318
1319 if(!CloseHandle(hFile)) {
1320 free(target_path);
1321 return -1;
1322 }
1323
1324 target_path[result_length] = 0;
1325 code = win32_lstat_w(target_path, result);
1326 free(target_path);
1327 }
1328
1329 return code;
1330 } 1284 }
1331 1285
1332 static int 1286 static int
1333 win32_fstat(int file_number, struct win32_stat *result) 1287 win32_fstat(int file_number, struct win32_stat *result)
1334 { 1288 {
1335 BY_HANDLE_FILE_INFORMATION info; 1289 BY_HANDLE_FILE_INFORMATION info;
1336 HANDLE h; 1290 HANDLE h;
1337 int type; 1291 int type;
1338 1292
1339 h = (HANDLE)_get_osfhandle(file_number); 1293 h = (HANDLE)_get_osfhandle(file_number);
(...skipping 1333 matching lines...) Expand 10 before | Expand all | Expand 10 after
2673 return NULL; 2627 return NULL;
2674 } 2628 }
2675 Py_DECREF(opath); 2629 Py_DECREF(opath);
2676 if (PyUnicode_Check(PyTuple_GetItem(args, 0))) { 2630 if (PyUnicode_Check(PyTuple_GetItem(args, 0))) {
2677 return PyUnicode_Decode(outbuf, strlen(outbuf), 2631 return PyUnicode_Decode(outbuf, strlen(outbuf),
2678 Py_FileSystemDefaultEncoding, NULL); 2632 Py_FileSystemDefaultEncoding, NULL);
2679 } 2633 }
2680 return PyBytes_FromString(outbuf); 2634 return PyBytes_FromString(outbuf);
2681 } /* end of posix__getfullpathname */ 2635 } /* end of posix__getfullpathname */
2682 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
2683 /* A helper function for samepath on windows */ 2661 /* A helper function for samepath on windows */
2684 static PyObject * 2662 static PyObject *
2685 posix__getfinalpathname(PyObject *self, PyObject *args) 2663 posix__getfinalpathname(PyObject *self, PyObject *args)
2686 { 2664 {
2687 HANDLE hFile; 2665 HANDLE hFile;
2688 int buf_size; 2666 int buf_size;
2689 wchar_t *target_path; 2667 wchar_t *target_path;
2690 int result_length; 2668 int result_length;
2691 PyObject *result; 2669 PyObject *result;
2692 wchar_t *path; 2670 wchar_t *path;
(...skipping 2379 matching lines...) Expand 10 before | Expand all | Expand 10 after
5072 { 5050 {
5073 return posix_2str(args, "O&O&:symlink", symlink); 5051 return posix_2str(args, "O&O&:symlink", symlink);
5074 } 5052 }
5075 #endif /* HAVE_SYMLINK */ 5053 #endif /* HAVE_SYMLINK */
5076 5054
5077 #if !defined(HAVE_READLINK) && defined(MS_WINDOWS) 5055 #if !defined(HAVE_READLINK) && defined(MS_WINDOWS)
5078 5056
5079 PyDoc_STRVAR(win_readlink__doc__, 5057 PyDoc_STRVAR(win_readlink__doc__,
5080 "readlink(path) -> path\n\n\ 5058 "readlink(path) -> path\n\n\
5081 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.");
5082
5083 /* The following structure was copied from
5084 http://msdn.microsoft.com/en-us/library/ms791514.aspx as the required
5085 include doesn't seem to be present in the Windows SDK (at least as included
5086 with Visual Studio Express). */
5087 typedef struct _REPARSE_DATA_BUFFER {
5088 ULONG ReparseTag;
5089 USHORT ReparseDataLength;
5090 USHORT Reserved;
5091 union {
5092 struct {
5093 USHORT SubstituteNameOffset;
5094 USHORT SubstituteNameLength;
5095 USHORT PrintNameOffset;
5096 USHORT PrintNameLength;
5097 ULONG Flags;
5098 WCHAR PathBuffer[1];
5099 } SymbolicLinkReparseBuffer;
5100
5101 struct {
5102 USHORT SubstituteNameOffset;
5103 USHORT SubstituteNameLength;
5104 USHORT PrintNameOffset;
5105 USHORT PrintNameLength;
5106 WCHAR PathBuffer[1];
5107 } MountPointReparseBuffer;
5108
5109 struct {
5110 UCHAR DataBuffer[1];
5111 } GenericReparseBuffer;
5112 };
5113 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
5114
5115 #define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER,\
5116 GenericReparseBuffer)
5117
5118 #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )
5119 5060
5120 /* Windows readlink implementation */ 5061 /* Windows readlink implementation */
5121 static PyObject * 5062 static PyObject *
5122 win_readlink(PyObject *self, PyObject *args) 5063 win_readlink(PyObject *self, PyObject *args)
5123 { 5064 {
5124 wchar_t *path; 5065 wchar_t *path;
5125 DWORD n_bytes_returned; 5066 DWORD n_bytes_returned;
5126 DWORD io_result; 5067 DWORD io_result;
5127 PyObject *result; 5068 PyObject *result;
5128 HANDLE reparse_point_handle; 5069 HANDLE reparse_point_handle;
(...skipping 3291 matching lines...) Expand 10 before | Expand all | Expand 10 after
8420 8361
8421 8362
8422 #endif /* __APPLE__ */ 8363 #endif /* __APPLE__ */
8423 return m; 8364 return m;
8424 8365
8425 } 8366 }
8426 8367
8427 #ifdef __cplusplus 8368 #ifdef __cplusplus
8428 } 8369 }
8429 #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+