1 /* Utility and Unix shadow routines for GNU Emacs support programs on NT.
3 Copyright (C) 1994, 2001-2013 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
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/>. */
28 #include <sys/types.h>
32 #include <sys/timeb.h>
37 /* MinGW64 defines _TIMEZONE_DEFINED and defines 'struct timespec' in
38 its system headers. */
39 #ifndef _TIMEZONE_DEFINED
42 int tz_minuteswest
; /* minutes west of Greenwich */
43 int tz_dsttime
; /* type of dst correction */
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. */
53 sleep (unsigned seconds
)
55 Sleep (seconds
* 1000);
59 /* Get the current working directory. */
63 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
68 static HANDLE getppid_parent
;
69 static int getppid_ppid
;
77 ppid
= getenv ("EM_PARENT_PROCESS_ID");
85 getppid_ppid
= atoi (ppid
);
90 getppid_parent
= OpenProcess (SYNCHRONIZE
, FALSE
, atoi (ppid
));
93 printf ("Failed to open handle to parent process: %d\n",
99 result
= WaitForSingleObject (getppid_parent
, 0);
103 /* The parent is still alive. */
106 /* The parent is gone. Return the pid of Unix init (1). */
110 printf ("Checking parent status failed: %d\n", GetLastError ());
118 static char user_name
[256];
119 DWORD length
= sizeof (user_name
);
121 if (GetUserName (user_name
, &length
))
129 char * name
= getlogin ();
131 return strcpy (s
, name
? name
: "");
160 setuid (unsigned uid
)
166 setregid (unsigned rgid
, unsigned gid
)
172 getpwuid (unsigned uid
)
178 getpass (const char * prompt
)
180 static char input
[256];
185 in
= GetStdHandle (STD_INPUT_HANDLE
);
186 err
= GetStdHandle (STD_ERROR_HANDLE
);
188 if (in
== INVALID_HANDLE_VALUE
|| err
== INVALID_HANDLE_VALUE
)
191 if (WriteFile (err
, prompt
, strlen (prompt
), &count
, NULL
))
193 int istty
= (GetFileType (in
) == FILE_TYPE_CHAR
);
199 if (GetConsoleMode (in
, &old_flags
))
200 SetConsoleMode (in
, ENABLE_LINE_INPUT
| ENABLE_PROCESSED_INPUT
);
204 rc
= ReadFile (in
, input
, sizeof (input
), &count
, NULL
);
205 if (count
>= 2 && input
[count
- 2] == '\r')
206 input
[count
- 2] = '\0';
210 while (ReadFile (in
, buf
, sizeof (buf
), &count
, NULL
) > 0)
211 if (count
>= 2 && buf
[count
- 2] == '\r')
214 WriteFile (err
, "\r\n", 2, &count
, NULL
);
216 SetConsoleMode (in
, old_flags
);
224 /* This is needed because lib/gettime.c calls gettimeofday, which MSVC
225 doesn't have. Copied from w32.c. */
227 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
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). */
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
)
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). */
257 sys_ctime (const time_t *t
)
259 char *str
= (char *) ctime (t
);
260 return (str
? str
: "Sun Jan 01 00:00:00 1970");
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
;
280 convert_time (FILETIME ft
)
284 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
287 ret
= (long double) ft
.dwHighDateTime
288 * 4096.0L * 1024.0L * 1024.0L + ft
.dwLowDateTime
;
290 return (time_t) (ret
* 1e-7L);
294 is_exec (const char * name
)
296 char * p
= strrchr (name
, '.');
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
)
318 char *name
= alloca (FILENAME_MAX
);
322 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
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
;
339 if (path
== NULL
|| buf
== NULL
|| *path
== '\0')
344 if (_mbspbrk (path
, "*?|<>\""))
351 /* Remove trailing directory separator, unless name is the root
352 directory of a drive in which case ensure there is a trailing
355 rootdir
= IS_DIRECTORY_SEP (name
[0])
356 || (len
== 3 && name
[1] == ':' && IS_DIRECTORY_SEP (name
[2]));
359 if (GetDriveType (name
) < 2)
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
);
373 if (IS_DIRECTORY_SEP (name
[len
-1]))
376 fh
= FindFirstFile (name
, &wfd
);
377 if (fh
== INVALID_HANDLE_VALUE
)
384 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
389 if (name
[0] && name
[1] == ':')
390 buf
->st_dev
= tolower (name
[0]) - 'a' + 1;
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
;
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);
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
)
441 unsigned uid
= GetCurrentThreadId ();
442 int save_errno
= errno
;
443 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
446 if (template == NULL
)
449 p
= template + strlen (template);
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;
458 if (i
< 0 && p
[0] == 'X')
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
474 while (++i
< sizeof (first_char
));
477 /* Template is badly formed or else we can't generate a unique name. */
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
);