1 /* Utility and Unix shadow routines for GNU Emacs support programs on NT.
3 Copyright (C) 1994, 2001-2016 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: %d\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: %d\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
)
261 /* Place a wrapper around the MSVC version of ctime. It returns NULL
262 on network directories, so we handle that case here.
263 (Ulrich Leodolter, 1/11/95). */
265 sys_ctime (const time_t *t
)
267 char *str
= (char *) ctime (t
);
268 return (str
? str
: "Sun Jan 01 00:00:00 1970");
272 sys_fopen (const char * path
, const char * mode
)
274 return fopen (path
, mode
);
278 sys_chdir (const char * path
)
280 return _chdir (path
);
283 static FILETIME utc_base_ft
;
284 static long double utc_base
;
288 convert_time (FILETIME ft
)
292 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
295 ret
= (long double) ft
.dwHighDateTime
296 * 4096.0L * 1024.0L * 1024.0L + ft
.dwLowDateTime
;
298 return (time_t) (ret
* 1e-7L);
302 is_exec (const char * name
)
304 char * p
= strrchr (name
, '.');
307 && (stricmp (p
, ".exe") == 0 ||
308 stricmp (p
, ".com") == 0 ||
309 stricmp (p
, ".bat") == 0 ||
310 stricmp (p
, ".cmd") == 0));
313 /* FIXME? This is in configure.ac now - is this still needed? */
314 #define IS_DIRECTORY_SEP(x) ((x) == '/' || (x) == '\\')
316 /* We need this because nt/inc/sys/stat.h defines struct stat that is
317 incompatible with the MS run-time libraries. */
319 stat (const char * path
, struct stat
* buf
)
326 char *name
= alloca (FILENAME_MAX
);
330 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
339 st
.wMilliseconds
= 0;
341 SystemTimeToFileTime (&st
, &utc_base_ft
);
342 utc_base
= (long double) utc_base_ft
.dwHighDateTime
343 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft
.dwLowDateTime
;
347 if (path
== NULL
|| buf
== NULL
|| *path
== '\0')
352 if (_mbspbrk (path
, "*?|<>\""))
359 /* Remove trailing directory separator, unless name is the root
360 directory of a drive in which case ensure there is a trailing
363 rootdir
= IS_DIRECTORY_SEP (name
[0])
364 || (len
== 3 && name
[1] == ':' && IS_DIRECTORY_SEP (name
[2]));
367 if (GetDriveType (name
) < 2)
372 memset (&wfd
, 0, sizeof (wfd
));
373 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
374 wfd
.ftCreationTime
= utc_base_ft
;
375 wfd
.ftLastAccessTime
= utc_base_ft
;
376 wfd
.ftLastWriteTime
= utc_base_ft
;
377 strcpy (wfd
.cFileName
, name
);
381 if (IS_DIRECTORY_SEP (name
[len
-1]))
384 fh
= FindFirstFile (name
, &wfd
);
385 if (fh
== INVALID_HANDLE_VALUE
)
392 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
397 if (name
[0] && name
[1] == ':')
398 buf
->st_dev
= tolower (name
[0]) - 'a' + 1;
400 buf
->st_dev
= _getdrive ();
401 buf
->st_rdev
= buf
->st_dev
;
403 buf
->st_size
= wfd
.nFileSizeLow
;
405 /* Convert timestamps to Unix format. */
406 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
407 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
408 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
409 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
410 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
412 /* determine rwx permissions */
413 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
414 permission
= S_IREAD
;
416 permission
= S_IREAD
| S_IWRITE
;
418 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
419 permission
|= S_IEXEC
;
420 else if (is_exec (name
))
421 permission
|= S_IEXEC
;
423 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
429 lstat (const char * path
, struct stat
* buf
)
431 return stat (path
, buf
);
434 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
435 when using mktemp. Copied from w32.c.
437 This is used only in update-game-score.c. It is overkill for that
438 use case, since update-game-score renames the temporary file into
439 the game score file, which isn't atomic on MS-Windows anyway, when
440 the game score already existed before running the program, which it
441 almost always does. But using a simpler implementation just to
442 make a point is uneconomical... */
445 mkostemp (char * template, int flags
)
449 unsigned uid
= GetCurrentThreadId ();
450 int save_errno
= errno
;
451 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
454 if (template == NULL
)
457 p
= template + strlen (template);
459 /* replace up to the last 5 X's with uid in decimal */
460 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
462 p
[0] = '0' + uid
% 10;
466 if (i
< 0 && p
[0] == 'X')
471 p
[0] = first_char
[i
];
472 if ((fd
= open (template,
473 flags
| _O_CREAT
| _O_EXCL
| _O_RDWR
,
474 S_IRUSR
| S_IWUSR
)) >= 0
482 while (++i
< sizeof (first_char
));
485 /* Template is badly formed or else we can't generate a unique name. */
489 /* On Windows, you cannot rename into an existing file. */
491 sys_rename (const char *from
, const char *to
)
493 int retval
= rename (from
, to
);
495 if (retval
< 0 && errno
== EEXIST
)
497 if (unlink (to
) == 0)
498 retval
= rename (from
, to
);