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