* vc/vc-hooks.el (vc-find-file-hook): Don't ask about following links
[emacs.git] / lib-src / ntlib.c
blobf43117457cb1de29b8f065ce0f13820b84abef8d
1 /* Utility and Unix shadow routines for GNU Emacs support programs on NT.
3 Copyright (C) 1994, 2001-2013 Free Software Foundation, Inc.
5 Author: Geoff Voelker (voelker@cs.washington.edu)
6 Created: 10-8-94
8 This file is part of GNU Emacs.
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.
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.
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/>. */
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>
35 #include "ntlib.h"
37 struct timezone
39 int tz_minuteswest; /* minutes west of Greenwich */
40 int tz_dsttime; /* type of dst correction */
43 #define MAXPATHLEN _MAX_PATH
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)
51 Sleep (seconds * 1000);
54 /* Get the current working directory. */
55 char *
56 getwd (char *dir)
58 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
59 return dir;
60 return NULL;
63 static HANDLE getppid_parent;
64 static int getppid_ppid;
66 int
67 getppid (void)
69 char *ppid;
70 DWORD result;
72 ppid = getenv ("EM_PARENT_PROCESS_ID");
73 if (!ppid)
75 printf ("no pid.\n");
76 return 0;
78 else
80 getppid_ppid = atoi (ppid);
83 if (!getppid_parent)
85 getppid_parent = OpenProcess (SYNCHRONIZE, FALSE, atoi (ppid));
86 if (!getppid_parent)
88 printf ("Failed to open handle to parent process: %d\n",
89 GetLastError ());
90 exit (1);
94 result = WaitForSingleObject (getppid_parent, 0);
95 switch (result)
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);
110 char *
111 getlogin (void)
113 static char user_name[256];
114 DWORD length = sizeof (user_name);
116 if (GetUserName (user_name, &length))
117 return user_name;
118 return NULL;
121 char *
122 cuserid (char * s)
124 char * name = getlogin ();
125 if (s)
126 return strcpy (s, name ? name : "");
127 return name;
130 unsigned
131 getuid (void)
133 return 0;
136 unsigned
137 getgid (void)
139 return 0;
142 unsigned
143 getegid (void)
145 return 0;
149 setuid (unsigned uid)
151 return 0;
155 setregid (unsigned rgid, unsigned gid)
157 return 0;
160 struct passwd *
161 getpwuid (unsigned uid)
163 return NULL;
166 char *
167 getpass (const char * prompt)
169 static char input[256];
170 HANDLE in;
171 HANDLE err;
172 DWORD count;
174 in = GetStdHandle (STD_INPUT_HANDLE);
175 err = GetStdHandle (STD_ERROR_HANDLE);
177 if (in == INVALID_HANDLE_VALUE || err == INVALID_HANDLE_VALUE)
178 return NULL;
180 if (WriteFile (err, prompt, strlen (prompt), &count, NULL))
182 int istty = (GetFileType (in) == FILE_TYPE_CHAR);
183 DWORD old_flags;
184 int rc;
186 if (istty)
188 if (GetConsoleMode (in, &old_flags))
189 SetConsoleMode (in, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
190 else
191 istty = 0;
193 rc = ReadFile (in, input, sizeof (input), &count, NULL);
194 if (count >= 2 && input[count - 2] == '\r')
195 input[count - 2] = '\0';
196 else
198 char buf[256];
199 while (ReadFile (in, buf, sizeof (buf), &count, NULL) > 0)
200 if (count >= 2 && buf[count - 2] == '\r')
201 break;
203 WriteFile (err, "\r\n", 2, &count, NULL);
204 if (istty)
205 SetConsoleMode (in, old_flags);
206 if (rc)
207 return input;
210 return NULL;
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)
218 struct _timeb tb;
219 _ftime (&tb);
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)
231 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
232 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
237 fchown (int fd, unsigned uid, unsigned gid)
239 return 0;
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)
248 char *str = (char *) ctime (t);
249 return (str ? str : "Sun Jan 01 00:00:00 1970");
252 FILE *
253 sys_fopen (const char * path, const char * mode)
255 return fopen (path, mode);
259 sys_chdir (const char * path)
261 return _chdir (path);
264 static FILETIME utc_base_ft;
265 static long double utc_base;
266 static int init = 0;
268 static time_t
269 convert_time (FILETIME ft)
271 long double ret;
273 if (CompareFileTime (&ft, &utc_base_ft) < 0)
274 return 0;
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);
282 static int
283 is_exec (const char * name)
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));
294 /* FIXME? This is in config.nt now - is this still needed? */
295 #define IS_DIRECTORY_SEP(x) ((x) == '/' || (x) == '\\')
297 /* We need this because nt/inc/sys/stat.h defines struct stat that is
298 incompatible with the MS run-time libraries. */
300 stat (const char * path, struct stat * buf)
302 WIN32_FIND_DATA wfd;
303 HANDLE fh;
304 int permission;
305 int len;
306 int rootdir = FALSE;
307 char *name = alloca (FILENAME_MAX);
309 if (!init)
311 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
312 SYSTEMTIME st;
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;
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;
328 if (path == NULL || buf == NULL || *path == '\0')
330 errno = EFAULT;
331 return -1;
333 if (_mbspbrk (path, "*?|<>\""))
335 errno = ENOENT;
336 return -1;
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)
348 if (GetDriveType (name) < 2)
350 errno = ENOENT;
351 return -1;
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);
360 else
362 if (IS_DIRECTORY_SEP (name[len-1]))
363 name[len - 1] = 0;
365 fh = FindFirstFile (name, &wfd);
366 if (fh == INVALID_HANDLE_VALUE)
368 errno = ENOENT;
369 return -1;
371 FindClose (fh);
373 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
374 S_IFDIR : S_IFREG;
375 buf->st_nlink = 1;
376 buf->st_ino = 0;
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;
384 buf->st_size = wfd.nFileSizeLow;
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;
393 /* determine rwx permissions */
394 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
395 permission = S_IREAD;
396 else
397 permission = S_IREAD | S_IWRITE;
399 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
400 permission |= S_IEXEC;
401 else if (is_exec (name))
402 permission |= S_IEXEC;
404 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
406 return 0;
410 lstat (const char * path, struct stat * buf)
412 return stat (path, buf);