Finished with lib-src compilation, except emacsclientw and emacsclient.res.
[bpt/emacs.git] / lib-src / ntlib.c
1 /* Utility and Unix shadow routines for GNU Emacs support programs on NT.
2
3 Copyright (C) 1994, 2001-2013 Free Software Foundation, Inc.
4
5 Author: Geoff Voelker (voelker@cs.washington.edu)
6 Created: 10-8-94
7
8 This file is part of GNU Emacs.
9
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.
14
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.
19
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/>. */
22
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
37 #include <windows.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <time.h>
41 #include <direct.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <errno.h>
45 #include <ctype.h>
46 #include <sys/timeb.h>
47 #include <mbstring.h>
48
49 #include "ntlib.h"
50
51 /* MinGW64 defines _TIMEZONE_DEFINED and defines 'struct timespec' in
52 its system headers. */
53 #ifndef _TIMEZONE_DEFINED
54 struct timezone
55 {
56 int tz_minuteswest; /* minutes west of Greenwich */
57 int tz_dsttime; /* type of dst correction */
58 };
59 #endif
60
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. */
66 unsigned
67 sleep (unsigned seconds)
68 {
69 Sleep (seconds * 1000);
70 return 0;
71 }
72
73 /* Get the current working directory. */
74 char *
75 getwd (char *dir)
76 {
77 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
78 return dir;
79 return NULL;
80 }
81
82 static HANDLE getppid_parent;
83 static int getppid_ppid;
84
85 int
86 getppid (void)
87 {
88 char *ppid;
89 DWORD result;
90
91 ppid = getenv ("EM_PARENT_PROCESS_ID");
92 if (!ppid)
93 {
94 printf ("no pid.\n");
95 return 0;
96 }
97 else
98 {
99 getppid_ppid = atoi (ppid);
100 }
101
102 if (!getppid_parent)
103 {
104 getppid_parent = OpenProcess (SYNCHRONIZE, FALSE, atoi (ppid));
105 if (!getppid_parent)
106 {
107 printf ("Failed to open handle to parent process: %d\n",
108 GetLastError ());
109 exit (1);
110 }
111 }
112
113 result = WaitForSingleObject (getppid_parent, 0);
114 switch (result)
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:
124 printf ("Checking parent status failed: %d\n", GetLastError ());
125 exit (1);
126 }
127 }
128
129 char *
130 getlogin (void)
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
140 char *
141 cuserid (char * s)
142 {
143 char * name = getlogin ();
144 if (s)
145 return strcpy (s, name ? name : "");
146 return name;
147 }
148
149 unsigned
150 getuid (void)
151 {
152 return 0;
153 }
154
155 unsigned
156 geteuid (void)
157 {
158 return getuid ();
159 }
160
161 unsigned
162 getgid (void)
163 {
164 return 0;
165 }
166
167 unsigned
168 getegid (void)
169 {
170 return 0;
171 }
172
173 int
174 setuid (unsigned uid)
175 {
176 return 0;
177 }
178
179 int
180 setregid (unsigned rgid, unsigned gid)
181 {
182 return 0;
183 }
184
185 struct passwd *
186 getpwuid (unsigned uid)
187 {
188 return NULL;
189 }
190
191 char *
192 getpass (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
238 /* This is needed because lib/gettime.c calls gettimeofday, which MSVC
239 doesn't have. Copied from w32.c. */
240 void
241 gettimeofday (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
261 int
262 fchown (int fd, unsigned uid, unsigned gid)
263 {
264 return 0;
265 }
266
267 /* Place a wrapper around the MSVC version of ctime. It returns NULL
268 on network directories, so we handle that case here.
269 (Ulrich Leodolter, 1/11/95). */
270 char *
271 sys_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
277 FILE *
278 sys_fopen (const char * path, const char * mode)
279 {
280 return fopen (path, mode);
281 }
282
283 int
284 sys_chdir (const char * path)
285 {
286 return _chdir (path);
287 }
288
289 static FILETIME utc_base_ft;
290 static long double utc_base;
291 static int init = 0;
292
293 static time_t
294 convert_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
307 static int
308 is_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
319 /* FIXME? This is in config.nt now - is this still needed? */
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. */
324 int
325 stat (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
434 int
435 lstat (const char * path, struct stat * buf)
436 {
437 return stat (path, buf);
438 }