[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]