aboutsummaryrefslogtreecommitdiffstats
path: root/src/w32.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/w32.c')
-rw-r--r--src/w32.c1152
1 files changed, 948 insertions, 204 deletions
diff --git a/src/w32.c b/src/w32.c
index e8c48a50a97..61de234cf70 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -1,4 +1,4 @@
1/* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API. 1/* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
2 Copyright (C) 1994-1995, 2000-2012 Free Software Foundation, Inc. 2 Copyright (C) 1994-1995, 2000-2012 Free Software Foundation, Inc.
3 3
4This file is part of GNU Emacs. 4This file is part of GNU Emacs.
@@ -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);
@@ -1567,17 +1709,19 @@ init_environment (char ** argv)
1567 char * def_value; 1709 char * def_value;
1568 } dflt_envvars[] = 1710 } dflt_envvars[] =
1569 { 1711 {
1712 /* If the default value is NULL, we will use the value from the
1713 outside environment or the Registry, but will not push the
1714 variable into the Emacs environment if it is defined neither
1715 in the Registry nor in the outside environment. */
1570 {"HOME", "C:/"}, 1716 {"HOME", "C:/"},
1571 {"PRELOAD_WINSOCK", NULL}, 1717 {"PRELOAD_WINSOCK", NULL},
1572 {"emacs_dir", "C:/emacs"}, 1718 {"emacs_dir", "C:/emacs"},
1573 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"}, 1719 {"EMACSLOADPATH", NULL},
1574 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"}, 1720 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1575 {"EMACSDATA", "%emacs_dir%/etc"}, 1721 {"EMACSDATA", NULL},
1576 {"EMACSPATH", "%emacs_dir%/bin"}, 1722 {"EMACSPATH", NULL},
1577 /* We no longer set INFOPATH because Info-default-directory-list 1723 {"INFOPATH", NULL},
1578 is then ignored. */ 1724 {"EMACSDOC", NULL},
1579 /* {"INFOPATH", "%emacs_dir%/info"}, */
1580 {"EMACSDOC", "%emacs_dir%/etc"},
1581 {"TERM", "cmd"}, 1725 {"TERM", "cmd"},
1582 {"LANG", NULL}, 1726 {"LANG", NULL},
1583 }; 1727 };
@@ -1635,29 +1779,10 @@ init_environment (char ** argv)
1635 } 1779 }
1636 } 1780 }
1637 1781
1638 /* When Emacs is invoked with --no-site-lisp, we must remove the
1639 site-lisp directories from the default value of EMACSLOADPATH.
1640 This assumes that the site-lisp entries are at the front, and
1641 that additional entries do exist. */
1642 if (no_site_lisp)
1643 {
1644 for (i = 0; i < N_ENV_VARS; i++)
1645 {
1646 if (strcmp (env_vars[i].name, "EMACSLOADPATH") == 0)
1647 {
1648 char *site;
1649 while ((site = strstr (env_vars[i].def_value, "site-lisp")))
1650 env_vars[i].def_value = strchr (site, ';') + 1;
1651 break;
1652 }
1653 }
1654 }
1655
1656#define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */ 1782#define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1657 1783
1658 /* Treat emacs_dir specially: set it unconditionally based on our 1784 /* Treat emacs_dir specially: set it unconditionally based on our
1659 location, if it appears that we are running from the bin subdir 1785 location. */
1660 of a standard installation. */
1661 { 1786 {
1662 char *p; 1787 char *p;
1663 char modname[MAX_PATH]; 1788 char modname[MAX_PATH];
@@ -1722,13 +1847,11 @@ init_environment (char ** argv)
1722 dwType = REG_EXPAND_SZ; 1847 dwType = REG_EXPAND_SZ;
1723 dont_free = 1; 1848 dont_free = 1;
1724 if (!strcmp (env_vars[i].name, "HOME") && !appdata) 1849 if (!strcmp (env_vars[i].name, "HOME") && !appdata)
1725 { 1850 Vdelayed_warnings_list
1726 Lisp_Object warning[2]; 1851 = Fcons (listn (CONSTYPE_HEAP, 2,
1727 warning[0] = intern ("initialization"); 1852 intern ("initialization"),
1728 warning[1] = build_string ("Setting HOME to C:\\ by default is deprecated"); 1853 build_string ("Setting HOME to C:\\ by default is deprecated")),
1729 Vdelayed_warnings_list = Fcons (Flist (2, warning), 1854 Vdelayed_warnings_list);
1730 Vdelayed_warnings_list);
1731 }
1732 } 1855 }
1733 1856
1734 if (lpval) 1857 if (lpval)
@@ -1776,6 +1899,8 @@ init_environment (char ** argv)
1776 } 1899 }
1777 1900
1778 /* Remember the initial working directory for getwd. */ 1901 /* Remember the initial working directory for getwd. */
1902 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
1903 Does it matter anywhere in Emacs? */
1779 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir)) 1904 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1780 abort (); 1905 abort ();
1781 1906
@@ -1795,6 +1920,8 @@ init_environment (char ** argv)
1795 init_user_info (); 1920 init_user_info ();
1796} 1921}
1797 1922
1923/* Called from expand-file-name when default-directory is not a string. */
1924
1798char * 1925char *
1799emacs_root_dir (void) 1926emacs_root_dir (void)
1800{ 1927{
@@ -2013,7 +2140,7 @@ fdutimens (int fd, char const *file, struct timespec const timespec[2])
2013 2140
2014 2141
2015/* ------------------------------------------------------------------------- */ 2142/* ------------------------------------------------------------------------- */
2016/* IO support and wrapper functions for W32 API. */ 2143/* IO support and wrapper functions for the Windows API. */
2017/* ------------------------------------------------------------------------- */ 2144/* ------------------------------------------------------------------------- */
2018 2145
2019/* Place a wrapper around the MSVC version of ctime. It returns NULL 2146/* Place a wrapper around the MSVC version of ctime. It returns NULL
@@ -2189,8 +2316,15 @@ GetCachedVolumeInformation (char * root_dir)
2189 return info; 2316 return info;
2190} 2317}
2191 2318
2192/* Get information on the volume where name is held; set path pointer to 2319/* Get information on the volume where NAME is held; set path pointer to
2193 start of pathname in name (past UNC header\volume header if present). */ 2320 start of pathname in NAME (past UNC header\volume header if present),
2321 if pPath is non-NULL.
2322
2323 Note: if NAME includes symlinks, the information is for the volume
2324 of the symlink, not of its target. That's because, even though
2325 GetVolumeInformation returns information about the symlink target
2326 of its argument, we only pass the root directory to
2327 GetVolumeInformation, not the full NAME. */
2194static int 2328static int
2195get_volume_info (const char * name, const char ** pPath) 2329get_volume_info (const char * name, const char ** pPath)
2196{ 2330{
@@ -2201,7 +2335,7 @@ get_volume_info (const char * name, const char ** pPath)
2201 if (name == NULL) 2335 if (name == NULL)
2202 return FALSE; 2336 return FALSE;
2203 2337
2204 /* find the root name of the volume if given */ 2338 /* Find the root name of the volume if given. */
2205 if (isalpha (name[0]) && name[1] == ':') 2339 if (isalpha (name[0]) && name[1] == ':')
2206 { 2340 {
2207 rootname = temp; 2341 rootname = temp;
@@ -2241,7 +2375,8 @@ get_volume_info (const char * name, const char ** pPath)
2241} 2375}
2242 2376
2243/* Determine if volume is FAT format (ie. only supports short 8.3 2377/* Determine if volume is FAT format (ie. only supports short 8.3
2244 names); also set path pointer to start of pathname in name. */ 2378 names); also set path pointer to start of pathname in name, if
2379 pPath is non-NULL. */
2245static int 2380static int
2246is_fat_volume (const char * name, const char ** pPath) 2381is_fat_volume (const char * name, const char ** pPath)
2247{ 2382{
@@ -2250,7 +2385,8 @@ is_fat_volume (const char * name, const char ** pPath)
2250 return FALSE; 2385 return FALSE;
2251} 2386}
2252 2387
2253/* Map filename to a valid 8.3 name if necessary. */ 2388/* Map filename to a valid 8.3 name if necessary.
2389 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
2254const char * 2390const char *
2255map_w32_filename (const char * name, const char ** pPath) 2391map_w32_filename (const char * name, const char ** pPath)
2256{ 2392{
@@ -2280,15 +2416,10 @@ map_w32_filename (const char * name, const char ** pPath)
2280 { 2416 {
2281 switch ( c ) 2417 switch ( c )
2282 { 2418 {
2419 case ':':
2283 case '\\': 2420 case '\\':
2284 case '/': 2421 case '/':
2285 *str++ = '\\'; 2422 *str++ = (c == ':' ? ':' : '\\');
2286 extn = 0; /* reset extension flags */
2287 dots = 2; /* max 2 dots */
2288 left = 8; /* max length 8 for main part */
2289 break;
2290 case ':':
2291 *str++ = ':';
2292 extn = 0; /* reset extension flags */ 2423 extn = 0; /* reset extension flags */
2293 dots = 2; /* max 2 dots */ 2424 dots = 2; /* max 2 dots */
2294 left = 8; /* max length 8 for main part */ 2425 left = 8; /* max length 8 for main part */
@@ -2397,6 +2528,9 @@ opendir (char *filename)
2397 if (wnet_enum_handle != INVALID_HANDLE_VALUE) 2528 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2398 return NULL; 2529 return NULL;
2399 2530
2531 /* Note: We don't support traversal of UNC volumes via symlinks.
2532 Doing so would mean punishing 99.99% of use cases by resolving
2533 all the possible symlinks in FILENAME, recursively. */
2400 if (is_unc_volume (filename)) 2534 if (is_unc_volume (filename))
2401 { 2535 {
2402 wnet_enum_handle = open_unc_volume (filename); 2536 wnet_enum_handle = open_unc_volume (filename);
@@ -2413,6 +2547,9 @@ opendir (char *filename)
2413 2547
2414 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN); 2548 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
2415 dir_pathname[MAXPATHLEN] = '\0'; 2549 dir_pathname[MAXPATHLEN] = '\0';
2550 /* Note: We don't support symlinks to file names on FAT volumes.
2551 Doing so would mean punishing 99.99% of use cases by resolving
2552 all the possible symlinks in FILENAME, recursively. */
2416 dir_is_fat = is_fat_volume (filename, NULL); 2553 dir_is_fat = is_fat_volume (filename, NULL);
2417 2554
2418 return dirp; 2555 return dirp;
@@ -2459,6 +2596,9 @@ readdir (DIR *dirp)
2459 strcat (filename, "\\"); 2596 strcat (filename, "\\");
2460 strcat (filename, "*"); 2597 strcat (filename, "*");
2461 2598
2599 /* Note: No need to resolve symlinks in FILENAME, because
2600 FindFirst opens the directory that is the target of a
2601 symlink. */
2462 dir_find_handle = FindFirstFile (filename, &dir_find_data); 2602 dir_find_handle = FindFirstFile (filename, &dir_find_data);
2463 2603
2464 if (dir_find_handle == INVALID_HANDLE_VALUE) 2604 if (dir_find_handle == INVALID_HANDLE_VALUE)
@@ -2652,21 +2792,34 @@ sys_access (const char * path, int mode)
2652 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its 2792 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
2653 newer versions blow up when passed D_OK. */ 2793 newer versions blow up when passed D_OK. */
2654 path = map_w32_filename (path, NULL); 2794 path = map_w32_filename (path, NULL);
2655 if (is_unc_volume (path)) 2795 /* If the last element of PATH is a symlink, we need to resolve it
2656 { 2796 to get the attributes of its target file. Note: any symlinks in
2657 attributes = unc_volume_file_attributes (path); 2797 PATH elements other than the last one are transparently resolved
2658 if (attributes == -1) { 2798 by GetFileAttributes below. */
2659 errno = EACCES; 2799 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
2660 return -1; 2800 path = chase_symlinks (path);
2661 } 2801
2662 } 2802 if ((attributes = GetFileAttributes (path)) == -1)
2663 else if ((attributes = GetFileAttributes (path)) == -1)
2664 { 2803 {
2665 DWORD w32err = GetLastError (); 2804 DWORD w32err = GetLastError ();
2666 2805
2667 switch (w32err) 2806 switch (w32err)
2668 { 2807 {
2808 case ERROR_INVALID_NAME:
2809 case ERROR_BAD_PATHNAME:
2810 if (is_unc_volume (path))
2811 {
2812 attributes = unc_volume_file_attributes (path);
2813 if (attributes == -1)
2814 {
2815 errno = EACCES;
2816 return -1;
2817 }
2818 break;
2819 }
2820 /* FALLTHROUGH */
2669 case ERROR_FILE_NOT_FOUND: 2821 case ERROR_FILE_NOT_FOUND:
2822 case ERROR_BAD_NETPATH:
2670 errno = ENOENT; 2823 errno = ENOENT;
2671 break; 2824 break;
2672 default: 2825 default:
@@ -2702,7 +2855,8 @@ sys_chdir (const char * path)
2702int 2855int
2703sys_chmod (const char * path, int mode) 2856sys_chmod (const char * path, int mode)
2704{ 2857{
2705 return _chmod (map_w32_filename (path, NULL), mode); 2858 path = chase_symlinks (map_w32_filename (path, NULL));
2859 return _chmod (path, mode);
2706} 2860}
2707 2861
2708int 2862int
@@ -2931,7 +3085,7 @@ sys_rename (const char * oldname, const char * newname)
2931 /* volume_info is set indirectly by map_w32_filename. */ 3085 /* volume_info is set indirectly by map_w32_filename. */
2932 oldname_dev = volume_info.serialnum; 3086 oldname_dev = volume_info.serialnum;
2933 3087
2934 if (os_subtype == OS_WIN95) 3088 if (os_subtype == OS_9X)
2935 { 3089 {
2936 char * o; 3090 char * o;
2937 char * p; 3091 char * p;
@@ -2982,6 +3136,7 @@ sys_rename (const char * oldname, const char * newname)
2982 3136
2983 if (result < 0) 3137 if (result < 0)
2984 { 3138 {
3139 DWORD w32err = GetLastError ();
2985 3140
2986 if (errno == EACCES 3141 if (errno == EACCES
2987 && newname_dev != oldname_dev) 3142 && newname_dev != oldname_dev)
@@ -2994,7 +3149,7 @@ sys_rename (const char * oldname, const char * newname)
2994 DWORD attributes; 3149 DWORD attributes;
2995 3150
2996 if ((attributes = GetFileAttributes (temp)) != -1 3151 if ((attributes = GetFileAttributes (temp)) != -1
2997 && attributes & FILE_ATTRIBUTE_DIRECTORY) 3152 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
2998 errno = EXDEV; 3153 errno = EXDEV;
2999 } 3154 }
3000 else if (errno == EEXIST) 3155 else if (errno == EEXIST)
@@ -3005,6 +3160,14 @@ sys_rename (const char * oldname, const char * newname)
3005 return result; 3160 return result;
3006 result = rename (temp, newname); 3161 result = rename (temp, newname);
3007 } 3162 }
3163 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
3164 && is_symlink (temp))
3165 {
3166 /* This is Windows prohibiting the user from creating a
3167 symlink in another place, since that requires
3168 privileges. */
3169 errno = EPERM;
3170 }
3008 } 3171 }
3009 3172
3010 return result; 3173 return result;
@@ -3135,7 +3298,23 @@ generate_inode_val (const char * name)
3135#endif 3298#endif
3136 3299
3137static PSECURITY_DESCRIPTOR 3300static PSECURITY_DESCRIPTOR
3138get_file_security_desc (const char *fname) 3301get_file_security_desc_by_handle (HANDLE h)
3302{
3303 PSECURITY_DESCRIPTOR psd = NULL;
3304 DWORD err;
3305 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3306 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3307
3308 err = get_security_info (h, SE_FILE_OBJECT, si,
3309 NULL, NULL, NULL, NULL, &psd);
3310 if (err != ERROR_SUCCESS)
3311 return NULL;
3312
3313 return psd;
3314}
3315
3316static PSECURITY_DESCRIPTOR
3317get_file_security_desc_by_name (const char *fname)
3139{ 3318{
3140 PSECURITY_DESCRIPTOR psd = NULL; 3319 PSECURITY_DESCRIPTOR psd = NULL;
3141 DWORD sd_len, err; 3320 DWORD sd_len, err;
@@ -3351,18 +3530,24 @@ is_slow_fs (const char *name)
3351 3530
3352/* MSVC stat function can't cope with UNC names and has other bugs, so 3531/* MSVC stat function can't cope with UNC names and has other bugs, so
3353 replace it with our own. This also allows us to calculate consistent 3532 replace it with our own. This also allows us to calculate consistent
3354 inode values without hacks in the main Emacs code. */ 3533 inode values and owner/group without hacks in the main Emacs code. */
3355int 3534
3356stat (const char * path, struct stat * buf) 3535static int
3536stat_worker (const char * path, struct stat * buf, int follow_symlinks)
3357{ 3537{
3358 char *name, *r; 3538 char *name, *save_name, *r;
3359 WIN32_FIND_DATA wfd; 3539 WIN32_FIND_DATA wfd;
3360 HANDLE fh; 3540 HANDLE fh;
3361 unsigned __int64 fake_inode; 3541 unsigned __int64 fake_inode = 0;
3362 int permission; 3542 int permission;
3363 int len; 3543 int len;
3364 int rootdir = FALSE; 3544 int rootdir = FALSE;
3365 PSECURITY_DESCRIPTOR psd = NULL; 3545 PSECURITY_DESCRIPTOR psd = NULL;
3546 int is_a_symlink = 0;
3547 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
3548 DWORD access_rights = 0;
3549 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
3550 FILETIME ctime, atime, wtime;
3366 3551
3367 if (path == NULL || buf == NULL) 3552 if (path == NULL || buf == NULL)
3368 { 3553 {
@@ -3370,7 +3555,7 @@ stat (const char * path, struct stat * buf)
3370 return -1; 3555 return -1;
3371 } 3556 }
3372 3557
3373 name = (char *) map_w32_filename (path, &path); 3558 save_name = name = (char *) map_w32_filename (path, &path);
3374 /* Must be valid filename, no wild cards or other invalid 3559 /* Must be valid filename, no wild cards or other invalid
3375 characters. We use _mbspbrk to support multibyte strings that 3560 characters. We use _mbspbrk to support multibyte strings that
3376 might look to strpbrk as if they included literal *, ?, and other 3561 might look to strpbrk as if they included literal *, ?, and other
@@ -3382,99 +3567,67 @@ stat (const char * path, struct stat * buf)
3382 return -1; 3567 return -1;
3383 } 3568 }
3384 3569
3385 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3386 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
3387 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
3388 {
3389 r[1] = r[2] = '\0';
3390 }
3391
3392 /* Remove trailing directory separator, unless name is the root 3570 /* Remove trailing directory separator, unless name is the root
3393 directory of a drive or UNC volume in which case ensure there 3571 directory of a drive or UNC volume in which case ensure there
3394 is a trailing separator. */ 3572 is a trailing separator. */
3395 len = strlen (name); 3573 len = strlen (name);
3396 rootdir = (path >= name + len - 1
3397 && (IS_DIRECTORY_SEP (*path) || *path == 0));
3398 name = strcpy (alloca (len + 2), name); 3574 name = strcpy (alloca (len + 2), name);
3399 3575
3400 if (is_unc_volume (name)) 3576 /* Avoid a somewhat costly call to is_symlink if the filesystem
3401 { 3577 doesn't support symlinks. */
3402 DWORD attrs = unc_volume_file_attributes (name); 3578 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
3403 3579 is_a_symlink = is_symlink (name);
3404 if (attrs == -1) 3580
3405 return -1; 3581 /* Plan A: Open the file and get all the necessary information via
3406 3582 the resulting handle. This solves several issues in one blow:
3407 memset (&wfd, 0, sizeof (wfd)); 3583
3408 wfd.dwFileAttributes = attrs; 3584 . retrieves attributes for the target of a symlink, if needed
3409 wfd.ftCreationTime = utc_base_ft; 3585 . gets attributes of root directories and symlinks pointing to
3410 wfd.ftLastAccessTime = utc_base_ft; 3586 root directories, thus avoiding the need for special-casing
3411 wfd.ftLastWriteTime = utc_base_ft; 3587 these and detecting them by examining the file-name format
3412 strcpy (wfd.cFileName, name); 3588 . retrieves more accurate attributes (e.g., non-zero size for
3413 } 3589 some directories, esp. directories that are junction points)
3414 else if (rootdir) 3590 . correctly resolves "c:/..", "/.." and similar file names
3415 { 3591 . avoids run-time penalties for 99% of use cases
3416 if (!IS_DIRECTORY_SEP (name[len-1])) 3592
3417 strcat (name, "\\"); 3593 Plan A is always tried first, unless the user asked not to (but
3418 if (GetDriveType (name) < 2) 3594 if the file is a symlink and we need to follow links, we try Plan
3419 { 3595 A even if the user asked not to).
3420 errno = ENOENT; 3596
3421 return -1; 3597 If Plan A fails, we go to Plan B (below), where various
3422 } 3598 potentially expensive techniques must be used to handle "special"
3423 memset (&wfd, 0, sizeof (wfd)); 3599 files such as UNC volumes etc. */
3424 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
3425 wfd.ftCreationTime = utc_base_ft;
3426 wfd.ftLastAccessTime = utc_base_ft;
3427 wfd.ftLastWriteTime = utc_base_ft;
3428 strcpy (wfd.cFileName, name);
3429 }
3430 else
3431 {
3432 if (IS_DIRECTORY_SEP (name[len-1]))
3433 name[len - 1] = 0;
3434
3435 /* (This is hacky, but helps when doing file completions on
3436 network drives.) Optimize by using information available from
3437 active readdir if possible. */
3438 len = strlen (dir_pathname);
3439 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
3440 len--;
3441 if (dir_find_handle != INVALID_HANDLE_VALUE
3442 && strnicmp (name, dir_pathname, len) == 0
3443 && IS_DIRECTORY_SEP (name[len])
3444 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
3445 {
3446 /* This was the last entry returned by readdir. */
3447 wfd = dir_find_data;
3448 }
3449 else
3450 {
3451 logon_network_drive (name);
3452
3453 fh = FindFirstFile (name, &wfd);
3454 if (fh == INVALID_HANDLE_VALUE)
3455 {
3456 errno = ENOENT;
3457 return -1;
3458 }
3459 FindClose (fh);
3460 }
3461 }
3462
3463 if (!(NILP (Vw32_get_true_file_attributes) 3600 if (!(NILP (Vw32_get_true_file_attributes)
3464 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name))) 3601 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
3465 /* No access rights required to get info. */ 3602 /* Following symlinks requires getting the info by handle. */
3466 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING, 3603 || (is_a_symlink && follow_symlinks))
3467 FILE_FLAG_BACKUP_SEMANTICS, NULL))
3468 != INVALID_HANDLE_VALUE)
3469 { 3604 {
3605 BY_HANDLE_FILE_INFORMATION info;
3606
3607 if (is_a_symlink && !follow_symlinks)
3608 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
3609 /* READ_CONTROL access rights are required to get security info
3610 by handle. But if the OS doesn't support security in the
3611 first place, we don't need to try. */
3612 if (is_windows_9x () != TRUE)
3613 access_rights |= READ_CONTROL;
3614
3615 fh = CreateFile (name, access_rights, 0, NULL, OPEN_EXISTING,
3616 file_flags, NULL);
3617 /* If CreateFile fails with READ_CONTROL, try again with zero as
3618 access rights. */
3619 if (fh == INVALID_HANDLE_VALUE && access_rights)
3620 fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
3621 file_flags, NULL);
3622 if (fh == INVALID_HANDLE_VALUE)
3623 goto no_true_file_attributes;
3624
3470 /* This is more accurate in terms of getting the correct number 3625 /* This is more accurate in terms of getting the correct number
3471 of links, but is quite slow (it is noticeable when Emacs is 3626 of links, but is quite slow (it is noticeable when Emacs is
3472 making a list of file name completions). */ 3627 making a list of file name completions). */
3473 BY_HANDLE_FILE_INFORMATION info;
3474
3475 if (GetFileInformationByHandle (fh, &info)) 3628 if (GetFileInformationByHandle (fh, &info))
3476 { 3629 {
3477 buf->st_nlink = info.nNumberOfLinks; 3630 nlinks = info.nNumberOfLinks;
3478 /* Might as well use file index to fake inode values, but this 3631 /* Might as well use file index to fake inode values, but this
3479 is not guaranteed to be unique unless we keep a handle open 3632 is not guaranteed to be unique unless we keep a handle open
3480 all the time (even then there are situations where it is 3633 all the time (even then there are situations where it is
@@ -3483,20 +3636,53 @@ stat (const char * path, struct stat * buf)
3483 fake_inode = info.nFileIndexHigh; 3636 fake_inode = info.nFileIndexHigh;
3484 fake_inode <<= 32; 3637 fake_inode <<= 32;
3485 fake_inode += info.nFileIndexLow; 3638 fake_inode += info.nFileIndexLow;
3639 serialnum = info.dwVolumeSerialNumber;
3640 fs_high = info.nFileSizeHigh;
3641 fs_low = info.nFileSizeLow;
3642 ctime = info.ftCreationTime;
3643 atime = info.ftLastAccessTime;
3644 wtime = info.ftLastWriteTime;
3645 fattrs = info.dwFileAttributes;
3486 } 3646 }
3487 else 3647 else
3488 { 3648 {
3489 buf->st_nlink = 1; 3649 /* We don't go to Plan B here, because it's not clear that
3490 fake_inode = 0; 3650 it's a good idea. The only known use case where
3651 CreateFile succeeds, but GetFileInformationByHandle fails
3652 (with ERROR_INVALID_FUNCTION) is for character devices
3653 such as NUL, PRN, etc. For these, switching to Plan B is
3654 a net loss, because we lose the character device
3655 attribute returned by GetFileType below (FindFirstFile
3656 doesn't set that bit in the attributes), and the other
3657 fields don't make sense for character devices anyway.
3658 Emacs doesn't really care for non-file entities in the
3659 context of l?stat, so neither do we. */
3660
3661 /* w32err is assigned so one could put a breakpoint here and
3662 examine its value, when GetFileInformationByHandle
3663 fails. */
3664 DWORD w32err = GetLastError ();
3665
3666 switch (w32err)
3667 {
3668 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
3669 errno = ENOENT;
3670 return -1;
3671 }
3491 } 3672 }
3492 3673
3493 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 3674 /* Test for a symlink before testing for a directory, since
3494 { 3675 symlinks to directories have the directory bit set, but we
3495 buf->st_mode = S_IFDIR; 3676 don't want them to appear as directories. */
3496 } 3677 if (is_a_symlink && !follow_symlinks)
3678 buf->st_mode = S_IFLNK;
3679 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
3680 buf->st_mode = S_IFDIR;
3497 else 3681 else
3498 { 3682 {
3499 switch (GetFileType (fh)) 3683 DWORD ftype = GetFileType (fh);
3684
3685 switch (ftype)
3500 { 3686 {
3501 case FILE_TYPE_DISK: 3687 case FILE_TYPE_DISK:
3502 buf->st_mode = S_IFREG; 3688 buf->st_mode = S_IFREG;
@@ -3510,21 +3696,143 @@ stat (const char * path, struct stat * buf)
3510 buf->st_mode = S_IFCHR; 3696 buf->st_mode = S_IFCHR;
3511 } 3697 }
3512 } 3698 }
3699 /* We produce the fallback owner and group data, based on the
3700 current user that runs Emacs, in the following cases:
3701
3702 . this is Windows 9X
3703 . getting security by handle failed, and we need to produce
3704 information for the target of a symlink (this is better
3705 than producing a potentially misleading info about the
3706 symlink itself)
3707
3708 If getting security by handle fails, and we don't need to
3709 resolve symlinks, we try getting security by name. */
3710 if (is_windows_9x () != TRUE)
3711 psd = get_file_security_desc_by_handle (fh);
3712 if (psd)
3713 {
3714 get_file_owner_and_group (psd, name, buf);
3715 LocalFree (psd);
3716 }
3717 else if (is_windows_9x () == TRUE)
3718 get_file_owner_and_group (NULL, name, buf);
3719 else if (!(is_a_symlink && follow_symlinks))
3720 {
3721 psd = get_file_security_desc_by_name (name);
3722 get_file_owner_and_group (psd, name, buf);
3723 xfree (psd);
3724 }
3725 else
3726 get_file_owner_and_group (NULL, name, buf);
3513 CloseHandle (fh); 3727 CloseHandle (fh);
3514 psd = get_file_security_desc (name);
3515 get_file_owner_and_group (psd, name, buf);
3516 } 3728 }
3517 else 3729 else
3518 { 3730 {
3519 /* Don't bother to make this information more accurate. */ 3731 no_true_file_attributes:
3520 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 3732 /* Plan B: Either getting a handle on the file failed, or the
3521 S_IFDIR : S_IFREG; 3733 caller explicitly asked us to not bother making this
3522 buf->st_nlink = 1; 3734 information more accurate.
3523 fake_inode = 0; 3735
3736 Implementation note: In Plan B, we never bother to resolve
3737 symlinks, even if we got here because we tried Plan A and
3738 failed. That's because, even if the caller asked for extra
3739 precision by setting Vw32_get_true_file_attributes to t,
3740 resolving symlinks requires acquiring a file handle to the
3741 symlink, which we already know will fail. And if the user
3742 did not ask for extra precision, resolving symlinks will fly
3743 in the face of that request, since the user then wants the
3744 lightweight version of the code. */
3745 rootdir = (path >= save_name + len - 1
3746 && (IS_DIRECTORY_SEP (*path) || *path == 0));
3747
3748 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3749 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
3750 if (IS_DIRECTORY_SEP (r[0])
3751 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
3752 r[1] = r[2] = '\0';
3753
3754 /* Note: If NAME is a symlink to the root of a UNC volume
3755 (i.e. "\\SERVER"), we will not detect that here, and we will
3756 return data about the symlink as result of FindFirst below.
3757 This is unfortunate, but that marginal use case does not
3758 justify a call to chase_symlinks which would impose a penalty
3759 on all the other use cases. (We get here for symlinks to
3760 roots of UNC volumes because CreateFile above fails for them,
3761 unlike with symlinks to root directories X:\ of drives.) */
3762 if (is_unc_volume (name))
3763 {
3764 fattrs = unc_volume_file_attributes (name);
3765 if (fattrs == -1)
3766 return -1;
3767
3768 ctime = atime = wtime = utc_base_ft;
3769 }
3770 else if (rootdir)
3771 {
3772 if (!IS_DIRECTORY_SEP (name[len-1]))
3773 strcat (name, "\\");
3774 if (GetDriveType (name) < 2)
3775 {
3776 errno = ENOENT;
3777 return -1;
3778 }
3779
3780 fattrs = FILE_ATTRIBUTE_DIRECTORY;
3781 ctime = atime = wtime = utc_base_ft;
3782 }
3783 else
3784 {
3785 if (IS_DIRECTORY_SEP (name[len-1]))
3786 name[len - 1] = 0;
3787
3788 /* (This is hacky, but helps when doing file completions on
3789 network drives.) Optimize by using information available from
3790 active readdir if possible. */
3791 len = strlen (dir_pathname);
3792 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
3793 len--;
3794 if (dir_find_handle != INVALID_HANDLE_VALUE
3795 && !(is_a_symlink && follow_symlinks)
3796 && strnicmp (save_name, dir_pathname, len) == 0
3797 && IS_DIRECTORY_SEP (name[len])
3798 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
3799 {
3800 /* This was the last entry returned by readdir. */
3801 wfd = dir_find_data;
3802 }
3803 else
3804 {
3805 logon_network_drive (name);
3806
3807 fh = FindFirstFile (name, &wfd);
3808 if (fh == INVALID_HANDLE_VALUE)
3809 {
3810 errno = ENOENT;
3811 return -1;
3812 }
3813 FindClose (fh);
3814 }
3815 /* Note: if NAME is a symlink, the information we get from
3816 FindFirstFile is for the symlink, not its target. */
3817 fattrs = wfd.dwFileAttributes;
3818 ctime = wfd.ftCreationTime;
3819 atime = wfd.ftLastAccessTime;
3820 wtime = wfd.ftLastWriteTime;
3821 fs_high = wfd.nFileSizeHigh;
3822 fs_low = wfd.nFileSizeLow;
3823 fake_inode = 0;
3824 nlinks = 1;
3825 serialnum = volume_info.serialnum;
3826 }
3827 if (is_a_symlink && !follow_symlinks)
3828 buf->st_mode = S_IFLNK;
3829 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
3830 buf->st_mode = S_IFDIR;
3831 else
3832 buf->st_mode = S_IFREG;
3524 3833
3525 get_file_owner_and_group (NULL, name, buf); 3834 get_file_owner_and_group (NULL, name, buf);
3526 } 3835 }
3527 xfree (psd);
3528 3836
3529#if 0 3837#if 0
3530 /* Not sure if there is any point in this. */ 3838 /* Not sure if there is any point in this. */
@@ -3538,43 +3846,56 @@ stat (const char * path, struct stat * buf)
3538 } 3846 }
3539#endif 3847#endif
3540 3848
3541 /* MSVC defines _ino_t to be short; other libc's might not. */ 3849 buf->st_ino = fake_inode;
3542 if (sizeof (buf->st_ino) == 2)
3543 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3544 else
3545 buf->st_ino = fake_inode;
3546 3850
3547 /* volume_info is set indirectly by map_w32_filename */ 3851 buf->st_dev = serialnum;
3548 buf->st_dev = volume_info.serialnum; 3852 buf->st_rdev = serialnum;
3549 buf->st_rdev = volume_info.serialnum;
3550 3853
3551 buf->st_size = wfd.nFileSizeHigh; 3854 buf->st_size = fs_high;
3552 buf->st_size <<= 32; 3855 buf->st_size <<= 32;
3553 buf->st_size += wfd.nFileSizeLow; 3856 buf->st_size += fs_low;
3857 buf->st_nlink = nlinks;
3554 3858
3555 /* Convert timestamps to Unix format. */ 3859 /* Convert timestamps to Unix format. */
3556 buf->st_mtime = convert_time (wfd.ftLastWriteTime); 3860 buf->st_mtime = convert_time (wtime);
3557 buf->st_atime = convert_time (wfd.ftLastAccessTime); 3861 buf->st_atime = convert_time (atime);
3558 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime; 3862 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3559 buf->st_ctime = convert_time (wfd.ftCreationTime); 3863 buf->st_ctime = convert_time (ctime);
3560 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime; 3864 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3561 3865
3562 /* determine rwx permissions */ 3866 /* determine rwx permissions */
3563 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) 3867 if (is_a_symlink && !follow_symlinks)
3564 permission = S_IREAD; 3868 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
3565 else 3869 else
3566 permission = S_IREAD | S_IWRITE; 3870 {
3871 if (fattrs & FILE_ATTRIBUTE_READONLY)
3872 permission = S_IREAD;
3873 else
3874 permission = S_IREAD | S_IWRITE;
3567 3875
3568 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 3876 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
3569 permission |= S_IEXEC; 3877 permission |= S_IEXEC;
3570 else if (is_exec (name)) 3878 else if (is_exec (name))
3571 permission |= S_IEXEC; 3879 permission |= S_IEXEC;
3880 }
3572 3881
3573 buf->st_mode |= permission | (permission >> 3) | (permission >> 6); 3882 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3574 3883
3575 return 0; 3884 return 0;
3576} 3885}
3577 3886
3887int
3888stat (const char * path, struct stat * buf)
3889{
3890 return stat_worker (path, buf, 1);
3891}
3892
3893int
3894lstat (const char * path, struct stat * buf)
3895{
3896 return stat_worker (path, buf, 0);
3897}
3898
3578/* Provide fstat and utime as well as stat for consistent handling of 3899/* Provide fstat and utime as well as stat for consistent handling of
3579 file timestamps. */ 3900 file timestamps. */
3580int 3901int
@@ -3715,31 +4036,460 @@ utime (const char *name, struct utimbuf *times)
3715} 4036}
3716 4037
3717 4038
3718/* Symlink-related functions that always fail. Used in fileio.c and in 4039/* Symlink-related functions. */
3719 sysdep.c to avoid #ifdef's. */ 4040#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4041#define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4042#endif
4043
3720int 4044int
3721symlink (char const *dummy1, char const *dummy2) 4045symlink (char const *filename, char const *linkname)
3722{ 4046{
3723 errno = ENOSYS; 4047 char linkfn[MAX_PATH], *tgtfn;
3724 return -1; 4048 DWORD flags = 0;
4049 int dir_access, filename_ends_in_slash;
4050
4051 /* Diagnostics follows Posix as much as possible. */
4052 if (filename == NULL || linkname == NULL)
4053 {
4054 errno = EFAULT;
4055 return -1;
4056 }
4057 if (!*filename)
4058 {
4059 errno = ENOENT;
4060 return -1;
4061 }
4062 if (strlen (filename) > MAX_PATH || strlen (linkname) > MAX_PATH)
4063 {
4064 errno = ENAMETOOLONG;
4065 return -1;
4066 }
4067
4068 strcpy (linkfn, map_w32_filename (linkname, NULL));
4069 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
4070 {
4071 errno = EPERM;
4072 return -1;
4073 }
4074
4075 /* Note: since empty FILENAME was already rejected, we can safely
4076 refer to FILENAME[1]. */
4077 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
4078 {
4079 /* Non-absolute FILENAME is understood as being relative to
4080 LINKNAME's directory. We need to prepend that directory to
4081 FILENAME to get correct results from sys_access below, since
4082 otherwise it will interpret FILENAME relative to the
4083 directory where the Emacs process runs. Note that
4084 make-symbolic-link always makes sure LINKNAME is a fully
4085 expanded file name. */
4086 char tem[MAX_PATH];
4087 char *p = linkfn + strlen (linkfn);
4088
4089 while (p > linkfn && !IS_ANY_SEP (p[-1]))
4090 p--;
4091 if (p > linkfn)
4092 strncpy (tem, linkfn, p - linkfn);
4093 tem[p - linkfn] = '\0';
4094 strcat (tem, filename);
4095 dir_access = sys_access (tem, D_OK);
4096 }
4097 else
4098 dir_access = sys_access (filename, D_OK);
4099
4100 /* Since Windows distinguishes between symlinks to directories and
4101 to files, we provide a kludgey feature: if FILENAME doesn't
4102 exist, but ends in a slash, we create a symlink to directory. If
4103 FILENAME exists and is a directory, we always create a symlink to
4104 directory. */
4105 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
4106 if (dir_access == 0 || filename_ends_in_slash)
4107 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
4108
4109 tgtfn = (char *)map_w32_filename (filename, NULL);
4110 if (filename_ends_in_slash)
4111 tgtfn[strlen (tgtfn) - 1] = '\0';
4112
4113 errno = 0;
4114 if (!create_symbolic_link (linkfn, tgtfn, flags))
4115 {
4116 /* ENOSYS is set by create_symbolic_link, when it detects that
4117 the OS doesn't support the CreateSymbolicLink API. */
4118 if (errno != ENOSYS)
4119 {
4120 DWORD w32err = GetLastError ();
4121
4122 switch (w32err)
4123 {
4124 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4125 TGTFN point to the same file name, go figure. */
4126 case ERROR_SUCCESS:
4127 case ERROR_FILE_EXISTS:
4128 errno = EEXIST;
4129 break;
4130 case ERROR_ACCESS_DENIED:
4131 errno = EACCES;
4132 break;
4133 case ERROR_FILE_NOT_FOUND:
4134 case ERROR_PATH_NOT_FOUND:
4135 case ERROR_BAD_NETPATH:
4136 case ERROR_INVALID_REPARSE_DATA:
4137 errno = ENOENT;
4138 break;
4139 case ERROR_DIRECTORY:
4140 errno = EISDIR;
4141 break;
4142 case ERROR_PRIVILEGE_NOT_HELD:
4143 case ERROR_NOT_ALL_ASSIGNED:
4144 errno = EPERM;
4145 break;
4146 case ERROR_DISK_FULL:
4147 errno = ENOSPC;
4148 break;
4149 default:
4150 errno = EINVAL;
4151 break;
4152 }
4153 }
4154 return -1;
4155 }
4156 return 0;
3725} 4157}
3726 4158
4159/* A quick inexpensive test of whether FILENAME identifies a file that
4160 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4161 must already be in the normalized form returned by
4162 map_w32_filename.
4163
4164 Note: for repeated operations on many files, it is best to test
4165 whether the underlying volume actually supports symlinks, by
4166 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4167 avoid the call to this function if it doesn't. That's because the
4168 call to GetFileAttributes takes a non-negligible time, expecially
4169 on non-local or removable filesystems. See stat_worker for an
4170 example of how to do that. */
4171static int
4172is_symlink (const char *filename)
4173{
4174 DWORD attrs;
4175 WIN32_FIND_DATA wfd;
4176 HANDLE fh;
4177
4178 attrs = GetFileAttributes (filename);
4179 if (attrs == -1)
4180 {
4181 DWORD w32err = GetLastError ();
4182
4183 switch (w32err)
4184 {
4185 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
4186 break;
4187 case ERROR_ACCESS_DENIED:
4188 errno = EACCES;
4189 break;
4190 case ERROR_FILE_NOT_FOUND:
4191 case ERROR_PATH_NOT_FOUND:
4192 default:
4193 errno = ENOENT;
4194 break;
4195 }
4196 return 0;
4197 }
4198 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
4199 return 0;
4200 logon_network_drive (filename);
4201 fh = FindFirstFile (filename, &wfd);
4202 if (fh == INVALID_HANDLE_VALUE)
4203 return 0;
4204 FindClose (fh);
4205 return (wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
4206 && (wfd.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
4207}
4208
4209/* If NAME identifies a symbolic link, copy into BUF the file name of
4210 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4211 null-terminate the target name, even if it fits. Return the number
4212 of bytes copied, or -1 if NAME is not a symlink or any error was
4213 encountered while resolving it. The file name copied into BUF is
4214 encoded in the current ANSI codepage. */
3727ssize_t 4215ssize_t
3728readlink (const char *name, char *dummy1, size_t dummy2) 4216readlink (const char *name, char *buf, size_t buf_size)
3729{ 4217{
3730 /* `access' is much faster than `stat' on MS-Windows. */ 4218 const char *path;
3731 if (sys_access (name, 0) == 0) 4219 TOKEN_PRIVILEGES privs;
3732 errno = EINVAL; 4220 int restore_privs = 0;
3733 return -1; 4221 HANDLE sh;
4222 ssize_t retval;
4223
4224 if (name == NULL)
4225 {
4226 errno = EFAULT;
4227 return -1;
4228 }
4229 if (!*name)
4230 {
4231 errno = ENOENT;
4232 return -1;
4233 }
4234
4235 path = map_w32_filename (name, NULL);
4236
4237 if (strlen (path) > MAX_PATH)
4238 {
4239 errno = ENAMETOOLONG;
4240 return -1;
4241 }
4242
4243 errno = 0;
4244 if (is_windows_9x () == TRUE
4245 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
4246 || !is_symlink (path))
4247 {
4248 if (!errno)
4249 errno = EINVAL; /* not a symlink */
4250 return -1;
4251 }
4252
4253 /* Done with simple tests, now we're in for some _real_ work. */
4254 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
4255 restore_privs = 1;
4256 /* Implementation note: From here and onward, don't return early,
4257 since that will fail to restore the original set of privileges of
4258 the calling thread. */
4259
4260 retval = -1; /* not too optimistic, are we? */
4261
4262 /* Note: In the next call to CreateFile, we use zero as the 2nd
4263 argument because, when the symlink is a hidden/system file,
4264 e.g. 'C:\Users\All Users', GENERIC_READ fails with
4265 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
4266 and directory symlinks. */
4267 sh = CreateFile (path, 0, 0, NULL, OPEN_EXISTING,
4268 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
4269 NULL);
4270 if (sh != INVALID_HANDLE_VALUE)
4271 {
4272 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
4273 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
4274 DWORD retbytes;
4275
4276 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
4277 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
4278 &retbytes, NULL))
4279 errno = EIO;
4280 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
4281 errno = EINVAL;
4282 else
4283 {
4284 /* Copy the link target name, in wide characters, fro
4285 reparse_data, then convert it to multibyte encoding in
4286 the current locale's codepage. */
4287 WCHAR *lwname;
4288 BYTE lname[MAX_PATH];
4289 USHORT lname_len;
4290 USHORT lwname_len =
4291 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
4292 WCHAR *lwname_src =
4293 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
4294 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
4295
4296 /* According to MSDN, PrintNameLength does not include the
4297 terminating null character. */
4298 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
4299 memcpy (lwname, lwname_src, lwname_len);
4300 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
4301
4302 /* FIXME: Should we use the current file-name coding system
4303 instead of the fixed value of the ANSI codepage? */
4304 lname_len = WideCharToMultiByte (w32_ansi_code_page, 0, lwname, -1,
4305 lname, MAX_PATH, NULL, NULL);
4306 if (!lname_len)
4307 {
4308 /* WideCharToMultiByte failed. */
4309 DWORD w32err1 = GetLastError ();
4310
4311 switch (w32err1)
4312 {
4313 case ERROR_INSUFFICIENT_BUFFER:
4314 errno = ENAMETOOLONG;
4315 break;
4316 case ERROR_INVALID_PARAMETER:
4317 errno = EFAULT;
4318 break;
4319 case ERROR_NO_UNICODE_TRANSLATION:
4320 errno = ENOENT;
4321 break;
4322 default:
4323 errno = EINVAL;
4324 break;
4325 }
4326 }
4327 else
4328 {
4329 size_t size_to_copy = buf_size;
4330 BYTE *p = lname;
4331 BYTE *pend = p + lname_len;
4332
4333 /* Normalize like dostounix_filename does, but we don't
4334 want to assume that lname is null-terminated. */
4335 if (*p && p[1] == ':' && *p >= 'A' && *p <= 'Z')
4336 *p += 'a' - 'A';
4337 while (p <= pend)
4338 {
4339 if (*p == '\\')
4340 *p = '/';
4341 ++p;
4342 }
4343 /* Testing for null-terminated LNAME is paranoia:
4344 WideCharToMultiByte should always return a
4345 null-terminated string when its 4th argument is -1
4346 and its 3rd argument is null-terminated (which they
4347 are, see above). */
4348 if (lname[lname_len - 1] == '\0')
4349 lname_len--;
4350 if (lname_len <= buf_size)
4351 size_to_copy = lname_len;
4352 strncpy (buf, lname, size_to_copy);
4353 /* Success! */
4354 retval = size_to_copy;
4355 }
4356 }
4357 CloseHandle (sh);
4358 }
4359 else
4360 {
4361 /* CreateFile failed. */
4362 DWORD w32err2 = GetLastError ();
4363
4364 switch (w32err2)
4365 {
4366 case ERROR_FILE_NOT_FOUND:
4367 case ERROR_PATH_NOT_FOUND:
4368 errno = ENOENT;
4369 break;
4370 case ERROR_ACCESS_DENIED:
4371 case ERROR_TOO_MANY_OPEN_FILES:
4372 errno = EACCES;
4373 break;
4374 default:
4375 errno = EPERM;
4376 break;
4377 }
4378 }
4379 if (restore_privs)
4380 {
4381 restore_privilege (&privs);
4382 revert_to_self ();
4383 }
4384
4385 return retval;
4386}
4387
4388/* If FILE is a symlink, return its target (stored in a static
4389 buffer); otherwise return FILE.
4390
4391 This function repeatedly resolves symlinks in the last component of
4392 a chain of symlink file names, as in foo -> bar -> baz -> ...,
4393 until it arrives at a file whose last component is not a symlink,
4394 or some error occurs. It returns the target of the last
4395 successfully resolved symlink in the chain. If it succeeds to
4396 resolve even a single symlink, the value returned is an absolute
4397 file name with backslashes (result of GetFullPathName). By
4398 contrast, if the original FILE is returned, it is unaltered.
4399
4400 Note: This function can set errno even if it succeeds.
4401
4402 Implementation note: we only resolve the last portion ("basename")
4403 of the argument FILE and of each following file in the chain,
4404 disregarding any possible symlinks in its leading directories.
4405 This is because Windows system calls and library functions
4406 transparently resolve symlinks in leading directories and return
4407 correct information, as long as the basename is not a symlink. */
4408static char *
4409chase_symlinks (const char *file)
4410{
4411 static char target[MAX_PATH];
4412 char link[MAX_PATH];
4413 ssize_t res, link_len;
4414 int loop_count = 0;
4415
4416 if (is_windows_9x () == TRUE || !is_symlink (file))
4417 return (char *)file;
4418
4419 if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0)
4420 return (char *)file;
4421
4422 target[0] = '\0';
4423 do {
4424
4425 /* Remove trailing slashes, as we want to resolve the last
4426 non-trivial part of the link name. */
4427 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
4428 link[link_len--] = '\0';
4429
4430 res = readlink (link, target, MAX_PATH);
4431 if (res > 0)
4432 {
4433 target[res] = '\0';
4434 if (!(IS_DEVICE_SEP (target[1])
4435 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
4436 {
4437 /* Target is relative. Append it to the directory part of
4438 the symlink, then copy the result back to target. */
4439 char *p = link + link_len;
4440
4441 while (p > link && !IS_ANY_SEP (p[-1]))
4442 p--;
4443 strcpy (p, target);
4444 strcpy (target, link);
4445 }
4446 /* Resolve any "." and ".." to get a fully-qualified file name
4447 in link[] again. */
4448 link_len = GetFullPathName (target, MAX_PATH, link, NULL);
4449 }
4450 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
4451
4452 if (loop_count > 100)
4453 errno = ELOOP;
4454
4455 if (target[0] == '\0') /* not a single call to readlink succeeded */
4456 return (char *)file;
4457 return target;
3734} 4458}
3735 4459
4460/* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
4461 have a fixed max size for file names, so we don't need the kind of
4462 alloc/malloc/realloc dance the gnulib version does. We also don't
4463 support FD-relative symlinks. */
3736char * 4464char *
3737careadlinkat (int fd, char const *filename, 4465careadlinkat (int fd, char const *filename,
3738 char *buffer, size_t buffer_size, 4466 char *buffer, size_t buffer_size,
3739 struct allocator const *alloc, 4467 struct allocator const *alloc,
3740 ssize_t (*preadlinkat) (int, char const *, char *, size_t)) 4468 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
3741{ 4469{
3742 errno = ENOSYS; 4470 char linkname[MAX_PATH];
4471 ssize_t link_size;
4472
4473 if (fd != AT_FDCWD)
4474 {
4475 errno = EINVAL;
4476 return NULL;
4477 }
4478
4479 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
4480
4481 if (link_size > 0)
4482 {
4483 char *retval = buffer;
4484
4485 linkname[link_size++] = '\0';
4486 if (link_size > buffer_size)
4487 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
4488 if (retval)
4489 memcpy (retval, linkname, link_size);
4490
4491 return retval;
4492 }
3743 return NULL; 4493 return NULL;
3744} 4494}
3745 4495
@@ -5850,7 +6600,7 @@ w32_delayed_load (Lisp_Object libraries, Lisp_Object library_id)
5850} 6600}
5851 6601
5852 6602
5853static void 6603void
5854check_windows_init_file (void) 6604check_windows_init_file (void)
5855{ 6605{
5856 /* A common indication that Emacs is not installed properly is when 6606 /* A common indication that Emacs is not installed properly is when
@@ -5862,19 +6612,14 @@ check_windows_init_file (void)
5862 loadup.el. */ 6612 loadup.el. */
5863 && NILP (Vpurify_flag)) 6613 && NILP (Vpurify_flag))
5864 { 6614 {
5865 Lisp_Object objs[2];
5866 Lisp_Object full_load_path;
5867 Lisp_Object init_file; 6615 Lisp_Object init_file;
5868 int fd; 6616 int fd;
5869 6617
5870 objs[0] = Vload_path;
5871 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5872 full_load_path = Fappend (2, objs);
5873 init_file = build_string ("term/w32-win"); 6618 init_file = build_string ("term/w32-win");
5874 fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil); 6619 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil);
5875 if (fd < 0) 6620 if (fd < 0)
5876 { 6621 {
5877 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil); 6622 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
5878 char *init_file_name = SDATA (init_file); 6623 char *init_file_name = SDATA (init_file);
5879 char *load_path = SDATA (load_path_print); 6624 char *load_path = SDATA (load_path_print);
5880 char *buffer = alloca (1024 6625 char *buffer = alloca (1024
@@ -6013,9 +6758,6 @@ init_ntproc (void)
6013 /* Reset the volume info cache. */ 6758 /* Reset the volume info cache. */
6014 volume_cache = NULL; 6759 volume_cache = NULL;
6015 } 6760 }
6016
6017 /* Check to see if Emacs has been installed correctly. */
6018 check_windows_init_file ();
6019} 6761}
6020 6762
6021/* 6763/*
@@ -6062,6 +6804,7 @@ globals_of_w32 (void)
6062 g_b_init_lookup_account_sid = 0; 6804 g_b_init_lookup_account_sid = 0;
6063 g_b_init_get_sid_sub_authority = 0; 6805 g_b_init_get_sid_sub_authority = 0;
6064 g_b_init_get_sid_sub_authority_count = 0; 6806 g_b_init_get_sid_sub_authority_count = 0;
6807 g_b_init_get_security_info = 0;
6065 g_b_init_get_file_security = 0; 6808 g_b_init_get_file_security = 0;
6066 g_b_init_get_security_descriptor_owner = 0; 6809 g_b_init_get_security_descriptor_owner = 0;
6067 g_b_init_get_security_descriptor_group = 0; 6810 g_b_init_get_security_descriptor_group = 0;
@@ -6081,6 +6824,7 @@ globals_of_w32 (void)
6081 g_b_init_get_length_sid = 0; 6824 g_b_init_get_length_sid = 0;
6082 g_b_init_get_native_system_info = 0; 6825 g_b_init_get_native_system_info = 0;
6083 g_b_init_get_system_times = 0; 6826 g_b_init_get_system_times = 0;
6827 g_b_init_create_symbolic_link = 0;
6084 num_of_processors = 0; 6828 num_of_processors = 0;
6085 /* The following sets a handler for shutdown notifications for 6829 /* The following sets a handler for shutdown notifications for
6086 console apps. This actually applies to Emacs in both console and 6830 console apps. This actually applies to Emacs in both console and
@@ -6279,7 +7023,7 @@ serial_configure (struct Lisp_Process *p, Lisp_Object contact)
6279 error ("SetCommState() failed"); 7023 error ("SetCommState() failed");
6280 7024
6281 childp2 = Fplist_put (childp2, QCsummary, build_string (summary)); 7025 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
6282 p->childp = childp2; 7026 PSET (p, childp, childp2);
6283} 7027}
6284 7028
6285#ifdef HAVE_GNUTLS 7029#ifdef HAVE_GNUTLS