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

ruby-changes:48887

From: usa <ko1@a...>
Date: Mon, 4 Dec 2017 12:33:53 +0900 (JST)
Subject: [ruby-changes:48887] usa:r61005 (trunk): support `File.identical?` on ReFS

usa	2017-12-04 12:33:48 +0900 (Mon, 04 Dec 2017)

  New Revision: 61005

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=61005

  Log:
    support `File.identical?` on ReFS
    
    * file.c (rb_file_idenitical_p): move Windows dependent code to win32/win32.c.
    
    * win32/win32.c (rb_w32_file_identical_p): support ReFS.
      see [Feature #13731] [ruby-dev:50166]

  Modified files:
    trunk/file.c
    trunk/win32/Makefile.sub
    trunk/win32/win32.c
Index: file.c
===================================================================
--- file.c	(revision 61004)
+++ file.c	(revision 61005)
@@ -1117,67 +1117,6 @@ rb_stat(VALUE file, struct stat *st) https://github.com/ruby/ruby/blob/trunk/file.c#L1117
     return (int)result;
 }
 
-#ifdef _WIN32
-static HANDLE
-w32_io_info(VALUE *file, BY_HANDLE_FILE_INFORMATION *st)
-{
-    VALUE tmp;
-    HANDLE f, ret = 0;
-
-    tmp = rb_check_convert_type_with_id(*file, T_FILE, "IO", idTo_io);
-    if (!NIL_P(tmp)) {
-	rb_io_t *fptr;
-
-	GetOpenFile(tmp, fptr);
-	f = (HANDLE)rb_w32_get_osfhandle(fptr->fd);
-	if (f == (HANDLE)-1) return INVALID_HANDLE_VALUE;
-    }
-    else {
-	VALUE tmp;
-	WCHAR *ptr;
-	int len;
-	VALUE v;
-
-	FilePathValue(*file);
-	tmp = rb_str_encode_ospath(*file);
-	len = MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, NULL, 0);
-	ptr = ALLOCV_N(WCHAR, v, len);
-	MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, ptr, len);
-	f = CreateFileW(ptr, 0,
-			FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
-			FILE_FLAG_BACKUP_SEMANTICS, NULL);
-	ALLOCV_END(v);
-	if (f == INVALID_HANDLE_VALUE) return f;
-	ret = f;
-    }
-    if (GetFileType(f) == FILE_TYPE_DISK) {
-	ZeroMemory(st, sizeof(*st));
-	if (GetFileInformationByHandle(f, st)) return ret;
-    }
-    if (ret) CloseHandle(ret);
-    return INVALID_HANDLE_VALUE;
-}
-
-static VALUE
-close_handle(VALUE h)
-{
-    CloseHandle((HANDLE)h);
-    return Qfalse;
-}
-
-struct w32_io_info_args {
-    VALUE *fname;
-    BY_HANDLE_FILE_INFORMATION *st;
-};
-
-static VALUE
-call_w32_io_info(VALUE arg)
-{
-    struct w32_io_info_args *p = (void *)arg;
-    return (VALUE)w32_io_info(p->fname, p->st);
-}
-#endif
-
 /*
  *  call-seq:
  *     File.stat(file_name)   ->  stat
@@ -2067,28 +2006,8 @@ rb_file_identical_p(VALUE obj, VALUE fna https://github.com/ruby/ruby/blob/trunk/file.c#L2006
     if (st1.st_ino != st2.st_ino) return Qfalse;
     return Qtrue;
 #else
-    BY_HANDLE_FILE_INFORMATION st1, st2;
-    HANDLE f1 = 0, f2 = 0;
-
-    f1 = w32_io_info(&fname1, &st1);
-    if (f1 == INVALID_HANDLE_VALUE) return Qfalse;
-    if (f1) {
-	struct w32_io_info_args arg;
-	arg.fname = &fname2;
-	arg.st = &st2;
-	f2 = (HANDLE)rb_ensure(call_w32_io_info, (VALUE)&arg, close_handle, (VALUE)f1);
-    }
-    else {
-	f2 = w32_io_info(&fname2, &st2);
-    }
-    if (f2 == INVALID_HANDLE_VALUE) return Qfalse;
-    if (f2) CloseHandle(f2);
-
-    if (st1.dwVolumeSerialNumber == st2.dwVolumeSerialNumber &&
-	st1.nFileIndexHigh == st2.nFileIndexHigh &&
-	st1.nFileIndexLow == st2.nFileIndexLow)
-	return Qtrue;
-    return Qfalse;
+    extern VALUE rb_w32_file_identical_p(VALUE, VALUE);
+    return rb_w32_file_identical_p(fname1, fname2);
 #endif
 }
 
Index: win32/win32.c
===================================================================
--- win32/win32.c	(revision 61004)
+++ win32/win32.c	(revision 61005)
@@ -52,6 +52,7 @@ https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L52
 #include "ruby/vm.h"
 #include "win32/dir.h"
 #include "win32/file.h"
+#include "id.h"
 #include "internal.h"
 #include "encindex.h"
 #define isdirsep(x) ((x) == '/' || (x) == '\\')
@@ -7894,6 +7895,133 @@ rb_w32_pow(double x, double y) https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L7895
 }
 #endif
 
+#if !defined(_WIN32_WINNT_WIN8) || _WIN32_WINNT < 0x602
+#define FileIdInfo 0x12
+
+typedef struct {
+    BYTE  Identifier[16];
+} FILE_ID_128;
+
+typedef struct {
+    unsigned LONG_LONG VolumeSerialNumber;
+    FILE_ID_128 FileId;
+} FILE_ID_INFO;
+#endif
+
+typedef union {
+    BY_HANDLE_FILE_INFORMATION bhfi;
+    FILE_ID_INFO fii;
+} w32_io_info_t;
+
+static HANDLE
+w32_io_info(VALUE *file, w32_io_info_t *st)
+{
+    VALUE tmp;
+    HANDLE f, ret = 0;
+
+    tmp = rb_check_convert_type_with_id(*file, T_FILE, "IO", idTo_io);
+    if (!NIL_P(tmp)) {
+	rb_io_t *fptr;
+
+	GetOpenFile(tmp, fptr);
+	f = (HANDLE)rb_w32_get_osfhandle(fptr->fd);
+	if (f == (HANDLE)-1) return INVALID_HANDLE_VALUE;
+    }
+    else {
+	VALUE tmp;
+	WCHAR *ptr;
+	int len;
+	VALUE v;
+
+	FilePathValue(*file);
+	tmp = rb_str_encode_ospath(*file);
+	len = MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, NULL, 0);
+	ptr = ALLOCV_N(WCHAR, v, len);
+	MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, ptr, len);
+	f = CreateFileW(ptr, 0,
+			FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+			FILE_FLAG_BACKUP_SEMANTICS, NULL);
+	ALLOCV_END(v);
+	if (f == INVALID_HANDLE_VALUE) return f;
+	ret = f;
+    }
+    if (GetFileType(f) == FILE_TYPE_DISK) {
+	ZeroMemory(st, sizeof(*st));
+	if (osver.dwMajorVersion < 6 ||
+	    (osver.dwMajorVersion == 6 && osver.dwMinorVersion < 2)) {
+	    if (GetFileInformationByHandle(f, &st->bhfi))
+		return ret;
+	}
+	else {
+	    typedef BOOL (WINAPI *gfibhe_t)(HANDLE, int, void *, DWORD);
+	    static gfibhe_t pGetFileInformationByHandleEx = (gfibhe_t)-1;
+	    if (pGetFileInformationByHandleEx == (gfibhe_t)-1)
+		pGetFileInformationByHandleEx = (gfibhe_t)get_proc_address("kernel32", "GetFileInformationByHandleEx", NULL);
+
+	    /* expect that this function is always available after Windows 8. */
+	    /* if not available, return with error... */
+	    if (pGetFileInformationByHandleEx &&
+		pGetFileInformationByHandleEx(f, FileIdInfo, &st->fii, sizeof(st->fii)))
+		return ret;
+	}
+    }
+    if (ret) CloseHandle(ret);
+    return INVALID_HANDLE_VALUE;
+}
+
+static VALUE
+close_handle(VALUE h)
+{
+    CloseHandle((HANDLE)h);
+    return Qfalse;
+}
+
+struct w32_io_info_args {
+    VALUE *fname;
+    w32_io_info_t *st;
+};
+
+static VALUE
+call_w32_io_info(VALUE arg)
+{
+    struct w32_io_info_args *p = (void *)arg;
+    return (VALUE)w32_io_info(p->fname, p->st);
+}
+
+VALUE
+rb_w32_file_identical_p(VALUE fname1, VALUE fname2)
+{
+    w32_io_info_t st1, st2;
+    HANDLE f1 = 0, f2 = 0;
+
+    f1 = w32_io_info(&fname1, &st1);
+    if (f1 == INVALID_HANDLE_VALUE) return Qfalse;
+    if (f1) {
+	struct w32_io_info_args arg;
+	arg.fname = &fname2;
+	arg.st = &st2;
+	f2 = (HANDLE)rb_ensure(call_w32_io_info, (VALUE)&arg, close_handle, (VALUE)f1);
+    }
+    else {
+	f2 = w32_io_info(&fname2, &st2);
+    }
+    if (f2 == INVALID_HANDLE_VALUE) return Qfalse;
+    if (f2) CloseHandle(f2);
+
+    if (osver.dwMajorVersion < 6 || (osver.dwMajorVersion == 6 && osver.dwMinorVersion < 2)) {
+	if (st1.bhfi.dwVolumeSerialNumber == st2.bhfi.dwVolumeSerialNumber &&
+	    st1.bhfi.nFileIndexHigh == st2.bhfi.nFileIndexHigh &&
+	    st1.bhfi.nFileIndexLow == st2.bhfi.nFileIndexLow)
+	    return Qtrue;
+    }
+    else {
+	if (st1.fii.VolumeSerialNumber == st2.fii.VolumeSerialNumber &&
+	    memcmp(&st1.fii.FileId, &st2.fii.FileId, sizeof(FILE_ID_128)) == 0)
+	    return Qtrue;
+    }
+    return Qfalse;
+}
+
 int
 rb_w32_set_thread_description(HANDLE th, const WCHAR *name)
 {
Index: win32/Makefile.sub
===================================================================
--- win32/Makefile.sub	(revision 61004)
+++ win32/Makefile.sub	(revision 61005)
@@ -1168,6 +1168,7 @@ $(srcdir)/enc/jis/props.h: {$(srcdir)}en https://github.com/ruby/ruby/blob/trunk/win32/Makefile.sub#L1168
 
 $(OBJS): {$(hdrdir)/ruby}win32.h
 
+win32/win32.$(OBJEXT): {$(VPATH)}id.h
 dir.$(OBJEXT) win32/win32.$(OBJEXT): {$(srcdir)}win32/dir.h
 file.$(OBJEXT) win32/win32.$(OBJEXT): {$(VPATH)}win32/file.h
 

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

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