Last active
July 1, 2017 02:52
-
-
Save kubo/0a351c5d6fbbd3d3f7cce44a0fbed9d9 to your computer and use it in GitHub Desktop.
https://github.com/oneclick/rubyinstaller2/issues/52 Apply 01-mtime-subsec.dif and then 02-file-utime.dif
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/dir.c b/dir.c | |
index 3db196f..426d0b6 100644 | |
--- a/dir.c | |
+++ b/dir.c | |
@@ -1300,9 +1300,9 @@ to_be_ignored(int e) | |
} | |
#ifdef _WIN32 | |
-#define STAT(p, s) rb_w32_ustati64((p), (s)) | |
+#define STAT(p, s) rb_w32_ustati64ns((p), (s)) | |
#undef lstat | |
-#define lstat(p, s) rb_w32_ulstati64((p), (s)) | |
+#define lstat(p, s) rb_w32_ulstati64ns((p), (s)) | |
#else | |
#define STAT(p, s) stat((p), (s)) | |
#endif | |
diff --git a/file.c b/file.c | |
index ce367fd..37df00e 100644 | |
--- a/file.c | |
+++ b/file.c | |
@@ -100,9 +100,9 @@ int flock(int, int); | |
/* define system APIs */ | |
#ifdef _WIN32 | |
#include "win32/file.h" | |
-#define STAT(p, s) rb_w32_ustati64((p), (s)) | |
+#define STAT(p, s) rb_w32_ustati64ns((p), (s)) | |
#undef lstat | |
-#define lstat(p, s) rb_w32_ulstati64((p), (s)) | |
+#define lstat(p, s) rb_w32_ulstati64ns((p), (s)) | |
#undef access | |
#define access(p, m) rb_w32_uaccess((p), (m)) | |
#undef truncate | |
diff --git a/include/ruby/win32.h b/include/ruby/win32.h | |
index a2ba226..5b3486c 100644 | |
--- a/include/ruby/win32.h | |
+++ b/include/ruby/win32.h | |
@@ -151,7 +151,6 @@ typedef int clockid_t; | |
#define getppid() rb_w32_getppid() | |
#define sleep(x) rb_w32_Sleep((x)*1000) | |
#define Sleep(msec) (void)rb_w32_Sleep(msec) | |
-#define fstati64(fd,st) rb_w32_fstati64(fd,st) | |
#undef execv | |
#define execv(path,argv) rb_w32_aspawn(P_OVERLAY,path,argv) | |
@@ -166,26 +165,39 @@ typedef int clockid_t; | |
#define unlink(p) rb_w32_unlink(p) | |
#endif /* RUBY_EXPORT */ | |
+/* same with stati64 except nanosecond timestamps */ | |
+struct stati64ns { | |
+ _dev_t st_dev; | |
+ _ino_t st_ino; | |
+ unsigned short st_mode; | |
+ short st_nlink; | |
+ short st_uid; | |
+ short st_gid; | |
+ _dev_t st_rdev; | |
+ __int64 st_size; | |
+ __time64_t st_atime; | |
+ long st_atimensec; | |
+ __time64_t st_mtime; | |
+ long st_mtimensec; | |
+ __time64_t st_ctime; | |
+ long st_ctimensec; | |
+}; | |
+ | |
#if SIZEOF_OFF_T == 8 | |
#define off_t __int64 | |
-#define stat stati64 | |
-#define fstat(fd,st) fstati64(fd,st) | |
-#if !defined(_MSC_VER) || RUBY_MSVCRT_VERSION < 80 | |
-#define stati64 _stati64 | |
-#ifndef _stati64 | |
-#define _stati64(path, st) rb_w32_stati64(path, st) | |
-#endif | |
-#else | |
-#define stati64 _stat64 | |
-#define _stat64(path, st) rb_w32_stati64(path, st) | |
-#endif | |
+#define stat stati64ns | |
+#define HAVE_STRUCT_STAT_ST_ATIMENSEC | |
+#define HAVE_STRUCT_STAT_ST_MTIMENSEC | |
+#define HAVE_STRUCT_STAT_ST_CTIMENSEC | |
+#define fstat(fd,st) rb_w32_fstati64ns(fd,st) | |
+#define stati64ns(path, st) rb_w32_stati64ns(path, st) | |
#else | |
#define stat(path,st) rb_w32_stat(path,st) | |
#define fstat(fd,st) rb_w32_fstat(fd,st) | |
extern int rb_w32_stat(const char *, struct stat *); | |
extern int rb_w32_fstat(int, struct stat *); | |
#endif | |
-#define lstat(path,st) rb_w32_lstati64(path,st) | |
+#define lstat(path,st) rb_w32_lstati64ns(path,st) | |
#define access(path,mode) rb_w32_access(path,mode) | |
#define strcasecmp _stricmp | |
@@ -316,14 +328,14 @@ extern int rb_w32_urmdir(const char *); | |
extern int rb_w32_unlink(const char *); | |
extern int rb_w32_uunlink(const char *); | |
extern int rb_w32_uchmod(const char *, int); | |
-extern int rb_w32_stati64(const char *, struct stati64 *); | |
-extern int rb_w32_ustati64(const char *, struct stati64 *); | |
-extern int rb_w32_lstati64(const char *, struct stati64 *); | |
-extern int rb_w32_ulstati64(const char *, struct stati64 *); | |
+extern int rb_w32_stati64ns(const char *, struct stati64ns *); | |
+extern int rb_w32_ustati64ns(const char *, struct stati64ns *); | |
+extern int rb_w32_lstati64ns(const char *, struct stati64ns *); | |
+extern int rb_w32_ulstati64ns(const char *, struct stati64ns *); | |
extern int rb_w32_access(const char *, int); | |
extern int rb_w32_uaccess(const char *, int); | |
extern char rb_w32_fd_is_text(int); | |
-extern int rb_w32_fstati64(int, struct stati64 *); | |
+extern int rb_w32_fstati64ns(int, struct stati64ns *); | |
extern int rb_w32_dup2(int, int); | |
#include <float.h> | |
@@ -440,8 +452,6 @@ extern rb_gid_t getegid (void); | |
extern int setuid (rb_uid_t); | |
extern int setgid (rb_gid_t); | |
-extern int fstati64(int, struct stati64 *); | |
- | |
extern char *rb_w32_strerror(int); | |
#ifdef RUBY_EXPORT | |
diff --git a/win32/win32.c b/win32/win32.c | |
index a997cb3..f266a56 100644 | |
--- a/win32/win32.c | |
+++ b/win32/win32.c | |
@@ -60,14 +60,14 @@ | |
#endif | |
static int w32_wopen(const WCHAR *file, int oflag, int perm); | |
-static int w32_stati64(const char *path, struct stati64 *st, UINT cp); | |
-static int w32_lstati64(const char *path, struct stati64 *st, UINT cp); | |
+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 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_stati64(path, st) w32_stati64(path, st, cp) | |
+#define rb_w32_stati64ns(path, st) w32_stati64ns(path, st, cp) | |
#define getenv(name) w32_getenv(name, cp) | |
#undef CharNext | |
#define CharNext(p) CharNextExA(cp, (p), 0) | |
@@ -76,7 +76,7 @@ static char *w32_getenv(const char *name, UINT cp); | |
#include "dln.h" | |
#include "dln_find.c" | |
#undef MAXPATHLEN | |
-#undef rb_w32_stati64 | |
+#undef rb_w32_stati64ns | |
#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) | |
@@ -121,8 +121,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 wstati64(const WCHAR *path, struct stati64 *st); | |
-static int wlstati64(const WCHAR *path, struct stati64 *st); | |
+static int wstati64ns(const WCHAR *path, struct stati64ns *st); | |
+static int wlstati64ns(const WCHAR *path, struct stati64ns *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); | |
@@ -1973,7 +1973,7 @@ open_dir_handle(const WCHAR *filename, WIN32_FIND_DATAW *fd) | |
static DIR * | |
w32_wopendir(const WCHAR *wpath) | |
{ | |
- struct stati64 sbuf; | |
+ struct stati64ns sbuf; | |
WIN32_FIND_DATAW fd; | |
HANDLE fh; | |
DIR *p; | |
@@ -1987,7 +1987,7 @@ w32_wopendir(const WCHAR *wpath) | |
// | |
// check to see if we've got a directory | |
// | |
- if (wstati64(wpath, &sbuf) < 0) { | |
+ if (wstati64ns(wpath, &sbuf) < 0) { | |
return NULL; | |
} | |
if (!(sbuf.st_mode & S_IFDIR) && | |
@@ -5344,12 +5344,13 @@ isUNCRoot(const WCHAR *path) | |
} while (0) | |
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 stati64_handle(HANDLE h, struct stati64 *st); | |
+static DWORD stati64ns_handle(HANDLE h, struct stati64ns *st); | |
/* License: Ruby's */ | |
static void | |
-stati64_set_inode(BY_HANDLE_FILE_INFORMATION *pinfo, struct stati64 *st) | |
+stati64ns_set_inode(BY_HANDLE_FILE_INFORMATION *pinfo, struct stati64ns *st) | |
{ | |
/* struct stati64 layout | |
* | |
@@ -5376,19 +5377,6 @@ stati64_set_inode(BY_HANDLE_FILE_INFORMATION *pinfo, struct stati64 *st) | |
p4[5] = pinfo->nFileIndexLow; | |
} | |
-/* License: Ruby's */ | |
-static DWORD | |
-stati64_set_inode_handle(HANDLE h, struct stati64 *st) | |
-{ | |
- BY_HANDLE_FILE_INFORMATION info; | |
- DWORD attr = (DWORD)-1; | |
- | |
- if (GetFileInformationByHandle(h, &info)) { | |
- stati64_set_inode(&info, st); | |
- } | |
- return attr; | |
-} | |
- | |
#undef fstat | |
/* License: Ruby's */ | |
int | |
@@ -5409,27 +5397,20 @@ rb_w32_fstat(int fd, struct stat *st) | |
/* License: Ruby's */ | |
int | |
-rb_w32_fstati64(int fd, struct stati64 *st) | |
+rb_w32_fstati64ns(int fd, struct stati64ns *st) | |
{ | |
struct stat tmp; | |
- int ret; | |
- | |
- if (GetEnvironmentVariableW(L"TZ", NULL, 0) == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) { | |
- ret = _fstati64(fd, st); | |
- stati64_set_inode_handle((HANDLE)_get_osfhandle(fd), st); | |
- return ret; | |
- } | |
- ret = fstat(fd, &tmp); | |
+ int ret = fstat(fd, &tmp); | |
if (ret) return ret; | |
COPY_STAT(tmp, *st, +); | |
- stati64_handle((HANDLE)_get_osfhandle(fd), st); | |
+ stati64ns_handle((HANDLE)_get_osfhandle(fd), st); | |
return ret; | |
} | |
/* License: Ruby's */ | |
static DWORD | |
-stati64_handle(HANDLE h, struct stati64 *st) | |
+stati64ns_handle(HANDLE h, struct stati64ns *st) | |
{ | |
BY_HANDLE_FILE_INFORMATION info; | |
DWORD attr = (DWORD)-1; | |
@@ -5437,11 +5418,14 @@ stati64_handle(HANDLE h, struct stati64 *st) | |
if (GetFileInformationByHandle(h, &info)) { | |
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); | |
st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime); | |
+ st->st_mtimensec = filetime_to_nsec(&info.ftLastWriteTime); | |
st->st_ctime = filetime_to_unixtime(&info.ftCreationTime); | |
+ st->st_ctimensec = filetime_to_nsec(&info.ftCreationTime); | |
st->st_nlink = info.nNumberOfLinks; | |
attr = info.dwFileAttributes; | |
- stati64_set_inode(&info, st); | |
+ stati64ns_set_inode(&info, st); | |
} | |
return attr; | |
} | |
@@ -5459,6 +5443,16 @@ filetime_to_unixtime(const FILETIME *ft) | |
} | |
/* License: Ruby's */ | |
+static long | |
+filetime_to_nsec(const FILETIME *ft) | |
+{ | |
+ ULARGE_INTEGER tmp; | |
+ tmp.LowPart = ft->dwLowDateTime; | |
+ tmp.HighPart = ft->dwHighDateTime; | |
+ return (long)(tmp.QuadPart % 10000000) * 100; | |
+} | |
+ | |
+/* License: Ruby's */ | |
static unsigned | |
fileattr_to_unixmode(DWORD attr, const WCHAR *path) | |
{ | |
@@ -5546,7 +5540,7 @@ check_valid_dir(const WCHAR *path) | |
/* License: Ruby's */ | |
static int | |
-stat_by_find(const WCHAR *path, struct stati64 *st) | |
+stat_by_find(const WCHAR *path, struct stati64ns *st) | |
{ | |
HANDLE h; | |
WIN32_FIND_DATAW wfd; | |
@@ -5568,8 +5562,11 @@ stat_by_find(const WCHAR *path, struct stati64 *st) | |
FindClose(h); | |
st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path); | |
st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime); | |
+ st->st_atimensec = filetime_to_nsec(&wfd.ftLastAccessTime); | |
st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime); | |
+ st->st_mtimensec = filetime_to_nsec(&wfd.ftLastWriteTime); | |
st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime); | |
+ st->st_ctimensec = filetime_to_nsec(&wfd.ftCreationTime); | |
st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow; | |
st->st_nlink = 1; | |
return 0; | |
@@ -5587,7 +5584,7 @@ static const WCHAR namespace_prefix[] = {L'\\', L'\\', L'?', L'\\'}; | |
/* License: Ruby's */ | |
static int | |
-winnt_stat(const WCHAR *path, struct stati64 *st) | |
+winnt_stat(const WCHAR *path, struct stati64ns *st) | |
{ | |
HANDLE f; | |
WCHAR finalname[PATH_MAX]; | |
@@ -5595,7 +5592,7 @@ winnt_stat(const WCHAR *path, struct stati64 *st) | |
memset(st, 0, sizeof(*st)); | |
f = open_special(path, 0, 0); | |
if (f != INVALID_HANDLE_VALUE) { | |
- const DWORD attr = stati64_handle(f, st); | |
+ const DWORD attr = stati64ns_handle(f, st); | |
const DWORD len = get_final_path(f, finalname, numberof(finalname), 0); | |
CloseHandle(f); | |
if (attr & FILE_ATTRIBUTE_DIRECTORY) { | |
@@ -5620,7 +5617,7 @@ winnt_stat(const WCHAR *path, struct stati64 *st) | |
/* License: Ruby's */ | |
static int | |
-winnt_lstat(const WCHAR *path, struct stati64 *st) | |
+winnt_lstat(const WCHAR *path, struct stati64ns *st) | |
{ | |
WIN32_FILE_ATTRIBUTE_DATA wfa; | |
const WCHAR *p = path; | |
@@ -5651,8 +5648,11 @@ winnt_lstat(const WCHAR *path, struct stati64 *st) | |
} | |
st->st_mode = fileattr_to_unixmode(wfa.dwFileAttributes, path); | |
st->st_atime = filetime_to_unixtime(&wfa.ftLastAccessTime); | |
+ st->st_atimensec = filetime_to_nsec(&wfa.ftLastAccessTime); | |
st->st_mtime = filetime_to_unixtime(&wfa.ftLastWriteTime); | |
+ st->st_mtimensec = filetime_to_nsec(&wfa.ftLastWriteTime); | |
st->st_ctime = filetime_to_unixtime(&wfa.ftCreationTime); | |
+ st->st_ctimensec = filetime_to_nsec(&wfa.ftCreationTime); | |
} | |
else { | |
if (stat_by_find(path, st)) return -1; | |
@@ -5667,16 +5667,16 @@ winnt_lstat(const WCHAR *path, struct stati64 *st) | |
int | |
rb_w32_stat(const char *path, struct stat *st) | |
{ | |
- struct stati64 tmp; | |
+ struct stati64ns tmp; | |
- if (rb_w32_stati64(path, &tmp)) return -1; | |
+ if (rb_w32_stati64ns(path, &tmp)) return -1; | |
COPY_STAT(tmp, *st, (_off_t)); | |
return 0; | |
} | |
/* License: Ruby's */ | |
static int | |
-wstati64(const WCHAR *path, struct stati64 *st) | |
+wstati64ns(const WCHAR *path, struct stati64ns *st) | |
{ | |
WCHAR *buf1; | |
int ret, size; | |
@@ -5699,7 +5699,7 @@ wstati64(const WCHAR *path, struct stati64 *st) | |
/* License: Ruby's */ | |
static int | |
-wlstati64(const WCHAR *path, struct stati64 *st) | |
+wlstati64ns(const WCHAR *path, struct stati64ns *st) | |
{ | |
WCHAR *buf1; | |
int ret, size; | |
@@ -5756,56 +5756,56 @@ name_for_stat(WCHAR *buf1, const WCHAR *path) | |
/* License: Ruby's */ | |
int | |
-rb_w32_ustati64(const char *path, struct stati64 *st) | |
+rb_w32_ustati64ns(const char *path, struct stati64ns *st) | |
{ | |
- return w32_stati64(path, st, CP_UTF8); | |
+ return w32_stati64ns(path, st, CP_UTF8); | |
} | |
/* License: Ruby's */ | |
int | |
-rb_w32_stati64(const char *path, struct stati64 *st) | |
+rb_w32_stati64ns(const char *path, struct stati64ns *st) | |
{ | |
- return w32_stati64(path, st, filecp()); | |
+ return w32_stati64ns(path, st, filecp()); | |
} | |
/* License: Ruby's */ | |
static int | |
-w32_stati64(const char *path, struct stati64 *st, UINT cp) | |
+w32_stati64ns(const char *path, struct stati64ns *st, UINT cp) | |
{ | |
WCHAR *wpath; | |
int ret; | |
if (!(wpath = mbstr_to_wstr(cp, path, -1, NULL))) | |
return -1; | |
- ret = wstati64(wpath, st); | |
+ ret = wstati64ns(wpath, st); | |
free(wpath); | |
return ret; | |
} | |
/* License: Ruby's */ | |
int | |
-rb_w32_ulstati64(const char *path, struct stati64 *st) | |
+rb_w32_ulstati64ns(const char *path, struct stati64ns *st) | |
{ | |
- return w32_lstati64(path, st, CP_UTF8); | |
+ return w32_lstati64ns(path, st, CP_UTF8); | |
} | |
/* License: Ruby's */ | |
int | |
-rb_w32_lstati64(const char *path, struct stati64 *st) | |
+rb_w32_lstati64ns(const char *path, struct stati64ns *st) | |
{ | |
- return w32_lstati64(path, st, filecp()); | |
+ return w32_lstati64ns(path, st, filecp()); | |
} | |
/* License: Ruby's */ | |
static int | |
-w32_lstati64(const char *path, struct stati64 *st, UINT cp) | |
+w32_lstati64ns(const char *path, struct stati64ns *st, UINT cp) | |
{ | |
WCHAR *wpath; | |
int ret; | |
if (!(wpath = mbstr_to_wstr(cp, path, -1, NULL))) | |
return -1; | |
- ret = wlstati64(wpath, st); | |
+ ret = wlstati64ns(wpath, st); | |
free(wpath); | |
return ret; | |
} | |
@@ -5814,8 +5814,8 @@ w32_lstati64(const char *path, struct stati64 *st, UINT cp) | |
int | |
rb_w32_access(const char *path, int mode) | |
{ | |
- struct stati64 stat; | |
- if (rb_w32_stati64(path, &stat) != 0) | |
+ struct stati64ns stat; | |
+ if (rb_w32_stati64ns(path, &stat) != 0) | |
return -1; | |
mode <<= 6; | |
if ((stat.st_mode & mode) != mode) { | |
@@ -5829,8 +5829,8 @@ rb_w32_access(const char *path, int mode) | |
int | |
rb_w32_uaccess(const char *path, int mode) | |
{ | |
- struct stati64 stat; | |
- if (rb_w32_ustati64(path, &stat) != 0) | |
+ struct stati64ns stat; | |
+ if (rb_w32_ustati64ns(path, &stat) != 0) | |
return -1; | |
mode <<= 6; | |
if ((stat.st_mode & mode) != mode) { | |
@@ -7266,10 +7266,10 @@ wutime(const WCHAR *path, const struct utimbuf *times) | |
{ | |
HANDLE hFile; | |
FILETIME atime, mtime; | |
- struct stati64 stat; | |
+ struct stati64ns stat; | |
int ret = 0; | |
- if (wstati64(path, &stat)) { | |
+ if (wstati64ns(path, &stat)) { | |
return -1; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/file.c b/file.c | |
index 37df00e..b1cdf62 100644 | |
--- a/file.c | |
+++ b/file.c | |
@@ -113,8 +113,8 @@ int flock(int, int); | |
#define chown(p, o, g) rb_w32_uchown((p), (o), (g)) | |
#undef lchown | |
#define lchown(p, o, g) rb_w32_ulchown((p), (o), (g)) | |
-#undef utime | |
-#define utime(p, t) rb_w32_uutime((p), (t)) | |
+#undef utimensat | |
+#define utimensat(s, p, t, f) rb_w32_uutimensat((s), (p), (t), (f)) | |
#undef link | |
#define link(f, t) rb_w32_ulink((f), (t)) | |
#undef unlink | |
diff --git a/include/ruby/win32.h b/include/ruby/win32.h | |
index 5b3486c..82613a8 100644 | |
--- a/include/ruby/win32.h | |
+++ b/include/ruby/win32.h | |
@@ -139,6 +139,13 @@ typedef int clockid_t; | |
#undef fstat | |
#ifdef RUBY_EXPORT | |
#define utime(_p, _t) rb_w32_utime(_p, _t) | |
+#undef HAVE_UTIMES | |
+#define HAVE_UTIMES 1 | |
+#define utimes(_p, _t) rb_w32_utimes(_p, _t) | |
+#undef HAVE_UTIMENSAT | |
+#define HAVE_UTIMENSAT 1 | |
+#define AT_FDCWD -100 | |
+#define utimensat(_d, _p, _t, _f) rb_w32_utimensat(_d, _p, _t, _f) | |
#define lseek(_f, _o, _w) _lseeki64(_f, _o, _w) | |
#define pipe(p) rb_w32_pipe(p) | |
@@ -742,6 +749,10 @@ ssize_t rb_w32_read(int, void *, size_t); | |
ssize_t rb_w32_write(int, const void *, size_t); | |
int rb_w32_utime(const char *, const struct utimbuf *); | |
int rb_w32_uutime(const char *, const struct utimbuf *); | |
+int rb_w32_utimes(const char *, const struct timeval *); | |
+int rb_w32_uutimes(const char *, const struct timeval *); | |
+int rb_w32_utimensat(int /* must be AT_FDCWD */, const char *, const struct timespec *, int /* must be 0 */); | |
+int rb_w32_uutimensat(int /* must be AT_FDCWD */, const char *, const struct timespec *, int /* must be 0 */); | |
long rb_w32_write_console(uintptr_t, int); /* use uintptr_t instead of VALUE because it's not defined yet here */ | |
int WINAPI rb_w32_Sleep(unsigned long msec); | |
int rb_w32_wait_events_blocking(HANDLE *events, int num, DWORD timeout); | |
diff --git a/win32/win32.c b/win32/win32.c | |
index f266a56..7f9a592 100644 | |
--- a/win32/win32.c | |
+++ b/win32/win32.c | |
@@ -7248,6 +7248,7 @@ rb_w32_write_console(uintptr_t strarg, int fd) | |
return (long)reslen; | |
} | |
+#if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__GMTIME64_S) | |
/* License: Ruby's */ | |
static int | |
unixtime_to_filetime(time_t time, FILETIME *ft) | |
@@ -7259,25 +7260,50 @@ unixtime_to_filetime(time_t time, FILETIME *ft) | |
ft->dwHighDateTime = tmp.HighPart; | |
return 0; | |
} | |
+#endif | |
+ | |
+/* License: Ruby's */ | |
+static int | |
+timespec_to_filetime(const struct timespec *ts, FILETIME *ft) | |
+{ | |
+ ULARGE_INTEGER tmp; | |
+ | |
+ tmp.QuadPart = ((LONG_LONG)ts->tv_sec + (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000; | |
+ tmp.QuadPart += ts->tv_nsec / 100; | |
+ ft->dwLowDateTime = tmp.LowPart; | |
+ ft->dwHighDateTime = tmp.HighPart; | |
+ return 0; | |
+} | |
/* License: Ruby's */ | |
static int | |
-wutime(const WCHAR *path, const struct utimbuf *times) | |
+wutimensat(int dirfd, const WCHAR *path, const struct timespec *times, int flags) | |
{ | |
HANDLE hFile; | |
FILETIME atime, mtime; | |
struct stati64ns stat; | |
int ret = 0; | |
+ /* TODO: When path is absolute, dirfd should be ignored. */ | |
+ if (dirfd != AT_FDCWD) { | |
+ errno = ENOSYS; | |
+ return -1; | |
+ } | |
+ | |
+ if (flags != 0) { | |
+ errno = EINVAL; /* AT_SYMLINK_NOFOLLOW isn't supported. */ | |
+ return -1; | |
+ } | |
+ | |
if (wstati64ns(path, &stat)) { | |
return -1; | |
} | |
if (times) { | |
- if (unixtime_to_filetime(times->actime, &atime)) { | |
+ if (timespec_to_filetime(×[0], &atime)) { | |
return -1; | |
} | |
- if (unixtime_to_filetime(times->modtime, &mtime)) { | |
+ if (timespec_to_filetime(×[1], &mtime)) { | |
return -1; | |
} | |
} | |
@@ -7313,26 +7339,78 @@ wutime(const WCHAR *path, const struct utimbuf *times) | |
int | |
rb_w32_uutime(const char *path, const struct utimbuf *times) | |
{ | |
+ struct timespec ts[2]; | |
+ | |
+ ts[0].tv_sec = times->actime; | |
+ ts[0].tv_nsec = 0; | |
+ ts[1].tv_sec = times->modtime; | |
+ ts[1].tv_nsec = 0; | |
+ return rb_w32_uutimensat(AT_FDCWD, path, ts, 0); | |
+} | |
+ | |
+/* License: Ruby's */ | |
+int | |
+rb_w32_utime(const char *path, const struct utimbuf *times) | |
+{ | |
+ struct timespec ts[2]; | |
+ | |
+ ts[0].tv_sec = times->actime; | |
+ ts[0].tv_nsec = 0; | |
+ ts[1].tv_sec = times->modtime; | |
+ ts[1].tv_nsec = 0; | |
+ return rb_w32_utimensat(AT_FDCWD, path, ts, 0); | |
+} | |
+ | |
+/* License: Ruby's */ | |
+int | |
+rb_w32_uutimes(const char *path, const struct timeval *times) | |
+{ | |
+ struct timespec ts[2]; | |
+ | |
+ ts[0].tv_sec = times[0].tv_sec; | |
+ ts[0].tv_nsec = times[0].tv_usec * 1000; | |
+ ts[1].tv_sec = times[1].tv_sec; | |
+ ts[1].tv_nsec = times[1].tv_usec * 1000; | |
+ return rb_w32_uutimensat(AT_FDCWD, path, ts, 0); | |
+} | |
+ | |
+/* License: Ruby's */ | |
+int | |
+rb_w32_utimes(const char *path, const struct timeval *times) | |
+{ | |
+ struct timespec ts[2]; | |
+ | |
+ ts[0].tv_sec = times[0].tv_sec; | |
+ ts[0].tv_nsec = times[0].tv_usec * 1000; | |
+ ts[1].tv_sec = times[1].tv_sec; | |
+ ts[1].tv_nsec = times[1].tv_usec * 1000; | |
+ return rb_w32_utimensat(AT_FDCWD, path, ts, 0); | |
+} | |
+ | |
+/* License: Ruby's */ | |
+int | |
+rb_w32_uutimensat(int dirfd, const char *path, const struct timespec *times, int flags) | |
+{ | |
WCHAR *wpath; | |
int ret; | |
if (!(wpath = utf8_to_wstr(path, NULL))) | |
return -1; | |
- ret = wutime(wpath, times); | |
+ ret = wutimensat(dirfd, wpath, times, flags); | |
free(wpath); | |
return ret; | |
} | |
/* License: Ruby's */ | |
int | |
-rb_w32_utime(const char *path, const struct utimbuf *times) | |
+rb_w32_utimensat(int dirfd, const char *path, const struct timespec *times, int flags) | |
{ | |
WCHAR *wpath; | |
int ret; | |
if (!(wpath = filecp_to_wstr(path, NULL))) | |
return -1; | |
- ret = wutime(wpath, times); | |
+ ret = wutimensat(dirfd, wpath, times, flags); | |
free(wpath); | |
return ret; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment