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 #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. */
59 sleep (unsigned seconds
)
61 Sleep (seconds
* 1000);
65 /* Get the current working directory. */
69 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
74 static HANDLE getppid_parent
;
75 static int getppid_ppid
;
83 ppid
= getenv ("EM_PARENT_PROCESS_ID");
91 getppid_ppid
= atoi (ppid
);
96 getppid_parent
= OpenProcess (SYNCHRONIZE
, FALSE
, atoi (ppid
));
99 printf ("Failed to open handle to parent process: %lu\n",
105 result
= WaitForSingleObject (getppid_parent
, 0);
109 /* The parent is still alive. */
112 /* The parent is gone. Return the pid of Unix init (1). */
116 printf ("Checking parent status failed: %lu\n", GetLastError ());
124 static char user_name
[256];
125 DWORD length
= sizeof (user_name
);
127 if (GetUserName (user_name
, &length
))
135 char * name
= getlogin ();
137 return strcpy (s
, name
? name
: "");
166 setuid (unsigned uid
)
172 setregid (unsigned rgid
, unsigned gid
)
178 getpwuid (unsigned uid
)
184 getpass (const char * prompt
)
186 static char input
[256];
191 in
= GetStdHandle (STD_INPUT_HANDLE
);
192 err
= GetStdHandle (STD_ERROR_HANDLE
);
194 if (in
== INVALID_HANDLE_VALUE
|| err
== INVALID_HANDLE_VALUE
)
197 if (WriteFile (err
, prompt
, strlen (prompt
), &count
, NULL
))
199 int istty
= (GetFileType (in
) == FILE_TYPE_CHAR
);
205 if (GetConsoleMode (in
, &old_flags
))
206 SetConsoleMode (in
, ENABLE_LINE_INPUT
| ENABLE_PROCESSED_INPUT
);
210 rc
= ReadFile (in
, input
, sizeof (input
), &count
, NULL
);
211 if (count
>= 2 && input
[count
- 2] == '\r')
212 input
[count
- 2] = '\0';
216 while (ReadFile (in
, buf
, sizeof (buf
), &count
, NULL
) > 0)
217 if (count
>= 2 && buf
[count
- 2] == '\r')
220 WriteFile (err
, "\r\n", 2, &count
, NULL
);
222 SetConsoleMode (in
, old_flags
);
231 fchown (int fd
, unsigned uid
, unsigned gid
)
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
;
253 convert_time (FILETIME ft
)
257 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
260 ret
= (long double) ft
.dwHighDateTime
261 * 4096.0L * 1024.0L * 1024.0L + ft
.dwLowDateTime
;
263 return (time_t) (ret
* 1e-7L);
267 is_exec (const char * name
)
269 char * p
= strrchr (name
, '.');
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
)
291 char *name
= alloca (FILENAME_MAX
);
295 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
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
;
312 if (path
== NULL
|| buf
== NULL
|| *path
== '\0')
317 if (_mbspbrk (path
, "*?|<>\""))
324 /* Remove trailing directory separator, unless name is the root
325 directory of a drive in which case ensure there is a trailing
328 rootdir
= IS_DIRECTORY_SEP (name
[0])
329 || (len
== 3 && name
[1] == ':' && IS_DIRECTORY_SEP (name
[2]));
332 if (GetDriveType (name
) < 2)
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
);
346 if (IS_DIRECTORY_SEP (name
[len
-1]))
349 fh
= FindFirstFile (name
, &wfd
);
350 if (fh
== INVALID_HANDLE_VALUE
)
357 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
362 if (name
[0] && name
[1] == ':')
363 buf
->st_dev
= tolower (name
[0]) - 'a' + 1;
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
;
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);
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
)
414 unsigned uid
= GetCurrentThreadId ();
415 int save_errno
= errno
;
416 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
419 if (template == NULL
)
422 p
= template + strlen (template);
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;
431 if (i
< 0 && p
[0] == 'X')
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
447 while (++i
< sizeof (first_char
));
450 /* Template is badly formed or else we can't generate a unique name. */
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
);