aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2013-11-23 13:16:36 +0200
committerEli Zaretskii2013-11-23 13:16:36 +0200
commiteeccd06f852001648e0307ce07f2687029b18889 (patch)
treeef24860d81c67af592db12867272a05d11f06fa9 /src
parent18b35e2c7a3ff95fb4a07e58c3f57c70c65c0701 (diff)
downloademacs-eeccd06f852001648e0307ce07f2687029b18889.tar.gz
emacs-eeccd06f852001648e0307ce07f2687029b18889.zip
Converted symlink-related functions with minimal testing.
Diffstat (limited to 'src')
-rw-r--r--src/fileio.c4
-rw-r--r--src/w32.c382
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);
diff --git a/src/w32.c b/src/w32.c
index 64fdd47a86a..999f2dd8109 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -293,7 +293,8 @@ static BOOL g_b_init_equal_sid;
293static BOOL g_b_init_copy_sid; 293static BOOL g_b_init_copy_sid;
294static BOOL g_b_init_get_native_system_info; 294static BOOL g_b_init_get_native_system_info;
295static BOOL g_b_init_get_system_times; 295static BOOL g_b_init_get_system_times;
296static BOOL g_b_init_create_symbolic_link; 296static BOOL g_b_init_create_symbolic_link_w;
297static BOOL g_b_init_create_symbolic_link_a;
297static BOOL g_b_init_get_security_descriptor_dacl; 298static BOOL g_b_init_get_security_descriptor_dacl;
298static BOOL g_b_init_convert_sd_to_sddl; 299static BOOL g_b_init_convert_sd_to_sddl;
299static BOOL g_b_init_convert_sddl_to_sd; 300static 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);
431typedef BOOLEAN (WINAPI *CreateSymbolicLink_Proc) ( 432typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
432 LPTSTR lpSymlinkFileName, 433 LPCWSTR lpSymlinkFileName,
433 LPTSTR lpTargetFileName, 434 LPCWSTR lpTargetFileName,
435 DWORD dwFlags);
436typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
437 LPCSTR lpSymlinkFileName,
438 LPCSTR lpTargetFileName,
434 DWORD dwFlags); 439 DWORD dwFlags);
435typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) ( 440typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
436 LPCTSTR StringSecurityDescriptor, 441 LPCTSTR StringSecurityDescriptor,
@@ -1008,11 +1013,12 @@ get_system_times (LPFILETIME lpIdleTime,
1008} 1013}
1009 1014
1010static BOOLEAN WINAPI 1015static BOOLEAN WINAPI
1011create_symbolic_link (LPTSTR lpSymlinkFilename, 1016create_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)
5027int 5068int
5028symlink (char const *filename, char const *linkname) 5069symlink (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
5179is_symlink (const char *filename) 5196is_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,
5452static char * 5456static char *
5453chase_symlinks (const char *file) 5457chase_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;