Make manuals and NEWS consistent
[emacs.git] / lib-src / ntlib.c
blob3754f914e3350ede33784207d0a900f13048b1b0
1 /* Utility and Unix shadow routines for GNU Emacs support programs on NT.
3 Copyright (C) 1994, 2001-2017 Free Software Foundation, Inc.
5 Author: Geoff Voelker (voelker@cs.washington.edu)
6 Created: 10-8-94
8 This file is part of GNU Emacs.
10 GNU Emacs is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or (at
13 your option) any later version.
15 GNU Emacs is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
23 #include <windows.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <time.h>
27 #include <direct.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <errno.h>
31 #include <ctype.h>
32 #include <sys/timeb.h>
33 #include <mbstring.h>
35 #include "ntlib.h"
37 char *sys_ctime (const time_t *);
38 FILE *sys_fopen (const char *, const char *);
39 int sys_mkdir (const char *, mode_t);
40 int sys_chdir (const char *);
41 int mkostemp (char *, int);
42 int sys_rename (const char *, const char *);
43 int sys_open (const char *, int, int);
45 /* MinGW64 defines _TIMEZONE_DEFINED and defines 'struct timespec' in
46 its system headers. */
47 #ifndef _TIMEZONE_DEFINED
48 struct timezone
50 int tz_minuteswest; /* minutes west of Greenwich */
51 int tz_dsttime; /* type of dst correction */
53 #endif
55 #define MAXPATHLEN _MAX_PATH
57 /* Emulate sleep...we could have done this with a define, but that
58 would necessitate including windows.h in the files that used it.
59 This is much easier. */
60 unsigned
61 sleep (unsigned seconds)
63 Sleep (seconds * 1000);
64 return 0;
67 /* Get the current working directory. */
68 char *
69 getwd (char *dir)
71 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
72 return dir;
73 return NULL;
76 static HANDLE getppid_parent;
77 static int getppid_ppid;
79 int
80 getppid (void)
82 char *ppid;
83 DWORD result;
85 ppid = getenv ("EM_PARENT_PROCESS_ID");
86 if (!ppid)
88 printf ("no pid.\n");
89 return 0;
91 else
93 getppid_ppid = atoi (ppid);
96 if (!getppid_parent)
98 getppid_parent = OpenProcess (SYNCHRONIZE, FALSE, atoi (ppid));
99 if (!getppid_parent)
101 printf ("Failed to open handle to parent process: %lu\n",
102 GetLastError ());
103 exit (1);
107 result = WaitForSingleObject (getppid_parent, 0);
108 switch (result)
110 case WAIT_TIMEOUT:
111 /* The parent is still alive. */
112 return getppid_ppid;
113 case WAIT_OBJECT_0:
114 /* The parent is gone. Return the pid of Unix init (1). */
115 return 1;
116 case WAIT_FAILED:
117 default:
118 printf ("Checking parent status failed: %lu\n", GetLastError ());
119 exit (1);
123 char *
124 getlogin (void)
126 static char user_name[256];
127 DWORD length = sizeof (user_name);
129 if (GetUserName (user_name, &length))
130 return user_name;
131 return NULL;
134 char *
135 cuserid (char * s)
137 char * name = getlogin ();
138 if (s)
139 return strcpy (s, name ? name : "");
140 return name;
143 unsigned
144 getuid (void)
146 return 0;
149 unsigned
150 geteuid (void)
152 return getuid ();
155 unsigned
156 getgid (void)
158 return 0;
161 unsigned
162 getegid (void)
164 return 0;
168 setuid (unsigned uid)
170 return 0;
174 setregid (unsigned rgid, unsigned gid)
176 return 0;
179 struct passwd *
180 getpwuid (unsigned uid)
182 return NULL;
185 char *
186 getpass (const char * prompt)
188 static char input[256];
189 HANDLE in;
190 HANDLE err;
191 DWORD count;
193 in = GetStdHandle (STD_INPUT_HANDLE);
194 err = GetStdHandle (STD_ERROR_HANDLE);
196 if (in == INVALID_HANDLE_VALUE || err == INVALID_HANDLE_VALUE)
197 return NULL;
199 if (WriteFile (err, prompt, strlen (prompt), &count, NULL))
201 int istty = (GetFileType (in) == FILE_TYPE_CHAR);
202 DWORD old_flags;
203 int rc;
205 if (istty)
207 if (GetConsoleMode (in, &old_flags))
208 SetConsoleMode (in, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
209 else
210 istty = 0;
212 rc = ReadFile (in, input, sizeof (input), &count, NULL);
213 if (count >= 2 && input[count - 2] == '\r')
214 input[count - 2] = '\0';
215 else
217 char buf[256];
218 while (ReadFile (in, buf, sizeof (buf), &count, NULL) > 0)
219 if (count >= 2 && buf[count - 2] == '\r')
220 break;
222 WriteFile (err, "\r\n", 2, &count, NULL);
223 if (istty)
224 SetConsoleMode (in, old_flags);
225 if (rc)
226 return input;
229 return NULL;
233 fchown (int fd, unsigned uid, unsigned gid)
235 return 0;
238 FILE *
239 sys_fopen (const char * path, const char * mode)
241 return fopen (path, mode);
245 sys_chdir (const char * path)
247 return _chdir (path);
251 sys_mkdir (const char * path, mode_t mode)
253 return _mkdir (path);
256 static FILETIME utc_base_ft;
257 static long double utc_base;
258 static int init = 0;
260 static time_t
261 convert_time (FILETIME ft)
263 long double ret;
265 if (CompareFileTime (&ft, &utc_base_ft) < 0)
266 return 0;
268 ret = (long double) ft.dwHighDateTime
269 * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
270 ret -= utc_base;
271 return (time_t) (ret * 1e-7L);
274 static int
275 is_exec (const char * name)
277 char * p = strrchr (name, '.');
278 return
279 (p != NULL
280 && (stricmp (p, ".exe") == 0 ||
281 stricmp (p, ".com") == 0 ||
282 stricmp (p, ".bat") == 0 ||
283 stricmp (p, ".cmd") == 0));
286 /* FIXME? This is in configure.ac now - is this still needed? */
287 #define IS_DIRECTORY_SEP(x) ((x) == '/' || (x) == '\\')
289 /* We need this because nt/inc/sys/stat.h defines struct stat that is
290 incompatible with the MS run-time libraries. */
292 stat (const char * path, struct stat * buf)
294 WIN32_FIND_DATA wfd;
295 HANDLE fh;
296 int permission;
297 int len;
298 int rootdir = FALSE;
299 char *name = alloca (FILENAME_MAX);
301 if (!init)
303 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
304 SYSTEMTIME st;
306 st.wYear = 1970;
307 st.wMonth = 1;
308 st.wDay = 1;
309 st.wHour = 0;
310 st.wMinute = 0;
311 st.wSecond = 0;
312 st.wMilliseconds = 0;
314 SystemTimeToFileTime (&st, &utc_base_ft);
315 utc_base = (long double) utc_base_ft.dwHighDateTime
316 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
317 init = 1;
320 if (path == NULL || buf == NULL || *path == '\0')
322 errno = EFAULT;
323 return -1;
325 if (_mbspbrk (path, "*?|<>\""))
327 errno = ENOENT;
328 return -1;
331 strcpy (name, path);
332 /* Remove trailing directory separator, unless name is the root
333 directory of a drive in which case ensure there is a trailing
334 separator. */
335 len = strlen (name);
336 rootdir = IS_DIRECTORY_SEP (name[0])
337 || (len == 3 && name[1] == ':' && IS_DIRECTORY_SEP (name[2]));
338 if (rootdir)
340 if (GetDriveType (name) < 2)
342 errno = ENOENT;
343 return -1;
345 memset (&wfd, 0, sizeof (wfd));
346 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
347 wfd.ftCreationTime = utc_base_ft;
348 wfd.ftLastAccessTime = utc_base_ft;
349 wfd.ftLastWriteTime = utc_base_ft;
350 strcpy (wfd.cFileName, name);
352 else
354 if (IS_DIRECTORY_SEP (name[len-1]))
355 name[len - 1] = 0;
357 fh = FindFirstFile (name, &wfd);
358 if (fh == INVALID_HANDLE_VALUE)
360 errno = ENOENT;
361 return -1;
363 FindClose (fh);
365 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
366 S_IFDIR : S_IFREG;
367 buf->st_nlink = 1;
368 buf->st_ino = 0;
370 if (name[0] && name[1] == ':')
371 buf->st_dev = tolower (name[0]) - 'a' + 1;
372 else
373 buf->st_dev = _getdrive ();
374 buf->st_rdev = buf->st_dev;
376 buf->st_size = wfd.nFileSizeLow;
378 /* Convert timestamps to Unix format. */
379 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
380 buf->st_atime = convert_time (wfd.ftLastAccessTime);
381 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
382 buf->st_ctime = convert_time (wfd.ftCreationTime);
383 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
385 /* determine rwx permissions */
386 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
387 permission = S_IREAD;
388 else
389 permission = S_IREAD | S_IWRITE;
391 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
392 permission |= S_IEXEC;
393 else if (is_exec (name))
394 permission |= S_IEXEC;
396 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
398 return 0;
402 lstat (const char * path, struct stat * buf)
404 return stat (path, buf);
407 /* On Windows, you cannot rename into an existing file. */
409 sys_rename (const char *from, const char *to)
411 int retval = rename (from, to);
413 if (retval < 0 && errno == EEXIST)
415 if (unlink (to) == 0)
416 retval = rename (from, to);
418 return retval;
422 sys_open (const char * path, int oflag, int mode)
424 return _open (path, oflag, mode);