Skip to content

Commit

Permalink
Unix.utimes: use native Windows API to avoid unintended DST timestamp…
Browse files Browse the repository at this point in the history
… shift
  • Loading branch information
nojb committed Oct 26, 2017
1 parent e51c390 commit af20b3e
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 18 deletions.
1 change: 0 additions & 1 deletion .gitignore
Expand Up @@ -213,7 +213,6 @@ _ocamltest
/otherlibs/win32unix/strofaddr.c
/otherlibs/win32unix/time.c
/otherlibs/win32unix/unlink.c
/otherlibs/win32unix/utimes.c

/parsing/parser.ml
/parsing/parser.mli
Expand Down
2 changes: 0 additions & 2 deletions byterun/caml/misc.h
Expand Up @@ -183,7 +183,6 @@ typedef wchar_t char_os;
#define getenv_os _wgetenv
#define system_os _wsystem
#define rmdir_os _wrmdir
#define utime_os _wutime
#define putenv_os _wputenv
#define chmod_os _wchmod
#define execv_os _wexecv
Expand Down Expand Up @@ -217,7 +216,6 @@ typedef char char_os;
#define getenv_os getenv
#define system_os system
#define rmdir_os rmdir
#define utime_os utime
#define putenv_os putenv
#define chmod_os chmod
#define execv_os execv
Expand Down
14 changes: 3 additions & 11 deletions otherlibs/unix/utimes.c
Expand Up @@ -58,21 +58,13 @@ CAMLprim value unix_utimes(value path, value atime, value mtime)
#elif defined(HAS_UTIME)

#include <sys/types.h>
#ifndef _WIN32
#include <utime.h>
#else
#include <sys/utime.h>
#endif

CAMLprim value unix_utimes(value path, value atime, value mtime)
{
CAMLparam3(path, atime, mtime);
#ifdef _WIN32
struct _utimbuf times, * t;
#else
struct utimbuf times, * t;
#endif
char_os * p;
char * p;
int ret;
double at, mt;
caml_unix_check_path(path, "utimes");
Expand All @@ -85,9 +77,9 @@ CAMLprim value unix_utimes(value path, value atime, value mtime)
times.modtime = mt;
t = &times;
}
p = caml_stat_strdup_to_os(String_val(path));
p = caml_stat_strdup(String_val(path));
caml_enter_blocking_section();
ret = utime_os(p, t);
ret = utime(p, t);
caml_leave_blocking_section();
caml_stat_free(p);
if (ret == -1) uerror("utimes", path);
Expand Down
4 changes: 2 additions & 2 deletions otherlibs/win32unix/Makefile
Expand Up @@ -26,15 +26,15 @@ WIN_FILES = accept.c bind.c channels.c close.c \
select.c sendrecv.c \
shutdown.c sleep.c socket.c sockopt.c startup.c stat.c \
symlink.c system.c times.c unixsupport.c windir.c winwait.c write.c \
winlist.c winworker.c windbug.c
winlist.c winworker.c windbug.c utimes.c

# Files from the ../unix directory
UNIX_FILES = access.c addrofstr.c chdir.c chmod.c cst2constr.c \
cstringv.c execv.c execve.c execvp.c \
exit.c getaddrinfo.c getcwd.c gethost.c gethostname.c \
getnameinfo.c getproto.c \
getserv.c gmtime.c mmap_ba.c putenv.c rmdir.c \
socketaddr.c strofaddr.c time.c unlink.c utimes.c
socketaddr.c strofaddr.c time.c unlink.c

UNIX_CAML_FILES = unix.mli unixLabels.mli unixLabels.ml

Expand Down
4 changes: 2 additions & 2 deletions otherlibs/win32unix/stat.c
Expand Up @@ -127,8 +127,8 @@ static int convert_time(FILETIME* time, __time64_t* result, __time64_t def)
ULARGE_INTEGER utime = {{time->dwLowDateTime, time->dwHighDateTime}};

if (utime.QuadPart) {
/* There are 11644473600000 seconds between 1 January 1601 (the NT Epoch)
* and 1 January 1970 (the Unix Epoch). FILETIME is measured in 100ns ticks.
/* There are 11644473600 seconds between 1 January 1601 (the NT Epoch) and 1
* January 1970 (the Unix Epoch). FILETIME is measured in 100ns ticks.
*/
*result = (utime.QuadPart - INT64_LITERAL(116444736000000000U));
}
Expand Down
80 changes: 80 additions & 0 deletions otherlibs/win32unix/utimes.c
@@ -0,0 +1,80 @@
/**************************************************************************/
/* */
/* OCaml */
/* */
/* Nicolas Ojeda Bar, LexiFi */
/* */
/* Copyright 2017 Institut National de Recherche en Informatique et */
/* en Automatique. */
/* */
/* All rights reserved. This file is distributed under the terms of */
/* the GNU Lesser General Public License version 2.1, with the */
/* special exception on linking described in the file LICENSE. */
/* */
/**************************************************************************/

#define CAML_INTERNALS

#include <caml/fail.h>
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/signals.h>
#include <caml/osdeps.h>
#include "unixsupport.h"

#include <windows.h>

static void convert_time(double unixTime, FILETIME* ft)
{
ULARGE_INTEGER u;
/* There are 11644473600 seconds between 1 January 1601 (the NT Epoch) and 1
* January 1970 (the Unix Epoch). FILETIME is measured in 100ns ticks.
*/
u.QuadPart = (ULONGLONG)(unixTime * 10000000.0) + INT64_LITERAL(116444736000000000U);
ft->dwLowDateTime = u.LowPart;
ft->dwHighDateTime = u.HighPart;
}

CAMLprim value unix_utimes(value path, value atime, value mtime)
{
CAMLparam3(path, atime, mtime);
WCHAR *wpath;
HANDLE hFile;
FILETIME lastAccessTime, lastModificationTime;
SYSTEMTIME systemTime;
double at, mt;
BOOL res;

caml_unix_check_path(path, "utimes");
at = Double_val(atime);
mt = Double_val(mtime);
wpath = caml_stat_strdup_to_utf16(String_val(path));
caml_enter_blocking_section();
hFile = CreateFile(wpath,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
caml_leave_blocking_section();
caml_stat_free(wpath);
if (hFile == INVALID_HANDLE_VALUE) {
win32_maperr(GetLastError());
uerror("utimes", path);
}
if (at == 0.0 && mt == 0.0) {
GetSystemTime(&systemTime);
SystemTimeToFileTime(&systemTime, &lastAccessTime);
memcpy(&lastModificationTime, &lastAccessTime, sizeof(FILETIME));
} else {
convert_time(at, &lastAccessTime);
convert_time(mt, &lastModificationTime);
}
caml_enter_blocking_section();
res = SetFileTime(hFile, NULL, &lastAccessTime, &lastModificationTime);
caml_leave_blocking_section();
if (res == 0) {
win32_maperr(GetLastError());
CloseHandle(hFile);
uerror("utimes", path);
}
CloseHandle(hFile);
CAMLreturn(Val_unit);
}

0 comments on commit af20b3e

Please sign in to comment.