aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2012-08-03 13:23:30 +0300
committerEli Zaretskii2012-08-03 13:23:30 +0300
commit6dad71783c018d3ccabcede7db6ea206de5b3255 (patch)
treea30427f359ae98e4f4f7cc1483cee77371e5ed42
parent0948632492830f08805f2c1250a9ababb6baa95a (diff)
downloademacs-6dad71783c018d3ccabcede7db6ea206de5b3255.tar.gz
emacs-6dad71783c018d3ccabcede7db6ea206de5b3255.zip
Support symlinks on latest versions of MS-Windows.
src/w32.c: Include winioctl.h and aclapi.h. (is_symlink, chase_symlinks, enable_privilege, restore_privilege) (revert_to_self): Forward declarations of static functions. <static BOOL g_b_init_get_security_info>: <g_b_init_create_symbolic_link>: New static flags. (globals_of_w32): Initialize them to zero. (GetSecurityInfo_Proc, CreateSymbolicLink_Proc): New typedefs. (map_w32_filename): Improve commentary. Simplify switch. (SYMBOLIC_LINK_FLAG_DIRECTORY): Define if not defined in system headers (most versions of MinGW w32api don't). (get_security_info, create_symbolic_link) (get_file_security_desc_by_handle, is_symlink, chase_symlinks): New functions. (sys_access, sys_chmod): Call 'chase_symlinks' to resolve symlinks in the argument file name. (sys_access): Call unc_volume_file_attributes only if GetFileAttributes fails with network-related error codes. (sys_rename): Diagnose renaming of a symlink when the user doesn't have the required privileges. (get_file_security_desc_by_name): Renamed from get_file_security_desc. (stat_worker): New function, with most of the guts of 'stat', and with addition of handling of symlinks and support for 'lstat'. If possible, get file's attributes and security information by handle, not by name. Produce S_IFLNK bit for symlinks, when called from 'lstat'. (stat, lstat): New functions, call 'stat_worker'. (symlink, readlink, careadlinkat): Rewritten to create and resolve symlinks when the underlying filesystem supports them. lib/src/ntlib.c (lstat): New function, calls 'stat'. nt/inc/sys/stat.h (S_IFLNK): Define. (S_ISLNK): A non-trivial definition. (lstat): Prototype instead of a macro that redirects to 'stat'. lisp/files.el (file-truename): Don't skip symlink-chasing part on windows-nt. Incorporate the resolution of 8+3 short aliases on Windows into the loop that recursively chases symlinks. Compare directory and its parent case-insensitively on MS-Windows and MS-DOS. etc/NEWS: Announce the symlink support on MS-Windows.
-rw-r--r--etc/NEWS2
-rw-r--r--lib-src/ChangeLog4
-rw-r--r--lib-src/ntlib.c6
-rw-r--r--lisp/ChangeLog8
-rw-r--r--lisp/files.el40
-rw-r--r--nt/ChangeLog6
-rw-r--r--nt/inc/sys/stat.h9
-rw-r--r--src/ChangeLog33
-rw-r--r--src/w32.c1082
9 files changed, 1002 insertions, 188 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 68932f02edc..b7fb10881ff 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -596,6 +596,8 @@ is detected.
596Emacs now supports mouse highlight, help-echo (in the echo area), and 596Emacs now supports mouse highlight, help-echo (in the echo area), and
597mouse-autoselect-window. 597mouse-autoselect-window.
598 598
599** On MS-Windows Vista and later Emacs now supports symbolic links.
600
599 601
600* Installation Changes in Emacs 24.1 602* Installation Changes in Emacs 24.1
601 603
diff --git a/lib-src/ChangeLog b/lib-src/ChangeLog
index 955f8cd0330..c98d377f199 100644
--- a/lib-src/ChangeLog
+++ b/lib-src/ChangeLog
@@ -1,3 +1,7 @@
12012-08-03 Eli Zaretskii <eliz@gnu.org>
2
3 * ntlib.c (lstat): New function, calls 'stat'.
4
12012-08-02 Paul Eggert <eggert@cs.ucla.edu> 52012-08-02 Paul Eggert <eggert@cs.ucla.edu>
2 6
3 Use C99-style 'extern inline' if available. 7 Use C99-style 'extern inline' if available.
diff --git a/lib-src/ntlib.c b/lib-src/ntlib.c
index d3b001c157c..7b41941ab14 100644
--- a/lib-src/ntlib.c
+++ b/lib-src/ntlib.c
@@ -374,3 +374,9 @@ stat (const char * path, struct stat * buf)
374 return 0; 374 return 0;
375} 375}
376 376
377int
378lstat (const char * path, struct stat * buf)
379{
380 return stat (path, buf);
381}
382
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 4bd509ce277..d36cc4574fa 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,11 @@
12012-08-03 Eli Zaretskii <eliz@gnu.org>
2
3 * files.el (file-truename): Don't skip symlink-chasing part on
4 windows-nt. Incorporate the resolution of 8+3 short aliases on
5 Windows into the loop that recursively chases symlinks. Compare
6 directory and its parent case-insensitively on MS-Windows and
7 MS-DOS.
8
12012-08-03 Chong Yidong <cyd@gnu.org> 92012-08-03 Chong Yidong <cyd@gnu.org>
2 10
3 * menu-bar.el (menu-bar-tools-menu): Remove PCL-CVS. 11 * menu-bar.el (menu-bar-tools-menu): Remove PCL-CVS.
diff --git a/lisp/files.el b/lisp/files.el
index 7fc7ccc8553..0c895669542 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -1079,9 +1079,7 @@ containing it, until no links are left at any level.
1079 (delq (rassq 'ange-ftp-completion-hook-function tem) tem))))) 1079 (delq (rassq 'ange-ftp-completion-hook-function tem) tem)))))
1080 (or prev-dirs (setq prev-dirs (list nil))) 1080 (or prev-dirs (setq prev-dirs (list nil)))
1081 1081
1082 ;; andrewi@harlequin.co.uk - none of the following code (except for 1082 ;; andrewi@harlequin.co.uk - on Windows, there is an issue with
1083 ;; invoking the file-name handler) currently applies on Windows
1084 ;; (ie. there are no native symlinks), but there is an issue with
1085 ;; case differences being ignored by the OS, and short "8.3 DOS" 1083 ;; case differences being ignored by the OS, and short "8.3 DOS"
1086 ;; name aliases existing for all files. (The short names are not 1084 ;; name aliases existing for all files. (The short names are not
1087 ;; reported by directory-files, but can be used to refer to files.) 1085 ;; reported by directory-files, but can be used to refer to files.)
@@ -1091,31 +1089,15 @@ containing it, until no links are left at any level.
1091 ;; it is stored on disk (expanding short name aliases with the full 1089 ;; it is stored on disk (expanding short name aliases with the full
1092 ;; name in the process). 1090 ;; name in the process).
1093 (if (eq system-type 'windows-nt) 1091 (if (eq system-type 'windows-nt)
1094 (let ((handler (find-file-name-handler filename 'file-truename))) 1092 (unless (string-match "[[*?]" filename)
1095 ;; For file name that has a special handler, call handler. 1093 ;; If filename exists, use its long name. If it doesn't
1096 ;; This is so that ange-ftp can save time by doing a no-op. 1094 ;; exist, the recursion below on the directory of filename
1097 (if handler 1095 ;; will drill down until we find a directory that exists,
1098 (setq filename (funcall handler 'file-truename filename)) 1096 ;; and use the long name of that, with the extra
1099 ;; If filename contains a wildcard, newname will be the old name. 1097 ;; non-existent path components concatenated.
1100 (unless (string-match "[[*?]" filename) 1098 (let ((longname (w32-long-file-name filename)))
1101 ;; If filename exists, use the long name. If it doesn't exist, 1099 (if longname
1102 ;; drill down until we find a directory that exists, and use 1100 (setq filename longname)))))
1103 ;; the long name of that, with the extra non-existent path
1104 ;; components concatenated.
1105 (let ((longname (w32-long-file-name filename))
1106 missing rest)
1107 (if longname
1108 (setq filename longname)
1109 ;; Include the preceding directory separator in the missing
1110 ;; part so subsequent recursion on the rest works.
1111 (setq missing (concat "/" (file-name-nondirectory filename)))
1112 (let ((length (length missing)))
1113 (setq rest
1114 (if (> length (length filename))
1115 ""
1116 (substring filename 0 (- length)))))
1117 (setq filename (concat (file-truename rest) missing))))))
1118 (setq done t)))
1119 1101
1120 ;; If this file directly leads to a link, process that iteratively 1102 ;; If this file directly leads to a link, process that iteratively
1121 ;; so that we don't use lots of stack. 1103 ;; so that we don't use lots of stack.
@@ -1135,6 +1117,8 @@ containing it, until no links are left at any level.
1135 (setq dirfile (directory-file-name dir)) 1117 (setq dirfile (directory-file-name dir))
1136 ;; If these are equal, we have the (or a) root directory. 1118 ;; If these are equal, we have the (or a) root directory.
1137 (or (string= dir dirfile) 1119 (or (string= dir dirfile)
1120 (and (memq system-type '(windows-nt ms-dos cygwin))
1121 (eq (compare-strings dir 0 nil dirfile 0 nil t) t))
1138 ;; If this is the same dir we last got the truename for, 1122 ;; If this is the same dir we last got the truename for,
1139 ;; save time--don't recalculate. 1123 ;; save time--don't recalculate.
1140 (if (assoc dir (car prev-dirs)) 1124 (if (assoc dir (car prev-dirs))
diff --git a/nt/ChangeLog b/nt/ChangeLog
index 8b9163c9f78..d8b9b14a3fb 100644
--- a/nt/ChangeLog
+++ b/nt/ChangeLog
@@ -1,3 +1,9 @@
12012-08-03 Eli Zaretskii <eliz@gnu.org>
2
3 * inc/sys/stat.h (S_IFLNK): Define.
4 (S_ISLNK): A non-trivial definition.
5 (lstat): Prototype instead of a macro that redirects to 'stat'.
6
12012-08-02 Paul Eggert <eggert@cs.ucla.edu> 72012-08-02 Paul Eggert <eggert@cs.ucla.edu>
2 8
3 Use C99-style 'extern inline' if available. 9 Use C99-style 'extern inline' if available.
diff --git a/nt/inc/sys/stat.h b/nt/inc/sys/stat.h
index 57fabff4b0c..b673b80a0e3 100644
--- a/nt/inc/sys/stat.h
+++ b/nt/inc/sys/stat.h
@@ -33,13 +33,14 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
33#include <sys/types.h> 33#include <sys/types.h>
34#include <time.h> 34#include <time.h>
35 35
36#define S_IFMT 0xF000 36#define S_IFMT 0xF800
37 37
38#define S_IFREG 0x8000 38#define S_IFREG 0x8000
39#define S_IFDIR 0x4000 39#define S_IFDIR 0x4000
40#define S_IFBLK 0x3000 40#define S_IFBLK 0x3000
41#define S_IFCHR 0x2000 41#define S_IFCHR 0x2000
42#define S_IFIFO 0x1000 42#define S_IFIFO 0x1000
43#define S_IFLNK 0x0800
43 44
44#define S_IREAD 0x0100 45#define S_IREAD 0x0100
45#define S_IWRITE 0x0080 46#define S_IWRITE 0x0080
@@ -55,6 +56,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
55#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) 56#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
56#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) 57#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
57#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) 58#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
59#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
58 60
59/* These don't exist on Windows, but lib/filemode.c wants them. */ 61/* These don't exist on Windows, but lib/filemode.c wants them. */
60#define S_ISUID 0 62#define S_ISUID 0
@@ -68,7 +70,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
68#define S_IXOTH (S_IXUSR >> 6) 70#define S_IXOTH (S_IXUSR >> 6)
69 71
70#define S_ISSOCK(m) 0 72#define S_ISSOCK(m) 0
71#define S_ISLNK(m) 0
72#define S_ISCTG(p) 0 73#define S_ISCTG(p) 0
73#define S_ISDOOR(m) 0 74#define S_ISDOOR(m) 0
74#define S_ISMPB(m) 0 75#define S_ISMPB(m) 0
@@ -103,9 +104,7 @@ struct stat {
103_CRTIMP int __cdecl __MINGW_NOTHROW fstat (int, struct stat*); 104_CRTIMP int __cdecl __MINGW_NOTHROW fstat (int, struct stat*);
104_CRTIMP int __cdecl __MINGW_NOTHROW chmod (const char*, int); 105_CRTIMP int __cdecl __MINGW_NOTHROW chmod (const char*, int);
105_CRTIMP int __cdecl __MINGW_NOTHROW stat (const char*, struct stat*); 106_CRTIMP int __cdecl __MINGW_NOTHROW stat (const char*, struct stat*);
106 107_CRTIMP int __cdecl __MINGW_NOTHROW lstat (const char*, struct stat*);
107/* fileio.c and dired.c want lstat. */
108#define lstat stat
109 108
110#endif /* INC_SYS_STAT_H_ */ 109#endif /* INC_SYS_STAT_H_ */
111 110
diff --git a/src/ChangeLog b/src/ChangeLog
index 45b24436519..3ba80f69749 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,36 @@
12012-08-03 Eli Zaretskii <eliz@gnu.org>
2
3 Support symlinks on latest versions of MS-Windows.
4 * w32.c: Include winioctl.h and aclapi.h.
5 (is_symlink, chase_symlinks, enable_privilege, restore_privilege)
6 (revert_to_self): Forward declarations of static functions.
7 <static BOOL g_b_init_get_security_info>:
8 <g_b_init_create_symbolic_link>: New static flags.
9 (globals_of_w32): Initialize them to zero.
10 (GetSecurityInfo_Proc, CreateSymbolicLink_Proc): New typedefs.
11 (map_w32_filename): Improve commentary. Simplify switch.
12 (SYMBOLIC_LINK_FLAG_DIRECTORY): Define if not defined in system
13 headers (most versions of MinGW w32api don't).
14 (get_security_info, create_symbolic_link)
15 (get_file_security_desc_by_handle, is_symlink, chase_symlinks):
16 New functions.
17 (sys_access, sys_chmod): Call 'chase_symlinks' to resolve symlinks
18 in the argument file name.
19 (sys_access): Call unc_volume_file_attributes only if
20 GetFileAttributes fails with network-related error codes.
21 (sys_rename): Diagnose renaming of a symlink when the user doesn't
22 have the required privileges.
23 (get_file_security_desc_by_name): Renamed from
24 get_file_security_desc.
25 (stat_worker): New function, with most of the guts of 'stat', and
26 with addition of handling of symlinks and support for 'lstat'. If
27 possible, get file's attributes and security information by
28 handle, not by name. Produce S_IFLNK bit for symlinks, when
29 called from 'lstat'.
30 (stat, lstat): New functions, call 'stat_worker'.
31 (symlink, readlink, careadlinkat): Rewritten to create and resolve
32 symlinks when the underlying filesystem supports them.
33
12012-08-02 Paul Eggert <eggert@cs.ucla.edu> 342012-08-02 Paul Eggert <eggert@cs.ucla.edu>
2 35
3 Fix macroexp crash on Windows with debugging (Bug#12118). 36 Fix macroexp crash on Windows with debugging (Bug#12118).
diff --git a/src/w32.c b/src/w32.c
index 5d2c8a34495..881e3b06efb 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -116,6 +116,42 @@ typedef struct _PROCESS_MEMORY_COUNTERS_EX {
116} PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX; 116} PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
117#endif 117#endif
118 118
119#include <winioctl.h>
120#include <aclapi.h>
121
122#ifdef _MSC_VER
123/* MSVC doesn't provide the definition of REPARSE_DATA_BUFFER, except
124 on ntifs.h, which cannot be included because it triggers conflicts
125 with other Windows API headers. So we define it here by hand. */
126
127typedef struct _REPARSE_DATA_BUFFER {
128 ULONG ReparseTag;
129 USHORT ReparseDataLength;
130 USHORT Reserved;
131 union {
132 struct {
133 USHORT SubstituteNameOffset;
134 USHORT SubstituteNameLength;
135 USHORT PrintNameOffset;
136 USHORT PrintNameLength;
137 ULONG Flags;
138 WCHAR PathBuffer[1];
139 } SymbolicLinkReparseBuffer;
140 struct {
141 USHORT SubstituteNameOffset;
142 USHORT SubstituteNameLength;
143 USHORT PrintNameOffset;
144 USHORT PrintNameLength;
145 WCHAR PathBuffer[1];
146 } MountPointReparseBuffer;
147 struct {
148 UCHAR DataBuffer[1];
149 } GenericReparseBuffer;
150 } DUMMYUNIONNAME;
151} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
152
153#endif
154
119/* TCP connection support. */ 155/* TCP connection support. */
120#include <sys/socket.h> 156#include <sys/socket.h>
121#undef socket 157#undef socket
@@ -156,6 +192,11 @@ Lisp_Object QCloaded_from;
156 192
157void globals_of_w32 (void); 193void globals_of_w32 (void);
158static DWORD get_rid (PSID); 194static DWORD get_rid (PSID);
195static int is_symlink (const char *);
196static char * chase_symlinks (const char *);
197static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
198static int restore_privilege (TOKEN_PRIVILEGES *);
199static BOOL WINAPI revert_to_self (void);
159 200
160 201
161/* Initialization states. 202/* Initialization states.
@@ -173,6 +214,7 @@ static BOOL g_b_init_get_token_information;
173static BOOL g_b_init_lookup_account_sid; 214static BOOL g_b_init_lookup_account_sid;
174static BOOL g_b_init_get_sid_sub_authority; 215static BOOL g_b_init_get_sid_sub_authority;
175static BOOL g_b_init_get_sid_sub_authority_count; 216static BOOL g_b_init_get_sid_sub_authority_count;
217static BOOL g_b_init_get_security_info;
176static BOOL g_b_init_get_file_security; 218static BOOL g_b_init_get_file_security;
177static BOOL g_b_init_get_security_descriptor_owner; 219static BOOL g_b_init_get_security_descriptor_owner;
178static BOOL g_b_init_get_security_descriptor_group; 220static BOOL g_b_init_get_security_descriptor_group;
@@ -192,6 +234,7 @@ static BOOL g_b_init_equal_sid;
192static BOOL g_b_init_copy_sid; 234static BOOL g_b_init_copy_sid;
193static BOOL g_b_init_get_native_system_info; 235static BOOL g_b_init_get_native_system_info;
194static BOOL g_b_init_get_system_times; 236static BOOL g_b_init_get_system_times;
237static BOOL g_b_init_create_symbolic_link;
195 238
196/* 239/*
197 BEGIN: Wrapper functions around OpenProcessToken 240 BEGIN: Wrapper functions around OpenProcessToken
@@ -238,6 +281,15 @@ typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
238 DWORD n); 281 DWORD n);
239typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) ( 282typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
240 PSID pSid); 283 PSID pSid);
284typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
285 HANDLE handle,
286 SE_OBJECT_TYPE ObjectType,
287 SECURITY_INFORMATION SecurityInfo,
288 PSID *ppsidOwner,
289 PSID *ppsidGroup,
290 PACL *ppDacl,
291 PACL *ppSacl,
292 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
241typedef BOOL (WINAPI * GetFileSecurity_Proc) ( 293typedef BOOL (WINAPI * GetFileSecurity_Proc) (
242 LPCTSTR lpFileName, 294 LPCTSTR lpFileName,
243 SECURITY_INFORMATION RequestedInformation, 295 SECURITY_INFORMATION RequestedInformation,
@@ -298,6 +350,10 @@ typedef BOOL (WINAPI * GetSystemTimes_Proc) (
298 LPFILETIME lpIdleTime, 350 LPFILETIME lpIdleTime,
299 LPFILETIME lpKernelTime, 351 LPFILETIME lpKernelTime,
300 LPFILETIME lpUserTime); 352 LPFILETIME lpUserTime);
353typedef BOOLEAN (WINAPI *CreateSymbolicLink_Proc) (
354 LPTSTR lpSymlinkFileName,
355 LPTSTR lpTargetFileName,
356 DWORD dwFlags);
301 357
302 /* ** A utility function ** */ 358 /* ** A utility function ** */
303static BOOL 359static BOOL
@@ -499,6 +555,39 @@ get_sid_sub_authority_count (PSID pSid)
499 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid)); 555 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
500} 556}
501 557
558static DWORD WINAPI
559get_security_info (HANDLE handle,
560 SE_OBJECT_TYPE ObjectType,
561 SECURITY_INFORMATION SecurityInfo,
562 PSID *ppsidOwner,
563 PSID *ppsidGroup,
564 PACL *ppDacl,
565 PACL *ppSacl,
566 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
567{
568 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
569 HMODULE hm_advapi32 = NULL;
570 if (is_windows_9x () == TRUE)
571 {
572 return FALSE;
573 }
574 if (g_b_init_get_security_info == 0)
575 {
576 g_b_init_get_security_info = 1;
577 hm_advapi32 = LoadLibrary ("Advapi32.dll");
578 s_pfn_Get_Security_Info =
579 (GetSecurityInfo_Proc) GetProcAddress (
580 hm_advapi32, "GetSecurityInfo");
581 }
582 if (s_pfn_Get_Security_Info == NULL)
583 {
584 return FALSE;
585 }
586 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
587 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
588 ppSecurityDescriptor));
589}
590
502static BOOL WINAPI 591static BOOL WINAPI
503get_file_security (LPCTSTR lpFileName, 592get_file_security (LPCTSTR lpFileName,
504 SECURITY_INFORMATION RequestedInformation, 593 SECURITY_INFORMATION RequestedInformation,
@@ -726,6 +815,57 @@ get_system_times (LPFILETIME lpIdleTime,
726 return FALSE; 815 return FALSE;
727 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime)); 816 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
728} 817}
818
819static BOOLEAN WINAPI
820create_symbolic_link (LPTSTR lpSymlinkFilename,
821 LPTSTR lpTargetFileName,
822 DWORD dwFlags)
823{
824 static CreateSymbolicLink_Proc s_pfn_Create_Symbolic_Link = NULL;
825 BOOLEAN retval;
826
827 if (is_windows_9x () == TRUE)
828 {
829 errno = ENOSYS;
830 return 0;
831 }
832 if (g_b_init_create_symbolic_link == 0)
833 {
834 g_b_init_create_symbolic_link = 1;
835#ifdef _UNICODE
836 s_pfn_Create_Symbolic_Link =
837 (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
838 "CreateSymbolicLinkW");
839#else
840 s_pfn_Create_Symbolic_Link =
841 (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
842 "CreateSymbolicLinkA");
843#endif
844 }
845 if (s_pfn_Create_Symbolic_Link == NULL)
846 {
847 errno = ENOSYS;
848 return 0;
849 }
850
851 retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName,
852 dwFlags);
853 /* If we were denied creation of the symlink, try again after
854 enabling the SeCreateSymbolicLinkPrivilege for our process. */
855 if (!retval)
856 {
857 TOKEN_PRIVILEGES priv_current;
858
859 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE, &priv_current))
860 {
861 retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName,
862 dwFlags);
863 restore_privilege (&priv_current);
864 revert_to_self ();
865 }
866 }
867 return retval;
868}
729 869
730/* Equivalent of strerror for W32 error codes. */ 870/* Equivalent of strerror for W32 error codes. */
731char * 871char *
@@ -1535,6 +1675,8 @@ init_environment (char ** argv)
1535 read-only filesystem, like CD-ROM or a write-protected floppy. 1675 read-only filesystem, like CD-ROM or a write-protected floppy.
1536 The only way to be really sure is to actually create a file and 1676 The only way to be really sure is to actually create a file and
1537 see if it succeeds. But I think that's too much to ask. */ 1677 see if it succeeds. But I think that's too much to ask. */
1678
1679 /* MSVCRT's _access crashes with D_OK. */
1538 if (tmp && sys_access (tmp, D_OK) == 0) 1680 if (tmp && sys_access (tmp, D_OK) == 0)
1539 { 1681 {
1540 char * var = alloca (strlen (tmp) + 8); 1682 char * var = alloca (strlen (tmp) + 8);
@@ -1774,6 +1916,8 @@ init_environment (char ** argv)
1774 } 1916 }
1775 1917
1776 /* Remember the initial working directory for getwd. */ 1918 /* Remember the initial working directory for getwd. */
1919 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
1920 Does it matter anywhere in Emacs? */
1777 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir)) 1921 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1778 abort (); 1922 abort ();
1779 1923
@@ -1793,6 +1937,8 @@ init_environment (char ** argv)
1793 init_user_info (); 1937 init_user_info ();
1794} 1938}
1795 1939
1940/* Called from expand-file-name when default-directory is not a string. */
1941
1796char * 1942char *
1797emacs_root_dir (void) 1943emacs_root_dir (void)
1798{ 1944{
@@ -2187,8 +2333,15 @@ GetCachedVolumeInformation (char * root_dir)
2187 return info; 2333 return info;
2188} 2334}
2189 2335
2190/* Get information on the volume where name is held; set path pointer to 2336/* Get information on the volume where NAME is held; set path pointer to
2191 start of pathname in name (past UNC header\volume header if present). */ 2337 start of pathname in NAME (past UNC header\volume header if present),
2338 if pPath is non-NULL.
2339
2340 Note: if NAME includes symlinks, the information is for the volume
2341 of the symlink, not of its target. That's because, even though
2342 GetVolumeInformation returns information about the symlink target
2343 of its argument, we only pass the root directory to
2344 GetVolumeInformation, not the full NAME. */
2192static int 2345static int
2193get_volume_info (const char * name, const char ** pPath) 2346get_volume_info (const char * name, const char ** pPath)
2194{ 2347{
@@ -2199,7 +2352,7 @@ get_volume_info (const char * name, const char ** pPath)
2199 if (name == NULL) 2352 if (name == NULL)
2200 return FALSE; 2353 return FALSE;
2201 2354
2202 /* find the root name of the volume if given */ 2355 /* Find the root name of the volume if given. */
2203 if (isalpha (name[0]) && name[1] == ':') 2356 if (isalpha (name[0]) && name[1] == ':')
2204 { 2357 {
2205 rootname = temp; 2358 rootname = temp;
@@ -2239,7 +2392,8 @@ get_volume_info (const char * name, const char ** pPath)
2239} 2392}
2240 2393
2241/* Determine if volume is FAT format (ie. only supports short 8.3 2394/* Determine if volume is FAT format (ie. only supports short 8.3
2242 names); also set path pointer to start of pathname in name. */ 2395 names); also set path pointer to start of pathname in name, if
2396 pPath is non-NULL. */
2243static int 2397static int
2244is_fat_volume (const char * name, const char ** pPath) 2398is_fat_volume (const char * name, const char ** pPath)
2245{ 2399{
@@ -2248,7 +2402,8 @@ is_fat_volume (const char * name, const char ** pPath)
2248 return FALSE; 2402 return FALSE;
2249} 2403}
2250 2404
2251/* Map filename to a valid 8.3 name if necessary. */ 2405/* Map filename to a valid 8.3 name if necessary.
2406 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
2252const char * 2407const char *
2253map_w32_filename (const char * name, const char ** pPath) 2408map_w32_filename (const char * name, const char ** pPath)
2254{ 2409{
@@ -2257,6 +2412,7 @@ map_w32_filename (const char * name, const char ** pPath)
2257 char c; 2412 char c;
2258 char * path; 2413 char * path;
2259 const char * save_name = name; 2414 const char * save_name = name;
2415 int is_fat = 0;
2260 2416
2261 if (strlen (name) >= MAX_PATH) 2417 if (strlen (name) >= MAX_PATH)
2262 { 2418 {
@@ -2278,15 +2434,10 @@ map_w32_filename (const char * name, const char ** pPath)
2278 { 2434 {
2279 switch ( c ) 2435 switch ( c )
2280 { 2436 {
2437 case ':':
2281 case '\\': 2438 case '\\':
2282 case '/': 2439 case '/':
2283 *str++ = '\\'; 2440 *str++ = (c == ':' ? ':' : '\\');
2284 extn = 0; /* reset extension flags */
2285 dots = 2; /* max 2 dots */
2286 left = 8; /* max length 8 for main part */
2287 break;
2288 case ':':
2289 *str++ = ':';
2290 extn = 0; /* reset extension flags */ 2441 extn = 0; /* reset extension flags */
2291 dots = 2; /* max 2 dots */ 2442 dots = 2; /* max 2 dots */
2292 left = 8; /* max length 8 for main part */ 2443 left = 8; /* max length 8 for main part */
@@ -2395,6 +2546,9 @@ opendir (char *filename)
2395 if (wnet_enum_handle != INVALID_HANDLE_VALUE) 2546 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2396 return NULL; 2547 return NULL;
2397 2548
2549 /* Note: We don't support traversal of UNC volumes via symlinks.
2550 Doing so would mean punishing 99.99% of use cases by resolving
2551 all the possible symlinks in FILENAME, recursively. */
2398 if (is_unc_volume (filename)) 2552 if (is_unc_volume (filename))
2399 { 2553 {
2400 wnet_enum_handle = open_unc_volume (filename); 2554 wnet_enum_handle = open_unc_volume (filename);
@@ -2411,6 +2565,9 @@ opendir (char *filename)
2411 2565
2412 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN); 2566 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
2413 dir_pathname[MAXPATHLEN] = '\0'; 2567 dir_pathname[MAXPATHLEN] = '\0';
2568 /* Note: We don't support symlinks to file names on FAT volumes.
2569 Doing so would mean punishing 99.99% of use cases by resolving
2570 all the possible symlinks in FILENAME, recursively. */
2414 dir_is_fat = is_fat_volume (filename, NULL); 2571 dir_is_fat = is_fat_volume (filename, NULL);
2415 2572
2416 return dirp; 2573 return dirp;
@@ -2457,6 +2614,9 @@ readdir (DIR *dirp)
2457 strcat (filename, "\\"); 2614 strcat (filename, "\\");
2458 strcat (filename, "*"); 2615 strcat (filename, "*");
2459 2616
2617 /* Note: No need to resolve symlinks in FILENAME, because
2618 FindFirst opens the directory that is the target of a
2619 symlink. */
2460 dir_find_handle = FindFirstFile (filename, &dir_find_data); 2620 dir_find_handle = FindFirstFile (filename, &dir_find_data);
2461 2621
2462 if (dir_find_handle == INVALID_HANDLE_VALUE) 2622 if (dir_find_handle == INVALID_HANDLE_VALUE)
@@ -2650,21 +2810,34 @@ sys_access (const char * path, int mode)
2650 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its 2810 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
2651 newer versions blow up when passed D_OK. */ 2811 newer versions blow up when passed D_OK. */
2652 path = map_w32_filename (path, NULL); 2812 path = map_w32_filename (path, NULL);
2653 if (is_unc_volume (path)) 2813 /* If the last element of PATH is a symlink, we need to resolve it
2654 { 2814 to get the attributes of its target file. Note: any symlinks in
2655 attributes = unc_volume_file_attributes (path); 2815 PATH elements other than the last one are transparently resolved
2656 if (attributes == -1) { 2816 by GetFileAttributes below. */
2657 errno = EACCES; 2817 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
2658 return -1; 2818 path = chase_symlinks (path);
2659 } 2819
2660 } 2820 if ((attributes = GetFileAttributes (path)) == -1)
2661 else if ((attributes = GetFileAttributes (path)) == -1)
2662 { 2821 {
2663 DWORD w32err = GetLastError (); 2822 DWORD w32err = GetLastError ();
2664 2823
2665 switch (w32err) 2824 switch (w32err)
2666 { 2825 {
2826 case ERROR_INVALID_NAME:
2827 case ERROR_BAD_PATHNAME:
2828 if (is_unc_volume (path))
2829 {
2830 attributes = unc_volume_file_attributes (path);
2831 if (attributes == -1)
2832 {
2833 errno = EACCES;
2834 return -1;
2835 }
2836 break;
2837 }
2838 /* FALLTHROUGH */
2667 case ERROR_FILE_NOT_FOUND: 2839 case ERROR_FILE_NOT_FOUND:
2840 case ERROR_BAD_NETPATH:
2668 errno = ENOENT; 2841 errno = ENOENT;
2669 break; 2842 break;
2670 default: 2843 default:
@@ -2700,7 +2873,8 @@ sys_chdir (const char * path)
2700int 2873int
2701sys_chmod (const char * path, int mode) 2874sys_chmod (const char * path, int mode)
2702{ 2875{
2703 return _chmod (map_w32_filename (path, NULL), mode); 2876 path = chase_symlinks (map_w32_filename (path, NULL));
2877 return _chmod (path, mode);
2704} 2878}
2705 2879
2706int 2880int
@@ -2980,6 +3154,7 @@ sys_rename (const char * oldname, const char * newname)
2980 3154
2981 if (result < 0) 3155 if (result < 0)
2982 { 3156 {
3157 DWORD w32err = GetLastError ();
2983 3158
2984 if (errno == EACCES 3159 if (errno == EACCES
2985 && newname_dev != oldname_dev) 3160 && newname_dev != oldname_dev)
@@ -2992,7 +3167,7 @@ sys_rename (const char * oldname, const char * newname)
2992 DWORD attributes; 3167 DWORD attributes;
2993 3168
2994 if ((attributes = GetFileAttributes (temp)) != -1 3169 if ((attributes = GetFileAttributes (temp)) != -1
2995 && attributes & FILE_ATTRIBUTE_DIRECTORY) 3170 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
2996 errno = EXDEV; 3171 errno = EXDEV;
2997 } 3172 }
2998 else if (errno == EEXIST) 3173 else if (errno == EEXIST)
@@ -3003,6 +3178,14 @@ sys_rename (const char * oldname, const char * newname)
3003 return result; 3178 return result;
3004 result = rename (temp, newname); 3179 result = rename (temp, newname);
3005 } 3180 }
3181 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
3182 && is_symlink (temp))
3183 {
3184 /* This is Windows prohibiting the user from creating a
3185 symlink in another place, since that requires
3186 privileges. */
3187 errno = EPERM;
3188 }
3006 } 3189 }
3007 3190
3008 return result; 3191 return result;
@@ -3133,7 +3316,23 @@ generate_inode_val (const char * name)
3133#endif 3316#endif
3134 3317
3135static PSECURITY_DESCRIPTOR 3318static PSECURITY_DESCRIPTOR
3136get_file_security_desc (const char *fname) 3319get_file_security_desc_by_handle (HANDLE h)
3320{
3321 PSECURITY_DESCRIPTOR psd = NULL;
3322 DWORD err;
3323 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3324 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3325
3326 err = get_security_info (h, SE_FILE_OBJECT, si,
3327 NULL, NULL, NULL, NULL, &psd);
3328 if (err != ERROR_SUCCESS)
3329 return NULL;
3330
3331 return psd;
3332}
3333
3334static PSECURITY_DESCRIPTOR
3335get_file_security_desc_by_name (const char *fname)
3137{ 3336{
3138 PSECURITY_DESCRIPTOR psd = NULL; 3337 PSECURITY_DESCRIPTOR psd = NULL;
3139 DWORD sd_len, err; 3338 DWORD sd_len, err;
@@ -3349,18 +3548,24 @@ is_slow_fs (const char *name)
3349 3548
3350/* MSVC stat function can't cope with UNC names and has other bugs, so 3549/* MSVC stat function can't cope with UNC names and has other bugs, so
3351 replace it with our own. This also allows us to calculate consistent 3550 replace it with our own. This also allows us to calculate consistent
3352 inode values without hacks in the main Emacs code. */ 3551 inode values and owner/group without hacks in the main Emacs code. */
3353int 3552
3354stat (const char * path, struct stat * buf) 3553static int
3554stat_worker (const char * path, struct stat * buf, int follow_symlinks)
3355{ 3555{
3356 char *name, *r; 3556 char *name, *save_name, *r;
3357 WIN32_FIND_DATA wfd; 3557 WIN32_FIND_DATA wfd;
3358 HANDLE fh; 3558 HANDLE fh;
3359 unsigned __int64 fake_inode; 3559 unsigned __int64 fake_inode = 0;
3360 int permission; 3560 int permission;
3361 int len; 3561 int len;
3362 int rootdir = FALSE; 3562 int rootdir = FALSE;
3363 PSECURITY_DESCRIPTOR psd = NULL; 3563 PSECURITY_DESCRIPTOR psd = NULL;
3564 int is_a_symlink = 0;
3565 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
3566 DWORD access_rights = 0;
3567 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
3568 FILETIME ctime, atime, wtime;
3364 3569
3365 if (path == NULL || buf == NULL) 3570 if (path == NULL || buf == NULL)
3366 { 3571 {
@@ -3368,7 +3573,7 @@ stat (const char * path, struct stat * buf)
3368 return -1; 3573 return -1;
3369 } 3574 }
3370 3575
3371 name = (char *) map_w32_filename (path, &path); 3576 save_name = name = (char *) map_w32_filename (path, &path);
3372 /* Must be valid filename, no wild cards or other invalid 3577 /* Must be valid filename, no wild cards or other invalid
3373 characters. We use _mbspbrk to support multibyte strings that 3578 characters. We use _mbspbrk to support multibyte strings that
3374 might look to strpbrk as if they included literal *, ?, and other 3579 might look to strpbrk as if they included literal *, ?, and other
@@ -3380,99 +3585,67 @@ stat (const char * path, struct stat * buf)
3380 return -1; 3585 return -1;
3381 } 3586 }
3382 3587
3383 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3384 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
3385 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
3386 {
3387 r[1] = r[2] = '\0';
3388 }
3389
3390 /* Remove trailing directory separator, unless name is the root 3588 /* Remove trailing directory separator, unless name is the root
3391 directory of a drive or UNC volume in which case ensure there 3589 directory of a drive or UNC volume in which case ensure there
3392 is a trailing separator. */ 3590 is a trailing separator. */
3393 len = strlen (name); 3591 len = strlen (name);
3394 rootdir = (path >= name + len - 1
3395 && (IS_DIRECTORY_SEP (*path) || *path == 0));
3396 name = strcpy (alloca (len + 2), name); 3592 name = strcpy (alloca (len + 2), name);
3397 3593
3398 if (is_unc_volume (name)) 3594 /* Avoid a somewhat costly call to is_symlink if the filesystem
3399 { 3595 doesn't support symlinks. */
3400 DWORD attrs = unc_volume_file_attributes (name); 3596 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
3401 3597 is_a_symlink = is_symlink (name);
3402 if (attrs == -1) 3598
3403 return -1; 3599 /* Plan A: Open the file and get all the necessary information via
3404 3600 the resulting handle. This solves several issues in one blow:
3405 memset (&wfd, 0, sizeof (wfd)); 3601
3406 wfd.dwFileAttributes = attrs; 3602 . retrieves attributes for the target of a symlink, if needed
3407 wfd.ftCreationTime = utc_base_ft; 3603 . gets attributes of root directories and symlinks pointing to
3408 wfd.ftLastAccessTime = utc_base_ft; 3604 root directories, thus avoiding the need for special-casing
3409 wfd.ftLastWriteTime = utc_base_ft; 3605 these and detecting them by examining the file-name format
3410 strcpy (wfd.cFileName, name); 3606 . retrieves more accurate attributes (e.g., non-zero size for
3411 } 3607 some directories, esp. directories that are junction points)
3412 else if (rootdir) 3608 . correctly resolves "c:/..", "/.." and similar file names
3413 { 3609 . avoids run-time penalties for 99% of use cases
3414 if (!IS_DIRECTORY_SEP (name[len-1])) 3610
3415 strcat (name, "\\"); 3611 Plan A is always tried first, unless the user asked not to (but
3416 if (GetDriveType (name) < 2) 3612 if the file is a symlink and we need to follow links, we try Plan
3417 { 3613 A even if the user asked not to).
3418 errno = ENOENT; 3614
3419 return -1; 3615 If Plan A fails, we go to Plan B (below), where various
3420 } 3616 potentially expensive techniques must be used to handle "special"
3421 memset (&wfd, 0, sizeof (wfd)); 3617 files such as UNC volumes etc. */
3422 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
3423 wfd.ftCreationTime = utc_base_ft;
3424 wfd.ftLastAccessTime = utc_base_ft;
3425 wfd.ftLastWriteTime = utc_base_ft;
3426 strcpy (wfd.cFileName, name);
3427 }
3428 else
3429 {
3430 if (IS_DIRECTORY_SEP (name[len-1]))
3431 name[len - 1] = 0;
3432
3433 /* (This is hacky, but helps when doing file completions on
3434 network drives.) Optimize by using information available from
3435 active readdir if possible. */
3436 len = strlen (dir_pathname);
3437 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
3438 len--;
3439 if (dir_find_handle != INVALID_HANDLE_VALUE
3440 && strnicmp (name, dir_pathname, len) == 0
3441 && IS_DIRECTORY_SEP (name[len])
3442 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
3443 {
3444 /* This was the last entry returned by readdir. */
3445 wfd = dir_find_data;
3446 }
3447 else
3448 {
3449 logon_network_drive (name);
3450
3451 fh = FindFirstFile (name, &wfd);
3452 if (fh == INVALID_HANDLE_VALUE)
3453 {
3454 errno = ENOENT;
3455 return -1;
3456 }
3457 FindClose (fh);
3458 }
3459 }
3460
3461 if (!(NILP (Vw32_get_true_file_attributes) 3618 if (!(NILP (Vw32_get_true_file_attributes)
3462 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name))) 3619 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
3463 /* No access rights required to get info. */ 3620 /* Following symlinks requires getting the info by handle. */
3464 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING, 3621 || (is_a_symlink && follow_symlinks))
3465 FILE_FLAG_BACKUP_SEMANTICS, NULL))
3466 != INVALID_HANDLE_VALUE)
3467 { 3622 {
3623 BY_HANDLE_FILE_INFORMATION info;
3624
3625 if (is_a_symlink && !follow_symlinks)
3626 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
3627 /* READ_CONTROL access rights are required to get security info
3628 by handle. But if the OS doesn't support security in the
3629 first place, we don't need to try. */
3630 if (is_windows_9x () != TRUE)
3631 access_rights |= READ_CONTROL;
3632
3633 fh = CreateFile (name, access_rights, 0, NULL, OPEN_EXISTING,
3634 file_flags, NULL);
3635 /* If CreateFile fails with READ_CONTROL, try again with zero as
3636 access rights. */
3637 if (fh == INVALID_HANDLE_VALUE && access_rights)
3638 fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
3639 file_flags, NULL);
3640 if (fh == INVALID_HANDLE_VALUE)
3641 goto no_true_file_attributes;
3642
3468 /* This is more accurate in terms of getting the correct number 3643 /* This is more accurate in terms of getting the correct number
3469 of links, but is quite slow (it is noticeable when Emacs is 3644 of links, but is quite slow (it is noticeable when Emacs is
3470 making a list of file name completions). */ 3645 making a list of file name completions). */
3471 BY_HANDLE_FILE_INFORMATION info;
3472
3473 if (GetFileInformationByHandle (fh, &info)) 3646 if (GetFileInformationByHandle (fh, &info))
3474 { 3647 {
3475 buf->st_nlink = info.nNumberOfLinks; 3648 nlinks = info.nNumberOfLinks;
3476 /* Might as well use file index to fake inode values, but this 3649 /* Might as well use file index to fake inode values, but this
3477 is not guaranteed to be unique unless we keep a handle open 3650 is not guaranteed to be unique unless we keep a handle open
3478 all the time (even then there are situations where it is 3651 all the time (even then there are situations where it is
@@ -3481,20 +3654,53 @@ stat (const char * path, struct stat * buf)
3481 fake_inode = info.nFileIndexHigh; 3654 fake_inode = info.nFileIndexHigh;
3482 fake_inode <<= 32; 3655 fake_inode <<= 32;
3483 fake_inode += info.nFileIndexLow; 3656 fake_inode += info.nFileIndexLow;
3657 serialnum = info.dwVolumeSerialNumber;
3658 fs_high = info.nFileSizeHigh;
3659 fs_low = info.nFileSizeLow;
3660 ctime = info.ftCreationTime;
3661 atime = info.ftLastAccessTime;
3662 wtime = info.ftLastWriteTime;
3663 fattrs = info.dwFileAttributes;
3484 } 3664 }
3485 else 3665 else
3486 { 3666 {
3487 buf->st_nlink = 1; 3667 /* We don't go to Plan B here, because it's not clear that
3488 fake_inode = 0; 3668 it's a good idea. The only known use case where
3669 CreateFile succeeds, but GetFileInformationByHandle fails
3670 (with ERROR_INVALID_FUNCTION) is for character devices
3671 such as NUL, PRN, etc. For these, switching to Plan B is
3672 a net loss, because we lose the character device
3673 attribute returned by GetFileType below (FindFirstFile
3674 doesn't set that bit in the attributes), and the other
3675 fields don't make sense for character devices anyway.
3676 Emacs doesn't really care for non-file entities in the
3677 context of l?stat, so neither do we. */
3678
3679 /* w32err is assigned so one could put a breakpoint here and
3680 examine its value, when GetFileInformationByHandle
3681 fails. */
3682 DWORD w32err = GetLastError ();
3683
3684 switch (w32err)
3685 {
3686 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
3687 errno = ENOENT;
3688 return -1;
3689 }
3489 } 3690 }
3490 3691
3491 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 3692 /* Test for a symlink before testing for a directory, since
3492 { 3693 symlinks to directories have the directory bit set, but we
3493 buf->st_mode = S_IFDIR; 3694 don't want them to appear as directories. */
3494 } 3695 if (is_a_symlink && !follow_symlinks)
3696 buf->st_mode = S_IFLNK;
3697 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
3698 buf->st_mode = S_IFDIR;
3495 else 3699 else
3496 { 3700 {
3497 switch (GetFileType (fh)) 3701 DWORD ftype = GetFileType (fh);
3702
3703 switch (ftype)
3498 { 3704 {
3499 case FILE_TYPE_DISK: 3705 case FILE_TYPE_DISK:
3500 buf->st_mode = S_IFREG; 3706 buf->st_mode = S_IFREG;
@@ -3508,21 +3714,143 @@ stat (const char * path, struct stat * buf)
3508 buf->st_mode = S_IFCHR; 3714 buf->st_mode = S_IFCHR;
3509 } 3715 }
3510 } 3716 }
3717 /* We produce the fallback owner and group data, based on the
3718 current user that runs Emacs, in the following cases:
3719
3720 . this is Windows 9X
3721 . getting security by handle failed, and we need to produce
3722 information for the target of a symlink (this is better
3723 than producing a potentially misleading info about the
3724 symlink itself)
3725
3726 If getting security by handle fails, and we don't need to
3727 resolve symlinks, we try getting security by name. */
3728 if (is_windows_9x () != TRUE)
3729 psd = get_file_security_desc_by_handle (fh);
3730 if (psd)
3731 {
3732 get_file_owner_and_group (psd, name, buf);
3733 LocalFree (psd);
3734 }
3735 else if (is_windows_9x () == TRUE)
3736 get_file_owner_and_group (NULL, name, buf);
3737 else if (!(is_a_symlink && follow_symlinks))
3738 {
3739 psd = get_file_security_desc_by_name (name);
3740 get_file_owner_and_group (psd, name, buf);
3741 xfree (psd);
3742 }
3743 else
3744 get_file_owner_and_group (NULL, name, buf);
3511 CloseHandle (fh); 3745 CloseHandle (fh);
3512 psd = get_file_security_desc (name);
3513 get_file_owner_and_group (psd, name, buf);
3514 } 3746 }
3515 else 3747 else
3516 { 3748 {
3517 /* Don't bother to make this information more accurate. */ 3749 no_true_file_attributes:
3518 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 3750 /* Plan B: Either getting a handle on the file failed, or the
3519 S_IFDIR : S_IFREG; 3751 caller explicitly asked us to not bother making this
3520 buf->st_nlink = 1; 3752 information more accurate.
3521 fake_inode = 0; 3753
3754 Implementation note: In Plan B, we never bother to resolve
3755 symlinks, even if we got here because we tried Plan A and
3756 failed. That's because, even if the caller asked for extra
3757 precision by setting Vw32_get_true_file_attributes to t,
3758 resolving symlinks requires acquiring a file handle to the
3759 symlink, which we already know will fail. And if the user
3760 did not ask for extra precision, resolving symlinks will fly
3761 in the face of that request, since the user then wants the
3762 lightweight version of the code. */
3763 rootdir = (path >= save_name + len - 1
3764 && (IS_DIRECTORY_SEP (*path) || *path == 0));
3765
3766 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3767 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
3768 if (IS_DIRECTORY_SEP (r[0])
3769 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
3770 r[1] = r[2] = '\0';
3771
3772 /* Note: If NAME is a symlink to the root of a UNC volume
3773 (i.e. "\\SERVER"), we will not detect that here, and we will
3774 return data about the symlink as result of FindFirst below.
3775 This is unfortunate, but that marginal use case does not
3776 justify a call to chase_symlinks which would impose a penalty
3777 on all the other use cases. (We get here for symlinks to
3778 roots of UNC volumes because CreateFile above fails for them,
3779 unlike with symlinks to root directories X:\ of drives.) */
3780 if (is_unc_volume (name))
3781 {
3782 fattrs = unc_volume_file_attributes (name);
3783 if (fattrs == -1)
3784 return -1;
3785
3786 ctime = atime = wtime = utc_base_ft;
3787 }
3788 else if (rootdir)
3789 {
3790 if (!IS_DIRECTORY_SEP (name[len-1]))
3791 strcat (name, "\\");
3792 if (GetDriveType (name) < 2)
3793 {
3794 errno = ENOENT;
3795 return -1;
3796 }
3797
3798 fattrs = FILE_ATTRIBUTE_DIRECTORY;
3799 ctime = atime = wtime = utc_base_ft;
3800 }
3801 else
3802 {
3803 if (IS_DIRECTORY_SEP (name[len-1]))
3804 name[len - 1] = 0;
3805
3806 /* (This is hacky, but helps when doing file completions on
3807 network drives.) Optimize by using information available from
3808 active readdir if possible. */
3809 len = strlen (dir_pathname);
3810 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
3811 len--;
3812 if (dir_find_handle != INVALID_HANDLE_VALUE
3813 && !(is_a_symlink && follow_symlinks)
3814 && strnicmp (save_name, dir_pathname, len) == 0
3815 && IS_DIRECTORY_SEP (name[len])
3816 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
3817 {
3818 /* This was the last entry returned by readdir. */
3819 wfd = dir_find_data;
3820 }
3821 else
3822 {
3823 logon_network_drive (name);
3824
3825 fh = FindFirstFile (name, &wfd);
3826 if (fh == INVALID_HANDLE_VALUE)
3827 {
3828 errno = ENOENT;
3829 return -1;
3830 }
3831 FindClose (fh);
3832 }
3833 /* Note: if NAME is a symlink, the information we get from
3834 FindFirstFile is for the symlink, not its target. */
3835 fattrs = wfd.dwFileAttributes;
3836 ctime = wfd.ftCreationTime;
3837 atime = wfd.ftLastAccessTime;
3838 wtime = wfd.ftLastWriteTime;
3839 fs_high = wfd.nFileSizeHigh;
3840 fs_low = wfd.nFileSizeLow;
3841 fake_inode = 0;
3842 nlinks = 1;
3843 serialnum = volume_info.serialnum;
3844 }
3845 if (is_a_symlink && !follow_symlinks)
3846 buf->st_mode = S_IFLNK;
3847 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
3848 buf->st_mode = S_IFDIR;
3849 else
3850 buf->st_mode = S_IFREG;
3522 3851
3523 get_file_owner_and_group (NULL, name, buf); 3852 get_file_owner_and_group (NULL, name, buf);
3524 } 3853 }
3525 xfree (psd);
3526 3854
3527#if 0 3855#if 0
3528 /* Not sure if there is any point in this. */ 3856 /* Not sure if there is any point in this. */
@@ -3536,43 +3864,56 @@ stat (const char * path, struct stat * buf)
3536 } 3864 }
3537#endif 3865#endif
3538 3866
3539 /* MSVC defines _ino_t to be short; other libc's might not. */ 3867 buf->st_ino = fake_inode;
3540 if (sizeof (buf->st_ino) == 2)
3541 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3542 else
3543 buf->st_ino = fake_inode;
3544 3868
3545 /* volume_info is set indirectly by map_w32_filename */ 3869 buf->st_dev = serialnum;
3546 buf->st_dev = volume_info.serialnum; 3870 buf->st_rdev = serialnum;
3547 buf->st_rdev = volume_info.serialnum;
3548 3871
3549 buf->st_size = wfd.nFileSizeHigh; 3872 buf->st_size = fs_high;
3550 buf->st_size <<= 32; 3873 buf->st_size <<= 32;
3551 buf->st_size += wfd.nFileSizeLow; 3874 buf->st_size += fs_low;
3875 buf->st_nlink = nlinks;
3552 3876
3553 /* Convert timestamps to Unix format. */ 3877 /* Convert timestamps to Unix format. */
3554 buf->st_mtime = convert_time (wfd.ftLastWriteTime); 3878 buf->st_mtime = convert_time (wtime);
3555 buf->st_atime = convert_time (wfd.ftLastAccessTime); 3879 buf->st_atime = convert_time (atime);
3556 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime; 3880 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3557 buf->st_ctime = convert_time (wfd.ftCreationTime); 3881 buf->st_ctime = convert_time (ctime);
3558 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime; 3882 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3559 3883
3560 /* determine rwx permissions */ 3884 /* determine rwx permissions */
3561 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) 3885 if (is_a_symlink && !follow_symlinks)
3562 permission = S_IREAD; 3886 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
3563 else 3887 else
3564 permission = S_IREAD | S_IWRITE; 3888 {
3889 if (fattrs & FILE_ATTRIBUTE_READONLY)
3890 permission = S_IREAD;
3891 else
3892 permission = S_IREAD | S_IWRITE;
3565 3893
3566 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 3894 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
3567 permission |= S_IEXEC; 3895 permission |= S_IEXEC;
3568 else if (is_exec (name)) 3896 else if (is_exec (name))
3569 permission |= S_IEXEC; 3897 permission |= S_IEXEC;
3898 }
3570 3899
3571 buf->st_mode |= permission | (permission >> 3) | (permission >> 6); 3900 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3572 3901
3573 return 0; 3902 return 0;
3574} 3903}
3575 3904
3905int
3906stat (const char * path, struct stat * buf)
3907{
3908 return stat_worker (path, buf, 1);
3909}
3910
3911int
3912lstat (const char * path, struct stat * buf)
3913{
3914 return stat_worker (path, buf, 0);
3915}
3916
3576/* Provide fstat and utime as well as stat for consistent handling of 3917/* Provide fstat and utime as well as stat for consistent handling of
3577 file timestamps. */ 3918 file timestamps. */
3578int 3919int
@@ -3713,31 +4054,460 @@ utime (const char *name, struct utimbuf *times)
3713} 4054}
3714 4055
3715 4056
3716/* Symlink-related functions that always fail. Used in fileio.c and in 4057/* Symlink-related functions. */
3717 sysdep.c to avoid #ifdef's. */ 4058#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4059#define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4060#endif
4061
3718int 4062int
3719symlink (char const *dummy1, char const *dummy2) 4063symlink (char const *filename, char const *linkname)
3720{ 4064{
3721 errno = ENOSYS; 4065 char linkfn[MAX_PATH], *tgtfn;
3722 return -1; 4066 DWORD flags = 0;
4067 int dir_access, filename_ends_in_slash;
4068
4069 /* Diagnostics follows Posix as much as possible. */
4070 if (filename == NULL || linkname == NULL)
4071 {
4072 errno = EFAULT;
4073 return -1;
4074 }
4075 if (!*filename)
4076 {
4077 errno = ENOENT;
4078 return -1;
4079 }
4080 if (strlen (filename) > MAX_PATH || strlen (linkname) > MAX_PATH)
4081 {
4082 errno = ENAMETOOLONG;
4083 return -1;
4084 }
4085
4086 strcpy (linkfn, map_w32_filename (linkname, NULL));
4087 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
4088 {
4089 errno = EPERM;
4090 return -1;
4091 }
4092
4093 /* Note: since empty FILENAME was already rejected, we can safely
4094 refer to FILENAME[1]. */
4095 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
4096 {
4097 /* Non-absolute FILENAME is understood as being relative to
4098 LINKNAME's directory. We need to prepend that directory to
4099 FILENAME to get correct results from sys_access below, since
4100 otherwise it will interpret FILENAME relative to the
4101 directory where the Emacs process runs. Note that
4102 make-symbolic-link always makes sure LINKNAME is a fully
4103 expanded file name. */
4104 char tem[MAX_PATH];
4105 char *p = linkfn + strlen (linkfn);
4106
4107 while (p > linkfn && !IS_ANY_SEP (p[-1]))
4108 p--;
4109 if (p > linkfn)
4110 strncpy (tem, linkfn, p - linkfn);
4111 tem[p - linkfn] = '\0';
4112 strcat (tem, filename);
4113 dir_access = sys_access (tem, D_OK);
4114 }
4115 else
4116 dir_access = sys_access (filename, D_OK);
4117
4118 /* Since Windows distinguishes between symlinks to directories and
4119 to files, we provide a kludgey feature: if FILENAME doesn't
4120 exist, but ends in a slash, we create a symlink to directory. If
4121 FILENAME exists and is a directory, we always create a symlink to
4122 directory. */
4123 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
4124 if (dir_access == 0 || filename_ends_in_slash)
4125 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
4126
4127 tgtfn = (char *)map_w32_filename (filename, NULL);
4128 if (filename_ends_in_slash)
4129 tgtfn[strlen (tgtfn) - 1] = '\0';
4130
4131 errno = 0;
4132 if (!create_symbolic_link (linkfn, tgtfn, flags))
4133 {
4134 /* ENOSYS is set by create_symbolic_link, when it detects that
4135 the OS doesn't support the CreateSymbolicLink API. */
4136 if (errno != ENOSYS)
4137 {
4138 DWORD w32err = GetLastError ();
4139
4140 switch (w32err)
4141 {
4142 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4143 TGTFN point to the same file name, go figure. */
4144 case ERROR_SUCCESS:
4145 case ERROR_FILE_EXISTS:
4146 errno = EEXIST;
4147 break;
4148 case ERROR_ACCESS_DENIED:
4149 errno = EACCES;
4150 break;
4151 case ERROR_FILE_NOT_FOUND:
4152 case ERROR_PATH_NOT_FOUND:
4153 case ERROR_BAD_NETPATH:
4154 case ERROR_INVALID_REPARSE_DATA:
4155 errno = ENOENT;
4156 break;
4157 case ERROR_DIRECTORY:
4158 errno = EISDIR;
4159 break;
4160 case ERROR_PRIVILEGE_NOT_HELD:
4161 case ERROR_NOT_ALL_ASSIGNED:
4162 errno = EPERM;
4163 break;
4164 case ERROR_DISK_FULL:
4165 errno = ENOSPC;
4166 break;
4167 default:
4168 errno = EINVAL;
4169 break;
4170 }
4171 }
4172 return -1;
4173 }
4174 return 0;
3723} 4175}
3724 4176
4177/* A quick inexpensive test of whether FILENAME identifies a file that
4178 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4179 must already be in the normalized form returned by
4180 map_w32_filename.
4181
4182 Note: for repeated operations on many files, it is best to test
4183 whether the underlying volume actually supports symlinks, by
4184 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4185 avoid the call to this function if it doesn't. That's because the
4186 call to GetFileAttributes takes a non-negligible time, expecially
4187 on non-local or removable filesystems. See stat_worker for an
4188 example of how to do that. */
4189static int
4190is_symlink (const char *filename)
4191{
4192 DWORD attrs;
4193 WIN32_FIND_DATA wfd;
4194 HANDLE fh;
4195
4196 attrs = GetFileAttributes (filename);
4197 if (attrs == -1)
4198 {
4199 DWORD w32err = GetLastError ();
4200
4201 switch (w32err)
4202 {
4203 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
4204 break;
4205 case ERROR_ACCESS_DENIED:
4206 errno = EACCES;
4207 break;
4208 case ERROR_FILE_NOT_FOUND:
4209 case ERROR_PATH_NOT_FOUND:
4210 default:
4211 errno = ENOENT;
4212 break;
4213 }
4214 return 0;
4215 }
4216 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
4217 return 0;
4218 logon_network_drive (filename);
4219 fh = FindFirstFile (filename, &wfd);
4220 if (fh == INVALID_HANDLE_VALUE)
4221 return 0;
4222 FindClose (fh);
4223 return (wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
4224 && (wfd.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
4225}
4226
4227/* If NAME identifies a symbolic link, copy into BUF the file name of
4228 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4229 null-terminate the target name, even if it fits. Return the number
4230 of bytes copied, or -1 if NAME is not a symlink or any error was
4231 encountered while resolving it. The file name copied into BUF is
4232 encoded in the current ANSI codepage. */
3725ssize_t 4233ssize_t
3726readlink (const char *name, char *dummy1, size_t dummy2) 4234readlink (const char *name, char *buf, size_t buf_size)
3727{ 4235{
3728 /* `access' is much faster than `stat' on MS-Windows. */ 4236 const char *path;
3729 if (sys_access (name, 0) == 0) 4237 TOKEN_PRIVILEGES privs;
3730 errno = EINVAL; 4238 int restore_privs = 0;
3731 return -1; 4239 HANDLE sh;
4240 ssize_t retval;
4241
4242 if (name == NULL)
4243 {
4244 errno = EFAULT;
4245 return -1;
4246 }
4247 if (!*name)
4248 {
4249 errno = ENOENT;
4250 return -1;
4251 }
4252
4253 path = map_w32_filename (name, NULL);
4254
4255 if (strlen (path) > MAX_PATH)
4256 {
4257 errno = ENAMETOOLONG;
4258 return -1;
4259 }
4260
4261 errno = 0;
4262 if (is_windows_9x () == TRUE
4263 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
4264 || !is_symlink (path))
4265 {
4266 if (!errno)
4267 errno = EINVAL; /* not a symlink */
4268 return -1;
4269 }
4270
4271 /* Done with simple tests, now we're in for some _real_ work. */
4272 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
4273 restore_privs = 1;
4274 /* Implementation note: From here and onward, don't return early,
4275 since that will fail to restore the original set of privileges of
4276 the calling thread. */
4277
4278 retval = -1; /* not too optimistic, are we? */
4279
4280 /* Note: In the next call to CreateFile, we use zero as the 2nd
4281 argument because, when the symlink is a hidden/system file,
4282 e.g. 'C:\Users\All Users', GENERIC_READ fails with
4283 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
4284 and directory symlinks. */
4285 sh = CreateFile (path, 0, 0, NULL, OPEN_EXISTING,
4286 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
4287 NULL);
4288 if (sh != INVALID_HANDLE_VALUE)
4289 {
4290 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
4291 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
4292 DWORD retbytes;
4293
4294 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
4295 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
4296 &retbytes, NULL))
4297 errno = EIO;
4298 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
4299 errno = EINVAL;
4300 else
4301 {
4302 /* Copy the link target name, in wide characters, fro
4303 reparse_data, then convert it to multibyte encoding in
4304 the current locale's codepage. */
4305 WCHAR *lwname;
4306 BYTE lname[MAX_PATH];
4307 USHORT lname_len;
4308 USHORT lwname_len =
4309 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
4310 WCHAR *lwname_src =
4311 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
4312 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
4313
4314 /* According to MSDN, PrintNameLength does not include the
4315 terminating null character. */
4316 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
4317 memcpy (lwname, lwname_src, lwname_len);
4318 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
4319
4320 /* FIXME: Should we use the current file-name coding system
4321 instead of the fixed value of the ANSI codepage? */
4322 lname_len = WideCharToMultiByte (w32_ansi_code_page, 0, lwname, -1,
4323 lname, MAX_PATH, NULL, NULL);
4324 if (!lname_len)
4325 {
4326 /* WideCharToMultiByte failed. */
4327 DWORD w32err1 = GetLastError ();
4328
4329 switch (w32err1)
4330 {
4331 case ERROR_INSUFFICIENT_BUFFER:
4332 errno = ENAMETOOLONG;
4333 break;
4334 case ERROR_INVALID_PARAMETER:
4335 errno = EFAULT;
4336 break;
4337 case ERROR_NO_UNICODE_TRANSLATION:
4338 errno = ENOENT;
4339 break;
4340 default:
4341 errno = EINVAL;
4342 break;
4343 }
4344 }
4345 else
4346 {
4347 size_t size_to_copy = buf_size;
4348 BYTE *p = lname;
4349 BYTE *pend = p + lname_len;
4350
4351 /* Normalize like dostounix_filename does, but we don't
4352 want to assume that lname is null-terminated. */
4353 if (*p && p[1] == ':' && *p >= 'A' && *p <= 'Z')
4354 *p += 'a' - 'A';
4355 while (p <= pend)
4356 {
4357 if (*p == '\\')
4358 *p = '/';
4359 ++p;
4360 }
4361 /* Testing for null-terminated LNAME is paranoia:
4362 WideCharToMultiByte should always return a
4363 null-terminated string when its 4th argument is -1
4364 and its 3rd argument is null-terminated (which they
4365 are, see above). */
4366 if (lname[lname_len - 1] == '\0')
4367 lname_len--;
4368 if (lname_len <= buf_size)
4369 size_to_copy = lname_len;
4370 strncpy (buf, lname, size_to_copy);
4371 /* Success! */
4372 retval = size_to_copy;
4373 }
4374 }
4375 CloseHandle (sh);
4376 }
4377 else
4378 {
4379 /* CreateFile failed. */
4380 DWORD w32err2 = GetLastError ();
4381
4382 switch (w32err2)
4383 {
4384 case ERROR_FILE_NOT_FOUND:
4385 case ERROR_PATH_NOT_FOUND:
4386 errno = ENOENT;
4387 break;
4388 case ERROR_ACCESS_DENIED:
4389 case ERROR_TOO_MANY_OPEN_FILES:
4390 errno = EACCES;
4391 break;
4392 default:
4393 errno = EPERM;
4394 break;
4395 }
4396 }
4397 if (restore_privs)
4398 {
4399 restore_privilege (&privs);
4400 revert_to_self ();
4401 }
4402
4403 return retval;
3732} 4404}
3733 4405
4406/* If FILE is a symlink, return its target (stored in a static
4407 buffer); otherwise return FILE.
4408
4409 This function repeatedly resolves symlinks in the last component of
4410 a chain of symlink file names, as in foo -> bar -> baz -> ...,
4411 until it arrives at a file whose last component is not a symlink,
4412 or some error occurs. It returns the target of the last
4413 successfully resolved symlink in the chain. If it succeeds to
4414 resolve even a single symlink, the value returned is an absolute
4415 file name with backslashes (result of GetFullPathName). By
4416 contrast, if the original FILE is returned, it is unaltered.
4417
4418 Note: This function can set errno even if it succeeds.
4419
4420 Implementation note: we only resolve the last portion ("basename")
4421 of the argument FILE and of each following file in the chain,
4422 disregarding any possible symlinks in its leading directories.
4423 This is because Windows system calls and library functions
4424 transparently resolve symlinks in leading directories and return
4425 correct information, as long as the basename is not a symlink. */
4426static char *
4427chase_symlinks (const char *file)
4428{
4429 static char target[MAX_PATH];
4430 char link[MAX_PATH];
4431 ssize_t res, link_len;
4432 int loop_count = 0;
4433
4434 if (is_windows_9x () == TRUE || !is_symlink (file))
4435 return (char *)file;
4436
4437 if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0)
4438 return (char *)file;
4439
4440 target[0] = '\0';
4441 do {
4442
4443 /* Remove trailing slashes, as we want to resolve the last
4444 non-trivial part of the link name. */
4445 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
4446 link[link_len--] = '\0';
4447
4448 res = readlink (link, target, MAX_PATH);
4449 if (res > 0)
4450 {
4451 target[res] = '\0';
4452 if (!(IS_DEVICE_SEP (target[1])
4453 || IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1])))
4454 {
4455 /* Target is relative. Append it to the directory part of
4456 the symlink, then copy the result back to target. */
4457 char *p = link + link_len;
4458
4459 while (p > link && !IS_ANY_SEP (p[-1]))
4460 p--;
4461 strcpy (p, target);
4462 strcpy (target, link);
4463 }
4464 /* Resolve any "." and ".." to get a fully-qualified file name
4465 in link[] again. */
4466 link_len = GetFullPathName (target, MAX_PATH, link, NULL);
4467 }
4468 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
4469
4470 if (loop_count > 100)
4471 errno = ELOOP;
4472
4473 if (target[0] == '\0') /* not a single call to readlink succeeded */
4474 return (char *)file;
4475 return target;
4476}
4477
4478/* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
4479 have a fixed max size for file names, so we don't need the kind of
4480 alloc/malloc/realloc dance the gnulib version does. We also don't
4481 support FD-relative symlinks. */
3734char * 4482char *
3735careadlinkat (int fd, char const *filename, 4483careadlinkat (int fd, char const *filename,
3736 char *buffer, size_t buffer_size, 4484 char *buffer, size_t buffer_size,
3737 struct allocator const *alloc, 4485 struct allocator const *alloc,
3738 ssize_t (*preadlinkat) (int, char const *, char *, size_t)) 4486 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
3739{ 4487{
3740 errno = ENOSYS; 4488 char linkname[MAX_PATH];
4489 ssize_t link_size;
4490
4491 if (fd != AT_FDCWD)
4492 {
4493 errno = EINVAL;
4494 return NULL;
4495 }
4496
4497 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
4498
4499 if (link_size > 0)
4500 {
4501 char *retval = buffer;
4502
4503 linkname[link_size++] = '\0';
4504 if (link_size > buffer_size)
4505 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
4506 if (retval)
4507 memcpy (retval, linkname, link_size);
4508
4509 return retval;
4510 }
3741 return NULL; 4511 return NULL;
3742} 4512}
3743 4513
@@ -6060,6 +6830,7 @@ globals_of_w32 (void)
6060 g_b_init_lookup_account_sid = 0; 6830 g_b_init_lookup_account_sid = 0;
6061 g_b_init_get_sid_sub_authority = 0; 6831 g_b_init_get_sid_sub_authority = 0;
6062 g_b_init_get_sid_sub_authority_count = 0; 6832 g_b_init_get_sid_sub_authority_count = 0;
6833 g_b_init_get_security_info = 0;
6063 g_b_init_get_file_security = 0; 6834 g_b_init_get_file_security = 0;
6064 g_b_init_get_security_descriptor_owner = 0; 6835 g_b_init_get_security_descriptor_owner = 0;
6065 g_b_init_get_security_descriptor_group = 0; 6836 g_b_init_get_security_descriptor_group = 0;
@@ -6079,6 +6850,7 @@ globals_of_w32 (void)
6079 g_b_init_get_length_sid = 0; 6850 g_b_init_get_length_sid = 0;
6080 g_b_init_get_native_system_info = 0; 6851 g_b_init_get_native_system_info = 0;
6081 g_b_init_get_system_times = 0; 6852 g_b_init_get_system_times = 0;
6853 g_b_init_create_symbolic_link = 0;
6082 num_of_processors = 0; 6854 num_of_processors = 0;
6083 /* The following sets a handler for shutdown notifications for 6855 /* The following sets a handler for shutdown notifications for
6084 console apps. This actually applies to Emacs in both console and 6856 console apps. This actually applies to Emacs in both console and