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