support nanosec file timestamp on newer Windows
Support nanosec file timestamp on Windows 8 or later. Original patches are written by kubo (Kubo Takehiro). Windows 7 and earlier also supports nanosec file timestamp, but it's too accurate than system time. so, this feature is disabled on such versions. [Feature #13726] this change also includes [Misc #13702] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61013 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
b91d5b7958
commit
ce7c1c0577
4
dir.c
4
dir.c
@ -1364,9 +1364,9 @@ to_be_ignored(int e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define STAT(p, s) rb_w32_ustati64((p), (s))
|
#define STAT(p, s) rb_w32_ustati64ns((p), (s))
|
||||||
#undef lstat
|
#undef lstat
|
||||||
#define lstat(p, s) rb_w32_ulstati64((p), (s))
|
#define lstat(p, s) rb_w32_ulstati64ns((p), (s))
|
||||||
#else
|
#else
|
||||||
#define STAT(p, s) stat((p), (s))
|
#define STAT(p, s) stat((p), (s))
|
||||||
#endif
|
#endif
|
||||||
|
8
file.c
8
file.c
@ -91,9 +91,9 @@ int flock(int, int);
|
|||||||
/* define system APIs */
|
/* define system APIs */
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "win32/file.h"
|
#include "win32/file.h"
|
||||||
#define STAT(p, s) rb_w32_ustati64((p), (s))
|
#define STAT(p, s) rb_w32_ustati64ns((p), (s))
|
||||||
#undef lstat
|
#undef lstat
|
||||||
#define lstat(p, s) rb_w32_ulstati64((p), (s))
|
#define lstat(p, s) rb_w32_ulstati64ns((p), (s))
|
||||||
#undef access
|
#undef access
|
||||||
#define access(p, m) rb_w32_uaccess((p), (m))
|
#define access(p, m) rb_w32_uaccess((p), (m))
|
||||||
#undef truncate
|
#undef truncate
|
||||||
@ -104,8 +104,8 @@ int flock(int, int);
|
|||||||
#define chown(p, o, g) rb_w32_uchown((p), (o), (g))
|
#define chown(p, o, g) rb_w32_uchown((p), (o), (g))
|
||||||
#undef lchown
|
#undef lchown
|
||||||
#define lchown(p, o, g) rb_w32_ulchown((p), (o), (g))
|
#define lchown(p, o, g) rb_w32_ulchown((p), (o), (g))
|
||||||
#undef utime
|
#undef utimensat
|
||||||
#define utime(p, t) rb_w32_uutime((p), (t))
|
#define utimensat(s, p, t, f) rb_w32_uutimensat((s), (p), (t), (f))
|
||||||
#undef link
|
#undef link
|
||||||
#define link(f, t) rb_w32_ulink((f), (t))
|
#define link(f, t) rb_w32_ulink((f), (t))
|
||||||
#undef unlink
|
#undef unlink
|
||||||
|
@ -139,6 +139,13 @@ typedef int clockid_t;
|
|||||||
#undef fstat
|
#undef fstat
|
||||||
#ifdef RUBY_EXPORT
|
#ifdef RUBY_EXPORT
|
||||||
#define utime(_p, _t) rb_w32_utime(_p, _t)
|
#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 lseek(_f, _o, _w) _lseeki64(_f, _o, _w)
|
||||||
|
|
||||||
#define pipe(p) rb_w32_pipe(p)
|
#define pipe(p) rb_w32_pipe(p)
|
||||||
@ -151,7 +158,6 @@ typedef int clockid_t;
|
|||||||
#define getppid() rb_w32_getppid()
|
#define getppid() rb_w32_getppid()
|
||||||
#define sleep(x) rb_w32_Sleep((x)*1000)
|
#define sleep(x) rb_w32_Sleep((x)*1000)
|
||||||
#define Sleep(msec) (void)rb_w32_Sleep(msec)
|
#define Sleep(msec) (void)rb_w32_Sleep(msec)
|
||||||
#define fstati64(fd,st) rb_w32_fstati64(fd,st)
|
|
||||||
|
|
||||||
#undef execv
|
#undef execv
|
||||||
#define execv(path,argv) rb_w32_aspawn(P_OVERLAY,path,argv)
|
#define execv(path,argv) rb_w32_aspawn(P_OVERLAY,path,argv)
|
||||||
@ -166,26 +172,39 @@ typedef int clockid_t;
|
|||||||
#define unlink(p) rb_w32_unlink(p)
|
#define unlink(p) rb_w32_unlink(p)
|
||||||
#endif /* RUBY_EXPORT */
|
#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
|
#if SIZEOF_OFF_T == 8
|
||||||
#define off_t __int64
|
#define off_t __int64
|
||||||
#define stat stati64
|
#define stat stati64ns
|
||||||
#define fstat(fd,st) fstati64(fd,st)
|
#define HAVE_STRUCT_STAT_ST_ATIMENSEC
|
||||||
#if !defined(_MSC_VER) || RUBY_MSVCRT_VERSION < 80
|
#define HAVE_STRUCT_STAT_ST_MTIMENSEC
|
||||||
#define stati64 _stati64
|
#define HAVE_STRUCT_STAT_ST_CTIMENSEC
|
||||||
#ifndef _stati64
|
#define fstat(fd,st) rb_w32_fstati64ns(fd,st)
|
||||||
#define _stati64(path, st) rb_w32_stati64(path, st)
|
#define stati64ns(path, st) rb_w32_stati64ns(path, st)
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#define stati64 _stat64
|
|
||||||
#define _stat64(path, st) rb_w32_stati64(path, st)
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
#define stat(path,st) rb_w32_stat(path,st)
|
#define stat(path,st) rb_w32_stat(path,st)
|
||||||
#define fstat(fd,st) rb_w32_fstat(fd,st)
|
#define fstat(fd,st) rb_w32_fstat(fd,st)
|
||||||
extern int rb_w32_stat(const char *, struct stat *);
|
extern int rb_w32_stat(const char *, struct stat *);
|
||||||
extern int rb_w32_fstat(int, struct stat *);
|
extern int rb_w32_fstat(int, struct stat *);
|
||||||
#endif
|
#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 access(path,mode) rb_w32_access(path,mode)
|
||||||
|
|
||||||
#define strcasecmp _stricmp
|
#define strcasecmp _stricmp
|
||||||
@ -316,14 +335,14 @@ extern int rb_w32_urmdir(const char *);
|
|||||||
extern int rb_w32_unlink(const char *);
|
extern int rb_w32_unlink(const char *);
|
||||||
extern int rb_w32_uunlink(const char *);
|
extern int rb_w32_uunlink(const char *);
|
||||||
extern int rb_w32_uchmod(const char *, int);
|
extern int rb_w32_uchmod(const char *, int);
|
||||||
extern int rb_w32_stati64(const char *, struct stati64 *);
|
extern int rb_w32_stati64ns(const char *, struct stati64ns *);
|
||||||
extern int rb_w32_ustati64(const char *, struct stati64 *);
|
extern int rb_w32_ustati64ns(const char *, struct stati64ns *);
|
||||||
extern int rb_w32_lstati64(const char *, struct stati64 *);
|
extern int rb_w32_lstati64ns(const char *, struct stati64ns *);
|
||||||
extern int rb_w32_ulstati64(const char *, struct stati64 *);
|
extern int rb_w32_ulstati64ns(const char *, struct stati64ns *);
|
||||||
extern int rb_w32_access(const char *, int);
|
extern int rb_w32_access(const char *, int);
|
||||||
extern int rb_w32_uaccess(const char *, int);
|
extern int rb_w32_uaccess(const char *, int);
|
||||||
extern char rb_w32_fd_is_text(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);
|
extern int rb_w32_dup2(int, int);
|
||||||
|
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
@ -440,8 +459,6 @@ extern rb_gid_t getegid (void);
|
|||||||
extern int setuid (rb_uid_t);
|
extern int setuid (rb_uid_t);
|
||||||
extern int setgid (rb_gid_t);
|
extern int setgid (rb_gid_t);
|
||||||
|
|
||||||
extern int fstati64(int, struct stati64 *);
|
|
||||||
|
|
||||||
extern char *rb_w32_strerror(int);
|
extern char *rb_w32_strerror(int);
|
||||||
|
|
||||||
#ifdef RUBY_EXPORT
|
#ifdef RUBY_EXPORT
|
||||||
@ -732,6 +749,10 @@ ssize_t rb_w32_read(int, void *, size_t);
|
|||||||
ssize_t rb_w32_write(int, const 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_utime(const char *, const struct utimbuf *);
|
||||||
int rb_w32_uutime(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 */
|
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 WINAPI rb_w32_Sleep(unsigned long msec);
|
||||||
int rb_w32_wait_events_blocking(HANDLE *events, int num, DWORD timeout);
|
int rb_w32_wait_events_blocking(HANDLE *events, int num, DWORD timeout);
|
||||||
|
262
win32/win32.c
262
win32/win32.c
@ -62,14 +62,14 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int w32_wopen(const WCHAR *file, int oflag, int perm);
|
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_stati64ns(const char *path, struct stati64ns *st, UINT cp);
|
||||||
static int w32_lstati64(const char *path, struct stati64 *st, UINT cp);
|
static int w32_lstati64ns(const char *path, struct stati64ns *st, UINT cp);
|
||||||
static char *w32_getenv(const char *name, UINT cp);
|
static char *w32_getenv(const char *name, UINT cp);
|
||||||
|
|
||||||
#undef getenv
|
#undef getenv
|
||||||
#define DLN_FIND_EXTRA_ARG_DECL ,UINT cp
|
#define DLN_FIND_EXTRA_ARG_DECL ,UINT cp
|
||||||
#define DLN_FIND_EXTRA_ARG ,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)
|
#define getenv(name) w32_getenv(name, cp)
|
||||||
#undef CharNext
|
#undef CharNext
|
||||||
#define CharNext(p) CharNextExA(cp, (p), 0)
|
#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.h"
|
||||||
#include "dln_find.c"
|
#include "dln_find.c"
|
||||||
#undef MAXPATHLEN
|
#undef MAXPATHLEN
|
||||||
#undef rb_w32_stati64
|
#undef rb_w32_stati64ns
|
||||||
#undef dln_find_exe_r
|
#undef dln_find_exe_r
|
||||||
#undef dln_find_file_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)
|
#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);
|
static int has_redirection(const char *, UINT);
|
||||||
int rb_w32_wait_events(HANDLE *events, int num, DWORD timeout);
|
int rb_w32_wait_events(HANDLE *events, int num, DWORD timeout);
|
||||||
static int rb_w32_open_osfhandle(intptr_t osfhandle, int flags);
|
static int rb_w32_open_osfhandle(intptr_t osfhandle, int flags);
|
||||||
static int wstati64(const WCHAR *path, struct stati64 *st);
|
static int wstati64ns(const WCHAR *path, struct stati64ns *st);
|
||||||
static int wlstati64(const WCHAR *path, struct stati64 *st);
|
static int wlstati64ns(const WCHAR *path, struct stati64ns *st);
|
||||||
VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc);
|
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);
|
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);
|
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 *
|
static DIR *
|
||||||
w32_wopendir(const WCHAR *wpath)
|
w32_wopendir(const WCHAR *wpath)
|
||||||
{
|
{
|
||||||
struct stati64 sbuf;
|
struct stati64ns sbuf;
|
||||||
WIN32_FIND_DATAW fd;
|
WIN32_FIND_DATAW fd;
|
||||||
HANDLE fh;
|
HANDLE fh;
|
||||||
DIR *p;
|
DIR *p;
|
||||||
@ -2006,7 +2006,7 @@ w32_wopendir(const WCHAR *wpath)
|
|||||||
//
|
//
|
||||||
// check to see if we've got a directory
|
// check to see if we've got a directory
|
||||||
//
|
//
|
||||||
if (wstati64(wpath, &sbuf) < 0) {
|
if (wstati64ns(wpath, &sbuf) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!(sbuf.st_mode & S_IFDIR) &&
|
if (!(sbuf.st_mode & S_IFDIR) &&
|
||||||
@ -4571,6 +4571,27 @@ waitpid(rb_pid_t pid, int *stat_loc, int options)
|
|||||||
|
|
||||||
#include <sys/timeb.h>
|
#include <sys/timeb.h>
|
||||||
|
|
||||||
|
static int have_precisetime = -1;
|
||||||
|
|
||||||
|
static void get_systemtime(FILETIME *ft)
|
||||||
|
{
|
||||||
|
typedef void (WINAPI *get_time_func)(FILETIME *ft);
|
||||||
|
static get_time_func func = (get_time_func)-1;
|
||||||
|
|
||||||
|
if (func == (get_time_func)-1) {
|
||||||
|
/* GetSystemTimePreciseAsFileTime is available since Windows 8 and Windows Server 2012. */
|
||||||
|
func = (get_time_func)get_proc_address("kernel32", "GetSystemTimePreciseAsFileTime", NULL);
|
||||||
|
if (func == NULL) {
|
||||||
|
func = GetSystemTimeAsFileTime;
|
||||||
|
have_precisetime = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
have_precisetime = 1;
|
||||||
|
}
|
||||||
|
if (!ft) return;
|
||||||
|
func(ft);
|
||||||
|
}
|
||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
static int
|
static int
|
||||||
filetime_to_timeval(const FILETIME* ft, struct timeval *tv)
|
filetime_to_timeval(const FILETIME* ft, struct timeval *tv)
|
||||||
@ -4595,21 +4616,6 @@ filetime_to_timeval(const FILETIME* ft, struct timeval *tv)
|
|||||||
return tv->tv_sec > 0 ? 0 : -1;
|
return tv->tv_sec > 0 ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_systemtime(FILETIME *ft)
|
|
||||||
{
|
|
||||||
typedef void (WINAPI *get_time_func)(FILETIME *ft);
|
|
||||||
static get_time_func func = (get_time_func)-1;
|
|
||||||
|
|
||||||
if (func == (get_time_func)-1) {
|
|
||||||
/* GetSystemTimePreciseAsFileTime is available since Windows 8 and Windows Server 2012. */
|
|
||||||
func = (get_time_func)get_proc_address("kernel32", "GetSystemTimePreciseAsFileTime", NULL);
|
|
||||||
if (func == NULL) {
|
|
||||||
func = GetSystemTimeAsFileTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func(ft);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
int __cdecl
|
int __cdecl
|
||||||
gettimeofday(struct timeval *tv, struct timezone *tz)
|
gettimeofday(struct timeval *tv, struct timezone *tz)
|
||||||
@ -5381,12 +5387,13 @@ isUNCRoot(const WCHAR *path)
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static time_t filetime_to_unixtime(const FILETIME *ft);
|
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 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 */
|
/* License: Ruby's */
|
||||||
static void
|
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
|
/* struct stati64 layout
|
||||||
*
|
*
|
||||||
@ -5413,19 +5420,6 @@ stati64_set_inode(BY_HANDLE_FILE_INFORMATION *pinfo, struct stati64 *st)
|
|||||||
p4[5] = pinfo->nFileIndexLow;
|
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
|
#undef fstat
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
int
|
int
|
||||||
@ -5446,27 +5440,20 @@ rb_w32_fstat(int fd, struct stat *st)
|
|||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
int
|
int
|
||||||
rb_w32_fstati64(int fd, struct stati64 *st)
|
rb_w32_fstati64ns(int fd, struct stati64ns *st)
|
||||||
{
|
{
|
||||||
struct stat tmp;
|
struct stat tmp;
|
||||||
int ret;
|
int ret = fstat(fd, &tmp);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (ret) return ret;
|
if (ret) return ret;
|
||||||
COPY_STAT(tmp, *st, +);
|
COPY_STAT(tmp, *st, +);
|
||||||
stati64_handle((HANDLE)_get_osfhandle(fd), st);
|
stati64ns_handle((HANDLE)_get_osfhandle(fd), st);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
static DWORD
|
static DWORD
|
||||||
stati64_handle(HANDLE h, struct stati64 *st)
|
stati64ns_handle(HANDLE h, struct stati64ns *st)
|
||||||
{
|
{
|
||||||
BY_HANDLE_FILE_INFORMATION info;
|
BY_HANDLE_FILE_INFORMATION info;
|
||||||
DWORD attr = (DWORD)-1;
|
DWORD attr = (DWORD)-1;
|
||||||
@ -5474,11 +5461,14 @@ stati64_handle(HANDLE h, struct stati64 *st)
|
|||||||
if (GetFileInformationByHandle(h, &info)) {
|
if (GetFileInformationByHandle(h, &info)) {
|
||||||
st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow;
|
st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow;
|
||||||
st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
|
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_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
|
||||||
|
st->st_mtimensec = filetime_to_nsec(&info.ftLastWriteTime);
|
||||||
st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
|
st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
|
||||||
|
st->st_ctimensec = filetime_to_nsec(&info.ftCreationTime);
|
||||||
st->st_nlink = info.nNumberOfLinks;
|
st->st_nlink = info.nNumberOfLinks;
|
||||||
attr = info.dwFileAttributes;
|
attr = info.dwFileAttributes;
|
||||||
stati64_set_inode(&info, st);
|
stati64ns_set_inode(&info, st);
|
||||||
}
|
}
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
@ -5495,6 +5485,20 @@ filetime_to_unixtime(const FILETIME *ft)
|
|||||||
return tv.tv_sec;
|
return tv.tv_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* License: Ruby's */
|
||||||
|
static long
|
||||||
|
filetime_to_nsec(const FILETIME *ft)
|
||||||
|
{
|
||||||
|
if (have_precisetime <= 0)
|
||||||
|
return 0;
|
||||||
|
else {
|
||||||
|
ULARGE_INTEGER tmp;
|
||||||
|
tmp.LowPart = ft->dwLowDateTime;
|
||||||
|
tmp.HighPart = ft->dwHighDateTime;
|
||||||
|
return (long)(tmp.QuadPart % 10000000) * 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
static unsigned
|
static unsigned
|
||||||
fileattr_to_unixmode(DWORD attr, const WCHAR *path)
|
fileattr_to_unixmode(DWORD attr, const WCHAR *path)
|
||||||
@ -5583,7 +5587,7 @@ check_valid_dir(const WCHAR *path)
|
|||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
static int
|
static int
|
||||||
stat_by_find(const WCHAR *path, struct stati64 *st)
|
stat_by_find(const WCHAR *path, struct stati64ns *st)
|
||||||
{
|
{
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
WIN32_FIND_DATAW wfd;
|
WIN32_FIND_DATAW wfd;
|
||||||
@ -5605,8 +5609,11 @@ stat_by_find(const WCHAR *path, struct stati64 *st)
|
|||||||
FindClose(h);
|
FindClose(h);
|
||||||
st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path);
|
st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path);
|
||||||
st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime);
|
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_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime);
|
||||||
|
st->st_mtimensec = filetime_to_nsec(&wfd.ftLastWriteTime);
|
||||||
st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime);
|
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_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow;
|
||||||
st->st_nlink = 1;
|
st->st_nlink = 1;
|
||||||
return 0;
|
return 0;
|
||||||
@ -5624,7 +5631,7 @@ static const WCHAR namespace_prefix[] = {L'\\', L'\\', L'?', L'\\'};
|
|||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
static int
|
static int
|
||||||
winnt_stat(const WCHAR *path, struct stati64 *st)
|
winnt_stat(const WCHAR *path, struct stati64ns *st)
|
||||||
{
|
{
|
||||||
HANDLE f;
|
HANDLE f;
|
||||||
WCHAR finalname[PATH_MAX];
|
WCHAR finalname[PATH_MAX];
|
||||||
@ -5632,7 +5639,7 @@ winnt_stat(const WCHAR *path, struct stati64 *st)
|
|||||||
memset(st, 0, sizeof(*st));
|
memset(st, 0, sizeof(*st));
|
||||||
f = open_special(path, 0, 0);
|
f = open_special(path, 0, 0);
|
||||||
if (f != INVALID_HANDLE_VALUE) {
|
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);
|
const DWORD len = get_final_path(f, finalname, numberof(finalname), 0);
|
||||||
CloseHandle(f);
|
CloseHandle(f);
|
||||||
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
|
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
|
||||||
@ -5657,7 +5664,7 @@ winnt_stat(const WCHAR *path, struct stati64 *st)
|
|||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
static int
|
static int
|
||||||
winnt_lstat(const WCHAR *path, struct stati64 *st)
|
winnt_lstat(const WCHAR *path, struct stati64ns *st)
|
||||||
{
|
{
|
||||||
WIN32_FILE_ATTRIBUTE_DATA wfa;
|
WIN32_FILE_ATTRIBUTE_DATA wfa;
|
||||||
const WCHAR *p = path;
|
const WCHAR *p = path;
|
||||||
@ -5688,8 +5695,11 @@ winnt_lstat(const WCHAR *path, struct stati64 *st)
|
|||||||
}
|
}
|
||||||
st->st_mode = fileattr_to_unixmode(wfa.dwFileAttributes, path);
|
st->st_mode = fileattr_to_unixmode(wfa.dwFileAttributes, path);
|
||||||
st->st_atime = filetime_to_unixtime(&wfa.ftLastAccessTime);
|
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_mtime = filetime_to_unixtime(&wfa.ftLastWriteTime);
|
||||||
|
st->st_mtimensec = filetime_to_nsec(&wfa.ftLastWriteTime);
|
||||||
st->st_ctime = filetime_to_unixtime(&wfa.ftCreationTime);
|
st->st_ctime = filetime_to_unixtime(&wfa.ftCreationTime);
|
||||||
|
st->st_ctimensec = filetime_to_nsec(&wfa.ftCreationTime);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (stat_by_find(path, st)) return -1;
|
if (stat_by_find(path, st)) return -1;
|
||||||
@ -5704,16 +5714,16 @@ winnt_lstat(const WCHAR *path, struct stati64 *st)
|
|||||||
int
|
int
|
||||||
rb_w32_stat(const char *path, struct stat *st)
|
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));
|
COPY_STAT(tmp, *st, (_off_t));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
static int
|
static int
|
||||||
wstati64(const WCHAR *path, struct stati64 *st)
|
wstati64ns(const WCHAR *path, struct stati64ns *st)
|
||||||
{
|
{
|
||||||
WCHAR *buf1;
|
WCHAR *buf1;
|
||||||
int ret, size;
|
int ret, size;
|
||||||
@ -5736,7 +5746,7 @@ wstati64(const WCHAR *path, struct stati64 *st)
|
|||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
static int
|
static int
|
||||||
wlstati64(const WCHAR *path, struct stati64 *st)
|
wlstati64ns(const WCHAR *path, struct stati64ns *st)
|
||||||
{
|
{
|
||||||
WCHAR *buf1;
|
WCHAR *buf1;
|
||||||
int ret, size;
|
int ret, size;
|
||||||
@ -5793,56 +5803,56 @@ name_for_stat(WCHAR *buf1, const WCHAR *path)
|
|||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
int
|
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 */
|
/* License: Ruby's */
|
||||||
int
|
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 */
|
/* License: Ruby's */
|
||||||
static int
|
static int
|
||||||
w32_stati64(const char *path, struct stati64 *st, UINT cp)
|
w32_stati64ns(const char *path, struct stati64ns *st, UINT cp)
|
||||||
{
|
{
|
||||||
WCHAR *wpath;
|
WCHAR *wpath;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!(wpath = mbstr_to_wstr(cp, path, -1, NULL)))
|
if (!(wpath = mbstr_to_wstr(cp, path, -1, NULL)))
|
||||||
return -1;
|
return -1;
|
||||||
ret = wstati64(wpath, st);
|
ret = wstati64ns(wpath, st);
|
||||||
free(wpath);
|
free(wpath);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
int
|
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 */
|
/* License: Ruby's */
|
||||||
int
|
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 */
|
/* License: Ruby's */
|
||||||
static int
|
static int
|
||||||
w32_lstati64(const char *path, struct stati64 *st, UINT cp)
|
w32_lstati64ns(const char *path, struct stati64ns *st, UINT cp)
|
||||||
{
|
{
|
||||||
WCHAR *wpath;
|
WCHAR *wpath;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!(wpath = mbstr_to_wstr(cp, path, -1, NULL)))
|
if (!(wpath = mbstr_to_wstr(cp, path, -1, NULL)))
|
||||||
return -1;
|
return -1;
|
||||||
ret = wlstati64(wpath, st);
|
ret = wlstati64ns(wpath, st);
|
||||||
free(wpath);
|
free(wpath);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -5851,8 +5861,8 @@ w32_lstati64(const char *path, struct stati64 *st, UINT cp)
|
|||||||
int
|
int
|
||||||
rb_w32_access(const char *path, int mode)
|
rb_w32_access(const char *path, int mode)
|
||||||
{
|
{
|
||||||
struct stati64 stat;
|
struct stati64ns stat;
|
||||||
if (rb_w32_stati64(path, &stat) != 0)
|
if (rb_w32_stati64ns(path, &stat) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
mode <<= 6;
|
mode <<= 6;
|
||||||
if ((stat.st_mode & mode) != mode) {
|
if ((stat.st_mode & mode) != mode) {
|
||||||
@ -5866,8 +5876,8 @@ rb_w32_access(const char *path, int mode)
|
|||||||
int
|
int
|
||||||
rb_w32_uaccess(const char *path, int mode)
|
rb_w32_uaccess(const char *path, int mode)
|
||||||
{
|
{
|
||||||
struct stati64 stat;
|
struct stati64ns stat;
|
||||||
if (rb_w32_ustati64(path, &stat) != 0)
|
if (rb_w32_ustati64ns(path, &stat) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
mode <<= 6;
|
mode <<= 6;
|
||||||
if ((stat.st_mode & mode) != mode) {
|
if ((stat.st_mode & mode) != mode) {
|
||||||
@ -7318,6 +7328,7 @@ rb_w32_write_console(uintptr_t strarg, int fd)
|
|||||||
return (long)reslen;
|
return (long)reslen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__GMTIME64_S)
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
static int
|
static int
|
||||||
unixtime_to_filetime(time_t time, FILETIME *ft)
|
unixtime_to_filetime(time_t time, FILETIME *ft)
|
||||||
@ -7329,25 +7340,50 @@ unixtime_to_filetime(time_t time, FILETIME *ft)
|
|||||||
ft->dwHighDateTime = tmp.HighPart;
|
ft->dwHighDateTime = tmp.HighPart;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
static int
|
static int
|
||||||
wutime(const WCHAR *path, const struct utimbuf *times)
|
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
|
||||||
|
wutimensat(int dirfd, const WCHAR *path, const struct timespec *times, int flags)
|
||||||
{
|
{
|
||||||
HANDLE hFile;
|
HANDLE hFile;
|
||||||
FILETIME atime, mtime;
|
FILETIME atime, mtime;
|
||||||
struct stati64 stat;
|
struct stati64ns stat;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (wstati64(path, &stat)) {
|
/* 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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (times) {
|
if (times) {
|
||||||
if (unixtime_to_filetime(times->actime, &atime)) {
|
if (timespec_to_filetime(×[0], &atime)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (unixtime_to_filetime(times->modtime, &mtime)) {
|
if (timespec_to_filetime(×[1], &mtime)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7383,26 +7419,78 @@ wutime(const WCHAR *path, const struct utimbuf *times)
|
|||||||
int
|
int
|
||||||
rb_w32_uutime(const char *path, const struct utimbuf *times)
|
rb_w32_uutime(const char *path, const struct utimbuf *times)
|
||||||
{
|
{
|
||||||
WCHAR *wpath;
|
struct timespec ts[2];
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!(wpath = utf8_to_wstr(path, NULL)))
|
ts[0].tv_sec = times->actime;
|
||||||
return -1;
|
ts[0].tv_nsec = 0;
|
||||||
ret = wutime(wpath, times);
|
ts[1].tv_sec = times->modtime;
|
||||||
free(wpath);
|
ts[1].tv_nsec = 0;
|
||||||
return ret;
|
return rb_w32_uutimensat(AT_FDCWD, path, ts, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
int
|
int
|
||||||
rb_w32_utime(const char *path, const struct utimbuf *times)
|
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 = wutimensat(dirfd, wpath, times, flags);
|
||||||
|
free(wpath);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* License: Ruby's */
|
||||||
|
int
|
||||||
|
rb_w32_utimensat(int dirfd, const char *path, const struct timespec *times, int flags)
|
||||||
{
|
{
|
||||||
WCHAR *wpath;
|
WCHAR *wpath;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!(wpath = filecp_to_wstr(path, NULL)))
|
if (!(wpath = filecp_to_wstr(path, NULL)))
|
||||||
return -1;
|
return -1;
|
||||||
ret = wutime(wpath, times);
|
ret = wutimensat(dirfd, wpath, times, flags);
|
||||||
free(wpath);
|
free(wpath);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user