diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/w32.c | 146 |
1 files changed, 113 insertions, 33 deletions
| @@ -30,6 +30,7 @@ Boston, MA 02111-1307, USA. | |||
| 30 | #include <fcntl.h> | 30 | #include <fcntl.h> |
| 31 | #include <ctype.h> | 31 | #include <ctype.h> |
| 32 | #include <signal.h> | 32 | #include <signal.h> |
| 33 | #include <sys/file.h> | ||
| 33 | #include <sys/time.h> | 34 | #include <sys/time.h> |
| 34 | #include <sys/utime.h> | 35 | #include <sys/utime.h> |
| 35 | 36 | ||
| @@ -627,6 +628,42 @@ extern Lisp_Object Vsystem_configuration; | |||
| 627 | void | 628 | void |
| 628 | init_environment () | 629 | init_environment () |
| 629 | { | 630 | { |
| 631 | int len; | ||
| 632 | static const char * const tempdirs[] = { | ||
| 633 | "$TMPDIR", "$TEMP", "$TMP", "c:/" | ||
| 634 | }; | ||
| 635 | int i; | ||
| 636 | const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]); | ||
| 637 | |||
| 638 | /* Make sure they have a usable $TMPDIR. Many Emacs functions use | ||
| 639 | temporary files and assume "/tmp" if $TMPDIR is unset, which | ||
| 640 | will break on DOS/Windows. Refuse to work if we cannot find | ||
| 641 | a directory, not even "c:/", usable for that purpose. */ | ||
| 642 | for (i = 0; i < imax ; i++) | ||
| 643 | { | ||
| 644 | const char *tmp = tempdirs[i]; | ||
| 645 | |||
| 646 | if (*tmp == '$') | ||
| 647 | tmp = getenv (tmp + 1); | ||
| 648 | /* Note that `access' can lie to us if the directory resides on a | ||
| 649 | read-only filesystem, like CD-ROM or a write-protected floppy. | ||
| 650 | The only way to be really sure is to actually create a file and | ||
| 651 | see if it succeeds. But I think that's too much to ask. */ | ||
| 652 | if (tmp && access (tmp, D_OK) == 0) | ||
| 653 | { | ||
| 654 | char * var = alloca (strlen (tmp) + 8); | ||
| 655 | sprintf (var, "TMPDIR=%s", tmp); | ||
| 656 | putenv (var); | ||
| 657 | break; | ||
| 658 | } | ||
| 659 | } | ||
| 660 | if (i >= imax) | ||
| 661 | cmd_error_internal | ||
| 662 | (Fcons (Qerror, | ||
| 663 | Fcons (build_string ("no usable temporary directories found!!"), | ||
| 664 | Qnil)), | ||
| 665 | "While setting TMPDIR: "); | ||
| 666 | |||
| 630 | /* Check for environment variables and use registry if they don't exist */ | 667 | /* Check for environment variables and use registry if they don't exist */ |
| 631 | { | 668 | { |
| 632 | int i; | 669 | int i; |
| @@ -1135,6 +1172,18 @@ map_w32_filename (const char * name, const char ** pPath) | |||
| 1135 | return shortname; | 1172 | return shortname; |
| 1136 | } | 1173 | } |
| 1137 | 1174 | ||
| 1175 | static int | ||
| 1176 | is_exec (const char * name) | ||
| 1177 | { | ||
| 1178 | char * p = strrchr (name, '.'); | ||
| 1179 | return | ||
| 1180 | (p != NULL | ||
| 1181 | && (stricmp (p, ".exe") == 0 || | ||
| 1182 | stricmp (p, ".com") == 0 || | ||
| 1183 | stricmp (p, ".bat") == 0 || | ||
| 1184 | stricmp (p, ".cmd") == 0)); | ||
| 1185 | } | ||
| 1186 | |||
| 1138 | /* Emulate the Unix directory procedures opendir, closedir, | 1187 | /* Emulate the Unix directory procedures opendir, closedir, |
| 1139 | and readdir. We can't use the procedures supplied in sysdep.c, | 1188 | and readdir. We can't use the procedures supplied in sysdep.c, |
| 1140 | so we provide them here. */ | 1189 | so we provide them here. */ |
| @@ -1240,7 +1289,33 @@ readdir (DIR *dirp) | |||
| 1240 | int | 1289 | int |
| 1241 | sys_access (const char * path, int mode) | 1290 | sys_access (const char * path, int mode) |
| 1242 | { | 1291 | { |
| 1243 | return _access (map_w32_filename (path, NULL), mode); | 1292 | DWORD attributes; |
| 1293 | |||
| 1294 | /* MSVC implementation doesn't recognize D_OK. */ | ||
| 1295 | path = map_w32_filename (path, NULL); | ||
| 1296 | if ((attributes = GetFileAttributes (path)) == -1) | ||
| 1297 | { | ||
| 1298 | /* Should try mapping GetLastError to errno; for now just indicate | ||
| 1299 | that path doesn't exist. */ | ||
| 1300 | errno = EACCES; | ||
| 1301 | return -1; | ||
| 1302 | } | ||
| 1303 | if ((mode & X_OK) != 0 && !is_exec (path)) | ||
| 1304 | { | ||
| 1305 | errno = EACCES; | ||
| 1306 | return -1; | ||
| 1307 | } | ||
| 1308 | if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0) | ||
| 1309 | { | ||
| 1310 | errno = EACCES; | ||
| 1311 | return -1; | ||
| 1312 | } | ||
| 1313 | if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) | ||
| 1314 | { | ||
| 1315 | errno = EACCES; | ||
| 1316 | return -1; | ||
| 1317 | } | ||
| 1318 | return 0; | ||
| 1244 | } | 1319 | } |
| 1245 | 1320 | ||
| 1246 | int | 1321 | int |
| @@ -1444,9 +1519,8 @@ sys_open (const char * path, int oflag, int mode) | |||
| 1444 | int | 1519 | int |
| 1445 | sys_rename (const char * oldname, const char * newname) | 1520 | sys_rename (const char * oldname, const char * newname) |
| 1446 | { | 1521 | { |
| 1447 | char temp[MAX_PATH]; | ||
| 1448 | DWORD attr; | ||
| 1449 | int result; | 1522 | int result; |
| 1523 | char temp[MAX_PATH]; | ||
| 1450 | 1524 | ||
| 1451 | /* MoveFile on Windows 95 doesn't correctly change the short file name | 1525 | /* MoveFile on Windows 95 doesn't correctly change the short file name |
| 1452 | alias in a number of circumstances (it is not easy to predict when | 1526 | alias in a number of circumstances (it is not easy to predict when |
| @@ -1465,39 +1539,53 @@ sys_rename (const char * oldname, const char * newname) | |||
| 1465 | 1539 | ||
| 1466 | if (os_subtype == OS_WIN95) | 1540 | if (os_subtype == OS_WIN95) |
| 1467 | { | 1541 | { |
| 1542 | char * o; | ||
| 1468 | char * p; | 1543 | char * p; |
| 1544 | int i = 0; | ||
| 1545 | |||
| 1546 | oldname = map_w32_filename (oldname, NULL); | ||
| 1547 | if (o = strrchr (oldname, '\\')) | ||
| 1548 | o++; | ||
| 1549 | else | ||
| 1550 | o = (char *) oldname; | ||
| 1469 | 1551 | ||
| 1470 | if (p = strrchr (temp, '\\')) | 1552 | if (p = strrchr (temp, '\\')) |
| 1471 | p++; | 1553 | p++; |
| 1472 | else | 1554 | else |
| 1473 | p = temp; | 1555 | p = temp; |
| 1474 | /* Force temp name to require a manufactured 8.3 alias - this | 1556 | |
| 1475 | seems to make the second rename work properly. */ | 1557 | do |
| 1476 | strcpy (p, "_rename_temp.XXXXXX"); | 1558 | { |
| 1477 | sys_mktemp (temp); | 1559 | /* Force temp name to require a manufactured 8.3 alias - this |
| 1478 | if (rename (map_w32_filename (oldname, NULL), temp) < 0) | 1560 | seems to make the second rename work properly. */ |
| 1561 | sprintf (p, ".%s.%u", o, i); | ||
| 1562 | i++; | ||
| 1563 | } | ||
| 1564 | /* This loop must surely terminate! */ | ||
| 1565 | while (rename (oldname, temp) < 0 && errno == EEXIST); | ||
| 1566 | if (errno != EEXIST) | ||
| 1479 | return -1; | 1567 | return -1; |
| 1480 | } | 1568 | } |
| 1481 | 1569 | ||
| 1482 | /* Emulate Unix behaviour - newname is deleted if it already exists | 1570 | /* Emulate Unix behaviour - newname is deleted if it already exists |
| 1483 | (at least if it is a file; don't do this for directories). | 1571 | (at least if it is a file; don't do this for directories). |
| 1484 | However, don't do this if we are just changing the case of the file | ||
| 1485 | name - we will end up deleting the file we are trying to rename! */ | ||
| 1486 | newname = map_w32_filename (newname, NULL); | ||
| 1487 | 1572 | ||
| 1488 | /* Suggested by Pekka Pirila <pekka.pirila@vtt.fi>: stricmp does not | 1573 | Since we mustn't do this if we are just changing the case of the |
| 1489 | handle accented characters correctly, so comparing filenames will | 1574 | file name (we would end up deleting the file we are trying to |
| 1490 | accidentally delete these files. Instead, do the rename first; | 1575 | rename!), we let rename detect if the destination file already |
| 1491 | newname will not be deleted if successful or if errno == EACCES. | 1576 | exists - that way we avoid the possible pitfalls of trying to |
| 1492 | In this case, delete the file explicitly. */ | 1577 | determine ourselves whether two names really refer to the same |
| 1578 | file, which is not always possible in the general case. (Consider | ||
| 1579 | all the permutations of shared or subst'd drives, etc.) */ | ||
| 1580 | |||
| 1581 | newname = map_w32_filename (newname, NULL); | ||
| 1493 | result = rename (temp, newname); | 1582 | result = rename (temp, newname); |
| 1494 | if (result < 0 && errno == EACCES | 1583 | |
| 1495 | && (attr = GetFileAttributes (newname)) != -1 | 1584 | if (result < 0 |
| 1496 | && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0) | 1585 | && errno == EEXIST |
| 1497 | { | 1586 | && _chmod (newname, 0666) == 0 |
| 1498 | _chmod (newname, 0666); | 1587 | && _unlink (newname) == 0) |
| 1499 | _unlink (newname); | 1588 | result = rename (temp, newname); |
| 1500 | } | ||
| 1501 | 1589 | ||
| 1502 | return result; | 1590 | return result; |
| 1503 | } | 1591 | } |
| @@ -1813,16 +1901,8 @@ stat (const char * path, struct stat * buf) | |||
| 1813 | 1901 | ||
| 1814 | if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | 1902 | if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
| 1815 | permission |= _S_IEXEC; | 1903 | permission |= _S_IEXEC; |
| 1816 | else | 1904 | else if (is_exec (name)) |
| 1817 | { | 1905 | permission |= _S_IEXEC; |
| 1818 | char * p = strrchr (name, '.'); | ||
| 1819 | if (p != NULL | ||
| 1820 | && (stricmp (p, ".exe") == 0 || | ||
| 1821 | stricmp (p, ".com") == 0 || | ||
| 1822 | stricmp (p, ".bat") == 0 || | ||
| 1823 | stricmp (p, ".cmd") == 0)) | ||
| 1824 | permission |= _S_IEXEC; | ||
| 1825 | } | ||
| 1826 | 1906 | ||
| 1827 | buf->st_mode |= permission | (permission >> 3) | (permission >> 6); | 1907 | buf->st_mode |= permission | (permission >> 3) | (permission >> 6); |
| 1828 | 1908 | ||