ruby-changes:39595
From: nobu <ko1@a...>
Date: Tue, 25 Aug 2015 14:11:37 +0900 (JST)
Subject: [ruby-changes:39595] nobu:r51676 (trunk): win32.c: rb_w32_reparse
nobu 2015-08-25 14:11:19 +0900 (Tue, 25 Aug 2015) New Revision: 51676 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=51676 Log: win32.c: rb_w32_reparse * win32/win32.c (rb_w32_reparse): read reparse point in a dynamic buffer. Added files: trunk/win32/file.h Modified files: trunk/common.mk trunk/win32/file.c trunk/win32/win32.c Index: common.mk =================================================================== --- common.mk (revision 51675) +++ common.mk (revision 51676) @@ -710,9 +710,10 @@ prelude.$(OBJEXT): {$(VPATH)}prelude.c https://github.com/ruby/ruby/blob/trunk/common.mk#L710 # dependencies for optional sources. 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) -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) $(NEWLINE_C): $(srcdir)/enc/trans/newline.trans $(srcdir)/tool/transcode-tblgen.rb Index: win32/win32.c =================================================================== --- win32/win32.c (revision 51675) +++ win32/win32.c (revision 51676) @@ -50,6 +50,7 @@ https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L50 #endif #include "ruby/win32.h" #include "win32/dir.h" +#include "win32/file.h" #include "internal.h" #define isdirsep(x) ((x) == '/' || (x) == '\\') @@ -4668,32 +4669,8 @@ link(const char *from, const char *to) https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L4669 #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 */ 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; DWORD ret; @@ -4721,12 +4698,12 @@ reparse_symlink(const WCHAR *path, repar https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L4698 } if (!device_io_control(f, FSCTL_GET_REPARSE_POINT, NULL, 0, - rp, sizeof(*rp), &ret, NULL)) { - e = map_errno(GetLastError()); + rp, size, &ret, NULL)) { + e = GetLastError(); } else if (rp->ReparseTag != IO_REPARSE_TAG_SYMLINK && rp->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) { - e = EINVAL; + e = ERROR_INVALID_PARAMETER; } CloseHandle(f); return e; @@ -4736,68 +4713,86 @@ reparse_symlink(const WCHAR *path, repar https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L4713 int rb_w32_reparse_symlink_p(const WCHAR *path) { - reparse_buffer_t rp; - return reparse_symlink(path, &rp) == 0; + rb_w32_reparse_buffer_t rp; + switch (reparse_symlink(path, &rp, sizeof(rp))) { + case 0: + case ERROR_MORE_DATA: + return TRUE; + } + return FALSE; } /* License: Ruby's */ -ssize_t -rb_w32_wreadlink(const WCHAR *path, WCHAR *buf, size_t bufsize) +int +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); + int e = reparse_symlink(path, rp, bufsize); DWORD ret; - if (!e) { + if (!e || e == ERROR_MORE_DATA) { void *name; - if (rp.ReparseTag == IO_REPARSE_TAG_SYMLINK) { - name = ((char *)rp.SymbolicLinkReparseBuffer.PathBuffer + - rp.SymbolicLinkReparseBuffer.PrintNameOffset); - ret = rp.SymbolicLinkReparseBuffer.PrintNameLength; + if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + name = ((char *)rp->SymbolicLinkReparseBuffer.PathBuffer + + rp->SymbolicLinkReparseBuffer.PrintNameOffset); + ret = rp->SymbolicLinkReparseBuffer.PrintNameLength; } else { /* IO_REPARSE_TAG_MOUNT_POINT */ /* +4/-4 means to drop "\??\" */ - name = ((char *)rp.MountPointReparseBuffer.PathBuffer + - rp.MountPointReparseBuffer.SubstituteNameOffset + + name = ((char *)rp->MountPointReparseBuffer.PathBuffer + + rp->MountPointReparseBuffer.SubstituteNameOffset + 4 * sizeof(WCHAR)); - ret = rp.MountPointReparseBuffer.SubstituteNameLength - + ret = rp->MountPointReparseBuffer.SubstituteNameLength - 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'; translate_wchar(name, L'\\', L'/'); - bufsize *= sizeof(WCHAR); - memcpy(buf, name, ret > bufsize ? bufsize : ret); + return 0; } else { - errno = e; - return -1; + return e; } - return ret / sizeof(WCHAR); } /* License: Ruby's */ static ssize_t w32_readlink(UINT cp, const char *path, char *buf, size_t bufsize) { - WCHAR *wpath; - WCHAR wbuf[MAXPATHLEN]; + WCHAR *wpath, *wname; + 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; + int e; wpath = mbstr_to_wstr(cp, path, -1, NULL); - if (!wpath) return -1; - ret = rb_w32_wreadlink(wpath, wbuf, MAXPATHLEN); + if (!wpath) { + ALLOCV_END(wtmp); + return -1; + } + e = rb_w32_read_reparse_point(wpath, rp, size, &wname, &len); free(wpath); - if (ret < 0) return ret; - ret = WideCharToMultiByte(cp, 0, wbuf, ret, buf, bufsize, NULL, NULL); - if (!ret) { - int e = GetLastError(); - if (e == ERROR_INSUFFICIENT_BUFFER) { - ret = bufsize; - } - else { - errno = map_errno(e); - ret = -1; - } + if (e && e != ERROR_MORE_DATA) { + ALLOCV_END(wtmp); + errno = map_errno(e); + return -1; + } + ret = WideCharToMultiByte(cp, 0, wname, len, buf, bufsize, NULL, NULL); + if (e) { + ret = bufsize; + } + else if (!ret) { + e = GetLastError(); + errno = map_errno(e); + ret = -1; } return ret; } Index: win32/file.c =================================================================== --- win32/file.c (revision 51675) +++ win32/file.c (revision 51676) @@ -9,6 +9,7 @@ https://github.com/ruby/ruby/blob/trunk/win32/file.c#L9 #include <winbase.h> #include <wchar.h> #include <shlwapi.h> +#include "win32/file.h" #ifndef INVALID_FILE_ATTRIBUTES # define INVALID_FILE_ATTRIBUTES ((DWORD)-1) @@ -658,15 +659,16 @@ rb_file_expand_path_internal(VALUE fname https://github.com/ruby/ruby/blob/trunk/win32/file.c#L659 return result; } -ssize_t rb_w32_wreadlink(const WCHAR *path, WCHAR *buf, size_t bufsize); - VALUE rb_readlink(VALUE path) { - ssize_t len; - WCHAR *wpath, wbuf[MAX_PATH]; + DWORD len; + VALUE wtmp = 0, 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); @@ -678,13 +680,23 @@ rb_readlink(VALUE path) https://github.com/ruby/ruby/blob/trunk/win32/file.c#L680 wpath = mbstr_to_wstr(cp, RSTRING_PTR(path), RSTRING_LEN(path)+rb_enc_mbminlen(enc), NULL); 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); - 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(); cp = path_cp = code_page(enc); 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 * Index: win32/file.h =================================================================== --- win32/file.h (revision 0) +++ win32/file.h (revision 51676) @@ -0,0 +1,40 @@ https://github.com/ruby/ruby/blob/trunk/win32/file.h#L1 +#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 */ Property changes on: win32/file.h ___________________________________________________________________ Added: svn:eol-style + LF -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/