Mercurial > hg > xemacs-beta
annotate src/nt.c @ 5006:ecdc03ef6e12
Instantiate Ben's compile fix for nt.c
author | Vin Shelton <acs@xemacs.org> |
---|---|
date | Mon, 08 Feb 2010 20:45:21 -0500 |
parents | 44d7bde26046 |
children | 3889ef128488 308d34e9f07d |
rev | line source |
---|---|
771 | 1 /* Utility and Unix shadow routines under MS Windows (WIN32_NATIVE defined). |
428 | 2 Copyright (C) 1994, 1995 Free Software Foundation, Inc. |
2957 | 3 Copyright (C) 2000, 2001, 2002, 2004, 2005 Ben Wing. |
428 | 4 |
5 This file is part of XEmacs. | |
6 | |
7 XEmacs is free software; you can redistribute it and/or modify it | |
8 under the terms of the GNU General Public License as published by the | |
9 Free Software Foundation; either version 2, or (at your option) any | |
10 later version. | |
11 | |
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
18 along with XEmacs; see the file COPYING. If not, write to the Free | |
19 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
20 02111-1307, USA. | |
21 | |
771 | 22 */ |
428 | 23 |
771 | 24 /* Authorship: |
428 | 25 |
771 | 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. | |
2526 | 33 Synched (completely!) with Emacs 21.0.103 by Ben Wing, 6-13-01. |
771 | 34 */ |
35 | |
36 /* This file Mule-ized by Ben Wing, 6-23-00. */ | |
428 | 37 |
38 #include <config.h> | |
39 #include "lisp.h" | |
40 | |
592 | 41 #include "buffer.h" |
872 | 42 #include "process.h" |
592 | 43 |
859 | 44 #include "sysdir.h" |
45 #include "sysfile.h" | |
428 | 46 #include "sysproc.h" |
442 | 47 #include "syspwd.h" |
859 | 48 #include "syssignal.h" |
49 #include "systime.h" | |
428 | 50 |
442 | 51 #include "syswindows.h" |
428 | 52 |
771 | 53 /* Control whether stat() attempts to determine file type and link count |
54 exactly, at the expense of slower operation. Since true hard links | |
55 are supported on NTFS volumes, this is only relevant on NT. */ | |
56 Lisp_Object Vmswindows_get_true_file_attributes; | |
428 | 57 |
771 | 58 /* Vmswindows_generate_fake_inodes; deleted */ |
59 | |
60 Fixnum mswindows_fake_unix_uid; | |
428 | 61 |
62 /* Emulate getpwuid, getpwnam and others. */ | |
63 | |
771 | 64 static struct passwd the_passwd = |
428 | 65 { |
771 | 66 "", |
67 "", | |
428 | 68 0, |
69 0, | |
70 0, | |
771 | 71 "", |
72 "", | |
73 "", | |
428 | 74 }; |
75 | |
76 uid_t | |
442 | 77 getuid (void) |
440 | 78 { |
771 | 79 return mswindows_fake_unix_uid; |
428 | 80 } |
81 | |
82 uid_t | |
442 | 83 geteuid (void) |
428 | 84 { |
771 | 85 /* Emacs 20.6 says: [[I could imagine arguing for checking to see |
86 whether the user is in the Administrators group and returning a | |
87 UID of 0 for that case, but I don't know how wise that would be | |
88 in the long run.]] */ | |
89 return mswindows_fake_unix_uid; | |
428 | 90 } |
91 | |
92 gid_t | |
442 | 93 getgid (void) |
428 | 94 { |
95 return the_passwd.pw_gid; | |
96 } | |
97 | |
98 gid_t | |
442 | 99 getegid (void) |
428 | 100 { |
101 return getgid (); | |
102 } | |
103 | |
104 struct passwd * | |
105 getpwuid (uid_t uid) | |
106 { | |
771 | 107 if (uid == mswindows_fake_unix_uid) |
440 | 108 { |
109 the_passwd.pw_gid = the_passwd.pw_uid = uid; | |
110 return &the_passwd; | |
111 } | |
112 else | |
113 return NULL; | |
428 | 114 } |
115 | |
116 struct passwd * | |
867 | 117 getpwnam (const Ibyte *name) |
428 | 118 { |
119 struct passwd *pw; | |
120 | |
121 pw = getpwuid (getuid ()); | |
122 if (!pw) | |
123 return pw; | |
124 | |
1204 | 125 if (qxestrcasecmp_i18n (name, (Ibyte *) pw->pw_name)) |
428 | 126 return NULL; |
127 | |
128 return pw; | |
129 } | |
130 | |
771 | 131 static void |
442 | 132 init_user_info (void) |
428 | 133 { |
440 | 134 /* This code is pretty much of ad hoc nature. There is no unix-like |
135 UIDs under Windows NT. There is no concept of root user, because | |
136 all security is ACL-based. Instead, let's use a simple variable, | |
137 nt-fake-unix-uid, which would allow the user to have a uid of | |
138 choice. --kkm, 02/03/2000 */ | |
139 #if 0 | |
428 | 140 /* Find the user's real name by opening the process token and |
141 looking up the name associated with the user-sid in that token. | |
142 | |
143 Use the relative portion of the identifier authority value from | |
144 the user-sid as the user id value (same for group id using the | |
145 primary group sid from the process token). */ | |
146 | |
771 | 147 TOKEN_USER sidinfo; |
148 Extbyte name[256], domain[256]; | |
149 Charcount length = sizeof (name) / XETCHAR_SIZE; | |
150 Charcount dlength = sizeof (domain) / XETCHAR_SIZE; | |
151 DWORD trash; | |
152 HANDLE token = NULL; | |
153 SID_NAME_USE user_type; | |
428 | 154 |
155 if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token) | |
771 | 156 && GetTokenInformation (token, TokenUser, &sidinfo, sizeof (sidinfo), |
157 &trash) | |
158 && qxeLookupAccountSid (NULL, sidinfo.User.Sid, name, &length, | |
159 domain, &dlength, &user_type)) | |
428 | 160 { |
5000
44d7bde26046
fix compile errors, fix revert-buffer bug on binary/Latin 1 files, Mule-ize some files
Ben Wing <ben@xemacs.org>
parents:
4982
diff
changeset
|
161 the_passwd.pw_name = (CIbyte *) TSTR_TO_ITEXT_MALLOC (name); |
428 | 162 /* Determine a reasonable uid value. */ |
5000
44d7bde26046
fix compile errors, fix revert-buffer bug on binary/Latin 1 files, Mule-ize some files
Ben Wing <ben@xemacs.org>
parents:
4982
diff
changeset
|
163 if (qxestrcasecmp ((Ibyte *) the_passwd.pw_name, "administrator") == 0) |
428 | 164 { |
165 the_passwd.pw_uid = 0; | |
166 the_passwd.pw_gid = 0; | |
167 } | |
168 else | |
169 { | |
170 SID_IDENTIFIER_AUTHORITY * pSIA; | |
771 | 171 TOKEN_PRIMARY_GROUP group; |
428 | 172 |
771 | 173 pSIA = GetSidIdentifierAuthority (sidinfo.User.Sid); |
428 | 174 /* I believe the relative portion is the last 4 bytes (of 6) |
175 with msb first. */ | |
176 the_passwd.pw_uid = ((pSIA->Value[2] << 24) + | |
177 (pSIA->Value[3] << 16) + | |
178 (pSIA->Value[4] << 8) + | |
179 (pSIA->Value[5] << 0)); | |
180 /* restrict to conventional uid range for normal users */ | |
181 the_passwd.pw_uid = the_passwd.pw_uid % 60001; | |
182 | |
183 /* Get group id */ | |
184 if (GetTokenInformation (token, TokenPrimaryGroup, | |
771 | 185 &group, sizeof (group), &trash)) |
428 | 186 { |
187 SID_IDENTIFIER_AUTHORITY * pSIA; | |
188 | |
771 | 189 pSIA = GetSidIdentifierAuthority (group.PrimaryGroup); |
428 | 190 the_passwd.pw_gid = ((pSIA->Value[2] << 24) + |
191 (pSIA->Value[3] << 16) + | |
192 (pSIA->Value[4] << 8) + | |
193 (pSIA->Value[5] << 0)); | |
194 /* I don't know if this is necessary, but for safety... */ | |
195 the_passwd.pw_gid = the_passwd.pw_gid % 60001; | |
196 } | |
197 else | |
198 the_passwd.pw_gid = the_passwd.pw_uid; | |
199 } | |
200 } | |
201 /* If security calls are not supported (presumably because we | |
202 are running under Windows 95), fallback to this. */ | |
771 | 203 else if (qxeGetUserName (name, &length)) |
428 | 204 { |
5000
44d7bde26046
fix compile errors, fix revert-buffer bug on binary/Latin 1 files, Mule-ize some files
Ben Wing <ben@xemacs.org>
parents:
4982
diff
changeset
|
205 the_passwd.pw_name = (CIbyte *) TSTR_TO_ITEXT_MALLOC (name); |
44d7bde26046
fix compile errors, fix revert-buffer bug on binary/Latin 1 files, Mule-ize some files
Ben Wing <ben@xemacs.org>
parents:
4982
diff
changeset
|
206 if (qxestrcasecmp_ascii ((Ibyte *) the_passwd.pw_name, |
44d7bde26046
fix compile errors, fix revert-buffer bug on binary/Latin 1 files, Mule-ize some files
Ben Wing <ben@xemacs.org>
parents:
4982
diff
changeset
|
207 "administrator") == 0) |
428 | 208 the_passwd.pw_uid = 0; |
209 else | |
210 the_passwd.pw_uid = 123; | |
211 the_passwd.pw_gid = the_passwd.pw_uid; | |
212 } | |
213 else | |
214 { | |
771 | 215 the_passwd.pw_name = "unknown"; |
428 | 216 the_passwd.pw_uid = 123; |
217 the_passwd.pw_gid = 123; | |
218 } | |
219 | |
440 | 220 if (token) |
221 CloseHandle (token); | |
222 #else | |
223 /* Obtain only logon id here, uid part is moved to getuid */ | |
771 | 224 DWORD length = UNLEN + 1; |
225 Extbyte name[MAX_XETCHAR_SIZE * (UNLEN + 1)]; | |
226 if (qxeGetUserName (name, &length)) | |
5000
44d7bde26046
fix compile errors, fix revert-buffer bug on binary/Latin 1 files, Mule-ize some files
Ben Wing <ben@xemacs.org>
parents:
4982
diff
changeset
|
227 the_passwd.pw_name = (CIbyte *) TSTR_TO_ITEXT_MALLOC (name); |
440 | 228 else |
771 | 229 the_passwd.pw_name = "unknown"; |
440 | 230 #endif |
231 | |
771 | 232 #if 0 |
428 | 233 /* Ensure HOME and SHELL are defined. */ |
234 /* | |
235 * With XEmacs, setting $HOME is deprecated. | |
236 */ | |
771 | 237 if (egetenv ("HOME") == NULL) |
238 eputenv ("HOME=c:/"); | |
428 | 239 #endif |
240 | |
611 | 241 /* Set dir from environment variables. */ |
5000
44d7bde26046
fix compile errors, fix revert-buffer bug on binary/Latin 1 files, Mule-ize some files
Ben Wing <ben@xemacs.org>
parents:
4982
diff
changeset
|
242 the_passwd.pw_dir = (CIbyte *) qxestrdup (get_home_directory ()); |
611 | 243 /* We used to set pw_shell here, but the order is wrong (SHELL gets |
853 | 244 initted in process.c, called later in the init process) and pw_shell |
611 | 245 is not used anywhere. */ |
428 | 246 } |
247 | |
771 | 248 /* Parse the root part of file name, if present. Return length and |
867 | 249 optionally store pointer to Ibyte after root. */ |
771 | 250 static Bytecount |
867 | 251 parse_root (Ibyte *name, Ibyte **pPath) |
428 | 252 { |
867 | 253 Ibyte *start = name; |
428 | 254 |
255 if (name == NULL) | |
256 return 0; | |
257 | |
258 /* find the root name of the volume if given */ | |
259 if (isalpha (name[0]) && name[1] == ':') | |
260 { | |
261 /* skip past drive specifier */ | |
262 name += 2; | |
263 if (IS_DIRECTORY_SEP (name[0])) | |
264 name++; | |
265 } | |
266 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1])) | |
267 { | |
268 int slashes = 2; | |
269 name += 2; | |
270 do | |
271 { | |
272 if (IS_DIRECTORY_SEP (*name) && --slashes == 0) | |
273 break; | |
274 name++; | |
275 } | |
771 | 276 while (*name); |
428 | 277 if (IS_DIRECTORY_SEP (name[0])) |
278 name++; | |
279 } | |
280 | |
281 if (pPath) | |
282 *pPath = name; | |
283 | |
284 return name - start; | |
285 } | |
286 | |
287 /* Get long base name for name; name is assumed to be absolute. */ | |
867 | 288 static Ibyte * |
289 get_long_basename (Ibyte *name) | |
428 | 290 { |
771 | 291 WIN32_FIND_DATAW find_data; |
428 | 292 HANDLE dir_handle; |
771 | 293 Extbyte *nameext; |
428 | 294 |
771 | 295 /* must be valid filename, no wild cards or other invalid characters */ |
296 if (qxestrpbrk (name, "*?|<>\"")) | |
297 return 0; | |
428 | 298 |
2526 | 299 PATHNAME_CONVERT_OUT (name, nameext); |
771 | 300 dir_handle = qxeFindFirstFile (nameext, &find_data); |
428 | 301 if (dir_handle != INVALID_HANDLE_VALUE) |
302 { | |
867 | 303 Ibyte *fileint; |
771 | 304 |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
305 fileint = TSTR_TO_ITEXT_MALLOC (find_data.cFileName); |
428 | 306 FindClose (dir_handle); |
771 | 307 return fileint; |
428 | 308 } |
771 | 309 return 0; |
428 | 310 } |
311 | |
312 /* Get long name for file, if possible (assumed to be absolute). */ | |
867 | 313 Ibyte * |
314 mswindows_get_long_filename (Ibyte *name) | |
428 | 315 { |
867 | 316 Ibyte *full = mswindows_canonicalize_filename (name); |
317 Ibyte *p; | |
318 Ibyte *q; | |
771 | 319 DECLARE_EISTRING (o); |
320 Bytecount len; | |
428 | 321 |
322 /* Copy root part verbatim. */ | |
323 len = parse_root (full, &p); | |
771 | 324 eicpy_raw (o, full, len); |
428 | 325 |
771 | 326 while (p != NULL && *p) |
428 | 327 { |
867 | 328 Ibyte *component; |
771 | 329 |
428 | 330 q = p; |
771 | 331 p = qxestrchr (q, '\\'); |
428 | 332 if (p) *p = '\0'; |
771 | 333 component = get_long_basename (full); |
334 if (component) | |
428 | 335 { |
771 | 336 eicat_rawz (o, component); |
428 | 337 if (p != NULL) |
338 { | |
339 *p++ = '\\'; | |
771 | 340 eicat_ch (o, '\\'); |
428 | 341 } |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
342 xfree (component); |
428 | 343 } |
344 else | |
771 | 345 { |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
346 xfree (full); |
771 | 347 return 0; |
348 } | |
428 | 349 } |
350 | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
351 xfree (full); |
771 | 352 return eicpyout_malloc (o, 0); |
428 | 353 } |
354 | |
771 | 355 static int |
867 | 356 is_unc_volume (const Ibyte *filename) |
771 | 357 { |
867 | 358 const Ibyte *ptr = filename; |
428 | 359 |
771 | 360 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2]) |
361 return 0; | |
362 | |
363 if (qxestrpbrk (ptr + 2, "*?|<>\"\\/")) | |
364 return 0; | |
365 | |
366 return 1; | |
428 | 367 } |
368 | |
771 | 369 /* NOTE: Value returned is still in external format. Callers need to |
370 convert. */ | |
707 | 371 #define REG_ROOT "SOFTWARE\\XEmacs\\XEmacs" |
428 | 372 |
771 | 373 static LPBYTE |
867 | 374 nt_get_resource (Ibyte *key, LPDWORD lpdwtype) |
428 | 375 { |
376 LPBYTE lpvalue; | |
377 HKEY hrootkey = NULL; | |
378 DWORD cbData; | |
771 | 379 Extbyte *keyext; |
380 | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
381 keyext = ITEXT_TO_TSTR (key); |
428 | 382 |
383 /* Check both the current user and the local machine to see if | |
384 we have any resources. */ | |
385 | |
771 | 386 if (qxeRegOpenKeyEx (HKEY_CURRENT_USER, XETEXT (REG_ROOT), 0, KEY_READ, |
387 &hrootkey) == ERROR_SUCCESS) | |
428 | 388 { |
389 lpvalue = NULL; | |
390 | |
771 | 391 if (qxeRegQueryValueEx (hrootkey, keyext, NULL, NULL, NULL, |
392 &cbData) == ERROR_SUCCESS | |
2367 | 393 && (lpvalue = xnew_array (BYTE, cbData)) != NULL |
771 | 394 && qxeRegQueryValueEx (hrootkey, keyext, NULL, lpdwtype, lpvalue, |
395 &cbData) == ERROR_SUCCESS) | |
396 return (lpvalue); | |
428 | 397 |
1726 | 398 if (lpvalue) |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
399 xfree (lpvalue); |
428 | 400 |
401 RegCloseKey (hrootkey); | |
402 } | |
403 | |
771 | 404 if (qxeRegOpenKeyEx (HKEY_LOCAL_MACHINE, XETEXT (REG_ROOT), 0, KEY_READ, |
405 &hrootkey) == ERROR_SUCCESS) | |
428 | 406 { |
407 lpvalue = NULL; | |
408 | |
771 | 409 if (qxeRegQueryValueEx (hrootkey, keyext, NULL, NULL, NULL, |
410 &cbData) == ERROR_SUCCESS && | |
2367 | 411 (lpvalue = xnew_array (BYTE, cbData)) != NULL && |
771 | 412 qxeRegQueryValueEx (hrootkey, keyext, NULL, lpdwtype, lpvalue, |
413 &cbData) == ERROR_SUCCESS) | |
414 return (lpvalue); | |
428 | 415 |
1726 | 416 if (lpvalue) |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
417 xfree (lpvalue); |
428 | 418 |
419 RegCloseKey (hrootkey); | |
420 } | |
421 | |
422 return (NULL); | |
423 } | |
424 | |
425 void | |
814 | 426 init_mswindows_environment (void) |
428 | 427 { |
428 /* Check for environment variables and use registry if they don't exist */ | |
771 | 429 /* Emacs 20.6 sets default values for these; not necessary here because |
430 we already supply them. (except SHELL, which is set in init_user_info().) | |
431 Emacs 20.6 messes with TMPDIR; not necessary here. */ | |
428 | 432 { |
433 int i; | |
434 LPBYTE lpval; | |
435 DWORD dwType; | |
436 | |
2367 | 437 static Ascbyte *env_vars[] = |
428 | 438 { |
439 "HOME", | |
440 "EMACSLOADPATH", | |
441 "EMACSDEBUGPATHS", | |
442 "SHELL", | |
443 "CMDPROXY", | |
444 "EMACSDATA", | |
445 "EMACSPATH", | |
446 "EMACSPACKAGEPATH", | |
3179 | 447 "EMACSEARLYPACKAGES", |
448 "EMACSLATEPACKAGES", | |
449 "EMACSLASTPACKAGES", | |
771 | 450 "EMACSLOCKMETHOD", |
428 | 451 "INFOPATH" |
452 }; | |
771 | 453 #if defined (HEAP_IN_DATA) && !defined (PDUMP) |
430 | 454 cache_system_info (); |
455 #endif | |
771 | 456 |
457 #if 0 /* FSF 21.1 */ | |
458 /* !!#### i think i already do the equivalent elsewhere. | |
459 delete when i'm sure i do. | |
460 (but maybe i should be playing with LANG when the user changes | |
461 the locale, so that subprocesses get it right.) */ | |
462 /* Get default locale info and use it for LANG. */ | |
463 if (GetLocaleInfo (LOCALE_USER_DEFAULT, | |
464 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP, | |
465 locale_name, sizeof (locale_name))) | |
466 { | |
467 for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++) | |
468 { | |
469 if (strcmp (env_vars[i].name, "LANG") == 0) | |
470 { | |
471 env_vars[i].def_value = locale_name; | |
472 break; | |
473 } | |
474 } | |
475 } | |
476 #endif /* 0 */ | |
477 | |
428 | 478 for (i = 0; i < countof (env_vars); i++) |
479 { | |
771 | 480 if (!egetenv (env_vars[i]) && |
1204 | 481 (lpval = nt_get_resource ((Ibyte *) env_vars[i], &dwType)) != NULL) |
428 | 482 { |
483 if (dwType == REG_EXPAND_SZ) | |
484 { | |
771 | 485 Extbyte *buf = NULL; |
867 | 486 Ibyte *envval; |
771 | 487 Charcount cch; |
428 | 488 |
771 | 489 cch = qxeExpandEnvironmentStrings ((Extbyte *) lpval, buf, 0); |
2367 | 490 buf = alloca_extbytes (cch * XETCHAR_SIZE); |
771 | 491 qxeExpandEnvironmentStrings ((Extbyte *) lpval, buf, cch); |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
492 envval = TSTR_TO_ITEXT (buf); |
1204 | 493 eputenv (env_vars[i], (CIbyte *) envval); |
428 | 494 } |
495 else if (dwType == REG_SZ) | |
496 { | |
867 | 497 Ibyte *envval; |
771 | 498 |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
499 envval = TSTR_TO_ITEXT (lpval); |
1204 | 500 eputenv (env_vars[i], (CIbyte *) envval); |
428 | 501 } |
502 | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
503 xfree (lpval); |
428 | 504 } |
505 } | |
506 } | |
507 | |
508 /* Another special case: on NT, the PATH variable is actually named | |
509 "Path" although cmd.exe (perhaps NT itself) arranges for | |
510 environment variable lookup and setting to be case insensitive. | |
511 However, Emacs assumes a fully case sensitive environment, so we | |
512 need to change "Path" to "PATH" to match the expectations of | |
771 | 513 various elisp packages. |
428 | 514 |
515 The same applies to COMSPEC. */ | |
516 { | |
2367 | 517 EXTERNAL_LIST_LOOP_2 (str, Vprocess_environment) |
771 | 518 { |
519 if (STRINGP (str)) | |
520 { | |
867 | 521 Ibyte *dat = XSTRING_DATA (str); |
2367 | 522 if (qxestrncasecmp_ascii (dat, "PATH=", 5) == 0) |
771 | 523 memcpy (dat, "PATH=", 5); |
2367 | 524 else if (qxestrncasecmp_ascii (dat, "COMSPEC=", 8) == 0) |
771 | 525 memcpy (dat, "COMSPEC=", 8); |
526 } | |
527 } | |
428 | 528 } |
529 | |
530 init_user_info (); | |
531 } | |
532 | |
771 | 533 /* Emacs 20.6 contains a routine get_emacs_configuration() here to set |
534 EMACS_CONFIGURATION. */ | |
428 | 535 #ifndef HAVE_X_WINDOWS |
536 /* X11R6 on NT provides the single parameter version of this command. */ | |
537 | |
538 #include <sys/timeb.h> | |
539 | |
540 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */ | |
541 void | |
542 gettimeofday (struct timeval *tv, struct timezone *tz) | |
543 { | |
544 struct _timeb tb; | |
545 _ftime (&tb); | |
546 | |
547 tv->tv_sec = tb.time; | |
548 tv->tv_usec = tb.millitm * 1000L; | |
549 if (tz) | |
550 { | |
551 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */ | |
552 tz->tz_dsttime = tb.dstflag; /* type of dst correction */ | |
553 } | |
554 } | |
555 | |
556 #endif /* HAVE_X_WINDOWS */ | |
557 | |
771 | 558 |
428 | 559 /* ------------------------------------------------------------------------- */ |
771 | 560 /* IO support and wrapper functions for Win32 API. */ |
428 | 561 /* ------------------------------------------------------------------------- */ |
562 | |
771 | 563 typedef struct volume_info_data |
428 | 564 { |
771 | 565 struct volume_info_data *next; |
428 | 566 |
567 /* time when info was obtained */ | |
771 | 568 DWORD timestamp; |
428 | 569 |
570 /* actual volume info */ | |
867 | 571 Ibyte *root_dir; |
771 | 572 DWORD serialnum; |
573 DWORD maxcomp; | |
574 DWORD flags; | |
867 | 575 Ibyte *name; |
576 Ibyte *type; | |
428 | 577 } volume_info_data; |
578 | |
579 /* Global referenced by various functions. */ | |
580 static volume_info_data volume_info; | |
581 | |
582 /* Vector to indicate which drives are local and fixed (for which cached | |
583 data never expires). */ | |
584 static BOOL fixed_drives[26]; | |
585 | |
586 /* Consider cached volume information to be stale if older than 10s, | |
587 at least for non-local drives. Info for fixed drives is never stale. */ | |
588 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' ) | |
589 #define VOLINFO_STILL_VALID( root_dir, info ) \ | |
590 ( ( isalpha (root_dir[0]) && \ | |
591 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \ | |
592 || GetTickCount () - info->timestamp < 10000 ) | |
593 | |
594 /* Cache support functions. */ | |
595 | |
596 /* Simple linked list with linear search is sufficient. */ | |
597 static volume_info_data *volume_cache = NULL; | |
598 | |
599 static volume_info_data * | |
867 | 600 lookup_volume_info (Ibyte *root_dir) |
428 | 601 { |
771 | 602 volume_info_data *info; |
428 | 603 |
604 for (info = volume_cache; info; info = info->next) | |
771 | 605 if (qxestrcasecmp_i18n (info->root_dir, root_dir) == 0) |
428 | 606 break; |
607 return info; | |
608 } | |
609 | |
610 static void | |
867 | 611 add_volume_info (Ibyte *root_dir, volume_info_data *info) |
428 | 612 { |
771 | 613 info->root_dir = qxestrdup (root_dir); |
428 | 614 info->next = volume_cache; |
615 volume_cache = info; | |
616 } | |
617 | |
618 | |
619 /* Wrapper for GetVolumeInformation, which uses caching to avoid | |
620 performance penalty (~2ms on 486 for local drives, 7.5ms for local | |
621 cdrom drive, ~5-10ms or more for remote drives on LAN). */ | |
771 | 622 static volume_info_data * |
867 | 623 get_cached_volume_information (Ibyte *root_dir) |
428 | 624 { |
771 | 625 volume_info_data *info; |
867 | 626 Ibyte *default_root; |
428 | 627 |
628 /* NULL for root_dir means use root from current directory. */ | |
629 if (root_dir == NULL) | |
630 { | |
771 | 631 Charcount nchars = qxeGetCurrentDirectory (0, NULL); |
632 Extbyte *rootext; | |
633 | |
634 if (!nchars) | |
428 | 635 return NULL; |
771 | 636 rootext = alloca_extbytes (nchars * XETCHAR_SIZE); |
637 if (!qxeGetCurrentDirectory (nchars, rootext)) | |
638 return NULL; | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
639 default_root = TSTR_TO_ITEXT (rootext); |
428 | 640 parse_root (default_root, &root_dir); |
641 *root_dir = 0; | |
642 root_dir = default_root; | |
643 } | |
644 | |
645 /* Local fixed drives can be cached permanently. Removable drives | |
646 cannot be cached permanently, since the volume name and serial | |
647 number (if nothing else) can change. Remote drives should be | |
648 treated as if they are removable, since there is no sure way to | |
649 tell whether they are or not. Also, the UNC association of drive | |
650 letters mapped to remote volumes can be changed at any time (even | |
651 by other processes) without notice. | |
652 | |
653 As a compromise, so we can benefit from caching info for remote | |
654 volumes, we use a simple expiry mechanism to invalidate cache | |
655 entries that are more than ten seconds old. */ | |
656 | |
657 #if 0 | |
658 /* No point doing this, because WNetGetConnection is even slower than | |
659 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW, | |
660 GetDriveType is about the only call of this type which does not | |
661 involve network access, and so is extremely quick). */ | |
662 | |
663 /* Map drive letter to UNC if remote. */ | |
771 | 664 if (isalpha (root_dir[0]) && !fixed [DRIVE_INDEX (root_dir[0])]) |
428 | 665 { |
771 | 666 Extbyte remote_name[256 * XETCHAR_SIZE]; |
867 | 667 Ibyte drive[3] = { root_dir[0], ':' }; |
771 | 668 Extbyte *driveext; |
428 | 669 |
2526 | 670 PATHNAME_CONVERT_OUT (drive, driveext); |
771 | 671 if (qxeWNetGetConnection (driveext, remote_name, |
672 sizeof (remote_name) / XETCHAR_SIZE) | |
428 | 673 == NO_ERROR) |
674 /* do something */ ; | |
675 } | |
676 #endif | |
677 | |
678 info = lookup_volume_info (root_dir); | |
679 | |
680 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info)) | |
771 | 681 { |
682 Extbyte name[256 * MAX_XETCHAR_SIZE]; | |
683 DWORD serialnum; | |
684 DWORD maxcomp; | |
685 DWORD flags; | |
686 Extbyte type[256 * MAX_XETCHAR_SIZE]; | |
1204 | 687 Extbyte *rootdirext; |
688 | |
2526 | 689 PATHNAME_CONVERT_OUT (root_dir, rootdirext); |
428 | 690 |
771 | 691 /* Info is not cached, or is stale. */ |
1204 | 692 if (!qxeGetVolumeInformation (rootdirext, |
771 | 693 name, sizeof (name) / XETCHAR_SIZE, |
694 &serialnum, | |
695 &maxcomp, | |
696 &flags, | |
697 type, sizeof (type) / XETCHAR_SIZE)) | |
698 return NULL; | |
428 | 699 |
771 | 700 /* Cache the volume information for future use, overwriting existing |
701 entry if present. */ | |
702 if (info == NULL) | |
703 { | |
2367 | 704 info = xnew (volume_info_data); |
771 | 705 add_volume_info (root_dir, info); |
706 } | |
707 else | |
708 { | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
709 xfree (info->name); |
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
710 xfree (info->type); |
771 | 711 } |
428 | 712 |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
713 info->name = TSTR_TO_ITEXT_MALLOC (name); |
771 | 714 info->serialnum = serialnum; |
715 info->maxcomp = maxcomp; | |
716 info->flags = flags; | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
717 info->type = TSTR_TO_ITEXT_MALLOC (type); |
771 | 718 info->timestamp = GetTickCount (); |
719 } | |
428 | 720 |
721 return info; | |
722 } | |
723 | |
724 /* Get information on the volume where name is held; set path pointer to | |
725 start of pathname in name (past UNC header\volume header if present). */ | |
771 | 726 static int |
867 | 727 get_volume_info (const Ibyte *name, const Ibyte **pPath) |
428 | 728 { |
771 | 729 /* We probably only need a couple of bytes, but let's be generous in |
730 case this function gets changed */ | |
2367 | 731 Ibyte *temp = alloca_ibytes (qxestrlen (name) + 10); |
867 | 732 Ibyte *rootname = NULL; /* default to current volume */ |
771 | 733 volume_info_data *info; |
428 | 734 |
735 if (name == NULL) | |
736 return FALSE; | |
737 | |
738 /* find the root name of the volume if given */ | |
739 if (isalpha (name[0]) && name[1] == ':') | |
740 { | |
741 rootname = temp; | |
742 temp[0] = *name++; | |
743 temp[1] = *name++; | |
744 temp[2] = '\\'; | |
745 temp[3] = 0; | |
746 } | |
747 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1])) | |
748 { | |
867 | 749 Ibyte *str = temp; |
428 | 750 int slashes = 4; |
751 rootname = temp; | |
752 do | |
753 { | |
754 if (IS_DIRECTORY_SEP (*name) && --slashes == 0) | |
755 break; | |
756 *str++ = *name++; | |
757 } | |
771 | 758 while (*name); |
428 | 759 |
760 *str++ = '\\'; | |
761 *str = 0; | |
762 } | |
763 | |
764 if (pPath) | |
765 *pPath = name; | |
766 | |
771 | 767 info = get_cached_volume_information (rootname); |
428 | 768 if (info != NULL) |
769 { | |
770 /* Set global referenced by other functions. */ | |
771 volume_info = *info; | |
772 return TRUE; | |
773 } | |
774 return FALSE; | |
775 } | |
776 | |
771 | 777 /* XEmacs: Everything referring to map_win32_filename() aka map_w32_filename() |
778 removed; it was only for NT 3.1, which we hereby do not support. (NT 3.5 | |
779 predates Windows 95!) */ | |
428 | 780 |
1204 | 781 int |
782 mswindows_is_executable (const Ibyte *name) | |
771 | 783 { |
867 | 784 Ibyte *p = qxestrrchr (name, '.'); |
2367 | 785 return (p != NULL && (qxestrcasecmp_ascii (p, ".exe") == 0 || |
786 qxestrcasecmp_ascii (p, ".com") == 0 || | |
787 qxestrcasecmp_ascii (p, ".bat") == 0 || | |
788 qxestrcasecmp_ascii (p, ".cmd") == 0)); | |
428 | 789 } |
790 | |
791 /* Emulate the Unix directory procedures opendir, closedir, | |
792 and readdir. We can't use the procedures supplied in sysdep.c, | |
793 so we provide them here. */ | |
794 | |
795 struct direct dir_static; /* simulated directory contents */ | |
796 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE; | |
771 | 797 /* dir_is_fat deleted */ |
867 | 798 static Ibyte *dir_pathname; |
771 | 799 static WIN32_FIND_DATAW dir_find_data; |
800 | |
801 /* Support shares on a network resource as subdirectories of a read-only | |
802 root directory. */ | |
803 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE; | |
867 | 804 static HANDLE open_unc_volume (const Ibyte *); |
805 static Ibyte *read_unc_volume (HANDLE); | |
771 | 806 static int close_unc_volume (HANDLE); |
428 | 807 |
808 DIR * | |
867 | 809 mswindows_opendir (const Ibyte *filename) |
428 | 810 { |
811 DIR *dirp; | |
812 | |
813 /* Opening is done by FindFirstFile. However, a read is inherent to | |
814 this operation, so we defer the open until read time. */ | |
815 | |
771 | 816 if (dir_find_handle != INVALID_HANDLE_VALUE) |
428 | 817 return NULL; |
771 | 818 if (wnet_enum_handle != INVALID_HANDLE_VALUE) |
428 | 819 return NULL; |
820 | |
771 | 821 if (is_unc_volume (filename)) |
822 { | |
823 wnet_enum_handle = open_unc_volume (filename); | |
824 if (wnet_enum_handle == INVALID_HANDLE_VALUE) | |
825 return NULL; | |
826 } | |
428 | 827 |
771 | 828 if (!(dirp = xnew_and_zero (DIR))) |
829 return NULL; | |
830 | |
831 if (dir_pathname) | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
832 xfree (dir_pathname); |
771 | 833 dir_pathname = qxestrdup (filename); |
428 | 834 |
835 return dirp; | |
836 } | |
837 | |
442 | 838 int |
771 | 839 mswindows_closedir (DIR *dirp) |
428 | 840 { |
2957 | 841 int retval = -1; |
442 | 842 |
428 | 843 /* If we have a find-handle open, close it. */ |
844 if (dir_find_handle != INVALID_HANDLE_VALUE) | |
845 { | |
771 | 846 retval = FindClose (dir_find_handle) ? 0 : -1; |
428 | 847 dir_find_handle = INVALID_HANDLE_VALUE; |
848 } | |
771 | 849 else if (wnet_enum_handle != INVALID_HANDLE_VALUE) |
850 { | |
851 retval = close_unc_volume (wnet_enum_handle); | |
852 wnet_enum_handle = INVALID_HANDLE_VALUE; | |
853 } | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
854 xfree (dirp); |
771 | 855 |
856 return retval; | |
857 } | |
858 | |
859 struct direct * | |
2286 | 860 mswindows_readdir (DIR *UNUSED (dirp)) |
771 | 861 { |
867 | 862 Ibyte *val; |
771 | 863 int need_to_free = 0; |
864 | |
865 if (wnet_enum_handle != INVALID_HANDLE_VALUE) | |
866 { | |
867 if (!(val = read_unc_volume (wnet_enum_handle))) | |
868 return NULL; | |
869 need_to_free = 1; | |
870 } | |
871 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */ | |
872 else if (dir_find_handle == INVALID_HANDLE_VALUE) | |
873 { | |
874 DECLARE_EISTRING (filename); | |
867 | 875 Ichar lastch; |
2526 | 876 Extbyte *fileext; |
771 | 877 |
878 eicpy_rawz (filename, dir_pathname); | |
879 lastch = eigetch_char (filename, eicharlen (filename) - 1); | |
880 if (!IS_DIRECTORY_SEP (lastch)) | |
881 eicat_ch (filename, '\\'); | |
882 eicat_ch (filename, '*'); | |
2526 | 883 PATHNAME_CONVERT_OUT (eidata (filename), fileext); |
771 | 884 |
2526 | 885 dir_find_handle = qxeFindFirstFile (fileext, &dir_find_data); |
771 | 886 |
887 if (dir_find_handle == INVALID_HANDLE_VALUE) | |
888 return NULL; | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
889 val = TSTR_TO_ITEXT (dir_find_data.cFileName); |
771 | 890 } |
891 else | |
892 { | |
893 if (!qxeFindNextFile (dir_find_handle, &dir_find_data)) | |
894 return NULL; | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
895 val = TSTR_TO_ITEXT (dir_find_data.cFileName); |
771 | 896 } |
897 | |
898 /* XEmacs never uses this value, so don't bother making it match | |
899 value returned by qxe_stat(). */ | |
900 dir_static.d_ino = 1; | |
901 | |
902 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 + | |
903 dir_static.d_namlen - dir_static.d_namlen % 4; | |
904 | |
905 { | |
906 DECLARE_EISTRING (found); | |
907 Bytecount namlen; | |
908 | |
2526 | 909 if (mswindows_shortcuts_are_symlinks) |
910 { | |
911 int len = qxestrlen (val); | |
912 if (len > 4 && !qxestrcasecmp_ascii (val + len - 4, ".LNK")) | |
913 { | |
914 /* If we've found a valid link, then chop off the .LNK ending */ | |
915 DECLARE_EISTRING (linkname); | |
916 Ichar lastch; | |
917 Ibyte *resolved; | |
918 | |
919 /* First check if link is valid */ | |
920 PATHNAME_RESOLVE_LINKS (dir_pathname, resolved); | |
921 eicpy_rawz (linkname, resolved); | |
922 lastch = eigetch_char (linkname, eicharlen (linkname) - 1); | |
923 if (!IS_DIRECTORY_SEP (lastch)) | |
924 eicat_ch (linkname, '\\'); | |
925 eicat_rawz (linkname, val); | |
926 resolved = mswindows_read_link (eidata (linkname)); | |
927 if (resolved) | |
928 { | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
929 xfree (resolved); |
2526 | 930 len -= 4; |
931 val[len] = '\0'; | |
932 } | |
933 } | |
934 } | |
935 | |
771 | 936 eicpy_rawz (found, val); |
937 if (need_to_free) | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
938 xfree (val); |
771 | 939 |
940 if (!NILP (Vmswindows_downcase_file_names)) | |
941 eilwr (found); | |
942 | |
943 namlen = min (eilen (found), sizeof (dir_static.d_name) - 1); | |
5000
44d7bde26046
fix compile errors, fix revert-buffer bug on binary/Latin 1 files, Mule-ize some files
Ben Wing <ben@xemacs.org>
parents:
4982
diff
changeset
|
944 qxestrncpy ((Ibyte *) dir_static.d_name, eidata (found), namlen); |
771 | 945 dir_static.d_name[namlen] = '\0'; |
946 dir_static.d_namlen = (unsigned short) namlen; | |
947 } | |
948 | |
949 return &dir_static; | |
950 } | |
951 | |
952 static HANDLE | |
867 | 953 open_unc_volume (const Ibyte *path) |
771 | 954 { |
955 NETRESOURCEW nr; | |
956 HANDLE henum; | |
957 int result; | |
5000
44d7bde26046
fix compile errors, fix revert-buffer bug on binary/Latin 1 files, Mule-ize some files
Ben Wing <ben@xemacs.org>
parents:
4982
diff
changeset
|
958 Extbyte *extpath; |
771 | 959 |
960 nr.dwScope = RESOURCE_GLOBALNET; | |
961 nr.dwType = RESOURCETYPE_DISK; | |
962 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER; | |
963 nr.dwUsage = RESOURCEUSAGE_CONTAINER; | |
964 nr.lpLocalName = NULL; | |
5000
44d7bde26046
fix compile errors, fix revert-buffer bug on binary/Latin 1 files, Mule-ize some files
Ben Wing <ben@xemacs.org>
parents:
4982
diff
changeset
|
965 PATHNAME_CONVERT_OUT (path, extpath); |
5006
ecdc03ef6e12
Instantiate Ben's compile fix for nt.c
Vin Shelton <acs@xemacs.org>
parents:
5000
diff
changeset
|
966 nr.lpRemoteName = (XELPTSTR) extpath; |
771 | 967 nr.lpComment = NULL; |
968 nr.lpProvider = NULL; | |
969 | |
970 result = qxeWNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK, | |
971 RESOURCEUSAGE_CONNECTABLE, &nr, &henum); | |
972 | |
973 if (result == NO_ERROR) | |
974 return henum; | |
975 else | |
976 return INVALID_HANDLE_VALUE; | |
977 } | |
978 | |
867 | 979 static Ibyte * |
2286 | 980 read_unc_volume (HANDLE UNUSED (henum)) |
771 | 981 { |
1204 | 982 DWORD count; |
771 | 983 int result; |
984 Extbyte buf[16384]; | |
867 | 985 Ibyte *ptr; |
1204 | 986 DWORD bufsize = sizeof (buf); |
771 | 987 |
988 count = 1; | |
989 /* #### we should just be querying the size and then allocating the | |
990 right amount, like for all similar API's. but the docs say this ?! | |
991 | |
992 An application cannot set the lpBuffer parameter to NULL and | |
993 retrieve the required buffer size from the lpBufferSize | |
994 parameter. Instead, the application should allocate a buffer of a | |
995 reasonable size -- 16 kilobytes (K) is typical -- and use the value | |
996 of lpBufferSize for error detection. | |
997 */ | |
998 | |
999 result = qxeWNetEnumResource (wnet_enum_handle, &count, buf, &bufsize); | |
1000 if (result != NO_ERROR) | |
1001 return NULL; | |
1002 | |
1003 /* WNetEnumResource returns \\resource\share...skip forward to "share". */ | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
1004 ptr = TSTR_TO_ITEXT (((LPNETRESOURCEW) buf)->lpRemoteName); |
867 | 1005 INC_IBYTEPTR (ptr); |
1006 INC_IBYTEPTR (ptr); | |
1007 while (*ptr && !IS_DIRECTORY_SEP (itext_ichar (ptr))) | |
1008 INC_IBYTEPTR (ptr); | |
1009 INC_IBYTEPTR (ptr); | |
771 | 1010 |
1011 return qxestrdup (ptr); | |
1012 } | |
1013 | |
1014 static int | |
1015 close_unc_volume (HANDLE henum) | |
1016 { | |
1017 if (henum != INVALID_HANDLE_VALUE) | |
1018 return WNetCloseEnum (henum) == NO_ERROR ? 0 : -1; | |
442 | 1019 else |
1020 return -1; | |
428 | 1021 } |
1022 | |
771 | 1023 static DWORD |
867 | 1024 unc_volume_file_attributes (const Ibyte *path) |
428 | 1025 { |
771 | 1026 HANDLE henum; |
1027 DWORD attrs; | |
1028 | |
1029 henum = open_unc_volume (path); | |
1030 if (henum == INVALID_HANDLE_VALUE) | |
1031 return -1; | |
1032 | |
1033 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY; | |
1034 | |
1035 close_unc_volume (henum); | |
428 | 1036 |
771 | 1037 return attrs; |
1038 } | |
1039 | |
1040 int | |
867 | 1041 mswindows_access (const Ibyte *path, int mode) |
771 | 1042 { |
1043 DWORD attributes; | |
428 | 1044 |
771 | 1045 /* MSVC implementation doesn't recognize D_OK. */ |
1046 if (is_unc_volume (path)) | |
1047 { | |
1048 attributes = unc_volume_file_attributes (path); | |
1049 if (attributes == -1) | |
1050 { | |
1051 errno = EACCES; | |
1052 return -1; | |
1053 } | |
428 | 1054 } |
1055 else | |
1056 { | |
771 | 1057 Extbyte *pathext; |
1058 | |
2526 | 1059 PATHNAME_CONVERT_OUT (path, pathext); |
771 | 1060 if ((attributes = qxeGetFileAttributes (pathext)) == -1) |
1061 { | |
1062 /* Should try mapping GetLastError to errno; for now just indicate | |
1063 that path doesn't exist. */ | |
1064 errno = EACCES; | |
1065 return -1; | |
1066 } | |
428 | 1067 } |
1204 | 1068 if ((mode & X_OK) != 0 && !mswindows_is_executable (path)) |
771 | 1069 { |
1070 errno = EACCES; | |
1071 return -1; | |
1072 } | |
1073 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0) | |
428 | 1074 { |
771 | 1075 errno = EACCES; |
1076 return -1; | |
428 | 1077 } |
771 | 1078 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) |
1079 { | |
1080 errno = EACCES; | |
1081 return -1; | |
1082 } | |
1083 return 0; | |
428 | 1084 } |
1085 | |
771 | 1086 /* This only works on NTFS volumes, but is useful to have. */ |
1087 /* #### NT 5.0 has a function CreateHardLink to do this directly, | |
1088 and it may do more things. */ | |
428 | 1089 int |
2957 | 1090 mswindows_link (const Ibyte *old, const Ibyte *new_) |
428 | 1091 { |
771 | 1092 HANDLE fileh; |
1093 int result = -1; | |
1204 | 1094 Extbyte *oldext; |
771 | 1095 |
2957 | 1096 if (old == NULL || new_ == NULL) |
771 | 1097 { |
1098 errno = ENOENT; | |
1099 return -1; | |
1100 } | |
1101 | |
2526 | 1102 PATHNAME_CONVERT_OUT (old, oldext); |
1204 | 1103 fileh = qxeCreateFile (oldext, 0, 0, NULL, OPEN_EXISTING, |
771 | 1104 FILE_FLAG_BACKUP_SEMANTICS, NULL); |
1105 if (fileh != INVALID_HANDLE_VALUE) | |
1106 { | |
1107 int wlen; | |
1108 WCHAR *newuni; | |
1109 | |
1110 /* Confusingly, the "alternate" stream name field does not apply | |
1111 when restoring a hard link, and instead contains the actual | |
1112 stream data for the link (ie. the name of the link to create). | |
1113 The WIN32_STREAM_ID structure before the cStreamName field is | |
1114 the stream header, which is then immediately followed by the | |
1115 stream data. */ | |
1116 | |
1117 struct | |
1118 { | |
1119 WIN32_STREAM_ID wid; | |
2421 | 1120 WCHAR wbuffer[_MAX_PATH]; /* extra space for link name */ |
771 | 1121 } data; |
1122 | |
2957 | 1123 TO_EXTERNAL_FORMAT (C_STRING, new_, |
771 | 1124 ALLOCA, (newuni, wlen), Qmswindows_unicode); |
2421 | 1125 if (wlen / sizeof (WCHAR) < _MAX_PATH) |
771 | 1126 { |
1127 LPVOID context = NULL; | |
1128 DWORD wbytes = 0; | |
428 | 1129 |
771 | 1130 wcscpy (data.wid.cStreamName, newuni); |
1131 data.wid.dwStreamId = BACKUP_LINK; | |
1132 data.wid.dwStreamAttributes = 0; | |
4638
5bbff3553494
mswindows_link had off-by-one error. <1vq2brxz.wl_Ron.Isaacson@morganstanley.com>
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4487
diff
changeset
|
1133 /* Include the trailing null. In bytes, not chars! */ |
5bbff3553494
mswindows_link had off-by-one error. <1vq2brxz.wl_Ron.Isaacson@morganstanley.com>
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4487
diff
changeset
|
1134 data.wid.Size.LowPart = wlen + sizeof (WCHAR); |
771 | 1135 data.wid.Size.HighPart = 0; |
1136 data.wid.dwStreamNameSize = 0; | |
1137 | |
1138 if (BackupWrite (fileh, (LPBYTE)&data, | |
1139 offsetof (WIN32_STREAM_ID, cStreamName) | |
1140 + data.wid.Size.LowPart, | |
1141 &wbytes, FALSE, FALSE, &context) | |
1142 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context)) | |
1143 { | |
1144 /* succeeded */ | |
1145 result = 0; | |
1146 } | |
1147 else | |
1148 { | |
1149 /* Should try mapping GetLastError to errno; for now just | |
1150 indicate a general error (eg. links not supported). */ | |
1242 | 1151 errno = EINVAL; /* perhaps EMLINK? */ |
771 | 1152 } |
1153 } | |
1154 | |
1155 CloseHandle (fileh); | |
1156 } | |
1157 else | |
1158 errno = ENOENT; | |
1159 | |
1160 return result; | |
1161 } | |
1162 | |
1163 /* sys_open() merged into sysdep.c sys_open() */ | |
1164 | |
1165 int | |
867 | 1166 mswindows_rename (const Ibyte *oldname, const Ibyte *newname) |
771 | 1167 { |
1168 int result; | |
867 | 1169 Ibyte *temp; |
771 | 1170 |
1171 /* MoveFile on Windows 95 doesn't correctly change the short file name | |
428 | 1172 alias in a number of circumstances (it is not easy to predict when |
1173 just by looking at oldname and newname, unfortunately). In these | |
1174 cases, renaming through a temporary name avoids the problem. | |
1175 | |
771 | 1176 A second problem on Windows 95 is that renaming through a temp name when |
428 | 1177 newname is uppercase fails (the final long name ends up in |
1178 lowercase, although the short alias might be uppercase) UNLESS the | |
1179 long temp name is not 8.3. | |
1180 | |
771 | 1181 So, on Windows 95 we always rename through a temp name, and we make sure |
428 | 1182 the temp name has a long extension to ensure correct renaming. */ |
1183 | |
771 | 1184 /* XEmacs: We sprintf() part of OLDNAME into part of OLDNAME + a number, |
1185 so the following calculation should certainly be enough. */ | |
428 | 1186 |
867 | 1187 temp = qxestrcpy (alloca_ibytes (2 * qxestrlen (oldname) + 100), oldname); |
771 | 1188 |
1189 if (mswindows_windows9x_p) | |
428 | 1190 { |
867 | 1191 Ibyte *o; |
1192 Ibyte *p; | |
771 | 1193 int i = 0; |
428 | 1194 |
771 | 1195 if (o = qxestrrchr (oldname, '\\')) |
1196 o++; | |
1197 else | |
867 | 1198 o = (Ibyte *) oldname; |
771 | 1199 |
1200 if (p = qxestrrchr (temp, '\\')) | |
428 | 1201 p++; |
1202 else | |
1203 p = temp; | |
771 | 1204 |
1205 do | |
1206 { | |
1207 Extbyte *oldext, *tempext; | |
1208 /* Force temp name to require a manufactured 8.3 alias - this | |
1209 seems to make the second rename work properly. */ | |
1210 qxesprintf (p, "_.%s.%u", o, i); | |
1211 i++; | |
2526 | 1212 PATHNAME_CONVERT_OUT (oldname, oldext); |
1213 PATHNAME_CONVERT_OUT (temp, tempext); | |
771 | 1214 result = rename (oldext, tempext); |
1215 } | |
1216 /* This loop must surely terminate! */ | |
1217 while (result < 0 && errno == EEXIST); | |
1218 if (result < 0) | |
428 | 1219 return -1; |
1220 } | |
1221 | |
771 | 1222 /* Emulate Unix behaviour - newname is deleted if it already exists |
428 | 1223 (at least if it is a file; don't do this for directories). |
771 | 1224 |
1225 Since we mustn't do this if we are just changing the case of the | |
1226 file name (we would end up deleting the file we are trying to | |
1227 rename!), we let rename detect if the destination file already | |
1228 exists - that way we avoid the possible pitfalls of trying to | |
1229 determine ourselves whether two names really refer to the same | |
1230 file, which is not always possible in the general case. (Consider | |
1231 all the permutations of shared or subst'd drives, etc.) */ | |
1232 { | |
1233 Extbyte *newext, *tempext; | |
1234 | |
2526 | 1235 PATHNAME_CONVERT_OUT (newname, newext); |
1236 PATHNAME_CONVERT_OUT (temp, tempext); | |
1237 if (XEUNICODE_P) | |
1238 { | |
1239 result = _wrename ((const wchar_t *) tempext, | |
1240 (const wchar_t *) newext); | |
1241 if (result < 0 | |
1242 && (errno == EEXIST || errno == EACCES) | |
1243 && _wchmod ((const wchar_t *) newext, 0666) == 0 | |
1244 && _wunlink ((const wchar_t *) newext) == 0) | |
1245 result = _wrename ((const wchar_t *) tempext, | |
1246 (const wchar_t *) newext); | |
1247 } | |
1248 else | |
1249 { | |
1250 result = rename (tempext, newext); | |
1251 if (result < 0 | |
1252 && (errno == EEXIST || errno == EACCES) | |
1253 && _chmod (newext, 0666) == 0 | |
1254 && _unlink (newext) == 0) | |
1255 result = rename (tempext, newext); | |
1256 } | |
771 | 1257 } |
1258 | |
1259 return result; | |
1260 } | |
428 | 1261 |
771 | 1262 int |
867 | 1263 mswindows_unlink (const Ibyte *path) |
771 | 1264 { |
1265 Extbyte *pathout; | |
1266 | |
2526 | 1267 PATHNAME_CONVERT_OUT (path, pathout); |
771 | 1268 /* On Unix, unlink works without write permission. */ |
2526 | 1269 if (XEUNICODE_P) |
1270 { | |
1271 _wchmod ((const wchar_t *) pathout, 0666); | |
1272 return _wunlink ((const wchar_t *) pathout); | |
1273 } | |
1274 else | |
1275 { | |
1276 _chmod (pathout, 0666); | |
1277 return _unlink (pathout); | |
1278 } | |
428 | 1279 } |
1280 | |
1281 static FILETIME utc_base_ft; | |
592 | 1282 static long double utc_base; |
440 | 1283 static int init = 0; |
771 | 1284 static LARGE_INTEGER utc_base_li; |
440 | 1285 |
771 | 1286 /* XEmacs: We seem to have a new definition of |
1287 mswindows_convert_time(), although I'm not sure why. --ben */ | |
428 | 1288 |
1289 time_t | |
771 | 1290 mswindows_convert_time (FILETIME uft) |
440 | 1291 { |
1292 time_t ret; | |
1293 #ifndef MAXLONGLONG | |
1294 SYSTEMTIME st; | |
1295 struct tm t; | |
1296 FILETIME ft; | |
1297 TIME_ZONE_INFORMATION tzi; | |
1298 DWORD tzid; | |
1299 #else | |
1300 LARGE_INTEGER lft; | |
1301 #endif | |
1302 | |
1303 if (!init) | |
1304 { | |
1305 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */ | |
1306 SYSTEMTIME st; | |
1307 | |
1308 st.wYear = 1970; | |
1309 st.wMonth = 1; | |
1310 st.wDay = 1; | |
1311 st.wHour = 0; | |
1312 st.wMinute = 0; | |
1313 st.wSecond = 0; | |
1314 st.wMilliseconds = 0; | |
1315 | |
1316 SystemTimeToFileTime (&st, &utc_base_ft); | |
1317 | |
1318 utc_base_li.LowPart = utc_base_ft.dwLowDateTime; | |
1319 utc_base_li.HighPart = utc_base_ft.dwHighDateTime; | |
1320 | |
1321 init = 1; | |
1322 } | |
1323 | |
1324 #ifdef MAXLONGLONG | |
1325 | |
1326 /* On a compiler that supports long integers, do it the easy way */ | |
1327 lft.LowPart = uft.dwLowDateTime; | |
1328 lft.HighPart = uft.dwHighDateTime; | |
1329 ret = (time_t) ((lft.QuadPart - utc_base_li.QuadPart) / 10000000); | |
1330 | |
1331 #else | |
1332 | |
1333 /* Do it the hard way using mktime. */ | |
1334 FileTimeToLocalFileTime(&uft, &ft); | |
1335 FileTimeToSystemTime (&ft, &st); | |
1336 tzid = GetTimeZoneInformation (&tzi); | |
1337 t.tm_year = st.wYear - 1900; | |
1338 t.tm_mon = st.wMonth - 1; | |
1339 t.tm_mday = st.wDay; | |
1340 t.tm_hour = st.wHour; | |
1341 t.tm_min = st.wMinute; | |
1342 t.tm_sec = st.wSecond; | |
1343 t.tm_isdst = (tzid == TIME_ZONE_ID_DAYLIGHT); | |
1344 /* st.wMilliseconds not applicable */ | |
1345 ret = mktime(&t); | |
1346 if (ret == -1) | |
1347 { | |
1348 ret = 0; | |
1349 } | |
1350 | |
1351 #endif | |
1352 | |
1353 return ret; | |
1354 } | |
428 | 1355 |
771 | 1356 static void |
428 | 1357 convert_from_time_t (time_t time, FILETIME * pft) |
1358 { | |
1359 long double tmp; | |
1360 | |
1361 if (!init) | |
1362 { | |
1363 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */ | |
1364 SYSTEMTIME st; | |
1365 | |
1366 st.wYear = 1970; | |
1367 st.wMonth = 1; | |
1368 st.wDay = 1; | |
1369 st.wHour = 0; | |
1370 st.wMinute = 0; | |
1371 st.wSecond = 0; | |
1372 st.wMilliseconds = 0; | |
1373 | |
1374 SystemTimeToFileTime (&st, &utc_base_ft); | |
1375 utc_base = (long double) utc_base_ft.dwHighDateTime | |
1376 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime; | |
1377 init = 1; | |
1378 } | |
1379 | |
1380 /* time in 100ns units since 1-Jan-1601 */ | |
1381 tmp = (long double) time * 1e7 + utc_base; | |
1382 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024)); | |
771 | 1383 pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * |
1384 pft->dwHighDateTime); | |
428 | 1385 } |
1386 | |
1387 #if 0 | |
771 | 1388 /* A comment from Emacs 20.6: |
1389 | |
1390 No reason to keep this; faking inode values either by hashing or even | |
428 | 1391 using the file index from GetInformationByHandle, is not perfect and |
1392 so by default Emacs doesn't use the inode values on Windows. | |
1393 Instead, we now determine file-truename correctly (except for | |
1394 possible drive aliasing etc). */ | |
1395 | |
771 | 1396 /* XEmacs: Removed the fake-inodes code here, which was if 0'd out. |
1397 If you want it, look in w32.c in Emacs 20.6. */ | |
428 | 1398 #endif |
1399 | |
442 | 1400 /* #### aichner@ecf.teradyne.com reported that with the library |
1401 provided stat/fstat, (file-exist "d:\\tmp\\") =>> nil, | |
1402 (file-exist "d:\\tmp") =>> t, when d:\tmp exists. Whenever | |
1403 we opt to use non-encapsulated stat(), this should serve as | |
1404 a compatibility test. --kkm */ | |
440 | 1405 |
771 | 1406 /* Provide fstat and utime as well as stat for consistent handling of |
1407 file timestamps. */ | |
442 | 1408 int |
771 | 1409 mswindows_fstat (int desc, struct stat *buf) |
432 | 1410 { |
448 | 1411 HANDLE fh = (HANDLE) _get_osfhandle (desc); |
1412 BY_HANDLE_FILE_INFORMATION info; | |
1413 DWORD fake_inode; | |
1414 int permission; | |
1415 | |
1416 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE) | |
432 | 1417 { |
448 | 1418 case FILE_TYPE_DISK: |
1419 buf->st_mode = _S_IFREG; | |
1420 if (!GetFileInformationByHandle (fh, &info)) | |
1421 { | |
1422 errno = EACCES; | |
1423 return -1; | |
1424 } | |
1425 break; | |
1426 case FILE_TYPE_PIPE: | |
1427 buf->st_mode = _S_IFIFO; | |
1428 goto non_disk; | |
1429 case FILE_TYPE_CHAR: | |
1430 case FILE_TYPE_UNKNOWN: | |
1431 default: | |
1432 buf->st_mode = _S_IFCHR; | |
1433 non_disk: | |
1434 memset (&info, 0, sizeof (info)); | |
1435 info.dwFileAttributes = 0; | |
1436 info.ftCreationTime = utc_base_ft; | |
1437 info.ftLastAccessTime = utc_base_ft; | |
1438 info.ftLastWriteTime = utc_base_ft; | |
1439 } | |
1440 | |
1441 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | |
1442 { | |
1443 buf->st_mode = _S_IFDIR; | |
1444 buf->st_nlink = 2; /* doesn't really matter */ | |
1445 fake_inode = 0; /* this doesn't either I think */ | |
432 | 1446 } |
1447 else | |
1448 { | |
462 | 1449 buf->st_nlink = (short) info.nNumberOfLinks; |
448 | 1450 /* Might as well use file index to fake inode values, but this |
1451 is not guaranteed to be unique unless we keep a handle open | |
1452 all the time (even then there are situations where it is | |
1453 not unique). Reputedly, there are at most 48 bits of info | |
1454 (on NTFS, presumably less on FAT). */ | |
1455 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh; | |
432 | 1456 } |
448 | 1457 |
1458 /* MSVC defines _ino_t to be short; other libc's might not. */ | |
1459 if (sizeof (buf->st_ino) == 2) | |
462 | 1460 buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16)); |
448 | 1461 else |
462 | 1462 buf->st_ino = (unsigned short) fake_inode; |
448 | 1463 |
1464 /* consider files to belong to current user */ | |
1465 buf->st_uid = 0; | |
1466 buf->st_gid = 0; | |
1467 | |
1468 buf->st_dev = info.dwVolumeSerialNumber; | |
1469 buf->st_rdev = info.dwVolumeSerialNumber; | |
1470 | |
1471 buf->st_size = info.nFileSizeLow; | |
1472 | |
1473 /* Convert timestamps to Unix format. */ | |
771 | 1474 buf->st_mtime = mswindows_convert_time (info.ftLastWriteTime); |
1475 buf->st_atime = mswindows_convert_time (info.ftLastAccessTime); | |
448 | 1476 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime; |
771 | 1477 buf->st_ctime = mswindows_convert_time (info.ftCreationTime); |
448 | 1478 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime; |
1479 | |
1480 /* determine rwx permissions */ | |
1481 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) | |
1482 permission = _S_IREAD; | |
1483 else | |
1484 permission = _S_IREAD | _S_IWRITE; | |
1485 | |
1486 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | |
1487 permission |= _S_IEXEC; | |
771 | 1488 else |
1489 { | |
1490 #if 0 /* no way of knowing the filename */ | |
1204 | 1491 if (mswindows_is_executable (name)) |
771 | 1492 permission |= _S_IEXEC; |
1493 #endif | |
1494 } | |
448 | 1495 |
1496 buf->st_mode |= permission | (permission >> 3) | (permission >> 6); | |
1497 | |
1498 return 0; | |
432 | 1499 } |
1500 | |
428 | 1501 /* MSVC stat function can't cope with UNC names and has other bugs, so |
1502 replace it with our own. This also allows us to calculate consistent | |
1503 inode values without hacks in the main Emacs code. */ | |
1504 int | |
867 | 1505 mswindows_stat (const Ibyte *path, struct stat *buf) |
428 | 1506 { |
867 | 1507 Ibyte *name, *r; |
771 | 1508 WIN32_FIND_DATAW wfd; |
428 | 1509 HANDLE fh; |
1510 DWORD fake_inode; | |
1511 int permission; | |
771 | 1512 Bytecount len; |
428 | 1513 int rootdir = FALSE; |
771 | 1514 Extbyte *nameext; |
819 | 1515 int errm; |
428 | 1516 |
1517 if (path == NULL || buf == NULL) | |
1518 { | |
1519 errno = EFAULT; | |
1520 return -1; | |
1521 } | |
1522 | |
867 | 1523 name = qxestrcpy (alloca_ibytes (qxestrlen (path) + 10), path); |
819 | 1524 errm = SetErrorMode (SEM_FAILCRITICALERRORS |
1525 | SEM_NOOPENFILEERRORBOX); | |
771 | 1526 |
1527 get_volume_info (name, &path); | |
1528 /* must be valid filename, no wild cards or other invalid characters */ | |
1529 if (qxestrpbrk (name, "*?|<>\"")) | |
428 | 1530 { |
1531 errno = ENOENT; | |
1532 return -1; | |
1533 } | |
1534 | |
771 | 1535 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */ |
1536 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name; | |
1537 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0') | |
1538 { | |
1539 r[1] = r[2] = '\0'; | |
1540 } | |
1541 | |
428 | 1542 /* Remove trailing directory separator, unless name is the root |
1543 directory of a drive or UNC volume in which case ensure there | |
1544 is a trailing separator. */ | |
771 | 1545 len = qxestrlen (name); |
428 | 1546 rootdir = (path >= name + len - 1 |
1547 && (IS_DIRECTORY_SEP (*path) || *path == 0)); | |
771 | 1548 |
1549 if (is_unc_volume (name)) | |
1550 { | |
1551 DWORD attrs = unc_volume_file_attributes (name); | |
1552 | |
1553 if (attrs == -1) | |
1554 return -1; | |
428 | 1555 |
771 | 1556 memset (&wfd, 0, sizeof (wfd)); |
1557 wfd.dwFileAttributes = attrs; | |
1558 wfd.ftCreationTime = utc_base_ft; | |
1559 wfd.ftLastAccessTime = utc_base_ft; | |
1560 wfd.ftLastWriteTime = utc_base_ft; | |
1561 /* XEmacs deleted: strcpy (wfd.cFileName, name); | |
1562 Not used later on. */ | |
1563 } | |
1564 else if (rootdir) | |
428 | 1565 { |
1566 if (!IS_DIRECTORY_SEP (name[len-1])) | |
867 | 1567 qxestrcat (name, (Ibyte *) "\\"); |
2526 | 1568 /* File has already been resolved and we don't want to do it again |
1569 in case of lstat() */ | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
1570 nameext = ITEXT_TO_TSTR (name); |
771 | 1571 if (qxeGetDriveType (nameext) < 2) |
428 | 1572 { |
819 | 1573 SetErrorMode (errm); |
428 | 1574 errno = ENOENT; |
1575 return -1; | |
1576 } | |
1577 memset (&wfd, 0, sizeof (wfd)); | |
1578 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY; | |
1579 wfd.ftCreationTime = utc_base_ft; | |
1580 wfd.ftLastAccessTime = utc_base_ft; | |
1581 wfd.ftLastWriteTime = utc_base_ft; | |
771 | 1582 /* XEmacs deleted: strcpy (wfd.cFileName, name); |
1583 Not used later on. */ | |
428 | 1584 } |
1585 else | |
1586 { | |
1587 if (IS_DIRECTORY_SEP (name[len-1])) | |
1588 name[len - 1] = 0; | |
1589 | |
1590 /* (This is hacky, but helps when doing file completions on | |
1591 network drives.) Optimize by using information available from | |
1592 active readdir if possible. */ | |
771 | 1593 if (dir_pathname) |
1594 { | |
1595 len = qxestrlen (dir_pathname); | |
1596 if (len && IS_DIRECTORY_SEP (dir_pathname[len-1])) | |
1597 len--; | |
1598 } | |
1599 if (dir_find_handle != INVALID_HANDLE_VALUE | |
1600 && dir_pathname | |
801 | 1601 && qxestrncasecmp_i18n (dir_pathname, name, len) == 0 |
771 | 1602 && IS_DIRECTORY_SEP (name[len]) |
1603 && qxestrcasecmp_i18n (name + len + 1, | |
867 | 1604 (Ibyte *) dir_static.d_name) == 0) |
428 | 1605 { |
1606 /* This was the last entry returned by readdir. */ | |
1607 wfd = dir_find_data; | |
1608 } | |
1609 else | |
1610 { | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
1611 nameext = ITEXT_TO_TSTR (name); |
771 | 1612 fh = qxeFindFirstFile (nameext, &wfd); |
1613 if (fh == INVALID_HANDLE_VALUE) | |
1614 { | |
819 | 1615 SetErrorMode (errm); |
771 | 1616 errno = ENOENT; |
1617 return -1; | |
1618 } | |
1619 FindClose (fh); | |
1620 /* XEmacs: Don't need to convert wfd.cFileName because | |
1621 not used later on. */ | |
428 | 1622 } |
1623 } | |
1624 | |
1625 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | |
1626 { | |
1627 buf->st_mode = _S_IFDIR; | |
1628 buf->st_nlink = 2; /* doesn't really matter */ | |
1629 fake_inode = 0; /* this doesn't either I think */ | |
1630 } | |
771 | 1631 else |
428 | 1632 { |
771 | 1633 if (!NILP (Vmswindows_get_true_file_attributes)) |
2526 | 1634 /* File has already been resolved and we don't want to do it again |
1635 in case of lstat() */ | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
1636 nameext = ITEXT_TO_TSTR (name); |
771 | 1637 if (!NILP (Vmswindows_get_true_file_attributes) |
1638 /* No access rights required to get info. */ | |
1639 && (fh = qxeCreateFile (nameext, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) | |
1640 != INVALID_HANDLE_VALUE) | |
1641 { | |
2526 | 1642 /* This is more accurate in terms of getting the correct number |
771 | 1643 of links, but is quite slow (it is noticable when Emacs is |
1644 making a list of file name completions). */ | |
1645 BY_HANDLE_FILE_INFORMATION info; | |
428 | 1646 |
771 | 1647 if (GetFileInformationByHandle (fh, &info)) |
1648 { | |
1649 buf->st_nlink = (short) info.nNumberOfLinks; | |
1650 /* Might as well use file index to fake inode values, but this | |
1651 is not guaranteed to be unique unless we keep a handle open | |
1652 all the time (even then there are situations where it is | |
1653 not unique). Reputedly, there are at most 48 bits of info | |
1654 (on NTFS, presumably less on FAT). */ | |
1655 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh; | |
1656 } | |
1657 else | |
1658 { | |
1659 buf->st_nlink = 1; | |
1660 fake_inode = 0; | |
1661 } | |
428 | 1662 |
1663 switch (GetFileType (fh)) | |
1664 { | |
1665 case FILE_TYPE_DISK: | |
1666 buf->st_mode = _S_IFREG; | |
1667 break; | |
1668 case FILE_TYPE_PIPE: | |
1669 buf->st_mode = _S_IFIFO; | |
1670 break; | |
1671 case FILE_TYPE_CHAR: | |
1672 case FILE_TYPE_UNKNOWN: | |
1673 default: | |
1674 buf->st_mode = _S_IFCHR; | |
1675 } | |
1676 CloseHandle (fh); | |
1677 } | |
1678 else | |
1679 { | |
771 | 1680 /* Don't bother to make this information more accurate. */ |
1681 buf->st_mode = _S_IFREG; | |
1682 buf->st_nlink = 1; | |
1683 fake_inode = 0; | |
428 | 1684 } |
2526 | 1685 |
1686 if (mswindows_shortcuts_are_symlinks && | |
1687 buf->st_mode == _S_IFREG) | |
1688 { | |
1689 len = qxestrlen (name); | |
1690 if (len > 4 && !qxestrcasecmp_ascii (name + len - 4, ".LNK")) | |
1691 { | |
1692 /* check if link is valid */ | |
1693 Ibyte *resolved = mswindows_read_link (name); | |
1694 if (resolved) | |
1695 { | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
1696 xfree (resolved); |
2526 | 1697 buf->st_mode = S_IFLNK; |
1698 } | |
1699 } | |
1700 } | |
428 | 1701 } |
1702 | |
819 | 1703 SetErrorMode (errm); |
1704 | |
428 | 1705 #if 0 |
771 | 1706 /* XEmacs: Removed the fake-inodes code here, which was if 0'd out. |
1707 If you want it, look in w32.c in Emacs 20.6. */ | |
428 | 1708 #endif |
1709 | |
771 | 1710 /* MSVC defines _ino_t to be short; other libc's might not. */ |
1711 if (sizeof (buf->st_ino) == 2) | |
1712 buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16)); | |
1713 else | |
1714 buf->st_ino = (unsigned short) fake_inode; | |
428 | 1715 |
1716 /* consider files to belong to current user */ | |
771 | 1717 buf->st_uid = the_passwd.pw_uid; |
1718 buf->st_gid = the_passwd.pw_gid; | |
428 | 1719 |
771 | 1720 /* volume_info is set by get_volume_info */ |
428 | 1721 buf->st_dev = volume_info.serialnum; |
1722 buf->st_rdev = volume_info.serialnum; | |
1723 | |
771 | 1724 |
428 | 1725 buf->st_size = wfd.nFileSizeLow; |
1726 | |
1727 /* Convert timestamps to Unix format. */ | |
771 | 1728 buf->st_mtime = mswindows_convert_time (wfd.ftLastWriteTime); |
1729 buf->st_atime = mswindows_convert_time (wfd.ftLastAccessTime); | |
428 | 1730 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime; |
771 | 1731 buf->st_ctime = mswindows_convert_time (wfd.ftCreationTime); |
428 | 1732 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime; |
1733 | |
1734 /* determine rwx permissions */ | |
1735 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) | |
1736 permission = _S_IREAD; | |
1737 else | |
1738 permission = _S_IREAD | _S_IWRITE; | |
1739 | |
1740 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | |
1741 permission |= _S_IEXEC; | |
1204 | 1742 else if (mswindows_is_executable (name)) |
771 | 1743 permission |= _S_IEXEC; |
428 | 1744 |
1745 buf->st_mode |= permission | (permission >> 3) | (permission >> 6); | |
1746 | |
1747 return 0; | |
1748 } | |
1749 | |
1750 int | |
771 | 1751 mswindows_utime (Lisp_Object path, struct utimbuf *times) |
428 | 1752 { |
771 | 1753 /* #### Supposedly we're providing this because standard utime() |
1754 might not work; or at the very least to get consistent results | |
1755 since we replace other time-handling routines in stat. But out | |
1756 replacement doesn't seem to work, probably due to some subtle bug | |
1757 in this routine, which should be investigated eventually. So for | |
1758 the moment, we just use utime(), which conceivably might be | |
1759 slightly off in comparison with our own routines? Seems strange, | |
1760 and so far no problems seen. --ben */ | |
428 | 1761 |
771 | 1762 struct utimbuf deftime; |
1763 #if 0 | |
1764 HANDLE fh; | |
1765 #endif | |
1766 static FILETIME mtime; | |
1767 static FILETIME atime; | |
1768 Extbyte *filename; | |
428 | 1769 |
771 | 1770 if (times == NULL) |
428 | 1771 { |
771 | 1772 deftime.modtime = deftime.actime = time (NULL); |
1773 times = &deftime; | |
428 | 1774 } |
1775 | |
2526 | 1776 LISP_PATHNAME_CONVERT_OUT (path, filename); |
771 | 1777 /* APA: SetFileTime fails to set mtime correctly (always 1-Jan-1970) */ |
1778 #if 0 | |
1779 /* Need write access to set times. */ | |
1780 fh = qxeCreateFile (filename, GENERIC_WRITE, | |
1781 FILE_SHARE_READ | FILE_SHARE_WRITE, | |
1782 0, OPEN_EXISTING, 0, NULL); | |
1783 if (fh) | |
1784 { | |
1785 convert_from_time_t (times->actime, &atime); | |
1786 convert_from_time_t (times->modtime, &mtime); | |
1787 if (!SetFileTime (fh, NULL, &atime, &mtime)) | |
1788 { | |
1789 CloseHandle (fh); | |
1790 errno = EACCES; | |
1791 return -1; | |
1792 } | |
1793 CloseHandle (fh); | |
1794 } | |
1795 else | |
1796 { | |
1797 errno = EINVAL; | |
1798 return -1; | |
1799 } | |
1800 return 0; | |
1801 #else | |
1802 { | |
1803 struct _utimbuf newtimes; | |
1804 | |
1805 newtimes.actime = times->actime; | |
1806 newtimes.modtime = times->modtime; | |
1807 | |
1808 if (XEUNICODE_P) | |
1809 return _wutime ((const wchar_t *) filename, &newtimes); | |
1810 else | |
1811 return _utime (filename, &newtimes); | |
1812 } | |
1813 #endif | |
1814 } | |
1815 | |
867 | 1816 Ibyte * |
771 | 1817 mswindows_getdcwd (int drivelet) |
1818 { | |
1819 Extbyte *cwdext; | |
867 | 1820 Ibyte *cwd; |
4786 | 1821 /* Following comment and two-liner fix comes from |
1822 https://bugzilla.mozilla.org/show_bug.cgi?id=419326 which | |
1823 apparently fell prey to this feature of msvcrt8 as well. */ | |
1824 /* We need to worry about IPH, for details read bug 419326. | |
1825 * _getdrives - http://msdn2.microsoft.com/en-us/library/xdhk0xd2.aspx | |
1826 * uses a bitmask, bit 0 is 'a:' | |
1827 * _chdrive - http://msdn2.microsoft.com/en-us/library/0d1409hb.aspx | |
1828 * _getdcwd - http://msdn2.microsoft.com/en-us/library/7t2zk3s4.aspx | |
1829 * take an int, 1 is 'a:'. | |
1830 * | |
1831 * Because of this, we need to do some math. Subtract 1 to convert from | |
1832 * _chdrive/_getdcwd format to _getdrives drive numbering. | |
1833 * Shift left x bits to convert from integer indexing to bitfield indexing. | |
1834 * And of course, we need to find out if the drive is in the bitmask. | |
1835 * | |
1836 * If we're really unlucky, we can still lose, but only if the user | |
1837 * manages to eject the drive between our call to _getdrives() and | |
1838 * our *calls* to _wgetdcwd. | |
1839 */ | |
1840 if (!((1 << (drivelet - 1)) & _getdrives())) | |
1841 return NULL; | |
771 | 1842 if (XEUNICODE_P) |
1843 cwdext = (Extbyte *) _wgetdcwd (drivelet, NULL, 0); | |
1844 else | |
1845 cwdext = _getdcwd (drivelet, NULL, 0); | |
3648 | 1846 if (cwdext == NULL) return NULL; |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
1847 cwd = TSTR_TO_ITEXT_MALLOC (cwdext); |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
1848 xfree (cwdext); |
771 | 1849 return cwd; |
428 | 1850 } |
1851 | |
442 | 1852 |
1853 /*--------------------------------------------------------------------*/ | |
1854 /* Memory-mapped files */ | |
1855 /*--------------------------------------------------------------------*/ | |
1856 | |
428 | 1857 int |
867 | 1858 open_input_file (file_data *p_file, const Ibyte *filename) |
428 | 1859 { |
442 | 1860 /* Synched with FSF 20.6. We fixed some warnings. */ |
428 | 1861 HANDLE file; |
1862 HANDLE file_mapping; | |
771 | 1863 void *file_base; |
428 | 1864 DWORD size, upper_size; |
771 | 1865 Extbyte *fileext; |
428 | 1866 |
2526 | 1867 PATHNAME_CONVERT_OUT (filename, fileext); |
771 | 1868 |
1869 file = qxeCreateFile (fileext, GENERIC_READ, FILE_SHARE_READ, NULL, | |
1870 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); | |
428 | 1871 if (file == INVALID_HANDLE_VALUE) |
1872 return FALSE; | |
1873 | |
1874 size = GetFileSize (file, &upper_size); | |
771 | 1875 file_mapping = qxeCreateFileMapping (file, NULL, PAGE_READONLY, |
1876 0, size, NULL); | |
428 | 1877 if (!file_mapping) |
1878 return FALSE; | |
1879 | |
1880 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size); | |
1881 if (file_base == 0) | |
1882 return FALSE; | |
1883 | |
771 | 1884 p_file->name = filename; |
442 | 1885 p_file->size = size; |
1886 p_file->file = file; | |
1887 p_file->file_mapping = file_mapping; | |
771 | 1888 p_file->file_base = file_base; |
442 | 1889 |
1890 return TRUE; | |
1891 } | |
1892 | |
1893 int | |
867 | 1894 open_output_file (file_data *p_file, const Ibyte *filename, |
771 | 1895 unsigned long size) |
442 | 1896 { |
1897 /* Synched with FSF 20.6. We fixed some warnings. */ | |
1898 HANDLE file; | |
1899 HANDLE file_mapping; | |
771 | 1900 void *file_base; |
1901 Extbyte *fileext; | |
442 | 1902 |
2526 | 1903 PATHNAME_CONVERT_OUT (filename, fileext); |
771 | 1904 |
1905 file = qxeCreateFile (fileext, GENERIC_READ | GENERIC_WRITE, 0, NULL, | |
1906 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); | |
442 | 1907 if (file == INVALID_HANDLE_VALUE) |
1908 return FALSE; | |
1909 | |
771 | 1910 file_mapping = qxeCreateFileMapping (file, NULL, PAGE_READWRITE, |
1911 0, size, NULL); | |
442 | 1912 if (!file_mapping) |
1913 return FALSE; | |
1914 | |
1915 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size); | |
1916 if (file_base == NULL) | |
1917 return FALSE; | |
1918 | |
1919 p_file->name = filename; | |
428 | 1920 p_file->size = size; |
1921 p_file->file = file; | |
1922 p_file->file_mapping = file_mapping; | |
771 | 1923 p_file->file_base = file_base; |
428 | 1924 |
1925 return TRUE; | |
1926 } | |
1927 | |
442 | 1928 #if 1 /* !defined(MINGW) */ |
1929 /* Return pointer to section header for section containing the given | |
1930 relative virtual address. */ | |
1931 static IMAGE_SECTION_HEADER * | |
771 | 1932 rva_to_section (DWORD rva, IMAGE_NT_HEADERS *nt_header) |
442 | 1933 { |
1934 /* Synched with FSF 20.6. We added MINGW stuff. */ | |
1935 PIMAGE_SECTION_HEADER section; | |
1936 int i; | |
1937 | |
1938 section = IMAGE_FIRST_SECTION (nt_header); | |
1939 | |
1940 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) | |
1941 { | |
1942 /* Some linkers (eg. the NT SDK linker I believe) swapped the | |
1943 meaning of these two values - or rather, they ignored | |
1944 VirtualSize entirely and always set it to zero. This affects | |
1945 some very old exes (eg. gzip dated Dec 1993). Since | |
1946 mswindows_executable_type relies on this function to work reliably, | |
1947 we need to cope with this. */ | |
1948 DWORD real_size = max (section->SizeOfRawData, | |
1949 section->Misc.VirtualSize); | |
1950 if (rva >= section->VirtualAddress | |
1951 && rva < section->VirtualAddress + real_size) | |
1952 return section; | |
1953 section++; | |
1954 } | |
1955 return NULL; | |
1956 } | |
1957 #endif | |
1958 | |
1959 void | |
867 | 1960 mswindows_executable_type (const Ibyte *filename, int *is_dos_app, |
771 | 1961 int *is_cygnus_app) |
442 | 1962 { |
1963 /* Synched with FSF 20.6. We added MINGW stuff and casts. */ | |
1964 file_data executable; | |
867 | 1965 Ibyte *p; |
442 | 1966 |
1967 /* Default values in case we can't tell for sure. */ | |
1968 *is_dos_app = FALSE; | |
1969 *is_cygnus_app = FALSE; | |
1970 | |
1971 if (!open_input_file (&executable, filename)) | |
1972 return; | |
1973 | |
771 | 1974 p = qxestrrchr (filename, '.'); |
442 | 1975 |
1976 /* We can only identify DOS .com programs from the extension. */ | |
2367 | 1977 if (p && qxestrcasecmp_ascii (p, ".com") == 0) |
442 | 1978 *is_dos_app = TRUE; |
2367 | 1979 else if (p && (qxestrcasecmp_ascii (p, ".bat") == 0 || |
1980 qxestrcasecmp_ascii (p, ".cmd") == 0)) | |
442 | 1981 { |
1982 /* A DOS shell script - it appears that CreateProcess is happy to | |
1983 accept this (somewhat surprisingly); presumably it looks at | |
1984 COMSPEC to determine what executable to actually invoke. | |
1985 Therefore, we have to do the same here as well. */ | |
1986 /* Actually, I think it uses the program association for that | |
1987 extension, which is defined in the registry. */ | |
1988 p = egetenv ("COMSPEC"); | |
1989 if (p) | |
1990 mswindows_executable_type (p, is_dos_app, is_cygnus_app); | |
1991 } | |
1992 else | |
1993 { | |
1994 /* Look for DOS .exe signature - if found, we must also check that | |
1995 it isn't really a 16- or 32-bit Windows exe, since both formats | |
1996 start with a DOS program stub. Note that 16-bit Windows | |
1997 executables use the OS/2 1.x format. */ | |
1998 | |
1999 #if 0 /* defined( MINGW ) */ | |
771 | 2000 /* mingw doesn't have enough headers to detect cygwin |
442 | 2001 apps, just do what we can. */ |
771 | 2002 FILHDR *exe_header; |
442 | 2003 |
771 | 2004 exe_header = (FILHDR *) executable.file_base; |
442 | 2005 if (exe_header->e_magic != DOSMAGIC) |
2006 goto unwind; | |
2007 | |
5000
44d7bde26046
fix compile errors, fix revert-buffer bug on binary/Latin 1 files, Mule-ize some files
Ben Wing <ben@xemacs.org>
parents:
4982
diff
changeset
|
2008 if ((Rawbyte *) exe_header->e_lfanew > (Rawbyte *) executable.size) |
442 | 2009 { |
2010 /* Some dos headers (pkunzip) have bogus e_lfanew fields. */ | |
2011 *is_dos_app = TRUE; | |
2012 } | |
2013 else if (exe_header->nt_signature != NT_SIGNATURE) | |
2014 { | |
2015 *is_dos_app = TRUE; | |
2016 } | |
2017 #else | |
771 | 2018 IMAGE_DOS_HEADER *dos_header; |
2019 IMAGE_NT_HEADERS *nt_header; | |
442 | 2020 |
2021 dos_header = (PIMAGE_DOS_HEADER) executable.file_base; | |
2022 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) | |
2023 goto unwind; | |
2024 | |
5000
44d7bde26046
fix compile errors, fix revert-buffer bug on binary/Latin 1 files, Mule-ize some files
Ben Wing <ben@xemacs.org>
parents:
4982
diff
changeset
|
2025 nt_header = (PIMAGE_NT_HEADERS) ((Rawbyte *) dos_header + |
771 | 2026 dos_header->e_lfanew); |
442 | 2027 |
5000
44d7bde26046
fix compile errors, fix revert-buffer bug on binary/Latin 1 files, Mule-ize some files
Ben Wing <ben@xemacs.org>
parents:
4982
diff
changeset
|
2028 if ((Rawbyte *) nt_header > (Rawbyte *) dos_header + executable.size) |
442 | 2029 { |
2030 /* Some dos headers (pkunzip) have bogus e_lfanew fields. */ | |
2031 *is_dos_app = TRUE; | |
2032 } | |
2033 else if (nt_header->Signature != IMAGE_NT_SIGNATURE && | |
2034 LOWORD (nt_header->Signature) != IMAGE_OS2_SIGNATURE) | |
2035 { | |
2036 *is_dos_app = TRUE; | |
2037 } | |
2038 else if (nt_header->Signature == IMAGE_NT_SIGNATURE) | |
2039 { | |
2040 /* Look for cygwin.dll in DLL import list. */ | |
2041 IMAGE_DATA_DIRECTORY import_dir = | |
771 | 2042 nt_header->OptionalHeader. |
2043 DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; | |
2044 IMAGE_IMPORT_DESCRIPTOR *imports; | |
2045 IMAGE_SECTION_HEADER *section; | |
442 | 2046 |
2047 section = rva_to_section (import_dir.VirtualAddress, nt_header); | |
771 | 2048 imports = |
2049 (IMAGE_IMPORT_DESCRIPTOR *) RVA_TO_PTR (import_dir.VirtualAddress, | |
2050 section, executable); | |
2051 | |
442 | 2052 for ( ; imports->Name; imports++) |
2053 { | |
771 | 2054 Extbyte *dllname_ext = |
2055 (Extbyte *) RVA_TO_PTR (imports->Name, section, executable); | |
867 | 2056 Ibyte *dllname; |
771 | 2057 |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2058 dllname = EXTERNAL_TO_ITEXT (dllname_ext, Qbinary); |
442 | 2059 |
2060 /* The exact name of the cygwin dll has changed with | |
2061 various releases, but hopefully this will be reasonably | |
2062 future proof. */ | |
867 | 2063 if (qxestrncasecmp (dllname, (Ibyte *) "cygwin", 6) == 0) |
442 | 2064 { |
2065 *is_cygnus_app = TRUE; | |
2066 break; | |
2067 } | |
2068 } | |
2069 } | |
2070 #endif | |
2071 } | |
2072 | |
2073 unwind: | |
2074 close_file_data (&executable); | |
2075 } | |
2076 | |
428 | 2077 /* Close the system structures associated with the given file. */ |
2078 void | |
2079 close_file_data (file_data *p_file) | |
2080 { | |
611 | 2081 UnmapViewOfFile (p_file->file_base); |
2082 CloseHandle (p_file->file_mapping); | |
2083 CloseHandle (p_file->file); | |
428 | 2084 } |
2085 | |
771 | 2086 |
2087 /* Some miscellaneous functions that are Windows specific, but not GUI | |
2088 specific (ie. are applicable in terminal or batch mode as well). */ | |
2089 | |
4487
866b84b7c97e
Remove interactive specs from #'mswindows-{short,long}-file-name,
Aidan Kehoe <kehoea@parhasard.net>
parents:
3648
diff
changeset
|
2090 DEFUN ("mswindows-short-file-name", Fmswindows_short_file_name, 1, 1, 0, /* |
771 | 2091 Return the short file name version (8.3) of the full path of FILENAME. |
2092 If FILENAME does not exist, return nil. | |
2093 All path elements in FILENAME are converted to their short names. | |
2094 */ | |
2095 (filename)) | |
2096 { | |
4854 | 2097 Extbyte shortname[PATH_MAX_TCHAR]; |
771 | 2098 Extbyte *fileext; |
867 | 2099 Ibyte *shortint; |
771 | 2100 |
2101 CHECK_STRING (filename); | |
2102 | |
2103 /* first expand it. */ | |
2104 filename = Fexpand_file_name (filename, Qnil); | |
2105 | |
2526 | 2106 LISP_PATHNAME_CONVERT_OUT (filename, fileext); |
771 | 2107 /* luckily, this returns the short version of each element in the path. */ |
2108 if (qxeGetShortPathName (fileext, shortname, | |
2109 sizeof (shortname) / XETCHAR_SIZE) == 0) | |
2110 return Qnil; | |
2111 | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2112 shortint = TSTR_TO_ITEXT (shortname); |
771 | 2113 MSWINDOWS_NORMALIZE_FILENAME (shortint); |
2114 | |
4953
304aebb79cd3
function renamings to track names of char typedefs
Ben Wing <ben@xemacs.org>
parents:
4854
diff
changeset
|
2115 return build_istring (shortint); |
771 | 2116 } |
2117 | |
2118 | |
4487
866b84b7c97e
Remove interactive specs from #'mswindows-{short,long}-file-name,
Aidan Kehoe <kehoea@parhasard.net>
parents:
3648
diff
changeset
|
2119 DEFUN ("mswindows-long-file-name", Fmswindows_long_file_name, 1, 1, 0, /* |
771 | 2120 Return the long file name version of the full path of FILENAME. |
2121 If FILENAME does not exist, return nil. | |
2122 All path elements in FILENAME are converted to their long names. | |
2123 */ | |
2124 (filename)) | |
2125 { | |
867 | 2126 Ibyte *longname, *canon; |
771 | 2127 Lisp_Object ret; |
2128 | |
2129 CHECK_STRING (filename); | |
2130 | |
2131 /* first expand it. */ | |
2132 filename = Fexpand_file_name (filename, Qnil); | |
2133 | |
2134 if (!(longname = mswindows_get_long_filename (XSTRING_DATA (filename)))) | |
2135 return Qnil; | |
2136 | |
2137 canon = mswindows_canonicalize_filename (longname); | |
4953
304aebb79cd3
function renamings to track names of char typedefs
Ben Wing <ben@xemacs.org>
parents:
4854
diff
changeset
|
2138 ret = build_istring (canon); |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2139 xfree (canon); |
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2140 xfree (longname); |
771 | 2141 return ret; |
2142 } | |
2143 | |
814 | 2144 |
2145 void | |
2146 init_nt (void) | |
2147 { | |
2148 /* Initial preparation for subprocess support: replace our standard | |
2149 handles with non-inheritable versions. | |
2150 | |
2151 #### Do we still need this? This is left over from the old process | |
2152 support. */ | |
2153 { | |
2154 HANDLE parent; | |
2155 HANDLE stdin_save = INVALID_HANDLE_VALUE; | |
2156 HANDLE stdout_save = INVALID_HANDLE_VALUE; | |
2157 HANDLE stderr_save = INVALID_HANDLE_VALUE; | |
2158 | |
2159 parent = GetCurrentProcess (); | |
2160 | |
2161 /* ignore errors when duplicating and closing; typically the | |
2162 handles will be invalid when running as a gui program. */ | |
2163 DuplicateHandle (parent, | |
2164 GetStdHandle (STD_INPUT_HANDLE), | |
2165 parent, | |
2166 &stdin_save, | |
2167 0, | |
2168 FALSE, | |
2169 DUPLICATE_SAME_ACCESS); | |
2170 | |
2171 DuplicateHandle (parent, | |
2172 GetStdHandle (STD_OUTPUT_HANDLE), | |
2173 parent, | |
2174 &stdout_save, | |
2175 0, | |
2176 FALSE, | |
2177 DUPLICATE_SAME_ACCESS); | |
2178 | |
2179 DuplicateHandle (parent, | |
2180 GetStdHandle (STD_ERROR_HANDLE), | |
2181 parent, | |
2182 &stderr_save, | |
2183 0, | |
2184 FALSE, | |
2185 DUPLICATE_SAME_ACCESS); | |
2186 | |
2187 retry_fclose (stdin); | |
2188 retry_fclose (stdout); | |
2189 retry_fclose (stderr); | |
2190 | |
2191 if (stdin_save != INVALID_HANDLE_VALUE) | |
2192 _open_osfhandle ((long) stdin_save, O_TEXT); | |
2193 else | |
2194 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY); | |
2195 _fdopen (0, "r"); | |
2196 | |
2197 if (stdout_save != INVALID_HANDLE_VALUE) | |
2198 _open_osfhandle ((long) stdout_save, O_TEXT); | |
2199 else | |
2200 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY); | |
2201 _fdopen (1, "w"); | |
2202 | |
2203 if (stderr_save != INVALID_HANDLE_VALUE) | |
2204 _open_osfhandle ((long) stderr_save, O_TEXT); | |
2205 else | |
2206 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY); | |
2207 _fdopen (2, "w"); | |
2208 } | |
2209 | |
2210 /* determine which drives are fixed, for get_cached_volume_information */ | |
2211 { | |
2212 /* GetDriveType must have trailing backslash. */ | |
867 | 2213 Ibyte drive[] = "A:\\"; |
814 | 2214 |
2215 /* Loop over all possible drive letters */ | |
2216 while (*drive <= 'Z') | |
2217 { | |
2218 Extbyte *driveext; | |
2219 | |
2526 | 2220 PATHNAME_CONVERT_OUT (drive, driveext); |
814 | 2221 |
2222 /* Record if this drive letter refers to a fixed drive. */ | |
2223 fixed_drives[DRIVE_INDEX (*drive)] = | |
2224 (qxeGetDriveType (driveext) == DRIVE_FIXED); | |
2225 | |
2226 (*drive)++; | |
2227 } | |
2228 | |
2229 /* Reset the volume info cache. */ | |
2230 volume_cache = NULL; | |
2231 } | |
2232 } | |
2233 | |
771 | 2234 void |
2235 syms_of_nt (void) | |
2236 { | |
2237 DEFSUBR (Fmswindows_short_file_name); | |
2238 DEFSUBR (Fmswindows_long_file_name); | |
2239 } | |
2240 | |
440 | 2241 void |
2242 vars_of_nt (void) | |
2243 { | |
771 | 2244 DEFVAR_INT ("mswindows-fake-unix-uid", &mswindows_fake_unix_uid /* |
440 | 2245 *Set uid returned by `user-uid' and `user-real-uid'. |
771 | 2246 Under NT and 9x, there are no uids, and even no almighty user called root. |
2247 By setting this variable, you can have any uid of choice. Default is 0. | |
440 | 2248 Changes to this variable take effect immediately. |
2249 */ ); | |
771 | 2250 mswindows_fake_unix_uid = 0; |
2251 | |
2252 DEFVAR_LISP ("mswindows-get-true-file-attributes", &Vmswindows_get_true_file_attributes /* | |
2253 Non-nil means determine accurate link count in file-attributes. | |
2254 This option slows down file-attributes noticeably, so is disabled by | |
2255 default. Note that it is only useful for files on NTFS volumes, | |
2256 where hard links are supported. | |
2257 */ ); | |
2258 Vmswindows_get_true_file_attributes = Qnil; | |
440 | 2259 } |
2260 | |
428 | 2261 /* end of nt.c */ |