Fix a couple of AM_V_GEN bugs
[emacs.git] / lib-src / ntlib.c
blob7d9dff9904caeeaaccb5bd4be462b9220d625a1d
1 /* Utility and Unix shadow routines for GNU Emacs support programs on NT.
3 Copyright (C) 1994, 2001-2015 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
13 (at 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 /* MinGW64 defines _TIMEZONE_DEFINED and defines 'struct timespec' in
38 its system headers. */
39 #ifndef _TIMEZONE_DEFINED
40 struct timezone
42 int tz_minuteswest; /* minutes west of Greenwich */
43 int tz_dsttime; /* type of dst correction */
45 #endif
47 #define MAXPATHLEN _MAX_PATH
49 /* Emulate sleep...we could have done this with a define, but that
50 would necessitate including windows.h in the files that used it.
51 This is much easier. */
52 unsigned
53 sleep (unsigned seconds)
55 Sleep (seconds * 1000);
56 return 0;
59 /* Get the current working directory. */
60 char *
61 getwd (char *dir)
63 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
64 return dir;
65 return NULL;
68 static HANDLE getppid_parent;
69 static int getppid_ppid;
71 int
72 getppid (void)
74 char *ppid;
75 DWORD result;
77 ppid = getenv ("EM_PARENT_PROCESS_ID");
78 if (!ppid)
80 printf ("no pid.\n");
81 return 0;
83 else
85 getppid_ppid = atoi (ppid);
88 if (!getppid_parent)
90 getppid_parent = OpenProcess (SYNCHRONIZE, FALSE, atoi (ppid));
91 if (!getppid_parent)
93 printf ("Failed to open handle to parent process: %d\n",
94 GetLastError ());
95 exit (1);
99 result = WaitForSingleObject (getppid_parent, 0);
100 switch (result)
102 case WAIT_TIMEOUT:
103 /* The parent is still alive. */
104 return getppid_ppid;
105 case WAIT_OBJECT_0:
106 /* The parent is gone. Return the pid of Unix init (1). */
107 return 1;
108 case WAIT_FAILED:
109 default:
110 printf ("Checking parent status failed: %d\n", GetLastError ());
111 exit (1);
115 char *
116 getlogin (void)
118 static char user_name[256];
119 DWORD length = sizeof (user_name);
121 if (GetUserName (user_name, &length))
122 return user_name;
123 return NULL;
126 char *
127 cuserid (char * s)
129 char * name = getlogin ();
130 if (s)
131 return strcpy (s, name ? name : "");
132 return name;
135 unsigned
136 getuid (void)
138 return 0;
141 unsigned
142 geteuid (void)
144 return getuid ();
147 unsigned
148 getgid (void)
150 return 0;
153 unsigned
154 getegid (void)
156 return 0;
160 setuid (unsigned uid)
162 return 0;
166 setregid (unsigned rgid, unsigned gid)
168 return 0;
171 struct passwd *
172 getpwuid (unsigned uid)
174 return NULL;
177 char *
178 getpass (const char * prompt)
180 static char input[256];
181 HANDLE in;
182 HANDLE err;
183 DWORD count;
185 in = GetStdHandle (STD_INPUT_HANDLE);
186 err = GetStdHandle (STD_ERROR_HANDLE);
188 if (in == INVALID_HANDLE_VALUE || err == INVALID_HANDLE_VALUE)
189 return NULL;
191 if (WriteFile (err, prompt, strlen (prompt), &count, NULL))
193 int istty = (GetFileType (in) == FILE_TYPE_CHAR);
194 DWORD old_flags;
195 int rc;
197 if (istty)
199 if (GetConsoleMode (in, &old_flags))
200 SetConsoleMode (in, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
201 else
202 istty = 0;
204 rc = ReadFile (in, input, sizeof (input), &count, NULL);
205 if (count >= 2 && input[count - 2] == '\r')
206 input[count - 2] = '\0';
207 else
209 char buf[256];
210 while (ReadFile (in, buf, sizeof (buf), &count, NULL) > 0)
211 if (count >= 2 && buf[count - 2] == '\r')
212 break;
214 WriteFile (err, "\r\n", 2, &count, NULL);
215 if (istty)
216 SetConsoleMode (in, old_flags);
217 if (rc)
218 return input;
221 return NULL;
224 /* This is needed because lib/gettime.c calls gettimeofday, which MSVC
225 doesn't have. Copied from w32.c. */
226 void
227 gettimeofday (struct timeval *tv, struct timezone *tz)
229 struct _timeb tb;
230 _ftime (&tb);
232 tv->tv_sec = tb.time;
233 tv->tv_usec = tb.millitm * 1000L;
234 /* Implementation note: _ftime sometimes doesn't update the dstflag
235 according to the new timezone when the system timezone is
236 changed. We could fix that by using GetSystemTime and
237 GetTimeZoneInformation, but that doesn't seem necessary, since
238 Emacs always calls gettimeofday with the 2nd argument NULL (see
239 current_emacs_time). */
240 if (tz)
242 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
243 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
248 fchown (int fd, unsigned uid, unsigned gid)
250 return 0;
253 /* Place a wrapper around the MSVC version of ctime. It returns NULL
254 on network directories, so we handle that case here.
255 (Ulrich Leodolter, 1/11/95). */
256 char *
257 sys_ctime (const time_t *t)
259 char *str = (char *) ctime (t);
260 return (str ? str : "Sun Jan 01 00:00:00 1970");
263 FILE *
264 sys_fopen (const char * path, const char * mode)
266 return fopen (path, mode);
270 sys_chdir (const char * path)
272 return _chdir (path);
275 static FILETIME utc_base_ft;
276 static long double utc_base;
277 static int init = 0;
279 static time_t
280 convert_time (FILETIME ft)
282 long double ret;
284 if (CompareFileTime (&ft, &utc_base_ft) < 0)
285 return 0;
287 ret = (long double) ft.dwHighDateTime
288 * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
289 ret -= utc_base;
290 return (time_t) (ret * 1e-7L);
293 static int
294 is_exec (const char * name)
296 char * p = strrchr (name, '.');
297 return
298 (p != NULL
299 && (stricmp (p, ".exe") == 0 ||
300 stricmp (p, ".com") == 0 ||
301 stricmp (p, ".bat") == 0 ||
302 stricmp (p, ".cmd") == 0));
305 /* FIXME? This is in config.nt now - is this still needed? */
306 #define IS_DIRECTORY_SEP(x) ((x) == '/' || (x) == '\\')
308 /* We need this because nt/inc/sys/stat.h defines struct stat that is
309 incompatible with the MS run-time libraries. */
311 stat (const char * path, struct stat * buf)
313 WIN32_FIND_DATA wfd;
314 HANDLE fh;
315 int permission;
316 int len;
317 int rootdir = FALSE;
318 char *name = alloca (FILENAME_MAX);
320 if (!init)
322 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
323 SYSTEMTIME st;
325 st.wYear = 1970;
326 st.wMonth = 1;
327 st.wDay = 1;
328 st.wHour = 0;
329 st.wMinute = 0;
330 st.wSecond = 0;
331 st.wMilliseconds = 0;
333 SystemTimeToFileTime (&st, &utc_base_ft);
334 utc_base = (long double) utc_base_ft.dwHighDateTime
335 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
336 init = 1;
339 if (path == NULL || buf == NULL || *path == '\0')
341 errno = EFAULT;
342 return -1;
344 if (_mbspbrk (path, "*?|<>\""))
346 errno = ENOENT;
347 return -1;
350 strcpy (name, path);
351 /* Remove trailing directory separator, unless name is the root
352 directory of a drive in which case ensure there is a trailing
353 separator. */
354 len = strlen (name);
355 rootdir = IS_DIRECTORY_SEP (name[0])
356 || (len == 3 && name[1] == ':' && IS_DIRECTORY_SEP (name[2]));
357 if (rootdir)
359 if (GetDriveType (name) < 2)
361 errno = ENOENT;
362 return -1;
364 memset (&wfd, 0, sizeof (wfd));
365 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
366 wfd.ftCreationTime = utc_base_ft;
367 wfd.ftLastAccessTime = utc_base_ft;
368 wfd.ftLastWriteTime = utc_base_ft;
369 strcpy (wfd.cFileName, name);
371 else
373 if (IS_DIRECTORY_SEP (name[len-1]))
374 name[len - 1] = 0;
376 fh = FindFirstFile (name, &wfd);
377 if (fh == INVALID_HANDLE_VALUE)
379 errno = ENOENT;
380 return -1;
382 FindClose (fh);
384 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
385 S_IFDIR : S_IFREG;
386 buf->st_nlink = 1;
387 buf->st_ino = 0;
389 if (name[0] && name[1] == ':')
390 buf->st_dev = tolower (name[0]) - 'a' + 1;
391 else
392 buf->st_dev = _getdrive ();
393 buf->st_rdev = buf->st_dev;
395 buf->st_size = wfd.nFileSizeLow;
397 /* Convert timestamps to Unix format. */
398 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
399 buf->st_atime = convert_time (wfd.ftLastAccessTime);
400 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
401 buf->st_ctime = convert_time (wfd.ftCreationTime);
402 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
404 /* determine rwx permissions */
405 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
406 permission = S_IREAD;
407 else
408 permission = S_IREAD | S_IWRITE;
410 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
411 permission |= S_IEXEC;
412 else if (is_exec (name))
413 permission |= S_IEXEC;
415 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
417 return 0;
421 lstat (const char * path, struct stat * buf)
423 return stat (path, buf);
426 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
427 when using mktemp. Copied from w32.c.
429 This is used only in update-game-score.c. It is overkill for that
430 use case, since update-game-score renames the temporary file into
431 the game score file, which isn't atomic on MS-Windows anyway, when
432 the game score already existed before running the program, which it
433 almost always does. But using a simpler implementation just to
434 make a point is uneconomical... */
437 mkostemp (char * template, int flags)
439 char * p;
440 int i, fd = -1;
441 unsigned uid = GetCurrentThreadId ();
442 int save_errno = errno;
443 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
445 errno = EINVAL;
446 if (template == NULL)
447 return -1;
449 p = template + strlen (template);
450 i = 5;
451 /* replace up to the last 5 X's with uid in decimal */
452 while (--p >= template && p[0] == 'X' && --i >= 0)
454 p[0] = '0' + uid % 10;
455 uid /= 10;
458 if (i < 0 && p[0] == 'X')
460 i = 0;
463 p[0] = first_char[i];
464 if ((fd = open (template,
465 flags | _O_CREAT | _O_EXCL | _O_RDWR,
466 S_IRUSR | S_IWUSR)) >= 0
467 || errno != EEXIST)
469 if (fd >= 0)
470 errno = save_errno;
471 return fd;
474 while (++i < sizeof (first_char));
477 /* Template is badly formed or else we can't generate a unique name. */
478 return -1;
481 /* On Windows, you cannot rename into an existing file. */
483 sys_rename (const char *from, const char *to)
485 int retval = rename (from, to);
487 if (retval < 0 && errno == EEXIST)
489 if (unlink (to) == 0)
490 retval = rename (from, to);
492 return retval;