From 91de3d6539ca93366cf5f5de0a26b4474ccecab2 Mon Sep 17 00:00:00 2001 From: usa Date: Sun, 10 Dec 2017 17:26:58 +0000 Subject: support 128bit ino on Windows (if available) * win32/win32.c, include/ruby/win32.h (stati128, rb_{,u,l,ul}stati128): rename from stati64ns, change the type of st_ino to 64bit and added st_inohigh. * dir.c, file.c (stat, lstat): follow above changes. * file.c (rb_stat_ino): support 128bit ino. * win32/win32.c (rb_{,u,l,ul}stati128): ditto. [Feature #13731] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61096 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- win32/win32.c | 191 ++++++++++++++++++++++++++++------------------------------ 1 file changed, 92 insertions(+), 99 deletions(-) (limited to 'win32') diff --git a/win32/win32.c b/win32/win32.c index 599225bbdd..754513b9ad 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -62,14 +62,14 @@ #endif static int w32_wopen(const WCHAR *file, int oflag, int perm); -static int w32_stati64ns(const char *path, struct stati64ns *st, UINT cp); -static int w32_lstati64ns(const char *path, struct stati64ns *st, UINT cp); +static int w32_stati128(const char *path, struct stati128 *st, UINT cp); +static int w32_lstati128(const char *path, struct stati128 *st, UINT cp); static char *w32_getenv(const char *name, UINT cp); #undef getenv #define DLN_FIND_EXTRA_ARG_DECL ,UINT cp #define DLN_FIND_EXTRA_ARG ,cp -#define rb_w32_stati64ns(path, st) w32_stati64ns(path, st, cp) +#define rb_w32_stati128(path, st) w32_stati128(path, st, cp) #define getenv(name) w32_getenv(name, cp) #undef CharNext #define CharNext(p) CharNextExA(cp, (p), 0) @@ -78,7 +78,7 @@ static char *w32_getenv(const char *name, UINT cp); #include "dln.h" #include "dln_find.c" #undef MAXPATHLEN -#undef rb_w32_stati64ns +#undef rb_w32_stati128 #undef dln_find_exe_r #undef dln_find_file_r #define dln_find_exe_r(fname, path, buf, size) rb_w32_udln_find_exe_r(fname, path, buf, size, cp) @@ -123,8 +123,8 @@ static struct ChildRecord *CreateChild(const WCHAR *, const WCHAR *, SECURITY_AT static int has_redirection(const char *, UINT); int rb_w32_wait_events(HANDLE *events, int num, DWORD timeout); static int rb_w32_open_osfhandle(intptr_t osfhandle, int flags); -static int wstati64ns(const WCHAR *path, struct stati64ns *st); -static int wlstati64ns(const WCHAR *path, struct stati64ns *st); +static int wstati128(const WCHAR *path, struct stati128 *st); +static int wlstati128(const WCHAR *path, struct stati128 *st); VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc); int ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc); static FARPROC get_proc_address(const char *module, const char *func, HANDLE *mh); @@ -1992,7 +1992,7 @@ open_dir_handle(const WCHAR *filename, WIN32_FIND_DATAW *fd) static DIR * w32_wopendir(const WCHAR *wpath) { - struct stati64ns sbuf; + struct stati128 sbuf; WIN32_FIND_DATAW fd; HANDLE fh; DIR *p; @@ -2006,7 +2006,7 @@ w32_wopendir(const WCHAR *wpath) // // check to see if we've got a directory // - if (wstati64ns(wpath, &sbuf) < 0) { + if (wstati128(wpath, &sbuf) < 0) { return NULL; } if (!(sbuf.st_mode & S_IFDIR) && @@ -5389,36 +5389,7 @@ isUNCRoot(const WCHAR *path) static time_t filetime_to_unixtime(const FILETIME *ft); static long filetime_to_nsec(const FILETIME *ft); static WCHAR *name_for_stat(WCHAR *buf, const WCHAR *path); -static DWORD stati64ns_handle(HANDLE h, struct stati64ns *st); - -/* License: Ruby's */ -static void -stati64ns_set_inode(BY_HANDLE_FILE_INFORMATION *pinfo, struct stati64ns *st) -{ - /* struct stati64 layout - * - * dev: 0-3 - * ino: 4-5 - * mode: 6-7 - * nlink: 8-9 - * uid: 10-11 - * gid: 12-13 - * _: 14-15 - * rdev: 16-19 - * _: 20-23 - * size: 24-31 - * atime: 32-39 - * mtime: 40-47 - * ctime: 48-55 - * - */ - unsigned short *p2 = (unsigned short *)st; - unsigned int *p4 = (unsigned int *)st; - DWORD high = pinfo->nFileIndexHigh; - p2[2] = high >> 16; - p2[7] = high & 0xFFFF; - p4[5] = pinfo->nFileIndexLow; -} +static DWORD stati128_handle(HANDLE h, struct stati128 *st); #undef fstat /* License: Ruby's */ @@ -5440,25 +5411,60 @@ rb_w32_fstat(int fd, struct stat *st) /* License: Ruby's */ int -rb_w32_fstati64ns(int fd, struct stati64ns *st) +rb_w32_fstati128(int fd, struct stati128 *st) { struct stat tmp; int ret = fstat(fd, &tmp); if (ret) return ret; COPY_STAT(tmp, *st, +); - stati64ns_handle((HANDLE)_get_osfhandle(fd), st); + stati128_handle((HANDLE)_get_osfhandle(fd), st); return ret; } +#if !defined FILE_INVALID_FILE_ID && !defined __MINGW32__ +typedef struct { + BYTE Identifier[16]; +} FILE_ID_128; +#endif + +#if !defined(_WIN32_WINNT_WIN8) || _WIN32_WINNT < 0x602 +#define FileIdInfo 0x12 + +typedef struct { + unsigned LONG_LONG VolumeSerialNumber; + FILE_ID_128 FileId; +} FILE_ID_INFO; +#endif + +static DWORD +get_ino(HANDLE h, FILE_ID_INFO *id) +{ + typedef BOOL (WINAPI *gfibhe_t)(HANDLE, int, void *, DWORD); + static gfibhe_t pGetFileInformationByHandleEx = (gfibhe_t)-1; + DWORD err; + + if (pGetFileInformationByHandleEx == (gfibhe_t)-1) + pGetFileInformationByHandleEx = (gfibhe_t)get_proc_address("kernel32", "GetFileInformationByHandleEx", NULL); + + if (pGetFileInformationByHandleEx) { + if (pGetFileInformationByHandleEx(h, FileIdInfo, id, sizeof(*id))) + return 0; + else + return GetLastError(); + } + return ERROR_INVALID_PARAMETER; +} + /* License: Ruby's */ static DWORD -stati64ns_handle(HANDLE h, struct stati64ns *st) +stati128_handle(HANDLE h, struct stati128 *st) { BY_HANDLE_FILE_INFORMATION info; DWORD attr = (DWORD)-1; if (GetFileInformationByHandle(h, &info)) { + FILE_ID_INFO fii; st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow; st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime); st->st_atimensec = filetime_to_nsec(&info.ftLastAccessTime); @@ -5468,7 +5474,14 @@ stati64ns_handle(HANDLE h, struct stati64ns *st) st->st_ctimensec = filetime_to_nsec(&info.ftCreationTime); st->st_nlink = info.nNumberOfLinks; attr = info.dwFileAttributes; - stati64ns_set_inode(&info, st); + if (!get_ino(h, &fii)) { + st->st_ino = *((unsigned __int64 *)&fii); + st->st_inohigh = *((__int64 *)&fii + 1); + } + else { + st->st_ino = ((__int64)info.nFileIndexHigh << 32) | info.nFileIndexLow; + st->st_inohigh = 0; + } } return attr; } @@ -5587,7 +5600,7 @@ check_valid_dir(const WCHAR *path) /* License: Ruby's */ static int -stat_by_find(const WCHAR *path, struct stati64ns *st) +stat_by_find(const WCHAR *path, struct stati128 *st) { HANDLE h; WIN32_FIND_DATAW wfd; @@ -5631,7 +5644,7 @@ static const WCHAR namespace_prefix[] = {L'\\', L'\\', L'?', L'\\'}; /* License: Ruby's */ static int -winnt_stat(const WCHAR *path, struct stati64ns *st) +winnt_stat(const WCHAR *path, struct stati128 *st) { HANDLE f; WCHAR finalname[PATH_MAX]; @@ -5639,7 +5652,7 @@ winnt_stat(const WCHAR *path, struct stati64ns *st) memset(st, 0, sizeof(*st)); f = open_special(path, 0, 0); if (f != INVALID_HANDLE_VALUE) { - const DWORD attr = stati64ns_handle(f, st); + const DWORD attr = stati128_handle(f, st); const DWORD len = get_final_path(f, finalname, numberof(finalname), 0); CloseHandle(f); if (attr & FILE_ATTRIBUTE_DIRECTORY) { @@ -5664,7 +5677,7 @@ winnt_stat(const WCHAR *path, struct stati64ns *st) /* License: Ruby's */ static int -winnt_lstat(const WCHAR *path, struct stati64ns *st) +winnt_lstat(const WCHAR *path, struct stati128 *st) { WIN32_FILE_ATTRIBUTE_DATA wfa; const WCHAR *p = path; @@ -5714,16 +5727,16 @@ winnt_lstat(const WCHAR *path, struct stati64ns *st) int rb_w32_stat(const char *path, struct stat *st) { - struct stati64ns tmp; + struct stati128 tmp; - if (rb_w32_stati64ns(path, &tmp)) return -1; + if (rb_w32_stati128(path, &tmp)) return -1; COPY_STAT(tmp, *st, (_off_t)); return 0; } /* License: Ruby's */ static int -wstati64ns(const WCHAR *path, struct stati64ns *st) +wstati128(const WCHAR *path, struct stati128 *st) { WCHAR *buf1; int ret, size; @@ -5746,7 +5759,7 @@ wstati64ns(const WCHAR *path, struct stati64ns *st) /* License: Ruby's */ static int -wlstati64ns(const WCHAR *path, struct stati64ns *st) +wlstati128(const WCHAR *path, struct stati128 *st) { WCHAR *buf1; int ret, size; @@ -5803,56 +5816,56 @@ name_for_stat(WCHAR *buf1, const WCHAR *path) /* License: Ruby's */ int -rb_w32_ustati64ns(const char *path, struct stati64ns *st) +rb_w32_ustati128(const char *path, struct stati128 *st) { - return w32_stati64ns(path, st, CP_UTF8); + return w32_stati128(path, st, CP_UTF8); } /* License: Ruby's */ int -rb_w32_stati64ns(const char *path, struct stati64ns *st) +rb_w32_stati128(const char *path, struct stati128 *st) { - return w32_stati64ns(path, st, filecp()); + return w32_stati128(path, st, filecp()); } /* License: Ruby's */ static int -w32_stati64ns(const char *path, struct stati64ns *st, UINT cp) +w32_stati128(const char *path, struct stati128 *st, UINT cp) { WCHAR *wpath; int ret; if (!(wpath = mbstr_to_wstr(cp, path, -1, NULL))) return -1; - ret = wstati64ns(wpath, st); + ret = wstati128(wpath, st); free(wpath); return ret; } /* License: Ruby's */ int -rb_w32_ulstati64ns(const char *path, struct stati64ns *st) +rb_w32_ulstati128(const char *path, struct stati128 *st) { - return w32_lstati64ns(path, st, CP_UTF8); + return w32_lstati128(path, st, CP_UTF8); } /* License: Ruby's */ int -rb_w32_lstati64ns(const char *path, struct stati64ns *st) +rb_w32_lstati128(const char *path, struct stati128 *st) { - return w32_lstati64ns(path, st, filecp()); + return w32_lstati128(path, st, filecp()); } /* License: Ruby's */ static int -w32_lstati64ns(const char *path, struct stati64ns *st, UINT cp) +w32_lstati128(const char *path, struct stati128 *st, UINT cp) { WCHAR *wpath; int ret; if (!(wpath = mbstr_to_wstr(cp, path, -1, NULL))) return -1; - ret = wlstati64ns(wpath, st); + ret = wlstati128(wpath, st); free(wpath); return ret; } @@ -5861,8 +5874,8 @@ w32_lstati64ns(const char *path, struct stati64ns *st, UINT cp) int rb_w32_access(const char *path, int mode) { - struct stati64ns stat; - if (rb_w32_stati64ns(path, &stat) != 0) + struct stati128 stat; + if (rb_w32_stati128(path, &stat) != 0) return -1; mode <<= 6; if ((stat.st_mode & mode) != mode) { @@ -5876,8 +5889,8 @@ rb_w32_access(const char *path, int mode) int rb_w32_uaccess(const char *path, int mode) { - struct stati64ns stat; - if (rb_w32_ustati64ns(path, &stat) != 0) + struct stati128 stat; + if (rb_w32_ustati128(path, &stat) != 0) return -1; mode <<= 6; if ((stat.st_mode & mode) != mode) { @@ -7361,7 +7374,7 @@ wutimensat(int dirfd, const WCHAR *path, const struct timespec *times, int flags { HANDLE hFile; FILETIME atime, mtime; - struct stati64ns stat; + struct stati128 stat; int ret = 0; /* TODO: When path is absolute, dirfd should be ignored. */ @@ -7375,7 +7388,7 @@ wutimensat(int dirfd, const WCHAR *path, const struct timespec *times, int flags return -1; } - if (wstati64ns(path, &stat)) { + if (wstati128(path, &stat)) { return -1; } @@ -7983,21 +7996,6 @@ rb_w32_pow(double x, double y) } #endif -#if !defined FILE_INVALID_FILE_ID && !defined __MINGW32__ -typedef struct { - BYTE Identifier[16]; -} FILE_ID_128; -#endif - -#if !defined(_WIN32_WINNT_WIN8) || _WIN32_WINNT < 0x602 -#define FileIdInfo 0x12 - -typedef struct { - unsigned LONG_LONG VolumeSerialNumber; - FILE_ID_128 FileId; -} FILE_ID_INFO; -#endif - typedef struct { BOOL file_id_p; union { @@ -8039,24 +8037,19 @@ w32_io_info(VALUE *file, w32_io_info_t *st) ret = f; } if (GetFileType(f) == FILE_TYPE_DISK) { - 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); - + DWORD err; ZeroMemory(st, sizeof(*st)); - if (pGetFileInformationByHandleEx) { - if (pGetFileInformationByHandleEx(f, FileIdInfo, &st->info.fii, sizeof(st->info.fii))) { - st->file_id_p = TRUE; - return ret; - } - else if (GetLastError() != ERROR_INVALID_PARAMETER) { - CloseHandle(f); - return FALSE; - } - /* this API may not wrok at files on non Microsoft SMB - * server, fallback to old API then. */ + err = get_ino(f, &st->info.fii); + if (!err) { + st->file_id_p = TRUE; + return ret; + } + else if (err != ERROR_INVALID_PARAMETER) { + CloseHandle(f); + return INVALID_HANDLE_VALUE; } + /* this API may not wrok at files on non Microsoft SMB + * server, fallback to old API then. */ if (GetFileInformationByHandle(f, &st->info.bhfi)) { st->file_id_p = FALSE; return ret; -- cgit v1.2.3