Mercurial > hg > xemacs-beta
comparison src/nt.c @ 771:943eaba38521
[xemacs-hg @ 2002-03-13 08:51:24 by ben]
The big ben-mule-21-5 check-in!
Various files were added and deleted. See CHANGES-ben-mule.
There are still some test suite failures. No crashes, though.
Many of the failures have to do with problems in the test suite itself
rather than in the actual code. I'll be addressing these in the next
day or so -- none of the test suite failures are at all critical.
Meanwhile I'll be trying to address the biggest issues -- i.e. build
or run failures, which will almost certainly happen on various platforms.
All comments should be sent to ben@xemacs.org -- use a Cc: if necessary
when sending to mailing lists. There will be pre- and post- tags,
something like
pre-ben-mule-21-5-merge-in, and
post-ben-mule-21-5-merge-in.
author | ben |
---|---|
date | Wed, 13 Mar 2002 08:54:06 +0000 |
parents | a307f9a2021d |
children | 2b676dc88c66 |
comparison
equal
deleted
inserted
replaced
770:336a418893b5 | 771:943eaba38521 |
---|---|
1 /* Utility and Unix shadow routines for XEmacs on MS Windows. | 1 /* Utility and Unix shadow routines under MS Windows (WIN32_NATIVE defined). |
2 Copyright (C) 1994, 1995 Free Software Foundation, Inc. | 2 Copyright (C) 1994, 1995 Free Software Foundation, Inc. |
3 Copyright (C) 2000, 2001, 2002 Ben Wing. | |
3 | 4 |
4 This file is part of XEmacs. | 5 This file is part of XEmacs. |
5 | 6 |
6 XEmacs is free software; you can redistribute it and/or modify it | 7 XEmacs is free software; you can redistribute it and/or modify it |
7 under the terms of the GNU General Public License as published by the | 8 under the terms of the GNU General Public License as published by the |
16 You should have received a copy of the GNU General Public License | 17 You should have received a copy of the GNU General Public License |
17 along with XEmacs; see the file COPYING. If not, write to the Free | 18 along with XEmacs; see the file COPYING. If not, write to the Free |
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | 19 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
19 02111-1307, USA. | 20 02111-1307, USA. |
20 | 21 |
21 | 22 */ |
22 Geoff Voelker (voelker@cs.washington.edu) 7-29-94 */ | 23 |
23 | 24 /* Authorship: |
24 /* Adapted for XEmacs by David Hobley <david@spook-le0.cia.com.au> */ | 25 |
25 /* Sync'ed with Emacs 19.34.6 by Marc Paquette <marcpa@cam.org> */ | 26 Geoff Voelker (voelker@cs.washington.edu) 7-29-94 |
27 Adapted for XEmacs by David Hobley <david@spook-le0.cia.com.au> | |
28 Sync'ed with Emacs 19.34.6 by Marc Paquette <marcpa@cam.org> | |
29 (Note: Sync messages from Marc Paquette may indicate | |
30 incomplete synching, so beware.) | |
31 Synched (completely!) with Emacs 20.6 by Ben Wing, 6-23-00. | |
32 Largely rewritten by Ben Wing for XEmacs Mule support. | |
33 Synched (completely!) with Emacs 21.1.103 by Ben Wing, 6-13-01. | |
34 */ | |
35 | |
36 /* This file Mule-ized by Ben Wing, 6-23-00. */ | |
26 | 37 |
27 #include <config.h> | 38 #include <config.h> |
28 #define getwd _getwd | |
29 #include "lisp.h" | 39 #include "lisp.h" |
30 #undef getwd | |
31 | 40 |
32 #include "buffer.h" | 41 #include "buffer.h" |
33 | 42 |
34 #include "systime.h" | 43 #include "systime.h" |
35 #include "syssignal.h" | 44 #include "syssignal.h" |
38 #include "syspwd.h" | 47 #include "syspwd.h" |
39 #include "sysdir.h" | 48 #include "sysdir.h" |
40 | 49 |
41 #include "syswindows.h" | 50 #include "syswindows.h" |
42 | 51 |
43 #include "nt.h" | 52 /* Control whether stat() attempts to determine file type and link count |
44 #include "ntheap.h" | 53 exactly, at the expense of slower operation. Since true hard links |
45 | 54 are supported on NTFS volumes, this is only relevant on NT. */ |
46 | 55 Lisp_Object Vmswindows_get_true_file_attributes; |
47 extern Lisp_Object Vmswindows_downcase_file_names; | 56 |
48 #if 0 | 57 /* Vmswindows_generate_fake_inodes; deleted */ |
49 extern Lisp_Object Vwin32_generate_fake_inodes; | 58 |
50 #endif | 59 Fixnum mswindows_fake_unix_uid; |
51 extern Lisp_Object Vmswindows_get_true_file_attributes; | |
52 | |
53 Fixnum nt_fake_unix_uid; | |
54 | |
55 static char startup_dir[ MAXPATHLEN ]; | |
56 | |
57 /* Get the current working directory. */ | |
58 char * | |
59 getwd (char *dir) | |
60 { | |
61 #if 0 | |
62 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0) | |
63 return dir; | |
64 return NULL; | |
65 #else | |
66 /* Emacs doesn't actually change directory itself, and we want to | |
67 force our real wd to be where emacs.exe is to avoid unnecessary | |
68 conflicts when trying to rename or delete directories. */ | |
69 strcpy (dir, startup_dir); | |
70 return dir; | |
71 #endif | |
72 } | |
73 | 60 |
74 /* Emulate getpwuid, getpwnam and others. */ | 61 /* Emulate getpwuid, getpwnam and others. */ |
75 | 62 |
76 #define PASSWD_FIELD_SIZE 256 | 63 static struct passwd the_passwd = |
77 | 64 { |
78 static char the_passwd_name[PASSWD_FIELD_SIZE]; | 65 "", |
79 static char the_passwd_passwd[PASSWD_FIELD_SIZE]; | 66 "", |
80 static char the_passwd_gecos[PASSWD_FIELD_SIZE]; | |
81 static char the_passwd_dir[PASSWD_FIELD_SIZE]; | |
82 static char the_passwd_shell[PASSWD_FIELD_SIZE]; | |
83 | |
84 static struct passwd the_passwd = | |
85 { | |
86 the_passwd_name, | |
87 the_passwd_passwd, | |
88 0, | 67 0, |
89 0, | 68 0, |
90 0, | 69 0, |
91 the_passwd_gecos, | 70 "", |
92 the_passwd_dir, | 71 "", |
93 the_passwd_shell, | 72 "", |
94 }; | 73 }; |
95 | 74 |
96 uid_t | 75 uid_t |
97 getuid (void) | 76 getuid (void) |
98 { | 77 { |
99 return nt_fake_unix_uid; | 78 return mswindows_fake_unix_uid; |
100 } | 79 } |
101 | 80 |
102 uid_t | 81 uid_t |
103 geteuid (void) | 82 geteuid (void) |
104 { | 83 { |
105 return nt_fake_unix_uid; | 84 /* Emacs 20.6 says: [[I could imagine arguing for checking to see |
85 whether the user is in the Administrators group and returning a | |
86 UID of 0 for that case, but I don't know how wise that would be | |
87 in the long run.]] */ | |
88 return mswindows_fake_unix_uid; | |
106 } | 89 } |
107 | 90 |
108 gid_t | 91 gid_t |
109 getgid (void) | 92 getgid (void) |
110 { | 93 { |
118 } | 101 } |
119 | 102 |
120 struct passwd * | 103 struct passwd * |
121 getpwuid (uid_t uid) | 104 getpwuid (uid_t uid) |
122 { | 105 { |
123 if (uid == nt_fake_unix_uid) | 106 if (uid == mswindows_fake_unix_uid) |
124 { | 107 { |
125 the_passwd.pw_gid = the_passwd.pw_uid = uid; | 108 the_passwd.pw_gid = the_passwd.pw_uid = uid; |
126 return &the_passwd; | 109 return &the_passwd; |
127 } | 110 } |
128 else | 111 else |
129 return NULL; | 112 return NULL; |
130 } | 113 } |
131 | 114 |
132 struct passwd * | 115 struct passwd * |
133 getpwnam (const char *name) | 116 getpwnam (const Intbyte *name) |
134 { | 117 { |
135 struct passwd *pw; | 118 struct passwd *pw; |
136 | 119 |
137 pw = getpwuid (getuid ()); | 120 pw = getpwuid (getuid ()); |
138 if (!pw) | 121 if (!pw) |
139 return pw; | 122 return pw; |
140 | 123 |
141 if (stricmp (name, pw->pw_name)) | 124 if (qxestrcasecmp_i18n (name, pw->pw_name)) |
142 return NULL; | 125 return NULL; |
143 | 126 |
144 return pw; | 127 return pw; |
145 } | 128 } |
146 | 129 |
147 void | 130 static void |
148 init_user_info (void) | 131 init_user_info (void) |
149 { | 132 { |
150 /* This code is pretty much of ad hoc nature. There is no unix-like | 133 /* This code is pretty much of ad hoc nature. There is no unix-like |
151 UIDs under Windows NT. There is no concept of root user, because | 134 UIDs under Windows NT. There is no concept of root user, because |
152 all security is ACL-based. Instead, let's use a simple variable, | 135 all security is ACL-based. Instead, let's use a simple variable, |
158 | 141 |
159 Use the relative portion of the identifier authority value from | 142 Use the relative portion of the identifier authority value from |
160 the user-sid as the user id value (same for group id using the | 143 the user-sid as the user id value (same for group id using the |
161 primary group sid from the process token). */ | 144 primary group sid from the process token). */ |
162 | 145 |
163 char user_sid[256], name[256], domain[256]; | 146 TOKEN_USER sidinfo; |
164 DWORD length = sizeof (name), dlength = sizeof (domain), trash; | 147 Extbyte name[256], domain[256]; |
165 HANDLE token = NULL; | 148 Charcount length = sizeof (name) / XETCHAR_SIZE; |
166 SID_NAME_USE user_type; | 149 Charcount dlength = sizeof (domain) / XETCHAR_SIZE; |
150 DWORD trash; | |
151 HANDLE token = NULL; | |
152 SID_NAME_USE user_type; | |
167 | 153 |
168 if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token) | 154 if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token) |
169 && GetTokenInformation (token, TokenUser, | 155 && GetTokenInformation (token, TokenUser, &sidinfo, sizeof (sidinfo), |
170 (PVOID) user_sid, sizeof (user_sid), &trash) | 156 &trash) |
171 && LookupAccountSid (NULL, *((PSID *) user_sid), name, &length, | 157 && qxeLookupAccountSid (NULL, sidinfo.User.Sid, name, &length, |
172 domain, &dlength, &user_type)) | 158 domain, &dlength, &user_type)) |
173 { | 159 { |
174 strcpy (the_passwd.pw_name, name); | 160 TSTR_TO_C_STRING_MALLOC (name, the_passwd.pw_name); |
175 /* Determine a reasonable uid value. */ | 161 /* Determine a reasonable uid value. */ |
176 if (stricmp ("administrator", name) == 0) | 162 if (qxestrcasecmp ("administrator", the_passwd.pw_name) == 0) |
177 { | 163 { |
178 the_passwd.pw_uid = 0; | 164 the_passwd.pw_uid = 0; |
179 the_passwd.pw_gid = 0; | 165 the_passwd.pw_gid = 0; |
180 } | 166 } |
181 else | 167 else |
182 { | 168 { |
183 SID_IDENTIFIER_AUTHORITY * pSIA; | 169 SID_IDENTIFIER_AUTHORITY * pSIA; |
184 | 170 TOKEN_PRIMARY_GROUP group; |
185 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid)); | 171 |
172 pSIA = GetSidIdentifierAuthority (sidinfo.User.Sid); | |
186 /* I believe the relative portion is the last 4 bytes (of 6) | 173 /* I believe the relative portion is the last 4 bytes (of 6) |
187 with msb first. */ | 174 with msb first. */ |
188 the_passwd.pw_uid = ((pSIA->Value[2] << 24) + | 175 the_passwd.pw_uid = ((pSIA->Value[2] << 24) + |
189 (pSIA->Value[3] << 16) + | 176 (pSIA->Value[3] << 16) + |
190 (pSIA->Value[4] << 8) + | 177 (pSIA->Value[4] << 8) + |
192 /* restrict to conventional uid range for normal users */ | 179 /* restrict to conventional uid range for normal users */ |
193 the_passwd.pw_uid = the_passwd.pw_uid % 60001; | 180 the_passwd.pw_uid = the_passwd.pw_uid % 60001; |
194 | 181 |
195 /* Get group id */ | 182 /* Get group id */ |
196 if (GetTokenInformation (token, TokenPrimaryGroup, | 183 if (GetTokenInformation (token, TokenPrimaryGroup, |
197 (PVOID) user_sid, sizeof (user_sid), &trash)) | 184 &group, sizeof (group), &trash)) |
198 { | 185 { |
199 SID_IDENTIFIER_AUTHORITY * pSIA; | 186 SID_IDENTIFIER_AUTHORITY * pSIA; |
200 | 187 |
201 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid)); | 188 pSIA = GetSidIdentifierAuthority (group.PrimaryGroup); |
202 the_passwd.pw_gid = ((pSIA->Value[2] << 24) + | 189 the_passwd.pw_gid = ((pSIA->Value[2] << 24) + |
203 (pSIA->Value[3] << 16) + | 190 (pSIA->Value[3] << 16) + |
204 (pSIA->Value[4] << 8) + | 191 (pSIA->Value[4] << 8) + |
205 (pSIA->Value[5] << 0)); | 192 (pSIA->Value[5] << 0)); |
206 /* I don't know if this is necessary, but for safety... */ | 193 /* I don't know if this is necessary, but for safety... */ |
210 the_passwd.pw_gid = the_passwd.pw_uid; | 197 the_passwd.pw_gid = the_passwd.pw_uid; |
211 } | 198 } |
212 } | 199 } |
213 /* If security calls are not supported (presumably because we | 200 /* If security calls are not supported (presumably because we |
214 are running under Windows 95), fallback to this. */ | 201 are running under Windows 95), fallback to this. */ |
215 else if (GetUserName (name, &length)) | 202 else if (qxeGetUserName (name, &length)) |
216 { | 203 { |
217 strcpy (the_passwd.pw_name, name); | 204 TSTR_TO_C_STRING_MALLOC (name, the_passwd.pw_name); |
218 if (stricmp ("administrator", name) == 0) | 205 if (qxestrcasecmp ("administrator", the_passwd.pw_name) == 0) |
219 the_passwd.pw_uid = 0; | 206 the_passwd.pw_uid = 0; |
220 else | 207 else |
221 the_passwd.pw_uid = 123; | 208 the_passwd.pw_uid = 123; |
222 the_passwd.pw_gid = the_passwd.pw_uid; | 209 the_passwd.pw_gid = the_passwd.pw_uid; |
223 } | 210 } |
224 else | 211 else |
225 { | 212 { |
226 strcpy (the_passwd.pw_name, "unknown"); | 213 the_passwd.pw_name = "unknown"; |
227 the_passwd.pw_uid = 123; | 214 the_passwd.pw_uid = 123; |
228 the_passwd.pw_gid = 123; | 215 the_passwd.pw_gid = 123; |
229 } | 216 } |
230 | 217 |
231 if (token) | 218 if (token) |
232 CloseHandle (token); | 219 CloseHandle (token); |
233 #else | 220 #else |
234 /* Obtain only logon id here, uid part is moved to getuid */ | 221 /* Obtain only logon id here, uid part is moved to getuid */ |
235 char name[256]; | 222 DWORD length = UNLEN + 1; |
236 DWORD length = sizeof (name); | 223 Extbyte name[MAX_XETCHAR_SIZE * (UNLEN + 1)]; |
237 if (GetUserName (name, &length)) | 224 if (qxeGetUserName (name, &length)) |
238 strcpy (the_passwd.pw_name, name); | 225 TSTR_TO_C_STRING_MALLOC (name, the_passwd.pw_name); |
239 else | 226 else |
240 strcpy (the_passwd.pw_name, "unknown"); | 227 the_passwd.pw_name = "unknown"; |
241 #endif | 228 #endif |
242 | 229 |
230 #if 0 | |
243 /* Ensure HOME and SHELL are defined. */ | 231 /* Ensure HOME and SHELL are defined. */ |
244 #if 0 | |
245 /* | 232 /* |
246 * With XEmacs, setting $HOME is deprecated. | 233 * With XEmacs, setting $HOME is deprecated. |
247 */ | 234 */ |
248 if (getenv ("HOME") == NULL) | 235 if (egetenv ("HOME") == NULL) |
249 putenv ("HOME=c:/"); | 236 eputenv ("HOME=c:/"); |
250 #endif | 237 #endif |
251 | 238 |
252 /* Set dir from environment variables. */ | 239 /* Set dir from environment variables. */ |
253 strcpy (the_passwd.pw_dir, (char *)get_home_directory()); | 240 the_passwd.pw_dir = (char *) qxestrdup (get_home_directory ()); |
254 /* We used to set pw_shell here, but the order is wrong (SHELL gets | 241 /* We used to set pw_shell here, but the order is wrong (SHELL gets |
255 init in callproc.c, called later in the init process) and pw_shell | 242 initted in callproc.c, called later in the init process) and pw_shell |
256 is not used anywhere. */ | 243 is not used anywhere. */ |
257 } | 244 } |
258 | 245 |
259 /* Normalize filename by converting all path separators to | |
260 the specified separator. Also conditionally convert upper | |
261 case path name components to lower case. */ | |
262 | |
263 static void | |
264 normalize_filename (char *fp, char path_sep) | |
265 { | |
266 char sep; | |
267 char *elem; | |
268 | |
269 /* Always lower-case drive letters a-z, even if the filesystem | |
270 preserves case in filenames. | |
271 This is so filenames can be compared by string comparison | |
272 functions that are case-sensitive. Even case-preserving filesystems | |
273 do not distinguish case in drive letters. */ | |
274 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z') | |
275 { | |
276 *fp += 'a' - 'A'; | |
277 fp += 2; | |
278 } | |
279 | |
280 if (NILP (Vmswindows_downcase_file_names)) | |
281 { | |
282 while (*fp) | |
283 { | |
284 if (*fp == '/' || *fp == '\\') | |
285 *fp = path_sep; | |
286 fp++; | |
287 } | |
288 return; | |
289 } | |
290 | |
291 sep = path_sep; /* convert to this path separator */ | |
292 elem = fp; /* start of current path element */ | |
293 | |
294 do { | |
295 if (*fp >= 'a' && *fp <= 'z') | |
296 elem = 0; /* don't convert this element */ | |
297 | |
298 if (*fp == 0 || *fp == ':') | |
299 { | |
300 sep = *fp; /* restore current separator (or 0) */ | |
301 *fp = '/'; /* after conversion of this element */ | |
302 } | |
303 | |
304 if (*fp == '/' || *fp == '\\') | |
305 { | |
306 if (elem && elem != fp) | |
307 { | |
308 *fp = 0; /* temporary end of string */ | |
309 _strlwr (elem); /* while we convert to lower case */ | |
310 } | |
311 *fp = sep; /* convert (or restore) path separator */ | |
312 elem = fp + 1; /* next element starts after separator */ | |
313 sep = path_sep; | |
314 } | |
315 } while (*fp++); | |
316 } | |
317 | |
318 /* Destructively turn backslashes into slashes. */ | |
319 void | |
320 dostounix_filename (char *p) | |
321 { | |
322 normalize_filename (p, '/'); | |
323 } | |
324 | |
325 /* Destructively turn slashes into backslashes. */ | |
326 void | |
327 unixtodos_filename (char *p) | |
328 { | |
329 normalize_filename (p, '\\'); | |
330 } | |
331 | |
332 /* Remove all CR's that are followed by a LF. | |
333 (From msdos.c...probably should figure out a way to share it, | |
334 although this code isn't going to ever change.) */ | |
335 int | |
336 crlf_to_lf (int n, unsigned char *buf, unsigned *lf_count) | |
337 { | |
338 unsigned char *np = buf; | |
339 unsigned char *startp = buf; | |
340 unsigned char *endp = buf + n; | |
341 | |
342 if (n == 0) | |
343 return n; | |
344 while (buf < endp - 1) | |
345 { | |
346 if (*buf == 0x0a) | |
347 (*lf_count)++; | |
348 if (*buf == 0x0d) | |
349 { | |
350 if (*(++buf) != 0x0a) | |
351 *np++ = 0x0d; | |
352 } | |
353 else | |
354 *np++ = *buf++; | |
355 } | |
356 if (buf < endp) | |
357 { | |
358 if (*buf == 0x0a) | |
359 (*lf_count)++; | |
360 *np++ = *buf++; | |
361 } | |
362 return np - startp; | |
363 } | |
364 | |
365 /* Parse the root part of file name, if present. Return length and | 246 /* Parse the root part of file name, if present. Return length and |
366 optionally store pointer to char after root. */ | 247 optionally store pointer to Intbyte after root. */ |
367 static int | 248 static Bytecount |
368 parse_root (char * name, char ** pPath) | 249 parse_root (Intbyte *name, Intbyte **pPath) |
369 { | 250 { |
370 char * start = name; | 251 Intbyte *start = name; |
371 | 252 |
372 if (name == NULL) | 253 if (name == NULL) |
373 return 0; | 254 return 0; |
374 | 255 |
375 /* find the root name of the volume if given */ | 256 /* find the root name of the volume if given */ |
388 { | 269 { |
389 if (IS_DIRECTORY_SEP (*name) && --slashes == 0) | 270 if (IS_DIRECTORY_SEP (*name) && --slashes == 0) |
390 break; | 271 break; |
391 name++; | 272 name++; |
392 } | 273 } |
393 while ( *name ); | 274 while (*name); |
394 if (IS_DIRECTORY_SEP (name[0])) | 275 if (IS_DIRECTORY_SEP (name[0])) |
395 name++; | 276 name++; |
396 } | 277 } |
397 | 278 |
398 if (pPath) | 279 if (pPath) |
400 | 281 |
401 return name - start; | 282 return name - start; |
402 } | 283 } |
403 | 284 |
404 /* Get long base name for name; name is assumed to be absolute. */ | 285 /* Get long base name for name; name is assumed to be absolute. */ |
405 static int | 286 static Intbyte * |
406 get_long_basename (char * name, char * buf, int size) | 287 get_long_basename (Intbyte *name) |
407 { | 288 { |
408 WIN32_FIND_DATA find_data; | 289 WIN32_FIND_DATAW find_data; |
409 HANDLE dir_handle; | 290 HANDLE dir_handle; |
410 int len = 0; | 291 Extbyte *nameext; |
411 #ifdef PIGSFLY | 292 |
412 char *p; | 293 /* must be valid filename, no wild cards or other invalid characters */ |
413 | 294 if (qxestrpbrk (name, "*?|<>\"")) |
414 /* If the last component of NAME has a wildcard character, | 295 return 0; |
415 return it as the basename. */ | 296 |
416 p = name + strlen (name); | 297 C_STRING_TO_TSTR (name, nameext); |
417 while (*p != '\\' && *p != ':' && p > name) p--; | 298 dir_handle = qxeFindFirstFile (nameext, &find_data); |
418 if (p > name) p++; | |
419 if (strchr (p, '*') || strchr (p, '?')) | |
420 { | |
421 if ((len = strlen (p)) < size) | |
422 memcpy (buf, p, len + 1); | |
423 else | |
424 len = 0; | |
425 return len; | |
426 } | |
427 #endif | |
428 | |
429 dir_handle = FindFirstFile (name, &find_data); | |
430 if (dir_handle != INVALID_HANDLE_VALUE) | 299 if (dir_handle != INVALID_HANDLE_VALUE) |
431 { | 300 { |
432 if ((len = strlen (find_data.cFileName)) < size) | 301 Intbyte *fileint; |
433 memcpy (buf, find_data.cFileName, len + 1); | 302 |
434 else | 303 TSTR_TO_C_STRING_MALLOC (find_data.cFileName, fileint); |
435 len = 0; | |
436 FindClose (dir_handle); | 304 FindClose (dir_handle); |
437 } | 305 return fileint; |
438 return len; | 306 } |
307 return 0; | |
439 } | 308 } |
440 | 309 |
441 /* Get long name for file, if possible (assumed to be absolute). */ | 310 /* Get long name for file, if possible (assumed to be absolute). */ |
442 BOOL | 311 Intbyte * |
443 win32_get_long_filename (char * name, char * buf, int size) | 312 mswindows_get_long_filename (Intbyte *name) |
444 { | 313 { |
445 char * o = buf; | 314 Intbyte *full = mswindows_canonicalize_filename (name); |
446 char * p; | 315 Intbyte *p; |
447 char * q; | 316 Intbyte *q; |
448 char full[ PATH_MAX ]; | 317 DECLARE_EISTRING (o); |
449 int len; | 318 Bytecount len; |
450 | |
451 len = strlen (name); | |
452 if (len >= PATH_MAX) | |
453 return FALSE; | |
454 | |
455 /* Use local copy for destructive modification. */ | |
456 memcpy (full, name, len+1); | |
457 unixtodos_filename (full); | |
458 | 319 |
459 /* Copy root part verbatim. */ | 320 /* Copy root part verbatim. */ |
460 len = parse_root (full, &p); | 321 len = parse_root (full, &p); |
461 memcpy (o, full, len); | 322 eicpy_raw (o, full, len); |
462 o += len; | 323 |
463 size -= len; | 324 while (p != NULL && *p) |
464 | 325 { |
465 do | 326 Intbyte *component; |
466 { | 327 |
467 q = p; | 328 q = p; |
468 p = strchr (q, '\\'); | 329 p = qxestrchr (q, '\\'); |
469 if (p) *p = '\0'; | 330 if (p) *p = '\0'; |
470 len = get_long_basename (full, o, size); | 331 component = get_long_basename (full); |
471 if (len > 0) | 332 if (component) |
472 { | 333 { |
473 o += len; | 334 eicat_rawz (o, component); |
474 size -= len; | |
475 if (p != NULL) | 335 if (p != NULL) |
476 { | 336 { |
477 *p++ = '\\'; | 337 *p++ = '\\'; |
478 if (size < 2) | 338 eicat_ch (o, '\\'); |
479 return FALSE; | |
480 *o++ = '\\'; | |
481 size--; | |
482 *o = '\0'; | |
483 } | 339 } |
340 xfree (component); | |
484 } | 341 } |
485 else | 342 else |
486 return FALSE; | 343 { |
487 } | 344 xfree (full); |
488 while (p != NULL && *p); | 345 return 0; |
489 | 346 } |
490 return TRUE; | 347 } |
491 } | 348 |
492 | 349 xfree (full); |
493 | 350 return eicpyout_malloc (o, 0); |
494 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */ | 351 } |
495 | 352 |
496 #if 0 /* #### We do not need those, do we? -kkm */ | 353 static int |
497 int | 354 is_unc_volume (const Intbyte *filename) |
498 unrequest_sigio (void) | 355 { |
499 { | 356 const Intbyte *ptr = filename; |
500 return 0; | 357 |
501 } | 358 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2]) |
502 | 359 return 0; |
503 int | 360 |
504 request_sigio (void) | 361 if (qxestrpbrk (ptr + 2, "*?|<>\"\\/")) |
505 { | 362 return 0; |
506 return 0; | 363 |
507 } | 364 return 1; |
508 #endif /* 0 */ | 365 } |
509 | 366 |
367 /* NOTE: Value returned is still in external format. Callers need to | |
368 convert. */ | |
510 #define REG_ROOT "SOFTWARE\\XEmacs\\XEmacs" | 369 #define REG_ROOT "SOFTWARE\\XEmacs\\XEmacs" |
511 | 370 |
512 LPBYTE | 371 static LPBYTE |
513 nt_get_resource (char *key, LPDWORD lpdwtype) | 372 nt_get_resource (Intbyte *key, LPDWORD lpdwtype) |
514 { | 373 { |
515 LPBYTE lpvalue; | 374 LPBYTE lpvalue; |
516 HKEY hrootkey = NULL; | 375 HKEY hrootkey = NULL; |
517 DWORD cbData; | 376 DWORD cbData; |
377 Extbyte *keyext; | |
378 | |
379 C_STRING_TO_TSTR (key, keyext); | |
518 | 380 |
519 /* Check both the current user and the local machine to see if | 381 /* Check both the current user and the local machine to see if |
520 we have any resources. */ | 382 we have any resources. */ |
521 | 383 |
522 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS) | 384 if (qxeRegOpenKeyEx (HKEY_CURRENT_USER, XETEXT (REG_ROOT), 0, KEY_READ, |
385 &hrootkey) == ERROR_SUCCESS) | |
523 { | 386 { |
524 lpvalue = NULL; | 387 lpvalue = NULL; |
525 | 388 |
526 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS | 389 if (qxeRegQueryValueEx (hrootkey, keyext, NULL, NULL, NULL, |
390 &cbData) == ERROR_SUCCESS | |
527 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL | 391 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL |
528 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS) | 392 && qxeRegQueryValueEx (hrootkey, keyext, NULL, lpdwtype, lpvalue, |
529 { | 393 &cbData) == ERROR_SUCCESS) |
530 return (lpvalue); | 394 return (lpvalue); |
531 } | |
532 | 395 |
533 if (lpvalue) xfree (lpvalue); | 396 if (lpvalue) xfree (lpvalue); |
534 | 397 |
535 RegCloseKey (hrootkey); | 398 RegCloseKey (hrootkey); |
536 } | 399 } |
537 | 400 |
538 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS) | 401 if (qxeRegOpenKeyEx (HKEY_LOCAL_MACHINE, XETEXT (REG_ROOT), 0, KEY_READ, |
402 &hrootkey) == ERROR_SUCCESS) | |
539 { | 403 { |
540 lpvalue = NULL; | 404 lpvalue = NULL; |
541 | 405 |
542 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS && | 406 if (qxeRegQueryValueEx (hrootkey, keyext, NULL, NULL, NULL, |
407 &cbData) == ERROR_SUCCESS && | |
543 (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL && | 408 (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL && |
544 RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS) | 409 qxeRegQueryValueEx (hrootkey, keyext, NULL, lpdwtype, lpvalue, |
545 { | 410 &cbData) == ERROR_SUCCESS) |
546 return (lpvalue); | 411 return (lpvalue); |
547 } | |
548 | 412 |
549 if (lpvalue) xfree (lpvalue); | 413 if (lpvalue) xfree (lpvalue); |
550 | 414 |
551 RegCloseKey (hrootkey); | 415 RegCloseKey (hrootkey); |
552 } | 416 } |
556 | 420 |
557 void | 421 void |
558 init_environment (void) | 422 init_environment (void) |
559 { | 423 { |
560 /* Check for environment variables and use registry if they don't exist */ | 424 /* Check for environment variables and use registry if they don't exist */ |
425 /* Emacs 20.6 sets default values for these; not necessary here because | |
426 we already supply them. (except SHELL, which is set in init_user_info().) | |
427 Emacs 20.6 messes with TMPDIR; not necessary here. */ | |
561 { | 428 { |
562 int i; | 429 int i; |
563 LPBYTE lpval; | 430 LPBYTE lpval; |
564 DWORD dwType; | 431 DWORD dwType; |
565 | 432 |
566 static char * env_vars[] = | 433 static Char_ASCII *env_vars[] = |
567 { | 434 { |
568 "HOME", | 435 "HOME", |
569 "emacs_dir", | |
570 "EMACSLOADPATH", | 436 "EMACSLOADPATH", |
571 "EMACSDEBUGPATHS", | 437 "EMACSDEBUGPATHS", |
572 "SHELL", | 438 "SHELL", |
573 "CMDPROXY", | 439 "CMDPROXY", |
574 "EMACSDATA", | 440 "EMACSDATA", |
575 "EMACSPATH", | 441 "EMACSPATH", |
576 "EMACSPACKAGEPATH", | 442 "EMACSPACKAGEPATH", |
577 "EMACSLOCKDIR", | 443 "EMACSLOCKMETHOD", |
578 "INFOPATH" | 444 "INFOPATH" |
579 }; | 445 }; |
580 #if defined (HEAP_IN_DATA) && !defined(PDUMP) | 446 #if defined (HEAP_IN_DATA) && !defined (PDUMP) |
581 cache_system_info (); | 447 cache_system_info (); |
582 #endif | 448 #endif |
449 | |
450 #if 0 /* FSF 21.1 */ | |
451 /* !!#### i think i already do the equivalent elsewhere. | |
452 delete when i'm sure i do. | |
453 (but maybe i should be playing with LANG when the user changes | |
454 the locale, so that subprocesses get it right.) */ | |
455 /* Get default locale info and use it for LANG. */ | |
456 if (GetLocaleInfo (LOCALE_USER_DEFAULT, | |
457 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP, | |
458 locale_name, sizeof (locale_name))) | |
459 { | |
460 for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++) | |
461 { | |
462 if (strcmp (env_vars[i].name, "LANG") == 0) | |
463 { | |
464 env_vars[i].def_value = locale_name; | |
465 break; | |
466 } | |
467 } | |
468 } | |
469 #endif /* 0 */ | |
470 | |
583 for (i = 0; i < countof (env_vars); i++) | 471 for (i = 0; i < countof (env_vars); i++) |
584 { | 472 { |
585 if (!getenv (env_vars[i]) && | 473 if (!egetenv (env_vars[i]) && |
586 (lpval = nt_get_resource (env_vars[i], &dwType)) != NULL) | 474 (lpval = nt_get_resource (env_vars[i], &dwType)) != NULL) |
587 { | 475 { |
588 if (dwType == REG_EXPAND_SZ) | 476 if (dwType == REG_EXPAND_SZ) |
589 { | 477 { |
590 char buf1[500], buf2[500]; | 478 Extbyte *buf = NULL; |
591 | 479 Intbyte *envval; |
592 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, 500); | 480 Charcount cch; |
593 _snprintf (buf2, 499, "%s=%s", env_vars[i], buf1); | 481 |
594 putenv (strdup (buf2)); | 482 cch = qxeExpandEnvironmentStrings ((Extbyte *) lpval, buf, 0); |
483 buf = (Extbyte *) alloca (cch * XETCHAR_SIZE); | |
484 qxeExpandEnvironmentStrings ((Extbyte *) lpval, buf, cch); | |
485 TSTR_TO_C_STRING (buf, envval); | |
486 eputenv (env_vars[i], envval); | |
595 } | 487 } |
596 else if (dwType == REG_SZ) | 488 else if (dwType == REG_SZ) |
597 { | 489 { |
598 char buf[500]; | 490 Intbyte *envval; |
599 | 491 |
600 _snprintf (buf, 499, "%s=%s", env_vars[i], lpval); | 492 TSTR_TO_C_STRING (lpval, envval); |
601 putenv (strdup (buf)); | 493 eputenv (env_vars[i], envval); |
602 } | 494 } |
603 | 495 |
604 xfree (lpval); | 496 xfree (lpval); |
605 } | 497 } |
606 } | 498 } |
609 /* Another special case: on NT, the PATH variable is actually named | 501 /* Another special case: on NT, the PATH variable is actually named |
610 "Path" although cmd.exe (perhaps NT itself) arranges for | 502 "Path" although cmd.exe (perhaps NT itself) arranges for |
611 environment variable lookup and setting to be case insensitive. | 503 environment variable lookup and setting to be case insensitive. |
612 However, Emacs assumes a fully case sensitive environment, so we | 504 However, Emacs assumes a fully case sensitive environment, so we |
613 need to change "Path" to "PATH" to match the expectations of | 505 need to change "Path" to "PATH" to match the expectations of |
614 various elisp packages. We do this by the sneaky method of | 506 various elisp packages. |
615 modifying the string in the C runtime environ entry. | |
616 | 507 |
617 The same applies to COMSPEC. */ | 508 The same applies to COMSPEC. */ |
618 { | 509 { |
619 char ** envp; | 510 Lisp_Object tail; |
620 | 511 |
621 for (envp = environ; *envp; envp++) | 512 EXTERNAL_LIST_LOOP (tail, Vprocess_environment) |
622 if (_strnicmp (*envp, "PATH=", 5) == 0) | 513 { |
623 memcpy (*envp, "PATH=", 5); | 514 Lisp_Object str = XCAR (tail); |
624 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0) | 515 if (STRINGP (str)) |
625 memcpy (*envp, "COMSPEC=", 8); | 516 { |
517 Intbyte *dat = XSTRING_DATA (str); | |
518 if (qxestrncasecmp (dat, "PATH=", 5) == 0) | |
519 memcpy (dat, "PATH=", 5); | |
520 else if (qxestrncasecmp (dat, "COMSPEC=", 8) == 0) | |
521 memcpy (dat, "COMSPEC=", 8); | |
522 } | |
523 } | |
626 } | 524 } |
627 | 525 |
628 /* Remember the initial working directory for getwd, then make the | |
629 real wd be the location of emacs.exe to avoid conflicts when | |
630 renaming or deleting directories. (We also don't call chdir when | |
631 running subprocesses for the same reason.) */ | |
632 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir)) | |
633 abort (); | |
634 | |
635 { | |
636 char *p; | |
637 char modname[PATH_MAX]; | |
638 | |
639 if (!GetModuleFileName (NULL, modname, PATH_MAX)) | |
640 abort (); | |
641 if ((p = strrchr (modname, '\\')) == NULL) | |
642 abort (); | |
643 *p = 0; | |
644 | |
645 SetCurrentDirectory (modname); | |
646 } | |
647 | |
648 init_user_info (); | 526 init_user_info (); |
649 } | 527 } |
650 | 528 |
529 /* Emacs 20.6 contains a routine get_emacs_configuration() here to set | |
530 EMACS_CONFIGURATION. */ | |
651 #ifndef HAVE_X_WINDOWS | 531 #ifndef HAVE_X_WINDOWS |
652 /* X11R6 on NT provides the single parameter version of this command. */ | 532 /* X11R6 on NT provides the single parameter version of this command. */ |
653 | 533 |
654 #include <sys/timeb.h> | 534 #include <sys/timeb.h> |
655 | 535 |
669 } | 549 } |
670 } | 550 } |
671 | 551 |
672 #endif /* HAVE_X_WINDOWS */ | 552 #endif /* HAVE_X_WINDOWS */ |
673 | 553 |
554 | |
674 /* ------------------------------------------------------------------------- */ | 555 /* ------------------------------------------------------------------------- */ |
675 /* IO support and wrapper functions for Win32 API. */ | 556 /* IO support and wrapper functions for Win32 API. */ |
676 /* ------------------------------------------------------------------------- */ | 557 /* ------------------------------------------------------------------------- */ |
677 | 558 |
678 /* Place a wrapper around the MSVC version of ctime. It returns NULL | 559 typedef struct volume_info_data |
679 on network directories, so we handle that case here. | 560 { |
680 (Ulrich Leodolter, 1/11/95). */ | 561 struct volume_info_data *next; |
681 char * | |
682 sys_ctime (const time_t *t) | |
683 { | |
684 char *str = (char *) ctime (t); | |
685 return (str ? str : "Sun Jan 01 00:00:00 1970"); | |
686 } | |
687 | |
688 /* Emulate sleep...we could have done this with a define, but that | |
689 would necessitate including windows.h in the files that used it. | |
690 This is much easier. */ | |
691 | |
692 #ifndef HAVE_X_WINDOWS | |
693 void | |
694 sys_sleep (int seconds) | |
695 { | |
696 Sleep (seconds * 1000); | |
697 } | |
698 #endif | |
699 | |
700 /* #### This is an evil dirty hack. We must get rid of it. | |
701 Word "munging" is not in XEmacs lexicon. - kkm */ | |
702 | |
703 /* Internal MSVC data and functions for low-level descriptor munging */ | |
704 #if (_MSC_VER == 900) | |
705 extern char _osfile[]; | |
706 #endif | |
707 extern int __cdecl _set_osfhnd (int fd, long h); | |
708 extern int __cdecl _free_osfhnd (int fd); | |
709 | |
710 /* parallel array of private info on file handles */ | |
711 filedesc fd_info [ MAXDESC ]; | |
712 | |
713 typedef struct volume_info_data { | |
714 struct volume_info_data * next; | |
715 | 562 |
716 /* time when info was obtained */ | 563 /* time when info was obtained */ |
717 DWORD timestamp; | 564 DWORD timestamp; |
718 | 565 |
719 /* actual volume info */ | 566 /* actual volume info */ |
720 char * root_dir; | 567 Intbyte *root_dir; |
721 DWORD serialnum; | 568 DWORD serialnum; |
722 DWORD maxcomp; | 569 DWORD maxcomp; |
723 DWORD flags; | 570 DWORD flags; |
724 char * name; | 571 Intbyte *name; |
725 char * type; | 572 Intbyte *type; |
726 } volume_info_data; | 573 } volume_info_data; |
727 | 574 |
728 /* Global referenced by various functions. */ | 575 /* Global referenced by various functions. */ |
729 static volume_info_data volume_info; | 576 static volume_info_data volume_info; |
730 | 577 |
744 | 591 |
745 /* Simple linked list with linear search is sufficient. */ | 592 /* Simple linked list with linear search is sufficient. */ |
746 static volume_info_data *volume_cache = NULL; | 593 static volume_info_data *volume_cache = NULL; |
747 | 594 |
748 static volume_info_data * | 595 static volume_info_data * |
749 lookup_volume_info (char * root_dir) | 596 lookup_volume_info (Intbyte *root_dir) |
750 { | 597 { |
751 volume_info_data * info; | 598 volume_info_data *info; |
752 | 599 |
753 for (info = volume_cache; info; info = info->next) | 600 for (info = volume_cache; info; info = info->next) |
754 if (stricmp (info->root_dir, root_dir) == 0) | 601 if (qxestrcasecmp_i18n (info->root_dir, root_dir) == 0) |
755 break; | 602 break; |
756 return info; | 603 return info; |
757 } | 604 } |
758 | 605 |
759 static void | 606 static void |
760 add_volume_info (char * root_dir, volume_info_data * info) | 607 add_volume_info (Intbyte *root_dir, volume_info_data *info) |
761 { | 608 { |
762 info->root_dir = xstrdup (root_dir); | 609 info->root_dir = qxestrdup (root_dir); |
763 info->next = volume_cache; | 610 info->next = volume_cache; |
764 volume_cache = info; | 611 volume_cache = info; |
765 } | 612 } |
766 | 613 |
767 | 614 |
768 /* Wrapper for GetVolumeInformation, which uses caching to avoid | 615 /* Wrapper for GetVolumeInformation, which uses caching to avoid |
769 performance penalty (~2ms on 486 for local drives, 7.5ms for local | 616 performance penalty (~2ms on 486 for local drives, 7.5ms for local |
770 cdrom drive, ~5-10ms or more for remote drives on LAN). */ | 617 cdrom drive, ~5-10ms or more for remote drives on LAN). */ |
771 volume_info_data * | 618 static volume_info_data * |
772 GetCachedVolumeInformation (char * root_dir) | 619 get_cached_volume_information (Intbyte *root_dir) |
773 { | 620 { |
774 volume_info_data * info; | 621 volume_info_data *info; |
775 char default_root[ PATH_MAX ]; | 622 Intbyte *default_root; |
776 | 623 |
777 /* NULL for root_dir means use root from current directory. */ | 624 /* NULL for root_dir means use root from current directory. */ |
778 if (root_dir == NULL) | 625 if (root_dir == NULL) |
779 { | 626 { |
780 if (GetCurrentDirectory (PATH_MAX, default_root) == 0) | 627 Charcount nchars = qxeGetCurrentDirectory (0, NULL); |
628 Extbyte *rootext; | |
629 | |
630 if (!nchars) | |
781 return NULL; | 631 return NULL; |
632 rootext = alloca_extbytes (nchars * XETCHAR_SIZE); | |
633 if (!qxeGetCurrentDirectory (nchars, rootext)) | |
634 return NULL; | |
635 TSTR_TO_C_STRING (rootext, default_root); | |
782 parse_root (default_root, &root_dir); | 636 parse_root (default_root, &root_dir); |
783 *root_dir = 0; | 637 *root_dir = 0; |
784 root_dir = default_root; | 638 root_dir = default_root; |
785 } | 639 } |
786 | 640 |
801 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW, | 655 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW, |
802 GetDriveType is about the only call of this type which does not | 656 GetDriveType is about the only call of this type which does not |
803 involve network access, and so is extremely quick). */ | 657 involve network access, and so is extremely quick). */ |
804 | 658 |
805 /* Map drive letter to UNC if remote. */ | 659 /* Map drive letter to UNC if remote. */ |
806 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] ) | 660 if (isalpha (root_dir[0]) && !fixed [DRIVE_INDEX (root_dir[0])]) |
807 { | 661 { |
808 char remote_name[ 256 ]; | 662 Extbyte remote_name[256 * XETCHAR_SIZE]; |
809 char drive[3] = { root_dir[0], ':' }; | 663 Intbyte drive[3] = { root_dir[0], ':' }; |
810 | 664 Extbyte *driveext; |
811 if (WNetGetConnection (drive, remote_name, sizeof (remote_name)) | 665 |
666 C_STRING_TO_TSTR (drive, driveext); | |
667 if (qxeWNetGetConnection (driveext, remote_name, | |
668 sizeof (remote_name) / XETCHAR_SIZE) | |
812 == NO_ERROR) | 669 == NO_ERROR) |
813 /* do something */ ; | 670 /* do something */ ; |
814 } | 671 } |
815 #endif | 672 #endif |
816 | 673 |
817 info = lookup_volume_info (root_dir); | 674 info = lookup_volume_info (root_dir); |
818 | 675 |
819 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info)) | 676 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info)) |
820 { | 677 { |
821 char name[ 256 ]; | 678 Extbyte name[256 * MAX_XETCHAR_SIZE]; |
822 DWORD serialnum; | 679 DWORD serialnum; |
823 DWORD maxcomp; | 680 DWORD maxcomp; |
824 DWORD flags; | 681 DWORD flags; |
825 char type[ 256 ]; | 682 Extbyte type[256 * MAX_XETCHAR_SIZE]; |
826 | 683 |
827 /* Info is not cached, or is stale. */ | 684 /* Info is not cached, or is stale. */ |
828 if (!GetVolumeInformation (root_dir, | 685 if (!qxeGetVolumeInformation (root_dir, |
829 name, sizeof (name), | 686 name, sizeof (name) / XETCHAR_SIZE, |
830 &serialnum, | 687 &serialnum, |
831 &maxcomp, | 688 &maxcomp, |
832 &flags, | 689 &flags, |
833 type, sizeof (type))) | 690 type, sizeof (type) / XETCHAR_SIZE)) |
834 return NULL; | 691 return NULL; |
835 | 692 |
836 /* Cache the volume information for future use, overwriting existing | 693 /* Cache the volume information for future use, overwriting existing |
837 entry if present. */ | 694 entry if present. */ |
838 if (info == NULL) | 695 if (info == NULL) |
839 { | 696 { |
840 info = (volume_info_data *) xmalloc (sizeof (volume_info_data)); | 697 info = (volume_info_data *) xmalloc (sizeof (volume_info_data)); |
841 add_volume_info (root_dir, info); | 698 add_volume_info (root_dir, info); |
842 } | 699 } |
843 else | 700 else |
844 { | 701 { |
845 free (info->name); | 702 xfree (info->name); |
846 free (info->type); | 703 xfree (info->type); |
847 } | 704 } |
848 | 705 |
849 info->name = xstrdup (name); | 706 TSTR_TO_C_STRING_MALLOC (name, info->name); |
850 info->serialnum = serialnum; | 707 info->serialnum = serialnum; |
851 info->maxcomp = maxcomp; | 708 info->maxcomp = maxcomp; |
852 info->flags = flags; | 709 info->flags = flags; |
853 info->type = xstrdup (type); | 710 TSTR_TO_C_STRING_MALLOC (type, info->type); |
854 info->timestamp = GetTickCount (); | 711 info->timestamp = GetTickCount (); |
855 } | 712 } |
856 | 713 |
857 return info; | 714 return info; |
858 } | 715 } |
859 | 716 |
860 /* Get information on the volume where name is held; set path pointer to | 717 /* Get information on the volume where name is held; set path pointer to |
861 start of pathname in name (past UNC header\volume header if present). */ | 718 start of pathname in name (past UNC header\volume header if present). */ |
862 int | 719 static int |
863 get_volume_info (const char * name, const char ** pPath) | 720 get_volume_info (const Intbyte *name, const Intbyte **pPath) |
864 { | 721 { |
865 char temp[PATH_MAX]; | 722 /* We probably only need a couple of bytes, but let's be generous in |
866 char *rootname = NULL; /* default to current volume */ | 723 case this function gets changed */ |
867 volume_info_data * info; | 724 Intbyte *temp = alloca_array (Intbyte, qxestrlen (name) + 10); |
725 Intbyte *rootname = NULL; /* default to current volume */ | |
726 volume_info_data *info; | |
868 | 727 |
869 if (name == NULL) | 728 if (name == NULL) |
870 return FALSE; | 729 return FALSE; |
871 | 730 |
872 /* find the root name of the volume if given */ | 731 /* find the root name of the volume if given */ |
878 temp[2] = '\\'; | 737 temp[2] = '\\'; |
879 temp[3] = 0; | 738 temp[3] = 0; |
880 } | 739 } |
881 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1])) | 740 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1])) |
882 { | 741 { |
883 char *str = temp; | 742 Intbyte *str = temp; |
884 int slashes = 4; | 743 int slashes = 4; |
885 rootname = temp; | 744 rootname = temp; |
886 do | 745 do |
887 { | 746 { |
888 if (IS_DIRECTORY_SEP (*name) && --slashes == 0) | 747 if (IS_DIRECTORY_SEP (*name) && --slashes == 0) |
889 break; | 748 break; |
890 *str++ = *name++; | 749 *str++ = *name++; |
891 } | 750 } |
892 while ( *name ); | 751 while (*name); |
893 | 752 |
894 *str++ = '\\'; | 753 *str++ = '\\'; |
895 *str = 0; | 754 *str = 0; |
896 } | 755 } |
897 | 756 |
898 if (pPath) | 757 if (pPath) |
899 *pPath = name; | 758 *pPath = name; |
900 | 759 |
901 info = GetCachedVolumeInformation (rootname); | 760 info = get_cached_volume_information (rootname); |
902 if (info != NULL) | 761 if (info != NULL) |
903 { | 762 { |
904 /* Set global referenced by other functions. */ | 763 /* Set global referenced by other functions. */ |
905 volume_info = *info; | 764 volume_info = *info; |
906 return TRUE; | 765 return TRUE; |
907 } | 766 } |
908 return FALSE; | 767 return FALSE; |
909 } | 768 } |
910 | 769 |
911 /* Determine if volume is FAT format (ie. only supports short 8.3 | 770 /* XEmacs: Everything referring to map_win32_filename() aka map_w32_filename() |
912 names); also set path pointer to start of pathname in name. */ | 771 removed; it was only for NT 3.1, which we hereby do not support. (NT 3.5 |
913 int | 772 predates Windows 95!) */ |
914 is_fat_volume (const char * name, const char ** pPath) | 773 |
915 { | 774 static int |
916 if (get_volume_info (name, pPath)) | 775 is_exec (const Intbyte *name) |
917 return (volume_info.maxcomp == 12); | 776 { |
918 return FALSE; | 777 Intbyte *p = qxestrrchr (name, '.'); |
919 } | 778 return (p != NULL && (qxestrcasecmp (p, ".exe") == 0 || |
920 | 779 qxestrcasecmp (p, ".com") == 0 || |
921 /* Map filename to a legal 8.3 name if necessary. */ | 780 qxestrcasecmp (p, ".bat") == 0 || |
922 const char * | 781 qxestrcasecmp (p, ".cmd") == 0)); |
923 map_win32_filename (const char * name, const char ** pPath) | 782 } |
924 { | |
925 static char shortname[PATH_MAX]; | |
926 char * str = shortname; | |
927 char c; | |
928 const char * path; | |
929 const char * save_name = name; | |
930 | |
931 if (is_fat_volume (name, &path)) /* truncate to 8.3 */ | |
932 { | |
933 REGISTER int left = 8; /* maximum number of chars in part */ | |
934 REGISTER int extn = 0; /* extension added? */ | |
935 REGISTER int dots = 2; /* maximum number of dots allowed */ | |
936 | |
937 while (name < path) | |
938 *str++ = *name++; /* skip past UNC header */ | |
939 | |
940 while ((c = *name++)) | |
941 { | |
942 switch ( c ) | |
943 { | |
944 case '\\': | |
945 case '/': | |
946 *str++ = '\\'; | |
947 extn = 0; /* reset extension flags */ | |
948 dots = 2; /* max 2 dots */ | |
949 left = 8; /* max length 8 for main part */ | |
950 break; | |
951 case ':': | |
952 *str++ = ':'; | |
953 extn = 0; /* reset extension flags */ | |
954 dots = 2; /* max 2 dots */ | |
955 left = 8; /* max length 8 for main part */ | |
956 break; | |
957 case '.': | |
958 if ( dots ) | |
959 { | |
960 /* Convert path components of the form .xxx to _xxx, | |
961 but leave . and .. as they are. This allows .emacs | |
962 to be read as _emacs, for example. */ | |
963 | |
964 if (! *name || | |
965 *name == '.' || | |
966 IS_DIRECTORY_SEP (*name)) | |
967 { | |
968 *str++ = '.'; | |
969 dots--; | |
970 } | |
971 else | |
972 { | |
973 *str++ = '_'; | |
974 left--; | |
975 dots = 0; | |
976 } | |
977 } | |
978 else if ( !extn ) | |
979 { | |
980 *str++ = '.'; | |
981 extn = 1; /* we've got an extension */ | |
982 left = 3; /* 3 chars in extension */ | |
983 } | |
984 else | |
985 { | |
986 /* any embedded dots after the first are converted to _ */ | |
987 *str++ = '_'; | |
988 } | |
989 break; | |
990 case '~': | |
991 case '#': /* don't lose these, they're important */ | |
992 if ( ! left ) | |
993 str[-1] = c; /* replace last character of part */ | |
994 /* FALLTHRU */ | |
995 default: | |
996 if ( left ) | |
997 { | |
998 *str++ = tolower (c); /* map to lower case (looks nicer) */ | |
999 left--; | |
1000 dots = 0; /* started a path component */ | |
1001 } | |
1002 break; | |
1003 } | |
1004 } | |
1005 *str = '\0'; | |
1006 } | |
1007 else | |
1008 { | |
1009 strcpy (shortname, name); | |
1010 unixtodos_filename (shortname); | |
1011 } | |
1012 | |
1013 if (pPath) | |
1014 *pPath = shortname + (path - save_name); | |
1015 | |
1016 return shortname; | |
1017 } | |
1018 | |
1019 | 783 |
1020 /* Emulate the Unix directory procedures opendir, closedir, | 784 /* Emulate the Unix directory procedures opendir, closedir, |
1021 and readdir. We can't use the procedures supplied in sysdep.c, | 785 and readdir. We can't use the procedures supplied in sysdep.c, |
1022 so we provide them here. */ | 786 so we provide them here. */ |
1023 | 787 |
1024 struct direct dir_static; /* simulated directory contents */ | 788 struct direct dir_static; /* simulated directory contents */ |
1025 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE; | 789 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE; |
1026 static int dir_is_fat; | 790 /* dir_is_fat deleted */ |
1027 static char dir_pathname[MAXPATHLEN+1]; | 791 static Intbyte *dir_pathname; |
1028 static WIN32_FIND_DATA dir_find_data; | 792 static WIN32_FIND_DATAW dir_find_data; |
793 | |
794 /* Support shares on a network resource as subdirectories of a read-only | |
795 root directory. */ | |
796 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE; | |
797 static HANDLE open_unc_volume (const Intbyte *); | |
798 static Intbyte *read_unc_volume (HANDLE); | |
799 static int close_unc_volume (HANDLE); | |
1029 | 800 |
1030 DIR * | 801 DIR * |
1031 opendir (const char *filename) | 802 mswindows_opendir (const Intbyte *filename) |
1032 { | 803 { |
1033 DIR *dirp; | 804 DIR *dirp; |
1034 | 805 |
1035 /* Opening is done by FindFirstFile. However, a read is inherent to | 806 /* Opening is done by FindFirstFile. However, a read is inherent to |
1036 this operation, so we defer the open until read time. */ | 807 this operation, so we defer the open until read time. */ |
1037 | 808 |
1038 if (!(dirp = xnew_and_zero(DIR))) | |
1039 return NULL; | |
1040 if (dir_find_handle != INVALID_HANDLE_VALUE) | 809 if (dir_find_handle != INVALID_HANDLE_VALUE) |
1041 return NULL; | 810 return NULL; |
1042 | 811 if (wnet_enum_handle != INVALID_HANDLE_VALUE) |
1043 dirp->dd_fd = 0; | 812 return NULL; |
1044 dirp->dd_loc = 0; | 813 |
1045 dirp->dd_size = 0; | 814 if (is_unc_volume (filename)) |
1046 | 815 { |
1047 strncpy (dir_pathname, map_win32_filename (filename, NULL), MAXPATHLEN); | 816 wnet_enum_handle = open_unc_volume (filename); |
1048 dir_pathname[MAXPATHLEN] = '\0'; | 817 if (wnet_enum_handle == INVALID_HANDLE_VALUE) |
1049 dir_is_fat = is_fat_volume (filename, NULL); | 818 return NULL; |
819 } | |
820 | |
821 if (!(dirp = xnew_and_zero (DIR))) | |
822 return NULL; | |
823 | |
824 if (dir_pathname) | |
825 xfree (dir_pathname); | |
826 dir_pathname = qxestrdup (filename); | |
1050 | 827 |
1051 return dirp; | 828 return dirp; |
1052 } | 829 } |
1053 | 830 |
1054 int | 831 int |
1055 closedir (DIR *dirp) | 832 mswindows_closedir (DIR *dirp) |
1056 { | 833 { |
1057 BOOL retval; | 834 int retval; |
1058 | 835 |
1059 /* If we have a find-handle open, close it. */ | 836 /* If we have a find-handle open, close it. */ |
1060 if (dir_find_handle != INVALID_HANDLE_VALUE) | 837 if (dir_find_handle != INVALID_HANDLE_VALUE) |
1061 { | 838 { |
1062 retval = FindClose (dir_find_handle); | 839 retval = FindClose (dir_find_handle) ? 0 : -1; |
1063 dir_find_handle = INVALID_HANDLE_VALUE; | 840 dir_find_handle = INVALID_HANDLE_VALUE; |
1064 } | 841 } |
842 else if (wnet_enum_handle != INVALID_HANDLE_VALUE) | |
843 { | |
844 retval = close_unc_volume (wnet_enum_handle); | |
845 wnet_enum_handle = INVALID_HANDLE_VALUE; | |
846 } | |
1065 xfree (dirp); | 847 xfree (dirp); |
1066 if (retval) | 848 |
1067 return 0; | 849 return retval; |
1068 else | |
1069 return -1; | |
1070 } | 850 } |
1071 | 851 |
1072 struct direct * | 852 struct direct * |
1073 readdir (DIR *dirp) | 853 mswindows_readdir (DIR *dirp) |
1074 { | 854 { |
855 Intbyte *val; | |
856 int need_to_free = 0; | |
857 | |
858 if (wnet_enum_handle != INVALID_HANDLE_VALUE) | |
859 { | |
860 if (!(val = read_unc_volume (wnet_enum_handle))) | |
861 return NULL; | |
862 need_to_free = 1; | |
863 } | |
1075 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */ | 864 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */ |
1076 if (dir_find_handle == INVALID_HANDLE_VALUE) | 865 else if (dir_find_handle == INVALID_HANDLE_VALUE) |
1077 { | 866 { |
1078 char filename[MAXNAMLEN + 3]; | 867 DECLARE_EISTRING (filename); |
1079 int ln; | 868 Emchar lastch; |
1080 | 869 |
1081 strcpy (filename, dir_pathname); | 870 eicpy_rawz (filename, dir_pathname); |
1082 ln = strlen (filename) - 1; | 871 lastch = eigetch_char (filename, eicharlen (filename) - 1); |
1083 if (!IS_DIRECTORY_SEP (filename[ln])) | 872 if (!IS_DIRECTORY_SEP (lastch)) |
1084 strcat (filename, "\\"); | 873 eicat_ch (filename, '\\'); |
1085 strcat (filename, "*"); | 874 eicat_ch (filename, '*'); |
1086 | 875 eito_external (filename, Qmswindows_tstr); |
1087 dir_find_handle = FindFirstFile (filename, &dir_find_data); | 876 |
877 dir_find_handle = qxeFindFirstFile (eiextdata (filename), | |
878 &dir_find_data); | |
1088 | 879 |
1089 if (dir_find_handle == INVALID_HANDLE_VALUE) | 880 if (dir_find_handle == INVALID_HANDLE_VALUE) |
1090 return NULL; | 881 return NULL; |
882 TSTR_TO_C_STRING (dir_find_data.cFileName, val); | |
1091 } | 883 } |
1092 else | 884 else |
1093 { | 885 { |
1094 if (!FindNextFile (dir_find_handle, &dir_find_data)) | 886 if (!qxeFindNextFile (dir_find_handle, &dir_find_data)) |
1095 return NULL; | 887 return NULL; |
888 TSTR_TO_C_STRING (dir_find_data.cFileName, val); | |
1096 } | 889 } |
1097 | 890 |
1098 /* Emacs never uses this value, so don't bother making it match | 891 /* XEmacs never uses this value, so don't bother making it match |
1099 value returned by xemacs_stat(). */ | 892 value returned by qxe_stat(). */ |
1100 dir_static.d_ino = 1; | 893 dir_static.d_ino = 1; |
1101 | 894 |
1102 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 + | 895 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 + |
1103 dir_static.d_namlen - dir_static.d_namlen % 4; | 896 dir_static.d_namlen - dir_static.d_namlen % 4; |
1104 | 897 |
1105 dir_static.d_namlen = strlen (dir_find_data.cFileName); | 898 { |
1106 strcpy (dir_static.d_name, dir_find_data.cFileName); | 899 DECLARE_EISTRING (found); |
1107 if (dir_is_fat) | 900 Bytecount namlen; |
1108 _strlwr (dir_static.d_name); | 901 |
1109 else if (!NILP (Vmswindows_downcase_file_names)) | 902 eicpy_rawz (found, val); |
1110 { | 903 if (need_to_free) |
1111 REGISTER char *p; | 904 xfree (val); |
1112 for (p = dir_static.d_name; *p; p++) | 905 |
1113 if (*p >= 'a' && *p <= 'z') | 906 if (!NILP (Vmswindows_downcase_file_names)) |
1114 break; | 907 eilwr (found); |
1115 if (!*p) | 908 |
1116 _strlwr (dir_static.d_name); | 909 namlen = min (eilen (found), sizeof (dir_static.d_name) - 1); |
1117 } | 910 strncpy (dir_static.d_name, (char *) eidata (found), namlen); |
1118 | 911 dir_static.d_name[namlen] = '\0'; |
912 dir_static.d_namlen = (unsigned short) namlen; | |
913 } | |
914 | |
1119 return &dir_static; | 915 return &dir_static; |
1120 } | 916 } |
1121 | 917 |
1122 #if 0 | 918 static HANDLE |
1123 /* #### Have to check if all that sad story about '95 is true - kkm */ | 919 open_unc_volume (const Intbyte *path) |
920 { | |
921 NETRESOURCEW nr; | |
922 HANDLE henum; | |
923 int result; | |
924 | |
925 nr.dwScope = RESOURCE_GLOBALNET; | |
926 nr.dwType = RESOURCETYPE_DISK; | |
927 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER; | |
928 nr.dwUsage = RESOURCEUSAGE_CONTAINER; | |
929 nr.lpLocalName = NULL; | |
930 C_STRING_TO_TSTR (path, nr.lpRemoteName); | |
931 nr.lpComment = NULL; | |
932 nr.lpProvider = NULL; | |
933 | |
934 result = qxeWNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK, | |
935 RESOURCEUSAGE_CONNECTABLE, &nr, &henum); | |
936 | |
937 if (result == NO_ERROR) | |
938 return henum; | |
939 else | |
940 return INVALID_HANDLE_VALUE; | |
941 } | |
942 | |
943 static Intbyte * | |
944 read_unc_volume (HANDLE henum) | |
945 { | |
946 int count; | |
947 int result; | |
948 Extbyte buf[16384]; | |
949 Intbyte *ptr; | |
950 Bytecount bufsize = sizeof (buf); | |
951 | |
952 count = 1; | |
953 /* #### we should just be querying the size and then allocating the | |
954 right amount, like for all similar API's. but the docs say this ?! | |
955 | |
956 An application cannot set the lpBuffer parameter to NULL and | |
957 retrieve the required buffer size from the lpBufferSize | |
958 parameter. Instead, the application should allocate a buffer of a | |
959 reasonable size -- 16 kilobytes (K) is typical -- and use the value | |
960 of lpBufferSize for error detection. | |
961 */ | |
962 | |
963 result = qxeWNetEnumResource (wnet_enum_handle, &count, buf, &bufsize); | |
964 if (result != NO_ERROR) | |
965 return NULL; | |
966 | |
967 /* WNetEnumResource returns \\resource\share...skip forward to "share". */ | |
968 TSTR_TO_C_STRING (((LPNETRESOURCEW) buf)->lpRemoteName, ptr); | |
969 INC_CHARPTR (ptr); | |
970 INC_CHARPTR (ptr); | |
971 while (*ptr && !IS_DIRECTORY_SEP (charptr_emchar (ptr))) | |
972 INC_CHARPTR (ptr); | |
973 INC_CHARPTR (ptr); | |
974 | |
975 return qxestrdup (ptr); | |
976 } | |
977 | |
978 static int | |
979 close_unc_volume (HANDLE henum) | |
980 { | |
981 if (henum != INVALID_HANDLE_VALUE) | |
982 return WNetCloseEnum (henum) == NO_ERROR ? 0 : -1; | |
983 else | |
984 return -1; | |
985 } | |
986 | |
987 static DWORD | |
988 unc_volume_file_attributes (const Intbyte *path) | |
989 { | |
990 HANDLE henum; | |
991 DWORD attrs; | |
992 | |
993 henum = open_unc_volume (path); | |
994 if (henum == INVALID_HANDLE_VALUE) | |
995 return -1; | |
996 | |
997 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY; | |
998 | |
999 close_unc_volume (henum); | |
1000 | |
1001 return attrs; | |
1002 } | |
1003 | |
1124 int | 1004 int |
1125 sys_rename (const char * oldname, const char * newname) | 1005 mswindows_access (const Intbyte *path, int mode) |
1126 { | 1006 { |
1127 char temp[PATH_MAX]; | 1007 DWORD attributes; |
1128 DWORD attr; | 1008 |
1129 | 1009 /* MSVC implementation doesn't recognize D_OK. */ |
1130 /* MoveFile on Win95 doesn't correctly change the short file name | 1010 if (is_unc_volume (path)) |
1011 { | |
1012 attributes = unc_volume_file_attributes (path); | |
1013 if (attributes == -1) | |
1014 { | |
1015 errno = EACCES; | |
1016 return -1; | |
1017 } | |
1018 } | |
1019 else | |
1020 { | |
1021 Extbyte *pathext; | |
1022 | |
1023 C_STRING_TO_TSTR (path, pathext); | |
1024 if ((attributes = qxeGetFileAttributes (pathext)) == -1) | |
1025 { | |
1026 /* Should try mapping GetLastError to errno; for now just indicate | |
1027 that path doesn't exist. */ | |
1028 errno = EACCES; | |
1029 return -1; | |
1030 } | |
1031 } | |
1032 if ((mode & X_OK) != 0 && !is_exec (path)) | |
1033 { | |
1034 errno = EACCES; | |
1035 return -1; | |
1036 } | |
1037 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0) | |
1038 { | |
1039 errno = EACCES; | |
1040 return -1; | |
1041 } | |
1042 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) | |
1043 { | |
1044 errno = EACCES; | |
1045 return -1; | |
1046 } | |
1047 return 0; | |
1048 } | |
1049 | |
1050 /* This only works on NTFS volumes, but is useful to have. */ | |
1051 /* #### NT 5.0 has a function CreateHardLink to do this directly, | |
1052 and it may do more things. */ | |
1053 int | |
1054 mswindows_link (const Intbyte *old, const Intbyte *new) | |
1055 { | |
1056 HANDLE fileh; | |
1057 int result = -1; | |
1058 | |
1059 if (old == NULL || new == NULL) | |
1060 { | |
1061 errno = ENOENT; | |
1062 return -1; | |
1063 } | |
1064 | |
1065 C_STRING_TO_TSTR (old, old); | |
1066 fileh = qxeCreateFile (old, 0, 0, NULL, OPEN_EXISTING, | |
1067 FILE_FLAG_BACKUP_SEMANTICS, NULL); | |
1068 if (fileh != INVALID_HANDLE_VALUE) | |
1069 { | |
1070 int wlen; | |
1071 WCHAR *newuni; | |
1072 | |
1073 /* Confusingly, the "alternate" stream name field does not apply | |
1074 when restoring a hard link, and instead contains the actual | |
1075 stream data for the link (ie. the name of the link to create). | |
1076 The WIN32_STREAM_ID structure before the cStreamName field is | |
1077 the stream header, which is then immediately followed by the | |
1078 stream data. */ | |
1079 | |
1080 struct | |
1081 { | |
1082 WIN32_STREAM_ID wid; | |
1083 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */ | |
1084 } data; | |
1085 | |
1086 TO_EXTERNAL_FORMAT (C_STRING, new, | |
1087 ALLOCA, (newuni, wlen), Qmswindows_unicode); | |
1088 if (wlen / sizeof (WCHAR) < MAX_PATH) | |
1089 { | |
1090 LPVOID context = NULL; | |
1091 DWORD wbytes = 0; | |
1092 | |
1093 wcscpy (data.wid.cStreamName, newuni); | |
1094 data.wid.dwStreamId = BACKUP_LINK; | |
1095 data.wid.dwStreamAttributes = 0; | |
1096 data.wid.Size.LowPart = wlen; /* in bytes, not chars! */ | |
1097 data.wid.Size.HighPart = 0; | |
1098 data.wid.dwStreamNameSize = 0; | |
1099 | |
1100 if (BackupWrite (fileh, (LPBYTE)&data, | |
1101 offsetof (WIN32_STREAM_ID, cStreamName) | |
1102 + data.wid.Size.LowPart, | |
1103 &wbytes, FALSE, FALSE, &context) | |
1104 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context)) | |
1105 { | |
1106 /* succeeded */ | |
1107 result = 0; | |
1108 } | |
1109 else | |
1110 { | |
1111 /* Should try mapping GetLastError to errno; for now just | |
1112 indicate a general error (eg. links not supported). */ | |
1113 errno = EINVAL; // perhaps EMLINK? | |
1114 } | |
1115 } | |
1116 | |
1117 CloseHandle (fileh); | |
1118 } | |
1119 else | |
1120 errno = ENOENT; | |
1121 | |
1122 return result; | |
1123 } | |
1124 | |
1125 /* sys_open() merged into sysdep.c sys_open() */ | |
1126 | |
1127 int | |
1128 mswindows_rename (const Intbyte *oldname, const Intbyte *newname) | |
1129 { | |
1130 int result; | |
1131 Intbyte *temp; | |
1132 | |
1133 /* MoveFile on Windows 95 doesn't correctly change the short file name | |
1131 alias in a number of circumstances (it is not easy to predict when | 1134 alias in a number of circumstances (it is not easy to predict when |
1132 just by looking at oldname and newname, unfortunately). In these | 1135 just by looking at oldname and newname, unfortunately). In these |
1133 cases, renaming through a temporary name avoids the problem. | 1136 cases, renaming through a temporary name avoids the problem. |
1134 | 1137 |
1135 A second problem on Win95 is that renaming through a temp name when | 1138 A second problem on Windows 95 is that renaming through a temp name when |
1136 newname is uppercase fails (the final long name ends up in | 1139 newname is uppercase fails (the final long name ends up in |
1137 lowercase, although the short alias might be uppercase) UNLESS the | 1140 lowercase, although the short alias might be uppercase) UNLESS the |
1138 long temp name is not 8.3. | 1141 long temp name is not 8.3. |
1139 | 1142 |
1140 So, on Win95 we always rename through a temp name, and we make sure | 1143 So, on Windows 95 we always rename through a temp name, and we make sure |
1141 the temp name has a long extension to ensure correct renaming. */ | 1144 the temp name has a long extension to ensure correct renaming. */ |
1142 | 1145 |
1143 strcpy (temp, map_win32_filename (oldname, NULL)); | 1146 /* XEmacs: We sprintf() part of OLDNAME into part of OLDNAME + a number, |
1144 | 1147 so the following calculation should certainly be enough. */ |
1145 if (GetVersion () & 0x80000000) | 1148 |
1146 { | 1149 temp = qxestrcpy (alloca_intbytes (2 * qxestrlen (oldname) + 100), oldname); |
1147 char * p; | 1150 |
1148 | 1151 if (mswindows_windows9x_p) |
1149 if (p = strrchr (temp, '\\')) | 1152 { |
1153 Intbyte *o; | |
1154 Intbyte *p; | |
1155 int i = 0; | |
1156 | |
1157 if (o = qxestrrchr (oldname, '\\')) | |
1158 o++; | |
1159 else | |
1160 o = (Intbyte *) oldname; | |
1161 | |
1162 if (p = qxestrrchr (temp, '\\')) | |
1150 p++; | 1163 p++; |
1151 else | 1164 else |
1152 p = temp; | 1165 p = temp; |
1153 /* Force temp name to require a manufactured 8.3 alias - this | 1166 |
1154 seems to make the second rename work properly. */ | 1167 do |
1155 strcpy (p, "_rename_temp.XXXXXX"); | 1168 { |
1156 sys_mktemp (temp); | 1169 Extbyte *oldext, *tempext; |
1157 if (rename (map_win32_filename (oldname, NULL), temp) < 0) | 1170 /* Force temp name to require a manufactured 8.3 alias - this |
1171 seems to make the second rename work properly. */ | |
1172 qxesprintf (p, "_.%s.%u", o, i); | |
1173 i++; | |
1174 C_STRING_TO_EXTERNAL (oldname, oldext, Qfile_name); | |
1175 C_STRING_TO_EXTERNAL (temp, tempext, Qfile_name); | |
1176 result = rename (oldext, tempext); | |
1177 } | |
1178 /* This loop must surely terminate! */ | |
1179 while (result < 0 && errno == EEXIST); | |
1180 if (result < 0) | |
1158 return -1; | 1181 return -1; |
1159 } | 1182 } |
1160 | 1183 |
1161 /* Emulate Unix behavior - newname is deleted if it already exists | 1184 /* Emulate Unix behaviour - newname is deleted if it already exists |
1162 (at least if it is a file; don't do this for directories). | 1185 (at least if it is a file; don't do this for directories). |
1163 However, don't do this if we are just changing the case of the file | 1186 |
1164 name - we will end up deleting the file we are trying to rename! */ | 1187 Since we mustn't do this if we are just changing the case of the |
1165 newname = map_win32_filename (newname, NULL); | 1188 file name (we would end up deleting the file we are trying to |
1166 | 1189 rename!), we let rename detect if the destination file already |
1167 /* TODO: Use GetInformationByHandle (on NT) to ensure newname and temp | 1190 exists - that way we avoid the possible pitfalls of trying to |
1168 do not refer to the same file, eg. through share aliases. */ | 1191 determine ourselves whether two names really refer to the same |
1169 if (stricmp (newname, temp) != 0 | 1192 file, which is not always possible in the general case. (Consider |
1170 && (attr = GetFileAttributes (newname)) != -1 | 1193 all the permutations of shared or subst'd drives, etc.) */ |
1171 && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0) | 1194 { |
1172 { | 1195 Extbyte *newext, *tempext; |
1173 _chmod (newname, 0666); | 1196 |
1174 _unlink (newname); | 1197 C_STRING_TO_EXTERNAL (newname, newext, Qfile_name); |
1175 } | 1198 C_STRING_TO_EXTERNAL (temp, tempext, Qfile_name); |
1176 | 1199 result = rename (tempext, newext); |
1177 return rename (temp, newname); | 1200 |
1178 } | 1201 if (result < 0 |
1179 #endif /* 0 */ | 1202 && errno == EEXIST |
1203 && _chmod (newext, 0666) == 0 | |
1204 && _unlink (newext) == 0) | |
1205 result = rename (tempext, newext); | |
1206 } | |
1207 | |
1208 return result; | |
1209 } | |
1210 | |
1211 int | |
1212 mswindows_unlink (const Intbyte *path) | |
1213 { | |
1214 Extbyte *pathout; | |
1215 | |
1216 C_STRING_TO_EXTERNAL (path, pathout, Qfile_name); | |
1217 /* On Unix, unlink works without write permission. */ | |
1218 _chmod (pathout, 0666); | |
1219 return _unlink (pathout); | |
1220 } | |
1180 | 1221 |
1181 static FILETIME utc_base_ft; | 1222 static FILETIME utc_base_ft; |
1182 static long double utc_base; | 1223 static long double utc_base; |
1183 static int init = 0; | 1224 static int init = 0; |
1184 | 1225 static LARGE_INTEGER utc_base_li; |
1185 #if 0 | 1226 |
1186 | 1227 /* XEmacs: We seem to have a new definition of |
1187 static long double utc_base; | 1228 mswindows_convert_time(), although I'm not sure why. --ben */ |
1188 | 1229 |
1189 time_t | 1230 time_t |
1190 convert_time (FILETIME ft) | 1231 mswindows_convert_time (FILETIME uft) |
1191 { | |
1192 long double ret; | |
1193 | |
1194 if (!init) | |
1195 { | |
1196 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */ | |
1197 SYSTEMTIME st; | |
1198 | |
1199 st.wYear = 1970; | |
1200 st.wMonth = 1; | |
1201 st.wDay = 1; | |
1202 st.wHour = 0; | |
1203 st.wMinute = 0; | |
1204 st.wSecond = 0; | |
1205 st.wMilliseconds = 0; | |
1206 | |
1207 SystemTimeToFileTime (&st, &utc_base_ft); | |
1208 utc_base = (long double) utc_base_ft.dwHighDateTime | |
1209 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime; | |
1210 init = 1; | |
1211 } | |
1212 | |
1213 if (CompareFileTime (&ft, &utc_base_ft) < 0) | |
1214 return 0; | |
1215 | |
1216 ret = (long double) ft.dwHighDateTime * 4096 * 1024 * 1024 + ft.dwLowDateTime; | |
1217 ret -= utc_base; | |
1218 return (time_t) (ret * 1e-7); | |
1219 } | |
1220 #else | |
1221 | |
1222 static LARGE_INTEGER utc_base_li; | |
1223 | |
1224 time_t | |
1225 convert_time (FILETIME uft) | |
1226 { | 1232 { |
1227 time_t ret; | 1233 time_t ret; |
1228 #ifndef MAXLONGLONG | 1234 #ifndef MAXLONGLONG |
1229 SYSTEMTIME st; | 1235 SYSTEMTIME st; |
1230 struct tm t; | 1236 struct tm t; |
1285 | 1291 |
1286 #endif | 1292 #endif |
1287 | 1293 |
1288 return ret; | 1294 return ret; |
1289 } | 1295 } |
1290 #endif | 1296 |
1291 #if defined(MINGW) && CYGWIN_VERSION_DLL_MAJOR <= 21 | 1297 static void |
1292 #undef LowPart | |
1293 #undef HighPart | |
1294 #endif | |
1295 | |
1296 #if 0 | |
1297 /* in case we ever have need of this */ | |
1298 void | |
1299 convert_from_time_t (time_t time, FILETIME * pft) | 1298 convert_from_time_t (time_t time, FILETIME * pft) |
1300 { | 1299 { |
1301 long double tmp; | 1300 long double tmp; |
1302 | 1301 |
1303 if (!init) | 1302 if (!init) |
1320 } | 1319 } |
1321 | 1320 |
1322 /* time in 100ns units since 1-Jan-1601 */ | 1321 /* time in 100ns units since 1-Jan-1601 */ |
1323 tmp = (long double) time * 1e7 + utc_base; | 1322 tmp = (long double) time * 1e7 + utc_base; |
1324 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024)); | 1323 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024)); |
1325 pft->dwLowDateTime = (DWORD) (tmp - pft->dwHighDateTime); | 1324 pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * |
1326 } | 1325 pft->dwHighDateTime); |
1327 #endif | 1326 } |
1328 | 1327 |
1329 #if 0 | 1328 #if 0 |
1330 /* No reason to keep this; faking inode values either by hashing or even | 1329 /* A comment from Emacs 20.6: |
1330 | |
1331 No reason to keep this; faking inode values either by hashing or even | |
1331 using the file index from GetInformationByHandle, is not perfect and | 1332 using the file index from GetInformationByHandle, is not perfect and |
1332 so by default Emacs doesn't use the inode values on Windows. | 1333 so by default Emacs doesn't use the inode values on Windows. |
1333 Instead, we now determine file-truename correctly (except for | 1334 Instead, we now determine file-truename correctly (except for |
1334 possible drive aliasing etc). */ | 1335 possible drive aliasing etc). */ |
1335 | 1336 |
1336 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */ | 1337 /* XEmacs: Removed the fake-inodes code here, which was if 0'd out. |
1337 static unsigned | 1338 If you want it, look in w32.c in Emacs 20.6. */ |
1338 hashval (const unsigned char * str) | |
1339 { | |
1340 unsigned h = 0; | |
1341 while (*str) | |
1342 { | |
1343 h = (h << 4) + *str++; | |
1344 h ^= (h >> 28); | |
1345 } | |
1346 return h; | |
1347 } | |
1348 | |
1349 /* Return the hash value of the canonical pathname, excluding the | |
1350 drive/UNC header, to get a hopefully unique inode number. */ | |
1351 static DWORD | |
1352 generate_inode_val (const char * name) | |
1353 { | |
1354 char fullname[ PATH_MAX ]; | |
1355 char * p; | |
1356 unsigned hash; | |
1357 | |
1358 /* Get the truly canonical filename, if it exists. (Note: this | |
1359 doesn't resolve aliasing due to subst commands, or recognize hard | |
1360 links. */ | |
1361 if (!win32_get_long_filename ((char *)name, fullname, PATH_MAX)) | |
1362 abort (); | |
1363 | |
1364 parse_root (fullname, &p); | |
1365 /* Normal Win32 filesystems are still case insensitive. */ | |
1366 _strlwr (p); | |
1367 return hashval (p); | |
1368 } | |
1369 | |
1370 #endif | 1339 #endif |
1371 | 1340 |
1372 /* #### aichner@ecf.teradyne.com reported that with the library | 1341 /* #### aichner@ecf.teradyne.com reported that with the library |
1373 provided stat/fstat, (file-exist "d:\\tmp\\") =>> nil, | 1342 provided stat/fstat, (file-exist "d:\\tmp\\") =>> nil, |
1374 (file-exist "d:\\tmp") =>> t, when d:\tmp exists. Whenever | 1343 (file-exist "d:\\tmp") =>> t, when d:\tmp exists. Whenever |
1375 we opt to use non-encapsulated stat(), this should serve as | 1344 we opt to use non-encapsulated stat(), this should serve as |
1376 a compatibility test. --kkm */ | 1345 a compatibility test. --kkm */ |
1377 | 1346 |
1378 /* Since stat is encapsulated on Windows NT, we need to encapsulate | 1347 /* Provide fstat and utime as well as stat for consistent handling of |
1379 the equally broken fstat as well. FSFmacs also provides its own | 1348 file timestamps. */ |
1380 utime. Is that necessary here too? */ | |
1381 int | 1349 int |
1382 mswindows_fstat (int desc, struct stat * buf) | 1350 mswindows_fstat (int desc, struct stat *buf) |
1383 { | 1351 { |
1384 HANDLE fh = (HANDLE) _get_osfhandle (desc); | 1352 HANDLE fh = (HANDLE) _get_osfhandle (desc); |
1385 BY_HANDLE_FILE_INFORMATION info; | 1353 BY_HANDLE_FILE_INFORMATION info; |
1386 DWORD fake_inode; | 1354 DWORD fake_inode; |
1387 int permission; | 1355 int permission; |
1442 buf->st_rdev = info.dwVolumeSerialNumber; | 1410 buf->st_rdev = info.dwVolumeSerialNumber; |
1443 | 1411 |
1444 buf->st_size = info.nFileSizeLow; | 1412 buf->st_size = info.nFileSizeLow; |
1445 | 1413 |
1446 /* Convert timestamps to Unix format. */ | 1414 /* Convert timestamps to Unix format. */ |
1447 buf->st_mtime = convert_time (info.ftLastWriteTime); | 1415 buf->st_mtime = mswindows_convert_time (info.ftLastWriteTime); |
1448 buf->st_atime = convert_time (info.ftLastAccessTime); | 1416 buf->st_atime = mswindows_convert_time (info.ftLastAccessTime); |
1449 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime; | 1417 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime; |
1450 buf->st_ctime = convert_time (info.ftCreationTime); | 1418 buf->st_ctime = mswindows_convert_time (info.ftCreationTime); |
1451 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime; | 1419 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime; |
1452 | 1420 |
1453 /* determine rwx permissions */ | 1421 /* determine rwx permissions */ |
1454 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) | 1422 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) |
1455 permission = _S_IREAD; | 1423 permission = _S_IREAD; |
1456 else | 1424 else |
1457 permission = _S_IREAD | _S_IWRITE; | 1425 permission = _S_IREAD | _S_IWRITE; |
1458 | 1426 |
1459 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | 1427 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
1460 permission |= _S_IEXEC; | 1428 permission |= _S_IEXEC; |
1429 else | |
1430 { | |
1431 #if 0 /* no way of knowing the filename */ | |
1432 Intbyte *p = qxestrrchr (name, '.'); | |
1433 if (p != NULL && | |
1434 (qxestrcasecmp (p, ".exe") == 0 || | |
1435 qxestrcasecmp (p, ".com") == 0 || | |
1436 qxestrcasecmp (p, ".bat") == 0 || | |
1437 qxestrcasecmp (p, ".cmd") == 0)) | |
1438 permission |= _S_IEXEC; | |
1439 #endif | |
1440 } | |
1461 | 1441 |
1462 buf->st_mode |= permission | (permission >> 3) | (permission >> 6); | 1442 buf->st_mode |= permission | (permission >> 3) | (permission >> 6); |
1463 | 1443 |
1464 return 0; | 1444 return 0; |
1465 } | 1445 } |
1466 | 1446 |
1467 /* MSVC stat function can't cope with UNC names and has other bugs, so | 1447 /* MSVC stat function can't cope with UNC names and has other bugs, so |
1468 replace it with our own. This also allows us to calculate consistent | 1448 replace it with our own. This also allows us to calculate consistent |
1469 inode values without hacks in the main Emacs code. */ | 1449 inode values without hacks in the main Emacs code. */ |
1470 int | 1450 int |
1471 mswindows_stat (const char * path, struct stat * buf) | 1451 mswindows_stat (const Intbyte *path, struct stat *buf) |
1472 { | 1452 { |
1473 char * name; | 1453 Intbyte *name, *r; |
1474 WIN32_FIND_DATA wfd; | 1454 WIN32_FIND_DATAW wfd; |
1475 HANDLE fh; | 1455 HANDLE fh; |
1476 DWORD fake_inode; | 1456 DWORD fake_inode; |
1477 int permission; | 1457 int permission; |
1478 int len; | 1458 Bytecount len; |
1479 int rootdir = FALSE; | 1459 int rootdir = FALSE; |
1460 Extbyte *nameext; | |
1480 | 1461 |
1481 if (path == NULL || buf == NULL) | 1462 if (path == NULL || buf == NULL) |
1482 { | 1463 { |
1483 errno = EFAULT; | 1464 errno = EFAULT; |
1484 return -1; | 1465 return -1; |
1485 } | 1466 } |
1486 | 1467 |
1487 name = (char *) map_win32_filename (path, &path); | 1468 name = qxestrcpy (alloca_intbytes (qxestrlen (path) + 10), path); |
1488 /* must be valid filename, no wild cards */ | 1469 |
1489 if (strchr (name, '*') || strchr (name, '?')) | 1470 get_volume_info (name, &path); |
1471 /* must be valid filename, no wild cards or other invalid characters */ | |
1472 if (qxestrpbrk (name, "*?|<>\"")) | |
1490 { | 1473 { |
1491 errno = ENOENT; | 1474 errno = ENOENT; |
1492 return -1; | 1475 return -1; |
1476 } | |
1477 | |
1478 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */ | |
1479 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name; | |
1480 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0') | |
1481 { | |
1482 r[1] = r[2] = '\0'; | |
1493 } | 1483 } |
1494 | 1484 |
1495 /* Remove trailing directory separator, unless name is the root | 1485 /* Remove trailing directory separator, unless name is the root |
1496 directory of a drive or UNC volume in which case ensure there | 1486 directory of a drive or UNC volume in which case ensure there |
1497 is a trailing separator. */ | 1487 is a trailing separator. */ |
1498 len = strlen (name); | 1488 len = qxestrlen (name); |
1499 rootdir = (path >= name + len - 1 | 1489 rootdir = (path >= name + len - 1 |
1500 && (IS_DIRECTORY_SEP (*path) || *path == 0)); | 1490 && (IS_DIRECTORY_SEP (*path) || *path == 0)); |
1501 name = strcpy ((char *)alloca (len + 2), name); | 1491 |
1502 | 1492 if (is_unc_volume (name)) |
1503 if (rootdir) | 1493 { |
1494 DWORD attrs = unc_volume_file_attributes (name); | |
1495 | |
1496 if (attrs == -1) | |
1497 return -1; | |
1498 | |
1499 memset (&wfd, 0, sizeof (wfd)); | |
1500 wfd.dwFileAttributes = attrs; | |
1501 wfd.ftCreationTime = utc_base_ft; | |
1502 wfd.ftLastAccessTime = utc_base_ft; | |
1503 wfd.ftLastWriteTime = utc_base_ft; | |
1504 /* XEmacs deleted: strcpy (wfd.cFileName, name); | |
1505 Not used later on. */ | |
1506 } | |
1507 else if (rootdir) | |
1504 { | 1508 { |
1505 if (!IS_DIRECTORY_SEP (name[len-1])) | 1509 if (!IS_DIRECTORY_SEP (name[len-1])) |
1506 strcat (name, "\\"); | 1510 qxestrcat (name, (Intbyte *) "\\"); |
1507 if (GetDriveType (name) < 2) | 1511 C_STRING_TO_TSTR (name, nameext); |
1512 if (qxeGetDriveType (nameext) < 2) | |
1508 { | 1513 { |
1509 errno = ENOENT; | 1514 errno = ENOENT; |
1510 return -1; | 1515 return -1; |
1511 } | 1516 } |
1512 memset (&wfd, 0, sizeof (wfd)); | 1517 memset (&wfd, 0, sizeof (wfd)); |
1513 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY; | 1518 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY; |
1514 wfd.ftCreationTime = utc_base_ft; | 1519 wfd.ftCreationTime = utc_base_ft; |
1515 wfd.ftLastAccessTime = utc_base_ft; | 1520 wfd.ftLastAccessTime = utc_base_ft; |
1516 wfd.ftLastWriteTime = utc_base_ft; | 1521 wfd.ftLastWriteTime = utc_base_ft; |
1517 strcpy (wfd.cFileName, name); | 1522 /* XEmacs deleted: strcpy (wfd.cFileName, name); |
1523 Not used later on. */ | |
1518 } | 1524 } |
1519 else | 1525 else |
1520 { | 1526 { |
1521 if (IS_DIRECTORY_SEP (name[len-1])) | 1527 if (IS_DIRECTORY_SEP (name[len-1])) |
1522 name[len - 1] = 0; | 1528 name[len - 1] = 0; |
1523 | 1529 |
1524 /* (This is hacky, but helps when doing file completions on | 1530 /* (This is hacky, but helps when doing file completions on |
1525 network drives.) Optimize by using information available from | 1531 network drives.) Optimize by using information available from |
1526 active readdir if possible. */ | 1532 active readdir if possible. */ |
1527 if (dir_find_handle != INVALID_HANDLE_VALUE && | 1533 if (dir_pathname) |
1528 (len = strlen (dir_pathname)), | 1534 { |
1529 strnicmp (name, dir_pathname, len) == 0 && | 1535 len = qxestrlen (dir_pathname); |
1530 IS_DIRECTORY_SEP (name[len]) && | 1536 if (len && IS_DIRECTORY_SEP (dir_pathname[len-1])) |
1531 stricmp (name + len + 1, dir_static.d_name) == 0) | 1537 len--; |
1538 } | |
1539 if (dir_find_handle != INVALID_HANDLE_VALUE | |
1540 && dir_pathname | |
1541 && qxestrncasecmp_i18n (name, dir_pathname, len) == 0 | |
1542 && IS_DIRECTORY_SEP (name[len]) | |
1543 && qxestrcasecmp_i18n (name + len + 1, | |
1544 (Intbyte *) dir_static.d_name) == 0) | |
1532 { | 1545 { |
1533 /* This was the last entry returned by readdir. */ | 1546 /* This was the last entry returned by readdir. */ |
1534 wfd = dir_find_data; | 1547 wfd = dir_find_data; |
1535 } | 1548 } |
1536 else | 1549 else |
1537 { | 1550 { |
1538 fh = FindFirstFile (name, &wfd); | 1551 C_STRING_TO_TSTR (name, nameext); |
1539 if (fh == INVALID_HANDLE_VALUE) | 1552 fh = qxeFindFirstFile (nameext, &wfd); |
1540 { | 1553 if (fh == INVALID_HANDLE_VALUE) |
1541 errno = ENOENT; | 1554 { |
1542 return -1; | 1555 errno = ENOENT; |
1543 } | 1556 return -1; |
1544 FindClose (fh); | 1557 } |
1545 } | 1558 FindClose (fh); |
1559 /* XEmacs: Don't need to convert wfd.cFileName because | |
1560 not used later on. */ | |
1561 } | |
1546 } | 1562 } |
1547 | 1563 |
1548 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | 1564 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
1549 { | 1565 { |
1550 buf->st_mode = _S_IFDIR; | 1566 buf->st_mode = _S_IFDIR; |
1551 buf->st_nlink = 2; /* doesn't really matter */ | 1567 buf->st_nlink = 2; /* doesn't really matter */ |
1552 fake_inode = 0; /* this doesn't either I think */ | 1568 fake_inode = 0; /* this doesn't either I think */ |
1553 } | 1569 } |
1554 else if (!NILP (Vmswindows_get_true_file_attributes)) | 1570 else |
1555 { | 1571 { |
1556 /* This is more accurate in terms of getting the correct number | 1572 if (!NILP (Vmswindows_get_true_file_attributes)) |
1557 of links, but is quite slow (it is noticeable when Emacs is | 1573 C_STRING_TO_TSTR (name, nameext); |
1558 making a list of file name completions). */ | 1574 if (!NILP (Vmswindows_get_true_file_attributes) |
1559 BY_HANDLE_FILE_INFORMATION info; | 1575 /* No access rights required to get info. */ |
1560 | 1576 && (fh = qxeCreateFile (nameext, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) |
1561 /* No access rights required to get info. */ | 1577 != INVALID_HANDLE_VALUE) |
1562 fh = CreateFile (name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, | 1578 { |
1563 OPEN_EXISTING, 0, NULL); | 1579 /* This is more accurate in terms of gettting the correct number |
1564 | 1580 of links, but is quite slow (it is noticable when Emacs is |
1565 if (GetFileInformationByHandle (fh, &info)) | 1581 making a list of file name completions). */ |
1566 { | 1582 BY_HANDLE_FILE_INFORMATION info; |
1583 | |
1584 if (GetFileInformationByHandle (fh, &info)) | |
1585 { | |
1586 buf->st_nlink = (short) info.nNumberOfLinks; | |
1587 /* Might as well use file index to fake inode values, but this | |
1588 is not guaranteed to be unique unless we keep a handle open | |
1589 all the time (even then there are situations where it is | |
1590 not unique). Reputedly, there are at most 48 bits of info | |
1591 (on NTFS, presumably less on FAT). */ | |
1592 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh; | |
1593 } | |
1594 else | |
1595 { | |
1596 buf->st_nlink = 1; | |
1597 fake_inode = 0; | |
1598 } | |
1599 | |
1567 switch (GetFileType (fh)) | 1600 switch (GetFileType (fh)) |
1568 { | 1601 { |
1569 case FILE_TYPE_DISK: | 1602 case FILE_TYPE_DISK: |
1570 buf->st_mode = _S_IFREG; | 1603 buf->st_mode = _S_IFREG; |
1571 break; | 1604 break; |
1575 case FILE_TYPE_CHAR: | 1608 case FILE_TYPE_CHAR: |
1576 case FILE_TYPE_UNKNOWN: | 1609 case FILE_TYPE_UNKNOWN: |
1577 default: | 1610 default: |
1578 buf->st_mode = _S_IFCHR; | 1611 buf->st_mode = _S_IFCHR; |
1579 } | 1612 } |
1580 buf->st_nlink = (short) info.nNumberOfLinks; | |
1581 /* Might as well use file index to fake inode values, but this | |
1582 is not guaranteed to be unique unless we keep a handle open | |
1583 all the time (even then there are situations where it is | |
1584 not unique). Reputedly, there are at most 48 bits of info | |
1585 (on NTFS, presumably less on FAT). */ | |
1586 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh; | |
1587 CloseHandle (fh); | 1613 CloseHandle (fh); |
1588 } | 1614 } |
1589 else | 1615 else |
1590 { | 1616 { |
1591 errno = EACCES; | 1617 /* Don't bother to make this information more accurate. */ |
1592 return -1; | 1618 buf->st_mode = _S_IFREG; |
1593 } | 1619 buf->st_nlink = 1; |
1594 } | 1620 fake_inode = 0; |
1621 } | |
1622 } | |
1623 | |
1624 #if 0 | |
1625 /* XEmacs: Removed the fake-inodes code here, which was if 0'd out. | |
1626 If you want it, look in w32.c in Emacs 20.6. */ | |
1627 #endif | |
1628 | |
1629 /* MSVC defines _ino_t to be short; other libc's might not. */ | |
1630 if (sizeof (buf->st_ino) == 2) | |
1631 buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16)); | |
1595 else | 1632 else |
1596 { | 1633 buf->st_ino = (unsigned short) fake_inode; |
1597 /* Don't bother to make this information more accurate. */ | |
1598 buf->st_mode = _S_IFREG; | |
1599 buf->st_nlink = 1; | |
1600 fake_inode = 0; | |
1601 } | |
1602 | |
1603 #if 0 | |
1604 /* Not sure if there is any point in this. */ | |
1605 if (!NILP (Vwin32_generate_fake_inodes)) | |
1606 fake_inode = generate_inode_val (name); | |
1607 else if (fake_inode == 0) | |
1608 { | |
1609 /* For want of something better, try to make everything unique. */ | |
1610 static DWORD gen_num = 0; | |
1611 fake_inode = ++gen_num; | |
1612 } | |
1613 #endif | |
1614 | |
1615 /* #### MSVC defines _ino_t to be short; other libc's might not. */ | |
1616 buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16)); | |
1617 | 1634 |
1618 /* consider files to belong to current user */ | 1635 /* consider files to belong to current user */ |
1619 buf->st_uid = buf->st_gid = (short) nt_fake_unix_uid; | 1636 buf->st_uid = the_passwd.pw_uid; |
1620 | 1637 buf->st_gid = the_passwd.pw_gid; |
1621 /* volume_info is set indirectly by map_win32_filename */ | 1638 |
1639 /* volume_info is set by get_volume_info */ | |
1622 buf->st_dev = volume_info.serialnum; | 1640 buf->st_dev = volume_info.serialnum; |
1623 buf->st_rdev = volume_info.serialnum; | 1641 buf->st_rdev = volume_info.serialnum; |
1624 | 1642 |
1643 | |
1625 buf->st_size = wfd.nFileSizeLow; | 1644 buf->st_size = wfd.nFileSizeLow; |
1626 | 1645 |
1627 /* Convert timestamps to Unix format. */ | 1646 /* Convert timestamps to Unix format. */ |
1628 buf->st_mtime = convert_time (wfd.ftLastWriteTime); | 1647 buf->st_mtime = mswindows_convert_time (wfd.ftLastWriteTime); |
1629 buf->st_atime = convert_time (wfd.ftLastAccessTime); | 1648 buf->st_atime = mswindows_convert_time (wfd.ftLastAccessTime); |
1630 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime; | 1649 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime; |
1631 buf->st_ctime = convert_time (wfd.ftCreationTime); | 1650 buf->st_ctime = mswindows_convert_time (wfd.ftCreationTime); |
1632 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime; | 1651 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime; |
1633 | 1652 |
1634 /* determine rwx permissions */ | 1653 /* determine rwx permissions */ |
1635 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) | 1654 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) |
1636 permission = _S_IREAD; | 1655 permission = _S_IREAD; |
1637 else | 1656 else |
1638 permission = _S_IREAD | _S_IWRITE; | 1657 permission = _S_IREAD | _S_IWRITE; |
1639 | 1658 |
1640 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | 1659 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
1641 permission |= _S_IEXEC; | 1660 permission |= _S_IEXEC; |
1661 else if (is_exec (name)) | |
1662 permission |= _S_IEXEC; | |
1663 | |
1664 buf->st_mode |= permission | (permission >> 3) | (permission >> 6); | |
1665 | |
1666 return 0; | |
1667 } | |
1668 | |
1669 int | |
1670 mswindows_utime (Lisp_Object path, struct utimbuf *times) | |
1671 { | |
1672 /* #### Supposedly we're providing this because standard utime() | |
1673 might not work; or at the very least to get consistent results | |
1674 since we replace other time-handling routines in stat. But out | |
1675 replacement doesn't seem to work, probably due to some subtle bug | |
1676 in this routine, which should be investigated eventually. So for | |
1677 the moment, we just use utime(), which conceivably might be | |
1678 slightly off in comparison with our own routines? Seems strange, | |
1679 and so far no problems seen. --ben */ | |
1680 | |
1681 struct utimbuf deftime; | |
1682 #if 0 | |
1683 HANDLE fh; | |
1684 #endif | |
1685 static FILETIME mtime; | |
1686 static FILETIME atime; | |
1687 Extbyte *filename; | |
1688 | |
1689 if (times == NULL) | |
1690 { | |
1691 deftime.modtime = deftime.actime = time (NULL); | |
1692 times = &deftime; | |
1693 } | |
1694 | |
1695 LISP_STRING_TO_TSTR (path, filename); | |
1696 /* APA: SetFileTime fails to set mtime correctly (always 1-Jan-1970) */ | |
1697 #if 0 | |
1698 /* Need write access to set times. */ | |
1699 fh = qxeCreateFile (filename, GENERIC_WRITE, | |
1700 FILE_SHARE_READ | FILE_SHARE_WRITE, | |
1701 0, OPEN_EXISTING, 0, NULL); | |
1702 if (fh) | |
1703 { | |
1704 convert_from_time_t (times->actime, &atime); | |
1705 convert_from_time_t (times->modtime, &mtime); | |
1706 if (!SetFileTime (fh, NULL, &atime, &mtime)) | |
1707 { | |
1708 CloseHandle (fh); | |
1709 errno = EACCES; | |
1710 return -1; | |
1711 } | |
1712 CloseHandle (fh); | |
1713 } | |
1642 else | 1714 else |
1643 { | 1715 { |
1644 char * p = strrchr (name, '.'); | 1716 errno = EINVAL; |
1645 if (p != NULL && | 1717 return -1; |
1646 (stricmp (p, ".exe") == 0 || | 1718 } |
1647 stricmp (p, ".com") == 0 || | |
1648 stricmp (p, ".bat") == 0 || | |
1649 stricmp (p, ".cmd") == 0)) | |
1650 permission |= _S_IEXEC; | |
1651 } | |
1652 | |
1653 buf->st_mode |= permission | (permission >> 3) | (permission >> 6); | |
1654 | |
1655 return 0; | 1719 return 0; |
1656 } | 1720 #else |
1657 | 1721 { |
1658 /* From callproc.c */ | 1722 struct _utimbuf newtimes; |
1659 extern Lisp_Object Vbinary_process_input; | 1723 |
1660 extern Lisp_Object Vbinary_process_output; | 1724 newtimes.actime = times->actime; |
1661 | 1725 newtimes.modtime = times->modtime; |
1662 /* Unix pipe() has only one arg */ | 1726 |
1663 int | 1727 if (XEUNICODE_P) |
1664 sys_pipe (int * phandles) | 1728 return _wutime ((const wchar_t *) filename, &newtimes); |
1665 { | 1729 else |
1666 int rc; | 1730 return _utime (filename, &newtimes); |
1667 unsigned flags; | 1731 } |
1668 | 1732 #endif |
1669 /* make pipe handles non-inheritable; when we spawn a child, we | 1733 } |
1670 replace the relevant handle with an inheritable one. Also put | 1734 |
1671 pipes into binary mode; we will do text mode translation ourselves | 1735 Intbyte * |
1672 if required. */ | 1736 mswindows_getdcwd (int drivelet) |
1673 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY); | 1737 { |
1674 | 1738 Extbyte *cwdext; |
1675 if (rc == 0) | 1739 Intbyte *cwd; |
1676 { | 1740 |
1677 flags = FILE_PIPE | FILE_READ; | 1741 if (XEUNICODE_P) |
1678 if (!NILP (Vbinary_process_output)) | 1742 cwdext = (Extbyte *) _wgetdcwd (drivelet, NULL, 0); |
1679 flags |= FILE_BINARY; | 1743 else |
1680 fd_info[phandles[0]].flags = flags; | 1744 cwdext = _getdcwd (drivelet, NULL, 0); |
1681 | 1745 TSTR_TO_C_STRING_MALLOC (cwdext, cwd); |
1682 flags = FILE_PIPE | FILE_WRITE; | 1746 xfree (cwdext); |
1683 if (!NILP (Vbinary_process_input)) | 1747 return cwd; |
1684 flags |= FILE_BINARY; | |
1685 fd_info[phandles[1]].flags = flags; | |
1686 } | |
1687 | |
1688 return rc; | |
1689 } | 1748 } |
1690 | 1749 |
1691 void | 1750 void |
1692 init_ntproc (void) | 1751 init_ntproc (void) |
1693 { | 1752 { |
1725 &stderr_save, | 1784 &stderr_save, |
1726 0, | 1785 0, |
1727 FALSE, | 1786 FALSE, |
1728 DUPLICATE_SAME_ACCESS); | 1787 DUPLICATE_SAME_ACCESS); |
1729 | 1788 |
1730 fclose (stdin); | 1789 retry_fclose (stdin); |
1731 fclose (stdout); | 1790 retry_fclose (stdout); |
1732 fclose (stderr); | 1791 retry_fclose (stderr); |
1733 | 1792 |
1734 if (stdin_save != INVALID_HANDLE_VALUE) | 1793 if (stdin_save != INVALID_HANDLE_VALUE) |
1735 _open_osfhandle ((long) stdin_save, O_TEXT); | 1794 _open_osfhandle ((long) stdin_save, O_TEXT); |
1736 else | 1795 else |
1737 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY); | 1796 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY); |
1748 else | 1807 else |
1749 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY); | 1808 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY); |
1750 _fdopen (2, "w"); | 1809 _fdopen (2, "w"); |
1751 } | 1810 } |
1752 | 1811 |
1753 /* determine which drives are fixed, for GetCachedVolumeInformation */ | 1812 /* determine which drives are fixed, for get_cached_volume_information */ |
1754 { | 1813 { |
1755 /* GetDriveType must have trailing backslash. */ | 1814 /* GetDriveType must have trailing backslash. */ |
1756 char drive[] = "A:\\"; | 1815 Intbyte drive[] = "A:\\"; |
1757 | 1816 |
1758 /* Loop over all possible drive letters */ | 1817 /* Loop over all possible drive letters */ |
1759 while ( *drive <= 'Z' ) | 1818 while (*drive <= 'Z') |
1760 { | 1819 { |
1820 Extbyte *driveext; | |
1821 | |
1822 C_STRING_TO_TSTR (drive, driveext); | |
1823 | |
1761 /* Record if this drive letter refers to a fixed drive. */ | 1824 /* Record if this drive letter refers to a fixed drive. */ |
1762 fixed_drives[ DRIVE_INDEX (*drive) ] = | 1825 fixed_drives[DRIVE_INDEX (*drive)] = |
1763 (GetDriveType (drive) == DRIVE_FIXED); | 1826 (qxeGetDriveType (driveext) == DRIVE_FIXED); |
1764 | 1827 |
1765 (*drive)++; | 1828 (*drive)++; |
1766 } | 1829 } |
1830 | |
1831 /* Reset the volume info cache. */ | |
1832 volume_cache = NULL; | |
1767 } | 1833 } |
1768 } | 1834 } |
1769 #ifndef HAVE_TTY | |
1770 Lisp_Object | |
1771 tty_semi_canonicalize_console_connection (Lisp_Object connection, | |
1772 Error_Behavior errb) | |
1773 { | |
1774 return Vstdio_str; | |
1775 } | |
1776 | |
1777 Lisp_Object | |
1778 tty_canonicalize_console_connection (Lisp_Object connection, | |
1779 Error_Behavior errb) | |
1780 { | |
1781 return Vstdio_str; | |
1782 } | |
1783 | |
1784 Lisp_Object | |
1785 tty_semi_canonicalize_device_connection (Lisp_Object connection, | |
1786 Error_Behavior errb) | |
1787 { | |
1788 return Vstdio_str; | |
1789 } | |
1790 | |
1791 Lisp_Object | |
1792 tty_canonicalize_device_connection (Lisp_Object connection, | |
1793 Error_Behavior errb) | |
1794 { | |
1795 return Vstdio_str; | |
1796 } | |
1797 #endif | |
1798 | 1835 |
1799 | 1836 |
1800 /*--------------------------------------------------------------------*/ | 1837 /*--------------------------------------------------------------------*/ |
1801 /* Memory-mapped files */ | 1838 /* Memory-mapped files */ |
1802 /*--------------------------------------------------------------------*/ | 1839 /*--------------------------------------------------------------------*/ |
1803 | 1840 |
1804 int | 1841 int |
1805 open_input_file (file_data *p_file, const char *filename) | 1842 open_input_file (file_data *p_file, const Intbyte *filename) |
1806 { | 1843 { |
1807 /* Synched with FSF 20.6. We fixed some warnings. */ | 1844 /* Synched with FSF 20.6. We fixed some warnings. */ |
1808 HANDLE file; | 1845 HANDLE file; |
1809 HANDLE file_mapping; | 1846 HANDLE file_mapping; |
1810 void *file_base; | 1847 void *file_base; |
1811 DWORD size, upper_size; | 1848 DWORD size, upper_size; |
1812 | 1849 Extbyte *fileext; |
1813 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL, | 1850 |
1814 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); | 1851 C_STRING_TO_TSTR (filename, fileext); |
1852 | |
1853 file = qxeCreateFile (fileext, GENERIC_READ, FILE_SHARE_READ, NULL, | |
1854 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); | |
1815 if (file == INVALID_HANDLE_VALUE) | 1855 if (file == INVALID_HANDLE_VALUE) |
1816 return FALSE; | 1856 return FALSE; |
1817 | 1857 |
1818 size = GetFileSize (file, &upper_size); | 1858 size = GetFileSize (file, &upper_size); |
1819 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY, | 1859 file_mapping = qxeCreateFileMapping (file, NULL, PAGE_READONLY, |
1820 0, size, NULL); | 1860 0, size, NULL); |
1821 if (!file_mapping) | 1861 if (!file_mapping) |
1822 return FALSE; | 1862 return FALSE; |
1823 | 1863 |
1824 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size); | 1864 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size); |
1825 if (file_base == 0) | 1865 if (file_base == 0) |
1826 return FALSE; | 1866 return FALSE; |
1827 | 1867 |
1828 p_file->name = (char *)filename; | 1868 p_file->name = filename; |
1829 p_file->size = size; | 1869 p_file->size = size; |
1830 p_file->file = file; | 1870 p_file->file = file; |
1831 p_file->file_mapping = file_mapping; | 1871 p_file->file_mapping = file_mapping; |
1832 p_file->file_base = (char *)file_base; | 1872 p_file->file_base = file_base; |
1833 | 1873 |
1834 return TRUE; | 1874 return TRUE; |
1835 } | 1875 } |
1836 | 1876 |
1837 int | 1877 int |
1838 open_output_file (file_data *p_file, const char *filename, unsigned long size) | 1878 open_output_file (file_data *p_file, const Intbyte *filename, |
1879 unsigned long size) | |
1839 { | 1880 { |
1840 /* Synched with FSF 20.6. We fixed some warnings. */ | 1881 /* Synched with FSF 20.6. We fixed some warnings. */ |
1841 HANDLE file; | 1882 HANDLE file; |
1842 HANDLE file_mapping; | 1883 HANDLE file_mapping; |
1843 void *file_base; | 1884 void *file_base; |
1844 | 1885 Extbyte *fileext; |
1845 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, | 1886 |
1846 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); | 1887 C_STRING_TO_TSTR (filename, fileext); |
1888 | |
1889 file = qxeCreateFile (fileext, GENERIC_READ | GENERIC_WRITE, 0, NULL, | |
1890 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); | |
1847 if (file == INVALID_HANDLE_VALUE) | 1891 if (file == INVALID_HANDLE_VALUE) |
1848 return FALSE; | 1892 return FALSE; |
1849 | 1893 |
1850 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE, | 1894 file_mapping = qxeCreateFileMapping (file, NULL, PAGE_READWRITE, |
1851 0, size, NULL); | 1895 0, size, NULL); |
1852 if (!file_mapping) | 1896 if (!file_mapping) |
1853 return FALSE; | 1897 return FALSE; |
1854 | 1898 |
1855 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size); | 1899 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size); |
1856 if (file_base == NULL) | 1900 if (file_base == NULL) |
1858 | 1902 |
1859 p_file->name = filename; | 1903 p_file->name = filename; |
1860 p_file->size = size; | 1904 p_file->size = size; |
1861 p_file->file = file; | 1905 p_file->file = file; |
1862 p_file->file_mapping = file_mapping; | 1906 p_file->file_mapping = file_mapping; |
1863 p_file->file_base = (char*) file_base; | 1907 p_file->file_base = file_base; |
1864 | 1908 |
1865 return TRUE; | 1909 return TRUE; |
1866 } | 1910 } |
1867 | 1911 |
1868 #if 1 /* !defined(MINGW) */ | 1912 #if 1 /* !defined(MINGW) */ |
1869 /* Return pointer to section header for section containing the given | 1913 /* Return pointer to section header for section containing the given |
1870 relative virtual address. */ | 1914 relative virtual address. */ |
1871 static IMAGE_SECTION_HEADER * | 1915 static IMAGE_SECTION_HEADER * |
1872 rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header) | 1916 rva_to_section (DWORD rva, IMAGE_NT_HEADERS *nt_header) |
1873 { | 1917 { |
1874 /* Synched with FSF 20.6. We added MINGW stuff. */ | 1918 /* Synched with FSF 20.6. We added MINGW stuff. */ |
1875 PIMAGE_SECTION_HEADER section; | 1919 PIMAGE_SECTION_HEADER section; |
1876 int i; | 1920 int i; |
1877 | 1921 |
1895 return NULL; | 1939 return NULL; |
1896 } | 1940 } |
1897 #endif | 1941 #endif |
1898 | 1942 |
1899 void | 1943 void |
1900 mswindows_executable_type (const char * filename, int * is_dos_app, | 1944 mswindows_executable_type (const Intbyte *filename, int *is_dos_app, |
1901 int * is_cygnus_app) | 1945 int *is_cygnus_app) |
1902 { | 1946 { |
1903 /* Synched with FSF 20.6. We added MINGW stuff and casts. */ | 1947 /* Synched with FSF 20.6. We added MINGW stuff and casts. */ |
1904 file_data executable; | 1948 file_data executable; |
1905 char * p; | 1949 Intbyte *p; |
1906 | 1950 |
1907 /* Default values in case we can't tell for sure. */ | 1951 /* Default values in case we can't tell for sure. */ |
1908 *is_dos_app = FALSE; | 1952 *is_dos_app = FALSE; |
1909 *is_cygnus_app = FALSE; | 1953 *is_cygnus_app = FALSE; |
1910 | 1954 |
1911 if (!open_input_file (&executable, filename)) | 1955 if (!open_input_file (&executable, filename)) |
1912 return; | 1956 return; |
1913 | 1957 |
1914 p = strrchr (filename, '.'); | 1958 p = qxestrrchr (filename, '.'); |
1915 | 1959 |
1916 /* We can only identify DOS .com programs from the extension. */ | 1960 /* We can only identify DOS .com programs from the extension. */ |
1917 if (p && stricmp (p, ".com") == 0) | 1961 if (p && qxestrcasecmp (p, ".com") == 0) |
1918 *is_dos_app = TRUE; | 1962 *is_dos_app = TRUE; |
1919 else if (p && (stricmp (p, ".bat") == 0 || | 1963 else if (p && (qxestrcasecmp (p, ".bat") == 0 || |
1920 stricmp (p, ".cmd") == 0)) | 1964 qxestrcasecmp (p, ".cmd") == 0)) |
1921 { | 1965 { |
1922 /* A DOS shell script - it appears that CreateProcess is happy to | 1966 /* A DOS shell script - it appears that CreateProcess is happy to |
1923 accept this (somewhat surprisingly); presumably it looks at | 1967 accept this (somewhat surprisingly); presumably it looks at |
1924 COMSPEC to determine what executable to actually invoke. | 1968 COMSPEC to determine what executable to actually invoke. |
1925 Therefore, we have to do the same here as well. */ | 1969 Therefore, we have to do the same here as well. */ |
1935 it isn't really a 16- or 32-bit Windows exe, since both formats | 1979 it isn't really a 16- or 32-bit Windows exe, since both formats |
1936 start with a DOS program stub. Note that 16-bit Windows | 1980 start with a DOS program stub. Note that 16-bit Windows |
1937 executables use the OS/2 1.x format. */ | 1981 executables use the OS/2 1.x format. */ |
1938 | 1982 |
1939 #if 0 /* defined( MINGW ) */ | 1983 #if 0 /* defined( MINGW ) */ |
1940 /* mingw32 doesn't have enough headers to detect cygwin | 1984 /* mingw doesn't have enough headers to detect cygwin |
1941 apps, just do what we can. */ | 1985 apps, just do what we can. */ |
1942 FILHDR * exe_header; | 1986 FILHDR *exe_header; |
1943 | 1987 |
1944 exe_header = (FILHDR*) executable.file_base; | 1988 exe_header = (FILHDR *) executable.file_base; |
1945 if (exe_header->e_magic != DOSMAGIC) | 1989 if (exe_header->e_magic != DOSMAGIC) |
1946 goto unwind; | 1990 goto unwind; |
1947 | 1991 |
1948 if ((char*) exe_header->e_lfanew > (char*) executable.size) | 1992 if ((char *) exe_header->e_lfanew > (char *) executable.size) |
1949 { | 1993 { |
1950 /* Some dos headers (pkunzip) have bogus e_lfanew fields. */ | 1994 /* Some dos headers (pkunzip) have bogus e_lfanew fields. */ |
1951 *is_dos_app = TRUE; | 1995 *is_dos_app = TRUE; |
1952 } | 1996 } |
1953 else if (exe_header->nt_signature != NT_SIGNATURE) | 1997 else if (exe_header->nt_signature != NT_SIGNATURE) |
1954 { | 1998 { |
1955 *is_dos_app = TRUE; | 1999 *is_dos_app = TRUE; |
1956 } | 2000 } |
1957 #else | 2001 #else |
1958 IMAGE_DOS_HEADER * dos_header; | 2002 IMAGE_DOS_HEADER *dos_header; |
1959 IMAGE_NT_HEADERS * nt_header; | 2003 IMAGE_NT_HEADERS *nt_header; |
1960 | 2004 |
1961 dos_header = (PIMAGE_DOS_HEADER) executable.file_base; | 2005 dos_header = (PIMAGE_DOS_HEADER) executable.file_base; |
1962 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) | 2006 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) |
1963 goto unwind; | 2007 goto unwind; |
1964 | 2008 |
1965 nt_header = (PIMAGE_NT_HEADERS) ((char*) dos_header + dos_header->e_lfanew); | 2009 nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + |
2010 dos_header->e_lfanew); | |
1966 | 2011 |
1967 if ((char*) nt_header > (char*) dos_header + executable.size) | 2012 if ((char *) nt_header > (char *) dos_header + executable.size) |
1968 { | 2013 { |
1969 /* Some dos headers (pkunzip) have bogus e_lfanew fields. */ | 2014 /* Some dos headers (pkunzip) have bogus e_lfanew fields. */ |
1970 *is_dos_app = TRUE; | 2015 *is_dos_app = TRUE; |
1971 } | 2016 } |
1972 else if (nt_header->Signature != IMAGE_NT_SIGNATURE && | 2017 else if (nt_header->Signature != IMAGE_NT_SIGNATURE && |
1976 } | 2021 } |
1977 else if (nt_header->Signature == IMAGE_NT_SIGNATURE) | 2022 else if (nt_header->Signature == IMAGE_NT_SIGNATURE) |
1978 { | 2023 { |
1979 /* Look for cygwin.dll in DLL import list. */ | 2024 /* Look for cygwin.dll in DLL import list. */ |
1980 IMAGE_DATA_DIRECTORY import_dir = | 2025 IMAGE_DATA_DIRECTORY import_dir = |
1981 nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; | 2026 nt_header->OptionalHeader. |
1982 IMAGE_IMPORT_DESCRIPTOR * imports; | 2027 DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; |
1983 IMAGE_SECTION_HEADER * section; | 2028 IMAGE_IMPORT_DESCRIPTOR *imports; |
2029 IMAGE_SECTION_HEADER *section; | |
1984 | 2030 |
1985 section = rva_to_section (import_dir.VirtualAddress, nt_header); | 2031 section = rva_to_section (import_dir.VirtualAddress, nt_header); |
1986 imports = (IMAGE_IMPORT_DESCRIPTOR *) RVA_TO_PTR (import_dir.VirtualAddress, | 2032 imports = |
1987 section, executable); | 2033 (IMAGE_IMPORT_DESCRIPTOR *) RVA_TO_PTR (import_dir.VirtualAddress, |
1988 | 2034 section, executable); |
2035 | |
1989 for ( ; imports->Name; imports++) | 2036 for ( ; imports->Name; imports++) |
1990 { | 2037 { |
1991 char *dllname = (char*) RVA_TO_PTR (imports->Name, section, executable); | 2038 Extbyte *dllname_ext = |
2039 (Extbyte *) RVA_TO_PTR (imports->Name, section, executable); | |
2040 Intbyte *dllname; | |
2041 | |
2042 EXTERNAL_TO_C_STRING (dllname_ext, dllname, Qbinary); | |
1992 | 2043 |
1993 /* The exact name of the cygwin dll has changed with | 2044 /* The exact name of the cygwin dll has changed with |
1994 various releases, but hopefully this will be reasonably | 2045 various releases, but hopefully this will be reasonably |
1995 future proof. */ | 2046 future proof. */ |
1996 if (strncmp (dllname, "cygwin", 6) == 0) | 2047 if (qxestrncasecmp (dllname, (Intbyte *) "cygwin", 6) == 0) |
1997 { | 2048 { |
1998 *is_cygnus_app = TRUE; | 2049 *is_cygnus_app = TRUE; |
1999 break; | 2050 break; |
2000 } | 2051 } |
2001 } | 2052 } |
2005 | 2056 |
2006 unwind: | 2057 unwind: |
2007 close_file_data (&executable); | 2058 close_file_data (&executable); |
2008 } | 2059 } |
2009 | 2060 |
2010 static void | |
2011 convert_from_time_t (time_t time, FILETIME * pft) | |
2012 { | |
2013 long double tmp; | |
2014 | |
2015 if (!init) | |
2016 { | |
2017 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */ | |
2018 SYSTEMTIME st; | |
2019 | |
2020 st.wYear = 1970; | |
2021 st.wMonth = 1; | |
2022 st.wDay = 1; | |
2023 st.wHour = 0; | |
2024 st.wMinute = 0; | |
2025 st.wSecond = 0; | |
2026 st.wMilliseconds = 0; | |
2027 | |
2028 SystemTimeToFileTime (&st, &utc_base_ft); | |
2029 utc_base = (long double) utc_base_ft.dwHighDateTime | |
2030 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime; | |
2031 init = 1; | |
2032 } | |
2033 | |
2034 /* time in 100ns units since 1-Jan-1601 */ | |
2035 tmp = (long double) time * 1e7 + utc_base; | |
2036 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024)); | |
2037 pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * | |
2038 pft->dwHighDateTime); | |
2039 } | |
2040 | |
2041 int | |
2042 mswindows_utime (Lisp_Object path, struct utimbuf *times) | |
2043 { | |
2044 struct utimbuf deftime; | |
2045 #if 0 | |
2046 HANDLE fh; | |
2047 #endif | |
2048 static FILETIME mtime; | |
2049 static FILETIME atime; | |
2050 Extbyte *filename; | |
2051 | |
2052 if (times == NULL) | |
2053 { | |
2054 deftime.modtime = deftime.actime = time (NULL); | |
2055 times = &deftime; | |
2056 } | |
2057 | |
2058 LISP_STRING_TO_EXTERNAL (path, filename, Qmswindows_tstr); | |
2059 /* APA: SetFileTime fails to set mtime correctly (always 1-Jan-1970) */ | |
2060 #if 0 | |
2061 /* Need write access to set times. */ | |
2062 fh = CreateFile (filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, | |
2063 0, OPEN_EXISTING, 0, NULL); | |
2064 if (fh) | |
2065 { | |
2066 convert_from_time_t (times->actime, &atime); | |
2067 convert_from_time_t (times->modtime, &mtime); | |
2068 if (!SetFileTime (fh, NULL, &atime, &mtime)) | |
2069 { | |
2070 CloseHandle (fh); | |
2071 errno = EACCES; | |
2072 return -1; | |
2073 } | |
2074 CloseHandle (fh); | |
2075 } | |
2076 else | |
2077 { | |
2078 errno = EINVAL; | |
2079 return -1; | |
2080 } | |
2081 return 0; | |
2082 #else | |
2083 return utime (filename, times); | |
2084 #endif | |
2085 } | |
2086 | |
2087 /* Close the system structures associated with the given file. */ | 2061 /* Close the system structures associated with the given file. */ |
2088 void | 2062 void |
2089 close_file_data (file_data *p_file) | 2063 close_file_data (file_data *p_file) |
2090 { | 2064 { |
2091 UnmapViewOfFile (p_file->file_base); | 2065 UnmapViewOfFile (p_file->file_base); |
2092 CloseHandle (p_file->file_mapping); | 2066 CloseHandle (p_file->file_mapping); |
2093 CloseHandle (p_file->file); | 2067 CloseHandle (p_file->file); |
2094 } | 2068 } |
2095 | 2069 |
2070 | |
2071 /* Some miscellaneous functions that are Windows specific, but not GUI | |
2072 specific (ie. are applicable in terminal or batch mode as well). */ | |
2073 | |
2074 DEFUN ("mswindows-short-file-name", Fmswindows_short_file_name, 1, 1, "", /* | |
2075 Return the short file name version (8.3) of the full path of FILENAME. | |
2076 If FILENAME does not exist, return nil. | |
2077 All path elements in FILENAME are converted to their short names. | |
2078 */ | |
2079 (filename)) | |
2080 { | |
2081 Extbyte shortname[MAX_PATH * MAX_XETCHAR_SIZE]; | |
2082 Extbyte *fileext; | |
2083 Intbyte *shortint; | |
2084 | |
2085 CHECK_STRING (filename); | |
2086 | |
2087 /* first expand it. */ | |
2088 filename = Fexpand_file_name (filename, Qnil); | |
2089 | |
2090 LISP_STRING_TO_TSTR (filename, fileext); | |
2091 /* luckily, this returns the short version of each element in the path. */ | |
2092 if (qxeGetShortPathName (fileext, shortname, | |
2093 sizeof (shortname) / XETCHAR_SIZE) == 0) | |
2094 return Qnil; | |
2095 | |
2096 TSTR_TO_C_STRING (shortname, shortint); | |
2097 MSWINDOWS_NORMALIZE_FILENAME (shortint); | |
2098 | |
2099 return build_string (shortint); | |
2100 } | |
2101 | |
2102 | |
2103 DEFUN ("mswindows-long-file-name", Fmswindows_long_file_name, 1, 1, "", /* | |
2104 Return the long file name version of the full path of FILENAME. | |
2105 If FILENAME does not exist, return nil. | |
2106 All path elements in FILENAME are converted to their long names. | |
2107 */ | |
2108 (filename)) | |
2109 { | |
2110 Intbyte *longname, *canon; | |
2111 Lisp_Object ret; | |
2112 | |
2113 CHECK_STRING (filename); | |
2114 | |
2115 /* first expand it. */ | |
2116 filename = Fexpand_file_name (filename, Qnil); | |
2117 | |
2118 if (!(longname = mswindows_get_long_filename (XSTRING_DATA (filename)))) | |
2119 return Qnil; | |
2120 | |
2121 canon = mswindows_canonicalize_filename (longname); | |
2122 ret = build_string (canon); | |
2123 xfree (canon); | |
2124 xfree (longname); | |
2125 return ret; | |
2126 } | |
2127 | |
2128 void | |
2129 syms_of_nt (void) | |
2130 { | |
2131 DEFSUBR (Fmswindows_short_file_name); | |
2132 DEFSUBR (Fmswindows_long_file_name); | |
2133 } | |
2134 | |
2096 void | 2135 void |
2097 vars_of_nt (void) | 2136 vars_of_nt (void) |
2098 { | 2137 { |
2099 DEFVAR_INT ("nt-fake-unix-uid", &nt_fake_unix_uid /* | 2138 DEFVAR_INT ("mswindows-fake-unix-uid", &mswindows_fake_unix_uid /* |
2100 *Set uid returned by `user-uid' and `user-real-uid'. | 2139 *Set uid returned by `user-uid' and `user-real-uid'. |
2101 Under NT and 9x, there is no uids, and even no almighty user called root. | 2140 Under NT and 9x, there are no uids, and even no almighty user called root. |
2102 By setting this variable, you can have any uid of choice. Default is 0. | 2141 By setting this variable, you can have any uid of choice. Default is 0. |
2103 Changes to this variable take effect immediately. | 2142 Changes to this variable take effect immediately. |
2104 */ ); | 2143 */ ); |
2105 nt_fake_unix_uid = 0; | 2144 mswindows_fake_unix_uid = 0; |
2145 | |
2146 DEFVAR_LISP ("mswindows-get-true-file-attributes", &Vmswindows_get_true_file_attributes /* | |
2147 Non-nil means determine accurate link count in file-attributes. | |
2148 This option slows down file-attributes noticeably, so is disabled by | |
2149 default. Note that it is only useful for files on NTFS volumes, | |
2150 where hard links are supported. | |
2151 */ ); | |
2152 Vmswindows_get_true_file_attributes = Qnil; | |
2106 } | 2153 } |
2107 | 2154 |
2108 /* end of nt.c */ | 2155 /* end of nt.c */ |