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 long seconds
)
55 Sleep (seconds
* 1000);
58 /* Get the current working directory. */
62 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
67 static HANDLE getppid_parent
;
68 static int getppid_ppid
;
76 ppid
= getenv ("EM_PARENT_PROCESS_ID");
84 getppid_ppid
= atoi (ppid
);
89 getppid_parent
= OpenProcess (SYNCHRONIZE
, FALSE
, atoi (ppid
));
92 printf ("Failed to open handle to parent process: %d\n",
98 result
= WaitForSingleObject (getppid_parent
, 0);
102 /* The parent is still alive. */
105 /* The parent is gone. Return the pid of Unix init (1). */
109 printf ("Checking parent status failed: %d\n", GetLastError ());
117 static char user_name
[256];
118 DWORD length
= sizeof (user_name
);
120 if (GetUserName (user_name
, &length
))
128 char * name
= getlogin ();
130 return strcpy (s
, name
? name
: "");
153 setuid (unsigned uid
)
159 setregid (unsigned rgid
, unsigned gid
)
165 getpwuid (unsigned uid
)
171 getpass (const char * prompt
)
173 static char input
[256];
178 in
= GetStdHandle (STD_INPUT_HANDLE
);
179 err
= GetStdHandle (STD_ERROR_HANDLE
);
181 if (in
== INVALID_HANDLE_VALUE
|| err
== INVALID_HANDLE_VALUE
)
184 if (WriteFile (err
, prompt
, strlen (prompt
), &count
, NULL
))
186 int istty
= (GetFileType (in
) == FILE_TYPE_CHAR
);
192 if (GetConsoleMode (in
, &old_flags
))
193 SetConsoleMode (in
, ENABLE_LINE_INPUT
| ENABLE_PROCESSED_INPUT
);
197 rc
= ReadFile (in
, input
, sizeof (input
), &count
, NULL
);
198 if (count
>= 2 && input
[count
- 2] == '\r')
199 input
[count
- 2] = '\0';
203 while (ReadFile (in
, buf
, sizeof (buf
), &count
, NULL
) > 0)
204 if (count
>= 2 && buf
[count
- 2] == '\r')
207 WriteFile (err
, "\r\n", 2, &count
, NULL
);
209 SetConsoleMode (in
, old_flags
);
217 /* This is needed because lib/gettime.c calls gettimeofday, which MSVC
218 doesn't have. Copied from w32.c. */
220 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
225 tv
->tv_sec
= tb
.time
;
226 tv
->tv_usec
= tb
.millitm
* 1000L;
227 /* Implementation note: _ftime sometimes doesn't update the dstflag
228 according to the new timezone when the system timezone is
229 changed. We could fix that by using GetSystemTime and
230 GetTimeZoneInformation, but that doesn't seem necessary, since
231 Emacs always calls gettimeofday with the 2nd argument NULL (see
232 current_emacs_time). */
235 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
236 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
241 fchown (int fd
, unsigned uid
, unsigned gid
)
246 /* Place a wrapper around the MSVC version of ctime. It returns NULL
247 on network directories, so we handle that case here.
248 (Ulrich Leodolter, 1/11/95). */
250 sys_ctime (const time_t *t
)
252 char *str
= (char *) ctime (t
);
253 return (str
? str
: "Sun Jan 01 00:00:00 1970");
257 sys_fopen (const char * path
, const char * mode
)
259 return fopen (path
, mode
);
263 sys_chdir (const char * path
)
265 return _chdir (path
);
268 static FILETIME utc_base_ft
;
269 static long double utc_base
;
273 convert_time (FILETIME ft
)
277 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
280 ret
= (long double) ft
.dwHighDateTime
281 * 4096.0L * 1024.0L * 1024.0L + ft
.dwLowDateTime
;
283 return (time_t) (ret
* 1e-7L);
287 is_exec (const char * name
)
289 char * p
= strrchr (name
, '.');
292 && (stricmp (p
, ".exe") == 0 ||
293 stricmp (p
, ".com") == 0 ||
294 stricmp (p
, ".bat") == 0 ||
295 stricmp (p
, ".cmd") == 0));
298 /* FIXME? This is in config.nt now - is this still needed? */
299 #define IS_DIRECTORY_SEP(x) ((x) == '/' || (x) == '\\')
301 /* We need this because nt/inc/sys/stat.h defines struct stat that is
302 incompatible with the MS run-time libraries. */
304 stat (const char * path
, struct stat
* buf
)
311 char *name
= alloca (FILENAME_MAX
);
315 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
324 st
.wMilliseconds
= 0;
326 SystemTimeToFileTime (&st
, &utc_base_ft
);
327 utc_base
= (long double) utc_base_ft
.dwHighDateTime
328 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft
.dwLowDateTime
;
332 if (path
== NULL
|| buf
== NULL
|| *path
== '\0')
337 if (_mbspbrk (path
, "*?|<>\""))
344 /* Remove trailing directory separator, unless name is the root
345 directory of a drive in which case ensure there is a trailing
348 rootdir
= IS_DIRECTORY_SEP (name
[0])
349 || (len
== 3 && name
[1] == ':' && IS_DIRECTORY_SEP (name
[2]));
352 if (GetDriveType (name
) < 2)
357 memset (&wfd
, 0, sizeof (wfd
));
358 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
359 wfd
.ftCreationTime
= utc_base_ft
;
360 wfd
.ftLastAccessTime
= utc_base_ft
;
361 wfd
.ftLastWriteTime
= utc_base_ft
;
362 strcpy (wfd
.cFileName
, name
);
366 if (IS_DIRECTORY_SEP (name
[len
-1]))
369 fh
= FindFirstFile (name
, &wfd
);
370 if (fh
== INVALID_HANDLE_VALUE
)
377 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
382 if (name
[0] && name
[1] == ':')
383 buf
->st_dev
= tolower (name
[0]) - 'a' + 1;
385 buf
->st_dev
= _getdrive ();
386 buf
->st_rdev
= buf
->st_dev
;
388 buf
->st_size
= wfd
.nFileSizeLow
;
390 /* Convert timestamps to Unix format. */
391 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
392 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
393 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
394 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
395 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
397 /* determine rwx permissions */
398 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
399 permission
= S_IREAD
;
401 permission
= S_IREAD
| S_IWRITE
;
403 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
404 permission
|= S_IEXEC
;
405 else if (is_exec (name
))
406 permission
|= S_IEXEC
;
408 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
414 lstat (const char * path
, struct stat
* buf
)
416 return stat (path
, buf
);