Merge from emacs-24; up to 2012-12-23T02:41:17Z!rgm@gnu.org
[bpt/emacs.git] / lib-src / ntlib.c
CommitLineData
95ed0025 1/* Utility and Unix shadow routines for GNU Emacs support programs on NT.
59a428eb 2
ab422c4d 3Copyright (C) 1994, 2001-2013 Free Software Foundation, Inc.
59a428eb
GM
4
5Author: Geoff Voelker (voelker@cs.washington.edu)
6Created: 10-8-94
95ed0025 7
3b7ad313
EN
8This file is part of GNU Emacs.
9
294981c7 10GNU Emacs is free software: you can redistribute it and/or modify
3b7ad313 11it under the terms of the GNU General Public License as published by
294981c7
GM
12the Free Software Foundation, either version 3 of the License, or
13(at your option) any later version.
3b7ad313
EN
14
15GNU Emacs is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
59a428eb 21along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
95ed0025
RS
22
23#include <windows.h>
24#include <stdlib.h>
25#include <stdio.h>
14f29224
GV
26#include <time.h>
27#include <direct.h>
10fea9c4
EZ
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <errno.h>
9c88f339 31#include <ctype.h>
62aba0d4 32#include <sys/timeb.h>
27067208 33#include <mbstring.h>
14f29224
GV
34
35#include "ntlib.h"
95ed0025 36
62aba0d4
FP
37struct timezone
38{
39 int tz_minuteswest; /* minutes west of Greenwich */
40 int tz_dsttime; /* type of dst correction */
41};
42
95ed0025
RS
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. */
48void
7c3320d8 49sleep (unsigned long seconds)
95ed0025
RS
50{
51 Sleep (seconds * 1000);
52}
53
54/* Get the current working directory. */
133319ab 55char *
95ed0025
RS
56getwd (char *dir)
57{
14f29224
GV
58 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
59 return dir;
60 return NULL;
95ed0025
RS
61}
62
63static HANDLE getppid_parent;
64static int getppid_ppid;
65
66int
7c3320d8 67getppid (void)
95ed0025
RS
68{
69 char *ppid;
70 DWORD result;
71
97e3c91b 72 ppid = getenv ("EM_PARENT_PROCESS_ID");
177c0ea7 73 if (!ppid)
95ed0025 74 {
7c3320d8 75 printf ("no pid.\n");
95ed0025 76 return 0;
177c0ea7
JB
77 }
78 else
95ed0025
RS
79 {
80 getppid_ppid = atoi (ppid);
81 }
82
177c0ea7 83 if (!getppid_parent)
95ed0025 84 {
7c3320d8 85 getppid_parent = OpenProcess (SYNCHRONIZE, FALSE, atoi (ppid));
177c0ea7 86 if (!getppid_parent)
95ed0025
RS
87 {
88 printf ("Failed to open handle to parent process: %d\n",
7c3320d8 89 GetLastError ());
95ed0025
RS
90 exit (1);
91 }
92 }
93
94 result = WaitForSingleObject (getppid_parent, 0);
177c0ea7 95 switch (result)
95ed0025
RS
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:
7c3320d8 105 printf ("Checking parent status failed: %d\n", GetLastError ());
95ed0025
RS
106 exit (1);
107 }
108}
14f29224
GV
109
110char *
7c3320d8 111getlogin (void)
14f29224
GV
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
121char *
122cuserid (char * s)
123{
124 char * name = getlogin ();
125 if (s)
126 return strcpy (s, name ? name : "");
127 return name;
128}
129
22749e9a 130unsigned
7c3320d8 131getuid (void)
14f29224
GV
132{
133 return 0;
134}
135
b372fceb 136unsigned
7c3320d8 137getgid (void)
b372fceb
JB
138{
139 return 0;
140}
141
142unsigned
7c3320d8 143getegid (void)
b372fceb
JB
144{
145 return 0;
146}
147
14f29224 148int
22749e9a 149setuid (unsigned uid)
14f29224
GV
150{
151 return 0;
152}
153
b372fceb 154int
f915f0f7 155setregid (unsigned rgid, unsigned gid)
b372fceb
JB
156{
157 return 0;
158}
159
14f29224 160struct passwd *
22749e9a 161getpwuid (unsigned uid)
14f29224
GV
162{
163 return NULL;
164}
165
166char *
167getpass (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
62aba0d4
FP
213/* This is needed because lib/gettime.c calls gettimeofday, which MSVC
214 doesn't have. Copied from w32.c. */
215void
216gettimeofday (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
14f29224 236int
22749e9a 237fchown (int fd, unsigned uid, unsigned gid)
14f29224
GV
238{
239 return 0;
240}
241
242/* Place a wrapper around the MSVC version of ctime. It returns NULL
177c0ea7 243 on network directories, so we handle that case here.
14f29224
GV
244 (Ulrich Leodolter, 1/11/95). */
245char *
246sys_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
252FILE *
7c3320d8 253sys_fopen (const char * path, const char * mode)
14f29224
GV
254{
255 return fopen (path, mode);
256}
257
258int
259sys_chdir (const char * path)
260{
261 return _chdir (path);
262}
ab5796a9 263
10fea9c4
EZ
264static FILETIME utc_base_ft;
265static long double utc_base;
266static int init = 0;
267
268static time_t
269convert_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
282static int
283is_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
59a428eb 294/* FIXME? This is in config.nt now - is this still needed? */
10fea9c4
EZ
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. */
299int
300stat (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
6dad7178
EZ
409int
410lstat (const char * path, struct stat * buf)
411{
412 return stat (path, buf);
413}
414