comparison src/w32.c @ 22363:d00f146c3e9d

#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.
author Karl Heuer <kwzh@gnu.org>
date Fri, 05 Jun 1998 16:08:32 +0000
parents 83928cc3329e
children 921311b43bf4
comparison
equal deleted inserted replaced
22362:e845baca3407 22363:d00f146c3e9d
28 #include <io.h> 28 #include <io.h>
29 #include <errno.h> 29 #include <errno.h>
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
36 /* must include CRT headers *before* config.h */ 37 /* must include CRT headers *before* config.h */
37 #include "config.h" 38 #include "config.h"
625 extern Lisp_Object Vsystem_configuration; 626 extern Lisp_Object Vsystem_configuration;
626 627
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;
633 LPBYTE lpval; 670 LPBYTE lpval;
634 DWORD dwType; 671 DWORD dwType;
1133 *pPath = shortname + (path - save_name); 1170 *pPath = shortname + (path - save_name);
1134 1171
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. */
1141 1190
1142 struct direct dir_static; /* simulated directory contents */ 1191 struct direct dir_static; /* simulated directory contents */
1238 long file names. */ 1287 long file names. */
1239 1288
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
1247 sys_chdir (const char * path) 1322 sys_chdir (const char * path)
1248 { 1323 {
1442 } 1517 }
1443 1518
1444 int 1519 int
1445 sys_rename (const char * oldname, const char * newname) 1520 sys_rename (const char * oldname, const char * newname)
1446 { 1521 {
1522 int result;
1447 char temp[MAX_PATH]; 1523 char temp[MAX_PATH];
1448 DWORD attr;
1449 int result;
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
1453 just by looking at oldname and newname, unfortunately). In these 1527 just by looking at oldname and newname, unfortunately). In these
1454 cases, renaming through a temporary name avoids the problem. 1528 cases, renaming through a temporary name avoids the problem.
1463 1537
1464 strcpy (temp, map_w32_filename (oldname, NULL)); 1538 strcpy (temp, map_w32_filename (oldname, NULL));
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 1572
1485 name - we will end up deleting the file we are trying to rename! */ 1573 Since we mustn't do this if we are just changing the case of the
1574 file name (we would end up deleting the file we are trying to
1575 rename!), we let rename detect if the destination file already
1576 exists - that way we avoid the possible pitfalls of trying to
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
1486 newname = map_w32_filename (newname, NULL); 1581 newname = map_w32_filename (newname, NULL);
1487
1488 /* Suggested by Pekka Pirila <pekka.pirila@vtt.fi>: stricmp does not
1489 handle accented characters correctly, so comparing filenames will
1490 accidentally delete these files. Instead, do the rename first;
1491 newname will not be deleted if successful or if errno == EACCES.
1492 In this case, delete the file explicitly. */
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 }
1504 1592
1505 int 1593 int
1811 else 1899 else
1812 permission = _S_IREAD | _S_IWRITE; 1900 permission = _S_IREAD | _S_IWRITE;
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
1829 return 0; 1909 return 0;
1830 } 1910 }