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
This commit is contained in:
Lars Kanis 2022-11-17 10:57:52 +01:00 committed by GitHub
parent 71e668e633
commit 7b1d23fd29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
Notes: git 2022-11-17 09:58:21 +00:00
Merged-By: ioquatix <samuel@codeotaku.com>
5 changed files with 22 additions and 66 deletions

4
file.c
View File

@ -115,6 +115,8 @@ int flock(int, int);
# define link(f, t) rb_w32_ulink((f), (t))
# undef unlink
# define unlink(p) rb_w32_uunlink(p)
# undef readlink
# define readlink(f, t, l) rb_w32_ureadlink((f), (t), (l))
# undef rename
# define rename(f, t) rb_w32_urename((f), (t))
# undef symlink
@ -3152,7 +3154,6 @@ rb_file_s_readlink(VALUE klass, VALUE path)
return rb_readlink(path, rb_filesystem_encoding());
}
#ifndef _WIN32
struct readlink_arg {
const char *path;
char *buf;
@ -3208,7 +3209,6 @@ rb_readlink(VALUE path, rb_encoding *enc)
return v;
}
#endif
#else
#define rb_file_s_readlink rb_f_notimplement
#endif

View File

@ -302,7 +302,6 @@ extern DWORD rb_w32_osver(void);
extern int rb_w32_uchown(const char *, int, int);
extern int rb_w32_ulink(const char *, const char *);
extern ssize_t rb_w32_ureadlink(const char *, char *, size_t);
extern ssize_t rb_w32_wreadlink(const WCHAR *, WCHAR *, size_t);
extern int rb_w32_usymlink(const char *src, const char *link);
extern int gettimeofday(struct timeval *, struct timezone *);
extern int clock_gettime(clockid_t, struct timespec *);

View File

@ -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)
{

View File

@ -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;

View File

@ -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;
}