diff options
| author | Karl Heuer | 1998-06-05 16:08:32 +0000 |
|---|---|---|
| committer | Karl Heuer | 1998-06-05 16:08:32 +0000 |
| commit | b3308d2eb92b86daf7b97989f2e06ae21406aa76 (patch) | |
| tree | 4bfde756ef05fba6c019968dbc73f18e1506003f /src | |
| parent | 6cf71bf1f744dae3ec072dffb40434304190db22 (diff) | |
| download | emacs-b3308d2eb92b86daf7b97989f2e06ae21406aa76.tar.gz emacs-b3308d2eb92b86daf7b97989f2e06ae21406aa76.zip | |
#include sys/file.h
(sys_access): Provide our own implementation which recognizes D_OK.
(is_exec): New function.
(stat): Use it.
(init_environment): Set TMPDIR to an existing directory.
Abort if none of the usual places is available.
(sys_rename): On Windows 95, choose a temp name that
includes the original file's base name and use an explicit loop
rather than calling mktemp. Only attempt to unlink the newname if
the rename fails, rather than second-guessing whether the old and
new names refer to the same file.
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 | ||