win32.c: rb_w32_reparse
* win32/win32.c (rb_w32_reparse): read reparse point in a dynamic buffer. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51676 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
b4b848e6a0
commit
2f6fdd3aeb
@ -710,9 +710,10 @@ prelude.$(OBJEXT): {$(VPATH)}prelude.c
|
|||||||
# dependencies for optional sources.
|
# dependencies for optional sources.
|
||||||
compile.$(OBJEXT): {$(VPATH)}opt_sc.inc {$(VPATH)}optunifs.inc
|
compile.$(OBJEXT): {$(VPATH)}opt_sc.inc {$(VPATH)}optunifs.inc
|
||||||
|
|
||||||
win32/win32.$(OBJEXT): {$(VPATH)}win32/win32.c {$(VPATH)}dln.h {$(VPATH)}dln_find.c \
|
win32/win32.$(OBJEXT): {$(VPATH)}win32/win32.c {$(VPATH)}win32/file.h \
|
||||||
|
{$(VPATH)}dln.h {$(VPATH)}dln_find.c \
|
||||||
{$(VPATH)}internal.h {$(VPATH)}util.h $(RUBY_H_INCLUDES) $(PLATFORM_D)
|
{$(VPATH)}internal.h {$(VPATH)}util.h $(RUBY_H_INCLUDES) $(PLATFORM_D)
|
||||||
win32/file.$(OBJEXT): {$(VPATH)}win32/file.c {$(VPATH)}thread.h \
|
win32/file.$(OBJEXT): {$(VPATH)}win32/file.c {$(VPATH)}win32/file.h {$(VPATH)}thread.h \
|
||||||
$(RUBY_H_INCLUDES) $(PLATFORM_D)
|
$(RUBY_H_INCLUDES) $(PLATFORM_D)
|
||||||
|
|
||||||
$(NEWLINE_C): $(srcdir)/enc/trans/newline.trans $(srcdir)/tool/transcode-tblgen.rb
|
$(NEWLINE_C): $(srcdir)/enc/trans/newline.trans $(srcdir)/tool/transcode-tblgen.rb
|
||||||
|
26
win32/file.c
26
win32/file.c
@ -9,6 +9,7 @@
|
|||||||
#include <winbase.h>
|
#include <winbase.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
|
#include "win32/file.h"
|
||||||
|
|
||||||
#ifndef INVALID_FILE_ATTRIBUTES
|
#ifndef INVALID_FILE_ATTRIBUTES
|
||||||
# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
|
# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
|
||||||
@ -658,15 +659,16 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t rb_w32_wreadlink(const WCHAR *path, WCHAR *buf, size_t bufsize);
|
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_readlink(VALUE path)
|
rb_readlink(VALUE path)
|
||||||
{
|
{
|
||||||
ssize_t len;
|
DWORD len;
|
||||||
WCHAR *wpath, wbuf[MAX_PATH];
|
VALUE wtmp = 0, str;
|
||||||
|
rb_w32_reparse_buffer_t rbuf, *rp = &rbuf;
|
||||||
|
WCHAR *wpath, *wbuf;
|
||||||
rb_encoding *enc;
|
rb_encoding *enc;
|
||||||
UINT cp, path_cp;
|
UINT cp, path_cp;
|
||||||
|
int e;
|
||||||
|
|
||||||
FilePathValue(path);
|
FilePathValue(path);
|
||||||
enc = rb_enc_get(path);
|
enc = rb_enc_get(path);
|
||||||
@ -678,13 +680,23 @@ rb_readlink(VALUE path)
|
|||||||
wpath = mbstr_to_wstr(cp, RSTRING_PTR(path),
|
wpath = mbstr_to_wstr(cp, RSTRING_PTR(path),
|
||||||
RSTRING_LEN(path)+rb_enc_mbminlen(enc), NULL);
|
RSTRING_LEN(path)+rb_enc_mbminlen(enc), NULL);
|
||||||
if (!wpath) rb_memerror();
|
if (!wpath) rb_memerror();
|
||||||
len = rb_w32_wreadlink(wpath, wbuf, numberof(wbuf));
|
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);
|
||||||
|
}
|
||||||
free(wpath);
|
free(wpath);
|
||||||
if (len < 0) rb_sys_fail_path(path);
|
if (e) {
|
||||||
|
ALLOCV_END(wtmp);
|
||||||
|
rb_syserr_fail_path(rb_w32_map_errno(e), path);
|
||||||
|
}
|
||||||
enc = rb_filesystem_encoding();
|
enc = rb_filesystem_encoding();
|
||||||
cp = path_cp = code_page(enc);
|
cp = path_cp = code_page(enc);
|
||||||
if (cp == INVALID_CODE_PAGE) cp = CP_UTF8;
|
if (cp == INVALID_CODE_PAGE) cp = CP_UTF8;
|
||||||
return append_wstr(rb_enc_str_new(0, 0, enc), wbuf, len, cp, path_cp, enc);
|
str = append_wstr(rb_enc_str_new(0, 0, enc), wbuf, len, cp, path_cp, enc);
|
||||||
|
ALLOCV_END(wtmp);
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
|
40
win32/file.h
Normal file
40
win32/file.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef RUBY_WIN32_FILE_H
|
||||||
|
#define RUBY_WIN32_FILE_H
|
||||||
|
|
||||||
|
#define MAX_REPARSE_PATH_LEN 4092
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MINIMUM_REPARSE_BUFFER_PATH_LEN = 4
|
||||||
|
};
|
||||||
|
/* License: Ruby's */
|
||||||
|
typedef struct {
|
||||||
|
ULONG ReparseTag;
|
||||||
|
USHORT ReparseDataLength;
|
||||||
|
USHORT Reserved;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
USHORT SubstituteNameOffset;
|
||||||
|
USHORT SubstituteNameLength;
|
||||||
|
USHORT PrintNameOffset;
|
||||||
|
USHORT PrintNameLength;
|
||||||
|
ULONG Flags;
|
||||||
|
WCHAR PathBuffer[4];
|
||||||
|
} SymbolicLinkReparseBuffer;
|
||||||
|
struct {
|
||||||
|
USHORT SubstituteNameOffset;
|
||||||
|
USHORT SubstituteNameLength;
|
||||||
|
USHORT PrintNameOffset;
|
||||||
|
USHORT PrintNameLength;
|
||||||
|
WCHAR PathBuffer[4];
|
||||||
|
} MountPointReparseBuffer;
|
||||||
|
};
|
||||||
|
} rb_w32_reparse_buffer_t;
|
||||||
|
|
||||||
|
#define rb_w32_reparse_buffer_size(n) \
|
||||||
|
(sizeof(rb_w32_reparse_buffer_t) + \
|
||||||
|
sizeof(WCHAR)*((n)-MINIMUM_REPARSE_BUFFER_PATH_LEN))
|
||||||
|
|
||||||
|
int rb_w32_read_reparse_point(const WCHAR *path, rb_w32_reparse_buffer_t *rp,
|
||||||
|
size_t bufsize, WCHAR **result, DWORD *len);
|
||||||
|
|
||||||
|
#endif /* RUBY_WIN32_FILE_H */
|
111
win32/win32.c
111
win32/win32.c
@ -50,6 +50,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "ruby/win32.h"
|
#include "ruby/win32.h"
|
||||||
#include "win32/dir.h"
|
#include "win32/dir.h"
|
||||||
|
#include "win32/file.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#define isdirsep(x) ((x) == '/' || (x) == '\\')
|
#define isdirsep(x) ((x) == '/' || (x) == '\\')
|
||||||
|
|
||||||
@ -4667,33 +4668,9 @@ link(const char *from, const char *to)
|
|||||||
# define IO_REPARSE_TAG_SYMLINK 0xA000000CL
|
# define IO_REPARSE_TAG_SYMLINK 0xA000000CL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* License: Ruby's */
|
|
||||||
typedef struct {
|
|
||||||
ULONG ReparseTag;
|
|
||||||
USHORT ReparseDataLength;
|
|
||||||
USHORT Reserved;
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
USHORT SubstituteNameOffset;
|
|
||||||
USHORT SubstituteNameLength;
|
|
||||||
USHORT PrintNameOffset;
|
|
||||||
USHORT PrintNameLength;
|
|
||||||
ULONG Flags;
|
|
||||||
WCHAR PathBuffer[MAXPATHLEN * 2];
|
|
||||||
} SymbolicLinkReparseBuffer;
|
|
||||||
struct {
|
|
||||||
USHORT SubstituteNameOffset;
|
|
||||||
USHORT SubstituteNameLength;
|
|
||||||
USHORT PrintNameOffset;
|
|
||||||
USHORT PrintNameLength;
|
|
||||||
WCHAR PathBuffer[MAXPATHLEN * 2];
|
|
||||||
} MountPointReparseBuffer;
|
|
||||||
};
|
|
||||||
} reparse_buffer_t;
|
|
||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
static int
|
static int
|
||||||
reparse_symlink(const WCHAR *path, reparse_buffer_t *rp)
|
reparse_symlink(const WCHAR *path, rb_w32_reparse_buffer_t *rp, size_t size)
|
||||||
{
|
{
|
||||||
HANDLE f;
|
HANDLE f;
|
||||||
DWORD ret;
|
DWORD ret;
|
||||||
@ -4721,12 +4698,12 @@ reparse_symlink(const WCHAR *path, reparse_buffer_t *rp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!device_io_control(f, FSCTL_GET_REPARSE_POINT, NULL, 0,
|
if (!device_io_control(f, FSCTL_GET_REPARSE_POINT, NULL, 0,
|
||||||
rp, sizeof(*rp), &ret, NULL)) {
|
rp, size, &ret, NULL)) {
|
||||||
e = map_errno(GetLastError());
|
e = GetLastError();
|
||||||
}
|
}
|
||||||
else if (rp->ReparseTag != IO_REPARSE_TAG_SYMLINK &&
|
else if (rp->ReparseTag != IO_REPARSE_TAG_SYMLINK &&
|
||||||
rp->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) {
|
rp->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) {
|
||||||
e = EINVAL;
|
e = ERROR_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
CloseHandle(f);
|
CloseHandle(f);
|
||||||
return e;
|
return e;
|
||||||
@ -4736,69 +4713,87 @@ reparse_symlink(const WCHAR *path, reparse_buffer_t *rp)
|
|||||||
int
|
int
|
||||||
rb_w32_reparse_symlink_p(const WCHAR *path)
|
rb_w32_reparse_symlink_p(const WCHAR *path)
|
||||||
{
|
{
|
||||||
reparse_buffer_t rp;
|
rb_w32_reparse_buffer_t rp;
|
||||||
return reparse_symlink(path, &rp) == 0;
|
switch (reparse_symlink(path, &rp, sizeof(rp))) {
|
||||||
|
case 0:
|
||||||
|
case ERROR_MORE_DATA:
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
ssize_t
|
int
|
||||||
rb_w32_wreadlink(const WCHAR *path, WCHAR *buf, size_t bufsize)
|
rb_w32_read_reparse_point(const WCHAR *path, rb_w32_reparse_buffer_t *rp,
|
||||||
|
size_t bufsize, WCHAR **result, DWORD *len)
|
||||||
{
|
{
|
||||||
reparse_buffer_t rp;
|
int e = reparse_symlink(path, rp, bufsize);
|
||||||
int e = reparse_symlink(path, &rp);
|
|
||||||
DWORD ret;
|
DWORD ret;
|
||||||
|
|
||||||
if (!e) {
|
if (!e || e == ERROR_MORE_DATA) {
|
||||||
void *name;
|
void *name;
|
||||||
if (rp.ReparseTag == IO_REPARSE_TAG_SYMLINK) {
|
if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
|
||||||
name = ((char *)rp.SymbolicLinkReparseBuffer.PathBuffer +
|
name = ((char *)rp->SymbolicLinkReparseBuffer.PathBuffer +
|
||||||
rp.SymbolicLinkReparseBuffer.PrintNameOffset);
|
rp->SymbolicLinkReparseBuffer.PrintNameOffset);
|
||||||
ret = rp.SymbolicLinkReparseBuffer.PrintNameLength;
|
ret = rp->SymbolicLinkReparseBuffer.PrintNameLength;
|
||||||
}
|
}
|
||||||
else { /* IO_REPARSE_TAG_MOUNT_POINT */
|
else { /* IO_REPARSE_TAG_MOUNT_POINT */
|
||||||
/* +4/-4 means to drop "\??\" */
|
/* +4/-4 means to drop "\??\" */
|
||||||
name = ((char *)rp.MountPointReparseBuffer.PathBuffer +
|
name = ((char *)rp->MountPointReparseBuffer.PathBuffer +
|
||||||
rp.MountPointReparseBuffer.SubstituteNameOffset +
|
rp->MountPointReparseBuffer.SubstituteNameOffset +
|
||||||
4 * sizeof(WCHAR));
|
4 * sizeof(WCHAR));
|
||||||
ret = rp.MountPointReparseBuffer.SubstituteNameLength -
|
ret = rp->MountPointReparseBuffer.SubstituteNameLength -
|
||||||
4 * sizeof(WCHAR);
|
4 * sizeof(WCHAR);
|
||||||
}
|
}
|
||||||
|
*result = name;
|
||||||
|
*len = ret / sizeof(WCHAR);
|
||||||
|
if (e) {
|
||||||
|
if ((char *)name + ret + sizeof(WCHAR) > (char *)rp + bufsize)
|
||||||
|
return e;
|
||||||
|
/* SubstituteName is not used */
|
||||||
|
}
|
||||||
((WCHAR *)name)[ret/sizeof(WCHAR)] = L'\0';
|
((WCHAR *)name)[ret/sizeof(WCHAR)] = L'\0';
|
||||||
translate_wchar(name, L'\\', L'/');
|
translate_wchar(name, L'\\', L'/');
|
||||||
bufsize *= sizeof(WCHAR);
|
return 0;
|
||||||
memcpy(buf, name, ret > bufsize ? bufsize : ret);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
errno = e;
|
return e;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
return ret / sizeof(WCHAR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
static ssize_t
|
static ssize_t
|
||||||
w32_readlink(UINT cp, const char *path, char *buf, size_t bufsize)
|
w32_readlink(UINT cp, const char *path, char *buf, size_t bufsize)
|
||||||
{
|
{
|
||||||
WCHAR *wpath;
|
WCHAR *wpath, *wname;
|
||||||
WCHAR wbuf[MAXPATHLEN];
|
VALUE wtmp;
|
||||||
|
size_t size = rb_w32_reparse_buffer_size(bufsize);
|
||||||
|
rb_w32_reparse_buffer_t *rp = ALLOCV(wtmp, size);
|
||||||
|
DWORD len;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
int e;
|
||||||
|
|
||||||
wpath = mbstr_to_wstr(cp, path, -1, NULL);
|
wpath = mbstr_to_wstr(cp, path, -1, NULL);
|
||||||
if (!wpath) return -1;
|
if (!wpath) {
|
||||||
ret = rb_w32_wreadlink(wpath, wbuf, MAXPATHLEN);
|
ALLOCV_END(wtmp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
e = rb_w32_read_reparse_point(wpath, rp, size, &wname, &len);
|
||||||
free(wpath);
|
free(wpath);
|
||||||
if (ret < 0) return ret;
|
if (e && e != ERROR_MORE_DATA) {
|
||||||
ret = WideCharToMultiByte(cp, 0, wbuf, ret, buf, bufsize, NULL, NULL);
|
ALLOCV_END(wtmp);
|
||||||
if (!ret) {
|
errno = map_errno(e);
|
||||||
int e = GetLastError();
|
return -1;
|
||||||
if (e == ERROR_INSUFFICIENT_BUFFER) {
|
}
|
||||||
|
ret = WideCharToMultiByte(cp, 0, wname, len, buf, bufsize, NULL, NULL);
|
||||||
|
if (e) {
|
||||||
ret = bufsize;
|
ret = bufsize;
|
||||||
}
|
}
|
||||||
else {
|
else if (!ret) {
|
||||||
|
e = GetLastError();
|
||||||
errno = map_errno(e);
|
errno = map_errno(e);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user