ntlib.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. /* Utility and Unix shadow routines for GNU Emacs support programs on NT.
  2. Copyright (C) 1994, 2001-2017 Free Software Foundation, Inc.
  3. Author: Geoff Voelker (voelker@cs.washington.edu)
  4. Created: 10-8-94
  5. This file is part of GNU Emacs.
  6. GNU Emacs is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or (at
  9. your option) any later version.
  10. GNU Emacs is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
  16. #include <windows.h>
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <time.h>
  20. #include <direct.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <errno.h>
  24. #include <ctype.h>
  25. #include <sys/timeb.h>
  26. #include <mbstring.h>
  27. #include "ntlib.h"
  28. char *sys_ctime (const time_t *);
  29. FILE *sys_fopen (const char *, const char *);
  30. int sys_mkdir (const char *, mode_t);
  31. int sys_chdir (const char *);
  32. int mkostemp (char *, int);
  33. int sys_rename (const char *, const char *);
  34. int sys_open (const char *, int, int);
  35. /* MinGW64 defines _TIMEZONE_DEFINED and defines 'struct timespec' in
  36. its system headers. */
  37. #ifndef _TIMEZONE_DEFINED
  38. struct timezone
  39. {
  40. int tz_minuteswest; /* minutes west of Greenwich */
  41. int tz_dsttime; /* type of dst correction */
  42. };
  43. #endif
  44. #define MAXPATHLEN _MAX_PATH
  45. /* Emulate sleep...we could have done this with a define, but that
  46. would necessitate including windows.h in the files that used it.
  47. This is much easier. */
  48. unsigned
  49. sleep (unsigned seconds)
  50. {
  51. Sleep (seconds * 1000);
  52. return 0;
  53. }
  54. /* Get the current working directory. */
  55. char *
  56. getwd (char *dir)
  57. {
  58. if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
  59. return dir;
  60. return NULL;
  61. }
  62. static HANDLE getppid_parent;
  63. static int getppid_ppid;
  64. int
  65. getppid (void)
  66. {
  67. char *ppid;
  68. DWORD result;
  69. ppid = getenv ("EM_PARENT_PROCESS_ID");
  70. if (!ppid)
  71. {
  72. printf ("no pid.\n");
  73. return 0;
  74. }
  75. else
  76. {
  77. getppid_ppid = atoi (ppid);
  78. }
  79. if (!getppid_parent)
  80. {
  81. getppid_parent = OpenProcess (SYNCHRONIZE, FALSE, atoi (ppid));
  82. if (!getppid_parent)
  83. {
  84. printf ("Failed to open handle to parent process: %lu\n",
  85. GetLastError ());
  86. exit (1);
  87. }
  88. }
  89. result = WaitForSingleObject (getppid_parent, 0);
  90. switch (result)
  91. {
  92. case WAIT_TIMEOUT:
  93. /* The parent is still alive. */
  94. return getppid_ppid;
  95. case WAIT_OBJECT_0:
  96. /* The parent is gone. Return the pid of Unix init (1). */
  97. return 1;
  98. case WAIT_FAILED:
  99. default:
  100. printf ("Checking parent status failed: %lu\n", GetLastError ());
  101. exit (1);
  102. }
  103. }
  104. char *
  105. getlogin (void)
  106. {
  107. static char user_name[256];
  108. DWORD length = sizeof (user_name);
  109. if (GetUserName (user_name, &length))
  110. return user_name;
  111. return NULL;
  112. }
  113. char *
  114. cuserid (char * s)
  115. {
  116. char * name = getlogin ();
  117. if (s)
  118. return strcpy (s, name ? name : "");
  119. return name;
  120. }
  121. unsigned
  122. getuid (void)
  123. {
  124. return 0;
  125. }
  126. unsigned
  127. geteuid (void)
  128. {
  129. return getuid ();
  130. }
  131. unsigned
  132. getgid (void)
  133. {
  134. return 0;
  135. }
  136. unsigned
  137. getegid (void)
  138. {
  139. return 0;
  140. }
  141. int
  142. setuid (unsigned uid)
  143. {
  144. return 0;
  145. }
  146. int
  147. setregid (unsigned rgid, unsigned gid)
  148. {
  149. return 0;
  150. }
  151. struct passwd *
  152. getpwuid (unsigned uid)
  153. {
  154. return NULL;
  155. }
  156. char *
  157. getpass (const char * prompt)
  158. {
  159. static char input[256];
  160. HANDLE in;
  161. HANDLE err;
  162. DWORD count;
  163. in = GetStdHandle (STD_INPUT_HANDLE);
  164. err = GetStdHandle (STD_ERROR_HANDLE);
  165. if (in == INVALID_HANDLE_VALUE || err == INVALID_HANDLE_VALUE)
  166. return NULL;
  167. if (WriteFile (err, prompt, strlen (prompt), &count, NULL))
  168. {
  169. int istty = (GetFileType (in) == FILE_TYPE_CHAR);
  170. DWORD old_flags;
  171. int rc;
  172. if (istty)
  173. {
  174. if (GetConsoleMode (in, &old_flags))
  175. SetConsoleMode (in, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
  176. else
  177. istty = 0;
  178. }
  179. rc = ReadFile (in, input, sizeof (input), &count, NULL);
  180. if (count >= 2 && input[count - 2] == '\r')
  181. input[count - 2] = '\0';
  182. else
  183. {
  184. char buf[256];
  185. while (ReadFile (in, buf, sizeof (buf), &count, NULL) > 0)
  186. if (count >= 2 && buf[count - 2] == '\r')
  187. break;
  188. }
  189. WriteFile (err, "\r\n", 2, &count, NULL);
  190. if (istty)
  191. SetConsoleMode (in, old_flags);
  192. if (rc)
  193. return input;
  194. }
  195. return NULL;
  196. }
  197. int
  198. fchown (int fd, unsigned uid, unsigned gid)
  199. {
  200. return 0;
  201. }
  202. FILE *
  203. sys_fopen (const char * path, const char * mode)
  204. {
  205. return fopen (path, mode);
  206. }
  207. int
  208. sys_chdir (const char * path)
  209. {
  210. return _chdir (path);
  211. }
  212. int
  213. sys_mkdir (const char * path, mode_t mode)
  214. {
  215. return _mkdir (path);
  216. }
  217. static FILETIME utc_base_ft;
  218. static long double utc_base;
  219. static int init = 0;
  220. static time_t
  221. convert_time (FILETIME ft)
  222. {
  223. long double ret;
  224. if (CompareFileTime (&ft, &utc_base_ft) < 0)
  225. return 0;
  226. ret = (long double) ft.dwHighDateTime
  227. * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
  228. ret -= utc_base;
  229. return (time_t) (ret * 1e-7L);
  230. }
  231. static int
  232. is_exec (const char * name)
  233. {
  234. char * p = strrchr (name, '.');
  235. return
  236. (p != NULL
  237. && (stricmp (p, ".exe") == 0 ||
  238. stricmp (p, ".com") == 0 ||
  239. stricmp (p, ".bat") == 0 ||
  240. stricmp (p, ".cmd") == 0));
  241. }
  242. /* FIXME? This is in configure.ac now - is this still needed? */
  243. #define IS_DIRECTORY_SEP(x) ((x) == '/' || (x) == '\\')
  244. /* We need this because nt/inc/sys/stat.h defines struct stat that is
  245. incompatible with the MS run-time libraries. */
  246. int
  247. stat (const char * path, struct stat * buf)
  248. {
  249. WIN32_FIND_DATA wfd;
  250. HANDLE fh;
  251. int permission;
  252. int len;
  253. int rootdir = FALSE;
  254. char *name = alloca (FILENAME_MAX);
  255. if (!init)
  256. {
  257. /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
  258. SYSTEMTIME st;
  259. st.wYear = 1970;
  260. st.wMonth = 1;
  261. st.wDay = 1;
  262. st.wHour = 0;
  263. st.wMinute = 0;
  264. st.wSecond = 0;
  265. st.wMilliseconds = 0;
  266. SystemTimeToFileTime (&st, &utc_base_ft);
  267. utc_base = (long double) utc_base_ft.dwHighDateTime
  268. * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
  269. init = 1;
  270. }
  271. if (path == NULL || buf == NULL || *path == '\0')
  272. {
  273. errno = EFAULT;
  274. return -1;
  275. }
  276. if (_mbspbrk (path, "*?|<>\""))
  277. {
  278. errno = ENOENT;
  279. return -1;
  280. }
  281. strcpy (name, path);
  282. /* Remove trailing directory separator, unless name is the root
  283. directory of a drive in which case ensure there is a trailing
  284. separator. */
  285. len = strlen (name);
  286. rootdir = IS_DIRECTORY_SEP (name[0])
  287. || (len == 3 && name[1] == ':' && IS_DIRECTORY_SEP (name[2]));
  288. if (rootdir)
  289. {
  290. if (GetDriveType (name) < 2)
  291. {
  292. errno = ENOENT;
  293. return -1;
  294. }
  295. memset (&wfd, 0, sizeof (wfd));
  296. wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
  297. wfd.ftCreationTime = utc_base_ft;
  298. wfd.ftLastAccessTime = utc_base_ft;
  299. wfd.ftLastWriteTime = utc_base_ft;
  300. strcpy (wfd.cFileName, name);
  301. }
  302. else
  303. {
  304. if (IS_DIRECTORY_SEP (name[len-1]))
  305. name[len - 1] = 0;
  306. fh = FindFirstFile (name, &wfd);
  307. if (fh == INVALID_HANDLE_VALUE)
  308. {
  309. errno = ENOENT;
  310. return -1;
  311. }
  312. FindClose (fh);
  313. }
  314. buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
  315. S_IFDIR : S_IFREG;
  316. buf->st_nlink = 1;
  317. buf->st_ino = 0;
  318. if (name[0] && name[1] == ':')
  319. buf->st_dev = tolower (name[0]) - 'a' + 1;
  320. else
  321. buf->st_dev = _getdrive ();
  322. buf->st_rdev = buf->st_dev;
  323. buf->st_size = wfd.nFileSizeLow;
  324. /* Convert timestamps to Unix format. */
  325. buf->st_mtime = convert_time (wfd.ftLastWriteTime);
  326. buf->st_atime = convert_time (wfd.ftLastAccessTime);
  327. if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
  328. buf->st_ctime = convert_time (wfd.ftCreationTime);
  329. if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
  330. /* determine rwx permissions */
  331. if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
  332. permission = S_IREAD;
  333. else
  334. permission = S_IREAD | S_IWRITE;
  335. if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  336. permission |= S_IEXEC;
  337. else if (is_exec (name))
  338. permission |= S_IEXEC;
  339. buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
  340. return 0;
  341. }
  342. int
  343. lstat (const char * path, struct stat * buf)
  344. {
  345. return stat (path, buf);
  346. }
  347. /* On Windows, you cannot rename into an existing file. */
  348. int
  349. sys_rename (const char *from, const char *to)
  350. {
  351. int retval = rename (from, to);
  352. if (retval < 0 && errno == EEXIST)
  353. {
  354. if (unlink (to) == 0)
  355. retval = rename (from, to);
  356. }
  357. return retval;
  358. }
  359. int
  360. sys_open (const char * path, int oflag, int mode)
  361. {
  362. return _open (path, oflag, mode);
  363. }