diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/w32.c | 148 |
1 files changed, 143 insertions, 5 deletions
| @@ -533,6 +533,19 @@ w32_get_long_filename (char * name, char * buf, int size) | |||
| 533 | return TRUE; | 533 | return TRUE; |
| 534 | } | 534 | } |
| 535 | 535 | ||
| 536 | int | ||
| 537 | is_unc_volume (const char *filename) | ||
| 538 | { | ||
| 539 | const char *ptr = filename; | ||
| 540 | |||
| 541 | if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2]) | ||
| 542 | return 0; | ||
| 543 | |||
| 544 | if (strpbrk (ptr + 2, "*?|<>\"\\/")) | ||
| 545 | return 0; | ||
| 546 | |||
| 547 | return 1; | ||
| 548 | } | ||
| 536 | 549 | ||
| 537 | /* Routines that are no-ops on NT but are defined to get Emacs to compile. */ | 550 | /* Routines that are no-ops on NT but are defined to get Emacs to compile. */ |
| 538 | 551 | ||
| @@ -1194,6 +1207,13 @@ static int dir_is_fat; | |||
| 1194 | static char dir_pathname[MAXPATHLEN+1]; | 1207 | static char dir_pathname[MAXPATHLEN+1]; |
| 1195 | static WIN32_FIND_DATA dir_find_data; | 1208 | static WIN32_FIND_DATA dir_find_data; |
| 1196 | 1209 | ||
| 1210 | /* Support shares on a network resource as subdirectories of a read-only | ||
| 1211 | root directory. */ | ||
| 1212 | static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE; | ||
| 1213 | HANDLE open_unc_volume (char *); | ||
| 1214 | char *read_unc_volume (HANDLE, char *, int); | ||
| 1215 | void close_unc_volume (HANDLE); | ||
| 1216 | |||
| 1197 | DIR * | 1217 | DIR * |
| 1198 | opendir (char *filename) | 1218 | opendir (char *filename) |
| 1199 | { | 1219 | { |
| @@ -1202,10 +1222,20 @@ opendir (char *filename) | |||
| 1202 | /* Opening is done by FindFirstFile. However, a read is inherent to | 1222 | /* Opening is done by FindFirstFile. However, a read is inherent to |
| 1203 | this operation, so we defer the open until read time. */ | 1223 | this operation, so we defer the open until read time. */ |
| 1204 | 1224 | ||
| 1205 | if (!(dirp = (DIR *) malloc (sizeof (DIR)))) | ||
| 1206 | return NULL; | ||
| 1207 | if (dir_find_handle != INVALID_HANDLE_VALUE) | 1225 | if (dir_find_handle != INVALID_HANDLE_VALUE) |
| 1208 | return NULL; | 1226 | return NULL; |
| 1227 | if (wnet_enum_handle != INVALID_HANDLE_VALUE) | ||
| 1228 | return NULL; | ||
| 1229 | |||
| 1230 | if (is_unc_volume (filename)) | ||
| 1231 | { | ||
| 1232 | wnet_enum_handle = open_unc_volume (filename); | ||
| 1233 | if (wnet_enum_handle == INVALID_HANDLE_VALUE) | ||
| 1234 | return NULL; | ||
| 1235 | } | ||
| 1236 | |||
| 1237 | if (!(dirp = (DIR *) malloc (sizeof (DIR)))) | ||
| 1238 | return NULL; | ||
| 1209 | 1239 | ||
| 1210 | dirp->dd_fd = 0; | 1240 | dirp->dd_fd = 0; |
| 1211 | dirp->dd_loc = 0; | 1241 | dirp->dd_loc = 0; |
| @@ -1227,14 +1257,26 @@ closedir (DIR *dirp) | |||
| 1227 | FindClose (dir_find_handle); | 1257 | FindClose (dir_find_handle); |
| 1228 | dir_find_handle = INVALID_HANDLE_VALUE; | 1258 | dir_find_handle = INVALID_HANDLE_VALUE; |
| 1229 | } | 1259 | } |
| 1260 | else if (wnet_enum_handle != INVALID_HANDLE_VALUE) | ||
| 1261 | { | ||
| 1262 | close_unc_volume (wnet_enum_handle); | ||
| 1263 | wnet_enum_handle = INVALID_HANDLE_VALUE; | ||
| 1264 | } | ||
| 1230 | xfree ((char *) dirp); | 1265 | xfree ((char *) dirp); |
| 1231 | } | 1266 | } |
| 1232 | 1267 | ||
| 1233 | struct direct * | 1268 | struct direct * |
| 1234 | readdir (DIR *dirp) | 1269 | readdir (DIR *dirp) |
| 1235 | { | 1270 | { |
| 1271 | if (wnet_enum_handle != INVALID_HANDLE_VALUE) | ||
| 1272 | { | ||
| 1273 | if (!read_unc_volume (wnet_enum_handle, | ||
| 1274 | dir_find_data.cFileName, | ||
| 1275 | MAX_PATH)) | ||
| 1276 | return NULL; | ||
| 1277 | } | ||
| 1236 | /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */ | 1278 | /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */ |
| 1237 | if (dir_find_handle == INVALID_HANDLE_VALUE) | 1279 | else if (dir_find_handle == INVALID_HANDLE_VALUE) |
| 1238 | { | 1280 | { |
| 1239 | char filename[MAXNAMLEN + 3]; | 1281 | char filename[MAXNAMLEN + 3]; |
| 1240 | int ln; | 1282 | int ln; |
| @@ -1280,6 +1322,80 @@ readdir (DIR *dirp) | |||
| 1280 | return &dir_static; | 1322 | return &dir_static; |
| 1281 | } | 1323 | } |
| 1282 | 1324 | ||
| 1325 | HANDLE | ||
| 1326 | open_unc_volume (char *path) | ||
| 1327 | { | ||
| 1328 | NETRESOURCE nr; | ||
| 1329 | HANDLE henum; | ||
| 1330 | int result; | ||
| 1331 | |||
| 1332 | nr.dwScope = RESOURCE_GLOBALNET; | ||
| 1333 | nr.dwType = RESOURCETYPE_DISK; | ||
| 1334 | nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER; | ||
| 1335 | nr.dwUsage = RESOURCEUSAGE_CONTAINER; | ||
| 1336 | nr.lpLocalName = NULL; | ||
| 1337 | nr.lpRemoteName = map_w32_filename (path, NULL); | ||
| 1338 | nr.lpComment = NULL; | ||
| 1339 | nr.lpProvider = NULL; | ||
| 1340 | |||
| 1341 | result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, | ||
| 1342 | RESOURCEUSAGE_CONNECTABLE, &nr, &henum); | ||
| 1343 | |||
| 1344 | if (result == NO_ERROR) | ||
| 1345 | return henum; | ||
| 1346 | else | ||
| 1347 | return INVALID_HANDLE_VALUE; | ||
| 1348 | } | ||
| 1349 | |||
| 1350 | char * | ||
| 1351 | read_unc_volume (HANDLE henum, char *readbuf, int size) | ||
| 1352 | { | ||
| 1353 | int count; | ||
| 1354 | int result; | ||
| 1355 | int bufsize = 512; | ||
| 1356 | char *buffer; | ||
| 1357 | char *ptr; | ||
| 1358 | |||
| 1359 | count = 1; | ||
| 1360 | buffer = alloca (bufsize); | ||
| 1361 | result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize); | ||
| 1362 | if (result != NO_ERROR) | ||
| 1363 | return NULL; | ||
| 1364 | |||
| 1365 | /* WNetEnumResource returns \\resource\share...skip forward to "share". */ | ||
| 1366 | ptr = ((LPNETRESOURCE) buffer)->lpRemoteName; | ||
| 1367 | ptr += 2; | ||
| 1368 | while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++; | ||
| 1369 | ptr++; | ||
| 1370 | |||
| 1371 | strncpy (readbuf, ptr, size); | ||
| 1372 | return readbuf; | ||
| 1373 | } | ||
| 1374 | |||
| 1375 | void | ||
| 1376 | close_unc_volume (HANDLE henum) | ||
| 1377 | { | ||
| 1378 | if (henum != INVALID_HANDLE_VALUE) | ||
| 1379 | WNetCloseEnum (henum); | ||
| 1380 | } | ||
| 1381 | |||
| 1382 | DWORD | ||
| 1383 | unc_volume_file_attributes (char *path) | ||
| 1384 | { | ||
| 1385 | HANDLE henum; | ||
| 1386 | DWORD attrs; | ||
| 1387 | |||
| 1388 | henum = open_unc_volume (path); | ||
| 1389 | if (henum == INVALID_HANDLE_VALUE) | ||
| 1390 | return -1; | ||
| 1391 | |||
| 1392 | attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY; | ||
| 1393 | |||
| 1394 | close_unc_volume (henum); | ||
| 1395 | |||
| 1396 | return attrs; | ||
| 1397 | } | ||
| 1398 | |||
| 1283 | 1399 | ||
| 1284 | /* Shadow some MSVC runtime functions to map requests for long filenames | 1400 | /* Shadow some MSVC runtime functions to map requests for long filenames |
| 1285 | to reasonable short names if necessary. This was originally added to | 1401 | to reasonable short names if necessary. This was originally added to |
| @@ -1293,7 +1409,15 @@ sys_access (const char * path, int mode) | |||
| 1293 | 1409 | ||
| 1294 | /* MSVC implementation doesn't recognize D_OK. */ | 1410 | /* MSVC implementation doesn't recognize D_OK. */ |
| 1295 | path = map_w32_filename (path, NULL); | 1411 | path = map_w32_filename (path, NULL); |
| 1296 | if ((attributes = GetFileAttributes (path)) == -1) | 1412 | if (is_unc_volume (path)) |
| 1413 | { | ||
| 1414 | attributes = unc_volume_file_attributes (path); | ||
| 1415 | if (attributes == -1) { | ||
| 1416 | errno = EACCES; | ||
| 1417 | return -1; | ||
| 1418 | } | ||
| 1419 | } | ||
| 1420 | else if ((attributes = GetFileAttributes (path)) == -1) | ||
| 1297 | { | 1421 | { |
| 1298 | /* Should try mapping GetLastError to errno; for now just indicate | 1422 | /* Should try mapping GetLastError to errno; for now just indicate |
| 1299 | that path doesn't exist. */ | 1423 | that path doesn't exist. */ |
| @@ -1759,7 +1883,21 @@ stat (const char * path, struct stat * buf) | |||
| 1759 | && (IS_DIRECTORY_SEP (*path) || *path == 0)); | 1883 | && (IS_DIRECTORY_SEP (*path) || *path == 0)); |
| 1760 | name = strcpy (alloca (len + 2), name); | 1884 | name = strcpy (alloca (len + 2), name); |
| 1761 | 1885 | ||
| 1762 | if (rootdir) | 1886 | if (is_unc_volume (name)) |
| 1887 | { | ||
| 1888 | DWORD attrs = unc_volume_file_attributes (name); | ||
| 1889 | |||
| 1890 | if (attrs == -1) | ||
| 1891 | return -1; | ||
| 1892 | |||
| 1893 | memset (&wfd, 0, sizeof (wfd)); | ||
| 1894 | wfd.dwFileAttributes = attrs; | ||
| 1895 | wfd.ftCreationTime = utc_base_ft; | ||
| 1896 | wfd.ftLastAccessTime = utc_base_ft; | ||
| 1897 | wfd.ftLastWriteTime = utc_base_ft; | ||
| 1898 | strcpy (wfd.cFileName, name); | ||
| 1899 | } | ||
| 1900 | else if (rootdir) | ||
| 1763 | { | 1901 | { |
| 1764 | if (!IS_DIRECTORY_SEP (name[len-1])) | 1902 | if (!IS_DIRECTORY_SEP (name[len-1])) |
| 1765 | strcat (name, "\\"); | 1903 | strcat (name, "\\"); |