]> code.delx.au - gnu-emacs/blob - lib-src/ntlib.c
Merge from trunk and resolve conflicts.
[gnu-emacs] / 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 #include <windows.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <time.h>
27 #include <direct.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <errno.h>
31 #include <ctype.h>
32 #include <sys/timeb.h>
33 #include <mbstring.h>
34
35 #include "ntlib.h"
36
37 /* MinGW64 defines _TIMEZONE_DEFINED and defines 'struct timespec' in
38 its system headers. */
39 #ifndef _TIMEZONE_DEFINED
40 struct timezone
41 {
42 int tz_minuteswest; /* minutes west of Greenwich */
43 int tz_dsttime; /* type of dst correction */
44 };
45 #endif
46
47 #define MAXPATHLEN _MAX_PATH
48
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. */
52 void
53 sleep (unsigned long seconds)
54 {
55 Sleep (seconds * 1000);
56 }
57
58 /* Get the current working directory. */
59 char *
60 getwd (char *dir)
61 {
62 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
63 return dir;
64 return NULL;
65 }
66
67 static HANDLE getppid_parent;
68 static int getppid_ppid;
69
70 int
71 getppid (void)
72 {
73 char *ppid;
74 DWORD result;
75
76 ppid = getenv ("EM_PARENT_PROCESS_ID");
77 if (!ppid)
78 {
79 printf ("no pid.\n");
80 return 0;
81 }
82 else
83 {
84 getppid_ppid = atoi (ppid);
85 }
86
87 if (!getppid_parent)
88 {
89 getppid_parent = OpenProcess (SYNCHRONIZE, FALSE, atoi (ppid));
90 if (!getppid_parent)
91 {
92 printf ("Failed to open handle to parent process: %d\n",
93 GetLastError ());
94 exit (1);
95 }
96 }
97
98 result = WaitForSingleObject (getppid_parent, 0);
99 switch (result)
100 {
101 case WAIT_TIMEOUT:
102 /* The parent is still alive. */
103 return getppid_ppid;
104 case WAIT_OBJECT_0:
105 /* The parent is gone. Return the pid of Unix init (1). */
106 return 1;
107 case WAIT_FAILED:
108 default:
109 printf ("Checking parent status failed: %d\n", GetLastError ());
110 exit (1);
111 }
112 }
113
114 char *
115 getlogin (void)
116 {
117 static char user_name[256];
118 DWORD length = sizeof (user_name);
119
120 if (GetUserName (user_name, &length))
121 return user_name;
122 return NULL;
123 }
124
125 char *
126 cuserid (char * s)
127 {
128 char * name = getlogin ();
129 if (s)
130 return strcpy (s, name ? name : "");
131 return name;
132 }
133
134 unsigned
135 getuid (void)
136 {
137 return 0;
138 }
139
140 unsigned
141 getgid (void)
142 {
143 return 0;
144 }
145
146 unsigned
147 getegid (void)
148 {
149 return 0;
150 }
151
152 int
153 setuid (unsigned uid)
154 {
155 return 0;
156 }
157
158 int
159 setregid (unsigned rgid, unsigned gid)
160 {
161 return 0;
162 }
163
164 struct passwd *
165 getpwuid (unsigned uid)
166 {
167 return NULL;
168 }
169
170 char *
171 getpass (const char * prompt)
172 {
173 static char input[256];
174 HANDLE in;
175 HANDLE err;
176 DWORD count;
177
178 in = GetStdHandle (STD_INPUT_HANDLE);
179 err = GetStdHandle (STD_ERROR_HANDLE);
180
181 if (in == INVALID_HANDLE_VALUE || err == INVALID_HANDLE_VALUE)
182 return NULL;
183
184 if (WriteFile (err, prompt, strlen (prompt), &count, NULL))
185 {
186 int istty = (GetFileType (in) == FILE_TYPE_CHAR);
187 DWORD old_flags;
188 int rc;
189
190 if (istty)
191 {
192 if (GetConsoleMode (in, &old_flags))
193 SetConsoleMode (in, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
194 else
195 istty = 0;
196 }
197 rc = ReadFile (in, input, sizeof (input), &count, NULL);
198 if (count >= 2 && input[count - 2] == '\r')
199 input[count - 2] = '\0';
200 else
201 {
202 char buf[256];
203 while (ReadFile (in, buf, sizeof (buf), &count, NULL) > 0)
204 if (count >= 2 && buf[count - 2] == '\r')
205 break;
206 }
207 WriteFile (err, "\r\n", 2, &count, NULL);
208 if (istty)
209 SetConsoleMode (in, old_flags);
210 if (rc)
211 return input;
212 }
213
214 return NULL;
215 }
216
217 /* This is needed because lib/gettime.c calls gettimeofday, which MSVC
218 doesn't have. Copied from w32.c. */
219 void
220 gettimeofday (struct timeval *tv, struct timezone *tz)
221 {
222 struct _timeb tb;
223 _ftime (&tb);
224
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). */
233 if (tz)
234 {
235 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
236 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
237 }
238 }
239
240 int
241 fchown (int fd, unsigned uid, unsigned gid)
242 {
243 return 0;
244 }
245
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). */
249 char *
250 sys_ctime (const time_t *t)
251 {
252 char *str = (char *) ctime (t);
253 return (str ? str : "Sun Jan 01 00:00:00 1970");
254 }
255
256 FILE *
257 sys_fopen (const char * path, const char * mode)
258 {
259 return fopen (path, mode);
260 }
261
262 int
263 sys_chdir (const char * path)
264 {
265 return _chdir (path);
266 }
267
268 static FILETIME utc_base_ft;
269 static long double utc_base;
270 static int init = 0;
271
272 static time_t
273 convert_time (FILETIME ft)
274 {
275 long double ret;
276
277 if (CompareFileTime (&ft, &utc_base_ft) < 0)
278 return 0;
279
280 ret = (long double) ft.dwHighDateTime
281 * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
282 ret -= utc_base;
283 return (time_t) (ret * 1e-7L);
284 }
285
286 static int
287 is_exec (const char * name)
288 {
289 char * p = strrchr (name, '.');
290 return
291 (p != NULL
292 && (stricmp (p, ".exe") == 0 ||
293 stricmp (p, ".com") == 0 ||
294 stricmp (p, ".bat") == 0 ||
295 stricmp (p, ".cmd") == 0));
296 }
297
298 /* FIXME? This is in config.nt now - is this still needed? */
299 #define IS_DIRECTORY_SEP(x) ((x) == '/' || (x) == '\\')
300
301 /* We need this because nt/inc/sys/stat.h defines struct stat that is
302 incompatible with the MS run-time libraries. */
303 int
304 stat (const char * path, struct stat * buf)
305 {
306 WIN32_FIND_DATA wfd;
307 HANDLE fh;
308 int permission;
309 int len;
310 int rootdir = FALSE;
311 char *name = alloca (FILENAME_MAX);
312
313 if (!init)
314 {
315 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
316 SYSTEMTIME st;
317
318 st.wYear = 1970;
319 st.wMonth = 1;
320 st.wDay = 1;
321 st.wHour = 0;
322 st.wMinute = 0;
323 st.wSecond = 0;
324 st.wMilliseconds = 0;
325
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;
329 init = 1;
330 }
331
332 if (path == NULL || buf == NULL || *path == '\0')
333 {
334 errno = EFAULT;
335 return -1;
336 }
337 if (_mbspbrk (path, "*?|<>\""))
338 {
339 errno = ENOENT;
340 return -1;
341 }
342
343 strcpy (name, path);
344 /* Remove trailing directory separator, unless name is the root
345 directory of a drive in which case ensure there is a trailing
346 separator. */
347 len = strlen (name);
348 rootdir = IS_DIRECTORY_SEP (name[0])
349 || (len == 3 && name[1] == ':' && IS_DIRECTORY_SEP (name[2]));
350 if (rootdir)
351 {
352 if (GetDriveType (name) < 2)
353 {
354 errno = ENOENT;
355 return -1;
356 }
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);
363 }
364 else
365 {
366 if (IS_DIRECTORY_SEP (name[len-1]))
367 name[len - 1] = 0;
368
369 fh = FindFirstFile (name, &wfd);
370 if (fh == INVALID_HANDLE_VALUE)
371 {
372 errno = ENOENT;
373 return -1;
374 }
375 FindClose (fh);
376 }
377 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
378 S_IFDIR : S_IFREG;
379 buf->st_nlink = 1;
380 buf->st_ino = 0;
381
382 if (name[0] && name[1] == ':')
383 buf->st_dev = tolower (name[0]) - 'a' + 1;
384 else
385 buf->st_dev = _getdrive ();
386 buf->st_rdev = buf->st_dev;
387
388 buf->st_size = wfd.nFileSizeLow;
389
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;
396
397 /* determine rwx permissions */
398 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
399 permission = S_IREAD;
400 else
401 permission = S_IREAD | S_IWRITE;
402
403 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
404 permission |= S_IEXEC;
405 else if (is_exec (name))
406 permission |= S_IEXEC;
407
408 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
409
410 return 0;
411 }
412
413 int
414 lstat (const char * path, struct stat * buf)
415 {
416 return stat (path, buf);
417 }
418