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/