kill-matching-buffers to optionally not confirm
[emacs.git] / lib-src / ntlib.c
blob78ba9061f6b93775fe65b56a7fec4ece6a03e20b
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 <http://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_chdir (const char *);
40 int mkostemp (char *, int);
41 int sys_rename (const char *, const char *);
43 /* MinGW64 defines _TIMEZONE_DEFINED and defines 'struct timespec' in
44 its system headers. */
45 #ifndef _TIMEZONE_DEFINED
46 struct timezone
48 int tz_minuteswest; /* minutes west of Greenwich */
49 int tz_dsttime; /* type of dst correction */
51 #endif
53 #define MAXPATHLEN _MAX_PATH
55 /* Emulate sleep...we could have done this with a define, but that
56 would necessitate including windows.h in the files that used it.
57 This is much easier. */
58 unsigned
59 sleep (unsigned seconds)
61 Sleep (seconds * 1000);
62 return 0;
65 /* Get the current working directory. */
66 char *
67 getwd (char *dir)
69 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
70 return dir;
71 return NULL;
74 static HANDLE getppid_parent;
75 static int getppid_ppid;
77 int
78 getppid (void)
80 char *ppid;
81 DWORD result;
83 ppid = getenv ("EM_PARENT_PROCESS_ID");
84 if (!ppid)
86 printf ("no pid.\n");
87 return 0;
89 else
91 getppid_ppid = atoi (ppid);
94 if (!getppid_parent)
96 getppid_parent = OpenProcess (SYNCHRONIZE, FALSE, atoi (ppid));
97 if (!getppid_parent)
99 printf ("Failed to open handle to parent process: %lu\n",
100 GetLastError ());
101 exit (1);
105 result = WaitForSingleObject (getppid_parent, 0);
106 switch (result)
108 case WAIT_TIMEOUT:
109 /* The parent is still alive. */
110 return getppid_ppid;
111 case WAIT_OBJECT_0:
112 /* The parent is gone. Return the pid of Unix init (1). */
113 return 1;
114 case WAIT_FAILED:
115 default:
116 printf ("Checking parent status failed: %lu\n", GetLastError ());
117 exit (1);
121 char *
122 getlogin (void)
124 static char user_name[256];
125 DWORD length = sizeof (user_name);
127 if (GetUserName (user_name, &length))
128 return user_name;
129 return NULL;
132 char *
133 cuserid (char * s)
135 char * name = getlogin ();
136 if (s)
137 return strcpy (s, name ? name : "");
138 return name;
141 unsigned
142 getuid (void)
144 return 0;
147 unsigned
148 geteuid (void)
150 return getuid ();
153 unsigned
154 getgid (void)
156 return 0;
159 unsigned
160 getegid (void)
162 return 0;
166 setuid (unsigned uid)
168 return 0;
172 setregid (unsigned rgid, unsigned gid)
174 return 0;
177 struct passwd *
178 getpwuid (unsigned uid)
180 return NULL;
183 char *
184 getpass (const char * prompt)
186 static char input[256];
187 HANDLE in;
188 HANDLE err;
189 DWORD count;
191 in = GetStdHandle (STD_INPUT_HANDLE);
192 err = GetStdHandle (STD_ERROR_HANDLE);
194 if (in == INVALID_HANDLE_VALUE || err == INVALID_HANDLE_VALUE)
195 return NULL;
197 if (WriteFile (err, prompt, strlen (prompt), &count, NULL))
199 int istty = (GetFileType (in) == FILE_TYPE_CHAR);
200 DWORD old_flags;
201 int rc;
203 if (istty)
205 if (GetConsoleMode (in, &old_flags))
206 SetConsoleMode (in, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
207 else
208 istty = 0;
210 rc = ReadFile (in, input, sizeof (input), &count, NULL);
211 if (count >= 2 && input[count - 2] == '\r')
212 input[count - 2] = '\0';
213 else
215 char buf[256];
216 while (ReadFile (in, buf, sizeof (buf), &count, NULL) > 0)
217 if (count >= 2 && buf[count - 2] == '\r')
218 break;
220 WriteFile (err, "\r\n", 2, &count, NULL);
221 if (istty)
222 SetConsoleMode (in, old_flags);
223 if (rc)
224 return input;
227 return NULL;
231 fchown (int fd, unsigned uid, unsigned gid)
233 return 0;
236 FILE *
237 sys_fopen (const char * path, const char * mode)
239 return fopen (path, mode);
243 sys_chdir (const char * path)
245 return _chdir (path);
248 static FILETIME utc_base_ft;
249 static long double utc_base;
250 static int init = 0;
252 static time_t
253 convert_time (FILETIME ft)
255 long double ret;
257 if (CompareFileTime (&ft, &utc_base_ft) < 0)
258 return 0;
260 ret = (long double) ft.dwHighDateTime
261 * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
262 ret -= utc_base;
263 return (time_t) (ret * 1e-7L);
266 static int
267 is_exec (const char * name)
269 char * p = strrchr (name, '.');
270 return
271 (p != NULL
272 && (stricmp (p, ".exe") == 0 ||
273 stricmp (p, ".com") == 0 ||
274 stricmp (p, ".bat") == 0 ||
275 stricmp (p, ".cmd") == 0));
278 /* FIXME? This is in configure.ac now - is this still needed? */
279 #define IS_DIRECTORY_SEP(x) ((x) == '/' || (x) == '\\')
281 /* We need this because nt/inc/sys/stat.h defines struct stat that is
282 incompatible with the MS run-time libraries. */
284 stat (const char * path, struct stat * buf)
286 WIN32_FIND_DATA wfd;
287 HANDLE fh;
288 int permission;
289 int len;
290 int rootdir = FALSE;
291 char *name = alloca (FILENAME_MAX);
293 if (!init)
295 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
296 SYSTEMTIME st;
298 st.wYear = 1970;
299 st.wMonth = 1;
300 st.wDay = 1;
301 st.wHour = 0;
302 st.wMinute = 0;
303 st.wSecond = 0;
304 st.wMilliseconds = 0;
306 SystemTimeToFileTime (&st, &utc_base_ft);
307 utc_base = (long double) utc_base_ft.dwHighDateTime
308 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
309 init = 1;
312 if (path == NULL || buf == NULL || *path == '\0')
314 errno = EFAULT;
315 return -1;
317 if (_mbspbrk (path, "*?|<>\""))
319 errno = ENOENT;
320 return -1;
323 strcpy (name, path);
324 /* Remove trailing directory separator, unless name is the root
325 directory of a drive in which case ensure there is a trailing
326 separator. */
327 len = strlen (name);
328 rootdir = IS_DIRECTORY_SEP (name[0])
329 || (len == 3 && name[1] == ':' && IS_DIRECTORY_SEP (name[2]));
330 if (rootdir)
332 if (GetDriveType (name) < 2)
334 errno = ENOENT;
335 return -1;
337 memset (&wfd, 0, sizeof (wfd));
338 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
339 wfd.ftCreationTime = utc_base_ft;
340 wfd.ftLastAccessTime = utc_base_ft;
341 wfd.ftLastWriteTime = utc_base_ft;
342 strcpy (wfd.cFileName, name);
344 else
346 if (IS_DIRECTORY_SEP (name[len-1]))
347 name[len - 1] = 0;
349 fh = FindFirstFile (name, &wfd);
350 if (fh == INVALID_HANDLE_VALUE)
352 errno = ENOENT;
353 return -1;
355 FindClose (fh);
357 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
358 S_IFDIR : S_IFREG;
359 buf->st_nlink = 1;
360 buf->st_ino = 0;
362 if (name[0] && name[1] == ':')
363 buf->st_dev = tolower (name[0]) - 'a' + 1;
364 else
365 buf->st_dev = _getdrive ();
366 buf->st_rdev = buf->st_dev;
368 buf->st_size = wfd.nFileSizeLow;
370 /* Convert timestamps to Unix format. */
371 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
372 buf->st_atime = convert_time (wfd.ftLastAccessTime);
373 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
374 buf->st_ctime = convert_time (wfd.ftCreationTime);
375 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
377 /* determine rwx permissions */
378 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
379 permission = S_IREAD;
380 else
381 permission = S_IREAD | S_IWRITE;
383 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
384 permission |= S_IEXEC;
385 else if (is_exec (name))
386 permission |= S_IEXEC;
388 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
390 return 0;
394 lstat (const char * path, struct stat * buf)
396 return stat (path, buf);
399 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
400 when using mktemp. Copied from w32.c.
402 This is used only in update-game-score.c. It is overkill for that
403 use case, since update-game-score renames the temporary file into
404 the game score file, which isn't atomic on MS-Windows anyway, when
405 the game score already existed before running the program, which it
406 almost always does. But using a simpler implementation just to
407 make a point is uneconomical... */
410 mkostemp (char * template, int flags)
412 char * p;
413 int i, fd = -1;
414 unsigned uid = GetCurrentThreadId ();
415 int save_errno = errno;
416 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
418 errno = EINVAL;
419 if (template == NULL)
420 return -1;
422 p = template + strlen (template);
423 i = 5;
424 /* replace up to the last 5 X's with uid in decimal */
425 while (--p >= template && p[0] == 'X' && --i >= 0)
427 p[0] = '0' + uid % 10;
428 uid /= 10;
431 if (i < 0 && p[0] == 'X')
433 i = 0;
436 p[0] = first_char[i];
437 if ((fd = open (template,
438 flags | _O_CREAT | _O_EXCL | _O_RDWR,
439 S_IRUSR | S_IWUSR)) >= 0
440 || errno != EEXIST)
442 if (fd >= 0)
443 errno = save_errno;
444 return fd;
447 while (++i < sizeof (first_char));
450 /* Template is badly formed or else we can't generate a unique name. */
451 return -1;
454 /* On Windows, you cannot rename into an existing file. */
456 sys_rename (const char *from, const char *to)
458 int retval = rename (from, to);
460 if (retval < 0 && errno == EEXIST)
462 if (unlink (to) == 0)
463 retval = rename (from, to);
465 return retval;