Mercurial > hg > xemacs-beta
comparison src/nt.c @ 290:c9fe270a4101 r21-0b43
Import from CVS: tag r21-0b43
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:36:47 +0200 |
parents | e11d67e05968 |
children | 70ad99077275 |
comparison
equal
deleted
inserted
replaced
289:6e6992ccc4b6 | 290:c9fe270a4101 |
---|---|
22 Geoff Voelker (voelker@cs.washington.edu) 7-29-94 */ | 22 Geoff Voelker (voelker@cs.washington.edu) 7-29-94 */ |
23 | 23 |
24 /* Adapted for XEmacs by David Hobley <david@spook-le0.cia.com.au> */ | 24 /* Adapted for XEmacs by David Hobley <david@spook-le0.cia.com.au> */ |
25 /* Sync'ed with Emacs 19.34.6 by Marc Paquette <marcpa@cam.org> */ | 25 /* Sync'ed with Emacs 19.34.6 by Marc Paquette <marcpa@cam.org> */ |
26 | 26 |
27 #include <config.h> | |
28 | |
29 #undef signal | |
30 #define getwd _getwd | |
31 #include "lisp.h" | |
32 #undef getwd | |
33 | |
34 #include "systime.h" | |
35 #include "syssignal.h" | |
36 #include "sysproc.h" | |
37 | |
38 #include <ctype.h> | |
39 #include <direct.h> | |
40 #include <errno.h> | |
41 #include <fcntl.h> | |
42 #include <io.h> | |
43 #include <pwd.h> | |
44 #include <signal.h> | |
27 #include <stddef.h> /* for offsetof */ | 45 #include <stddef.h> /* for offsetof */ |
28 #include <string.h> | 46 #include <string.h> |
29 #include <stdlib.h> | 47 #include <stdlib.h> |
30 #include <stdio.h> | 48 #include <stdio.h> |
31 #include <io.h> | |
32 #include <errno.h> | |
33 #include <fcntl.h> | |
34 #include <ctype.h> | |
35 #include <signal.h> | |
36 #include <direct.h> | |
37 | |
38 /* must include CRT headers *before* config.h */ | |
39 /* ### I don't believe it - martin */ | |
40 #include <config.h> | |
41 #include "systime.h" | |
42 #include "syssignal.h" | |
43 #include "sysproc.h" | |
44 | |
45 #undef access | |
46 #undef chdir | |
47 #undef chmod | |
48 #undef creat | |
49 #undef ctime | |
50 #undef fopen | |
51 #undef link | |
52 #undef mkdir | |
53 #undef mktemp | |
54 #undef open | |
55 #undef rename | |
56 #undef rmdir | |
57 #undef unlink | |
58 | |
59 #undef close | |
60 #undef dup | |
61 #undef dup2 | |
62 #undef pipe | |
63 #undef read | |
64 #undef write | |
65 #undef closedir | |
66 | |
67 #define getwd _getwd | |
68 #include "lisp.h" | |
69 #undef getwd | |
70 | |
71 #include <pwd.h> | |
72 | 49 |
73 #include <windows.h> | 50 #include <windows.h> |
74 #include <mmsystem.h> | 51 #include <mmsystem.h> |
75 | 52 |
76 #include "nt.h" | 53 #include "nt.h" |
1213 } | 1190 } |
1214 | 1191 |
1215 return &dir_static; | 1192 return &dir_static; |
1216 } | 1193 } |
1217 | 1194 |
1218 /* Shadow some MSVC runtime functions to map requests for long filenames | 1195 #if 0 |
1219 to reasonable short names if necessary. This was originally added to | 1196 /* #### Have to check if all that sad story about '95 is true - kkm */ |
1220 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support | |
1221 long file names. */ | |
1222 | |
1223 int | |
1224 sys_access (const char * path, int mode) | |
1225 { | |
1226 return _access (map_win32_filename (path, NULL), mode); | |
1227 } | |
1228 | |
1229 int | |
1230 sys_chdir (const char * path) | |
1231 { | |
1232 return _chdir (map_win32_filename (path, NULL)); | |
1233 } | |
1234 | |
1235 int | |
1236 sys_chmod (const char * path, mode_t mode) | |
1237 { | |
1238 return _chmod (map_win32_filename (path, NULL), mode); | |
1239 } | |
1240 | |
1241 int | |
1242 sys_creat (const char * path, mode_t mode) | |
1243 { | |
1244 return _creat (map_win32_filename (path, NULL), mode); | |
1245 } | |
1246 | |
1247 FILE * | |
1248 sys_fopen(const char * path, const char * mode) | |
1249 { | |
1250 int fd; | |
1251 int oflag; | |
1252 const char * mode_save = mode; | |
1253 | |
1254 /* Force all file handles to be non-inheritable. This is necessary to | |
1255 ensure child processes don't unwittingly inherit handles that might | |
1256 prevent future file access. */ | |
1257 | |
1258 if (mode[0] == 'r') | |
1259 oflag = O_RDONLY; | |
1260 else if (mode[0] == 'w' || mode[0] == 'a') | |
1261 oflag = O_WRONLY | O_CREAT | O_TRUNC; | |
1262 else | |
1263 return NULL; | |
1264 | |
1265 /* Only do simplistic option parsing. */ | |
1266 while (*++mode) | |
1267 if (mode[0] == '+') | |
1268 { | |
1269 oflag &= ~(O_RDONLY | O_WRONLY); | |
1270 oflag |= O_RDWR; | |
1271 } | |
1272 else if (mode[0] == 'b') | |
1273 { | |
1274 oflag &= ~O_TEXT; | |
1275 oflag |= O_BINARY; | |
1276 } | |
1277 else if (mode[0] == 't') | |
1278 { | |
1279 oflag &= ~O_BINARY; | |
1280 oflag |= O_TEXT; | |
1281 } | |
1282 else break; | |
1283 | |
1284 fd = _open (map_win32_filename (path, NULL), oflag | _O_NOINHERIT, 0644); | |
1285 if (fd < 0) | |
1286 return NULL; | |
1287 | |
1288 return _fdopen (fd, mode_save); | |
1289 } | |
1290 | |
1291 /* This only works on NTFS volumes, but is useful to have. */ | |
1292 int | |
1293 sys_link (const char * old, const char * new) | |
1294 { | |
1295 HANDLE fileh; | |
1296 int result = -1; | |
1297 char oldname[MAX_PATH], newname[MAX_PATH]; | |
1298 | |
1299 if (old == NULL || new == NULL) | |
1300 { | |
1301 errno = ENOENT; | |
1302 return -1; | |
1303 } | |
1304 | |
1305 strcpy (oldname, map_win32_filename (old, NULL)); | |
1306 strcpy (newname, map_win32_filename (new, NULL)); | |
1307 | |
1308 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING, | |
1309 FILE_FLAG_BACKUP_SEMANTICS, NULL); | |
1310 if (fileh != INVALID_HANDLE_VALUE) | |
1311 { | |
1312 int wlen; | |
1313 | |
1314 /* Confusingly, the "alternate" stream name field does not apply | |
1315 when restoring a hard link, and instead contains the actual | |
1316 stream data for the link (ie. the name of the link to create). | |
1317 The WIN32_STREAM_ID structure before the cStreamName field is | |
1318 the stream header, which is then immediately followed by the | |
1319 stream data. */ | |
1320 | |
1321 struct { | |
1322 WIN32_STREAM_ID wid; | |
1323 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */ | |
1324 } data; | |
1325 | |
1326 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1, | |
1327 data.wid.cStreamName, MAX_PATH); | |
1328 if (wlen > 0) | |
1329 { | |
1330 LPVOID context = NULL; | |
1331 DWORD wbytes = 0; | |
1332 | |
1333 data.wid.dwStreamId = BACKUP_LINK; | |
1334 data.wid.dwStreamAttributes = 0; | |
1335 data.wid.Size.LowPart = wlen * sizeof(WCHAR); | |
1336 data.wid.Size.HighPart = 0; | |
1337 data.wid.dwStreamNameSize = 0; | |
1338 | |
1339 if (BackupWrite (fileh, (LPBYTE)&data, | |
1340 offsetof (WIN32_STREAM_ID, cStreamName) | |
1341 + data.wid.Size.LowPart, | |
1342 &wbytes, FALSE, FALSE, &context) | |
1343 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context)) | |
1344 { | |
1345 /* succeeded */ | |
1346 result = 0; | |
1347 } | |
1348 else | |
1349 { | |
1350 /* Should try mapping GetLastError to errno; for now just | |
1351 indicate a general error (eg. links not supported). */ | |
1352 errno = EINVAL; // perhaps EMLINK? | |
1353 } | |
1354 } | |
1355 | |
1356 CloseHandle (fileh); | |
1357 } | |
1358 else | |
1359 errno = ENOENT; | |
1360 | |
1361 return result; | |
1362 } | |
1363 | |
1364 int | |
1365 sys_mkdir (const char * path, int mode_unused) | |
1366 { | |
1367 return _mkdir (map_win32_filename (path, NULL)); | |
1368 } | |
1369 | |
1370 /* Because of long name mapping issues, we need to implement this | |
1371 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate | |
1372 a unique name, instead of setting the input template to an empty | |
1373 string. | |
1374 | |
1375 Standard algorithm seems to be use pid or tid with a letter on the | |
1376 front (in place of the 6 X's) and cycle through the letters to find a | |
1377 unique name. We extend that to allow any reasonable character as the | |
1378 first of the 6 X's. */ | |
1379 char * | |
1380 sys_mktemp (char * template) | |
1381 { | |
1382 char * p; | |
1383 int i; | |
1384 unsigned uid = GetCurrentThreadId (); | |
1385 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#"; | |
1386 | |
1387 if (template == NULL) | |
1388 return NULL; | |
1389 p = template + strlen (template); | |
1390 i = 5; | |
1391 /* replace up to the last 5 X's with uid in decimal */ | |
1392 while (--p >= template && p[0] == 'X' && --i >= 0) | |
1393 { | |
1394 p[0] = '0' + uid % 10; | |
1395 uid /= 10; | |
1396 } | |
1397 | |
1398 if (i < 0 && p[0] == 'X') | |
1399 { | |
1400 i = 0; | |
1401 do | |
1402 { | |
1403 int save_errno = errno; | |
1404 p[0] = first_char[i]; | |
1405 if (sys_access (template, 0) < 0) | |
1406 { | |
1407 errno = save_errno; | |
1408 return template; | |
1409 } | |
1410 } | |
1411 while (++i < sizeof (first_char)); | |
1412 } | |
1413 | |
1414 /* Template is badly formed or else we can't generate a unique name, | |
1415 so return empty string */ | |
1416 template[0] = 0; | |
1417 return template; | |
1418 } | |
1419 | |
1420 int | |
1421 sys_open (const char * path, int oflag, int mode) | |
1422 { | |
1423 int fd; | |
1424 | |
1425 /* Force all file handles to be non-inheritable. */ | |
1426 fd = _open (map_win32_filename (path, NULL), oflag | _O_NOINHERIT, mode); | |
1427 | |
1428 if (fd >= MAXDESC) | |
1429 { | |
1430 _close (fd); | |
1431 errno = EMFILE; | |
1432 return -1; | |
1433 } | |
1434 | |
1435 if (fd >= 0) | |
1436 { | |
1437 fd_info[fd].cp = 0; | |
1438 } | |
1439 return (fd); | |
1440 } | |
1441 | |
1442 int | 1197 int |
1443 sys_rename (const char * oldname, const char * newname) | 1198 sys_rename (const char * oldname, const char * newname) |
1444 { | 1199 { |
1445 char temp[MAX_PATH]; | 1200 char temp[MAX_PATH]; |
1446 DWORD attr; | 1201 DWORD attr; |
1492 _unlink (newname); | 1247 _unlink (newname); |
1493 } | 1248 } |
1494 | 1249 |
1495 return rename (temp, newname); | 1250 return rename (temp, newname); |
1496 } | 1251 } |
1497 | 1252 #endif /* 0 */ |
1498 int | |
1499 sys_rmdir (const char * path) | |
1500 { | |
1501 return _rmdir (map_win32_filename (path, NULL)); | |
1502 } | |
1503 | |
1504 int | |
1505 sys_unlink (const char * path) | |
1506 { | |
1507 return _unlink (map_win32_filename (path, NULL)); | |
1508 } | |
1509 | 1253 |
1510 static FILETIME utc_base_ft; | 1254 static FILETIME utc_base_ft; |
1511 static long double utc_base; | 1255 static long double utc_base; |
1512 static int init = 0; | 1256 static int init = 0; |
1513 | 1257 |
1810 buf->st_mode |= permission | (permission >> 3) | (permission >> 6); | 1554 buf->st_mode |= permission | (permission >> 3) | (permission >> 6); |
1811 | 1555 |
1812 return 0; | 1556 return 0; |
1813 } | 1557 } |
1814 | 1558 |
1815 /* Shadow main io functions: we need to handle pipes and sockets more | |
1816 intelligently, and implement non-blocking mode as well. */ | |
1817 | |
1818 int | |
1819 sys_close (int fd) | |
1820 { | |
1821 int rc; | |
1822 | |
1823 if (fd < 0 || fd >= MAXDESC) | |
1824 { | |
1825 errno = EBADF; | |
1826 return -1; | |
1827 } | |
1828 | |
1829 if (fd_info[fd].cp) | |
1830 { | |
1831 child_process * cp = fd_info[fd].cp; | |
1832 | |
1833 fd_info[fd].cp = NULL; | |
1834 | |
1835 if (CHILD_ACTIVE (cp)) | |
1836 { | |
1837 /* if last descriptor to active child_process then cleanup */ | |
1838 int i; | |
1839 for (i = 0; i < MAXDESC; i++) | |
1840 { | |
1841 if (i == fd) | |
1842 continue; | |
1843 if (fd_info[i].cp == cp) | |
1844 break; | |
1845 } | |
1846 if (i == MAXDESC) | |
1847 { | |
1848 delete_child (cp); | |
1849 } | |
1850 } | |
1851 } | |
1852 | |
1853 /* Note that sockets do not need special treatment here (at least on | |
1854 NT and Win95 using the standard tcp/ip stacks) - it appears that | |
1855 closesocket is equivalent to CloseHandle, which is to be expected | |
1856 because socket handles are fully fledged kernel handles. */ | |
1857 rc = _close (fd); | |
1858 | |
1859 if (rc == 0) | |
1860 fd_info[fd].flags = 0; | |
1861 | |
1862 return rc; | |
1863 } | |
1864 | |
1865 int | |
1866 sys_dup (int fd) | |
1867 { | |
1868 int new_fd; | |
1869 | |
1870 new_fd = _dup (fd); | |
1871 if (new_fd >= 0) | |
1872 { | |
1873 /* duplicate our internal info as well */ | |
1874 fd_info[new_fd] = fd_info[fd]; | |
1875 } | |
1876 return new_fd; | |
1877 } | |
1878 | |
1879 | |
1880 int | |
1881 sys_dup2 (int src, int dst) | |
1882 { | |
1883 int rc; | |
1884 | |
1885 if (dst < 0 || dst >= MAXDESC) | |
1886 { | |
1887 errno = EBADF; | |
1888 return -1; | |
1889 } | |
1890 | |
1891 /* make sure we close the destination first if it's a pipe or socket */ | |
1892 if (src != dst && fd_info[dst].flags != 0) | |
1893 sys_close (dst); | |
1894 | |
1895 rc = _dup2 (src, dst); | |
1896 if (rc == 0) | |
1897 { | |
1898 /* duplicate our internal info as well */ | |
1899 fd_info[dst] = fd_info[src]; | |
1900 } | |
1901 return rc; | |
1902 } | |
1903 | |
1904 /* From callproc.c */ | 1559 /* From callproc.c */ |
1905 extern Lisp_Object Vbinary_process_input; | 1560 extern Lisp_Object Vbinary_process_input; |
1906 extern Lisp_Object Vbinary_process_output; | 1561 extern Lisp_Object Vbinary_process_output; |
1907 | 1562 |
1908 /* Unix pipe() has only one arg */ | 1563 /* Unix pipe() has only one arg */ |
1992 else | 1647 else |
1993 cp->status = STATUS_READ_FAILED; | 1648 cp->status = STATUS_READ_FAILED; |
1994 | 1649 |
1995 return cp->status; | 1650 return cp->status; |
1996 } | 1651 } |
1997 | |
1998 int | |
1999 sys_read (int fd, char * buffer, size_t count) | |
2000 { | |
2001 int nchars; | |
2002 int to_read; | |
2003 DWORD waiting; | |
2004 char * orig_buffer = buffer; | |
2005 | |
2006 if (fd < 0 || fd >= MAXDESC) | |
2007 { | |
2008 errno = EBADF; | |
2009 return -1; | |
2010 } | |
2011 | |
2012 if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) | |
2013 { | |
2014 child_process *cp = fd_info[fd].cp; | |
2015 | |
2016 if ((fd_info[fd].flags & FILE_READ) == 0) | |
2017 { | |
2018 errno = EBADF; | |
2019 return -1; | |
2020 } | |
2021 | |
2022 nchars = 0; | |
2023 | |
2024 /* re-read CR carried over from last read */ | |
2025 if (fd_info[fd].flags & FILE_LAST_CR) | |
2026 { | |
2027 if (fd_info[fd].flags & FILE_BINARY) abort (); | |
2028 *buffer++ = 0x0d; | |
2029 count--; | |
2030 nchars++; | |
2031 fd_info[fd].flags &= ~FILE_LAST_CR; | |
2032 } | |
2033 | |
2034 /* presence of a child_process structure means we are operating in | |
2035 non-blocking mode - otherwise we just call _read directly. | |
2036 Note that the child_process structure might be missing because | |
2037 reap_subprocess has been called; in this case the pipe is | |
2038 already broken, so calling _read on it is okay. */ | |
2039 if (cp) | |
2040 { | |
2041 int current_status = cp->status; | |
2042 | |
2043 switch (current_status) | |
2044 { | |
2045 case STATUS_READ_FAILED: | |
2046 case STATUS_READ_ERROR: | |
2047 /* report normal EOF if nothing in buffer */ | |
2048 if (nchars <= 0) | |
2049 fd_info[fd].flags |= FILE_AT_EOF; | |
2050 return nchars; | |
2051 | |
2052 case STATUS_READ_READY: | |
2053 case STATUS_READ_IN_PROGRESS: | |
2054 errno = EWOULDBLOCK; | |
2055 return -1; | |
2056 | |
2057 case STATUS_READ_SUCCEEDED: | |
2058 /* consume read-ahead char */ | |
2059 *buffer++ = cp->chr; | |
2060 count--; | |
2061 nchars++; | |
2062 cp->status = STATUS_READ_ACKNOWLEDGED; | |
2063 ResetEvent (cp->char_avail); | |
2064 | |
2065 case STATUS_READ_ACKNOWLEDGED: | |
2066 break; | |
2067 | |
2068 default: | |
2069 errno = EBADF; | |
2070 return -1; | |
2071 } | |
2072 | |
2073 if (fd_info[fd].flags & FILE_PIPE) | |
2074 { | |
2075 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL); | |
2076 to_read = min (waiting, (DWORD) count); | |
2077 | |
2078 if (to_read > 0) | |
2079 nchars += _read (fd, buffer, to_read); | |
2080 } | |
2081 } | |
2082 else | |
2083 { | |
2084 int nread = _read (fd, buffer, count); | |
2085 if (nread >= 0) | |
2086 nchars += nread; | |
2087 else if (nchars == 0) | |
2088 nchars = nread; | |
2089 } | |
2090 | |
2091 if (nchars <= 0) | |
2092 fd_info[fd].flags |= FILE_AT_EOF; | |
2093 /* Perform text mode translation if required. */ | |
2094 else if ((fd_info[fd].flags & FILE_BINARY) == 0) | |
2095 { | |
2096 unsigned lf_count = 0; | |
2097 nchars = crlf_to_lf (nchars, orig_buffer, &lf_count); | |
2098 /* If buffer contains only CR, return that. To be absolutely | |
2099 sure we should attempt to read the next char, but in | |
2100 practice a CR to be followed by LF would not appear by | |
2101 itself in the buffer. */ | |
2102 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d) | |
2103 { | |
2104 fd_info[fd].flags |= FILE_LAST_CR; | |
2105 nchars--; | |
2106 } | |
2107 } | |
2108 } | |
2109 else | |
2110 nchars = _read (fd, buffer, count); | |
2111 | |
2112 return nchars; | |
2113 } | |
2114 | |
2115 /* For now, don't bother with a non-blocking mode */ | |
2116 int | |
2117 sys_write (int fd, const void * buffer, size_t count) | |
2118 { | |
2119 int nchars; | |
2120 | |
2121 if (fd < 0 || fd >= MAXDESC) | |
2122 { | |
2123 errno = EBADF; | |
2124 return -1; | |
2125 } | |
2126 | |
2127 if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) | |
2128 { | |
2129 if ((fd_info[fd].flags & FILE_WRITE) == 0) | |
2130 { | |
2131 errno = EBADF; | |
2132 return -1; | |
2133 } | |
2134 | |
2135 /* Perform text mode translation if required. */ | |
2136 if ((fd_info[fd].flags & FILE_BINARY) == 0) | |
2137 { | |
2138 char * tmpbuf = alloca (count * 2); | |
2139 unsigned char * src = (void *)buffer; | |
2140 unsigned char * dst = tmpbuf; | |
2141 int nbytes = count; | |
2142 | |
2143 while (1) | |
2144 { | |
2145 unsigned char *next; | |
2146 /* copy next line or remaining bytes */ | |
2147 next = _memccpy (dst, src, '\n', nbytes); | |
2148 if (next) | |
2149 { | |
2150 /* copied one line ending with '\n' */ | |
2151 int copied = next - dst; | |
2152 nbytes -= copied; | |
2153 src += copied; | |
2154 /* insert '\r' before '\n' */ | |
2155 next[-1] = '\r'; | |
2156 next[0] = '\n'; | |
2157 dst = next + 1; | |
2158 count++; | |
2159 } | |
2160 else | |
2161 /* copied remaining partial line -> now finished */ | |
2162 break; | |
2163 } | |
2164 buffer = tmpbuf; | |
2165 } | |
2166 } | |
2167 | |
2168 nchars = _write (fd, buffer, count); | |
2169 | |
2170 return nchars; | |
2171 } | |
2172 | |
2173 | 1652 |
2174 void | 1653 void |
2175 term_ntproc (int unused) | 1654 term_ntproc (int unused) |
2176 { | 1655 { |
2177 } | 1656 } |