aboutsummaryrefslogtreecommitdiffstats
path: root/win32
diff options
context:
space:
mode:
authorLars Kanis <kanis@comcard.de>2022-11-17 10:57:52 +0100
committerGitHub <noreply@github.com>2022-11-17 01:57:52 -0800
commit7b1d23fd295fe8275b313f31ea545f7f6b3f2e62 (patch)
tree6da8827ada67a79daee059f1228df11eaeb94a5b /win32
parent71e668e63383030adc06893d0b16a16e9abdabce (diff)
downloadruby-7b1d23fd295fe8275b313f31ea545f7f6b3f2e62.tar.gz
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
Diffstat (limited to 'win32')
-rw-r--r--win32/file.c44
-rw-r--r--win32/file.h8
-rw-r--r--win32/win32.c31
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;
}