diff options
author | Lars Kanis <[email protected]> | 2022-11-17 10:57:52 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2022-11-17 01:57:52 -0800 |
commit | 7b1d23fd295fe8275b313f31ea545f7f6b3f2e62 (patch) | |
tree | 6da8827ada67a79daee059f1228df11eaeb94a5b /win32 | |
parent | 71e668e63383030adc06893d0b16a16e9abdabce (diff) |
Windows: Readlink improvements (#6745)
* Windows: Use readlink emulation for File.readlink
This fixes readlink emulation for the ERROR_MORE_DATA case and general error reporting.
It now releases GVL while readlink IO operation.
The dedicated rb_readlink was introduced in commit 2ffb87995a33cdc7ba609a4b867f03f18da0c3b3
in order to improve encoding and buffer allocation.
However the encoding issues are solved since ruby-3.0 switched to UTF-8
and the buffer allocation will be improved in a later commit.
* Windows: Increase the default buffer size for reparse point info
So far nearly all queries of reparse points needed two attempts to get enough buffer.
* Windows: Remove declaration of rb_w32_wreadlink
It was removed in commit 2f6fdd3aebdee2ce04d003b206f6da78120e8235
Notes
Notes:
Merged-By: ioquatix <[email protected]>
Diffstat (limited to 'win32')
-rw-r--r-- | win32/file.c | 44 | ||||
-rw-r--r-- | win32/file.h | 8 | ||||
-rw-r--r-- | win32/win32.c | 31 |
3 files changed, 20 insertions, 63 deletions
diff --git a/win32/file.c b/win32/file.c index 243cb1722a..e047144d36 100644 --- a/win32/file.c +++ b/win32/file.c @@ -591,50 +591,6 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na return result; } -VALUE -rb_readlink(VALUE path, rb_encoding *resultenc) -{ - DWORD len; - VALUE wtmp = 0, wpathbuf, str; - rb_w32_reparse_buffer_t rbuf, *rp = &rbuf; - WCHAR *wpath, *wbuf; - rb_encoding *enc; - UINT cp, path_cp; - int e; - - FilePathValue(path); - enc = rb_enc_get(path); - cp = path_cp = code_page(enc); - if (cp == INVALID_CODE_PAGE) { - path = fix_string_encoding(path, enc); - cp = CP_UTF8; - } - len = MultiByteToWideChar(cp, 0, RSTRING_PTR(path), RSTRING_LEN(path), NULL, 0); - wpath = ALLOCV_N(WCHAR, wpathbuf, len+1); - MultiByteToWideChar(cp, 0, RSTRING_PTR(path), RSTRING_LEN(path), wpath, len); - wpath[len] = L'\0'; - e = rb_w32_read_reparse_point(wpath, rp, sizeof(rbuf), &wbuf, &len); - if (e == ERROR_MORE_DATA) { - size_t size = rb_w32_reparse_buffer_size(len + 1); - rp = ALLOCV(wtmp, size); - e = rb_w32_read_reparse_point(wpath, rp, size, &wbuf, &len); - } - ALLOCV_END(wpathbuf); - if (e) { - ALLOCV_END(wtmp); - if (e != -1) - rb_syserr_fail_path(rb_w32_map_errno(e), path); - else /* not symlink; maybe volume mount point */ - rb_syserr_fail_path(EINVAL, path); - } - enc = resultenc; - path_cp = code_page(enc); - len = lstrlenW(wbuf); - str = append_wstr(rb_enc_str_new(0, 0, enc), wbuf, len, path_cp, enc); - ALLOCV_END(wtmp); - return str; -} - int rb_file_load_ok(const char *path) { diff --git a/win32/file.h b/win32/file.h index 36ff27c9b1..ef701487dd 100644 --- a/win32/file.h +++ b/win32/file.h @@ -1,10 +1,8 @@ #ifndef RUBY_WIN32_FILE_H #define RUBY_WIN32_FILE_H -#define MAX_REPARSE_PATH_LEN 4092 - enum { - MINIMUM_REPARSE_BUFFER_PATH_LEN = 4 + MINIMUM_REPARSE_BUFFER_PATH_LEN = 100 }; /* License: Ruby's */ typedef struct { @@ -18,14 +16,14 @@ typedef struct { USHORT PrintNameOffset; USHORT PrintNameLength; ULONG Flags; - WCHAR PathBuffer[4]; + WCHAR PathBuffer[MINIMUM_REPARSE_BUFFER_PATH_LEN]; } SymbolicLinkReparseBuffer; struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; - WCHAR PathBuffer[4]; + WCHAR PathBuffer[MINIMUM_REPARSE_BUFFER_PATH_LEN]; } MountPointReparseBuffer; }; } rb_w32_reparse_buffer_t; diff --git a/win32/win32.c b/win32/win32.c index 865edc8aa6..3ddfe9bfdf 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -5144,32 +5144,35 @@ rb_w32_read_reparse_point(const WCHAR *path, rb_w32_reparse_buffer_t *rp, static ssize_t w32_readlink(UINT cp, const char *path, char *buf, size_t bufsize) { - VALUE wtmp; + VALUE rp_buf, rp_buf_bigger = 0; DWORD len = MultiByteToWideChar(cp, 0, path, -1, NULL, 0); - size_t size = rb_w32_reparse_buffer_size(len); - WCHAR *wname, *wpath = ALLOCV(wtmp, size + sizeof(WCHAR) * len); + size_t size = rb_w32_reparse_buffer_size(bufsize); + WCHAR *wname; + WCHAR *wpath = ALLOCV(rp_buf, sizeof(WCHAR) * len + size); rb_w32_reparse_buffer_t *rp = (void *)(wpath + len); ssize_t ret; int e; MultiByteToWideChar(cp, 0, path, -1, wpath, len); e = rb_w32_read_reparse_point(wpath, rp, size, &wname, &len); - if (e && e != ERROR_MORE_DATA) { - ALLOCV_END(wtmp); - errno = map_errno(e); + if (e == ERROR_MORE_DATA) { + size = rb_w32_reparse_buffer_size(len + 1); + rp = ALLOCV(rp_buf_bigger, size); + e = rb_w32_read_reparse_point(wpath, rp, size, &wname, &len); + } + if (e) { + ALLOCV_END(rp_buf); + ALLOCV_END(rp_buf_bigger); + errno = e == -1 ? EINVAL : map_errno(e); return -1; } - len = lstrlenW(wname) + 1; + len = lstrlenW(wname); ret = WideCharToMultiByte(cp, 0, wname, len, buf, bufsize, NULL, NULL); - ALLOCV_END(wtmp); - if (e) { + ALLOCV_END(rp_buf); + ALLOCV_END(rp_buf_bigger); + if (!ret) { ret = bufsize; } - else if (!ret) { - e = GetLastError(); - errno = map_errno(e); - ret = -1; - } return ret; } |