Finished with lib-src compilation, except emacsclientw and emacsclient.res.
[bpt/emacs.git] / lib-src / ntlib.c
CommitLineData
95ed0025 1/* Utility and Unix shadow routines for GNU Emacs support programs on NT.
59a428eb 2
ab422c4d 3Copyright (C) 1994, 2001-2013 Free Software Foundation, Inc.
59a428eb
GM
4
5Author: Geoff Voelker (voelker@cs.washington.edu)
6Created: 10-8-94
95ed0025 7
3b7ad313
EN
8This file is part of GNU Emacs.
9
294981c7 10GNU Emacs is free software: you can redistribute it and/or modify
3b7ad313 11it under the terms of the GNU General Public License as published by
294981c7
GM
12the Free Software Foundation, either version 3 of the License, or
13(at your option) any later version.
3b7ad313
EN
14
15GNU Emacs is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
59a428eb 21along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
95ed0025 22
7c4026b6
EZ
23#ifdef __MINGW32__
24/* A kludge to avoid including header files in lib/. They cannot be
25 configured-out, and their stuff interferes with what we have
26 defined in this header and in other headers in nt/inc. Yuck! */
27#define __need_system_fcntl_h
28#define _GL_FCNTL_H
29#define _GL_JUST_INCLUDE_SYSTEM_INTTYPES_H
30#define _GL_ALREADY_INCLUDING_SIGNAL_H
31#define _GL_ALREADY_INCLUDING_STDIO_H
32#define __need_system_stdlib_h
33#define _GL_TIME_H
34#define __need_system_sys_stat_h
35#endif
36
95ed0025
RS
37#include <windows.h>
38#include <stdlib.h>
39#include <stdio.h>
14f29224
GV
40#include <time.h>
41#include <direct.h>
10fea9c4
EZ
42#include <sys/types.h>
43#include <sys/stat.h>
44#include <errno.h>
9c88f339 45#include <ctype.h>
62aba0d4 46#include <sys/timeb.h>
27067208 47#include <mbstring.h>
14f29224
GV
48
49#include "ntlib.h"
95ed0025 50
b88b62de
EZ
51/* MinGW64 defines _TIMEZONE_DEFINED and defines 'struct timespec' in
52 its system headers. */
53#ifndef _TIMEZONE_DEFINED
62aba0d4
FP
54struct timezone
55{
56 int tz_minuteswest; /* minutes west of Greenwich */
57 int tz_dsttime; /* type of dst correction */
58};
b88b62de 59#endif
62aba0d4 60
95ed0025
RS
61#define MAXPATHLEN _MAX_PATH
62
63/* Emulate sleep...we could have done this with a define, but that
64 would necessitate including windows.h in the files that used it.
65 This is much easier. */
7c4026b6
EZ
66unsigned
67sleep (unsigned seconds)
95ed0025
RS
68{
69 Sleep (seconds * 1000);
7c4026b6 70 return 0;
95ed0025
RS
71}
72
73/* Get the current working directory. */
133319ab 74char *
95ed0025
RS
75getwd (char *dir)
76{
14f29224
GV
77 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
78 return dir;
79 return NULL;
95ed0025
RS
80}
81
82static HANDLE getppid_parent;
83static int getppid_ppid;
84
85int
7c3320d8 86getppid (void)
95ed0025
RS
87{
88 char *ppid;
89 DWORD result;
90
97e3c91b 91 ppid = getenv ("EM_PARENT_PROCESS_ID");
177c0ea7 92 if (!ppid)
95ed0025 93 {
7c3320d8 94 printf ("no pid.\n");
95ed0025 95 return 0;
177c0ea7
JB
96 }
97 else
95ed0025
RS
98 {
99 getppid_ppid = atoi (ppid);
100 }
101
177c0ea7 102 if (!getppid_parent)
95ed0025 103 {
7c3320d8 104 getppid_parent = OpenProcess (SYNCHRONIZE, FALSE, atoi (ppid));
177c0ea7 105 if (!getppid_parent)
95ed0025
RS
106 {
107 printf ("Failed to open handle to parent process: %d\n",
7c3320d8 108 GetLastError ());
95ed0025
RS
109 exit (1);
110 }
111 }
112
113 result = WaitForSingleObject (getppid_parent, 0);
177c0ea7 114 switch (result)
95ed0025
RS
115 {
116 case WAIT_TIMEOUT:
117 /* The parent is still alive. */
118 return getppid_ppid;
119 case WAIT_OBJECT_0:
120 /* The parent is gone. Return the pid of Unix init (1). */
121 return 1;
122 case WAIT_FAILED:
123 default:
7c3320d8 124 printf ("Checking parent status failed: %d\n", GetLastError ());
95ed0025
RS
125 exit (1);
126 }
127}
14f29224
GV
128
129char *
7c3320d8 130getlogin (void)
14f29224
GV
131{
132 static char user_name[256];
133 DWORD length = sizeof (user_name);
134
135 if (GetUserName (user_name, &length))
136 return user_name;
137 return NULL;
138}
139
140char *
141cuserid (char * s)
142{
143 char * name = getlogin ();
144 if (s)
145 return strcpy (s, name ? name : "");
146 return name;
147}
148
22749e9a 149unsigned
7c3320d8 150getuid (void)
14f29224
GV
151{
152 return 0;
153}
154
7c4026b6
EZ
155unsigned
156geteuid (void)
157{
158 return getuid ();
159}
160
b372fceb 161unsigned
7c3320d8 162getgid (void)
b372fceb
JB
163{
164 return 0;
165}
166
167unsigned
7c3320d8 168getegid (void)
b372fceb
JB
169{
170 return 0;
171}
172
14f29224 173int
22749e9a 174setuid (unsigned uid)
14f29224
GV
175{
176 return 0;
177}
178
b372fceb 179int
f915f0f7 180setregid (unsigned rgid, unsigned gid)
b372fceb
JB
181{
182 return 0;
183}
184
14f29224 185struct passwd *
22749e9a 186getpwuid (unsigned uid)
14f29224
GV
187{
188 return NULL;
189}
190
191char *
192getpass (const char * prompt)
193{
194 static char input[256];
195 HANDLE in;
196 HANDLE err;
197 DWORD count;
198
199 in = GetStdHandle (STD_INPUT_HANDLE);
200 err = GetStdHandle (STD_ERROR_HANDLE);
201
202 if (in == INVALID_HANDLE_VALUE || err == INVALID_HANDLE_VALUE)
203 return NULL;
204
205 if (WriteFile (err, prompt, strlen (prompt), &count, NULL))
206 {
207 int istty = (GetFileType (in) == FILE_TYPE_CHAR);
208 DWORD old_flags;
209 int rc;
210
211 if (istty)
212 {
213 if (GetConsoleMode (in, &old_flags))
214 SetConsoleMode (in, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
215 else
216 istty = 0;
217 }
218 rc = ReadFile (in, input, sizeof (input), &count, NULL);
219 if (count >= 2 && input[count - 2] == '\r')
220 input[count - 2] = '\0';
221 else
222 {
223 char buf[256];
224 while (ReadFile (in, buf, sizeof (buf), &count, NULL) > 0)
225 if (count >= 2 && buf[count - 2] == '\r')
226 break;
227 }
228 WriteFile (err, "\r\n", 2, &count, NULL);
229 if (istty)
230 SetConsoleMode (in, old_flags);
231 if (rc)
232 return input;
233 }
234
235 return NULL;
236}
237
62aba0d4
FP
238/* This is needed because lib/gettime.c calls gettimeofday, which MSVC
239 doesn't have. Copied from w32.c. */
240void
241gettimeofday (struct timeval *tv, struct timezone *tz)
242{
243 struct _timeb tb;
244 _ftime (&tb);
245
246 tv->tv_sec = tb.time;
247 tv->tv_usec = tb.millitm * 1000L;
248 /* Implementation note: _ftime sometimes doesn't update the dstflag
249 according to the new timezone when the system timezone is
250 changed. We could fix that by using GetSystemTime and
251 GetTimeZoneInformation, but that doesn't seem necessary, since
252 Emacs always calls gettimeofday with the 2nd argument NULL (see
253 current_emacs_time). */
254 if (tz)
255 {
256 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
257 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
258 }
259}
260
14f29224 261int
22749e9a 262fchown (int fd, unsigned uid, unsigned gid)
14f29224
GV
263{
264 return 0;
265}
266
267/* Place a wrapper around the MSVC version of ctime. It returns NULL
177c0ea7 268 on network directories, so we handle that case here.
14f29224
GV
269 (Ulrich Leodolter, 1/11/95). */
270char *
271sys_ctime (const time_t *t)
272{
273 char *str = (char *) ctime (t);
274 return (str ? str : "Sun Jan 01 00:00:00 1970");
275}
276
277FILE *
7c3320d8 278sys_fopen (const char * path, const char * mode)
14f29224
GV
279{
280 return fopen (path, mode);
281}
282
283int
284sys_chdir (const char * path)
285{
286 return _chdir (path);
287}
ab5796a9 288
10fea9c4
EZ
289static FILETIME utc_base_ft;
290static long double utc_base;
291static int init = 0;
292
293static time_t
294convert_time (FILETIME ft)
295{
296 long double ret;
297
298 if (CompareFileTime (&ft, &utc_base_ft) < 0)
299 return 0;
300
301 ret = (long double) ft.dwHighDateTime
302 * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
303 ret -= utc_base;
304 return (time_t) (ret * 1e-7L);
305}
306
307static int
308is_exec (const char * name)
309{
310 char * p = strrchr (name, '.');
311 return
312 (p != NULL
313 && (stricmp (p, ".exe") == 0 ||
314 stricmp (p, ".com") == 0 ||
315 stricmp (p, ".bat") == 0 ||
316 stricmp (p, ".cmd") == 0));
317}
318
59a428eb 319/* FIXME? This is in config.nt now - is this still needed? */
10fea9c4
EZ
320#define IS_DIRECTORY_SEP(x) ((x) == '/' || (x) == '\\')
321
322/* We need this because nt/inc/sys/stat.h defines struct stat that is
323 incompatible with the MS run-time libraries. */
324int
325stat (const char * path, struct stat * buf)
326{
327 WIN32_FIND_DATA wfd;
328 HANDLE fh;
329 int permission;
330 int len;
331 int rootdir = FALSE;
332 char *name = alloca (FILENAME_MAX);
333
334 if (!init)
335 {
336 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
337 SYSTEMTIME st;
338
339 st.wYear = 1970;
340 st.wMonth = 1;
341 st.wDay = 1;
342 st.wHour = 0;
343 st.wMinute = 0;
344 st.wSecond = 0;
345 st.wMilliseconds = 0;
346
347 SystemTimeToFileTime (&st, &utc_base_ft);
348 utc_base = (long double) utc_base_ft.dwHighDateTime
349 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
350 init = 1;
351 }
352
353 if (path == NULL || buf == NULL || *path == '\0')
354 {
355 errno = EFAULT;
356 return -1;
357 }
358 if (_mbspbrk (path, "*?|<>\""))
359 {
360 errno = ENOENT;
361 return -1;
362 }
363
364 strcpy (name, path);
365 /* Remove trailing directory separator, unless name is the root
366 directory of a drive in which case ensure there is a trailing
367 separator. */
368 len = strlen (name);
369 rootdir = IS_DIRECTORY_SEP (name[0])
370 || (len == 3 && name[1] == ':' && IS_DIRECTORY_SEP (name[2]));
371 if (rootdir)
372 {
373 if (GetDriveType (name) < 2)
374 {
375 errno = ENOENT;
376 return -1;
377 }
378 memset (&wfd, 0, sizeof (wfd));
379 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
380 wfd.ftCreationTime = utc_base_ft;
381 wfd.ftLastAccessTime = utc_base_ft;
382 wfd.ftLastWriteTime = utc_base_ft;
383 strcpy (wfd.cFileName, name);
384 }
385 else
386 {
387 if (IS_DIRECTORY_SEP (name[len-1]))
388 name[len - 1] = 0;
389
390 fh = FindFirstFile (name, &wfd);
391 if (fh == INVALID_HANDLE_VALUE)
392 {
393 errno = ENOENT;
394 return -1;
395 }
396 FindClose (fh);
397 }
398 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
399 S_IFDIR : S_IFREG;
400 buf->st_nlink = 1;
401 buf->st_ino = 0;
402
403 if (name[0] && name[1] == ':')
404 buf->st_dev = tolower (name[0]) - 'a' + 1;
405 else
406 buf->st_dev = _getdrive ();
407 buf->st_rdev = buf->st_dev;
408
409 buf->st_size = wfd.nFileSizeLow;
410
411 /* Convert timestamps to Unix format. */
412 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
413 buf->st_atime = convert_time (wfd.ftLastAccessTime);
414 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
415 buf->st_ctime = convert_time (wfd.ftCreationTime);
416 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
417
418 /* determine rwx permissions */
419 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
420 permission = S_IREAD;
421 else
422 permission = S_IREAD | S_IWRITE;
423
424 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
425 permission |= S_IEXEC;
426 else if (is_exec (name))
427 permission |= S_IEXEC;
428
429 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
430
431 return 0;
432}
433
6dad7178
EZ
434int
435lstat (const char * path, struct stat * buf)
436{
437 return stat (path, buf);
438}