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