diff options
Diffstat (limited to 'src/w32.c')
| -rw-r--r-- | src/w32.c | 1334 |
1 files changed, 1079 insertions, 255 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows 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-2013 Free Software Foundation, Inc. |
| 3 | 3 | ||
| 4 | This file is part of GNU Emacs. | 4 | This file is part of GNU Emacs. |
| 5 | 5 | ||
| @@ -29,15 +29,15 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 29 | #include <ctype.h> | 29 | #include <ctype.h> |
| 30 | #include <signal.h> | 30 | #include <signal.h> |
| 31 | #include <sys/file.h> | 31 | #include <sys/file.h> |
| 32 | #include <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */ | ||
| 32 | #include <sys/time.h> | 33 | #include <sys/time.h> |
| 33 | #include <sys/utime.h> | 34 | #include <sys/utime.h> |
| 34 | #include <math.h> | 35 | #include <math.h> |
| 35 | #include <time.h> | ||
| 36 | 36 | ||
| 37 | /* must include CRT headers *before* config.h */ | 37 | /* must include CRT headers *before* config.h */ |
| 38 | 38 | ||
| 39 | #include <config.h> | 39 | #include <config.h> |
| 40 | #include <mbstring.h> /* for _mbspbrk */ | 40 | #include <mbstring.h> /* for _mbspbrk, _mbslwr, _mbsrchr, ... */ |
| 41 | 41 | ||
| 42 | #undef access | 42 | #undef access |
| 43 | #undef chdir | 43 | #undef chdir |
| @@ -69,7 +69,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 69 | #include <pwd.h> | 69 | #include <pwd.h> |
| 70 | #include <grp.h> | 70 | #include <grp.h> |
| 71 | 71 | ||
| 72 | #ifdef __GNUC__ | 72 | /* MinGW64 (_W64) defines these in its _mingw.h. */ |
| 73 | #if defined(__GNUC__) && !defined(_W64) | ||
| 73 | #define _ANONYMOUS_UNION | 74 | #define _ANONYMOUS_UNION |
| 74 | #define _ANONYMOUS_STRUCT | 75 | #define _ANONYMOUS_STRUCT |
| 75 | #endif | 76 | #endif |
| @@ -96,33 +97,44 @@ typedef struct _MEMORY_STATUS_EX { | |||
| 96 | #ifndef _MSC_VER | 97 | #ifndef _MSC_VER |
| 97 | #include <w32api.h> | 98 | #include <w32api.h> |
| 98 | #endif | 99 | #endif |
| 100 | #if _WIN32_WINNT < 0x0500 | ||
| 99 | #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15) | 101 | #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15) |
| 100 | /* This either is not in psapi.h or guarded by higher value of | 102 | /* This either is not in psapi.h or guarded by higher value of |
| 101 | _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15 | 103 | _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15 |
| 102 | defines it in psapi.h */ | 104 | defines it in psapi.h */ |
| 103 | typedef struct _PROCESS_MEMORY_COUNTERS_EX { | 105 | typedef struct _PROCESS_MEMORY_COUNTERS_EX { |
| 104 | DWORD cb; | 106 | DWORD cb; |
| 105 | DWORD PageFaultCount; | 107 | DWORD PageFaultCount; |
| 106 | DWORD PeakWorkingSetSize; | 108 | SIZE_T PeakWorkingSetSize; |
| 107 | DWORD WorkingSetSize; | 109 | SIZE_T WorkingSetSize; |
| 108 | DWORD QuotaPeakPagedPoolUsage; | 110 | SIZE_T QuotaPeakPagedPoolUsage; |
| 109 | DWORD QuotaPagedPoolUsage; | 111 | SIZE_T QuotaPagedPoolUsage; |
| 110 | DWORD QuotaPeakNonPagedPoolUsage; | 112 | SIZE_T QuotaPeakNonPagedPoolUsage; |
| 111 | DWORD QuotaNonPagedPoolUsage; | 113 | SIZE_T QuotaNonPagedPoolUsage; |
| 112 | DWORD PagefileUsage; | 114 | SIZE_T PagefileUsage; |
| 113 | DWORD PeakPagefileUsage; | 115 | SIZE_T PeakPagefileUsage; |
| 114 | DWORD PrivateUsage; | 116 | SIZE_T PrivateUsage; |
| 115 | } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX; | 117 | } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX; |
| 116 | #endif | 118 | #endif |
| 119 | #endif | ||
| 117 | 120 | ||
| 118 | #include <winioctl.h> | 121 | #include <winioctl.h> |
| 119 | #include <aclapi.h> | 122 | #include <aclapi.h> |
| 123 | #include <sddl.h> | ||
| 120 | 124 | ||
| 121 | #ifdef _MSC_VER | 125 | #include <sys/acl.h> |
| 122 | /* MSVC doesn't provide the definition of REPARSE_DATA_BUFFER and the | 126 | |
| 123 | associated macros, except on ntifs.h, which cannot be included | 127 | /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we |
| 124 | because it triggers conflicts with other Windows API headers. So | 128 | define them by hand if not already defined. */ |
| 125 | we define it here by hand. */ | 129 | #ifndef SDDL_REVISION_1 |
| 130 | #define SDDL_REVISION_1 1 | ||
| 131 | #endif /* SDDL_REVISION_1 */ | ||
| 132 | |||
| 133 | #if defined(_MSC_VER) || defined(_W64) | ||
| 134 | /* MSVC and MinGW64 don't provide the definition of | ||
| 135 | REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h, | ||
| 136 | which cannot be included because it triggers conflicts with other | ||
| 137 | Windows API headers. So we define it here by hand. */ | ||
| 126 | 138 | ||
| 127 | typedef struct _REPARSE_DATA_BUFFER { | 139 | typedef struct _REPARSE_DATA_BUFFER { |
| 128 | ULONG ReparseTag; | 140 | ULONG ReparseTag; |
| @@ -150,13 +162,24 @@ typedef struct _REPARSE_DATA_BUFFER { | |||
| 150 | } DUMMYUNIONNAME; | 162 | } DUMMYUNIONNAME; |
| 151 | } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; | 163 | } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; |
| 152 | 164 | ||
| 165 | #ifndef FILE_DEVICE_FILE_SYSTEM | ||
| 153 | #define FILE_DEVICE_FILE_SYSTEM 9 | 166 | #define FILE_DEVICE_FILE_SYSTEM 9 |
| 167 | #endif | ||
| 168 | #ifndef METHOD_BUFFERED | ||
| 154 | #define METHOD_BUFFERED 0 | 169 | #define METHOD_BUFFERED 0 |
| 170 | #endif | ||
| 171 | #ifndef FILE_ANY_ACCESS | ||
| 155 | #define FILE_ANY_ACCESS 0x00000000 | 172 | #define FILE_ANY_ACCESS 0x00000000 |
| 173 | #endif | ||
| 174 | #ifndef CTL_CODE | ||
| 156 | #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m)) | 175 | #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m)) |
| 176 | #endif | ||
| 177 | /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */ | ||
| 178 | #ifndef FSCTL_GET_REPARSE_POINT | ||
| 157 | #define FSCTL_GET_REPARSE_POINT \ | 179 | #define FSCTL_GET_REPARSE_POINT \ |
| 158 | CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) | 180 | CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) |
| 159 | #endif | 181 | #endif |
| 182 | #endif | ||
| 160 | 183 | ||
| 161 | /* TCP connection support. */ | 184 | /* TCP connection support. */ |
| 162 | #include <sys/socket.h> | 185 | #include <sys/socket.h> |
| @@ -249,6 +272,11 @@ static BOOL g_b_init_copy_sid; | |||
| 249 | static BOOL g_b_init_get_native_system_info; | 272 | static BOOL g_b_init_get_native_system_info; |
| 250 | static BOOL g_b_init_get_system_times; | 273 | static BOOL g_b_init_get_system_times; |
| 251 | static BOOL g_b_init_create_symbolic_link; | 274 | static BOOL g_b_init_create_symbolic_link; |
| 275 | static BOOL g_b_init_get_security_descriptor_dacl; | ||
| 276 | static BOOL g_b_init_convert_sd_to_sddl; | ||
| 277 | static BOOL g_b_init_convert_sddl_to_sd; | ||
| 278 | static BOOL g_b_init_is_valid_security_descriptor; | ||
| 279 | static BOOL g_b_init_set_file_security; | ||
| 252 | 280 | ||
| 253 | /* | 281 | /* |
| 254 | BEGIN: Wrapper functions around OpenProcessToken | 282 | BEGIN: Wrapper functions around OpenProcessToken |
| @@ -278,9 +306,11 @@ GetProcessTimes_Proc get_process_times_fn = NULL; | |||
| 278 | #ifdef _UNICODE | 306 | #ifdef _UNICODE |
| 279 | const char * const LookupAccountSid_Name = "LookupAccountSidW"; | 307 | const char * const LookupAccountSid_Name = "LookupAccountSidW"; |
| 280 | const char * const GetFileSecurity_Name = "GetFileSecurityW"; | 308 | const char * const GetFileSecurity_Name = "GetFileSecurityW"; |
| 309 | const char * const SetFileSecurity_Name = "SetFileSecurityW"; | ||
| 281 | #else | 310 | #else |
| 282 | const char * const LookupAccountSid_Name = "LookupAccountSidA"; | 311 | const char * const LookupAccountSid_Name = "LookupAccountSidA"; |
| 283 | const char * const GetFileSecurity_Name = "GetFileSecurityA"; | 312 | const char * const GetFileSecurity_Name = "GetFileSecurityA"; |
| 313 | const char * const SetFileSecurity_Name = "SetFileSecurityA"; | ||
| 284 | #endif | 314 | #endif |
| 285 | typedef BOOL (WINAPI * LookupAccountSid_Proc) ( | 315 | typedef BOOL (WINAPI * LookupAccountSid_Proc) ( |
| 286 | LPCTSTR lpSystemName, | 316 | LPCTSTR lpSystemName, |
| @@ -310,6 +340,10 @@ typedef BOOL (WINAPI * GetFileSecurity_Proc) ( | |||
| 310 | PSECURITY_DESCRIPTOR pSecurityDescriptor, | 340 | PSECURITY_DESCRIPTOR pSecurityDescriptor, |
| 311 | DWORD nLength, | 341 | DWORD nLength, |
| 312 | LPDWORD lpnLengthNeeded); | 342 | LPDWORD lpnLengthNeeded); |
| 343 | typedef BOOL (WINAPI *SetFileSecurity_Proc) ( | ||
| 344 | LPCTSTR lpFileName, | ||
| 345 | SECURITY_INFORMATION SecurityInformation, | ||
| 346 | PSECURITY_DESCRIPTOR pSecurityDescriptor); | ||
| 313 | typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) ( | 347 | typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) ( |
| 314 | PSECURITY_DESCRIPTOR pSecurityDescriptor, | 348 | PSECURITY_DESCRIPTOR pSecurityDescriptor, |
| 315 | PSID *pOwner, | 349 | PSID *pOwner, |
| @@ -318,6 +352,11 @@ typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) ( | |||
| 318 | PSECURITY_DESCRIPTOR pSecurityDescriptor, | 352 | PSECURITY_DESCRIPTOR pSecurityDescriptor, |
| 319 | PSID *pGroup, | 353 | PSID *pGroup, |
| 320 | LPBOOL lpbGroupDefaulted); | 354 | LPBOOL lpbGroupDefaulted); |
| 355 | typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) ( | ||
| 356 | PSECURITY_DESCRIPTOR pSecurityDescriptor, | ||
| 357 | LPBOOL lpbDaclPresent, | ||
| 358 | PACL *pDacl, | ||
| 359 | LPBOOL lpbDaclDefaulted); | ||
| 321 | typedef BOOL (WINAPI * IsValidSid_Proc) ( | 360 | typedef BOOL (WINAPI * IsValidSid_Proc) ( |
| 322 | PSID sid); | 361 | PSID sid); |
| 323 | typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) ( | 362 | typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) ( |
| @@ -343,8 +382,8 @@ typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) ( | |||
| 343 | DWORD cb); | 382 | DWORD cb); |
| 344 | typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) ( | 383 | typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) ( |
| 345 | HANDLE hProcess, | 384 | HANDLE hProcess, |
| 346 | DWORD * lpMinimumWorkingSetSize, | 385 | PSIZE_T lpMinimumWorkingSetSize, |
| 347 | DWORD * lpMaximumWorkingSetSize); | 386 | PSIZE_T lpMaximumWorkingSetSize); |
| 348 | typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) ( | 387 | typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) ( |
| 349 | LPMEMORYSTATUS lpBuffer); | 388 | LPMEMORYSTATUS lpBuffer); |
| 350 | typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) ( | 389 | typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) ( |
| @@ -368,6 +407,18 @@ typedef BOOLEAN (WINAPI *CreateSymbolicLink_Proc) ( | |||
| 368 | LPTSTR lpSymlinkFileName, | 407 | LPTSTR lpSymlinkFileName, |
| 369 | LPTSTR lpTargetFileName, | 408 | LPTSTR lpTargetFileName, |
| 370 | DWORD dwFlags); | 409 | DWORD dwFlags); |
| 410 | typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) ( | ||
| 411 | LPCTSTR StringSecurityDescriptor, | ||
| 412 | DWORD StringSDRevision, | ||
| 413 | PSECURITY_DESCRIPTOR *SecurityDescriptor, | ||
| 414 | PULONG SecurityDescriptorSize); | ||
| 415 | typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) ( | ||
| 416 | PSECURITY_DESCRIPTOR SecurityDescriptor, | ||
| 417 | DWORD RequestedStringSDRevision, | ||
| 418 | SECURITY_INFORMATION SecurityInformation, | ||
| 419 | LPTSTR *StringSecurityDescriptor, | ||
| 420 | PULONG StringSecurityDescriptorLen); | ||
| 421 | typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR); | ||
| 371 | 422 | ||
| 372 | /* ** A utility function ** */ | 423 | /* ** A utility function ** */ |
| 373 | static BOOL | 424 | static BOOL |
| @@ -613,6 +664,7 @@ get_file_security (LPCTSTR lpFileName, | |||
| 613 | HMODULE hm_advapi32 = NULL; | 664 | HMODULE hm_advapi32 = NULL; |
| 614 | if (is_windows_9x () == TRUE) | 665 | if (is_windows_9x () == TRUE) |
| 615 | { | 666 | { |
| 667 | errno = ENOTSUP; | ||
| 616 | return FALSE; | 668 | return FALSE; |
| 617 | } | 669 | } |
| 618 | if (g_b_init_get_file_security == 0) | 670 | if (g_b_init_get_file_security == 0) |
| @@ -625,6 +677,7 @@ get_file_security (LPCTSTR lpFileName, | |||
| 625 | } | 677 | } |
| 626 | if (s_pfn_Get_File_Security == NULL) | 678 | if (s_pfn_Get_File_Security == NULL) |
| 627 | { | 679 | { |
| 680 | errno = ENOTSUP; | ||
| 628 | return FALSE; | 681 | return FALSE; |
| 629 | } | 682 | } |
| 630 | return (s_pfn_Get_File_Security (lpFileName, RequestedInformation, | 683 | return (s_pfn_Get_File_Security (lpFileName, RequestedInformation, |
| @@ -633,6 +686,35 @@ get_file_security (LPCTSTR lpFileName, | |||
| 633 | } | 686 | } |
| 634 | 687 | ||
| 635 | static BOOL WINAPI | 688 | static BOOL WINAPI |
| 689 | set_file_security (LPCTSTR lpFileName, | ||
| 690 | SECURITY_INFORMATION SecurityInformation, | ||
| 691 | PSECURITY_DESCRIPTOR pSecurityDescriptor) | ||
| 692 | { | ||
| 693 | static SetFileSecurity_Proc s_pfn_Set_File_Security = NULL; | ||
| 694 | HMODULE hm_advapi32 = NULL; | ||
| 695 | if (is_windows_9x () == TRUE) | ||
| 696 | { | ||
| 697 | errno = ENOTSUP; | ||
| 698 | return FALSE; | ||
| 699 | } | ||
| 700 | if (g_b_init_set_file_security == 0) | ||
| 701 | { | ||
| 702 | g_b_init_set_file_security = 1; | ||
| 703 | hm_advapi32 = LoadLibrary ("Advapi32.dll"); | ||
| 704 | s_pfn_Set_File_Security = | ||
| 705 | (SetFileSecurity_Proc) GetProcAddress ( | ||
| 706 | hm_advapi32, SetFileSecurity_Name); | ||
| 707 | } | ||
| 708 | if (s_pfn_Set_File_Security == NULL) | ||
| 709 | { | ||
| 710 | errno = ENOTSUP; | ||
| 711 | return FALSE; | ||
| 712 | } | ||
| 713 | return (s_pfn_Set_File_Security (lpFileName, SecurityInformation, | ||
| 714 | pSecurityDescriptor)); | ||
| 715 | } | ||
| 716 | |||
| 717 | static BOOL WINAPI | ||
| 636 | get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor, | 718 | get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor, |
| 637 | PSID *pOwner, | 719 | PSID *pOwner, |
| 638 | LPBOOL lpbOwnerDefaulted) | 720 | LPBOOL lpbOwnerDefaulted) |
| @@ -641,6 +723,7 @@ get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor, | |||
| 641 | HMODULE hm_advapi32 = NULL; | 723 | HMODULE hm_advapi32 = NULL; |
| 642 | if (is_windows_9x () == TRUE) | 724 | if (is_windows_9x () == TRUE) |
| 643 | { | 725 | { |
| 726 | errno = ENOTSUP; | ||
| 644 | return FALSE; | 727 | return FALSE; |
| 645 | } | 728 | } |
| 646 | if (g_b_init_get_security_descriptor_owner == 0) | 729 | if (g_b_init_get_security_descriptor_owner == 0) |
| @@ -653,6 +736,7 @@ get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor, | |||
| 653 | } | 736 | } |
| 654 | if (s_pfn_Get_Security_Descriptor_Owner == NULL) | 737 | if (s_pfn_Get_Security_Descriptor_Owner == NULL) |
| 655 | { | 738 | { |
| 739 | errno = ENOTSUP; | ||
| 656 | return FALSE; | 740 | return FALSE; |
| 657 | } | 741 | } |
| 658 | return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner, | 742 | return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner, |
| @@ -668,6 +752,7 @@ get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor, | |||
| 668 | HMODULE hm_advapi32 = NULL; | 752 | HMODULE hm_advapi32 = NULL; |
| 669 | if (is_windows_9x () == TRUE) | 753 | if (is_windows_9x () == TRUE) |
| 670 | { | 754 | { |
| 755 | errno = ENOTSUP; | ||
| 671 | return FALSE; | 756 | return FALSE; |
| 672 | } | 757 | } |
| 673 | if (g_b_init_get_security_descriptor_group == 0) | 758 | if (g_b_init_get_security_descriptor_group == 0) |
| @@ -680,6 +765,7 @@ get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor, | |||
| 680 | } | 765 | } |
| 681 | if (s_pfn_Get_Security_Descriptor_Group == NULL) | 766 | if (s_pfn_Get_Security_Descriptor_Group == NULL) |
| 682 | { | 767 | { |
| 768 | errno = ENOTSUP; | ||
| 683 | return FALSE; | 769 | return FALSE; |
| 684 | } | 770 | } |
| 685 | return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup, | 771 | return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup, |
| @@ -687,6 +773,37 @@ get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor, | |||
| 687 | } | 773 | } |
| 688 | 774 | ||
| 689 | static BOOL WINAPI | 775 | static BOOL WINAPI |
| 776 | get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor, | ||
| 777 | LPBOOL lpbDaclPresent, | ||
| 778 | PACL *pDacl, | ||
| 779 | LPBOOL lpbDaclDefaulted) | ||
| 780 | { | ||
| 781 | static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL; | ||
| 782 | HMODULE hm_advapi32 = NULL; | ||
| 783 | if (is_windows_9x () == TRUE) | ||
| 784 | { | ||
| 785 | errno = ENOTSUP; | ||
| 786 | return FALSE; | ||
| 787 | } | ||
| 788 | if (g_b_init_get_security_descriptor_dacl == 0) | ||
| 789 | { | ||
| 790 | g_b_init_get_security_descriptor_dacl = 1; | ||
| 791 | hm_advapi32 = LoadLibrary ("Advapi32.dll"); | ||
| 792 | s_pfn_Get_Security_Descriptor_Dacl = | ||
| 793 | (GetSecurityDescriptorDacl_Proc) GetProcAddress ( | ||
| 794 | hm_advapi32, "GetSecurityDescriptorDacl"); | ||
| 795 | } | ||
| 796 | if (s_pfn_Get_Security_Descriptor_Dacl == NULL) | ||
| 797 | { | ||
| 798 | errno = ENOTSUP; | ||
| 799 | return FALSE; | ||
| 800 | } | ||
| 801 | return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor, | ||
| 802 | lpbDaclPresent, pDacl, | ||
| 803 | lpbDaclDefaulted)); | ||
| 804 | } | ||
| 805 | |||
| 806 | static BOOL WINAPI | ||
| 690 | is_valid_sid (PSID sid) | 807 | is_valid_sid (PSID sid) |
| 691 | { | 808 | { |
| 692 | static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL; | 809 | static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL; |
| @@ -880,6 +997,120 @@ create_symbolic_link (LPTSTR lpSymlinkFilename, | |||
| 880 | } | 997 | } |
| 881 | return retval; | 998 | return retval; |
| 882 | } | 999 | } |
| 1000 | |||
| 1001 | static BOOL WINAPI | ||
| 1002 | is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor) | ||
| 1003 | { | ||
| 1004 | static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL; | ||
| 1005 | |||
| 1006 | if (is_windows_9x () == TRUE) | ||
| 1007 | { | ||
| 1008 | errno = ENOTSUP; | ||
| 1009 | return FALSE; | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | if (g_b_init_is_valid_security_descriptor == 0) | ||
| 1013 | { | ||
| 1014 | g_b_init_is_valid_security_descriptor = 1; | ||
| 1015 | s_pfn_Is_Valid_Security_Descriptor_Proc = | ||
| 1016 | (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"), | ||
| 1017 | "IsValidSecurityDescriptor"); | ||
| 1018 | } | ||
| 1019 | if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL) | ||
| 1020 | { | ||
| 1021 | errno = ENOTSUP; | ||
| 1022 | return FALSE; | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor); | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | static BOOL WINAPI | ||
| 1029 | convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor, | ||
| 1030 | DWORD RequestedStringSDRevision, | ||
| 1031 | SECURITY_INFORMATION SecurityInformation, | ||
| 1032 | LPTSTR *StringSecurityDescriptor, | ||
| 1033 | PULONG StringSecurityDescriptorLen) | ||
| 1034 | { | ||
| 1035 | static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL; | ||
| 1036 | BOOL retval; | ||
| 1037 | |||
| 1038 | if (is_windows_9x () == TRUE) | ||
| 1039 | { | ||
| 1040 | errno = ENOTSUP; | ||
| 1041 | return FALSE; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | if (g_b_init_convert_sd_to_sddl == 0) | ||
| 1045 | { | ||
| 1046 | g_b_init_convert_sd_to_sddl = 1; | ||
| 1047 | #ifdef _UNICODE | ||
| 1048 | s_pfn_Convert_SD_To_SDDL = | ||
| 1049 | (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"), | ||
| 1050 | "ConvertSecurityDescriptorToStringSecurityDescriptorW"); | ||
| 1051 | #else | ||
| 1052 | s_pfn_Convert_SD_To_SDDL = | ||
| 1053 | (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"), | ||
| 1054 | "ConvertSecurityDescriptorToStringSecurityDescriptorA"); | ||
| 1055 | #endif | ||
| 1056 | } | ||
| 1057 | if (s_pfn_Convert_SD_To_SDDL == NULL) | ||
| 1058 | { | ||
| 1059 | errno = ENOTSUP; | ||
| 1060 | return FALSE; | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor, | ||
| 1064 | RequestedStringSDRevision, | ||
| 1065 | SecurityInformation, | ||
| 1066 | StringSecurityDescriptor, | ||
| 1067 | StringSecurityDescriptorLen); | ||
| 1068 | |||
| 1069 | return retval; | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | static BOOL WINAPI | ||
| 1073 | convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor, | ||
| 1074 | DWORD StringSDRevision, | ||
| 1075 | PSECURITY_DESCRIPTOR *SecurityDescriptor, | ||
| 1076 | PULONG SecurityDescriptorSize) | ||
| 1077 | { | ||
| 1078 | static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL; | ||
| 1079 | BOOL retval; | ||
| 1080 | |||
| 1081 | if (is_windows_9x () == TRUE) | ||
| 1082 | { | ||
| 1083 | errno = ENOTSUP; | ||
| 1084 | return FALSE; | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | if (g_b_init_convert_sddl_to_sd == 0) | ||
| 1088 | { | ||
| 1089 | g_b_init_convert_sddl_to_sd = 1; | ||
| 1090 | #ifdef _UNICODE | ||
| 1091 | s_pfn_Convert_SDDL_To_SD = | ||
| 1092 | (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"), | ||
| 1093 | "ConvertStringSecurityDescriptorToSecurityDescriptorW"); | ||
| 1094 | #else | ||
| 1095 | s_pfn_Convert_SDDL_To_SD = | ||
| 1096 | (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"), | ||
| 1097 | "ConvertStringSecurityDescriptorToSecurityDescriptorA"); | ||
| 1098 | #endif | ||
| 1099 | } | ||
| 1100 | if (s_pfn_Convert_SDDL_To_SD == NULL) | ||
| 1101 | { | ||
| 1102 | errno = ENOTSUP; | ||
| 1103 | return FALSE; | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor, | ||
| 1107 | StringSDRevision, | ||
| 1108 | SecurityDescriptor, | ||
| 1109 | SecurityDescriptorSize); | ||
| 1110 | |||
| 1111 | return retval; | ||
| 1112 | } | ||
| 1113 | |||
| 883 | 1114 | ||
| 884 | 1115 | ||
| 885 | /* Return 1 if P is a valid pointer to an object of size SIZE. Return | 1116 | /* Return 1 if P is a valid pointer to an object of size SIZE. Return |
| @@ -1306,35 +1537,110 @@ srandom (int seed) | |||
| 1306 | srand (seed); | 1537 | srand (seed); |
| 1307 | } | 1538 | } |
| 1308 | 1539 | ||
| 1540 | /* Current codepage for encoding file names. */ | ||
| 1541 | static int file_name_codepage; | ||
| 1542 | |||
| 1543 | /* Return the maximum length in bytes of a multibyte character | ||
| 1544 | sequence encoded in the current ANSI codepage. This is required to | ||
| 1545 | correctly walk the encoded file names one character at a time. */ | ||
| 1546 | static int | ||
| 1547 | max_filename_mbslen (void) | ||
| 1548 | { | ||
| 1549 | /* A simple cache to avoid calling GetCPInfo every time we need to | ||
| 1550 | normalize a file name. The file-name encoding is not supposed to | ||
| 1551 | be changed too frequently, if ever. */ | ||
| 1552 | static Lisp_Object last_file_name_encoding; | ||
| 1553 | static int last_max_mbslen; | ||
| 1554 | Lisp_Object current_encoding; | ||
| 1555 | |||
| 1556 | current_encoding = Vfile_name_coding_system; | ||
| 1557 | if (NILP (current_encoding)) | ||
| 1558 | current_encoding = Vdefault_file_name_coding_system; | ||
| 1559 | |||
| 1560 | if (!EQ (last_file_name_encoding, current_encoding)) | ||
| 1561 | { | ||
| 1562 | CPINFO cp_info; | ||
| 1563 | |||
| 1564 | last_file_name_encoding = current_encoding; | ||
| 1565 | /* Default to the current ANSI codepage. */ | ||
| 1566 | file_name_codepage = w32_ansi_code_page; | ||
| 1567 | if (!NILP (current_encoding)) | ||
| 1568 | { | ||
| 1569 | char *cpname = SDATA (SYMBOL_NAME (current_encoding)); | ||
| 1570 | char *cp = NULL, *end; | ||
| 1571 | int cpnum; | ||
| 1572 | |||
| 1573 | if (strncmp (cpname, "cp", 2) == 0) | ||
| 1574 | cp = cpname + 2; | ||
| 1575 | else if (strncmp (cpname, "windows-", 8) == 0) | ||
| 1576 | cp = cpname + 8; | ||
| 1577 | |||
| 1578 | if (cp) | ||
| 1579 | { | ||
| 1580 | end = cp; | ||
| 1581 | cpnum = strtol (cp, &end, 10); | ||
| 1582 | if (cpnum && *end == '\0' && end - cp >= 2) | ||
| 1583 | file_name_codepage = cpnum; | ||
| 1584 | } | ||
| 1585 | } | ||
| 1586 | |||
| 1587 | if (!file_name_codepage) | ||
| 1588 | file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */ | ||
| 1589 | |||
| 1590 | if (!GetCPInfo (file_name_codepage, &cp_info)) | ||
| 1591 | { | ||
| 1592 | file_name_codepage = CP_ACP; | ||
| 1593 | if (!GetCPInfo (file_name_codepage, &cp_info)) | ||
| 1594 | emacs_abort (); | ||
| 1595 | } | ||
| 1596 | last_max_mbslen = cp_info.MaxCharSize; | ||
| 1597 | } | ||
| 1598 | |||
| 1599 | return last_max_mbslen; | ||
| 1600 | } | ||
| 1309 | 1601 | ||
| 1310 | /* Normalize filename by converting all path separators to | 1602 | /* Normalize filename by converting all path separators to |
| 1311 | the specified separator. Also conditionally convert upper | 1603 | the specified separator. Also conditionally convert upper |
| 1312 | case path name components to lower case. */ | 1604 | case path name components to lower case. */ |
| 1313 | 1605 | ||
| 1314 | static void | 1606 | static void |
| 1315 | normalize_filename (register char *fp, char path_sep) | 1607 | normalize_filename (register char *fp, char path_sep, int multibyte) |
| 1316 | { | 1608 | { |
| 1317 | char sep; | 1609 | char sep; |
| 1318 | char *elem; | 1610 | char *elem, *p2; |
| 1611 | int dbcs_p = max_filename_mbslen () > 1; | ||
| 1612 | |||
| 1613 | /* Multibyte file names are in the Emacs internal representation, so | ||
| 1614 | we can traverse them by bytes with no problems. */ | ||
| 1615 | if (multibyte) | ||
| 1616 | dbcs_p = 0; | ||
| 1319 | 1617 | ||
| 1320 | /* Always lower-case drive letters a-z, even if the filesystem | 1618 | /* Always lower-case drive letters a-z, even if the filesystem |
| 1321 | preserves case in filenames. | 1619 | preserves case in filenames. |
| 1322 | This is so filenames can be compared by string comparison | 1620 | This is so filenames can be compared by string comparison |
| 1323 | functions that are case-sensitive. Even case-preserving filesystems | 1621 | functions that are case-sensitive. Even case-preserving filesystems |
| 1324 | do not distinguish case in drive letters. */ | 1622 | do not distinguish case in drive letters. */ |
| 1325 | if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z') | 1623 | if (dbcs_p) |
| 1624 | p2 = CharNextExA (file_name_codepage, fp, 0); | ||
| 1625 | else | ||
| 1626 | p2 = fp + 1; | ||
| 1627 | |||
| 1628 | if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z') | ||
| 1326 | { | 1629 | { |
| 1327 | *fp += 'a' - 'A'; | 1630 | *fp += 'a' - 'A'; |
| 1328 | fp += 2; | 1631 | fp += 2; |
| 1329 | } | 1632 | } |
| 1330 | 1633 | ||
| 1331 | if (NILP (Vw32_downcase_file_names)) | 1634 | if (multibyte || NILP (Vw32_downcase_file_names)) |
| 1332 | { | 1635 | { |
| 1333 | while (*fp) | 1636 | while (*fp) |
| 1334 | { | 1637 | { |
| 1335 | if (*fp == '/' || *fp == '\\') | 1638 | if (*fp == '/' || *fp == '\\') |
| 1336 | *fp = path_sep; | 1639 | *fp = path_sep; |
| 1337 | fp++; | 1640 | if (!dbcs_p) |
| 1641 | fp++; | ||
| 1642 | else | ||
| 1643 | fp = CharNextExA (file_name_codepage, fp, 0); | ||
| 1338 | } | 1644 | } |
| 1339 | return; | 1645 | return; |
| 1340 | } | 1646 | } |
| @@ -1357,27 +1663,36 @@ normalize_filename (register char *fp, char path_sep) | |||
| 1357 | if (elem && elem != fp) | 1663 | if (elem && elem != fp) |
| 1358 | { | 1664 | { |
| 1359 | *fp = 0; /* temporary end of string */ | 1665 | *fp = 0; /* temporary end of string */ |
| 1360 | _strlwr (elem); /* while we convert to lower case */ | 1666 | _mbslwr (elem); /* while we convert to lower case */ |
| 1361 | } | 1667 | } |
| 1362 | *fp = sep; /* convert (or restore) path separator */ | 1668 | *fp = sep; /* convert (or restore) path separator */ |
| 1363 | elem = fp + 1; /* next element starts after separator */ | 1669 | elem = fp + 1; /* next element starts after separator */ |
| 1364 | sep = path_sep; | 1670 | sep = path_sep; |
| 1365 | } | 1671 | } |
| 1366 | } while (*fp++); | 1672 | if (*fp) |
| 1673 | { | ||
| 1674 | if (!dbcs_p) | ||
| 1675 | fp++; | ||
| 1676 | else | ||
| 1677 | fp = CharNextExA (file_name_codepage, fp, 0); | ||
| 1678 | } | ||
| 1679 | } while (*fp); | ||
| 1367 | } | 1680 | } |
| 1368 | 1681 | ||
| 1369 | /* Destructively turn backslashes into slashes. */ | 1682 | /* Destructively turn backslashes into slashes. MULTIBYTE non-zero |
| 1683 | means the file name is a multibyte string in Emacs's internal | ||
| 1684 | representation. */ | ||
| 1370 | void | 1685 | void |
| 1371 | dostounix_filename (register char *p) | 1686 | dostounix_filename (register char *p, int multibyte) |
| 1372 | { | 1687 | { |
| 1373 | normalize_filename (p, '/'); | 1688 | normalize_filename (p, '/', multibyte); |
| 1374 | } | 1689 | } |
| 1375 | 1690 | ||
| 1376 | /* Destructively turn slashes into backslashes. */ | 1691 | /* Destructively turn slashes into backslashes. */ |
| 1377 | void | 1692 | void |
| 1378 | unixtodos_filename (register char *p) | 1693 | unixtodos_filename (register char *p) |
| 1379 | { | 1694 | { |
| 1380 | normalize_filename (p, '\\'); | 1695 | normalize_filename (p, '\\', 0); |
| 1381 | } | 1696 | } |
| 1382 | 1697 | ||
| 1383 | /* Remove all CR's that are followed by a LF. | 1698 | /* Remove all CR's that are followed by a LF. |
| @@ -1428,12 +1743,17 @@ parse_root (char * name, char ** pPath) | |||
| 1428 | else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1])) | 1743 | else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1])) |
| 1429 | { | 1744 | { |
| 1430 | int slashes = 2; | 1745 | int slashes = 2; |
| 1746 | int dbcs_p = max_filename_mbslen () > 1; | ||
| 1747 | |||
| 1431 | name += 2; | 1748 | name += 2; |
| 1432 | do | 1749 | do |
| 1433 | { | 1750 | { |
| 1434 | if (IS_DIRECTORY_SEP (*name) && --slashes == 0) | 1751 | if (IS_DIRECTORY_SEP (*name) && --slashes == 0) |
| 1435 | break; | 1752 | break; |
| 1436 | name++; | 1753 | if (dbcs_p) |
| 1754 | name = CharNextExA (file_name_codepage, name, 0); | ||
| 1755 | else | ||
| 1756 | name++; | ||
| 1437 | } | 1757 | } |
| 1438 | while ( *name ); | 1758 | while ( *name ); |
| 1439 | if (IS_DIRECTORY_SEP (name[0])) | 1759 | if (IS_DIRECTORY_SEP (name[0])) |
| @@ -1498,7 +1818,7 @@ w32_get_long_filename (char * name, char * buf, int size) | |||
| 1498 | while (p != NULL && *p) | 1818 | while (p != NULL && *p) |
| 1499 | { | 1819 | { |
| 1500 | q = p; | 1820 | q = p; |
| 1501 | p = strchr (q, '\\'); | 1821 | p = _mbschr (q, '\\'); |
| 1502 | if (p) *p = '\0'; | 1822 | if (p) *p = '\0'; |
| 1503 | len = get_long_basename (full, o, size); | 1823 | len = get_long_basename (full, o, size); |
| 1504 | if (len > 0) | 1824 | if (len > 0) |
| @@ -1536,6 +1856,51 @@ is_unc_volume (const char *filename) | |||
| 1536 | return 1; | 1856 | return 1; |
| 1537 | } | 1857 | } |
| 1538 | 1858 | ||
| 1859 | /* Emulate the Posix unsetenv. */ | ||
| 1860 | int | ||
| 1861 | unsetenv (const char *name) | ||
| 1862 | { | ||
| 1863 | char *var; | ||
| 1864 | size_t name_len; | ||
| 1865 | int retval; | ||
| 1866 | |||
| 1867 | if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) | ||
| 1868 | { | ||
| 1869 | errno = EINVAL; | ||
| 1870 | return -1; | ||
| 1871 | } | ||
| 1872 | name_len = strlen (name); | ||
| 1873 | /* MS docs says an environment variable cannot be longer than 32K. */ | ||
| 1874 | if (name_len > 32767) | ||
| 1875 | { | ||
| 1876 | errno = ENOMEM; | ||
| 1877 | return 0; | ||
| 1878 | } | ||
| 1879 | /* It is safe to use 'alloca' with 32K size, since the stack is at | ||
| 1880 | least 2MB, and we set it to 8MB in the link command line. */ | ||
| 1881 | var = alloca (name_len + 2); | ||
| 1882 | strncpy (var, name, name_len); | ||
| 1883 | var[name_len++] = '='; | ||
| 1884 | var[name_len] = '\0'; | ||
| 1885 | return _putenv (var); | ||
| 1886 | } | ||
| 1887 | |||
| 1888 | /* MS _putenv doesn't support removing a variable when the argument | ||
| 1889 | does not include the '=' character, so we fix that here. */ | ||
| 1890 | int | ||
| 1891 | sys_putenv (char *str) | ||
| 1892 | { | ||
| 1893 | const char *const name_end = strchr (str, '='); | ||
| 1894 | |||
| 1895 | if (name_end == NULL) | ||
| 1896 | { | ||
| 1897 | /* Remove the variable from the environment. */ | ||
| 1898 | return unsetenv (str); | ||
| 1899 | } | ||
| 1900 | |||
| 1901 | return _putenv (str); | ||
| 1902 | } | ||
| 1903 | |||
| 1539 | #define REG_ROOT "SOFTWARE\\GNU\\Emacs" | 1904 | #define REG_ROOT "SOFTWARE\\GNU\\Emacs" |
| 1540 | 1905 | ||
| 1541 | LPBYTE | 1906 | LPBYTE |
| @@ -1725,16 +2090,16 @@ init_environment (char ** argv) | |||
| 1725 | 2090 | ||
| 1726 | if (!GetModuleFileName (NULL, modname, MAX_PATH)) | 2091 | if (!GetModuleFileName (NULL, modname, MAX_PATH)) |
| 1727 | emacs_abort (); | 2092 | emacs_abort (); |
| 1728 | if ((p = strrchr (modname, '\\')) == NULL) | 2093 | if ((p = _mbsrchr (modname, '\\')) == NULL) |
| 1729 | emacs_abort (); | 2094 | emacs_abort (); |
| 1730 | *p = 0; | 2095 | *p = 0; |
| 1731 | 2096 | ||
| 1732 | if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0) | 2097 | if ((p = _mbsrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0) |
| 1733 | { | 2098 | { |
| 1734 | char buf[SET_ENV_BUF_SIZE]; | 2099 | char buf[SET_ENV_BUF_SIZE]; |
| 1735 | 2100 | ||
| 1736 | *p = 0; | 2101 | *p = 0; |
| 1737 | for (p = modname; *p; p++) | 2102 | for (p = modname; *p; p = CharNext (p)) |
| 1738 | if (*p == '\\') *p = '/'; | 2103 | if (*p == '\\') *p = '/'; |
| 1739 | 2104 | ||
| 1740 | _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname); | 2105 | _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname); |
| @@ -1749,17 +2114,17 @@ init_environment (char ** argv) | |||
| 1749 | || xstrcasecmp (p, "\\AMD64") == 0)) | 2114 | || xstrcasecmp (p, "\\AMD64") == 0)) |
| 1750 | { | 2115 | { |
| 1751 | *p = 0; | 2116 | *p = 0; |
| 1752 | p = strrchr (modname, '\\'); | 2117 | p = _mbsrchr (modname, '\\'); |
| 1753 | if (p != NULL) | 2118 | if (p != NULL) |
| 1754 | { | 2119 | { |
| 1755 | *p = 0; | 2120 | *p = 0; |
| 1756 | p = strrchr (modname, '\\'); | 2121 | p = _mbsrchr (modname, '\\'); |
| 1757 | if (p && xstrcasecmp (p, "\\src") == 0) | 2122 | if (p && xstrcasecmp (p, "\\src") == 0) |
| 1758 | { | 2123 | { |
| 1759 | char buf[SET_ENV_BUF_SIZE]; | 2124 | char buf[SET_ENV_BUF_SIZE]; |
| 1760 | 2125 | ||
| 1761 | *p = 0; | 2126 | *p = 0; |
| 1762 | for (p = modname; *p; p++) | 2127 | for (p = modname; *p; p = CharNext (p)) |
| 1763 | if (*p == '\\') *p = '/'; | 2128 | if (*p == '\\') *p = '/'; |
| 1764 | 2129 | ||
| 1765 | _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname); | 2130 | _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname); |
| @@ -1870,7 +2235,7 @@ emacs_root_dir (void) | |||
| 1870 | emacs_abort (); | 2235 | emacs_abort (); |
| 1871 | strcpy (root_dir, p); | 2236 | strcpy (root_dir, p); |
| 1872 | root_dir[parse_root (root_dir, NULL)] = '\0'; | 2237 | root_dir[parse_root (root_dir, NULL)] = '\0'; |
| 1873 | dostounix_filename (root_dir); | 2238 | dostounix_filename (root_dir, 0); |
| 1874 | return root_dir; | 2239 | return root_dir; |
| 1875 | } | 2240 | } |
| 1876 | 2241 | ||
| @@ -2294,12 +2659,23 @@ get_volume_info (const char * name, const char ** pPath) | |||
| 2294 | { | 2659 | { |
| 2295 | char *str = temp; | 2660 | char *str = temp; |
| 2296 | int slashes = 4; | 2661 | int slashes = 4; |
| 2662 | int dbcs_p = max_filename_mbslen () > 1; | ||
| 2663 | |||
| 2297 | rootname = temp; | 2664 | rootname = temp; |
| 2298 | do | 2665 | do |
| 2299 | { | 2666 | { |
| 2300 | if (IS_DIRECTORY_SEP (*name) && --slashes == 0) | 2667 | if (IS_DIRECTORY_SEP (*name) && --slashes == 0) |
| 2301 | break; | 2668 | break; |
| 2302 | *str++ = *name++; | 2669 | if (!dbcs_p) |
| 2670 | *str++ = *name++; | ||
| 2671 | else | ||
| 2672 | { | ||
| 2673 | const char *p = name; | ||
| 2674 | |||
| 2675 | name = CharNextExA (file_name_codepage, name, 0); | ||
| 2676 | memcpy (str, p, name - p); | ||
| 2677 | str += name - p; | ||
| 2678 | } | ||
| 2303 | } | 2679 | } |
| 2304 | while ( *name ); | 2680 | while ( *name ); |
| 2305 | 2681 | ||
| @@ -2462,7 +2838,7 @@ static char *read_unc_volume (HANDLE, char *, int); | |||
| 2462 | static void close_unc_volume (HANDLE); | 2838 | static void close_unc_volume (HANDLE); |
| 2463 | 2839 | ||
| 2464 | DIR * | 2840 | DIR * |
| 2465 | opendir (char *filename) | 2841 | opendir (const char *filename) |
| 2466 | { | 2842 | { |
| 2467 | DIR *dirp; | 2843 | DIR *dirp; |
| 2468 | 2844 | ||
| @@ -2535,11 +2911,23 @@ readdir (DIR *dirp) | |||
| 2535 | { | 2911 | { |
| 2536 | char filename[MAXNAMLEN + 3]; | 2912 | char filename[MAXNAMLEN + 3]; |
| 2537 | int ln; | 2913 | int ln; |
| 2914 | int dbcs_p = max_filename_mbslen () > 1; | ||
| 2538 | 2915 | ||
| 2539 | strcpy (filename, dir_pathname); | 2916 | strcpy (filename, dir_pathname); |
| 2540 | ln = strlen (filename) - 1; | 2917 | ln = strlen (filename) - 1; |
| 2541 | if (!IS_DIRECTORY_SEP (filename[ln])) | 2918 | if (!dbcs_p) |
| 2542 | strcat (filename, "\\"); | 2919 | { |
| 2920 | if (!IS_DIRECTORY_SEP (filename[ln])) | ||
| 2921 | strcat (filename, "\\"); | ||
| 2922 | } | ||
| 2923 | else | ||
| 2924 | { | ||
| 2925 | char *end = filename + ln + 1; | ||
| 2926 | char *last_char = CharPrevExA (file_name_codepage, filename, end, 0); | ||
| 2927 | |||
| 2928 | if (!IS_DIRECTORY_SEP (*last_char)) | ||
| 2929 | strcat (filename, "\\"); | ||
| 2930 | } | ||
| 2543 | strcat (filename, "*"); | 2931 | strcat (filename, "*"); |
| 2544 | 2932 | ||
| 2545 | /* Note: No need to resolve symlinks in FILENAME, because | 2933 | /* Note: No need to resolve symlinks in FILENAME, because |
| @@ -2590,15 +2978,22 @@ readdir (DIR *dirp) | |||
| 2590 | strcpy (dir_static.d_name, dir_find_data.cFileName); | 2978 | strcpy (dir_static.d_name, dir_find_data.cFileName); |
| 2591 | dir_static.d_namlen = strlen (dir_static.d_name); | 2979 | dir_static.d_namlen = strlen (dir_static.d_name); |
| 2592 | if (dir_is_fat) | 2980 | if (dir_is_fat) |
| 2593 | _strlwr (dir_static.d_name); | 2981 | _mbslwr (dir_static.d_name); |
| 2594 | else if (downcase) | 2982 | else if (downcase) |
| 2595 | { | 2983 | { |
| 2596 | register char *p; | 2984 | register char *p; |
| 2597 | for (p = dir_static.d_name; *p; p++) | 2985 | int dbcs_p = max_filename_mbslen () > 1; |
| 2598 | if (*p >= 'a' && *p <= 'z') | 2986 | for (p = dir_static.d_name; *p; ) |
| 2599 | break; | 2987 | { |
| 2988 | if (*p >= 'a' && *p <= 'z') | ||
| 2989 | break; | ||
| 2990 | if (dbcs_p) | ||
| 2991 | p = CharNextExA (file_name_codepage, p, 0); | ||
| 2992 | else | ||
| 2993 | p++; | ||
| 2994 | } | ||
| 2600 | if (!*p) | 2995 | if (!*p) |
| 2601 | _strlwr (dir_static.d_name); | 2996 | _mbslwr (dir_static.d_name); |
| 2602 | } | 2997 | } |
| 2603 | 2998 | ||
| 2604 | return &dir_static; | 2999 | return &dir_static; |
| @@ -2637,6 +3032,7 @@ read_unc_volume (HANDLE henum, char *readbuf, int size) | |||
| 2637 | DWORD bufsize = 512; | 3032 | DWORD bufsize = 512; |
| 2638 | char *buffer; | 3033 | char *buffer; |
| 2639 | char *ptr; | 3034 | char *ptr; |
| 3035 | int dbcs_p = max_filename_mbslen () > 1; | ||
| 2640 | 3036 | ||
| 2641 | count = 1; | 3037 | count = 1; |
| 2642 | buffer = alloca (bufsize); | 3038 | buffer = alloca (bufsize); |
| @@ -2647,7 +3043,13 @@ read_unc_volume (HANDLE henum, char *readbuf, int size) | |||
| 2647 | /* WNetEnumResource returns \\resource\share...skip forward to "share". */ | 3043 | /* WNetEnumResource returns \\resource\share...skip forward to "share". */ |
| 2648 | ptr = ((LPNETRESOURCE) buffer)->lpRemoteName; | 3044 | ptr = ((LPNETRESOURCE) buffer)->lpRemoteName; |
| 2649 | ptr += 2; | 3045 | ptr += 2; |
| 2650 | while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++; | 3046 | if (!dbcs_p) |
| 3047 | while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++; | ||
| 3048 | else | ||
| 3049 | { | ||
| 3050 | while (*ptr && !IS_DIRECTORY_SEP (*ptr)) | ||
| 3051 | ptr = CharNextExA (file_name_codepage, ptr, 0); | ||
| 3052 | } | ||
| 2651 | ptr++; | 3053 | ptr++; |
| 2652 | 3054 | ||
| 2653 | strncpy (readbuf, ptr, size); | 3055 | strncpy (readbuf, ptr, size); |
| @@ -2684,9 +3086,11 @@ logon_network_drive (const char *path) | |||
| 2684 | { | 3086 | { |
| 2685 | NETRESOURCE resource; | 3087 | NETRESOURCE resource; |
| 2686 | char share[MAX_PATH]; | 3088 | char share[MAX_PATH]; |
| 2687 | int i, n_slashes; | 3089 | int n_slashes; |
| 2688 | char drive[4]; | 3090 | char drive[4]; |
| 2689 | UINT drvtype; | 3091 | UINT drvtype; |
| 3092 | char *p; | ||
| 3093 | int dbcs_p; | ||
| 2690 | 3094 | ||
| 2691 | if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1])) | 3095 | if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1])) |
| 2692 | drvtype = DRIVE_REMOTE; | 3096 | drvtype = DRIVE_REMOTE; |
| @@ -2708,13 +3112,18 @@ logon_network_drive (const char *path) | |||
| 2708 | n_slashes = 2; | 3112 | n_slashes = 2; |
| 2709 | strncpy (share, path, MAX_PATH); | 3113 | strncpy (share, path, MAX_PATH); |
| 2710 | /* Truncate to just server and share name. */ | 3114 | /* Truncate to just server and share name. */ |
| 2711 | for (i = 2; i < MAX_PATH; i++) | 3115 | dbcs_p = max_filename_mbslen () > 1; |
| 3116 | for (p = share + 2; *p && p < share + MAX_PATH; ) | ||
| 2712 | { | 3117 | { |
| 2713 | if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3) | 3118 | if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3) |
| 2714 | { | 3119 | { |
| 2715 | share[i] = '\0'; | 3120 | *p = '\0'; |
| 2716 | break; | 3121 | break; |
| 2717 | } | 3122 | } |
| 3123 | if (dbcs_p) | ||
| 3124 | p = CharNextExA (file_name_codepage, p, 0); | ||
| 3125 | else | ||
| 3126 | p++; | ||
| 2718 | } | 3127 | } |
| 2719 | 3128 | ||
| 2720 | resource.dwType = RESOURCETYPE_DISK; | 3129 | resource.dwType = RESOURCETYPE_DISK; |
| @@ -2817,14 +3226,6 @@ sys_chmod (const char * path, int mode) | |||
| 2817 | } | 3226 | } |
| 2818 | 3227 | ||
| 2819 | int | 3228 | int |
| 2820 | sys_chown (const char *path, uid_t owner, gid_t group) | ||
| 2821 | { | ||
| 2822 | if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */ | ||
| 2823 | return -1; | ||
| 2824 | return 0; | ||
| 2825 | } | ||
| 2826 | |||
| 2827 | int | ||
| 2828 | sys_creat (const char * path, int mode) | 3229 | sys_creat (const char * path, int mode) |
| 2829 | { | 3230 | { |
| 2830 | return _creat (map_w32_filename (path, NULL), mode); | 3231 | return _creat (map_w32_filename (path, NULL), mode); |
| @@ -3007,17 +3408,27 @@ int | |||
| 3007 | sys_open (const char * path, int oflag, int mode) | 3408 | sys_open (const char * path, int oflag, int mode) |
| 3008 | { | 3409 | { |
| 3009 | const char* mpath = map_w32_filename (path, NULL); | 3410 | const char* mpath = map_w32_filename (path, NULL); |
| 3010 | /* Try to open file without _O_CREAT, to be able to write to hidden | 3411 | int res = -1; |
| 3011 | and system files. Force all file handles to be | 3412 | |
| 3012 | non-inheritable. */ | 3413 | /* If possible, try to open file without _O_CREAT, to be able to |
| 3013 | int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode); | 3414 | write to existing hidden and system files. Force all file |
| 3014 | if (res >= 0) | 3415 | handles to be non-inheritable. */ |
| 3015 | return res; | 3416 | if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL)) |
| 3016 | return _open (mpath, oflag | _O_NOINHERIT, mode); | 3417 | res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode); |
| 3418 | if (res < 0) | ||
| 3419 | res = _open (mpath, oflag | _O_NOINHERIT, mode); | ||
| 3420 | |||
| 3421 | return res; | ||
| 3017 | } | 3422 | } |
| 3018 | 3423 | ||
| 3019 | int | 3424 | int |
| 3020 | sys_rename (const char * oldname, const char * newname) | 3425 | fchmod (int fd, mode_t mode) |
| 3426 | { | ||
| 3427 | return 0; | ||
| 3428 | } | ||
| 3429 | |||
| 3430 | int | ||
| 3431 | sys_rename_replace (const char *oldname, const char *newname, BOOL force) | ||
| 3021 | { | 3432 | { |
| 3022 | BOOL result; | 3433 | BOOL result; |
| 3023 | char temp[MAX_PATH]; | 3434 | char temp[MAX_PATH]; |
| @@ -3073,7 +3484,7 @@ sys_rename (const char * oldname, const char * newname) | |||
| 3073 | return -1; | 3484 | return -1; |
| 3074 | } | 3485 | } |
| 3075 | 3486 | ||
| 3076 | /* Emulate Unix behavior - newname is deleted if it already exists | 3487 | /* If FORCE, emulate Unix behavior - newname is deleted if it already exists |
| 3077 | (at least if it is a file; don't do this for directories). | 3488 | (at least if it is a file; don't do this for directories). |
| 3078 | 3489 | ||
| 3079 | Since we mustn't do this if we are just changing the case of the | 3490 | Since we mustn't do this if we are just changing the case of the |
| @@ -3091,7 +3502,7 @@ sys_rename (const char * oldname, const char * newname) | |||
| 3091 | 3502 | ||
| 3092 | result = rename (temp, newname); | 3503 | result = rename (temp, newname); |
| 3093 | 3504 | ||
| 3094 | if (result < 0) | 3505 | if (result < 0 && force) |
| 3095 | { | 3506 | { |
| 3096 | DWORD w32err = GetLastError (); | 3507 | DWORD w32err = GetLastError (); |
| 3097 | 3508 | ||
| @@ -3131,6 +3542,12 @@ sys_rename (const char * oldname, const char * newname) | |||
| 3131 | } | 3542 | } |
| 3132 | 3543 | ||
| 3133 | int | 3544 | int |
| 3545 | sys_rename (char const *old, char const *new) | ||
| 3546 | { | ||
| 3547 | return sys_rename_replace (old, new, TRUE); | ||
| 3548 | } | ||
| 3549 | |||
| 3550 | int | ||
| 3134 | sys_rmdir (const char * path) | 3551 | sys_rmdir (const char * path) |
| 3135 | { | 3552 | { |
| 3136 | return _rmdir (map_w32_filename (path, NULL)); | 3553 | return _rmdir (map_w32_filename (path, NULL)); |
| @@ -3375,18 +3792,15 @@ w32_add_to_cache (PSID sid, unsigned id, char *name) | |||
| 3375 | #define GID 2 | 3792 | #define GID 2 |
| 3376 | 3793 | ||
| 3377 | static int | 3794 | static int |
| 3378 | get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname, | 3795 | get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what) |
| 3379 | unsigned *id, char *nm, int what) | ||
| 3380 | { | 3796 | { |
| 3381 | PSID sid = NULL; | 3797 | PSID sid = NULL; |
| 3382 | char machine[MAX_COMPUTERNAME_LENGTH+1]; | ||
| 3383 | BOOL dflt; | 3798 | BOOL dflt; |
| 3384 | SID_NAME_USE ignore; | 3799 | SID_NAME_USE ignore; |
| 3385 | char name[UNLEN+1]; | 3800 | char name[UNLEN+1]; |
| 3386 | DWORD name_len = sizeof (name); | 3801 | DWORD name_len = sizeof (name); |
| 3387 | char domain[1024]; | 3802 | char domain[1024]; |
| 3388 | DWORD domain_len = sizeof (domain); | 3803 | DWORD domain_len = sizeof (domain); |
| 3389 | char *mp = NULL; | ||
| 3390 | int use_dflt = 0; | 3804 | int use_dflt = 0; |
| 3391 | int result; | 3805 | int result; |
| 3392 | 3806 | ||
| @@ -3401,22 +3815,7 @@ get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname, | |||
| 3401 | use_dflt = 1; | 3815 | use_dflt = 1; |
| 3402 | else if (!w32_cached_id (sid, id, nm)) | 3816 | else if (!w32_cached_id (sid, id, nm)) |
| 3403 | { | 3817 | { |
| 3404 | /* If FNAME is a UNC, we need to lookup account on the | 3818 | if (!lookup_account_sid (NULL, sid, name, &name_len, |
| 3405 | specified machine. */ | ||
| 3406 | if (IS_DIRECTORY_SEP (fname[0]) && IS_DIRECTORY_SEP (fname[1]) | ||
| 3407 | && fname[2] != '\0') | ||
| 3408 | { | ||
| 3409 | const char *s; | ||
| 3410 | char *p; | ||
| 3411 | |||
| 3412 | for (s = fname + 2, p = machine; | ||
| 3413 | *s && !IS_DIRECTORY_SEP (*s); s++, p++) | ||
| 3414 | *p = *s; | ||
| 3415 | *p = '\0'; | ||
| 3416 | mp = machine; | ||
| 3417 | } | ||
| 3418 | |||
| 3419 | if (!lookup_account_sid (mp, sid, name, &name_len, | ||
| 3420 | domain, &domain_len, &ignore) | 3819 | domain, &domain_len, &ignore) |
| 3421 | || name_len > UNLEN+1) | 3820 | || name_len > UNLEN+1) |
| 3422 | use_dflt = 1; | 3821 | use_dflt = 1; |
| @@ -3431,9 +3830,7 @@ get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname, | |||
| 3431 | } | 3830 | } |
| 3432 | 3831 | ||
| 3433 | static void | 3832 | static void |
| 3434 | get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, | 3833 | get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st) |
| 3435 | const char *fname, | ||
| 3436 | struct stat *st) | ||
| 3437 | { | 3834 | { |
| 3438 | int dflt_usr = 0, dflt_grp = 0; | 3835 | int dflt_usr = 0, dflt_grp = 0; |
| 3439 | 3836 | ||
| @@ -3444,9 +3841,9 @@ get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, | |||
| 3444 | } | 3841 | } |
| 3445 | else | 3842 | else |
| 3446 | { | 3843 | { |
| 3447 | if (get_name_and_id (psd, fname, &st->st_uid, st->st_uname, UID)) | 3844 | if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID)) |
| 3448 | dflt_usr = 1; | 3845 | dflt_usr = 1; |
| 3449 | if (get_name_and_id (psd, fname, &st->st_gid, st->st_gname, GID)) | 3846 | if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID)) |
| 3450 | dflt_grp = 1; | 3847 | dflt_grp = 1; |
| 3451 | } | 3848 | } |
| 3452 | /* Consider files to belong to current user/group, if we cannot get | 3849 | /* Consider files to belong to current user/group, if we cannot get |
| @@ -3485,6 +3882,10 @@ is_slow_fs (const char *name) | |||
| 3485 | return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK); | 3882 | return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK); |
| 3486 | } | 3883 | } |
| 3487 | 3884 | ||
| 3885 | /* If this is non-zero, the caller wants accurate information about | ||
| 3886 | file's owner and group, which could be expensive to get. */ | ||
| 3887 | int w32_stat_get_owner_group; | ||
| 3888 | |||
| 3488 | /* MSVC stat function can't cope with UNC names and has other bugs, so | 3889 | /* MSVC stat function can't cope with UNC names and has other bugs, so |
| 3489 | replace it with our own. This also allows us to calculate consistent | 3890 | replace it with our own. This also allows us to calculate consistent |
| 3490 | inode values and owner/group without hacks in the main Emacs code. */ | 3891 | inode values and owner/group without hacks in the main Emacs code. */ |
| @@ -3505,6 +3906,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) | |||
| 3505 | DWORD access_rights = 0; | 3906 | DWORD access_rights = 0; |
| 3506 | DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1; | 3907 | DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1; |
| 3507 | FILETIME ctime, atime, wtime; | 3908 | FILETIME ctime, atime, wtime; |
| 3909 | int dbcs_p; | ||
| 3508 | 3910 | ||
| 3509 | if (path == NULL || buf == NULL) | 3911 | if (path == NULL || buf == NULL) |
| 3510 | { | 3912 | { |
| @@ -3656,6 +4058,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) | |||
| 3656 | /* We produce the fallback owner and group data, based on the | 4058 | /* We produce the fallback owner and group data, based on the |
| 3657 | current user that runs Emacs, in the following cases: | 4059 | current user that runs Emacs, in the following cases: |
| 3658 | 4060 | ||
| 4061 | . caller didn't request owner and group info | ||
| 3659 | . this is Windows 9X | 4062 | . this is Windows 9X |
| 3660 | . getting security by handle failed, and we need to produce | 4063 | . getting security by handle failed, and we need to produce |
| 3661 | information for the target of a symlink (this is better | 4064 | information for the target of a symlink (this is better |
| @@ -3664,23 +4067,25 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) | |||
| 3664 | 4067 | ||
| 3665 | If getting security by handle fails, and we don't need to | 4068 | If getting security by handle fails, and we don't need to |
| 3666 | resolve symlinks, we try getting security by name. */ | 4069 | resolve symlinks, we try getting security by name. */ |
| 3667 | if (is_windows_9x () != TRUE) | 4070 | if (!w32_stat_get_owner_group || is_windows_9x () == TRUE) |
| 3668 | psd = get_file_security_desc_by_handle (fh); | 4071 | get_file_owner_and_group (NULL, buf); |
| 3669 | if (psd) | 4072 | else |
| 3670 | { | ||
| 3671 | get_file_owner_and_group (psd, name, buf); | ||
| 3672 | LocalFree (psd); | ||
| 3673 | } | ||
| 3674 | else if (is_windows_9x () == TRUE) | ||
| 3675 | get_file_owner_and_group (NULL, name, buf); | ||
| 3676 | else if (!(is_a_symlink && follow_symlinks)) | ||
| 3677 | { | 4073 | { |
| 3678 | psd = get_file_security_desc_by_name (name); | 4074 | psd = get_file_security_desc_by_handle (fh); |
| 3679 | get_file_owner_and_group (psd, name, buf); | 4075 | if (psd) |
| 3680 | xfree (psd); | 4076 | { |
| 4077 | get_file_owner_and_group (psd, buf); | ||
| 4078 | LocalFree (psd); | ||
| 4079 | } | ||
| 4080 | else if (!(is_a_symlink && follow_symlinks)) | ||
| 4081 | { | ||
| 4082 | psd = get_file_security_desc_by_name (name); | ||
| 4083 | get_file_owner_and_group (psd, buf); | ||
| 4084 | xfree (psd); | ||
| 4085 | } | ||
| 4086 | else | ||
| 4087 | get_file_owner_and_group (NULL, buf); | ||
| 3681 | } | 4088 | } |
| 3682 | else | ||
| 3683 | get_file_owner_and_group (NULL, name, buf); | ||
| 3684 | CloseHandle (fh); | 4089 | CloseHandle (fh); |
| 3685 | } | 4090 | } |
| 3686 | else | 4091 | else |
| @@ -3699,6 +4104,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) | |||
| 3699 | did not ask for extra precision, resolving symlinks will fly | 4104 | did not ask for extra precision, resolving symlinks will fly |
| 3700 | in the face of that request, since the user then wants the | 4105 | in the face of that request, since the user then wants the |
| 3701 | lightweight version of the code. */ | 4106 | lightweight version of the code. */ |
| 4107 | dbcs_p = max_filename_mbslen () > 1; | ||
| 3702 | rootdir = (path >= save_name + len - 1 | 4108 | rootdir = (path >= save_name + len - 1 |
| 3703 | && (IS_DIRECTORY_SEP (*path) || *path == 0)); | 4109 | && (IS_DIRECTORY_SEP (*path) || *path == 0)); |
| 3704 | 4110 | ||
| @@ -3726,8 +4132,19 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) | |||
| 3726 | } | 4132 | } |
| 3727 | else if (rootdir) | 4133 | else if (rootdir) |
| 3728 | { | 4134 | { |
| 3729 | if (!IS_DIRECTORY_SEP (name[len-1])) | 4135 | if (!dbcs_p) |
| 3730 | strcat (name, "\\"); | 4136 | { |
| 4137 | if (!IS_DIRECTORY_SEP (name[len-1])) | ||
| 4138 | strcat (name, "\\"); | ||
| 4139 | } | ||
| 4140 | else | ||
| 4141 | { | ||
| 4142 | char *end = name + len; | ||
| 4143 | char *n = CharPrevExA (file_name_codepage, name, end, 0); | ||
| 4144 | |||
| 4145 | if (!IS_DIRECTORY_SEP (*n)) | ||
| 4146 | strcat (name, "\\"); | ||
| 4147 | } | ||
| 3731 | if (GetDriveType (name) < 2) | 4148 | if (GetDriveType (name) < 2) |
| 3732 | { | 4149 | { |
| 3733 | errno = ENOENT; | 4150 | errno = ENOENT; |
| @@ -3739,15 +4156,37 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) | |||
| 3739 | } | 4156 | } |
| 3740 | else | 4157 | else |
| 3741 | { | 4158 | { |
| 3742 | if (IS_DIRECTORY_SEP (name[len-1])) | 4159 | if (!dbcs_p) |
| 3743 | name[len - 1] = 0; | 4160 | { |
| 4161 | if (IS_DIRECTORY_SEP (name[len-1])) | ||
| 4162 | name[len - 1] = 0; | ||
| 4163 | } | ||
| 4164 | else | ||
| 4165 | { | ||
| 4166 | char *end = name + len; | ||
| 4167 | char *n = CharPrevExA (file_name_codepage, name, end, 0); | ||
| 4168 | |||
| 4169 | if (IS_DIRECTORY_SEP (*n)) | ||
| 4170 | *n = 0; | ||
| 4171 | } | ||
| 3744 | 4172 | ||
| 3745 | /* (This is hacky, but helps when doing file completions on | 4173 | /* (This is hacky, but helps when doing file completions on |
| 3746 | network drives.) Optimize by using information available from | 4174 | network drives.) Optimize by using information available from |
| 3747 | active readdir if possible. */ | 4175 | active readdir if possible. */ |
| 3748 | len = strlen (dir_pathname); | 4176 | len = strlen (dir_pathname); |
| 3749 | if (IS_DIRECTORY_SEP (dir_pathname[len-1])) | 4177 | if (!dbcs_p) |
| 3750 | len--; | 4178 | { |
| 4179 | if (IS_DIRECTORY_SEP (dir_pathname[len-1])) | ||
| 4180 | len--; | ||
| 4181 | } | ||
| 4182 | else | ||
| 4183 | { | ||
| 4184 | char *end = dir_pathname + len; | ||
| 4185 | char *n = CharPrevExA (file_name_codepage, dir_pathname, end, 0); | ||
| 4186 | |||
| 4187 | if (IS_DIRECTORY_SEP (*n)) | ||
| 4188 | len--; | ||
| 4189 | } | ||
| 3751 | if (dir_find_handle != INVALID_HANDLE_VALUE | 4190 | if (dir_find_handle != INVALID_HANDLE_VALUE |
| 3752 | && !(is_a_symlink && follow_symlinks) | 4191 | && !(is_a_symlink && follow_symlinks) |
| 3753 | && strnicmp (save_name, dir_pathname, len) == 0 | 4192 | && strnicmp (save_name, dir_pathname, len) == 0 |
| @@ -3788,7 +4227,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) | |||
| 3788 | else | 4227 | else |
| 3789 | buf->st_mode = S_IFREG; | 4228 | buf->st_mode = S_IFREG; |
| 3790 | 4229 | ||
| 3791 | get_file_owner_and_group (NULL, name, buf); | 4230 | get_file_owner_and_group (NULL, buf); |
| 3792 | } | 4231 | } |
| 3793 | 4232 | ||
| 3794 | #if 0 | 4233 | #if 0 |
| @@ -3853,6 +4292,30 @@ lstat (const char * path, struct stat * buf) | |||
| 3853 | return stat_worker (path, buf, 0); | 4292 | return stat_worker (path, buf, 0); |
| 3854 | } | 4293 | } |
| 3855 | 4294 | ||
| 4295 | int | ||
| 4296 | fstatat (int fd, char const *name, struct stat *st, int flags) | ||
| 4297 | { | ||
| 4298 | /* Rely on a hack: an open directory is modeled as file descriptor 0. | ||
| 4299 | This is good enough for the current usage in Emacs, but is fragile. | ||
| 4300 | |||
| 4301 | FIXME: Add proper support for fdopendir, fstatat, readlinkat. | ||
| 4302 | Gnulib does this and can serve as a model. */ | ||
| 4303 | char fullname[MAX_PATH]; | ||
| 4304 | |||
| 4305 | if (fd != AT_FDCWD) | ||
| 4306 | { | ||
| 4307 | if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name) | ||
| 4308 | < 0) | ||
| 4309 | { | ||
| 4310 | errno = ENAMETOOLONG; | ||
| 4311 | return -1; | ||
| 4312 | } | ||
| 4313 | name = fullname; | ||
| 4314 | } | ||
| 4315 | |||
| 4316 | return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW)); | ||
| 4317 | } | ||
| 4318 | |||
| 3856 | /* Provide fstat and utime as well as stat for consistent handling of | 4319 | /* Provide fstat and utime as well as stat for consistent handling of |
| 3857 | file timestamps. */ | 4320 | file timestamps. */ |
| 3858 | int | 4321 | int |
| @@ -3907,13 +4370,23 @@ fstat (int desc, struct stat * buf) | |||
| 3907 | else | 4370 | else |
| 3908 | buf->st_ino = fake_inode; | 4371 | buf->st_ino = fake_inode; |
| 3909 | 4372 | ||
| 3910 | /* Consider files to belong to current user. | 4373 | /* If the caller so requested, get the true file owner and group. |
| 3911 | FIXME: this should use GetSecurityInfo API, but it is only | 4374 | Otherwise, consider the file to belong to the current user. */ |
| 3912 | available for _WIN32_WINNT >= 0x501. */ | 4375 | if (!w32_stat_get_owner_group || is_windows_9x () == TRUE) |
| 3913 | buf->st_uid = dflt_passwd.pw_uid; | 4376 | get_file_owner_and_group (NULL, buf); |
| 3914 | buf->st_gid = dflt_passwd.pw_gid; | 4377 | else |
| 3915 | strcpy (buf->st_uname, dflt_passwd.pw_name); | 4378 | { |
| 3916 | strcpy (buf->st_gname, dflt_group.gr_name); | 4379 | PSECURITY_DESCRIPTOR psd = NULL; |
| 4380 | |||
| 4381 | psd = get_file_security_desc_by_handle (fh); | ||
| 4382 | if (psd) | ||
| 4383 | { | ||
| 4384 | get_file_owner_and_group (psd, buf); | ||
| 4385 | LocalFree (psd); | ||
| 4386 | } | ||
| 4387 | else | ||
| 4388 | get_file_owner_and_group (NULL, buf); | ||
| 4389 | } | ||
| 3917 | 4390 | ||
| 3918 | buf->st_dev = info.dwVolumeSerialNumber; | 4391 | buf->st_dev = info.dwVolumeSerialNumber; |
| 3919 | buf->st_rdev = info.dwVolumeSerialNumber; | 4392 | buf->st_rdev = info.dwVolumeSerialNumber; |
| @@ -4008,6 +4481,7 @@ symlink (char const *filename, char const *linkname) | |||
| 4008 | char linkfn[MAX_PATH], *tgtfn; | 4481 | char linkfn[MAX_PATH], *tgtfn; |
| 4009 | DWORD flags = 0; | 4482 | DWORD flags = 0; |
| 4010 | int dir_access, filename_ends_in_slash; | 4483 | int dir_access, filename_ends_in_slash; |
| 4484 | int dbcs_p; | ||
| 4011 | 4485 | ||
| 4012 | /* Diagnostics follows Posix as much as possible. */ | 4486 | /* Diagnostics follows Posix as much as possible. */ |
| 4013 | if (filename == NULL || linkname == NULL) | 4487 | if (filename == NULL || linkname == NULL) |
| @@ -4033,6 +4507,8 @@ symlink (char const *filename, char const *linkname) | |||
| 4033 | return -1; | 4507 | return -1; |
| 4034 | } | 4508 | } |
| 4035 | 4509 | ||
| 4510 | dbcs_p = max_filename_mbslen () > 1; | ||
| 4511 | |||
| 4036 | /* Note: since empty FILENAME was already rejected, we can safely | 4512 | /* Note: since empty FILENAME was already rejected, we can safely |
| 4037 | refer to FILENAME[1]. */ | 4513 | refer to FILENAME[1]. */ |
| 4038 | if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1]))) | 4514 | if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1]))) |
| @@ -4047,8 +4523,21 @@ symlink (char const *filename, char const *linkname) | |||
| 4047 | char tem[MAX_PATH]; | 4523 | char tem[MAX_PATH]; |
| 4048 | char *p = linkfn + strlen (linkfn); | 4524 | char *p = linkfn + strlen (linkfn); |
| 4049 | 4525 | ||
| 4050 | while (p > linkfn && !IS_ANY_SEP (p[-1])) | 4526 | if (!dbcs_p) |
| 4051 | p--; | 4527 | { |
| 4528 | while (p > linkfn && !IS_ANY_SEP (p[-1])) | ||
| 4529 | p--; | ||
| 4530 | } | ||
| 4531 | else | ||
| 4532 | { | ||
| 4533 | char *p1 = CharPrevExA (file_name_codepage, linkfn, p, 0); | ||
| 4534 | |||
| 4535 | while (p > linkfn && !IS_ANY_SEP (*p1)) | ||
| 4536 | { | ||
| 4537 | p = p1; | ||
| 4538 | p1 = CharPrevExA (file_name_codepage, linkfn, p1, 0); | ||
| 4539 | } | ||
| 4540 | } | ||
| 4052 | if (p > linkfn) | 4541 | if (p > linkfn) |
| 4053 | strncpy (tem, linkfn, p - linkfn); | 4542 | strncpy (tem, linkfn, p - linkfn); |
| 4054 | tem[p - linkfn] = '\0'; | 4543 | tem[p - linkfn] = '\0'; |
| @@ -4063,7 +4552,15 @@ symlink (char const *filename, char const *linkname) | |||
| 4063 | exist, but ends in a slash, we create a symlink to directory. If | 4552 | exist, but ends in a slash, we create a symlink to directory. If |
| 4064 | FILENAME exists and is a directory, we always create a symlink to | 4553 | FILENAME exists and is a directory, we always create a symlink to |
| 4065 | directory. */ | 4554 | directory. */ |
| 4066 | filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]); | 4555 | if (!dbcs_p) |
| 4556 | filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]); | ||
| 4557 | else | ||
| 4558 | { | ||
| 4559 | const char *end = filename + strlen (filename); | ||
| 4560 | const char *n = CharPrevExA (file_name_codepage, filename, end, 0); | ||
| 4561 | |||
| 4562 | filename_ends_in_slash = IS_DIRECTORY_SEP (*n); | ||
| 4563 | } | ||
| 4067 | if (dir_access == 0 || filename_ends_in_slash) | 4564 | if (dir_access == 0 || filename_ends_in_slash) |
| 4068 | flags = SYMBOLIC_LINK_FLAG_DIRECTORY; | 4565 | flags = SYMBOLIC_LINK_FLAG_DIRECTORY; |
| 4069 | 4566 | ||
| @@ -4242,7 +4739,7 @@ readlink (const char *name, char *buf, size_t buf_size) | |||
| 4242 | errno = EINVAL; | 4739 | errno = EINVAL; |
| 4243 | else | 4740 | else |
| 4244 | { | 4741 | { |
| 4245 | /* Copy the link target name, in wide characters, fro | 4742 | /* Copy the link target name, in wide characters, from |
| 4246 | reparse_data, then convert it to multibyte encoding in | 4743 | reparse_data, then convert it to multibyte encoding in |
| 4247 | the current locale's codepage. */ | 4744 | the current locale's codepage. */ |
| 4248 | WCHAR *lwname; | 4745 | WCHAR *lwname; |
| @@ -4253,6 +4750,8 @@ readlink (const char *name, char *buf, size_t buf_size) | |||
| 4253 | WCHAR *lwname_src = | 4750 | WCHAR *lwname_src = |
| 4254 | reparse_data->SymbolicLinkReparseBuffer.PathBuffer | 4751 | reparse_data->SymbolicLinkReparseBuffer.PathBuffer |
| 4255 | + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR); | 4752 | + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR); |
| 4753 | /* This updates file_name_codepage which we need below. */ | ||
| 4754 | int dbcs_p = max_filename_mbslen () > 1; | ||
| 4256 | 4755 | ||
| 4257 | /* According to MSDN, PrintNameLength does not include the | 4756 | /* According to MSDN, PrintNameLength does not include the |
| 4258 | terminating null character. */ | 4757 | terminating null character. */ |
| @@ -4260,9 +4759,7 @@ readlink (const char *name, char *buf, size_t buf_size) | |||
| 4260 | memcpy (lwname, lwname_src, lwname_len); | 4759 | memcpy (lwname, lwname_src, lwname_len); |
| 4261 | lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */ | 4760 | lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */ |
| 4262 | 4761 | ||
| 4263 | /* FIXME: Should we use the current file-name coding system | 4762 | lname_len = WideCharToMultiByte (file_name_codepage, 0, lwname, -1, |
| 4264 | instead of the fixed value of the ANSI codepage? */ | ||
| 4265 | lname_len = WideCharToMultiByte (w32_ansi_code_page, 0, lwname, -1, | ||
| 4266 | lname, MAX_PATH, NULL, NULL); | 4763 | lname, MAX_PATH, NULL, NULL); |
| 4267 | if (!lname_len) | 4764 | if (!lname_len) |
| 4268 | { | 4765 | { |
| @@ -4288,18 +4785,33 @@ readlink (const char *name, char *buf, size_t buf_size) | |||
| 4288 | else | 4785 | else |
| 4289 | { | 4786 | { |
| 4290 | size_t size_to_copy = buf_size; | 4787 | size_t size_to_copy = buf_size; |
| 4291 | BYTE *p = lname; | 4788 | BYTE *p = lname, *p2; |
| 4292 | BYTE *pend = p + lname_len; | 4789 | BYTE *pend = p + lname_len; |
| 4293 | 4790 | ||
| 4294 | /* Normalize like dostounix_filename does, but we don't | 4791 | /* Normalize like dostounix_filename does, but we don't |
| 4295 | want to assume that lname is null-terminated. */ | 4792 | want to assume that lname is null-terminated. */ |
| 4296 | if (*p && p[1] == ':' && *p >= 'A' && *p <= 'Z') | 4793 | if (dbcs_p) |
| 4297 | *p += 'a' - 'A'; | 4794 | p2 = CharNextExA (file_name_codepage, p, 0); |
| 4795 | else | ||
| 4796 | p2 = p + 1; | ||
| 4797 | if (*p && *p2 == ':' && *p >= 'A' && *p <= 'Z') | ||
| 4798 | { | ||
| 4799 | *p += 'a' - 'A'; | ||
| 4800 | p += 2; | ||
| 4801 | } | ||
| 4298 | while (p <= pend) | 4802 | while (p <= pend) |
| 4299 | { | 4803 | { |
| 4300 | if (*p == '\\') | 4804 | if (*p == '\\') |
| 4301 | *p = '/'; | 4805 | *p = '/'; |
| 4302 | ++p; | 4806 | if (dbcs_p) |
| 4807 | { | ||
| 4808 | p = CharNextExA (file_name_codepage, p, 0); | ||
| 4809 | /* CharNextExA doesn't advance at null character. */ | ||
| 4810 | if (!*p) | ||
| 4811 | break; | ||
| 4812 | } | ||
| 4813 | else | ||
| 4814 | ++p; | ||
| 4303 | } | 4815 | } |
| 4304 | /* Testing for null-terminated LNAME is paranoia: | 4816 | /* Testing for null-terminated LNAME is paranoia: |
| 4305 | WideCharToMultiByte should always return a | 4817 | WideCharToMultiByte should always return a |
| @@ -4346,6 +4858,28 @@ readlink (const char *name, char *buf, size_t buf_size) | |||
| 4346 | return retval; | 4858 | return retval; |
| 4347 | } | 4859 | } |
| 4348 | 4860 | ||
| 4861 | ssize_t | ||
| 4862 | readlinkat (int fd, char const *name, char *buffer, | ||
| 4863 | size_t buffer_size) | ||
| 4864 | { | ||
| 4865 | /* Rely on a hack: an open directory is modeled as file descriptor 0, | ||
| 4866 | as in fstatat. FIXME: Add proper support for readlinkat. */ | ||
| 4867 | char fullname[MAX_PATH]; | ||
| 4868 | |||
| 4869 | if (fd != AT_FDCWD) | ||
| 4870 | { | ||
| 4871 | if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name) | ||
| 4872 | < 0) | ||
| 4873 | { | ||
| 4874 | errno = ENAMETOOLONG; | ||
| 4875 | return -1; | ||
| 4876 | } | ||
| 4877 | name = fullname; | ||
| 4878 | } | ||
| 4879 | |||
| 4880 | return readlink (name, buffer, buffer_size); | ||
| 4881 | } | ||
| 4882 | |||
| 4349 | /* If FILE is a symlink, return its target (stored in a static | 4883 | /* If FILE is a symlink, return its target (stored in a static |
| 4350 | buffer); otherwise return FILE. | 4884 | buffer); otherwise return FILE. |
| 4351 | 4885 | ||
| @@ -4373,6 +4907,7 @@ chase_symlinks (const char *file) | |||
| 4373 | char link[MAX_PATH]; | 4907 | char link[MAX_PATH]; |
| 4374 | ssize_t res, link_len; | 4908 | ssize_t res, link_len; |
| 4375 | int loop_count = 0; | 4909 | int loop_count = 0; |
| 4910 | int dbcs_p; | ||
| 4376 | 4911 | ||
| 4377 | if (is_windows_9x () == TRUE || !is_symlink (file)) | 4912 | if (is_windows_9x () == TRUE || !is_symlink (file)) |
| 4378 | return (char *)file; | 4913 | return (char *)file; |
| @@ -4380,13 +4915,27 @@ chase_symlinks (const char *file) | |||
| 4380 | if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0) | 4915 | if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0) |
| 4381 | return (char *)file; | 4916 | return (char *)file; |
| 4382 | 4917 | ||
| 4918 | dbcs_p = max_filename_mbslen () > 1; | ||
| 4383 | target[0] = '\0'; | 4919 | target[0] = '\0'; |
| 4384 | do { | 4920 | do { |
| 4385 | 4921 | ||
| 4386 | /* Remove trailing slashes, as we want to resolve the last | 4922 | /* Remove trailing slashes, as we want to resolve the last |
| 4387 | non-trivial part of the link name. */ | 4923 | non-trivial part of the link name. */ |
| 4388 | while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1])) | 4924 | if (!dbcs_p) |
| 4389 | link[link_len--] = '\0'; | 4925 | { |
| 4926 | while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1])) | ||
| 4927 | link[link_len--] = '\0'; | ||
| 4928 | } | ||
| 4929 | else if (link_len > 3) | ||
| 4930 | { | ||
| 4931 | char *n = CharPrevExA (file_name_codepage, link, link + link_len, 0); | ||
| 4932 | |||
| 4933 | while (n >= link + 2 && IS_DIRECTORY_SEP (*n)) | ||
| 4934 | { | ||
| 4935 | n[1] = '\0'; | ||
| 4936 | n = CharPrevExA (file_name_codepage, link, n, 0); | ||
| 4937 | } | ||
| 4938 | } | ||
| 4390 | 4939 | ||
| 4391 | res = readlink (link, target, MAX_PATH); | 4940 | res = readlink (link, target, MAX_PATH); |
| 4392 | if (res > 0) | 4941 | if (res > 0) |
| @@ -4399,8 +4948,21 @@ chase_symlinks (const char *file) | |||
| 4399 | the symlink, then copy the result back to target. */ | 4948 | the symlink, then copy the result back to target. */ |
| 4400 | char *p = link + link_len; | 4949 | char *p = link + link_len; |
| 4401 | 4950 | ||
| 4402 | while (p > link && !IS_ANY_SEP (p[-1])) | 4951 | if (!dbcs_p) |
| 4403 | p--; | 4952 | { |
| 4953 | while (p > link && !IS_ANY_SEP (p[-1])) | ||
| 4954 | p--; | ||
| 4955 | } | ||
| 4956 | else | ||
| 4957 | { | ||
| 4958 | char *p1 = CharPrevExA (file_name_codepage, link, p, 0); | ||
| 4959 | |||
| 4960 | while (p > link && !IS_ANY_SEP (*p1)) | ||
| 4961 | { | ||
| 4962 | p = p1; | ||
| 4963 | p1 = CharPrevExA (file_name_codepage, link, p1, 0); | ||
| 4964 | } | ||
| 4965 | } | ||
| 4404 | strcpy (p, target); | 4966 | strcpy (p, target); |
| 4405 | strcpy (target, link); | 4967 | strcpy (target, link); |
| 4406 | } | 4968 | } |
| @@ -4418,6 +4980,245 @@ chase_symlinks (const char *file) | |||
| 4418 | return target; | 4980 | return target; |
| 4419 | } | 4981 | } |
| 4420 | 4982 | ||
| 4983 | |||
| 4984 | /* Posix ACL emulation. */ | ||
| 4985 | |||
| 4986 | int | ||
| 4987 | acl_valid (acl_t acl) | ||
| 4988 | { | ||
| 4989 | return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1; | ||
| 4990 | } | ||
| 4991 | |||
| 4992 | char * | ||
| 4993 | acl_to_text (acl_t acl, ssize_t *size) | ||
| 4994 | { | ||
| 4995 | LPTSTR str_acl; | ||
| 4996 | SECURITY_INFORMATION flags = | ||
| 4997 | OWNER_SECURITY_INFORMATION | | ||
| 4998 | GROUP_SECURITY_INFORMATION | | ||
| 4999 | DACL_SECURITY_INFORMATION; | ||
| 5000 | char *retval = NULL; | ||
| 5001 | ULONG local_size; | ||
| 5002 | int e = errno; | ||
| 5003 | |||
| 5004 | errno = 0; | ||
| 5005 | |||
| 5006 | if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size)) | ||
| 5007 | { | ||
| 5008 | errno = e; | ||
| 5009 | /* We don't want to mix heaps, so we duplicate the string in our | ||
| 5010 | heap and free the one allocated by the API. */ | ||
| 5011 | retval = xstrdup (str_acl); | ||
| 5012 | if (size) | ||
| 5013 | *size = local_size; | ||
| 5014 | LocalFree (str_acl); | ||
| 5015 | } | ||
| 5016 | else if (errno != ENOTSUP) | ||
| 5017 | errno = EINVAL; | ||
| 5018 | |||
| 5019 | return retval; | ||
| 5020 | } | ||
| 5021 | |||
| 5022 | acl_t | ||
| 5023 | acl_from_text (const char *acl_str) | ||
| 5024 | { | ||
| 5025 | PSECURITY_DESCRIPTOR psd, retval = NULL; | ||
| 5026 | ULONG sd_size; | ||
| 5027 | int e = errno; | ||
| 5028 | |||
| 5029 | errno = 0; | ||
| 5030 | |||
| 5031 | if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size)) | ||
| 5032 | { | ||
| 5033 | errno = e; | ||
| 5034 | retval = xmalloc (sd_size); | ||
| 5035 | memcpy (retval, psd, sd_size); | ||
| 5036 | LocalFree (psd); | ||
| 5037 | } | ||
| 5038 | else if (errno != ENOTSUP) | ||
| 5039 | errno = EINVAL; | ||
| 5040 | |||
| 5041 | return retval; | ||
| 5042 | } | ||
| 5043 | |||
| 5044 | int | ||
| 5045 | acl_free (void *ptr) | ||
| 5046 | { | ||
| 5047 | xfree (ptr); | ||
| 5048 | return 0; | ||
| 5049 | } | ||
| 5050 | |||
| 5051 | acl_t | ||
| 5052 | acl_get_file (const char *fname, acl_type_t type) | ||
| 5053 | { | ||
| 5054 | PSECURITY_DESCRIPTOR psd = NULL; | ||
| 5055 | const char *filename; | ||
| 5056 | |||
| 5057 | if (type == ACL_TYPE_ACCESS) | ||
| 5058 | { | ||
| 5059 | DWORD sd_len, err; | ||
| 5060 | SECURITY_INFORMATION si = | ||
| 5061 | OWNER_SECURITY_INFORMATION | | ||
| 5062 | GROUP_SECURITY_INFORMATION | | ||
| 5063 | DACL_SECURITY_INFORMATION ; | ||
| 5064 | int e = errno; | ||
| 5065 | |||
| 5066 | filename = map_w32_filename (fname, NULL); | ||
| 5067 | if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0) | ||
| 5068 | fname = chase_symlinks (filename); | ||
| 5069 | else | ||
| 5070 | fname = filename; | ||
| 5071 | |||
| 5072 | errno = 0; | ||
| 5073 | if (!get_file_security (fname, si, psd, 0, &sd_len) | ||
| 5074 | && errno != ENOTSUP) | ||
| 5075 | { | ||
| 5076 | err = GetLastError (); | ||
| 5077 | if (err == ERROR_INSUFFICIENT_BUFFER) | ||
| 5078 | { | ||
| 5079 | psd = xmalloc (sd_len); | ||
| 5080 | if (!get_file_security (fname, si, psd, sd_len, &sd_len)) | ||
| 5081 | { | ||
| 5082 | xfree (psd); | ||
| 5083 | errno = EIO; | ||
| 5084 | psd = NULL; | ||
| 5085 | } | ||
| 5086 | } | ||
| 5087 | else if (err == ERROR_FILE_NOT_FOUND | ||
| 5088 | || err == ERROR_PATH_NOT_FOUND) | ||
| 5089 | errno = ENOENT; | ||
| 5090 | else | ||
| 5091 | errno = EIO; | ||
| 5092 | } | ||
| 5093 | else if (!errno) | ||
| 5094 | errno = e; | ||
| 5095 | } | ||
| 5096 | else if (type != ACL_TYPE_DEFAULT) | ||
| 5097 | errno = EINVAL; | ||
| 5098 | |||
| 5099 | return psd; | ||
| 5100 | } | ||
| 5101 | |||
| 5102 | int | ||
| 5103 | acl_set_file (const char *fname, acl_type_t type, acl_t acl) | ||
| 5104 | { | ||
| 5105 | TOKEN_PRIVILEGES old1, old2; | ||
| 5106 | DWORD err; | ||
| 5107 | int st = 0, retval = -1; | ||
| 5108 | SECURITY_INFORMATION flags = 0; | ||
| 5109 | PSID psid; | ||
| 5110 | PACL pacl; | ||
| 5111 | BOOL dflt; | ||
| 5112 | BOOL dacl_present; | ||
| 5113 | int e; | ||
| 5114 | const char *filename; | ||
| 5115 | |||
| 5116 | if (acl_valid (acl) != 0 | ||
| 5117 | || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS)) | ||
| 5118 | { | ||
| 5119 | errno = EINVAL; | ||
| 5120 | return -1; | ||
| 5121 | } | ||
| 5122 | |||
| 5123 | if (type == ACL_TYPE_DEFAULT) | ||
| 5124 | { | ||
| 5125 | errno = ENOSYS; | ||
| 5126 | return -1; | ||
| 5127 | } | ||
| 5128 | |||
| 5129 | filename = map_w32_filename (fname, NULL); | ||
| 5130 | if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0) | ||
| 5131 | fname = chase_symlinks (filename); | ||
| 5132 | else | ||
| 5133 | fname = filename; | ||
| 5134 | |||
| 5135 | if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt) | ||
| 5136 | && psid) | ||
| 5137 | flags |= OWNER_SECURITY_INFORMATION; | ||
| 5138 | if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt) | ||
| 5139 | && psid) | ||
| 5140 | flags |= GROUP_SECURITY_INFORMATION; | ||
| 5141 | if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present, | ||
| 5142 | &pacl, &dflt) | ||
| 5143 | && dacl_present) | ||
| 5144 | flags |= DACL_SECURITY_INFORMATION; | ||
| 5145 | if (!flags) | ||
| 5146 | return 0; | ||
| 5147 | |||
| 5148 | /* According to KB-245153, setting the owner will succeed if either: | ||
| 5149 | (1) the caller is the user who will be the new owner, and has the | ||
| 5150 | SE_TAKE_OWNERSHIP privilege, or | ||
| 5151 | (2) the caller has the SE_RESTORE privilege, in which case she can | ||
| 5152 | set any valid user or group as the owner | ||
| 5153 | |||
| 5154 | We request below both SE_TAKE_OWNERSHIP and SE_RESTORE | ||
| 5155 | privileges, and disregard any failures in obtaining them. If | ||
| 5156 | these privileges cannot be obtained, and do not already exist in | ||
| 5157 | the calling thread's security token, this function could fail | ||
| 5158 | with EPERM. */ | ||
| 5159 | if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1)) | ||
| 5160 | st++; | ||
| 5161 | if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2)) | ||
| 5162 | st++; | ||
| 5163 | |||
| 5164 | e = errno; | ||
| 5165 | errno = 0; | ||
| 5166 | if (!set_file_security ((char *)fname, flags, (PSECURITY_DESCRIPTOR)acl)) | ||
| 5167 | { | ||
| 5168 | err = GetLastError (); | ||
| 5169 | |||
| 5170 | if (errno == ENOTSUP) | ||
| 5171 | ; | ||
| 5172 | else if (err == ERROR_INVALID_OWNER | ||
| 5173 | || err == ERROR_NOT_ALL_ASSIGNED | ||
| 5174 | || err == ERROR_ACCESS_DENIED) | ||
| 5175 | { | ||
| 5176 | /* Maybe the requested ACL and the one the file already has | ||
| 5177 | are identical, in which case we can silently ignore the | ||
| 5178 | failure. (And no, Windows doesn't.) */ | ||
| 5179 | acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS); | ||
| 5180 | |||
| 5181 | errno = EPERM; | ||
| 5182 | if (current_acl) | ||
| 5183 | { | ||
| 5184 | char *acl_from = acl_to_text (current_acl, NULL); | ||
| 5185 | char *acl_to = acl_to_text (acl, NULL); | ||
| 5186 | |||
| 5187 | if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0) | ||
| 5188 | { | ||
| 5189 | retval = 0; | ||
| 5190 | errno = e; | ||
| 5191 | } | ||
| 5192 | if (acl_from) | ||
| 5193 | acl_free (acl_from); | ||
| 5194 | if (acl_to) | ||
| 5195 | acl_free (acl_to); | ||
| 5196 | acl_free (current_acl); | ||
| 5197 | } | ||
| 5198 | } | ||
| 5199 | else if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) | ||
| 5200 | errno = ENOENT; | ||
| 5201 | else | ||
| 5202 | errno = EACCES; | ||
| 5203 | } | ||
| 5204 | else | ||
| 5205 | { | ||
| 5206 | retval = 0; | ||
| 5207 | errno = e; | ||
| 5208 | } | ||
| 5209 | |||
| 5210 | if (st) | ||
| 5211 | { | ||
| 5212 | if (st >= 2) | ||
| 5213 | restore_privilege (&old2); | ||
| 5214 | restore_privilege (&old1); | ||
| 5215 | revert_to_self (); | ||
| 5216 | } | ||
| 5217 | |||
| 5218 | return retval; | ||
| 5219 | } | ||
| 5220 | |||
| 5221 | |||
| 4421 | /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We | 5222 | /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We |
| 4422 | have a fixed max size for file names, so we don't need the kind of | 5223 | have a fixed max size for file names, so we don't need the kind of |
| 4423 | alloc/malloc/realloc dance the gnulib version does. We also don't | 5224 | alloc/malloc/realloc dance the gnulib version does. We also don't |
| @@ -4431,12 +5232,6 @@ careadlinkat (int fd, char const *filename, | |||
| 4431 | char linkname[MAX_PATH]; | 5232 | char linkname[MAX_PATH]; |
| 4432 | ssize_t link_size; | 5233 | ssize_t link_size; |
| 4433 | 5234 | ||
| 4434 | if (fd != AT_FDCWD) | ||
| 4435 | { | ||
| 4436 | errno = EINVAL; | ||
| 4437 | return NULL; | ||
| 4438 | } | ||
| 4439 | |||
| 4440 | link_size = preadlinkat (fd, filename, linkname, sizeof(linkname)); | 5235 | link_size = preadlinkat (fd, filename, linkname, sizeof(linkname)); |
| 4441 | 5236 | ||
| 4442 | if (link_size > 0) | 5237 | if (link_size > 0) |
| @@ -4454,14 +5249,6 @@ careadlinkat (int fd, char const *filename, | |||
| 4454 | return NULL; | 5249 | return NULL; |
| 4455 | } | 5250 | } |
| 4456 | 5251 | ||
| 4457 | ssize_t | ||
| 4458 | careadlinkatcwd (int fd, char const *filename, char *buffer, | ||
| 4459 | size_t buffer_size) | ||
| 4460 | { | ||
| 4461 | (void) fd; | ||
| 4462 | return readlink (filename, buffer, buffer_size); | ||
| 4463 | } | ||
| 4464 | |||
| 4465 | 5252 | ||
| 4466 | /* Support for browsing other processes and their attributes. See | 5253 | /* Support for browsing other processes and their attributes. See |
| 4467 | process.c for the Lisp bindings. */ | 5254 | process.c for the Lisp bindings. */ |
| @@ -4633,8 +5420,8 @@ get_process_memory_info (HANDLE h_proc, | |||
| 4633 | 5420 | ||
| 4634 | static BOOL WINAPI | 5421 | static BOOL WINAPI |
| 4635 | get_process_working_set_size (HANDLE h_proc, | 5422 | get_process_working_set_size (HANDLE h_proc, |
| 4636 | DWORD *minrss, | 5423 | PSIZE_T minrss, |
| 4637 | DWORD *maxrss) | 5424 | PSIZE_T maxrss) |
| 4638 | { | 5425 | { |
| 4639 | static GetProcessWorkingSetSize_Proc | 5426 | static GetProcessWorkingSetSize_Proc |
| 4640 | s_pfn_Get_Process_Working_Set_Size = NULL; | 5427 | s_pfn_Get_Process_Working_Set_Size = NULL; |
| @@ -4799,10 +5586,8 @@ ltime (ULONGLONG time_100ns) | |||
| 4799 | { | 5586 | { |
| 4800 | ULONGLONG time_sec = time_100ns / 10000000; | 5587 | ULONGLONG time_sec = time_100ns / 10000000; |
| 4801 | int subsec = time_100ns % 10000000; | 5588 | int subsec = time_100ns % 10000000; |
| 4802 | return list4 (make_number (time_sec >> 16), | 5589 | return list4i (time_sec >> 16, time_sec & 0xffff, |
| 4803 | make_number (time_sec & 0xffff), | 5590 | subsec / 10, subsec % 10 * 100000); |
| 4804 | make_number (subsec / 10), | ||
| 4805 | make_number (subsec % 10 * 100000)); | ||
| 4806 | } | 5591 | } |
| 4807 | 5592 | ||
| 4808 | #define U64_TO_LISP_TIME(time) ltime (time) | 5593 | #define U64_TO_LISP_TIME(time) ltime (time) |
| @@ -4879,7 +5664,7 @@ system_process_attributes (Lisp_Object pid) | |||
| 4879 | unsigned egid; | 5664 | unsigned egid; |
| 4880 | PROCESS_MEMORY_COUNTERS mem; | 5665 | PROCESS_MEMORY_COUNTERS mem; |
| 4881 | PROCESS_MEMORY_COUNTERS_EX mem_ex; | 5666 | PROCESS_MEMORY_COUNTERS_EX mem_ex; |
| 4882 | DWORD minrss, maxrss; | 5667 | SIZE_T minrss, maxrss; |
| 4883 | MEMORYSTATUS memst; | 5668 | MEMORYSTATUS memst; |
| 4884 | MEMORY_STATUS_EX memstex; | 5669 | MEMORY_STATUS_EX memstex; |
| 4885 | double totphys = 0.0; | 5670 | double totphys = 0.0; |
| @@ -5107,7 +5892,7 @@ system_process_attributes (Lisp_Object pid) | |||
| 5107 | && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex, | 5892 | && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex, |
| 5108 | sizeof (mem_ex))) | 5893 | sizeof (mem_ex))) |
| 5109 | { | 5894 | { |
| 5110 | DWORD rss = mem_ex.WorkingSetSize / 1024; | 5895 | SIZE_T rss = mem_ex.WorkingSetSize / 1024; |
| 5111 | 5896 | ||
| 5112 | attrs = Fcons (Fcons (Qmajflt, | 5897 | attrs = Fcons (Fcons (Qmajflt, |
| 5113 | make_fixnum_or_float (mem_ex.PageFaultCount)), | 5898 | make_fixnum_or_float (mem_ex.PageFaultCount)), |
| @@ -5122,7 +5907,7 @@ system_process_attributes (Lisp_Object pid) | |||
| 5122 | else if (h_proc | 5907 | else if (h_proc |
| 5123 | && get_process_memory_info (h_proc, &mem, sizeof (mem))) | 5908 | && get_process_memory_info (h_proc, &mem, sizeof (mem))) |
| 5124 | { | 5909 | { |
| 5125 | DWORD rss = mem_ex.WorkingSetSize / 1024; | 5910 | SIZE_T rss = mem_ex.WorkingSetSize / 1024; |
| 5126 | 5911 | ||
| 5127 | attrs = Fcons (Fcons (Qmajflt, | 5912 | attrs = Fcons (Fcons (Qmajflt, |
| 5128 | make_fixnum_or_float (mem.PageFaultCount)), | 5913 | make_fixnum_or_float (mem.PageFaultCount)), |
| @@ -5316,35 +6101,39 @@ init_winsock (int load_now) | |||
| 5316 | 6101 | ||
| 5317 | int h_errno = 0; | 6102 | int h_errno = 0; |
| 5318 | 6103 | ||
| 5319 | /* function to set h_errno for compatibility; map winsock error codes to | 6104 | /* Function to map winsock error codes to errno codes for those errno |
| 5320 | normal system codes where they overlap (non-overlapping definitions | 6105 | code defined in errno.h (errno values not defined by errno.h are |
| 5321 | are already in <sys/socket.h> */ | 6106 | already in nt/inc/sys/socket.h). */ |
| 5322 | static void | 6107 | static void |
| 5323 | set_errno (void) | 6108 | set_errno (void) |
| 5324 | { | 6109 | { |
| 6110 | int wsa_err; | ||
| 6111 | |||
| 6112 | h_errno = 0; | ||
| 5325 | if (winsock_lib == NULL) | 6113 | if (winsock_lib == NULL) |
| 5326 | h_errno = EINVAL; | 6114 | wsa_err = EINVAL; |
| 5327 | else | 6115 | else |
| 5328 | h_errno = pfn_WSAGetLastError (); | 6116 | wsa_err = pfn_WSAGetLastError (); |
| 5329 | 6117 | ||
| 5330 | switch (h_errno) | 6118 | switch (wsa_err) |
| 5331 | { | 6119 | { |
| 5332 | case WSAEACCES: h_errno = EACCES; break; | 6120 | case WSAEACCES: errno = EACCES; break; |
| 5333 | case WSAEBADF: h_errno = EBADF; break; | 6121 | case WSAEBADF: errno = EBADF; break; |
| 5334 | case WSAEFAULT: h_errno = EFAULT; break; | 6122 | case WSAEFAULT: errno = EFAULT; break; |
| 5335 | case WSAEINTR: h_errno = EINTR; break; | 6123 | case WSAEINTR: errno = EINTR; break; |
| 5336 | case WSAEINVAL: h_errno = EINVAL; break; | 6124 | case WSAEINVAL: errno = EINVAL; break; |
| 5337 | case WSAEMFILE: h_errno = EMFILE; break; | 6125 | case WSAEMFILE: errno = EMFILE; break; |
| 5338 | case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break; | 6126 | case WSAENAMETOOLONG: errno = ENAMETOOLONG; break; |
| 5339 | case WSAENOTEMPTY: h_errno = ENOTEMPTY; break; | 6127 | case WSAENOTEMPTY: errno = ENOTEMPTY; break; |
| 6128 | default: errno = wsa_err; break; | ||
| 5340 | } | 6129 | } |
| 5341 | errno = h_errno; | ||
| 5342 | } | 6130 | } |
| 5343 | 6131 | ||
| 5344 | static void | 6132 | static void |
| 5345 | check_errno (void) | 6133 | check_errno (void) |
| 5346 | { | 6134 | { |
| 5347 | if (h_errno == 0 && winsock_lib != NULL) | 6135 | h_errno = 0; |
| 6136 | if (winsock_lib != NULL) | ||
| 5348 | pfn_WSASetLastError (0); | 6137 | pfn_WSASetLastError (0); |
| 5349 | } | 6138 | } |
| 5350 | 6139 | ||
| @@ -5456,7 +6245,7 @@ sys_socket (int af, int type, int protocol) | |||
| 5456 | 6245 | ||
| 5457 | if (winsock_lib == NULL) | 6246 | if (winsock_lib == NULL) |
| 5458 | { | 6247 | { |
| 5459 | h_errno = ENETDOWN; | 6248 | errno = ENETDOWN; |
| 5460 | return INVALID_SOCKET; | 6249 | return INVALID_SOCKET; |
| 5461 | } | 6250 | } |
| 5462 | 6251 | ||
| @@ -5533,6 +6322,7 @@ socket_to_fd (SOCKET s) | |||
| 5533 | } | 6322 | } |
| 5534 | } | 6323 | } |
| 5535 | } | 6324 | } |
| 6325 | eassert (fd < MAXDESC); | ||
| 5536 | fd_info[fd].hnd = (HANDLE) s; | 6326 | fd_info[fd].hnd = (HANDLE) s; |
| 5537 | 6327 | ||
| 5538 | /* set our own internal flags */ | 6328 | /* set our own internal flags */ |
| @@ -5561,8 +6351,9 @@ socket_to_fd (SOCKET s) | |||
| 5561 | /* clean up */ | 6351 | /* clean up */ |
| 5562 | _close (fd); | 6352 | _close (fd); |
| 5563 | } | 6353 | } |
| 6354 | else | ||
| 5564 | pfn_closesocket (s); | 6355 | pfn_closesocket (s); |
| 5565 | h_errno = EMFILE; | 6356 | errno = EMFILE; |
| 5566 | return -1; | 6357 | return -1; |
| 5567 | } | 6358 | } |
| 5568 | 6359 | ||
| @@ -5571,7 +6362,7 @@ sys_bind (int s, const struct sockaddr * addr, int namelen) | |||
| 5571 | { | 6362 | { |
| 5572 | if (winsock_lib == NULL) | 6363 | if (winsock_lib == NULL) |
| 5573 | { | 6364 | { |
| 5574 | h_errno = ENOTSOCK; | 6365 | errno = ENOTSOCK; |
| 5575 | return SOCKET_ERROR; | 6366 | return SOCKET_ERROR; |
| 5576 | } | 6367 | } |
| 5577 | 6368 | ||
| @@ -5583,7 +6374,7 @@ sys_bind (int s, const struct sockaddr * addr, int namelen) | |||
| 5583 | set_errno (); | 6374 | set_errno (); |
| 5584 | return rc; | 6375 | return rc; |
| 5585 | } | 6376 | } |
| 5586 | h_errno = ENOTSOCK; | 6377 | errno = ENOTSOCK; |
| 5587 | return SOCKET_ERROR; | 6378 | return SOCKET_ERROR; |
| 5588 | } | 6379 | } |
| 5589 | 6380 | ||
| @@ -5592,7 +6383,7 @@ sys_connect (int s, const struct sockaddr * name, int namelen) | |||
| 5592 | { | 6383 | { |
| 5593 | if (winsock_lib == NULL) | 6384 | if (winsock_lib == NULL) |
| 5594 | { | 6385 | { |
| 5595 | h_errno = ENOTSOCK; | 6386 | errno = ENOTSOCK; |
| 5596 | return SOCKET_ERROR; | 6387 | return SOCKET_ERROR; |
| 5597 | } | 6388 | } |
| 5598 | 6389 | ||
| @@ -5604,7 +6395,7 @@ sys_connect (int s, const struct sockaddr * name, int namelen) | |||
| 5604 | set_errno (); | 6395 | set_errno (); |
| 5605 | return rc; | 6396 | return rc; |
| 5606 | } | 6397 | } |
| 5607 | h_errno = ENOTSOCK; | 6398 | errno = ENOTSOCK; |
| 5608 | return SOCKET_ERROR; | 6399 | return SOCKET_ERROR; |
| 5609 | } | 6400 | } |
| 5610 | 6401 | ||
| @@ -5633,12 +6424,20 @@ int | |||
| 5633 | sys_gethostname (char * name, int namelen) | 6424 | sys_gethostname (char * name, int namelen) |
| 5634 | { | 6425 | { |
| 5635 | if (winsock_lib != NULL) | 6426 | if (winsock_lib != NULL) |
| 5636 | return pfn_gethostname (name, namelen); | 6427 | { |
| 6428 | int retval; | ||
| 6429 | |||
| 6430 | check_errno (); | ||
| 6431 | retval = pfn_gethostname (name, namelen); | ||
| 6432 | if (retval == SOCKET_ERROR) | ||
| 6433 | set_errno (); | ||
| 6434 | return retval; | ||
| 6435 | } | ||
| 5637 | 6436 | ||
| 5638 | if (namelen > MAX_COMPUTERNAME_LENGTH) | 6437 | if (namelen > MAX_COMPUTERNAME_LENGTH) |
| 5639 | return !GetComputerName (name, (DWORD *)&namelen); | 6438 | return !GetComputerName (name, (DWORD *)&namelen); |
| 5640 | 6439 | ||
| 5641 | h_errno = EFAULT; | 6440 | errno = EFAULT; |
| 5642 | return SOCKET_ERROR; | 6441 | return SOCKET_ERROR; |
| 5643 | } | 6442 | } |
| 5644 | 6443 | ||
| @@ -5646,17 +6445,24 @@ struct hostent * | |||
| 5646 | sys_gethostbyname (const char * name) | 6445 | sys_gethostbyname (const char * name) |
| 5647 | { | 6446 | { |
| 5648 | struct hostent * host; | 6447 | struct hostent * host; |
| 6448 | int h_err = h_errno; | ||
| 5649 | 6449 | ||
| 5650 | if (winsock_lib == NULL) | 6450 | if (winsock_lib == NULL) |
| 5651 | { | 6451 | { |
| 5652 | h_errno = ENETDOWN; | 6452 | h_errno = NO_RECOVERY; |
| 6453 | errno = ENETDOWN; | ||
| 5653 | return NULL; | 6454 | return NULL; |
| 5654 | } | 6455 | } |
| 5655 | 6456 | ||
| 5656 | check_errno (); | 6457 | check_errno (); |
| 5657 | host = pfn_gethostbyname (name); | 6458 | host = pfn_gethostbyname (name); |
| 5658 | if (!host) | 6459 | if (!host) |
| 5659 | set_errno (); | 6460 | { |
| 6461 | set_errno (); | ||
| 6462 | h_errno = errno; | ||
| 6463 | } | ||
| 6464 | else | ||
| 6465 | h_errno = h_err; | ||
| 5660 | return host; | 6466 | return host; |
| 5661 | } | 6467 | } |
| 5662 | 6468 | ||
| @@ -5667,7 +6473,7 @@ sys_getservbyname (const char * name, const char * proto) | |||
| 5667 | 6473 | ||
| 5668 | if (winsock_lib == NULL) | 6474 | if (winsock_lib == NULL) |
| 5669 | { | 6475 | { |
| 5670 | h_errno = ENETDOWN; | 6476 | errno = ENETDOWN; |
| 5671 | return NULL; | 6477 | return NULL; |
| 5672 | } | 6478 | } |
| 5673 | 6479 | ||
| @@ -5683,7 +6489,7 @@ sys_getpeername (int s, struct sockaddr *addr, int * namelen) | |||
| 5683 | { | 6489 | { |
| 5684 | if (winsock_lib == NULL) | 6490 | if (winsock_lib == NULL) |
| 5685 | { | 6491 | { |
| 5686 | h_errno = ENETDOWN; | 6492 | errno = ENETDOWN; |
| 5687 | return SOCKET_ERROR; | 6493 | return SOCKET_ERROR; |
| 5688 | } | 6494 | } |
| 5689 | 6495 | ||
| @@ -5695,7 +6501,7 @@ sys_getpeername (int s, struct sockaddr *addr, int * namelen) | |||
| 5695 | set_errno (); | 6501 | set_errno (); |
| 5696 | return rc; | 6502 | return rc; |
| 5697 | } | 6503 | } |
| 5698 | h_errno = ENOTSOCK; | 6504 | errno = ENOTSOCK; |
| 5699 | return SOCKET_ERROR; | 6505 | return SOCKET_ERROR; |
| 5700 | } | 6506 | } |
| 5701 | 6507 | ||
| @@ -5704,7 +6510,7 @@ sys_shutdown (int s, int how) | |||
| 5704 | { | 6510 | { |
| 5705 | if (winsock_lib == NULL) | 6511 | if (winsock_lib == NULL) |
| 5706 | { | 6512 | { |
| 5707 | h_errno = ENETDOWN; | 6513 | errno = ENETDOWN; |
| 5708 | return SOCKET_ERROR; | 6514 | return SOCKET_ERROR; |
| 5709 | } | 6515 | } |
| 5710 | 6516 | ||
| @@ -5716,7 +6522,7 @@ sys_shutdown (int s, int how) | |||
| 5716 | set_errno (); | 6522 | set_errno (); |
| 5717 | return rc; | 6523 | return rc; |
| 5718 | } | 6524 | } |
| 5719 | h_errno = ENOTSOCK; | 6525 | errno = ENOTSOCK; |
| 5720 | return SOCKET_ERROR; | 6526 | return SOCKET_ERROR; |
| 5721 | } | 6527 | } |
| 5722 | 6528 | ||
| @@ -5725,7 +6531,7 @@ sys_setsockopt (int s, int level, int optname, const void * optval, int optlen) | |||
| 5725 | { | 6531 | { |
| 5726 | if (winsock_lib == NULL) | 6532 | if (winsock_lib == NULL) |
| 5727 | { | 6533 | { |
| 5728 | h_errno = ENETDOWN; | 6534 | errno = ENETDOWN; |
| 5729 | return SOCKET_ERROR; | 6535 | return SOCKET_ERROR; |
| 5730 | } | 6536 | } |
| 5731 | 6537 | ||
| @@ -5738,7 +6544,7 @@ sys_setsockopt (int s, int level, int optname, const void * optval, int optlen) | |||
| 5738 | set_errno (); | 6544 | set_errno (); |
| 5739 | return rc; | 6545 | return rc; |
| 5740 | } | 6546 | } |
| 5741 | h_errno = ENOTSOCK; | 6547 | errno = ENOTSOCK; |
| 5742 | return SOCKET_ERROR; | 6548 | return SOCKET_ERROR; |
| 5743 | } | 6549 | } |
| 5744 | 6550 | ||
| @@ -5747,7 +6553,7 @@ sys_listen (int s, int backlog) | |||
| 5747 | { | 6553 | { |
| 5748 | if (winsock_lib == NULL) | 6554 | if (winsock_lib == NULL) |
| 5749 | { | 6555 | { |
| 5750 | h_errno = ENETDOWN; | 6556 | errno = ENETDOWN; |
| 5751 | return SOCKET_ERROR; | 6557 | return SOCKET_ERROR; |
| 5752 | } | 6558 | } |
| 5753 | 6559 | ||
| @@ -5761,7 +6567,7 @@ sys_listen (int s, int backlog) | |||
| 5761 | fd_info[s].flags |= FILE_LISTEN; | 6567 | fd_info[s].flags |= FILE_LISTEN; |
| 5762 | return rc; | 6568 | return rc; |
| 5763 | } | 6569 | } |
| 5764 | h_errno = ENOTSOCK; | 6570 | errno = ENOTSOCK; |
| 5765 | return SOCKET_ERROR; | 6571 | return SOCKET_ERROR; |
| 5766 | } | 6572 | } |
| 5767 | 6573 | ||
| @@ -5770,7 +6576,7 @@ sys_getsockname (int s, struct sockaddr * name, int * namelen) | |||
| 5770 | { | 6576 | { |
| 5771 | if (winsock_lib == NULL) | 6577 | if (winsock_lib == NULL) |
| 5772 | { | 6578 | { |
| 5773 | h_errno = ENETDOWN; | 6579 | errno = ENETDOWN; |
| 5774 | return SOCKET_ERROR; | 6580 | return SOCKET_ERROR; |
| 5775 | } | 6581 | } |
| 5776 | 6582 | ||
| @@ -5782,7 +6588,7 @@ sys_getsockname (int s, struct sockaddr * name, int * namelen) | |||
| 5782 | set_errno (); | 6588 | set_errno (); |
| 5783 | return rc; | 6589 | return rc; |
| 5784 | } | 6590 | } |
| 5785 | h_errno = ENOTSOCK; | 6591 | errno = ENOTSOCK; |
| 5786 | return SOCKET_ERROR; | 6592 | return SOCKET_ERROR; |
| 5787 | } | 6593 | } |
| 5788 | 6594 | ||
| @@ -5791,7 +6597,7 @@ sys_accept (int s, struct sockaddr * addr, int * addrlen) | |||
| 5791 | { | 6597 | { |
| 5792 | if (winsock_lib == NULL) | 6598 | if (winsock_lib == NULL) |
| 5793 | { | 6599 | { |
| 5794 | h_errno = ENETDOWN; | 6600 | errno = ENETDOWN; |
| 5795 | return -1; | 6601 | return -1; |
| 5796 | } | 6602 | } |
| 5797 | 6603 | ||
| @@ -5805,11 +6611,14 @@ sys_accept (int s, struct sockaddr * addr, int * addrlen) | |||
| 5805 | else | 6611 | else |
| 5806 | fd = socket_to_fd (t); | 6612 | fd = socket_to_fd (t); |
| 5807 | 6613 | ||
| 5808 | fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED; | 6614 | if (fd >= 0) |
| 5809 | ResetEvent (fd_info[s].cp->char_avail); | 6615 | { |
| 6616 | fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED; | ||
| 6617 | ResetEvent (fd_info[s].cp->char_avail); | ||
| 6618 | } | ||
| 5810 | return fd; | 6619 | return fd; |
| 5811 | } | 6620 | } |
| 5812 | h_errno = ENOTSOCK; | 6621 | errno = ENOTSOCK; |
| 5813 | return -1; | 6622 | return -1; |
| 5814 | } | 6623 | } |
| 5815 | 6624 | ||
| @@ -5819,7 +6628,7 @@ sys_recvfrom (int s, char * buf, int len, int flags, | |||
| 5819 | { | 6628 | { |
| 5820 | if (winsock_lib == NULL) | 6629 | if (winsock_lib == NULL) |
| 5821 | { | 6630 | { |
| 5822 | h_errno = ENETDOWN; | 6631 | errno = ENETDOWN; |
| 5823 | return SOCKET_ERROR; | 6632 | return SOCKET_ERROR; |
| 5824 | } | 6633 | } |
| 5825 | 6634 | ||
| @@ -5831,7 +6640,7 @@ sys_recvfrom (int s, char * buf, int len, int flags, | |||
| 5831 | set_errno (); | 6640 | set_errno (); |
| 5832 | return rc; | 6641 | return rc; |
| 5833 | } | 6642 | } |
| 5834 | h_errno = ENOTSOCK; | 6643 | errno = ENOTSOCK; |
| 5835 | return SOCKET_ERROR; | 6644 | return SOCKET_ERROR; |
| 5836 | } | 6645 | } |
| 5837 | 6646 | ||
| @@ -5841,7 +6650,7 @@ sys_sendto (int s, const char * buf, int len, int flags, | |||
| 5841 | { | 6650 | { |
| 5842 | if (winsock_lib == NULL) | 6651 | if (winsock_lib == NULL) |
| 5843 | { | 6652 | { |
| 5844 | h_errno = ENETDOWN; | 6653 | errno = ENETDOWN; |
| 5845 | return SOCKET_ERROR; | 6654 | return SOCKET_ERROR; |
| 5846 | } | 6655 | } |
| 5847 | 6656 | ||
| @@ -5853,7 +6662,7 @@ sys_sendto (int s, const char * buf, int len, int flags, | |||
| 5853 | set_errno (); | 6662 | set_errno (); |
| 5854 | return rc; | 6663 | return rc; |
| 5855 | } | 6664 | } |
| 5856 | h_errno = ENOTSOCK; | 6665 | errno = ENOTSOCK; |
| 5857 | return SOCKET_ERROR; | 6666 | return SOCKET_ERROR; |
| 5858 | } | 6667 | } |
| 5859 | 6668 | ||
| @@ -5864,7 +6673,7 @@ fcntl (int s, int cmd, int options) | |||
| 5864 | { | 6673 | { |
| 5865 | if (winsock_lib == NULL) | 6674 | if (winsock_lib == NULL) |
| 5866 | { | 6675 | { |
| 5867 | h_errno = ENETDOWN; | 6676 | errno = ENETDOWN; |
| 5868 | return -1; | 6677 | return -1; |
| 5869 | } | 6678 | } |
| 5870 | 6679 | ||
| @@ -5883,11 +6692,11 @@ fcntl (int s, int cmd, int options) | |||
| 5883 | } | 6692 | } |
| 5884 | else | 6693 | else |
| 5885 | { | 6694 | { |
| 5886 | h_errno = EINVAL; | 6695 | errno = EINVAL; |
| 5887 | return SOCKET_ERROR; | 6696 | return SOCKET_ERROR; |
| 5888 | } | 6697 | } |
| 5889 | } | 6698 | } |
| 5890 | h_errno = ENOTSOCK; | 6699 | errno = ENOTSOCK; |
| 5891 | return SOCKET_ERROR; | 6700 | return SOCKET_ERROR; |
| 5892 | } | 6701 | } |
| 5893 | 6702 | ||
| @@ -5934,20 +6743,34 @@ sys_close (int fd) | |||
| 5934 | 6743 | ||
| 5935 | winsock_inuse--; /* count open sockets */ | 6744 | winsock_inuse--; /* count open sockets */ |
| 5936 | } | 6745 | } |
| 5937 | delete_child (cp); | 6746 | /* If the process handle is NULL, it's either a socket |
| 6747 | or serial connection, or a subprocess that was | ||
| 6748 | already reaped by reap_subprocess, but whose | ||
| 6749 | resources were not yet freed, because its output was | ||
| 6750 | not fully read yet by the time it was reaped. (This | ||
| 6751 | usually happens with async subprocesses whose output | ||
| 6752 | is being read by Emacs.) Otherwise, this process was | ||
| 6753 | not reaped yet, so we set its FD to a negative value | ||
| 6754 | to make sure sys_select will eventually get to | ||
| 6755 | calling the SIGCHLD handler for it, which will then | ||
| 6756 | invoke waitpid and reap_subprocess. */ | ||
| 6757 | if (cp->procinfo.hProcess == NULL) | ||
| 6758 | delete_child (cp); | ||
| 6759 | else | ||
| 6760 | cp->fd = -1; | ||
| 5938 | } | 6761 | } |
| 5939 | } | 6762 | } |
| 5940 | } | 6763 | } |
| 5941 | 6764 | ||
| 6765 | if (fd >= 0 && fd < MAXDESC) | ||
| 6766 | fd_info[fd].flags = 0; | ||
| 6767 | |||
| 5942 | /* Note that sockets do not need special treatment here (at least on | 6768 | /* Note that sockets do not need special treatment here (at least on |
| 5943 | NT and Windows 95 using the standard tcp/ip stacks) - it appears that | 6769 | NT and Windows 95 using the standard tcp/ip stacks) - it appears that |
| 5944 | closesocket is equivalent to CloseHandle, which is to be expected | 6770 | closesocket is equivalent to CloseHandle, which is to be expected |
| 5945 | because socket handles are fully fledged kernel handles. */ | 6771 | because socket handles are fully fledged kernel handles. */ |
| 5946 | rc = _close (fd); | 6772 | rc = _close (fd); |
| 5947 | 6773 | ||
| 5948 | if (rc == 0 && fd < MAXDESC) | ||
| 5949 | fd_info[fd].flags = 0; | ||
| 5950 | |||
| 5951 | return rc; | 6774 | return rc; |
| 5952 | } | 6775 | } |
| 5953 | 6776 | ||
| @@ -6010,6 +6833,7 @@ sys_pipe (int * phandles) | |||
| 6010 | { | 6833 | { |
| 6011 | _close (phandles[0]); | 6834 | _close (phandles[0]); |
| 6012 | _close (phandles[1]); | 6835 | _close (phandles[1]); |
| 6836 | errno = EMFILE; | ||
| 6013 | rc = -1; | 6837 | rc = -1; |
| 6014 | } | 6838 | } |
| 6015 | else | 6839 | else |
| @@ -6026,7 +6850,8 @@ sys_pipe (int * phandles) | |||
| 6026 | } | 6850 | } |
| 6027 | 6851 | ||
| 6028 | /* Function to do blocking read of one byte, needed to implement | 6852 | /* Function to do blocking read of one byte, needed to implement |
| 6029 | select. It is only allowed on sockets and pipes. */ | 6853 | select. It is only allowed on communication ports, sockets, or |
| 6854 | pipes. */ | ||
| 6030 | int | 6855 | int |
| 6031 | _sys_read_ahead (int fd) | 6856 | _sys_read_ahead (int fd) |
| 6032 | { | 6857 | { |
| @@ -6082,19 +6907,31 @@ _sys_read_ahead (int fd) | |||
| 6082 | 6907 | ||
| 6083 | /* Configure timeouts for blocking read. */ | 6908 | /* Configure timeouts for blocking read. */ |
| 6084 | if (!GetCommTimeouts (hnd, &ct)) | 6909 | if (!GetCommTimeouts (hnd, &ct)) |
| 6085 | return STATUS_READ_ERROR; | 6910 | { |
| 6911 | cp->status = STATUS_READ_ERROR; | ||
| 6912 | return STATUS_READ_ERROR; | ||
| 6913 | } | ||
| 6086 | ct.ReadIntervalTimeout = 0; | 6914 | ct.ReadIntervalTimeout = 0; |
| 6087 | ct.ReadTotalTimeoutMultiplier = 0; | 6915 | ct.ReadTotalTimeoutMultiplier = 0; |
| 6088 | ct.ReadTotalTimeoutConstant = 0; | 6916 | ct.ReadTotalTimeoutConstant = 0; |
| 6089 | if (!SetCommTimeouts (hnd, &ct)) | 6917 | if (!SetCommTimeouts (hnd, &ct)) |
| 6090 | return STATUS_READ_ERROR; | 6918 | { |
| 6919 | cp->status = STATUS_READ_ERROR; | ||
| 6920 | return STATUS_READ_ERROR; | ||
| 6921 | } | ||
| 6091 | 6922 | ||
| 6092 | if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl)) | 6923 | if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl)) |
| 6093 | { | 6924 | { |
| 6094 | if (GetLastError () != ERROR_IO_PENDING) | 6925 | if (GetLastError () != ERROR_IO_PENDING) |
| 6095 | return STATUS_READ_ERROR; | 6926 | { |
| 6927 | cp->status = STATUS_READ_ERROR; | ||
| 6928 | return STATUS_READ_ERROR; | ||
| 6929 | } | ||
| 6096 | if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE)) | 6930 | if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE)) |
| 6097 | return STATUS_READ_ERROR; | 6931 | { |
| 6932 | cp->status = STATUS_READ_ERROR; | ||
| 6933 | return STATUS_READ_ERROR; | ||
| 6934 | } | ||
| 6098 | } | 6935 | } |
| 6099 | } | 6936 | } |
| 6100 | else if (fd_info[fd].flags & FILE_SOCKET) | 6937 | else if (fd_info[fd].flags & FILE_SOCKET) |
| @@ -6290,7 +7127,7 @@ sys_read (int fd, char * buffer, unsigned int count) | |||
| 6290 | pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting); | 7127 | pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting); |
| 6291 | if (waiting == 0 && nchars == 0) | 7128 | if (waiting == 0 && nchars == 0) |
| 6292 | { | 7129 | { |
| 6293 | h_errno = errno = EWOULDBLOCK; | 7130 | errno = EWOULDBLOCK; |
| 6294 | return -1; | 7131 | return -1; |
| 6295 | } | 7132 | } |
| 6296 | 7133 | ||
| @@ -6788,6 +7625,11 @@ globals_of_w32 (void) | |||
| 6788 | g_b_init_get_native_system_info = 0; | 7625 | g_b_init_get_native_system_info = 0; |
| 6789 | g_b_init_get_system_times = 0; | 7626 | g_b_init_get_system_times = 0; |
| 6790 | g_b_init_create_symbolic_link = 0; | 7627 | g_b_init_create_symbolic_link = 0; |
| 7628 | g_b_init_get_security_descriptor_dacl = 0; | ||
| 7629 | g_b_init_convert_sd_to_sddl = 0; | ||
| 7630 | g_b_init_convert_sddl_to_sd = 0; | ||
| 7631 | g_b_init_is_valid_security_descriptor = 0; | ||
| 7632 | g_b_init_set_file_security = 0; | ||
| 6791 | num_of_processors = 0; | 7633 | num_of_processors = 0; |
| 6792 | /* The following sets a handler for shutdown notifications for | 7634 | /* The following sets a handler for shutdown notifications for |
| 6793 | console apps. This actually applies to Emacs in both console and | 7635 | console apps. This actually applies to Emacs in both console and |
| @@ -6797,6 +7639,9 @@ globals_of_w32 (void) | |||
| 6797 | 7639 | ||
| 6798 | /* "None" is the default group name on standalone workstations. */ | 7640 | /* "None" is the default group name on standalone workstations. */ |
| 6799 | strcpy (dflt_group_name, "None"); | 7641 | strcpy (dflt_group_name, "None"); |
| 7642 | |||
| 7643 | /* Reset, in case it has some value inherited from dump time. */ | ||
| 7644 | w32_stat_get_owner_group = 0; | ||
| 6800 | } | 7645 | } |
| 6801 | 7646 | ||
| 6802 | /* For make-serial-process */ | 7647 | /* For make-serial-process */ |
| @@ -6994,47 +7839,26 @@ serial_configure (struct Lisp_Process *p, Lisp_Object contact) | |||
| 6994 | ssize_t | 7839 | ssize_t |
| 6995 | emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz) | 7840 | emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz) |
| 6996 | { | 7841 | { |
| 6997 | int n, sc, err; | 7842 | int n, err; |
| 6998 | SELECT_TYPE fdset; | 7843 | SELECT_TYPE fdset; |
| 6999 | EMACS_TIME timeout; | 7844 | EMACS_TIME timeout; |
| 7000 | struct Lisp_Process *process = (struct Lisp_Process *)p; | 7845 | struct Lisp_Process *process = (struct Lisp_Process *)p; |
| 7001 | int fd = process->infd; | 7846 | int fd = process->infd; |
| 7002 | 7847 | ||
| 7003 | for (;;) | 7848 | n = sys_read (fd, (char*)buf, sz); |
| 7004 | { | ||
| 7005 | n = sys_read (fd, (char*)buf, sz); | ||
| 7006 | 7849 | ||
| 7007 | if (n >= 0) | 7850 | if (n >= 0) |
| 7008 | return n; | 7851 | return n; |
| 7009 | 7852 | ||
| 7010 | err = errno; | 7853 | err = errno; |
| 7011 | 7854 | ||
| 7012 | if (err == EWOULDBLOCK) | 7855 | /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */ |
| 7013 | { | 7856 | if (err == EWOULDBLOCK) |
| 7014 | /* Set a small timeout. */ | 7857 | err = EAGAIN; |
| 7015 | timeout = make_emacs_time (1, 0); | ||
| 7016 | FD_ZERO (&fdset); | ||
| 7017 | FD_SET ((int)fd, &fdset); | ||
| 7018 | |||
| 7019 | /* Use select with the timeout to poll the selector. */ | ||
| 7020 | sc = select (fd + 1, &fdset, (SELECT_TYPE *)0, (SELECT_TYPE *)0, | ||
| 7021 | &timeout, NULL); | ||
| 7022 | |||
| 7023 | if (sc > 0) | ||
| 7024 | continue; /* Try again. */ | ||
| 7025 | |||
| 7026 | /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. | ||
| 7027 | Also accept select return 0 as an indicator to EAGAIN. */ | ||
| 7028 | if (sc == 0 || errno == EWOULDBLOCK) | ||
| 7029 | err = EAGAIN; | ||
| 7030 | else | ||
| 7031 | err = errno; /* Other errors are just passed on. */ | ||
| 7032 | } | ||
| 7033 | 7858 | ||
| 7034 | emacs_gnutls_transport_set_errno (process->gnutls_state, err); | 7859 | emacs_gnutls_transport_set_errno (process->gnutls_state, err); |
| 7035 | 7860 | ||
| 7036 | return -1; | 7861 | return -1; |
| 7037 | } | ||
| 7038 | } | 7862 | } |
| 7039 | 7863 | ||
| 7040 | ssize_t | 7864 | ssize_t |