diff options
| author | Eli Zaretskii | 2013-11-23 13:16:36 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2013-11-23 13:16:36 +0200 |
| commit | eeccd06f852001648e0307ce07f2687029b18889 (patch) | |
| tree | ef24860d81c67af592db12867272a05d11f06fa9 /src | |
| parent | 18b35e2c7a3ff95fb4a07e58c3f57c70c65c0701 (diff) | |
| download | emacs-eeccd06f852001648e0307ce07f2687029b18889.tar.gz emacs-eeccd06f852001648e0307ce07f2687029b18889.zip | |
Converted symlink-related functions with minimal testing.
Diffstat (limited to 'src')
| -rw-r--r-- | src/fileio.c | 4 | ||||
| -rw-r--r-- | src/w32.c | 382 |
2 files changed, 198 insertions, 188 deletions
diff --git a/src/fileio.c b/src/fileio.c index fbf896e91c3..476d77f8244 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -2670,9 +2670,9 @@ emacs_readlinkat (int fd, char const *filename) | |||
| 2670 | if (!buf) | 2670 | if (!buf) |
| 2671 | return Qnil; | 2671 | return Qnil; |
| 2672 | 2672 | ||
| 2673 | val = build_string (buf); | 2673 | val = build_unibyte_string (buf); |
| 2674 | if (buf[0] == '/' && strchr (buf, ':')) | 2674 | if (buf[0] == '/' && strchr (buf, ':')) |
| 2675 | val = concat2 (build_string ("/:"), val); | 2675 | val = concat2 (build_unibyte_string ("/:"), val); |
| 2676 | if (buf != readlink_buf) | 2676 | if (buf != readlink_buf) |
| 2677 | xfree (buf); | 2677 | xfree (buf); |
| 2678 | val = DECODE_FILE (val); | 2678 | val = DECODE_FILE (val); |
| @@ -293,7 +293,8 @@ static BOOL g_b_init_equal_sid; | |||
| 293 | static BOOL g_b_init_copy_sid; | 293 | static BOOL g_b_init_copy_sid; |
| 294 | static BOOL g_b_init_get_native_system_info; | 294 | static BOOL g_b_init_get_native_system_info; |
| 295 | static BOOL g_b_init_get_system_times; | 295 | static BOOL g_b_init_get_system_times; |
| 296 | static BOOL g_b_init_create_symbolic_link; | 296 | static BOOL g_b_init_create_symbolic_link_w; |
| 297 | static BOOL g_b_init_create_symbolic_link_a; | ||
| 297 | static BOOL g_b_init_get_security_descriptor_dacl; | 298 | static BOOL g_b_init_get_security_descriptor_dacl; |
| 298 | static BOOL g_b_init_convert_sd_to_sddl; | 299 | static BOOL g_b_init_convert_sd_to_sddl; |
| 299 | static BOOL g_b_init_convert_sddl_to_sd; | 300 | static BOOL g_b_init_convert_sddl_to_sd; |
| @@ -428,9 +429,13 @@ typedef BOOL (WINAPI * GetSystemTimes_Proc) ( | |||
| 428 | LPFILETIME lpIdleTime, | 429 | LPFILETIME lpIdleTime, |
| 429 | LPFILETIME lpKernelTime, | 430 | LPFILETIME lpKernelTime, |
| 430 | LPFILETIME lpUserTime); | 431 | LPFILETIME lpUserTime); |
| 431 | typedef BOOLEAN (WINAPI *CreateSymbolicLink_Proc) ( | 432 | typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) ( |
| 432 | LPTSTR lpSymlinkFileName, | 433 | LPCWSTR lpSymlinkFileName, |
| 433 | LPTSTR lpTargetFileName, | 434 | LPCWSTR lpTargetFileName, |
| 435 | DWORD dwFlags); | ||
| 436 | typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) ( | ||
| 437 | LPCSTR lpSymlinkFileName, | ||
| 438 | LPCSTR lpTargetFileName, | ||
| 434 | DWORD dwFlags); | 439 | DWORD dwFlags); |
| 435 | typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) ( | 440 | typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) ( |
| 436 | LPCTSTR StringSecurityDescriptor, | 441 | LPCTSTR StringSecurityDescriptor, |
| @@ -1008,11 +1013,12 @@ get_system_times (LPFILETIME lpIdleTime, | |||
| 1008 | } | 1013 | } |
| 1009 | 1014 | ||
| 1010 | static BOOLEAN WINAPI | 1015 | static BOOLEAN WINAPI |
| 1011 | create_symbolic_link (LPTSTR lpSymlinkFilename, | 1016 | create_symbolic_link (LPCSTR lpSymlinkFilename, |
| 1012 | LPTSTR lpTargetFileName, | 1017 | LPCSTR lpTargetFileName, |
| 1013 | DWORD dwFlags) | 1018 | DWORD dwFlags) |
| 1014 | { | 1019 | { |
| 1015 | static CreateSymbolicLink_Proc s_pfn_Create_Symbolic_Link = NULL; | 1020 | static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL; |
| 1021 | static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL; | ||
| 1016 | BOOLEAN retval; | 1022 | BOOLEAN retval; |
| 1017 | 1023 | ||
| 1018 | if (is_windows_9x () == TRUE) | 1024 | if (is_windows_9x () == TRUE) |
| @@ -1020,39 +1026,74 @@ create_symbolic_link (LPTSTR lpSymlinkFilename, | |||
| 1020 | errno = ENOSYS; | 1026 | errno = ENOSYS; |
| 1021 | return 0; | 1027 | return 0; |
| 1022 | } | 1028 | } |
| 1023 | if (g_b_init_create_symbolic_link == 0) | 1029 | if (w32_unicode_filenames) |
| 1024 | { | 1030 | { |
| 1025 | g_b_init_create_symbolic_link = 1; | 1031 | wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH]; |
| 1026 | #ifdef _UNICODE | 1032 | |
| 1027 | s_pfn_Create_Symbolic_Link = | 1033 | if (g_b_init_create_symbolic_link_w == 0) |
| 1028 | (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"), | 1034 | { |
| 1029 | "CreateSymbolicLinkW"); | 1035 | g_b_init_create_symbolic_link_w = 1; |
| 1030 | #else | 1036 | s_pfn_Create_Symbolic_LinkW = |
| 1031 | s_pfn_Create_Symbolic_Link = | 1037 | (CreateSymbolicLinkW_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"), |
| 1032 | (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"), | 1038 | "CreateSymbolicLinkW"); |
| 1033 | "CreateSymbolicLinkA"); | 1039 | } |
| 1034 | #endif | 1040 | if (s_pfn_Create_Symbolic_LinkW == NULL) |
| 1041 | { | ||
| 1042 | errno = ENOSYS; | ||
| 1043 | return 0; | ||
| 1044 | } | ||
| 1045 | |||
| 1046 | filename_to_utf16 (lpSymlinkFilename, symfn_w); | ||
| 1047 | filename_to_utf16 (lpTargetFileName, tgtfn_w); | ||
| 1048 | retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags); | ||
| 1049 | /* If we were denied creation of the symlink, try again after | ||
| 1050 | enabling the SeCreateSymbolicLinkPrivilege for our process. */ | ||
| 1051 | if (!retval) | ||
| 1052 | { | ||
| 1053 | TOKEN_PRIVILEGES priv_current; | ||
| 1054 | |||
| 1055 | if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE, | ||
| 1056 | &priv_current)) | ||
| 1057 | { | ||
| 1058 | retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags); | ||
| 1059 | restore_privilege (&priv_current); | ||
| 1060 | revert_to_self (); | ||
| 1061 | } | ||
| 1062 | } | ||
| 1035 | } | 1063 | } |
| 1036 | if (s_pfn_Create_Symbolic_Link == NULL) | 1064 | else |
| 1037 | { | 1065 | { |
| 1038 | errno = ENOSYS; | 1066 | char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH]; |
| 1039 | return 0; | ||
| 1040 | } | ||
| 1041 | 1067 | ||
| 1042 | retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName, | 1068 | if (g_b_init_create_symbolic_link_a == 0) |
| 1043 | dwFlags); | 1069 | { |
| 1044 | /* If we were denied creation of the symlink, try again after | 1070 | g_b_init_create_symbolic_link_a = 1; |
| 1045 | enabling the SeCreateSymbolicLinkPrivilege for our process. */ | 1071 | s_pfn_Create_Symbolic_LinkA = |
| 1046 | if (!retval) | 1072 | (CreateSymbolicLinkA_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"), |
| 1047 | { | 1073 | "CreateSymbolicLinkA"); |
| 1048 | TOKEN_PRIVILEGES priv_current; | 1074 | } |
| 1075 | if (s_pfn_Create_Symbolic_LinkA == NULL) | ||
| 1076 | { | ||
| 1077 | errno = ENOSYS; | ||
| 1078 | return 0; | ||
| 1079 | } | ||
| 1049 | 1080 | ||
| 1050 | if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE, &priv_current)) | 1081 | filename_to_ansi (lpSymlinkFilename, symfn_a); |
| 1082 | filename_to_ansi (lpTargetFileName, tgtfn_a); | ||
| 1083 | retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags); | ||
| 1084 | /* If we were denied creation of the symlink, try again after | ||
| 1085 | enabling the SeCreateSymbolicLinkPrivilege for our process. */ | ||
| 1086 | if (!retval) | ||
| 1051 | { | 1087 | { |
| 1052 | retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName, | 1088 | TOKEN_PRIVILEGES priv_current; |
| 1053 | dwFlags); | 1089 | |
| 1054 | restore_privilege (&priv_current); | 1090 | if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE, |
| 1055 | revert_to_self (); | 1091 | &priv_current)) |
| 1092 | { | ||
| 1093 | retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags); | ||
| 1094 | restore_privilege (&priv_current); | ||
| 1095 | revert_to_self (); | ||
| 1096 | } | ||
| 1056 | } | 1097 | } |
| 1057 | } | 1098 | } |
| 1058 | return retval; | 1099 | return retval; |
| @@ -5027,10 +5068,9 @@ utime (const char *name, struct utimbuf *times) | |||
| 5027 | int | 5068 | int |
| 5028 | symlink (char const *filename, char const *linkname) | 5069 | symlink (char const *filename, char const *linkname) |
| 5029 | { | 5070 | { |
| 5030 | char linkfn[MAX_PATH], *tgtfn; | 5071 | char linkfn[MAX_UTF8_PATH], *tgtfn; |
| 5031 | DWORD flags = 0; | 5072 | DWORD flags = 0; |
| 5032 | int dir_access, filename_ends_in_slash; | 5073 | int dir_access, filename_ends_in_slash; |
| 5033 | int dbcs_p; | ||
| 5034 | 5074 | ||
| 5035 | /* Diagnostics follows Posix as much as possible. */ | 5075 | /* Diagnostics follows Posix as much as possible. */ |
| 5036 | if (filename == NULL || linkname == NULL) | 5076 | if (filename == NULL || linkname == NULL) |
| @@ -5043,7 +5083,7 @@ symlink (char const *filename, char const *linkname) | |||
| 5043 | errno = ENOENT; | 5083 | errno = ENOENT; |
| 5044 | return -1; | 5084 | return -1; |
| 5045 | } | 5085 | } |
| 5046 | if (strlen (filename) > MAX_PATH || strlen (linkname) > MAX_PATH) | 5086 | if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH) |
| 5047 | { | 5087 | { |
| 5048 | errno = ENAMETOOLONG; | 5088 | errno = ENAMETOOLONG; |
| 5049 | return -1; | 5089 | return -1; |
| @@ -5056,8 +5096,6 @@ symlink (char const *filename, char const *linkname) | |||
| 5056 | return -1; | 5096 | return -1; |
| 5057 | } | 5097 | } |
| 5058 | 5098 | ||
| 5059 | dbcs_p = max_filename_mbslen () > 1; | ||
| 5060 | |||
| 5061 | /* Note: since empty FILENAME was already rejected, we can safely | 5099 | /* Note: since empty FILENAME was already rejected, we can safely |
| 5062 | refer to FILENAME[1]. */ | 5100 | refer to FILENAME[1]. */ |
| 5063 | if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1]))) | 5101 | if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1]))) |
| @@ -5069,24 +5107,11 @@ symlink (char const *filename, char const *linkname) | |||
| 5069 | directory where the Emacs process runs. Note that | 5107 | directory where the Emacs process runs. Note that |
| 5070 | make-symbolic-link always makes sure LINKNAME is a fully | 5108 | make-symbolic-link always makes sure LINKNAME is a fully |
| 5071 | expanded file name. */ | 5109 | expanded file name. */ |
| 5072 | char tem[MAX_PATH]; | 5110 | char tem[MAX_UTF8_PATH]; |
| 5073 | char *p = linkfn + strlen (linkfn); | 5111 | char *p = linkfn + strlen (linkfn); |
| 5074 | 5112 | ||
| 5075 | if (!dbcs_p) | 5113 | while (p > linkfn && !IS_ANY_SEP (p[-1])) |
| 5076 | { | 5114 | p--; |
| 5077 | while (p > linkfn && !IS_ANY_SEP (p[-1])) | ||
| 5078 | p--; | ||
| 5079 | } | ||
| 5080 | else | ||
| 5081 | { | ||
| 5082 | char *p1 = CharPrevExA (file_name_codepage, linkfn, p, 0); | ||
| 5083 | |||
| 5084 | while (p > linkfn && !IS_ANY_SEP (*p1)) | ||
| 5085 | { | ||
| 5086 | p = p1; | ||
| 5087 | p1 = CharPrevExA (file_name_codepage, linkfn, p1, 0); | ||
| 5088 | } | ||
| 5089 | } | ||
| 5090 | if (p > linkfn) | 5115 | if (p > linkfn) |
| 5091 | strncpy (tem, linkfn, p - linkfn); | 5116 | strncpy (tem, linkfn, p - linkfn); |
| 5092 | tem[p - linkfn] = '\0'; | 5117 | tem[p - linkfn] = '\0'; |
| @@ -5101,15 +5126,7 @@ symlink (char const *filename, char const *linkname) | |||
| 5101 | exist, but ends in a slash, we create a symlink to directory. If | 5126 | exist, but ends in a slash, we create a symlink to directory. If |
| 5102 | FILENAME exists and is a directory, we always create a symlink to | 5127 | FILENAME exists and is a directory, we always create a symlink to |
| 5103 | directory. */ | 5128 | directory. */ |
| 5104 | if (!dbcs_p) | 5129 | filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]); |
| 5105 | filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]); | ||
| 5106 | else | ||
| 5107 | { | ||
| 5108 | const char *end = filename + strlen (filename); | ||
| 5109 | const char *n = CharPrevExA (file_name_codepage, filename, end, 0); | ||
| 5110 | |||
| 5111 | filename_ends_in_slash = IS_DIRECTORY_SEP (*n); | ||
| 5112 | } | ||
| 5113 | if (dir_access == 0 || filename_ends_in_slash) | 5130 | if (dir_access == 0 || filename_ends_in_slash) |
| 5114 | flags = SYMBOLIC_LINK_FLAG_DIRECTORY; | 5131 | flags = SYMBOLIC_LINK_FLAG_DIRECTORY; |
| 5115 | 5132 | ||
| @@ -5179,10 +5196,23 @@ static int | |||
| 5179 | is_symlink (const char *filename) | 5196 | is_symlink (const char *filename) |
| 5180 | { | 5197 | { |
| 5181 | DWORD attrs; | 5198 | DWORD attrs; |
| 5182 | WIN32_FIND_DATA wfd; | 5199 | wchar_t filename_w[MAX_PATH]; |
| 5200 | char filename_a[MAX_PATH]; | ||
| 5201 | WIN32_FIND_DATAW wfdw; | ||
| 5202 | WIN32_FIND_DATAA wfda; | ||
| 5183 | HANDLE fh; | 5203 | HANDLE fh; |
| 5204 | int attrs_mean_symlink; | ||
| 5184 | 5205 | ||
| 5185 | attrs = GetFileAttributes (filename); | 5206 | if (w32_unicode_filenames) |
| 5207 | { | ||
| 5208 | filename_to_utf16 (filename, filename_w); | ||
| 5209 | attrs = GetFileAttributesW (filename_w); | ||
| 5210 | } | ||
| 5211 | else | ||
| 5212 | { | ||
| 5213 | filename_to_ansi (filename, filename_a); | ||
| 5214 | attrs = GetFileAttributesA (filename_a); | ||
| 5215 | } | ||
| 5186 | if (attrs == -1) | 5216 | if (attrs == -1) |
| 5187 | { | 5217 | { |
| 5188 | DWORD w32err = GetLastError (); | 5218 | DWORD w32err = GetLastError (); |
| @@ -5205,12 +5235,30 @@ is_symlink (const char *filename) | |||
| 5205 | if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0) | 5235 | if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0) |
| 5206 | return 0; | 5236 | return 0; |
| 5207 | logon_network_drive (filename); | 5237 | logon_network_drive (filename); |
| 5208 | fh = FindFirstFile (filename, &wfd); | 5238 | if (w32_unicode_filenames) |
| 5239 | { | ||
| 5240 | fh = FindFirstFileW (filename_w, &wfdw); | ||
| 5241 | attrs_mean_symlink = | ||
| 5242 | (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0 | ||
| 5243 | && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK; | ||
| 5244 | } | ||
| 5245 | else if (_mbspbrk (filename_a, "?")) | ||
| 5246 | { | ||
| 5247 | /* filename_to_ansi failed to convert the file name. */ | ||
| 5248 | errno = ENOENT; | ||
| 5249 | return 0; | ||
| 5250 | } | ||
| 5251 | else | ||
| 5252 | { | ||
| 5253 | fh = FindFirstFileA (filename_a, &wfda); | ||
| 5254 | attrs_mean_symlink = | ||
| 5255 | (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0 | ||
| 5256 | && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK; | ||
| 5257 | } | ||
| 5209 | if (fh == INVALID_HANDLE_VALUE) | 5258 | if (fh == INVALID_HANDLE_VALUE) |
| 5210 | return 0; | 5259 | return 0; |
| 5211 | FindClose (fh); | 5260 | FindClose (fh); |
| 5212 | return (wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0 | 5261 | return attrs_mean_symlink; |
| 5213 | && (wfd.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK; | ||
| 5214 | } | 5262 | } |
| 5215 | 5263 | ||
| 5216 | /* If NAME identifies a symbolic link, copy into BUF the file name of | 5264 | /* If NAME identifies a symbolic link, copy into BUF the file name of |
| @@ -5227,6 +5275,7 @@ readlink (const char *name, char *buf, size_t buf_size) | |||
| 5227 | int restore_privs = 0; | 5275 | int restore_privs = 0; |
| 5228 | HANDLE sh; | 5276 | HANDLE sh; |
| 5229 | ssize_t retval; | 5277 | ssize_t retval; |
| 5278 | char resolved[MAX_UTF8_PATH]; | ||
| 5230 | 5279 | ||
| 5231 | if (name == NULL) | 5280 | if (name == NULL) |
| 5232 | { | 5281 | { |
| @@ -5241,7 +5290,7 @@ readlink (const char *name, char *buf, size_t buf_size) | |||
| 5241 | 5290 | ||
| 5242 | path = map_w32_filename (name, NULL); | 5291 | path = map_w32_filename (name, NULL); |
| 5243 | 5292 | ||
| 5244 | if (strlen (path) > MAX_PATH) | 5293 | if (strlen (path) > MAX_UTF8_PATH) |
| 5245 | { | 5294 | { |
| 5246 | errno = ENAMETOOLONG; | 5295 | errno = ENAMETOOLONG; |
| 5247 | return -1; | 5296 | return -1; |
| @@ -5271,9 +5320,26 @@ readlink (const char *name, char *buf, size_t buf_size) | |||
| 5271 | e.g. 'C:\Users\All Users', GENERIC_READ fails with | 5320 | e.g. 'C:\Users\All Users', GENERIC_READ fails with |
| 5272 | ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file | 5321 | ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file |
| 5273 | and directory symlinks. */ | 5322 | and directory symlinks. */ |
| 5274 | sh = CreateFile (path, 0, 0, NULL, OPEN_EXISTING, | 5323 | if (w32_unicode_filenames) |
| 5275 | FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, | 5324 | { |
| 5276 | NULL); | 5325 | wchar_t path_w[MAX_PATH]; |
| 5326 | |||
| 5327 | filename_to_utf16 (path, path_w); | ||
| 5328 | sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING, | ||
| 5329 | FILE_FLAG_OPEN_REPARSE_POINT | ||
| 5330 | | FILE_FLAG_BACKUP_SEMANTICS, | ||
| 5331 | NULL); | ||
| 5332 | } | ||
| 5333 | else | ||
| 5334 | { | ||
| 5335 | char path_a[MAX_PATH]; | ||
| 5336 | |||
| 5337 | filename_to_ansi (path, path_a); | ||
| 5338 | sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING, | ||
| 5339 | FILE_FLAG_OPEN_REPARSE_POINT | ||
| 5340 | | FILE_FLAG_BACKUP_SEMANTICS, | ||
| 5341 | NULL); | ||
| 5342 | } | ||
| 5277 | if (sh != INVALID_HANDLE_VALUE) | 5343 | if (sh != INVALID_HANDLE_VALUE) |
| 5278 | { | 5344 | { |
| 5279 | BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; | 5345 | BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; |
| @@ -5292,89 +5358,27 @@ readlink (const char *name, char *buf, size_t buf_size) | |||
| 5292 | reparse_data, then convert it to multibyte encoding in | 5358 | reparse_data, then convert it to multibyte encoding in |
| 5293 | the current locale's codepage. */ | 5359 | the current locale's codepage. */ |
| 5294 | WCHAR *lwname; | 5360 | WCHAR *lwname; |
| 5295 | BYTE lname[MAX_PATH]; | 5361 | size_t lname_size; |
| 5296 | USHORT lname_len; | ||
| 5297 | USHORT lwname_len = | 5362 | USHORT lwname_len = |
| 5298 | reparse_data->SymbolicLinkReparseBuffer.PrintNameLength; | 5363 | reparse_data->SymbolicLinkReparseBuffer.PrintNameLength; |
| 5299 | WCHAR *lwname_src = | 5364 | WCHAR *lwname_src = |
| 5300 | reparse_data->SymbolicLinkReparseBuffer.PathBuffer | 5365 | reparse_data->SymbolicLinkReparseBuffer.PathBuffer |
| 5301 | + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR); | 5366 | + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR); |
| 5302 | /* This updates file_name_codepage which we need below. */ | 5367 | size_t size_to_copy = buf_size; |
| 5303 | int dbcs_p = max_filename_mbslen () > 1; | ||
| 5304 | 5368 | ||
| 5305 | /* According to MSDN, PrintNameLength does not include the | 5369 | /* According to MSDN, PrintNameLength does not include the |
| 5306 | terminating null character. */ | 5370 | terminating null character. */ |
| 5307 | lwname = alloca ((lwname_len + 1) * sizeof(WCHAR)); | 5371 | lwname = alloca ((lwname_len + 1) * sizeof(WCHAR)); |
| 5308 | memcpy (lwname, lwname_src, lwname_len); | 5372 | memcpy (lwname, lwname_src, lwname_len); |
| 5309 | lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */ | 5373 | lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */ |
| 5310 | 5374 | filename_from_utf16 (lwname, resolved); | |
| 5311 | lname_len = WideCharToMultiByte (file_name_codepage, 0, lwname, -1, | 5375 | dostounix_filename (resolved); |
| 5312 | lname, MAX_PATH, NULL, NULL); | 5376 | lname_size = strlen (resolved) + 1; |
| 5313 | if (!lname_len) | 5377 | if (lname_size <= buf_size) |
| 5314 | { | 5378 | size_to_copy = lname_size; |
| 5315 | /* WideCharToMultiByte failed. */ | 5379 | strncpy (buf, resolved, size_to_copy); |
| 5316 | DWORD w32err1 = GetLastError (); | 5380 | /* Success! */ |
| 5317 | 5381 | retval = size_to_copy; | |
| 5318 | switch (w32err1) | ||
| 5319 | { | ||
| 5320 | case ERROR_INSUFFICIENT_BUFFER: | ||
| 5321 | errno = ENAMETOOLONG; | ||
| 5322 | break; | ||
| 5323 | case ERROR_INVALID_PARAMETER: | ||
| 5324 | errno = EFAULT; | ||
| 5325 | break; | ||
| 5326 | case ERROR_NO_UNICODE_TRANSLATION: | ||
| 5327 | errno = ENOENT; | ||
| 5328 | break; | ||
| 5329 | default: | ||
| 5330 | errno = EINVAL; | ||
| 5331 | break; | ||
| 5332 | } | ||
| 5333 | } | ||
| 5334 | else | ||
| 5335 | { | ||
| 5336 | size_t size_to_copy = buf_size; | ||
| 5337 | BYTE *p = lname, *p2; | ||
| 5338 | BYTE *pend = p + lname_len; | ||
| 5339 | |||
| 5340 | /* Normalize like dostounix_filename does, but we don't | ||
| 5341 | want to assume that lname is null-terminated. */ | ||
| 5342 | if (dbcs_p) | ||
| 5343 | p2 = CharNextExA (file_name_codepage, p, 0); | ||
| 5344 | else | ||
| 5345 | p2 = p + 1; | ||
| 5346 | if (*p && *p2 == ':' && *p >= 'A' && *p <= 'Z') | ||
| 5347 | { | ||
| 5348 | *p += 'a' - 'A'; | ||
| 5349 | p += 2; | ||
| 5350 | } | ||
| 5351 | while (p <= pend) | ||
| 5352 | { | ||
| 5353 | if (*p == '\\') | ||
| 5354 | *p = '/'; | ||
| 5355 | if (dbcs_p) | ||
| 5356 | { | ||
| 5357 | p = CharNextExA (file_name_codepage, p, 0); | ||
| 5358 | /* CharNextExA doesn't advance at null character. */ | ||
| 5359 | if (!*p) | ||
| 5360 | break; | ||
| 5361 | } | ||
| 5362 | else | ||
| 5363 | ++p; | ||
| 5364 | } | ||
| 5365 | /* Testing for null-terminated LNAME is paranoia: | ||
| 5366 | WideCharToMultiByte should always return a | ||
| 5367 | null-terminated string when its 4th argument is -1 | ||
| 5368 | and its 3rd argument is null-terminated (which they | ||
| 5369 | are, see above). */ | ||
| 5370 | if (lname[lname_len - 1] == '\0') | ||
| 5371 | lname_len--; | ||
| 5372 | if (lname_len <= buf_size) | ||
| 5373 | size_to_copy = lname_len; | ||
| 5374 | strncpy (buf, lname, size_to_copy); | ||
| 5375 | /* Success! */ | ||
| 5376 | retval = size_to_copy; | ||
| 5377 | } | ||
| 5378 | } | 5382 | } |
| 5379 | CloseHandle (sh); | 5383 | CloseHandle (sh); |
| 5380 | } | 5384 | } |
| @@ -5413,7 +5417,7 @@ readlinkat (int fd, char const *name, char *buffer, | |||
| 5413 | { | 5417 | { |
| 5414 | /* Rely on a hack: an open directory is modeled as file descriptor 0, | 5418 | /* Rely on a hack: an open directory is modeled as file descriptor 0, |
| 5415 | as in fstatat. FIXME: Add proper support for readlinkat. */ | 5419 | as in fstatat. FIXME: Add proper support for readlinkat. */ |
| 5416 | char fullname[MAX_PATH]; | 5420 | char fullname[MAX_UTF8_PATH]; |
| 5417 | 5421 | ||
| 5418 | if (fd != AT_FDCWD) | 5422 | if (fd != AT_FDCWD) |
| 5419 | { | 5423 | { |
| @@ -5452,41 +5456,45 @@ readlinkat (int fd, char const *name, char *buffer, | |||
| 5452 | static char * | 5456 | static char * |
| 5453 | chase_symlinks (const char *file) | 5457 | chase_symlinks (const char *file) |
| 5454 | { | 5458 | { |
| 5455 | static char target[MAX_PATH]; | 5459 | static char target[MAX_UTF8_PATH]; |
| 5456 | char link[MAX_PATH]; | 5460 | char link[MAX_UTF8_PATH]; |
| 5461 | wchar_t target_w[MAX_PATH], link_w[MAX_PATH]; | ||
| 5462 | char target_a[MAX_PATH], link_a[MAX_PATH]; | ||
| 5457 | ssize_t res, link_len; | 5463 | ssize_t res, link_len; |
| 5458 | int loop_count = 0; | 5464 | int loop_count = 0; |
| 5459 | int dbcs_p; | ||
| 5460 | 5465 | ||
| 5461 | if (is_windows_9x () == TRUE || !is_symlink (file)) | 5466 | if (is_windows_9x () == TRUE || !is_symlink (file)) |
| 5462 | return (char *)file; | 5467 | return (char *)file; |
| 5463 | 5468 | ||
| 5464 | if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0) | 5469 | if (w32_unicode_filenames) |
| 5465 | return (char *)file; | 5470 | { |
| 5471 | wchar_t file_w[MAX_PATH]; | ||
| 5472 | |||
| 5473 | filename_to_utf16 (file, file_w); | ||
| 5474 | if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0) | ||
| 5475 | return (char *)file; | ||
| 5476 | filename_from_utf16 (link_w, link); | ||
| 5477 | } | ||
| 5478 | else | ||
| 5479 | { | ||
| 5480 | char file_a[MAX_PATH]; | ||
| 5481 | |||
| 5482 | filename_to_ansi (file, file_a); | ||
| 5483 | if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0) | ||
| 5484 | return (char *)file; | ||
| 5485 | filename_from_ansi (link_a, link); | ||
| 5486 | } | ||
| 5487 | link_len = strlen (link); | ||
| 5466 | 5488 | ||
| 5467 | dbcs_p = max_filename_mbslen () > 1; | ||
| 5468 | target[0] = '\0'; | 5489 | target[0] = '\0'; |
| 5469 | do { | 5490 | do { |
| 5470 | 5491 | ||
| 5471 | /* Remove trailing slashes, as we want to resolve the last | 5492 | /* Remove trailing slashes, as we want to resolve the last |
| 5472 | non-trivial part of the link name. */ | 5493 | non-trivial part of the link name. */ |
| 5473 | if (!dbcs_p) | 5494 | while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1])) |
| 5474 | { | 5495 | link[link_len--] = '\0'; |
| 5475 | while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1])) | ||
| 5476 | link[link_len--] = '\0'; | ||
| 5477 | } | ||
| 5478 | else if (link_len > 3) | ||
| 5479 | { | ||
| 5480 | char *n = CharPrevExA (file_name_codepage, link, link + link_len, 0); | ||
| 5481 | |||
| 5482 | while (n >= link + 2 && IS_DIRECTORY_SEP (*n)) | ||
| 5483 | { | ||
| 5484 | n[1] = '\0'; | ||
| 5485 | n = CharPrevExA (file_name_codepage, link, n, 0); | ||
| 5486 | } | ||
| 5487 | } | ||
| 5488 | 5496 | ||
| 5489 | res = readlink (link, target, MAX_PATH); | 5497 | res = readlink (link, target, MAX_UTF8_PATH); |
| 5490 | if (res > 0) | 5498 | if (res > 0) |
| 5491 | { | 5499 | { |
| 5492 | target[res] = '\0'; | 5500 | target[res] = '\0'; |
| @@ -5497,27 +5505,28 @@ chase_symlinks (const char *file) | |||
| 5497 | the symlink, then copy the result back to target. */ | 5505 | the symlink, then copy the result back to target. */ |
| 5498 | char *p = link + link_len; | 5506 | char *p = link + link_len; |
| 5499 | 5507 | ||
| 5500 | if (!dbcs_p) | 5508 | while (p > link && !IS_ANY_SEP (p[-1])) |
| 5501 | { | 5509 | p--; |
| 5502 | while (p > link && !IS_ANY_SEP (p[-1])) | ||
| 5503 | p--; | ||
| 5504 | } | ||
| 5505 | else | ||
| 5506 | { | ||
| 5507 | char *p1 = CharPrevExA (file_name_codepage, link, p, 0); | ||
| 5508 | |||
| 5509 | while (p > link && !IS_ANY_SEP (*p1)) | ||
| 5510 | { | ||
| 5511 | p = p1; | ||
| 5512 | p1 = CharPrevExA (file_name_codepage, link, p1, 0); | ||
| 5513 | } | ||
| 5514 | } | ||
| 5515 | strcpy (p, target); | 5510 | strcpy (p, target); |
| 5516 | strcpy (target, link); | 5511 | strcpy (target, link); |
| 5517 | } | 5512 | } |
| 5518 | /* Resolve any "." and ".." to get a fully-qualified file name | 5513 | /* Resolve any "." and ".." to get a fully-qualified file name |
| 5519 | in link[] again. */ | 5514 | in link[] again. */ |
| 5520 | link_len = GetFullPathName (target, MAX_PATH, link, NULL); | 5515 | if (w32_unicode_filenames) |
| 5516 | { | ||
| 5517 | filename_to_utf16 (target, target_w); | ||
| 5518 | link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL); | ||
| 5519 | if (link_len > 0) | ||
| 5520 | filename_from_utf16 (link_w, link); | ||
| 5521 | } | ||
| 5522 | else | ||
| 5523 | { | ||
| 5524 | filename_to_ansi (target, target_a); | ||
| 5525 | link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL); | ||
| 5526 | if (link_len > 0) | ||
| 5527 | filename_from_ansi (link_a, link); | ||
| 5528 | } | ||
| 5529 | link_len = strlen (link); | ||
| 5521 | } | 5530 | } |
| 5522 | } while (res > 0 && link_len > 0 && ++loop_count <= 100); | 5531 | } while (res > 0 && link_len > 0 && ++loop_count <= 100); |
| 5523 | 5532 | ||
| @@ -5778,7 +5787,7 @@ careadlinkat (int fd, char const *filename, | |||
| 5778 | struct allocator const *alloc, | 5787 | struct allocator const *alloc, |
| 5779 | ssize_t (*preadlinkat) (int, char const *, char *, size_t)) | 5788 | ssize_t (*preadlinkat) (int, char const *, char *, size_t)) |
| 5780 | { | 5789 | { |
| 5781 | char linkname[MAX_PATH]; | 5790 | char linkname[MAX_UTF8_PATH]; |
| 5782 | ssize_t link_size; | 5791 | ssize_t link_size; |
| 5783 | 5792 | ||
| 5784 | link_size = preadlinkat (fd, filename, linkname, sizeof(linkname)); | 5793 | link_size = preadlinkat (fd, filename, linkname, sizeof(linkname)); |
| @@ -8486,7 +8495,8 @@ globals_of_w32 (void) | |||
| 8486 | g_b_init_get_length_sid = 0; | 8495 | g_b_init_get_length_sid = 0; |
| 8487 | g_b_init_get_native_system_info = 0; | 8496 | g_b_init_get_native_system_info = 0; |
| 8488 | g_b_init_get_system_times = 0; | 8497 | g_b_init_get_system_times = 0; |
| 8489 | g_b_init_create_symbolic_link = 0; | 8498 | g_b_init_create_symbolic_link_w = 0; |
| 8499 | g_b_init_create_symbolic_link_a = 0; | ||
| 8490 | g_b_init_get_security_descriptor_dacl = 0; | 8500 | g_b_init_get_security_descriptor_dacl = 0; |
| 8491 | g_b_init_convert_sd_to_sddl = 0; | 8501 | g_b_init_convert_sd_to_sddl = 0; |
| 8492 | g_b_init_convert_sddl_to_sd = 0; | 8502 | g_b_init_convert_sddl_to_sd = 0; |