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)
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/>. */
28 #include <sys/types.h>
32 #include <sys/timeb.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
48 int tz_minuteswest
; /* minutes west of Greenwich */
49 int tz_dsttime
; /* type of dst correction */
53 void gettimeofday (struct timeval
*, struct timezone
*);
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. */
61 sleep (unsigned seconds
)
63 Sleep (seconds
* 1000);
67 /* Get the current working directory. */
71 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
76 static HANDLE getppid_parent
;
77 static int getppid_ppid
;
85 ppid
= getenv ("EM_PARENT_PROCESS_ID");
93 getppid_ppid
= atoi (ppid
);
98 getppid_parent
= OpenProcess (SYNCHRONIZE
, FALSE
, atoi (ppid
));
101 printf ("Failed to open handle to parent process: %lu\n",
107 result
= WaitForSingleObject (getppid_parent
, 0);
111 /* The parent is still alive. */
114 /* The parent is gone. Return the pid of Unix init (1). */
118 printf ("Checking parent status failed: %lu\n", GetLastError ());
126 static char user_name
[256];
127 DWORD length
= sizeof (user_name
);
129 if (GetUserName (user_name
, &length
))
137 char * name
= getlogin ();
139 return strcpy (s
, name
? name
: "");
168 setuid (unsigned uid
)
174 setregid (unsigned rgid
, unsigned gid
)
180 getpwuid (unsigned uid
)
186 getpass (const char * prompt
)
188 static char input
[256];
193 in
= GetStdHandle (STD_INPUT_HANDLE
);
194 err
= GetStdHandle (STD_ERROR_HANDLE
);
196 if (in
== INVALID_HANDLE_VALUE
|| err
== INVALID_HANDLE_VALUE
)
199 if (WriteFile (err
, prompt
, strlen (prompt
), &count
, NULL
))
201 int istty
= (GetFileType (in
) == FILE_TYPE_CHAR
);
207 if (GetConsoleMode (in
, &old_flags
))
208 SetConsoleMode (in
, ENABLE_LINE_INPUT
| ENABLE_PROCESSED_INPUT
);
212 rc
= ReadFile (in
, input
, sizeof (input
), &count
, NULL
);
213 if (count
>= 2 && input
[count
- 2] == '\r')
214 input
[count
- 2] = '\0';
218 while (ReadFile (in
, buf
, sizeof (buf
), &count
, NULL
) > 0)
219 if (count
>= 2 && buf
[count
- 2] == '\r')
222 WriteFile (err
, "\r\n", 2, &count
, NULL
);
224 SetConsoleMode (in
, old_flags
);
232 /* This is needed because lib/gettime.c calls gettimeofday, which MSVC
233 doesn't have. Copied from w32.c. */
235 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
240 tv
->tv_sec
= tb
.time
;
241 tv
->tv_usec
= tb
.millitm
* 1000L;
242 /* Implementation note: _ftime sometimes doesn't update the dstflag
243 according to the new timezone when the system timezone is
244 changed. We could fix that by using GetSystemTime and
245 GetTimeZoneInformation, but that doesn't seem necessary, since
246 Emacs always calls gettimeofday with the 2nd argument NULL (see
247 current_emacs_time). */
250 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
251 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
256 fchown (int fd
, unsigned uid
, unsigned gid
)
262 sys_fopen (const char * path
, const char * mode
)
264 return fopen (path
, mode
);
268 sys_chdir (const char * path
)
270 return _chdir (path
);
273 static FILETIME utc_base_ft
;
274 static long double utc_base
;
278 convert_time (FILETIME ft
)
282 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
285 ret
= (long double) ft
.dwHighDateTime
286 * 4096.0L * 1024.0L * 1024.0L + ft
.dwLowDateTime
;
288 return (time_t) (ret
* 1e-7L);
292 is_exec (const char * name
)
294 char * p
= strrchr (name
, '.');
297 && (stricmp (p
, ".exe") == 0 ||
298 stricmp (p
, ".com") == 0 ||
299 stricmp (p
, ".bat") == 0 ||
300 stricmp (p
, ".cmd") == 0));
303 /* FIXME? This is in configure.ac now - is this still needed? */
304 #define IS_DIRECTORY_SEP(x) ((x) == '/' || (x) == '\\')
306 /* We need this because nt/inc/sys/stat.h defines struct stat that is
307 incompatible with the MS run-time libraries. */
309 stat (const char * path
, struct stat
* buf
)
316 char *name
= alloca (FILENAME_MAX
);
320 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
329 st
.wMilliseconds
= 0;
331 SystemTimeToFileTime (&st
, &utc_base_ft
);
332 utc_base
= (long double) utc_base_ft
.dwHighDateTime
333 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft
.dwLowDateTime
;
337 if (path
== NULL
|| buf
== NULL
|| *path
== '\0')
342 if (_mbspbrk (path
, "*?|<>\""))
349 /* Remove trailing directory separator, unless name is the root
350 directory of a drive in which case ensure there is a trailing
353 rootdir
= IS_DIRECTORY_SEP (name
[0])
354 || (len
== 3 && name
[1] == ':' && IS_DIRECTORY_SEP (name
[2]));
357 if (GetDriveType (name
) < 2)
362 memset (&wfd
, 0, sizeof (wfd
));
363 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
364 wfd
.ftCreationTime
= utc_base_ft
;
365 wfd
.ftLastAccessTime
= utc_base_ft
;
366 wfd
.ftLastWriteTime
= utc_base_ft
;
367 strcpy (wfd
.cFileName
, name
);
371 if (IS_DIRECTORY_SEP (name
[len
-1]))
374 fh
= FindFirstFile (name
, &wfd
);
375 if (fh
== INVALID_HANDLE_VALUE
)
382 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
387 if (name
[0] && name
[1] == ':')
388 buf
->st_dev
= tolower (name
[0]) - 'a' + 1;
390 buf
->st_dev
= _getdrive ();
391 buf
->st_rdev
= buf
->st_dev
;
393 buf
->st_size
= wfd
.nFileSizeLow
;
395 /* Convert timestamps to Unix format. */
396 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
397 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
398 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
399 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
400 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
402 /* determine rwx permissions */
403 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
404 permission
= S_IREAD
;
406 permission
= S_IREAD
| S_IWRITE
;
408 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
409 permission
|= S_IEXEC
;
410 else if (is_exec (name
))
411 permission
|= S_IEXEC
;
413 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
419 lstat (const char * path
, struct stat
* buf
)
421 return stat (path
, buf
);
424 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
425 when using mktemp. Copied from w32.c.
427 This is used only in update-game-score.c. It is overkill for that
428 use case, since update-game-score renames the temporary file into
429 the game score file, which isn't atomic on MS-Windows anyway, when
430 the game score already existed before running the program, which it
431 almost always does. But using a simpler implementation just to
432 make a point is uneconomical... */
435 mkostemp (char * template, int flags
)
439 unsigned uid
= GetCurrentThreadId ();
440 int save_errno
= errno
;
441 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
444 if (template == NULL
)
447 p
= template + strlen (template);
449 /* replace up to the last 5 X's with uid in decimal */
450 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
452 p
[0] = '0' + uid
% 10;
456 if (i
< 0 && p
[0] == 'X')
461 p
[0] = first_char
[i
];
462 if ((fd
= open (template,
463 flags
| _O_CREAT
| _O_EXCL
| _O_RDWR
,
464 S_IRUSR
| S_IWUSR
)) >= 0
472 while (++i
< sizeof (first_char
));
475 /* Template is badly formed or else we can't generate a unique name. */
479 /* On Windows, you cannot rename into an existing file. */
481 sys_rename (const char *from
, const char *to
)
483 int retval
= rename (from
, to
);
485 if (retval
< 0 && errno
== EEXIST
)
487 if (unlink (to
) == 0)
488 retval
= rename (from
, to
);