From c3a615aa2da09bc3a0575e973959f800460a63de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 17 Jun 2011 12:54:20 +0200 Subject: Use epoch seconds instead of datetime() First stage in utc-time for prim_file. --- erts/emulator/drivers/common/efile_drv.c | 53 +++++++------- erts/emulator/drivers/common/erl_efile.h | 23 +++--- erts/emulator/drivers/unix/unix_efile.c | 60 +++------------- erts/preloaded/src/prim_file.erl | 116 +++++++++++++++++-------------- 4 files changed, 113 insertions(+), 139 deletions(-) diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 5c52b99348..184d27fb62 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -2120,24 +2120,24 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) if (d->result_ok) { resbuf[0] = FILE_RESP_INFO; - put_int32(d->info.size_high, &resbuf[1 + (0 * 4)]); - put_int32(d->info.size_low, &resbuf[1 + (1 * 4)]); - put_int32(d->info.type, &resbuf[1 + (2 * 4)]); - - PUT_TIME(d->info.accessTime, resbuf + 1 + 3*4); - PUT_TIME(d->info.modifyTime, resbuf + 1 + 9*4); - PUT_TIME(d->info.cTime, resbuf + 1 + 15*4); - - put_int32(d->info.mode, &resbuf[1 + (21 * 4)]); - put_int32(d->info.links, &resbuf[1 + (22 * 4)]); - put_int32(d->info.major_device, &resbuf[1 + (23 * 4)]); - put_int32(d->info.minor_device, &resbuf[1 + (24 * 4)]); - put_int32(d->info.inode, &resbuf[1 + (25 * 4)]); - put_int32(d->info.uid, &resbuf[1 + (26 * 4)]); - put_int32(d->info.gid, &resbuf[1 + (27 * 4)]); - put_int32(d->info.access, &resbuf[1 + (28 * 4)]); - -#define RESULT_SIZE (1 + (29 * 4)) + put_int32(d->info.size_high, &resbuf[1 + ( 0 * 4)]); + put_int32(d->info.size_low, &resbuf[1 + ( 1 * 4)]); + put_int32(d->info.type, &resbuf[1 + ( 2 * 4)]); + + put_int64(d->info.accessTime, &resbuf[1 + ( 3 * 4)]); + put_int64(d->info.modifyTime, &resbuf[1 + ( 5 * 4)]); + put_int64(d->info.cTime , &resbuf[1 + ( 7 * 4)]); + + put_int32(d->info.mode, &resbuf[1 + ( 9 * 4)]); + put_int32(d->info.links, &resbuf[1 + (10 * 4)]); + put_int32(d->info.major_device, &resbuf[1 + (11 * 4)]); + put_int32(d->info.minor_device, &resbuf[1 + (12 * 4)]); + put_int32(d->info.inode, &resbuf[1 + (13 * 4)]); + put_int32(d->info.uid, &resbuf[1 + (14 * 4)]); + put_int32(d->info.gid, &resbuf[1 + (15 * 4)]); + put_int32(d->info.access, &resbuf[1 + (16 * 4)]); + +#define RESULT_SIZE (1 + (17 * 4)) TRACE_C('R'); driver_output2(desc->port, resbuf, RESULT_SIZE, NULL, 0); #undef RESULT_SIZE @@ -2485,15 +2485,16 @@ file_output(ErlDrvData e, char* buf, int count) case FILE_WRITE_INFO: { d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 - + FILENAME_BYTELEN(buf+21*4) + FILENAME_CHARSIZE); + + FILENAME_BYTELEN(buf + 9*4) + FILENAME_CHARSIZE); - d->info.mode = get_int32(buf + 0 * 4); - d->info.uid = get_int32(buf + 1 * 4); - d->info.gid = get_int32(buf + 2 * 4); - GET_TIME(d->info.accessTime, buf + 3 * 4); - GET_TIME(d->info.modifyTime, buf + 9 * 4); - GET_TIME(d->info.cTime, buf + 15 * 4); - FILENAME_COPY(d->b, buf+21*4); + d->info.mode = get_int32(buf + 0 * 4); + d->info.uid = get_int32(buf + 1 * 4); + d->info.gid = get_int32(buf + 2 * 4); + d->info.accessTime = get_int64(buf + 3 * 4); + d->info.modifyTime = get_int64(buf + 5 * 4); + d->info.cTime = get_int64(buf + 7 * 4); + + FILENAME_COPY(d->b, buf + 9*4); d->command = command; d->invoke = invoke_write_info; d->free = free_data; diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h index 349ab0e17b..5c0b89e850 100644 --- a/erts/emulator/drivers/common/erl_efile.h +++ b/erts/emulator/drivers/common/erl_efile.h @@ -85,14 +85,15 @@ typedef struct _Efile_error { /* * This structure contains date and time. */ -typedef struct _Efile_time { - unsigned year; /* (4 digits). */ - unsigned month; /* (1..12). */ - unsigned day; /* (1..31). */ - unsigned hour; /* (0..23). */ - unsigned minute; /* (0..59). */ - unsigned second; /* (0..59). */ -} Efile_time; + +//typedef struct _Efile_time { +// unsigned year; /* (4 digits). */ +// unsigned month; /* (1..12). */ +// unsigned day; /* (1..31). */ +// unsigned hour; /* (0..23). */ +// unsigned minute; /* (0..59). */ +// unsigned second; /* (0..59). */ +//} Efile_time; /* @@ -111,9 +112,9 @@ typedef struct _Efile_info { Uint32 inode; /* Inode number. */ Uint32 uid; /* User id of owner. */ Uint32 gid; /* Group id of owner. */ - Efile_time accessTime; /* Last time the file was accessed. */ - Efile_time modifyTime; /* Last time the file was modified. */ - Efile_time cTime; /* Creation time (Windows) or last + time_t accessTime; /* Last time the file was accessed. */ + time_t modifyTime; /* Last time the file was modified. */ + time_t cTime; /* Creation time (Windows) or last * inode change (Unix). */ } Efile_info; diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 72911641d3..0237c81e1e 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -816,7 +816,6 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, char* name, int info_for_link) { struct stat statbuf; /* Information about the file */ - struct tm *timep; /* Broken-apart filetime. */ int result; #ifdef VXWORKS @@ -883,40 +882,17 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, else pInfo->type = FT_OTHER; -#if defined(HAVE_LOCALTIME_R) || defined(VXWORKS) - { - /* Use the reentrant version of localtime() */ - static struct tm local_tm; -#define localtime(a) (localtime_r((a), &local_tm), &local_tm) -#endif - - -#define GET_TIME(dst, src) \ - timep = localtime(&statbuf.src); \ - (dst).year = timep->tm_year+1900; \ - (dst).month = timep->tm_mon+1; \ - (dst).day = timep->tm_mday; \ - (dst).hour = timep->tm_hour; \ - (dst).minute = timep->tm_min; \ - (dst).second = timep->tm_sec - - GET_TIME(pInfo->accessTime, st_atime); - GET_TIME(pInfo->modifyTime, st_mtime); - GET_TIME(pInfo->cTime, st_ctime); - -#undef GET_TIME + pInfo->accessTime = statbuf.st_atime; + pInfo->modifyTime = statbuf.st_mtime; + pInfo->cTime = statbuf.st_ctime; -#if defined(HAVE_LOCALTIME_R) || defined(VXWORKS) - } -#endif - - pInfo->mode = statbuf.st_mode; - pInfo->links = statbuf.st_nlink; + pInfo->mode = statbuf.st_mode; + pInfo->links = statbuf.st_nlink; pInfo->major_device = statbuf.st_dev; pInfo->minor_device = statbuf.st_rdev; - pInfo->inode = statbuf.st_ino; - pInfo->uid = statbuf.st_uid; - pInfo->gid = statbuf.st_gid; + pInfo->inode = statbuf.st_ino; + pInfo->uid = statbuf.st_uid; + pInfo->gid = statbuf.st_gid; return 1; } @@ -976,27 +952,13 @@ efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) #endif /* !VXWORKS */ - if (pInfo->accessTime.year != -1 && pInfo->modifyTime.year != -1) { + if (pInfo->accessTime != 0 && pInfo->modifyTime != 0) { struct utimbuf tval; struct tm timebuf; -#define MKTIME(tb, ts) \ - timebuf.tm_year = ts.year-1900; \ - timebuf.tm_mon = ts.month-1; \ - timebuf.tm_mday = ts.day; \ - timebuf.tm_hour = ts.hour; \ - timebuf.tm_min = ts.minute; \ - timebuf.tm_sec = ts.second; \ - timebuf.tm_isdst = -1; \ - if ((tb = mktime(&timebuf)) == (time_t) -1) { \ - errno = EINVAL; \ - return check_error(-1, errInfo); \ - } + tval.actime = pInfo->accessTime; + tval.modtime = pInfo->modifyTime; - MKTIME(tval.actime, pInfo->accessTime); - MKTIME(tval.modtime, pInfo->modifyTime); -#undef MKTIME - #ifdef VXWORKS /* VxWorks' utime doesn't work when the file is a nfs mounted * one, don't report error if utime fails. diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 7316e0be99..2fe7797e54 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -736,6 +736,7 @@ read_file_info(Port, File) when is_port(Port) -> read_file_info_int(Port, File) -> drv_command(Port, [?FILE_FSTAT, pathname(File)]). + %% altname/{1,2} altname(File) -> @@ -760,22 +761,24 @@ write_file_info_int(Port, #file_info{mode=Mode, uid=Uid, gid=Gid, - atime=Atime0, - mtime=Mtime0, - ctime=Ctime}) -> - {Atime, Mtime} = - case {Atime0, Mtime0} of - {undefined, Mtime0} -> {erlang:localtime(), Mtime0}; - {Atime0, undefined} -> {Atime0, Atime0}; - Complete -> Complete - end, + atime=Atime, + mtime=Mtime, + ctime=Ctime}) when + (is_integer(Atime) orelse Atime =:= undefined) andalso + (is_integer(Mtime) orelse Mtime =:= undefined) andalso + (is_integer(Ctime) orelse Ctime =:= undefined) -> + + %% todo: set atime to localtime() (seconds since epoch) if undefined + %% set mtime to atime if undefined + %% if both undefined ? + drv_command(Port, [?FILE_WRITE_INFO, - int_to_bytes(Mode), - int_to_bytes(Uid), - int_to_bytes(Gid), - date_to_bytes(Atime), - date_to_bytes(Mtime), - date_to_bytes(Ctime), + int_to_int32bytes(Mode), + int_to_int32bytes(Uid), + int_to_int32bytes(Gid), + int_to_int64bytes(Atime), + int_to_int64bytes(Mtime), + int_to_int64bytes(Ctime), pathname(File)]). @@ -1075,7 +1078,8 @@ translate_response(?FILE_RESP_DATA, List) -> {_N, _Data} = ND = get_uint64(List), {ok, ND}; translate_response(?FILE_RESP_INFO, List) when is_list(List) -> - {ok, transform_info_ints(get_uint32s(List))}; + {ok, transform_info(List)}; + %{ok, transform_info_ints(get_uint32s(List))}; translate_response(?FILE_RESP_NUMERR, L0) -> {N, L1} = get_uint64(L0), {error, {N, list_to_atom(L1)}}; @@ -1129,27 +1133,38 @@ translate_response(?FILE_RESP_ALL_DATA, Data) -> translate_response(X, Data) -> {error, {bad_response_from_port, [X | Data]}}. -transform_info_ints(Ints) -> - [HighSize, LowSize, Type|Tail0] = Ints, - Size = HighSize * 16#100000000 + LowSize, - [Ay, Am, Ad, Ah, Ami, As|Tail1] = Tail0, - [My, Mm, Md, Mh, Mmi, Ms|Tail2] = Tail1, - [Cy, Cm, Cd, Ch, Cmi, Cs|Tail3] = Tail2, - [Mode, Links, Major, Minor, Inode, Uid, Gid, Access] = Tail3, + +transform_info([ + Hsize1, Hsize2, Hsize3, Hsize4, + Lsize1, Lsize2, Lsize3, Lsize4, + Type1, Type2, Type3, Type4, + Atime1, Atime2, Atime3, Atime4, Atime5, Atime6, Atime7, Atime8, + Mtime1, Mtime2, Mtime3, Mtime4, Mtime5, Mtime6, Mtime7, Mtime8, + Ctime1, Ctime2, Ctime3, Ctime4, Ctime5, Ctime6, Ctime7, Ctime8, + Mode1, Mode2, Mode3, Mode4, + Links1, Links2, Links3, Links4, + Major1, Major2, Major3, Major4, + Minor1, Minor2, Minor3, Minor4, + Inode1, Inode2, Inode3, Inode4, + Uid1, Uid2, Uid3, Uid4, + Gid1, Gid2, Gid3, Gid4, + Access1,Access2,Access3,Access4]) -> #file_info { - size = Size, - type = file_type(Type), - access = file_access(Access), - atime = {{Ay, Am, Ad}, {Ah, Ami, As}}, - mtime = {{My, Mm, Md}, {Mh, Mmi, Ms}}, - ctime = {{Cy, Cm, Cd}, {Ch, Cmi, Cs}}, - mode = Mode, - links = Links, - major_device = Major, - minor_device = Minor, - inode = Inode, - uid = Uid, - gid = Gid}. + size = uint32(Hsize1,Hsize2,Hsize3,Hsize4)*16#100000000 + uint32(Lsize1,Lsize2,Lsize3,Lsize4), + type = file_type(uint32(Type1,Type2,Type3,Type4)), + access = file_access(uint32(Access1,Access2,Access3,Access4)), + atime = sint64(Atime1, Atime2, Atime3, Atime4, Atime5, Atime6, Atime7, Atime8), + mtime = sint64(Mtime1, Mtime2, Mtime3, Mtime4, Mtime5, Mtime6, Mtime7, Mtime8), + ctime = sint64(Ctime1, Ctime2, Ctime3, Ctime4, Ctime5, Ctime6, Ctime7, Ctime8), + mode = uint32(Mode1,Mode2,Mode3,Mode4), + links = uint32(Links1,Links2,Links3,Links4), + major_device = uint32(Major1,Major2,Major3,Major4), + minor_device = uint32(Minor1,Minor2,Minor3,Minor4), + inode = uint32(Inode1,Inode2,Inode3,Inode4), + uid = uint32(Uid1,Uid2,Uid3,Uid4), + gid = uint32(Gid1,Gid2,Gid3,Gid4) + }. + file_type(1) -> device; file_type(2) -> directory; @@ -1162,24 +1177,24 @@ file_access(1) -> write; file_access(2) -> read; file_access(3) -> read_write. -int_to_bytes(Int) when is_integer(Int) -> +int_to_int32bytes(Int) when is_integer(Int) -> <>; -int_to_bytes(undefined) -> +int_to_int32bytes(undefined) -> <<-1:32>>. -date_to_bytes(undefined) -> - <<-1:32, -1:32, -1:32, -1:32, -1:32, -1:32>>; -date_to_bytes({{Y, Mon, D}, {H, Min, S}}) -> - <>. +int_to_int64bytes(Int) when is_integer(Int) -> + <>; +int_to_int64bytes(undefined) -> + <<-1:64>>. -%% uint64([[X1, X2, X3, X4] = Y1 | [X5, X6, X7, X8] = Y2]) -> -%% (uint32(Y1) bsl 32) bor uint32(Y2). -%% uint64(X1, X2, X3, X4, X5, X6, X7, X8) -> -%% (uint32(X1, X2, X3, X4) bsl 32) bor uint32(X5, X6, X7, X8). +sint64(I1,I2,I3,I4,I5,I6,I7,I8) when I1 > 127 -> + ((I1 bsl 56) bor (I2 bsl 48) bor (I3 bsl 40) bor (I4 bsl 32) bor + (I5 bsl 24) bor (I6 bsl 16) bor (I7 bsl 8) bor I8) - (1 bsl 64); +sint64(I1,I2,I3,I4,I5,I6,I7,I8) -> + ((I1 bsl 56) bor (I2 bsl 48) bor (I3 bsl 40) bor (I4 bsl 32) bor + (I5 bsl 24) bor (I6 bsl 16) bor (I7 bsl 8) bor I8). -%% uint32([X1,X2,X3,X4]) -> -%% (X1 bsl 24) bor (X2 bsl 16) bor (X3 bsl 8) bor X4. uint32(X1,X2,X3,X4) -> (X1 bsl 24) bor (X2 bsl 16) bor (X3 bsl 8) bor X4. @@ -1192,11 +1207,6 @@ get_uint64(L0) -> get_uint32([X1,X2,X3,X4|List]) -> {(((((X1 bsl 8) bor X2) bsl 8) bor X3) bsl 8) bor X4, List}. -get_uint32s([X1,X2,X3,X4|Tail]) -> - [uint32(X1,X2,X3,X4) | get_uint32s(Tail)]; -get_uint32s([]) -> []. - - %% Binary mode transform_ldata(<<0:32, 0:32>>) -> -- cgit v1.2.3 From e7b0c8c6e72d8b0b60eb00e7e66fea2769963dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 27 Jun 2011 11:17:04 +0200 Subject: Teach file.erl datetime conversions --- lib/kernel/src/file.erl | 73 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index 0b0f91d86a..bdafcf2cfb 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -28,9 +28,10 @@ %% File system and metadata. -export([get_cwd/0, get_cwd/1, set_cwd/1, delete/1, rename/2, make_dir/1, del_dir/1, list_dir/1, - read_file_info/1, write_file_info/2, + read_file_info/1, read_file_info/2, + write_file_info/2, write_file_info/3, altname/1, - read_link_info/1, read_link/1, + read_link_info/1, read_link_info/2, read_link/1, make_link/2, make_symlink/2, read_file/1, write_file/2, write_file/3]). %% Specialized @@ -212,7 +213,10 @@ del_dir(Name) -> Reason :: posix() | badarg. read_file_info(Name) -> - check_and_call(read_file_info, [file_name(Name)]). + file_info_time(local, check_and_call(read_file_info, [file_name(Name)])). + +read_file_info(Name, Opts) when is_list(Opts) -> + file_info_time(proplists:get_value(time, Opts, local), check_and_call(read_file_info, [file_name(Name)])). -spec altname(Name :: name()) -> any(). @@ -225,7 +229,10 @@ altname(Name) -> Reason :: posix() | badarg. read_link_info(Name) -> - check_and_call(read_link_info, [file_name(Name)]). + read_link_info(Name, [{time, local}]). + +read_link_info(Name, Opts) when is_list(Opts) -> + file_info_time(proplists:get_value(time, Opts, local), check_and_call(read_link_info, [file_name(Name)])). -spec read_link(Name) -> {ok, Filename} | {error, Reason} when Name :: name(), @@ -241,7 +248,10 @@ read_link(Name) -> Reason :: posix() | badarg. write_file_info(Name, Info = #file_info{}) -> - check_and_call(write_file_info, [file_name(Name), Info]). + check_and_call(write_file_info, [file_name(Name), file_info_epochs(local, Info)]). + +write_file_info(Name, Info = #file_info{}, Opts) when is_list(Opts) -> + check_and_call(write_file_info, [file_name(Name), file_info_epochs(proplists:get_value(time, Opts, local), Info)]). -spec list_dir(Dir) -> {ok, Filenames} | {error, Reason} when Dir :: name(), @@ -1321,6 +1331,59 @@ fname_join(Dir, Name) -> %%%----------------------------------------------------------------- %%% Utility functions. +%% convert file times. +%% all times from prime_file (and file_server) are in unix epochs + +%% from_epochs +file_info_time(epoch, {ok, FI}) -> FI; +file_info_time(local, {ok, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI}) -> + {ok, FI#file_info{ + atime = time_epochs_to_local(Atime), + ctime = time_epochs_to_local(Ctime), + mtime = time_epochs_to_local(Mtime) + } + }; +file_info_time(utc, {ok, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI}) -> + {ok, FI#file_info{ + atime = time_epochs_to_utc(Atime), + ctime = time_epochs_to_utc(Ctime), + mtime = time_epochs_to_utc(Mtime) + } + }; +file_info_time(_, Error) -> Error. + +%% from_epochs +file_info_epochs(epoch, FI) -> FI; +file_info_epochs(local, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI) -> + FI#file_info{ + atime = time_local_to_epochs(Atime), + ctime = time_local_to_epochs(Ctime), + mtime = time_local_to_epochs(Mtime) + }; +file_info_epochs(utc, {ok, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI}) -> + FI#file_info{ + atime = time_utc_to_epochs(Atime), + ctime = time_utc_to_epochs(Ctime), + mtime = time_utc_to_epochs(Mtime) + }. + + +-define(DAYS_FROM_0_TO_1970, 719528). +-define(SECONDS_PER_DAY, 86400). + +time_epochs_to_utc(Seconds) when is_integer(Seconds) -> + calendar:gregorian_seconds_to_datetime(Seconds + ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970). + +time_epochs_to_local(Seconds) when is_integer(Seconds) -> + erlang:universaltime_to_localtime(calendar:gregorian_seconds_to_datetime(Seconds + ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970)). + +time_utc_to_epochs({_, _} = Datetime) -> + calendar:datetime_to_gregorian_seconds(Datetime) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970. + +time_local_to_epochs({_, _} = Datetime) -> + calendar:datetime_to_gregorian_seconds(erlang:localtime_to_universaltime(Datetime)) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970. + + %% file_name(FileName) %% Generates a flat file name from a deep list of atoms and %% characters (integers). -- cgit v1.2.3 From c489db32a796be2d7de7a683544c333a77d917b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 29 Jun 2011 15:20:38 +0200 Subject: Fix undefined datetimes --- lib/kernel/src/file.erl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index bdafcf2cfb..8f027f5a40 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -1378,10 +1378,15 @@ time_epochs_to_local(Seconds) when is_integer(Seconds) -> erlang:universaltime_to_localtime(calendar:gregorian_seconds_to_datetime(Seconds + ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970)). time_utc_to_epochs({_, _} = Datetime) -> - calendar:datetime_to_gregorian_seconds(Datetime) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970. + calendar:datetime_to_gregorian_seconds(Datetime) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970; +time_utc_to_epochs(undefined) -> + time_utc_to_epochs(erlang:universaltime()). + time_local_to_epochs({_, _} = Datetime) -> - calendar:datetime_to_gregorian_seconds(erlang:localtime_to_universaltime(Datetime)) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970. + calendar:datetime_to_gregorian_seconds(erlang:localtime_to_universaltime(Datetime)) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970; +time_local_to_epochs(undefined) -> + time_utc_to_epochs(erlang:universaltime()). %% file_name(FileName) -- cgit v1.2.3 From 82c79cc3b00175ac3ff6f892736c95fe3b00ea06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 9 Aug 2011 17:38:47 +0200 Subject: Teach erlang about the times before 1970 --- erts/emulator/beam/erl_time_sup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index 4d1e1c8a59..bc09ba8001 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -583,7 +583,7 @@ static const int mdays[14] = {0, 31, 28, 31, 30, 31, 30, (((y) % 100) != 0)) || \ (((y) % 400) == 0)) -#define BASEYEAR 1970 +#define BASEYEAR INT_MIN /* * gregday -- cgit v1.2.3 From 1eef7653baae2046c26cfe8fb5fc91d6f9fa709b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 9 Aug 2011 18:27:20 +0200 Subject: Workaround for the -1 problem of mktime --- erts/emulator/beam/erl_time_sup.c | 46 +++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index bc09ba8001..829ec32288 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -585,6 +585,41 @@ static const int mdays[14] = {0, 31, 28, 31, 30, 31, 30, #define BASEYEAR INT_MIN +/* A more "clever" mktime + * return 1, if successful + * return -1, if not successful + */ + +static int erl_mktime(time_t *c, struct tm *tm) { + time_t clock; + + clock = mktime(tm); + + if (clock != -1) { + *c = clock; + return 1; + } + + /* in rare occasions mktime returns -1 + * when a correct value has been entered + * + * decrease seconds with one second + * if the result is -2, epochs should be -1 + */ + + tm->tm_sec = tm->tm_sec - 1; + clock = mktime(tm); + tm->tm_sec = tm->tm_sec + 1; + + *c = -1; + + if (clock == -2) { + return 1; + } + + return -1; +} + /* * gregday * @@ -644,15 +679,18 @@ local_to_univ(Sint *year, Sint *month, Sint *day, t.tm_min = *minute; t.tm_sec = *second; t.tm_isdst = isdst; - the_clock = mktime(&t); - if (the_clock == -1) { + + /* the nature of mktime makes this a bit interesting, + * up to four mktime calls could happen here + */ + + if (erl_mktime(&the_clock, &t) < 0) { if (isdst) { /* If this is a timezone without DST and the OS (correctly) refuses to give us a DST time, we simulate the Linux/Solaris behaviour of giving the same data as if is_dst was not set. */ t.tm_isdst = 0; - the_clock = mktime(&t); - if (the_clock == -1) { + if (erl_mktime(&the_clock, &t)) { /* Failed anyway, something else is bad - will be a badarg */ return 0; } -- cgit v1.2.3 From f21b72789018cf5ac581d851685162194b049d11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 30 Nov 2011 19:08:38 +0100 Subject: stdlib: Fix return file_info on epoch --- lib/kernel/src/file.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index 8f027f5a40..dafd2c6909 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -1335,7 +1335,7 @@ fname_join(Dir, Name) -> %% all times from prime_file (and file_server) are in unix epochs %% from_epochs -file_info_time(epoch, {ok, FI}) -> FI; +file_info_time(epoch, {ok, FI} = R) -> R; file_info_time(local, {ok, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI}) -> {ok, FI#file_info{ atime = time_epochs_to_local(Atime), -- cgit v1.2.3 From 3c5f8d903787b24a3d0d0f4404a652e25f089765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 16 Nov 2011 19:43:58 +0100 Subject: Teach win32 efile driver epochs Conflicts: erts/emulator/drivers/win32/win_efile.c --- erts/emulator/drivers/win32/win_efile.c | 104 +++++++++++++------------------- 1 file changed, 41 insertions(+), 63 deletions(-) diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index 0bc701c4cb..19b9384940 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -45,6 +45,23 @@ #define INVALID_FILE_ATTRIBUTES ((DWORD) 0xFFFFFFFF) #endif +// #define TICKS_PER_SECOND 10000000 +// #define EPOCH_DIFFERENCE 11644473600LL +// time_t convertWindowsTimeToUnixTime(long long int input){ +// long long int temp; +// temp = input / TICKS_PER_SECOND; //convert from 100ns intervals to seconds; +// temp = temp - EPOCH_DIFFERENCE; //subtract number of seconds between epochs +// return (time_t) temp; +// } + +#define TICKS_PER_SECOND (10000000) +#define EPOCH_DIFFERENCE (11644473600LL) +#define FILETIME_TO_EPOCH(time) \ + (((time) / TICKS_PER_SECOND) - EPOCH_DIFFERENCE) +#define EPOCH_TO_FILETIME(epoch) \ + (EPOCH_DIFFERENCE + ((epoch) * TICKS_PER_SECOND)) + + static int check_error(int result, Efile_error* errInfo); static int set_error(Efile_error* errInfo); static int is_root_unc_name(const WCHAR *path); @@ -905,34 +922,21 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, } } -#define GET_TIME(dst, src) \ -if (!FileTimeToLocalFileTime(&findbuf.src, &LocalFTime) || \ - !FileTimeToSystemTime(&LocalFTime, &SystemTime)) { \ - return set_error(errInfo); \ -} \ -(dst).year = SystemTime.wYear; \ -(dst).month = SystemTime.wMonth; \ -(dst).day = SystemTime.wDay; \ -(dst).hour = SystemTime.wHour; \ -(dst).minute = SystemTime.wMinute; \ -(dst).second = SystemTime.wSecond; - - GET_TIME(pInfo->modifyTime, ftLastWriteTime); + pInfo->modifyTime = FILETIME_TO_EPOCH(findbuf.ftLastWriteTime); if (findbuf.ftLastAccessTime.dwLowDateTime == 0 && findbuf.ftLastAccessTime.dwHighDateTime == 0) { pInfo->accessTime = pInfo->modifyTime; } else { - GET_TIME(pInfo->accessTime, ftLastAccessTime); + pInfo->accessTime = FILETIME_TO_EPOCH(findbuf.ftLastAccessTime); } if (findbuf.ftCreationTime.dwLowDateTime == 0 && findbuf.ftCreationTime.dwHighDateTime == 0) { pInfo->cTime = pInfo->modifyTime; } else { - GET_TIME(pInfo->cTime, ftCreationTime); + pInfo->cTime = FILETIME_TO_EPOCH(findbuf.ftCreationTime); } -#undef GET_TIME FindClose(findhandle); } @@ -968,17 +972,12 @@ efile_write_info(Efile_error* errInfo, char* name) { SYSTEMTIME timebuf; - FILETIME LocalFileTime; FILETIME ModifyFileTime; FILETIME AccessFileTime; FILETIME CreationFileTime; HANDLE fd; - FILETIME* mtime = NULL; - FILETIME* atime = NULL; - FILETIME* ctime = NULL; DWORD attr; DWORD tempAttr; - BOOL modifyTime = FALSE; WCHAR *wname = (WCHAR *) name; /* @@ -1003,57 +1002,36 @@ efile_write_info(Efile_error* errInfo, * Construct all file times. */ -#define MKTIME(tb, ts, ptr) \ - timebuf.wYear = ts.year; \ - timebuf.wMonth = ts.month; \ - timebuf.wDay = ts.day; \ - timebuf.wHour = ts.hour; \ - timebuf.wMinute = ts.minute; \ - timebuf.wSecond = ts.second; \ - timebuf.wMilliseconds = 0; \ - if (ts.year != -1) { \ - modifyTime = TRUE; \ - ptr = &tb; \ - if (!SystemTimeToFileTime(&timebuf, &LocalFileTime ) || \ - !LocalFileTimeToFileTime(&LocalFileTime, &tb)) { \ - errno = EINVAL; \ - return check_error(-1, errInfo); \ - } \ - } - - MKTIME(ModifyFileTime, pInfo->modifyTime, mtime); - MKTIME(AccessFileTime, pInfo->accessTime, atime); - MKTIME(CreationFileTime, pInfo->cTime, ctime); -#undef MKTIME + ModifyFileTime = EPOCH_TO_FILETIME(pInfo->modifyTime); + AccessFileTime = EPOCH_TO_FILETIME(pInfo->accessTime); + CreationFileTime = EPOCH_TO_FILETIME(pInfo->cTime); /* * If necessary, set the file times. */ - if (modifyTime) { - /* - * If the has read only access, we must temporarily turn on - * write access (this is necessary for native filesystems, - * but not for NFS filesystems). - */ + /* + * If the has read only access, we must temporarily turn on + * write access (this is necessary for native filesystems, + * but not for NFS filesystems). + */ - if (tempAttr & FILE_ATTRIBUTE_READONLY) { - tempAttr &= ~FILE_ATTRIBUTE_READONLY; - if (!SetFileAttributesW(wname, tempAttr)) { - return set_error(errInfo); - } + if (tempAttr & FILE_ATTRIBUTE_READONLY) { + tempAttr &= ~FILE_ATTRIBUTE_READONLY; + if (!SetFileAttributesW(wname, tempAttr)) { + return set_error(errInfo); } + } - fd = CreateFileW(wname, GENERIC_READ|GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (fd != INVALID_HANDLE_VALUE) { - BOOL result = SetFileTime(fd, ctime, atime, mtime); - if (!result) { - return set_error(errInfo); - } - CloseHandle(fd); + fd = CreateFileW(wname, GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (fd != INVALID_HANDLE_VALUE) { + BOOL result = SetFileTime(fd, &CreationFileTime, &AccessFileTime, &ModifyFileTime); + if (!result) { + return set_error(errInfo); } + CloseHandle(fd); } /* -- cgit v1.2.3 From 98da1412fbf9fd6aa6ebcff4a014bf9bbc45d962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 16 Nov 2011 18:46:23 +0100 Subject: Fix EPOCH <-> FILETIME conversion --- erts/emulator/drivers/win32/win_efile.c | 51 ++++++++++++++++----------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index 19b9384940..134c4b675f 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -45,21 +45,24 @@ #define INVALID_FILE_ATTRIBUTES ((DWORD) 0xFFFFFFFF) #endif -// #define TICKS_PER_SECOND 10000000 -// #define EPOCH_DIFFERENCE 11644473600LL -// time_t convertWindowsTimeToUnixTime(long long int input){ -// long long int temp; -// temp = input / TICKS_PER_SECOND; //convert from 100ns intervals to seconds; -// temp = temp - EPOCH_DIFFERENCE; //subtract number of seconds between epochs -// return (time_t) temp; -// } - -#define TICKS_PER_SECOND (10000000) +#define TICKS_PER_SECOND (10000000ULL) #define EPOCH_DIFFERENCE (11644473600LL) -#define FILETIME_TO_EPOCH(time) \ - (((time) / TICKS_PER_SECOND) - EPOCH_DIFFERENCE) -#define EPOCH_TO_FILETIME(epoch) \ - (EPOCH_DIFFERENCE + ((epoch) * TICKS_PER_SECOND)) + +#define FILETIME_TO_EPOCH(epoch, ft) \ + do { \ + ULARGE_INTEGER ull; \ + ull.LowPart = (ft).dwLowDateTime; \ + ull.HighPart = (ft).dwHighDateTime; \ + (epoch) = ((ull.QuadPart / TICKS_PER_SECOND) - EPOCH_DIFFERENCE); \ + } while(0) + +#define EPOCH_TO_FILETIME(ft, epoch) \ + do { \ + ULARGE_INTEGER ull; \ + ull.QuadPart = (((epoch)*TICKS_PER_SECOND) + EPOCH_DIFFERENCE); \ + (ft).dwLowDateTime = ull.LowPart; \ + (ft).dwHighDateTime = ull.HighPart; \ + } while(0) static int check_error(int result, Efile_error* errInfo); @@ -881,13 +884,7 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, findbuf.cFileName[0] = L'\0'; pInfo->links = 1; - pInfo->modifyTime.year = 1980; - pInfo->modifyTime.month = 1; - pInfo->modifyTime.day = 1; - pInfo->modifyTime.hour = 0; - pInfo->modifyTime.minute = 0; - pInfo->modifyTime.second = 0; - + pInfo->modifyTime = 0; pInfo->accessTime = pInfo->modifyTime; } else { SYSTEMTIME SystemTime; @@ -922,20 +919,20 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, } } - pInfo->modifyTime = FILETIME_TO_EPOCH(findbuf.ftLastWriteTime); + FILETIME_TO_EPOCH(pInfo->modifyTime, findbuf.ftLastWriteTime); if (findbuf.ftLastAccessTime.dwLowDateTime == 0 && findbuf.ftLastAccessTime.dwHighDateTime == 0) { pInfo->accessTime = pInfo->modifyTime; } else { - pInfo->accessTime = FILETIME_TO_EPOCH(findbuf.ftLastAccessTime); + FILETIME_TO_EPOCH(pInfo->accessTime, findbuf.ftLastAccessTime); } if (findbuf.ftCreationTime.dwLowDateTime == 0 && findbuf.ftCreationTime.dwHighDateTime == 0) { pInfo->cTime = pInfo->modifyTime; } else { - pInfo->cTime = FILETIME_TO_EPOCH(findbuf.ftCreationTime); + FILETIME_TO_EPOCH(pInfo->cTime ,findbuf.ftCreationTime); } FindClose(findhandle); } @@ -1002,9 +999,9 @@ efile_write_info(Efile_error* errInfo, * Construct all file times. */ - ModifyFileTime = EPOCH_TO_FILETIME(pInfo->modifyTime); - AccessFileTime = EPOCH_TO_FILETIME(pInfo->accessTime); - CreationFileTime = EPOCH_TO_FILETIME(pInfo->cTime); + EPOCH_TO_FILETIME(ModifyFileTime, pInfo->modifyTime); + EPOCH_TO_FILETIME(AccessFileTime, pInfo->accessTime); + EPOCH_TO_FILETIME(CreationFileTime, pInfo->cTime); /* * If necessary, set the file times. -- cgit v1.2.3 From f356bb25df7fe4d6a20d7427b4b4249e9219157c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 18 Nov 2011 18:02:12 +0100 Subject: Move datetime into prim_file --- erts/preloaded/src/prim_file.erl | 236 ++++++++++++++++++++++++++++++++++----- lib/kernel/src/file.erl | 135 ++++++++++++---------- lib/kernel/src/file_server.erl | 9 ++ 3 files changed, 292 insertions(+), 88 deletions(-) diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 2fe7797e54..69ef0b9d54 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -45,9 +45,9 @@ rename/2, rename/3, make_dir/1, make_dir/2, del_dir/1, del_dir/2, - read_file_info/1, read_file_info/2, + read_file_info/1, read_file_info/2, read_file_info/3, altname/1, altname/2, - write_file_info/2, write_file_info/3, + write_file_info/2, write_file_info/3, write_file_info/4, make_link/2, make_link/3, make_symlink/2, make_symlink/3, read_link/1, read_link/2, @@ -728,13 +728,23 @@ del_dir_int(Port, Dir) -> %% read_file_info/{1,2} read_file_info(File) -> - read_file_info_int({?DRV, [binary]}, File). + read_file_info_int({?DRV, [binary]}, File, local). read_file_info(Port, File) when is_port(Port) -> - read_file_info_int(Port, File). - -read_file_info_int(Port, File) -> - drv_command(Port, [?FILE_FSTAT, pathname(File)]). + read_file_info_int(Port, File, local). + +read_file_info(Port, File, Opts) when is_port(Port) -> + read_file_info_int(Port, File, plgv(time, Opts)). + +read_file_info_int(Port, File, TimeType) -> + case drv_command(Port, [?FILE_FSTAT, pathname(File)]) of + {ok, FI} -> {ok, FI#file_info{ + ctime = from_seconds(FI#file_info.ctime, TimeType), + mtime = from_seconds(FI#file_info.mtime, TimeType), + atime = from_seconds(FI#file_info.atime, TimeType) + }}; + Error -> Error + end. %% altname/{1,2} @@ -748,37 +758,44 @@ altname(Port, File) when is_port(Port) -> altname_int(Port, File) -> drv_command(Port, [?FILE_ALTNAME, pathname(File)]). -%% write_file_info/{2,3} +%% write_file_info/{2,3,4} write_file_info(File, Info) -> - write_file_info_int({?DRV, [binary]}, File, Info). + write_file_info_int({?DRV, [binary]}, File, Info, local). write_file_info(Port, File, Info) when is_port(Port) -> - write_file_info_int(Port, File, Info). + write_file_info_int(Port, File, Info, local); + +write_file_info(File, Info, Opts) -> + write_file_info_int({?DRV, [binary]}, File, Info, plgv(time, Opts)). + +write_file_info(Port, File, Info, Opts) when is_port(Port) -> + write_file_info_int(Port, File, Info, plgv(time, Opts)). write_file_info_int(Port, File, #file_info{mode=Mode, uid=Uid, gid=Gid, - atime=Atime, - mtime=Mtime, - ctime=Ctime}) when - (is_integer(Atime) orelse Atime =:= undefined) andalso - (is_integer(Mtime) orelse Mtime =:= undefined) andalso - (is_integer(Ctime) orelse Ctime =:= undefined) -> - - %% todo: set atime to localtime() (seconds since epoch) if undefined - %% set mtime to atime if undefined - %% if both undefined ? + atime=Atime0, + mtime=Mtime0, + ctime=Ctime}, + TimeType) -> + + %% FIXME: wtf + {Atime, Mtime} = case {Atime0, Mtime0} of + {undefined, Mtime0} -> {erlang:localtime(), Mtime0}; + {Atime0, undefined} -> {Atime0, Atime0}; + Complete -> Complete + end, drv_command(Port, [?FILE_WRITE_INFO, int_to_int32bytes(Mode), int_to_int32bytes(Uid), int_to_int32bytes(Gid), - int_to_int64bytes(Atime), - int_to_int64bytes(Mtime), - int_to_int64bytes(Ctime), + int_to_int64bytes(to_seconds(Atime, TimeType)), + int_to_int64bytes(to_seconds(Mtime, TimeType)), + int_to_int64bytes(to_seconds(Ctime, TimeType)), pathname(File)]). @@ -825,16 +842,28 @@ read_link_int(Port, Link) -> %% read_link_info/{2,3} read_link_info(Link) -> - read_link_info_int({?DRV, [binary]}, Link). + read_link_info_int({?DRV, [binary]}, Link, local). read_link_info(Port, Link) when is_port(Port) -> - read_link_info_int(Port, Link). + read_link_info_int(Port, Link, local); -read_link_info_int(Port, Link) -> - drv_command(Port, [?FILE_LSTAT, pathname(Link)]). +read_link_info(Link, Opts) -> + read_link_info_int({?DRV, [binary]}, Link, plgv(time, Opts)). +read_link_info(Port, Link, Opts) when is_port(Port) -> + read_link_info_int(Port, Link, plgv(time, Opts)). +read_link_info_int(Port, Link, TimeType) -> + case drv_command(Port, [?FILE_LSTAT, pathname(Link)]) of + {ok, FI} -> {ok, FI#file_info{ + ctime = from_seconds(FI#file_info.ctime, TimeType), + mtime = from_seconds(FI#file_info.mtime, TimeType), + atime = from_seconds(FI#file_info.atime, TimeType) + }}; + Error -> Error + end. + %% list_dir/{1,2} list_dir(Dir) -> @@ -1079,7 +1108,6 @@ translate_response(?FILE_RESP_DATA, List) -> {ok, ND}; translate_response(?FILE_RESP_INFO, List) when is_list(List) -> {ok, transform_info(List)}; - %{ok, transform_info_ints(get_uint32s(List))}; translate_response(?FILE_RESP_NUMERR, L0) -> {N, L1} = get_uint64(L0), {error, {N, list_to_atom(L1)}}; @@ -1285,3 +1313,155 @@ reverse(L, T) -> lists:reverse(L, T). % in list_to_binary, which is caught and generates the {error,badarg} return pathname(File) -> (catch prim_file:internal_name2native(File)). + + +%% proplist:get_value/2 +plgv(K,[{K, V}|_]) -> V; +plgv(K,[_|KVs]) -> plgv(K,KVs); +plgv(_,[]) -> undefined. + + +%% +%% We don't actually want this here +%% We want to use epochs in all prim but erl_prim_loader makes that tricky +%% It is probably needed to redo the whole erl_prim_loader + +-define(DAYS_FROM_0_TO_1970, 719528). +-define(SECONDS_PER_DAY, 86400). +-define(SECONDS_PER_HOUR, 3600). +-define(SECONDS_PER_MINUTE, 60). +-define(DAYS_PER_YEAR, 365). +-define(DAYS_PER_LEAP_YEAR, 366). + +from_seconds(Seconds, utc) when is_integer(Seconds) -> + gregorian_seconds_to_datetime(Seconds + ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970); +from_seconds(Seconds, local) when is_integer(Seconds) -> + erlang:universaltime_to_localtime(gregorian_seconds_to_datetime(Seconds + ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970)). + +to_seconds({_,_} = Datetime, utc) -> + datetime_to_gregorian_seconds(Datetime) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970; +to_seconds({_,_} = Datetime, local) -> + datetime_to_gregorian_seconds(erlang:localtime_to_universaltime(Datetime)) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970; +to_seconds(undefined, _) -> to_seconds(erlang:universaltime(), utc). + +%% perhaps like this + +posix_time(Time) -> + EpochStart = {{1970,1,1},{0,0,0}}, + {Days,{Hour,Min,Sec}} = calendar:time_difference(EpochStart, Time), + 86400*Days + 3600*Hour + 60*Min + Sec. + +posix_to_erlang_time(Sec) -> + OneMillion = 1000000, + Time = calendar:now_to_datetime({Sec div OneMillion, Sec rem OneMillion, 0}), + erlang:universaltime_to_localtime(Time). + + +% from calendar, slightly modified + +%% calendar:datetime_to_gregorian_seconds/1 + +datetime_to_gregorian_seconds({Date, Time}) -> + ?SECONDS_PER_DAY*date_to_gregorian_days(Date) + time_to_seconds(Time). + + +time_to_seconds({H, M, S}) when is_integer(H), is_integer(M), is_integer(S) -> + H * ?SECONDS_PER_HOUR + M * ?SECONDS_PER_MINUTE + S. + +date_to_gregorian_days({Year, Month, Day}) -> + date_to_gregorian_days(Year, Month, Day). + +date_to_gregorian_days(Year, Month, Day) when is_integer(Day), Day > 0 -> + Last = last_day_of_the_month(Year, Month), + if + Day =< Last -> + dy(Year) + dm(Month) + df(Year, Month) + Day - 1 + end. + +last_day_of_the_month(Y, M) when is_integer(Y), Y >= 0 -> + last_day_of_the_month1(Y, M). + +last_day_of_the_month1(_, 4) -> 30; +last_day_of_the_month1(_, 6) -> 30; +last_day_of_the_month1(_, 9) -> 30; +last_day_of_the_month1(_,11) -> 30; +last_day_of_the_month1(Y, 2) -> + case is_leap_year(Y) of + true -> 29; + _ -> 28 + end; +last_day_of_the_month1(_, M) when is_integer(M), M > 0, M < 13 -> + 31. + +dm(1) -> 0; dm(2) -> 31; dm(3) -> 59; dm(4) -> 90; +dm(5) -> 120; dm(6) -> 151; dm(7) -> 181; dm(8) -> 212; +dm(9) -> 243; dm(10) -> 273; dm(11) -> 304; dm(12) -> 334. + +df(_, Month) when Month < 3 -> 0; +df(Year, _) -> + case is_leap_year(Year) of + true -> 1; + false -> 0 + end. + + + +%% calendar:gregorian_seconds_to_datetime/1 + +gregorian_seconds_to_datetime(Secs) when Secs >= 0 -> + Days = Secs div ?SECONDS_PER_DAY, + Rest = Secs rem ?SECONDS_PER_DAY, + {gregorian_days_to_date(Days), seconds_to_time(Rest)}. + +seconds_to_time(Secs0) when Secs0 >= 0, Secs0 < ?SECONDS_PER_DAY -> + Hour = Secs0 div ?SECONDS_PER_HOUR, + Secs1 = Secs0 rem ?SECONDS_PER_HOUR, + Minute = Secs1 div ?SECONDS_PER_MINUTE, + Second = Secs1 rem ?SECONDS_PER_MINUTE, + {Hour, Minute, Second}. + +gregorian_days_to_date(Days) -> + {Year, DayOfYear} = day_to_year(Days), + {Month, DayOfMonth} = year_day_to_date(Year, DayOfYear), + {Year, Month, DayOfMonth}. + +day_to_year(DayOfEpoch) when DayOfEpoch >= 0 -> + Y0 = DayOfEpoch div ?DAYS_PER_YEAR, + {Y1, D1} = dty(Y0, DayOfEpoch, dy(Y0)), + {Y1, DayOfEpoch - D1}. + +dty(Y, D1, D2) when D1 < D2 -> dty(Y-1, D1, dy(Y-1)); +dty(Y, _D1, D2) -> {Y, D2}. + +dy(Y) when Y =< 0 -> 0; +dy(Y) -> + X = Y - 1, + (X div 4) - (X div 100) + (X div 400) + X*?DAYS_PER_YEAR + ?DAYS_PER_LEAP_YEAR. + +year_day_to_date(Year, DayOfYear) -> + ExtraDay = case is_leap_year(Year) of + true -> 1; + false -> 0 + end, + {Month, Day} = year_day_to_date2(ExtraDay, DayOfYear), + {Month, Day + 1}. + +year_day_to_date2(_, Day) when Day < 31 -> {1, Day}; +year_day_to_date2(E, Day) when 31 =< Day, Day < 59 + E -> {2, Day - 31}; +year_day_to_date2(E, Day) when 59 + E =< Day, Day < 90 + E -> { 3, Day - ( 59 + E)}; +year_day_to_date2(E, Day) when 90 + E =< Day, Day < 120 + E -> { 4, Day - ( 90 + E)}; +year_day_to_date2(E, Day) when 120 + E =< Day, Day < 151 + E -> { 5, Day - (120 + E)}; +year_day_to_date2(E, Day) when 151 + E =< Day, Day < 181 + E -> { 6, Day - (151 + E)}; +year_day_to_date2(E, Day) when 181 + E =< Day, Day < 212 + E -> { 7, Day - (181 + E)}; +year_day_to_date2(E, Day) when 212 + E =< Day, Day < 243 + E -> { 8, Day - (212 + E)}; +year_day_to_date2(E, Day) when 243 + E =< Day, Day < 273 + E -> { 9, Day - (243 + E)}; +year_day_to_date2(E, Day) when 273 + E =< Day, Day < 304 + E -> {10, Day - (273 + E)}; +year_day_to_date2(E, Day) when 304 + E =< Day, Day < 334 + E -> {11, Day - (304 + E)}; +year_day_to_date2(E, Day) when 334 + E =< Day -> {12, Day - (334 + E)}. + +is_leap_year(Y) when is_integer(Y), Y >= 0 -> is_leap_year1(Y). +is_leap_year1(Year) when Year rem 4 =:= 0, Year rem 100 > 0 -> true; +is_leap_year1(Year) when Year rem 400 =:= 0 -> true; +is_leap_year1(_) -> false. + + diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index dafd2c6909..d8ade07336 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -31,7 +31,8 @@ read_file_info/1, read_file_info/2, write_file_info/2, write_file_info/3, altname/1, - read_link_info/1, read_link_info/2, read_link/1, + read_link_info/1, read_link_info/2, + read_link/1, make_link/2, make_symlink/2, read_file/1, write_file/2, write_file/3]). %% Specialized @@ -213,10 +214,16 @@ del_dir(Name) -> Reason :: posix() | badarg. read_file_info(Name) -> - file_info_time(local, check_and_call(read_file_info, [file_name(Name)])). + check_and_call(read_file_info, [file_name(Name)]). + +-spec read_file_info(Filename, Opts) -> {ok, FileInfo} | {error, Reason} when + Filename :: name(), + Opts :: list(), + FileInfo :: file_info(), + Reason :: posix() | badarg. read_file_info(Name, Opts) when is_list(Opts) -> - file_info_time(proplists:get_value(time, Opts, local), check_and_call(read_file_info, [file_name(Name)])). + check_and_call(read_file_info, [file_name(Name), Opts]). -spec altname(Name :: name()) -> any(). @@ -229,10 +236,11 @@ altname(Name) -> Reason :: posix() | badarg. read_link_info(Name) -> - read_link_info(Name, [{time, local}]). + check_and_call(read_link_info, [file_name(Name)]). read_link_info(Name, Opts) when is_list(Opts) -> - file_info_time(proplists:get_value(time, Opts, local), check_and_call(read_link_info, [file_name(Name)])). + check_and_call(read_link_info, [file_name(Name),Opts]). + -spec read_link(Name) -> {ok, Filename} | {error, Reason} when Name :: name(), @@ -248,10 +256,17 @@ read_link(Name) -> Reason :: posix() | badarg. write_file_info(Name, Info = #file_info{}) -> - check_and_call(write_file_info, [file_name(Name), file_info_epochs(local, Info)]). + check_and_call(write_file_info, [file_name(Name), Info]). + +-spec write_file_info(Filename, FileInfo, Opts) -> ok | {error, Reason} when + Filename :: name(), + Opts :: list(), + FileInfo :: file_info(), + Reason :: posix() | badarg. + write_file_info(Name, Info = #file_info{}, Opts) when is_list(Opts) -> - check_and_call(write_file_info, [file_name(Name), file_info_epochs(proplists:get_value(time, Opts, local), Info)]). + check_and_call(write_file_info, [file_name(Name), Info, Opts]). -spec list_dir(Dir) -> {ok, Filenames} | {error, Reason} when Dir :: name(), @@ -1335,59 +1350,59 @@ fname_join(Dir, Name) -> %% all times from prime_file (and file_server) are in unix epochs %% from_epochs -file_info_time(epoch, {ok, FI} = R) -> R; -file_info_time(local, {ok, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI}) -> - {ok, FI#file_info{ - atime = time_epochs_to_local(Atime), - ctime = time_epochs_to_local(Ctime), - mtime = time_epochs_to_local(Mtime) - } - }; -file_info_time(utc, {ok, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI}) -> - {ok, FI#file_info{ - atime = time_epochs_to_utc(Atime), - ctime = time_epochs_to_utc(Ctime), - mtime = time_epochs_to_utc(Mtime) - } - }; -file_info_time(_, Error) -> Error. - -%% from_epochs -file_info_epochs(epoch, FI) -> FI; -file_info_epochs(local, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI) -> - FI#file_info{ - atime = time_local_to_epochs(Atime), - ctime = time_local_to_epochs(Ctime), - mtime = time_local_to_epochs(Mtime) - }; -file_info_epochs(utc, {ok, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI}) -> - FI#file_info{ - atime = time_utc_to_epochs(Atime), - ctime = time_utc_to_epochs(Ctime), - mtime = time_utc_to_epochs(Mtime) - }. - - --define(DAYS_FROM_0_TO_1970, 719528). --define(SECONDS_PER_DAY, 86400). - -time_epochs_to_utc(Seconds) when is_integer(Seconds) -> - calendar:gregorian_seconds_to_datetime(Seconds + ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970). - -time_epochs_to_local(Seconds) when is_integer(Seconds) -> - erlang:universaltime_to_localtime(calendar:gregorian_seconds_to_datetime(Seconds + ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970)). - -time_utc_to_epochs({_, _} = Datetime) -> - calendar:datetime_to_gregorian_seconds(Datetime) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970; -time_utc_to_epochs(undefined) -> - time_utc_to_epochs(erlang:universaltime()). - - -time_local_to_epochs({_, _} = Datetime) -> - calendar:datetime_to_gregorian_seconds(erlang:localtime_to_universaltime(Datetime)) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970; -time_local_to_epochs(undefined) -> - time_utc_to_epochs(erlang:universaltime()). - +%file_info_time(epoch, {ok, FI} = R) -> R; +%file_info_time(local, {ok, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI}) -> +% {ok, FI#file_info{ +% atime = time_epochs_to_local(Atime), +% ctime = time_epochs_to_local(Ctime), +% mtime = time_epochs_to_local(Mtime) +% } +% }; +%file_info_time(utc, {ok, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI}) -> +% {ok, FI#file_info{ +% atime = time_epochs_to_utc(Atime), +% ctime = time_epochs_to_utc(Ctime), +% mtime = time_epochs_to_utc(Mtime) +% } +% }; +%file_info_time(_, Error) -> Error. +% +%%% from_epochs +%file_info_epochs(epoch, FI) -> FI; +%file_info_epochs(local, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI) -> +% FI#file_info{ +% atime = time_local_to_epochs(Atime), +% ctime = time_local_to_epochs(Ctime), +% mtime = time_local_to_epochs(Mtime) +% }; +%file_info_epochs(utc, {ok, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI}) -> +% FI#file_info{ +% atime = time_utc_to_epochs(Atime), +% ctime = time_utc_to_epochs(Ctime), +% mtime = time_utc_to_epochs(Mtime) +% }. +% +% +%-define(DAYS_FROM_0_TO_1970, 719528). +%-define(SECONDS_PER_DAY, 86400). +% +%time_epochs_to_utc(Seconds) when is_integer(Seconds) -> +% calendar:gregorian_seconds_to_datetime(Seconds + ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970). +% +%time_epochs_to_local(Seconds) when is_integer(Seconds) -> +% erlang:universaltime_to_localtime(calendar:gregorian_seconds_to_datetime(Seconds + ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970)). +% +%time_utc_to_epochs({_, _} = Datetime) -> +% calendar:datetime_to_gregorian_seconds(Datetime) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970; +%time_utc_to_epochs(undefined) -> +% time_utc_to_epochs(erlang:universaltime()). +% +% +%time_local_to_epochs({_, _} = Datetime) -> +% calendar:datetime_to_gregorian_seconds(erlang:localtime_to_universaltime(Datetime)) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970; +%time_local_to_epochs(undefined) -> +% time_utc_to_epochs(erlang:universaltime()). +% %% file_name(FileName) %% Generates a flat file name from a deep list of atoms and diff --git a/lib/kernel/src/file_server.erl b/lib/kernel/src/file_server.erl index 64c61ba3ac..81f9efcf39 100644 --- a/lib/kernel/src/file_server.erl +++ b/lib/kernel/src/file_server.erl @@ -147,15 +147,24 @@ handle_call({get_cwd, Name}, _From, Handle) -> handle_call({read_file_info, Name}, _From, Handle) -> {reply, ?PRIM_FILE:read_file_info(Handle, Name), Handle}; +handle_call({read_file_info, Name, Opts}, _From, Handle) -> + {reply, ?PRIM_FILE:read_file_info(Handle, Name, Opts), Handle}; + handle_call({altname, Name}, _From, Handle) -> {reply, ?PRIM_FILE:altname(Handle, Name), Handle}; handle_call({write_file_info, Name, Info}, _From, Handle) -> {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info), Handle}; +handle_call({write_file_info, Name, Info, Opts}, _From, Handle) -> + {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, Opts), Handle}; + handle_call({read_link_info, Name}, _From, Handle) -> {reply, ?PRIM_FILE:read_link_info(Handle, Name), Handle}; +handle_call({read_link_info, Name, Opts}, _From, Handle) -> + {reply, ?PRIM_FILE:read_link_info(Handle, Name, Opts), Handle}; + handle_call({read_link, Name}, _From, Handle) -> {reply, ?PRIM_FILE:read_link(Handle, Name), Handle}; -- cgit v1.2.3 From 7be5712096a0fdf44e2b31d493f03688d4c137e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 27 Jun 2011 16:06:53 +0200 Subject: Do not use calendar module in preloaded Bad practice --- erts/preloaded/src/prim_zip.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erts/preloaded/src/prim_zip.erl b/erts/preloaded/src/prim_zip.erl index 392a9feb45..d29f17ae56 100644 --- a/erts/preloaded/src/prim_zip.erl +++ b/erts/preloaded/src/prim_zip.erl @@ -432,7 +432,7 @@ binary_io({file_info, B}, _) -> is_binary(B) -> {regular, byte_size(B)}; B =:= directory -> {directory, 0} end, - Now = calendar:local_time(), + Now = erlang:localtime(), #file_info{size = Size, type = Type, access = read_write, atime = Now, mtime = Now, ctime = Now, mode = 0, links = 1, major_device = 0, -- cgit v1.2.3 From 9c15c1015bd60dd837587e9cf4be67abe0995129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 30 Nov 2011 17:59:40 +0100 Subject: efile_drv: Fix casting between Sint64 and time_t --- erts/emulator/drivers/common/efile_drv.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 184d27fb62..e7235c30f7 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -2124,9 +2124,10 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) put_int32(d->info.size_low, &resbuf[1 + ( 1 * 4)]); put_int32(d->info.type, &resbuf[1 + ( 2 * 4)]); + /* Note 64 bit indexing in resbuf here */ put_int64(d->info.accessTime, &resbuf[1 + ( 3 * 4)]); put_int64(d->info.modifyTime, &resbuf[1 + ( 5 * 4)]); - put_int64(d->info.cTime , &resbuf[1 + ( 7 * 4)]); + put_int64(d->info.cTime, &resbuf[1 + ( 7 * 4)]); put_int32(d->info.mode, &resbuf[1 + ( 9 * 4)]); put_int32(d->info.links, &resbuf[1 + (10 * 4)]); @@ -2490,9 +2491,9 @@ file_output(ErlDrvData e, char* buf, int count) d->info.mode = get_int32(buf + 0 * 4); d->info.uid = get_int32(buf + 1 * 4); d->info.gid = get_int32(buf + 2 * 4); - d->info.accessTime = get_int64(buf + 3 * 4); - d->info.modifyTime = get_int64(buf + 5 * 4); - d->info.cTime = get_int64(buf + 7 * 4); + d->info.accessTime = (time_t)((Sint64)get_int64(buf + 3 * 4)); + d->info.modifyTime = (time_t)((Sint64)get_int64(buf + 5 * 4)); + d->info.cTime = (time_t)((Sint64)get_int64(buf + 7 * 4)); FILENAME_COPY(d->b, buf + 9*4); d->command = command; -- cgit v1.2.3 From 4545abc3bc54ac9be175a53f19ed62fcd3911794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 30 Nov 2011 18:11:42 +0100 Subject: Fix prim_file time conversions --- erts/preloaded/src/prim_file.erl | 58 +++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 69ef0b9d54..b781dffba5 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -51,7 +51,7 @@ make_link/2, make_link/3, make_symlink/2, make_symlink/3, read_link/1, read_link/2, - read_link_info/1, read_link_info/2, + read_link_info/1, read_link_info/2, read_link_info/3, list_dir/1, list_dir/2]). %% How to start and stop the ?DRV port. -export([start/0, stop/1]). @@ -725,16 +725,18 @@ del_dir_int(Port, Dir) -> -%% read_file_info/{1,2} +%% read_file_info/{1,2,3} read_file_info(File) -> read_file_info_int({?DRV, [binary]}, File, local). read_file_info(Port, File) when is_port(Port) -> - read_file_info_int(Port, File, local). + read_file_info_int(Port, File, local); +read_file_info(File, Opts) -> + read_file_info_int({?DRV, [binary]}, File, plgv(time, Opts, local)). read_file_info(Port, File, Opts) when is_port(Port) -> - read_file_info_int(Port, File, plgv(time, Opts)). + read_file_info_int(Port, File, plgv(time, Opts, local)). read_file_info_int(Port, File, TimeType) -> case drv_command(Port, [?FILE_FSTAT, pathname(File)]) of @@ -765,12 +767,11 @@ write_file_info(File, Info) -> write_file_info(Port, File, Info) when is_port(Port) -> write_file_info_int(Port, File, Info, local); - write_file_info(File, Info, Opts) -> - write_file_info_int({?DRV, [binary]}, File, Info, plgv(time, Opts)). + write_file_info_int({?DRV, [binary]}, File, Info, plgv(time, Opts, local)). write_file_info(Port, File, Info, Opts) when is_port(Port) -> - write_file_info_int(Port, File, Info, plgv(time, Opts)). + write_file_info_int(Port, File, Info, plgv(time, Opts, local)). write_file_info_int(Port, File, @@ -783,9 +784,13 @@ write_file_info_int(Port, TimeType) -> %% FIXME: wtf + %% sätt atime beroende på timetype, om ej satt + %% sätt mtime som atime, om ej satt + {Atime, Mtime} = case {Atime0, Mtime0} of {undefined, Mtime0} -> {erlang:localtime(), Mtime0}; {Atime0, undefined} -> {Atime0, Atime0}; + {undefined, undefined} -> {erlang:localtime(), erlang:localtime()}; Complete -> Complete end, @@ -848,10 +853,10 @@ read_link_info(Port, Link) when is_port(Port) -> read_link_info_int(Port, Link, local); read_link_info(Link, Opts) -> - read_link_info_int({?DRV, [binary]}, Link, plgv(time, Opts)). + read_link_info_int({?DRV, [binary]}, Link, plgv(time, Opts, local)). read_link_info(Port, Link, Opts) when is_port(Port) -> - read_link_info_int(Port, Link, plgv(time, Opts)). + read_link_info_int(Port, Link, plgv(time, Opts, local)). read_link_info_int(Port, Link, TimeType) -> @@ -1161,7 +1166,6 @@ translate_response(?FILE_RESP_ALL_DATA, Data) -> translate_response(X, Data) -> {error, {bad_response_from_port, [X | Data]}}. - transform_info([ Hsize1, Hsize2, Hsize3, Hsize4, Lsize1, Lsize2, Lsize3, Lsize4, @@ -1211,9 +1215,7 @@ int_to_int32bytes(undefined) -> <<-1:32>>. int_to_int64bytes(Int) when is_integer(Int) -> - <>; -int_to_int64bytes(undefined) -> - <<-1:64>>. + <>. sint64(I1,I2,I3,I4,I5,I6,I7,I8) when I1 > 127 -> @@ -1315,10 +1317,10 @@ pathname(File) -> (catch prim_file:internal_name2native(File)). -%% proplist:get_value/2 -plgv(K,[{K, V}|_]) -> V; -plgv(K,[_|KVs]) -> plgv(K,KVs); -plgv(_,[]) -> undefined. +%% proplist:get_value/3 +plgv(K, [{K, V}|_], _) -> V; +plgv(K, [_|KVs], D) -> plgv(K, KVs, D); +plgv(_, [], D) -> D. %% @@ -1333,16 +1335,28 @@ plgv(_,[]) -> undefined. -define(DAYS_PER_YEAR, 365). -define(DAYS_PER_LEAP_YEAR, 366). +from_seconds(Seconds, epoch) when is_integer(Seconds) -> + Seconds; from_seconds(Seconds, utc) when is_integer(Seconds) -> - gregorian_seconds_to_datetime(Seconds + ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970); + epoch_to_datetime(Seconds); from_seconds(Seconds, local) when is_integer(Seconds) -> - erlang:universaltime_to_localtime(gregorian_seconds_to_datetime(Seconds + ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970)). + erlang:universaltime_to_localtime(epoch_to_datetime(Seconds)). +epoch_to_datetime(Seconds) -> + gregorian_seconds_to_datetime(Seconds + ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970). + +to_seconds(Seconds, epoch) when is_integer(Seconds) -> + Seconds; to_seconds({_,_} = Datetime, utc) -> - datetime_to_gregorian_seconds(Datetime) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970; + datetime_to_epoch(Datetime); to_seconds({_,_} = Datetime, local) -> - datetime_to_gregorian_seconds(erlang:localtime_to_universaltime(Datetime)) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970; -to_seconds(undefined, _) -> to_seconds(erlang:universaltime(), utc). + datetime_to_epoch(erlang:localtime_to_universaltime(Datetime)); +to_seconds(undefined, _) -> + to_seconds(erlang:universaltime(), utc). + +datetime_to_epoch(Datetime) -> + datetime_to_gregorian_seconds(Datetime) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970. + %% perhaps like this -- cgit v1.2.3 From 4ee95bc5c0113da005feeded022876383879d55c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 30 Nov 2011 18:12:31 +0100 Subject: Add spec for file:read_link_info/2 --- lib/kernel/src/file.erl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index d8ade07336..80780700ab 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -238,6 +238,12 @@ altname(Name) -> read_link_info(Name) -> check_and_call(read_link_info, [file_name(Name)]). +-spec read_link_info(Name, Opts) -> {ok, FileInfo} | {error, Reason} when + Name :: name(), + Opts :: list(), + FileInfo :: file_info(), + Reason :: posix() | badarg. + read_link_info(Name, Opts) when is_list(Opts) -> check_and_call(read_link_info, [file_name(Name),Opts]). @@ -264,7 +270,6 @@ write_file_info(Name, Info = #file_info{}) -> FileInfo :: file_info(), Reason :: posix() | badarg. - write_file_info(Name, Info = #file_info{}, Opts) when is_list(Opts) -> check_and_call(write_file_info, [file_name(Name), Info, Opts]). -- cgit v1.2.3 From 2a1f035f777b5caef0c47dfd863675ef51296c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 30 Nov 2011 18:41:15 +0100 Subject: Fix validate structure in file_info --- erts/preloaded/src/prim_file.erl | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index b781dffba5..a301abb667 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -773,8 +773,7 @@ write_file_info(File, Info, Opts) -> write_file_info(Port, File, Info, Opts) when is_port(Port) -> write_file_info_int(Port, File, Info, plgv(time, Opts, local)). -write_file_info_int(Port, - File, +write_file_info_int(Port, File, #file_info{mode=Mode, uid=Uid, gid=Gid, @@ -783,16 +782,12 @@ write_file_info_int(Port, ctime=Ctime}, TimeType) -> - %% FIXME: wtf - %% sätt atime beroende på timetype, om ej satt - %% sätt mtime som atime, om ej satt + % Atime and/or Mtime might be undefined + % - use localtime() for atime, if atime is undefined + % - use atime as mtime if mtime is undefined - {Atime, Mtime} = case {Atime0, Mtime0} of - {undefined, Mtime0} -> {erlang:localtime(), Mtime0}; - {Atime0, undefined} -> {Atime0, Atime0}; - {undefined, undefined} -> {erlang:localtime(), erlang:localtime()}; - Complete -> Complete - end, + Atime = file_info_validate_atime(Atime0, TimeType), + Mtime = file_info_validate_mtime(Mtime0, Atime), drv_command(Port, [?FILE_WRITE_INFO, int_to_int32bytes(Mode), @@ -804,6 +799,13 @@ write_file_info_int(Port, pathname(File)]). +file_info_validate_atime(Atime, _) when Atime =/= undefined -> Atime; +file_info_validate_atime(undefined, local) -> erlang:localtime(); +file_info_validate_atime(undefined, utc) -> erlang:universaltime(); +file_info_validate_atime(undefined, epoch) -> datetime_to_epoch(erlang:universaltime()). + +file_info_validate_mtime(undefined, Atime) -> Atime; +file_info_validate_mtime(Mtime, _) -> Mtime. %% make_link/{2,3} -- cgit v1.2.3 From 73b4ed6d1141e760fcc108e45d3d66ca110f1018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 30 Nov 2011 19:12:45 +0100 Subject: Silence warnings in prim_file --- erts/preloaded/src/prim_file.erl | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index a301abb667..87fdb3fb8f 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -1360,17 +1360,17 @@ datetime_to_epoch(Datetime) -> datetime_to_gregorian_seconds(Datetime) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970. -%% perhaps like this - -posix_time(Time) -> - EpochStart = {{1970,1,1},{0,0,0}}, - {Days,{Hour,Min,Sec}} = calendar:time_difference(EpochStart, Time), - 86400*Days + 3600*Hour + 60*Min + Sec. - -posix_to_erlang_time(Sec) -> - OneMillion = 1000000, - Time = calendar:now_to_datetime({Sec div OneMillion, Sec rem OneMillion, 0}), - erlang:universaltime_to_localtime(Time). +%% erl_tar uses this convention (investigate) +%% +%% posix_time(Time) -> +%% EpochStart = {{1970,1,1},{0,0,0}}, +%% {Days,{Hour,Min,Sec}} = calendar:time_difference(EpochStart, Time), +%% 86400*Days + 3600*Hour + 60*Min + Sec. +%% +%% posix_to_erlang_time(Sec) -> +%% OneMillion = 1000000, +%% Time = calendar:now_to_datetime({Sec div OneMillion, Sec rem OneMillion, 0}), +%% erlang:universaltime_to_localtime(Time). % from calendar, slightly modified -- cgit v1.2.3 From b7f7f363c44aaf0bd29e877f8060b806963458ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 2 Dec 2011 15:17:28 +0100 Subject: Fix undefined ctime for invalid file handles * ctime were never defined for invalid file handles * fix epoch <-> fileinfo conversions --- erts/emulator/drivers/win32/win_efile.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index 134c4b675f..630d2b4df8 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -59,7 +59,7 @@ #define EPOCH_TO_FILETIME(ft, epoch) \ do { \ ULARGE_INTEGER ull; \ - ull.QuadPart = (((epoch)*TICKS_PER_SECOND) + EPOCH_DIFFERENCE); \ + ull.QuadPart = (((epoch) + EPOCH_DIFFERENCE) + TICKS_PER_SECOND); \ (ft).dwLowDateTime = ull.LowPart; \ (ft).dwHighDateTime = ull.HighPart; \ } while(0) @@ -884,8 +884,7 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, findbuf.cFileName[0] = L'\0'; pInfo->links = 1; - pInfo->modifyTime = 0; - pInfo->accessTime = pInfo->modifyTime; + pInfo->cTime = pInfo->accessTime = pInfo->modifyTime = 0; } else { SYSTEMTIME SystemTime; FILETIME LocalFTime; -- cgit v1.2.3 From 913f05af100e98a8665bbb6168e89fbcfe4ece75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 2 Dec 2011 15:25:30 +0100 Subject: Teach windows sys_localtime_r --- erts/emulator/drivers/win32/win_efile.c | 2 +- erts/emulator/sys/win32/erl_win_sys.h | 5 +++ erts/emulator/sys/win32/sys_time.c | 54 ++++++++++++++++++++++++++++----- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index 630d2b4df8..0d3d334154 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -59,7 +59,7 @@ #define EPOCH_TO_FILETIME(ft, epoch) \ do { \ ULARGE_INTEGER ull; \ - ull.QuadPart = (((epoch) + EPOCH_DIFFERENCE) + TICKS_PER_SECOND); \ + ull.QuadPart = (((epoch) + EPOCH_DIFFERENCE) * TICKS_PER_SECOND); \ (ft).dwLowDateTime = ull.LowPart; \ (ft).dwHighDateTime = ull.HighPart; \ } while(0) diff --git a/erts/emulator/sys/win32/erl_win_sys.h b/erts/emulator/sys/win32/erl_win_sys.h index d770691026..4ed0b94e2d 100644 --- a/erts/emulator/sys/win32/erl_win_sys.h +++ b/erts/emulator/sys/win32/erl_win_sys.h @@ -117,6 +117,11 @@ int erts_check_io_debug(void); #define SYS_CLK_TCK 1000 #define SYS_CLOCK_RESOLUTION 1 +struct tm *sys_localtime_r(time_t *epochs, struct tm *ptm); + +#define localtime_r sys_localtime_r +#define HAVE_LOCALTIME_R 1 + typedef struct { long tv_sec; long tv_usec; diff --git a/erts/emulator/sys/win32/sys_time.c b/erts/emulator/sys/win32/sys_time.c index fc868507cb..af903aacfd 100644 --- a/erts/emulator/sys/win32/sys_time.c +++ b/erts/emulator/sys/win32/sys_time.c @@ -35,7 +35,24 @@ /******************* Routines for time measurement *********************/ #define EPOCH_JULIAN_DIFF LL_LITERAL(11644473600) - +#define TICKS_PER_SECOND (10000000LL) + +#define EPOCH_TO_FILETIME(ft, epoch) \ + do { \ + ULARGE_INTEGER ull; \ + ull.QuadPart = (((epoch) + EPOCH_JULIAN_DIFF) * TICKS_PER_SECOND); \ + (ft).dwLowDateTime = ull.LowPart; \ + (ft).dwHighDateTime = ull.HighPart; \ + } while(0) + +#define FILETIME_TO_EPOCH(epoch, ft) \ + do { \ + ULARGE_INTEGER ull; \ + ull.LowPart = (ft).dwLowDateTime; \ + ull.HighPart = (ft).dwHighDateTime; \ + (epoch) = ((ull.QuadPart / TICKS_PER_SECOND) - EPOCH_JULIAN_DIFF); \ + } while(0) + static SysHrTime wrap = 0; static DWORD last_tick_count = 0; @@ -45,6 +62,35 @@ sys_init_time(void) return 1; } +struct tm * sys_localtime_r(time_t *epochs, struct tm *ptm) +{ + FILETIME ft,lft; + SYSTEMTIME st; + + if ((((*epochs) + EPOCH_JULIAN_DIFF) * TICKS_PER_SECOND) < 0LL) { + return NULL; + } + + EPOCH_TO_FILETIME(ft,*epochs); + + if (!FileTimeToLocalFileTime(&ft,&lft)) { + return NULL; + } + + if (!FileTimeToSystemTime(&lft,&st)) { + return NULL; + } + + ptm->tm_year = (int) st.wYear - 1900; + ptm->tm_mon = (int) st.wMonth - 1; + ptm->tm_mday = (int) st.wDay; + ptm->tm_hour = (int) st.wHour; + ptm->tm_min = (int) st.wMinute; + ptm->tm_sec = (int) st.wSecond; + + return ptm; +} + void sys_gettimeofday(SysTimeval *tv) { @@ -91,9 +137,3 @@ sys_times(SysTimes *buffer) { buffer->tms_stime = (clock_t) (system & LL_LITERAL(0x7FFFFFFF)); return kernel_ticks; } - - - - - - -- cgit v1.2.3 From 42f20932f5b2b8e1eebca47bfe696ab5685ba5f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 2 Dec 2011 15:34:19 +0100 Subject: Fix types for gregday in erl_time_sup.c --- erts/emulator/beam/erl_time_sup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index 829ec32288..ab2aa6f5dc 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -627,7 +627,7 @@ static int erl_mktime(time_t *c, struct tm *tm) { * greater of equal to 1600 , and month [1-12] and day [1-31] * are within range. Otherwise it returns -1. */ -static int long gregday(int year, int month, int day) +static time_t gregday(Sint year, Sint month, Sint day) { int long ndays = 0; int gyear, pyear, m; -- cgit v1.2.3 From 1d603bc4e80cbb3d23da61a55cee0fb8e67d72fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 2 Dec 2011 15:36:39 +0100 Subject: Let univ_to_local reflect HAVE localtime_r Handle error cases when localtime or localtime_r returns null. --- erts/emulator/beam/erl_time_sup.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index ab2aa6f5dc..695d08ae2d 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -757,17 +757,20 @@ univ_to_local(Sint *year, Sint *month, Sint *day, #endif #ifdef HAVE_LOCALTIME_R - localtime_r(&the_clock, (tm = &tmbuf)); + tm = localtime_r(&the_clock, &tmbuf); #else tm = localtime(&the_clock); #endif - *year = tm->tm_year + 1900; - *month = tm->tm_mon +1; - *day = tm->tm_mday; - *hour = tm->tm_hour; - *minute = tm->tm_min; - *second = tm->tm_sec; - return 1; + if (tm) { + *year = tm->tm_year + 1900; + *month = tm->tm_mon +1; + *day = tm->tm_mday; + *hour = tm->tm_hour; + *minute = tm->tm_min; + *second = tm->tm_sec; + return 1; + } + return 0; } -- cgit v1.2.3 From 24f661ade9375e2489d3f07fd7f0113da3593a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 2 Dec 2011 18:50:00 +0100 Subject: unix_efile: Zero is a valid number in utime Both mtime and atime were incorrectly checked for zero --- erts/emulator/drivers/unix/unix_efile.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 0237c81e1e..2e6aa15b06 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -952,24 +952,20 @@ efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) #endif /* !VXWORKS */ - if (pInfo->accessTime != 0 && pInfo->modifyTime != 0) { - struct utimbuf tval; - struct tm timebuf; + struct utimbuf tval; - tval.actime = pInfo->accessTime; - tval.modtime = pInfo->modifyTime; + tval.actime = pInfo->accessTime; + tval.modtime = pInfo->modifyTime; #ifdef VXWORKS - /* VxWorks' utime doesn't work when the file is a nfs mounted - * one, don't report error if utime fails. - */ - utime(name, &tval); - return 1; + /* VxWorks' utime doesn't work when the file is a nfs mounted + * one, don't report error if utime fails. + */ + utime(name, &tval); + return 1; #else - return check_error(utime(name, &tval), errInfo); + return check_error(utime(name, &tval), errInfo); #endif - } - return 1; } -- cgit v1.2.3 From bd271023fe529f1b591408226743968085a78556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 2 Dec 2011 18:54:19 +0100 Subject: Add file_info_opt tests in prim_file_SUITE --- lib/kernel/test/prim_file_SUITE.erl | 106 +++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index 00eda6292f..035817a8bc 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -32,7 +32,10 @@ file_info_basic_directory_a/1, file_info_basic_directory_b/1, file_info_bad_a/1, file_info_bad_b/1, file_info_times_a/1, file_info_times_b/1, - file_write_file_info_a/1, file_write_file_info_b/1]). + file_write_file_info_a/1, file_write_file_info_b/1, + file_read_file_info_opts/1, file_write_file_info_opts/1, + file_write_read_file_info_opts/1 + ]). -export([rename_a/1, rename_b/1, access/1, truncate/1, datasync/1, sync/1, read_write/1, pread_write/1, append/1, exclusive/1]). @@ -90,7 +93,10 @@ groups() -> file_info_basic_directory_a, file_info_basic_directory_b, file_info_bad_a, file_info_bad_b, file_info_times_a, file_info_times_b, - file_write_file_info_a, file_write_file_info_b]}, + file_write_file_info_a, file_write_file_info_b, + file_read_file_info_opts, file_write_file_info_opts, + file_write_read_file_info_opts + ]}, {errors, [], [e_delete, e_rename, e_make_dir, e_del_dir]}, {compression, [], @@ -1074,6 +1080,102 @@ file_write_file_info(Config, Handle, Suffix) -> ?line test_server:timetrap_cancel(Dog), ok. +%% Test the write_file_info/3 function. + +file_write_file_info_opts(suite) -> []; +file_write_file_info_opts(doc) -> []; +file_write_file_info_opts(Config) when is_list(Config) -> + {ok, Handle} = ?PRIM_FILE:start(), + Dog = test_server:timetrap(test_server:seconds(10)), + RootDir = get_good_directory(Config), + test_server:format("RootDir = ~p", [RootDir]), + + Name = filename:join(RootDir, atom_to_list(?MODULE) ++"_write_file_info_opts"), + ok = ?PRIM_FILE:write_file(Name, "hello_opts"), + + lists:foreach(fun + ({FI, Opts}) -> + ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, FI, Opts]) + end, [ + {#file_info{ mode=8#600, atime = Time, mtime = Time, ctime = Time}, Opts} || + Opts <- [[{time, epoch}]], + Time <- [ 0,1,-1,100,-100,1000,-1000,10000,-10000 ] + ]), + + lists:foreach(fun + ({FI, Opts}) -> + ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, FI, Opts]) + end, [ + {#file_info{ mode=8#400, atime = Time, mtime = Time, ctime = Time}, Opts} || + Opts <- [[{time, utc}],[{time, local}]], + Time <- [ + {{1970,1,1},{0,0,0}}, + {{1970,1,1},{0,0,1}}, + {{1969,12,31},{23,59,59}}, + {{1908,2,3},{23,59,59}}, + {{2012,2,3},{23,59,59}}, + {{2040,2,3},{23,59,59}}, + erlang:localtime() + ]]), + ok = ?PRIM_FILE:stop(Handle), + test_server:timetrap_cancel(Dog), + ok. + +file_read_file_info_opts(suite) -> []; +file_read_file_info_opts(doc) -> []; +file_read_file_info_opts(Config) when is_list(Config) -> + {ok, Handle} = ?PRIM_FILE:start(), + Dog = test_server:timetrap(test_server:seconds(10)), + RootDir = get_good_directory(Config), + test_server:format("RootDir = ~p", [RootDir]), + + Name = filename:join(RootDir, atom_to_list(?MODULE) ++"_read_file_info_opts"), + ok = ?PRIM_FILE:write_file(Name, "hello_opts"), + + lists:foreach(fun + (Opts) -> + {ok,_} = ?PRIM_FILE_call(read_file_info, Handle, [Name, Opts]) + end, [[{time, Type}] || Type <- [local, utc, epoch]]), + ok = ?PRIM_FILE:stop(Handle), + test_server:timetrap_cancel(Dog), + ok. + +%% Test the write and read back *_file_info/3 functions. + +file_write_read_file_info_opts(suite) -> []; +file_write_read_file_info_opts(doc) -> []; +file_write_read_file_info_opts(Config) when is_list(Config) -> + {ok, Handle} = ?PRIM_FILE:start(), + Dog = test_server:timetrap(test_server:seconds(10)), + RootDir = get_good_directory(Config), + test_server:format("RootDir = ~p", [RootDir]), + + Name = filename:join(RootDir, atom_to_list(?MODULE) ++"_read_write_file_info_opts"), + ok = ?PRIM_FILE:write_file(Name, "hello_opts2"), + + ok = file_write_read_file_info_opts(Handle, Name, {{1989, 04, 28}, {19,30,22}}, [{time, local}]), + ok = file_write_read_file_info_opts(Handle, Name, {{1989, 04, 28}, {19,30,22}}, [{time, utc}]), + ok = file_write_read_file_info_opts(Handle, Name, {{1930, 04, 28}, {19,30,22}}, [{time, local}]), + ok = file_write_read_file_info_opts(Handle, Name, {{1930, 04, 28}, {19,30,22}}, [{time, utc}]), + ok = file_write_read_file_info_opts(Handle, Name, 1, [{time, epoch}]), + ok = file_write_read_file_info_opts(Handle, Name, -1, [{time, epoch}]), + ok = file_write_read_file_info_opts(Handle, Name, 300000, [{time, epoch}]), + ok = file_write_read_file_info_opts(Handle, Name, -300000, [{time, epoch}]), + ok = file_write_read_file_info_opts(Handle, Name, 0, [{time, epoch}]), + + ok = ?PRIM_FILE:stop(Handle), + test_server:timetrap_cancel(Dog), + ok. + +file_write_read_file_info_opts(Handle, Name, Mtime, Opts) -> + {ok, FI} = ?PRIM_FILE_call(read_file_info, Handle, [Name, Opts]), + FI2 = FI#file_info{ mtime = Mtime }, + ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, FI2, Opts]), + {ok, FI2} = ?PRIM_FILE_call(read_file_info, Handle, [Name, Opts]), + ok. + + + %% Returns a directory on a file system that has correct file times. get_good_directory(Config) -> -- cgit v1.2.3 From cf50fadc0133a41e8c4a52c3db05a1d0d6186e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 2 Dec 2011 19:54:12 +0100 Subject: Teach #file_info spec unix epochs for file times --- lib/kernel/include/file.hrl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/kernel/include/file.hrl b/lib/kernel/include/file.hrl index 3889bce393..ef42987a3d 100644 --- a/lib/kernel/include/file.hrl +++ b/lib/kernel/include/file.hrl @@ -25,10 +25,11 @@ {size :: non_neg_integer(), % Size of file in bytes. type :: 'device' | 'directory' | 'other' | 'regular' | 'symlink', access :: 'read' | 'write' | 'read_write' | 'none', - atime :: file:date_time(), % The local time the file was last read: - % {{Year, Mon, Day}, {Hour, Min, Sec}}. - mtime :: file:date_time(), % The local time the file was last written. - ctime :: file:date_time(), % The interpretation of this time field + atime :: file:date_time() | integer(), % The local time the file was last read: + % {{Year, Mon, Day}, {Hour, Min, Sec}}. + % atime, ctime, mtime may also be unix epochs() + mtime :: file:date_time() | integer(), % The local time the file was last written. + ctime :: file:date_time() | integer(), % The interpretation of this time field % is dependent on operating system. % On Unix it is the last time the file % or the inode was changed. On Windows, -- cgit v1.2.3 From abaefc0452f5b40841562da0f215e7d1ac371f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 2 Dec 2011 20:05:08 +0100 Subject: Let prim_file validate ctime in file_info --- erts/preloaded/src/prim_file.erl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 87fdb3fb8f..507ac9c360 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -779,15 +779,17 @@ write_file_info_int(Port, File, gid=Gid, atime=Atime0, mtime=Mtime0, - ctime=Ctime}, + ctime=Ctime0}, TimeType) -> % Atime and/or Mtime might be undefined % - use localtime() for atime, if atime is undefined % - use atime as mtime if mtime is undefined + % - use mtime as ctime if ctime is undefined Atime = file_info_validate_atime(Atime0, TimeType), Mtime = file_info_validate_mtime(Mtime0, Atime), + Ctime = file_info_validate_ctime(Ctime0, Mtime), drv_command(Port, [?FILE_WRITE_INFO, int_to_int32bytes(Mode), @@ -807,6 +809,9 @@ file_info_validate_atime(undefined, epoch) -> datetime_to_epoch(erlang:universal file_info_validate_mtime(undefined, Atime) -> Atime; file_info_validate_mtime(Mtime, _) -> Mtime. +file_info_validate_ctime(undefined, Mtime) -> Mtime; +file_info_validate_ctime(Ctime, _) -> Ctime. + %% make_link/{2,3} make_link(Old, New) -> -- cgit v1.2.3 From 469815129bd1ce53dc332d2c75142292e0604ef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 6 Dec 2011 01:33:46 +0100 Subject: Add utc <-> seconds conversions bifs --- erts/emulator/beam/bif.c | 64 +++++++++++++++++++++++++++++++++++++++ erts/emulator/beam/bif.tab | 6 ++++ erts/emulator/beam/erl_time_sup.c | 29 ++++++++++++++++++ erts/emulator/beam/sys.h | 3 ++ 4 files changed, 102 insertions(+) diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 26f1b4facb..c3c247fffe 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -3385,6 +3385,70 @@ BIF_RETTYPE universaltime_to_localtime_1(BIF_ALIST_1) BIF_RET(TUPLE2(hp, res1, res2)); } +/* convert calendar:universaltime_to_seconds/1 */ + +BIF_RETTYPE universaltime_to_seconds_1(BIF_ALIST_1) +{ + Sint year, month, day; + Sint hour, minute, second; + + Sint64 seconds = 0; + Eterm *hp; + Uint hsz = 0; + + if (!time_to_parts(BIF_ARG_1, &year, &month, &day, + &hour, &minute, &second)) + BIF_ERROR(BIF_P, BADARG); + + if (!univ_to_seconds(year, month, day, hour, minute, second, &seconds)) { + BIF_ERROR(BIF_P, BADARG); + } + + erts_bld_sint64(NULL, &hsz, seconds); + hp = HAlloc(BIF_P, hsz); + BIF_RET(erts_bld_sint64(&hp, NULL, seconds)); +} + +/* convert calendar:seconds_to_universaltime/1 */ + +BIF_RETTYPE seconds_to_universaltime_1(BIF_ALIST_1) +{ + Sint year, month, day; + Sint hour, minute, second; + Eterm res1, res2; + struct tm t; + Eterm* hp; + + time_t seconds = 0; + + if (is_not_integer(BIF_ARG_1)) { + BIF_ERROR(BIF_P, BADARG); + } + + seconds = (time_t)signed_val(BIF_ARG_1); + + if (!gmtime_r(&seconds, &t)) { + BIF_ERROR(BIF_P, BADARG); + } + + year = t.tm_year + 1900; + month = t.tm_mon + 1; + day = t.tm_hour; + minute = t.tm_min; + second = t.tm_sec; + /* isdst = t.tm_isdst */ + + hp = HAlloc(BIF_P, 4+4+3); + res1 = TUPLE3(hp,make_small(year),make_small(month), + make_small(day)); + hp += 4; + res2 = TUPLE3(hp,make_small(hour),make_small(minute), + make_small(second)); + hp += 4; + BIF_RET(TUPLE2(hp, res1, res2)); +} + + /**********************************************************************/ diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 987008c937..0d6af46aa5 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -806,6 +806,12 @@ bif file:native_name_encoding/0 # bif erlang:check_old_code/1 + +# +# New in R15B +# +bif erlang:universaltime_to_seconds/1 +bif erlang:seconds_to_universaltime/1 # # Obsolete # diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index 695d08ae2d..00a4906caa 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -648,7 +648,36 @@ static time_t gregday(Sint year, Sint month, Sint day) return ndays - 135140; /* 135140 = Jan 1, 1970 */ } +#define SECONDS_PER_MINUTE (60) +#define SECONDS_PER_HOUR (60 * SECONDS_PER_MINUTE) +#define SECONDS_PER_DAY (24 * SECONDS_PER_HOUR) +#define SECONDS_PER_YEAR (86400) + + +int univ_to_seconds(Sint year, Sint month, Sint day, Sint hour, Sint minute, Sint second, Sint64 *time) { + Sint days; + + if (!(IN_RANGE(1600, year, INT_MAX - 1) && + IN_RANGE(1, month, 12) && + IN_RANGE(1, day, (mdays[month] + + (month == 2 + && (year % 4 == 0) + && (year % 100 != 0 || year % 400 == 0)))) && + IN_RANGE(0, hour, 23) && + IN_RANGE(0, minute, 59) && + IN_RANGE(0, second, 59))) { + return 0; + } + + days = gregday(year, month, day); + *time = SECONDS_PER_DAY; + *time *= days; /* don't try overflow it, it hurts */ + *time += SECONDS_PER_HOUR * hour; + *time += SECONDS_PER_MINUTE * minute; + *time += second; + return 1; +} int local_to_univ(Sint *year, Sint *month, Sint *day, diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index d8cd22a177..3abae2243c 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -668,6 +668,9 @@ void get_universaltime(int *year, int *month, int *day, int *hour, int *minute, int *second); int univ_to_local(Sint *year, Sint *month, Sint *day, Sint *hour, Sint *minute, Sint *second); +int univ_to_seconds(Sint year, Sint month, Sint day, + Sint hour, Sint minute, Sint second, + Sint64* seconds); int local_to_univ(Sint *year, Sint *month, Sint *day, Sint *hour, Sint *minute, Sint *second, int isdst); void get_now(Uint*, Uint*, Uint*); -- cgit v1.2.3 From 8f36514229bfaaa6ede8a2daa6aa920686d4251f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 6 Dec 2011 02:55:13 +0100 Subject: Remove OS taint from datetime conversion --- erts/emulator/beam/bif.c | 17 ++++------------- erts/emulator/beam/erl_time_sup.c | 28 +++++++++++++++++++++++++++- erts/emulator/beam/sys.h | 8 ++++++-- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index c3c247fffe..12dc7b3a48 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -3416,28 +3416,19 @@ BIF_RETTYPE seconds_to_universaltime_1(BIF_ALIST_1) Sint year, month, day; Sint hour, minute, second; Eterm res1, res2; - struct tm t; Eterm* hp; - time_t seconds = 0; + Sint64 time = 0; - if (is_not_integer(BIF_ARG_1)) { + if (!term_to_Sint64(BIF_ARG_1, &time)) { BIF_ERROR(BIF_P, BADARG); } - seconds = (time_t)signed_val(BIF_ARG_1); - - if (!gmtime_r(&seconds, &t)) { + if (!seconds_to_univ(time, &year, &month, &day, + &hour, &minute, &second)) { BIF_ERROR(BIF_P, BADARG); } - year = t.tm_year + 1900; - month = t.tm_mon + 1; - day = t.tm_hour; - minute = t.tm_min; - second = t.tm_sec; - /* isdst = t.tm_isdst */ - hp = HAlloc(BIF_P, 4+4+3); res1 = TUPLE3(hp,make_small(year),make_small(month), make_small(day)); diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index 00a4906caa..edf03d06fb 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -651,8 +651,34 @@ static time_t gregday(Sint year, Sint month, Sint day) #define SECONDS_PER_MINUTE (60) #define SECONDS_PER_HOUR (60 * SECONDS_PER_MINUTE) #define SECONDS_PER_DAY (24 * SECONDS_PER_HOUR) -#define SECONDS_PER_YEAR (86400) +int seconds_to_univ(Sint64 time, Sint *year, Sint *month, Sint *day, + Sint *hour, Sint *minute, Sint *second) { + + Sint y,mi; + Sint64 days = time / SECONDS_PER_DAY; + Sint secs = time % SECONDS_PER_DAY; + Sint tmp = secs % SECONDS_PER_HOUR; + + *hour = secs / SECONDS_PER_HOUR; + *minute = tmp / SECONDS_PER_MINUTE; + *second = tmp % SECONDS_PER_MINUTE; + + days += 719468; + y = (10000*days + 14780) / 3652425; /* seriosly? */ + tmp = days - (365 * y + y/4 - y/100 + y/400); + + if (tmp < 0) { + y--; + tmp = days - (365*y + y/4 - y/100 + y/400); + } + mi = (100 * tmp + 52)/3060; + *month = (mi + 2) % 12 + 1; + *year = y + (mi + 2) / 12; + *day = tmp - (mi * 306 + 5)/10 + 1; + + return 1; +} int univ_to_seconds(Sint year, Sint month, Sint day, Sint hour, Sint minute, Sint second, Sint64 *time) { Sint days; diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index 3abae2243c..038c319470 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -666,11 +666,15 @@ void get_localtime(int *year, int *month, int *day, int *hour, int *minute, int *second); void get_universaltime(int *year, int *month, int *day, int *hour, int *minute, int *second); -int univ_to_local(Sint *year, Sint *month, Sint *day, - Sint *hour, Sint *minute, Sint *second); +int seconds_to_univ(Sint64 seconds, + Sint *year, Sint *month, Sint *day, + Sint *hour, Sint *minute, Sint *second); int univ_to_seconds(Sint year, Sint month, Sint day, Sint hour, Sint minute, Sint second, Sint64* seconds); +int univ_to_local( + Sint *year, Sint *month, Sint *day, + Sint *hour, Sint *minute, Sint *second); int local_to_univ(Sint *year, Sint *month, Sint *day, Sint *hour, Sint *minute, Sint *second, int isdst); void get_now(Uint*, Uint*, Uint*); -- cgit v1.2.3 From ec0c88f4ef6ec02f3e3f2af7a6e4920cbdbfdfa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 6 Dec 2011 13:13:37 +0100 Subject: Fix negative time in seconds_to_universaltime/1 --- erts/emulator/beam/erl_time_sup.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index edf03d06fb..54d732000b 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -655,17 +655,24 @@ static time_t gregday(Sint year, Sint month, Sint day) int seconds_to_univ(Sint64 time, Sint *year, Sint *month, Sint *day, Sint *hour, Sint *minute, Sint *second) { - Sint y,mi; - Sint64 days = time / SECONDS_PER_DAY; - Sint secs = time % SECONDS_PER_DAY; - Sint tmp = secs % SECONDS_PER_HOUR; + Sint y,mi; + Sint days = time / SECONDS_PER_DAY; + Sint secs = time % SECONDS_PER_DAY; + Sint tmp; + + if (secs < 0) { + days--; + secs += SECONDS_PER_DAY; + } + + tmp = secs % SECONDS_PER_HOUR; *hour = secs / SECONDS_PER_HOUR; *minute = tmp / SECONDS_PER_MINUTE; *second = tmp % SECONDS_PER_MINUTE; days += 719468; - y = (10000*days + 14780) / 3652425; /* seriosly? */ + y = (10000*((Sint64)days) + 14780) / 3652425; tmp = days - (365 * y + y/4 - y/100 + y/400); if (tmp < 0) { -- cgit v1.2.3 From c27463eecbe3ff8ee3416d7b6f3607d25e1bf01d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 6 Dec 2011 19:43:07 +0100 Subject: Testcase for utc <-> seconds conversion --- erts/emulator/test/time_SUITE.erl | 55 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/erts/emulator/test/time_SUITE.erl b/erts/emulator/test/time_SUITE.erl index bd48a0a7db..b8e2cf51d2 100644 --- a/erts/emulator/test/time_SUITE.erl +++ b/erts/emulator/test/time_SUITE.erl @@ -32,6 +32,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, univ_to_local/1, local_to_univ/1, bad_univ_to_local/1, bad_local_to_univ/1, + univ_to_seconds/1, seconds_to_univ/1, consistency/1, now_unique/1, now_update/1, timestamp/1]). @@ -59,7 +60,9 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [univ_to_local, local_to_univ, local_to_univ_utc, - bad_univ_to_local, bad_local_to_univ, consistency, + bad_univ_to_local, bad_local_to_univ, + univ_to_seconds, seconds_to_univ, + consistency, {group, now}, timestamp]. groups() -> @@ -162,6 +165,30 @@ bad_test_local_to_univ([Local|Rest]) -> bad_test_local_to_univ([]) -> ok. + +%% Test universaltime to seconds conversions +univ_to_seconds(Config) when is_list(Config) -> + test_univ_to_seconds(ok_utc_seconds()). + +test_univ_to_seconds([{Datetime, Seconds}|DSs]) -> + io:format("universaltime = ~p -> seconds = ~p", [Datetime, Seconds]), + Seconds = erlang:universaltime_to_seconds(Datetime), + test_univ_to_seconds(DSs); +test_univ_to_seconds([]) -> + ok. + +%% Test seconds to universaltime conversions +seconds_to_univ(Config) when is_list(Config) -> + test_seconds_to_univ(ok_utc_seconds()). + +test_seconds_to_univ([{Datetime, Seconds}|DSs]) -> + io:format("universaltime = ~p <- seconds = ~p", [Datetime, Seconds]), + Datetime = erlang:seconds_to_universaltime(Seconds), + test_seconds_to_univ(DSs); +test_seconds_to_univ([]) -> + ok. + + %% Test that the the different time functions return %% consistent results. (See the test case for assumptions %% and limitations.) @@ -453,6 +480,32 @@ dst_dates() -> {1998, 06, 3}, {1999, 06, 4}]. +%% exakt utc {date(), time()} which corresponds to the same seconds since 1 jan 1970 +%% negative seconds are ok +%% generated with date --date='1979-05-28 12:30:35 UTC' +%s +ok_utc_seconds() -> [ + { {{1970, 1, 1},{ 0, 0, 0}}, 0 }, + { {{1970, 1, 1},{ 0, 0, 1}}, 1 }, + { {{1969,12,31},{23,59,59}}, -1 }, + { {{1920,12,31},{23,59,59}}, -1546300801 }, + { {{1600,02,19},{15,14,08}}, -11671807552 }, + { {{1979,05,28},{12,30,35}}, 296742635 }, + { {{1999,12,31},{23,59,59}}, 946684799 }, + { {{2000, 1, 1},{ 0, 0, 0}}, 946684800 }, + { {{2000, 1, 1},{ 0, 0, 1}}, 946684801 }, + + { {{2038, 1,19},{03,14,07}}, 2147483647 }, % Sint32 full - 1 + { {{2038, 1,19},{03,14,08}}, 2147483648 }, % Sint32 full + { {{2038, 1,19},{03,14,09}}, 2147483649 }, % Sint32 full + 1 + + { {{2106, 2, 7},{ 6,28,14}}, 4294967294 }, % Uint32 full 0xFFFFFFFF - 1 + { {{2106, 2, 7},{ 6,28,15}}, 4294967295 }, % Uint32 full 0xFFFFFFFF + { {{2106, 2, 7},{ 6,28,16}}, 4294967296 }, % Uint32 full 0xFFFFFFFF + 1 + { {{2012,12, 6},{16,28,08}}, 1354811288 }, + { {{2412,12, 6},{16,28,08}}, 13977592088 } + ]. + + %% The following dates should not be near the end or beginning of %% a month, because they will be used to test when the dates are %% different in UTC and local time. -- cgit v1.2.3 From 58c4c46694982b59dc52d0443c426009c0910e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 6 Dec 2011 20:12:30 +0100 Subject: Catch errors from prim_file:*_file_info We do not want to crash the file server. --- erts/preloaded/src/prim_file.erl | 213 ++++++++------------------------------- 1 file changed, 43 insertions(+), 170 deletions(-) diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 507ac9c360..2567388a6a 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -739,13 +739,17 @@ read_file_info(Port, File, Opts) when is_port(Port) -> read_file_info_int(Port, File, plgv(time, Opts, local)). read_file_info_int(Port, File, TimeType) -> - case drv_command(Port, [?FILE_FSTAT, pathname(File)]) of - {ok, FI} -> {ok, FI#file_info{ - ctime = from_seconds(FI#file_info.ctime, TimeType), - mtime = from_seconds(FI#file_info.mtime, TimeType), - atime = from_seconds(FI#file_info.atime, TimeType) - }}; - Error -> Error + try + case drv_command(Port, [?FILE_FSTAT, pathname(File)]) of + {ok, FI} -> {ok, FI#file_info{ + ctime = from_seconds(FI#file_info.ctime, TimeType), + mtime = from_seconds(FI#file_info.mtime, TimeType), + atime = from_seconds(FI#file_info.atime, TimeType) + }}; + Error -> Error + end + catch + error:_ -> {error, badarg} end. @@ -787,24 +791,28 @@ write_file_info_int(Port, File, % - use atime as mtime if mtime is undefined % - use mtime as ctime if ctime is undefined - Atime = file_info_validate_atime(Atime0, TimeType), - Mtime = file_info_validate_mtime(Mtime0, Atime), - Ctime = file_info_validate_ctime(Ctime0, Mtime), - - drv_command(Port, [?FILE_WRITE_INFO, - int_to_int32bytes(Mode), - int_to_int32bytes(Uid), - int_to_int32bytes(Gid), - int_to_int64bytes(to_seconds(Atime, TimeType)), - int_to_int64bytes(to_seconds(Mtime, TimeType)), - int_to_int64bytes(to_seconds(Ctime, TimeType)), - pathname(File)]). + try + Atime = file_info_validate_atime(Atime0, TimeType), + Mtime = file_info_validate_mtime(Mtime0, Atime), + Ctime = file_info_validate_ctime(Ctime0, Mtime), + + drv_command(Port, [?FILE_WRITE_INFO, + int_to_int32bytes(Mode), + int_to_int32bytes(Uid), + int_to_int32bytes(Gid), + int_to_int64bytes(to_seconds(Atime, TimeType)), + int_to_int64bytes(to_seconds(Mtime, TimeType)), + int_to_int64bytes(to_seconds(Ctime, TimeType)), + pathname(File)]) + catch + error:_ -> {error, badarg} + end. file_info_validate_atime(Atime, _) when Atime =/= undefined -> Atime; file_info_validate_atime(undefined, local) -> erlang:localtime(); file_info_validate_atime(undefined, utc) -> erlang:universaltime(); -file_info_validate_atime(undefined, epoch) -> datetime_to_epoch(erlang:universaltime()). +file_info_validate_atime(undefined, epoch) -> erlang:universaltime_to_seconds((erlang:universaltime())). file_info_validate_mtime(undefined, Atime) -> Atime; file_info_validate_mtime(Mtime, _) -> Mtime. @@ -867,13 +875,17 @@ read_link_info(Port, Link, Opts) when is_port(Port) -> read_link_info_int(Port, Link, TimeType) -> - case drv_command(Port, [?FILE_LSTAT, pathname(Link)]) of - {ok, FI} -> {ok, FI#file_info{ - ctime = from_seconds(FI#file_info.ctime, TimeType), - mtime = from_seconds(FI#file_info.mtime, TimeType), - atime = from_seconds(FI#file_info.atime, TimeType) - }}; - Error -> Error + try + case drv_command(Port, [?FILE_LSTAT, pathname(Link)]) of + {ok, FI} -> {ok, FI#file_info{ + ctime = from_seconds(FI#file_info.ctime, TimeType), + mtime = from_seconds(FI#file_info.mtime, TimeType), + atime = from_seconds(FI#file_info.atime, TimeType) + }}; + Error -> Error + end + catch + error:_ -> {error, badarg} end. %% list_dir/{1,2} @@ -1329,160 +1341,21 @@ plgv(K, [{K, V}|_], _) -> V; plgv(K, [_|KVs], D) -> plgv(K, KVs, D); plgv(_, [], D) -> D. - %% %% We don't actually want this here %% We want to use epochs in all prim but erl_prim_loader makes that tricky %% It is probably needed to redo the whole erl_prim_loader --define(DAYS_FROM_0_TO_1970, 719528). --define(SECONDS_PER_DAY, 86400). --define(SECONDS_PER_HOUR, 3600). --define(SECONDS_PER_MINUTE, 60). --define(DAYS_PER_YEAR, 365). --define(DAYS_PER_LEAP_YEAR, 366). - from_seconds(Seconds, epoch) when is_integer(Seconds) -> Seconds; from_seconds(Seconds, utc) when is_integer(Seconds) -> - epoch_to_datetime(Seconds); + erlang:seconds_to_universaltime(Seconds); from_seconds(Seconds, local) when is_integer(Seconds) -> - erlang:universaltime_to_localtime(epoch_to_datetime(Seconds)). - -epoch_to_datetime(Seconds) -> - gregorian_seconds_to_datetime(Seconds + ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970). + erlang:universaltime_to_localtime(erlang:seconds_to_universaltime(Seconds)). to_seconds(Seconds, epoch) when is_integer(Seconds) -> Seconds; to_seconds({_,_} = Datetime, utc) -> - datetime_to_epoch(Datetime); + erlang:universaltime_to_seconds(Datetime); to_seconds({_,_} = Datetime, local) -> - datetime_to_epoch(erlang:localtime_to_universaltime(Datetime)); -to_seconds(undefined, _) -> - to_seconds(erlang:universaltime(), utc). - -datetime_to_epoch(Datetime) -> - datetime_to_gregorian_seconds(Datetime) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970. - - -%% erl_tar uses this convention (investigate) -%% -%% posix_time(Time) -> -%% EpochStart = {{1970,1,1},{0,0,0}}, -%% {Days,{Hour,Min,Sec}} = calendar:time_difference(EpochStart, Time), -%% 86400*Days + 3600*Hour + 60*Min + Sec. -%% -%% posix_to_erlang_time(Sec) -> -%% OneMillion = 1000000, -%% Time = calendar:now_to_datetime({Sec div OneMillion, Sec rem OneMillion, 0}), -%% erlang:universaltime_to_localtime(Time). - - -% from calendar, slightly modified - -%% calendar:datetime_to_gregorian_seconds/1 - -datetime_to_gregorian_seconds({Date, Time}) -> - ?SECONDS_PER_DAY*date_to_gregorian_days(Date) + time_to_seconds(Time). - - -time_to_seconds({H, M, S}) when is_integer(H), is_integer(M), is_integer(S) -> - H * ?SECONDS_PER_HOUR + M * ?SECONDS_PER_MINUTE + S. - -date_to_gregorian_days({Year, Month, Day}) -> - date_to_gregorian_days(Year, Month, Day). - -date_to_gregorian_days(Year, Month, Day) when is_integer(Day), Day > 0 -> - Last = last_day_of_the_month(Year, Month), - if - Day =< Last -> - dy(Year) + dm(Month) + df(Year, Month) + Day - 1 - end. - -last_day_of_the_month(Y, M) when is_integer(Y), Y >= 0 -> - last_day_of_the_month1(Y, M). - -last_day_of_the_month1(_, 4) -> 30; -last_day_of_the_month1(_, 6) -> 30; -last_day_of_the_month1(_, 9) -> 30; -last_day_of_the_month1(_,11) -> 30; -last_day_of_the_month1(Y, 2) -> - case is_leap_year(Y) of - true -> 29; - _ -> 28 - end; -last_day_of_the_month1(_, M) when is_integer(M), M > 0, M < 13 -> - 31. - -dm(1) -> 0; dm(2) -> 31; dm(3) -> 59; dm(4) -> 90; -dm(5) -> 120; dm(6) -> 151; dm(7) -> 181; dm(8) -> 212; -dm(9) -> 243; dm(10) -> 273; dm(11) -> 304; dm(12) -> 334. - -df(_, Month) when Month < 3 -> 0; -df(Year, _) -> - case is_leap_year(Year) of - true -> 1; - false -> 0 - end. - - - -%% calendar:gregorian_seconds_to_datetime/1 - -gregorian_seconds_to_datetime(Secs) when Secs >= 0 -> - Days = Secs div ?SECONDS_PER_DAY, - Rest = Secs rem ?SECONDS_PER_DAY, - {gregorian_days_to_date(Days), seconds_to_time(Rest)}. - -seconds_to_time(Secs0) when Secs0 >= 0, Secs0 < ?SECONDS_PER_DAY -> - Hour = Secs0 div ?SECONDS_PER_HOUR, - Secs1 = Secs0 rem ?SECONDS_PER_HOUR, - Minute = Secs1 div ?SECONDS_PER_MINUTE, - Second = Secs1 rem ?SECONDS_PER_MINUTE, - {Hour, Minute, Second}. - -gregorian_days_to_date(Days) -> - {Year, DayOfYear} = day_to_year(Days), - {Month, DayOfMonth} = year_day_to_date(Year, DayOfYear), - {Year, Month, DayOfMonth}. - -day_to_year(DayOfEpoch) when DayOfEpoch >= 0 -> - Y0 = DayOfEpoch div ?DAYS_PER_YEAR, - {Y1, D1} = dty(Y0, DayOfEpoch, dy(Y0)), - {Y1, DayOfEpoch - D1}. - -dty(Y, D1, D2) when D1 < D2 -> dty(Y-1, D1, dy(Y-1)); -dty(Y, _D1, D2) -> {Y, D2}. - -dy(Y) when Y =< 0 -> 0; -dy(Y) -> - X = Y - 1, - (X div 4) - (X div 100) + (X div 400) + X*?DAYS_PER_YEAR + ?DAYS_PER_LEAP_YEAR. - -year_day_to_date(Year, DayOfYear) -> - ExtraDay = case is_leap_year(Year) of - true -> 1; - false -> 0 - end, - {Month, Day} = year_day_to_date2(ExtraDay, DayOfYear), - {Month, Day + 1}. - -year_day_to_date2(_, Day) when Day < 31 -> {1, Day}; -year_day_to_date2(E, Day) when 31 =< Day, Day < 59 + E -> {2, Day - 31}; -year_day_to_date2(E, Day) when 59 + E =< Day, Day < 90 + E -> { 3, Day - ( 59 + E)}; -year_day_to_date2(E, Day) when 90 + E =< Day, Day < 120 + E -> { 4, Day - ( 90 + E)}; -year_day_to_date2(E, Day) when 120 + E =< Day, Day < 151 + E -> { 5, Day - (120 + E)}; -year_day_to_date2(E, Day) when 151 + E =< Day, Day < 181 + E -> { 6, Day - (151 + E)}; -year_day_to_date2(E, Day) when 181 + E =< Day, Day < 212 + E -> { 7, Day - (181 + E)}; -year_day_to_date2(E, Day) when 212 + E =< Day, Day < 243 + E -> { 8, Day - (212 + E)}; -year_day_to_date2(E, Day) when 243 + E =< Day, Day < 273 + E -> { 9, Day - (243 + E)}; -year_day_to_date2(E, Day) when 273 + E =< Day, Day < 304 + E -> {10, Day - (273 + E)}; -year_day_to_date2(E, Day) when 304 + E =< Day, Day < 334 + E -> {11, Day - (304 + E)}; -year_day_to_date2(E, Day) when 334 + E =< Day -> {12, Day - (334 + E)}. - -is_leap_year(Y) when is_integer(Y), Y >= 0 -> is_leap_year1(Y). -is_leap_year1(Year) when Year rem 4 =:= 0, Year rem 100 > 0 -> true; -is_leap_year1(Year) when Year rem 400 =:= 0 -> true; -is_leap_year1(_) -> false. - - + erlang:universaltime_to_seconds(erlang:localtime_to_universaltime(Datetime)). -- cgit v1.2.3 From 9158448a508e3e919739dbee0e8e0cad32445941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 7 Dec 2011 15:35:43 +0100 Subject: Remove dead code --- lib/kernel/src/file.erl | 58 ------------------------------------------------- 1 file changed, 58 deletions(-) diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index 80780700ab..7a48d34a09 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -1351,64 +1351,6 @@ fname_join(Dir, Name) -> %%%----------------------------------------------------------------- %%% Utility functions. -%% convert file times. -%% all times from prime_file (and file_server) are in unix epochs - -%% from_epochs -%file_info_time(epoch, {ok, FI} = R) -> R; -%file_info_time(local, {ok, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI}) -> -% {ok, FI#file_info{ -% atime = time_epochs_to_local(Atime), -% ctime = time_epochs_to_local(Ctime), -% mtime = time_epochs_to_local(Mtime) -% } -% }; -%file_info_time(utc, {ok, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI}) -> -% {ok, FI#file_info{ -% atime = time_epochs_to_utc(Atime), -% ctime = time_epochs_to_utc(Ctime), -% mtime = time_epochs_to_utc(Mtime) -% } -% }; -%file_info_time(_, Error) -> Error. -% -%%% from_epochs -%file_info_epochs(epoch, FI) -> FI; -%file_info_epochs(local, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI) -> -% FI#file_info{ -% atime = time_local_to_epochs(Atime), -% ctime = time_local_to_epochs(Ctime), -% mtime = time_local_to_epochs(Mtime) -% }; -%file_info_epochs(utc, {ok, #file_info{ atime = Atime, ctime = Ctime, mtime = Mtime } = FI}) -> -% FI#file_info{ -% atime = time_utc_to_epochs(Atime), -% ctime = time_utc_to_epochs(Ctime), -% mtime = time_utc_to_epochs(Mtime) -% }. -% -% -%-define(DAYS_FROM_0_TO_1970, 719528). -%-define(SECONDS_PER_DAY, 86400). -% -%time_epochs_to_utc(Seconds) when is_integer(Seconds) -> -% calendar:gregorian_seconds_to_datetime(Seconds + ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970). -% -%time_epochs_to_local(Seconds) when is_integer(Seconds) -> -% erlang:universaltime_to_localtime(calendar:gregorian_seconds_to_datetime(Seconds + ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970)). -% -%time_utc_to_epochs({_, _} = Datetime) -> -% calendar:datetime_to_gregorian_seconds(Datetime) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970; -%time_utc_to_epochs(undefined) -> -% time_utc_to_epochs(erlang:universaltime()). -% -% -%time_local_to_epochs({_, _} = Datetime) -> -% calendar:datetime_to_gregorian_seconds(erlang:localtime_to_universaltime(Datetime)) - ?SECONDS_PER_DAY * ?DAYS_FROM_0_TO_1970; -%time_local_to_epochs(undefined) -> -% time_utc_to_epochs(erlang:universaltime()). -% - %% file_name(FileName) %% Generates a flat file name from a deep list of atoms and %% characters (integers). -- cgit v1.2.3 From a37f854be3aaee3786d555a28bb4c8d53384a852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 7 Dec 2011 15:53:21 +0100 Subject: Change options to prim_file:*_file_info/* * 'utc' changed to 'universal' * 'epoch' changed to 'posix' This change conforms to other naming already in OTP, e.g. erlang:universaltime_to_localtime/1. --- erts/preloaded/src/prim_file.erl | 16 ++++++++-------- lib/kernel/test/prim_file_SUITE.erl | 20 ++++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 2567388a6a..e5cb1d5c03 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -810,9 +810,9 @@ write_file_info_int(Port, File, file_info_validate_atime(Atime, _) when Atime =/= undefined -> Atime; -file_info_validate_atime(undefined, local) -> erlang:localtime(); -file_info_validate_atime(undefined, utc) -> erlang:universaltime(); -file_info_validate_atime(undefined, epoch) -> erlang:universaltime_to_seconds((erlang:universaltime())). +file_info_validate_atime(undefined, local) -> erlang:localtime(); +file_info_validate_atime(undefined, universal) -> erlang:universaltime(); +file_info_validate_atime(undefined, posix) -> erlang:universaltime_to_seconds((erlang:universaltime())). file_info_validate_mtime(undefined, Atime) -> Atime; file_info_validate_mtime(Mtime, _) -> Mtime. @@ -1343,19 +1343,19 @@ plgv(_, [], D) -> D. %% %% We don't actually want this here -%% We want to use epochs in all prim but erl_prim_loader makes that tricky +%% We want to use posix time in all prim but erl_prim_loader makes that tricky %% It is probably needed to redo the whole erl_prim_loader -from_seconds(Seconds, epoch) when is_integer(Seconds) -> +from_seconds(Seconds, posix) when is_integer(Seconds) -> Seconds; -from_seconds(Seconds, utc) when is_integer(Seconds) -> +from_seconds(Seconds, universal) when is_integer(Seconds) -> erlang:seconds_to_universaltime(Seconds); from_seconds(Seconds, local) when is_integer(Seconds) -> erlang:universaltime_to_localtime(erlang:seconds_to_universaltime(Seconds)). -to_seconds(Seconds, epoch) when is_integer(Seconds) -> +to_seconds(Seconds, posix) when is_integer(Seconds) -> Seconds; -to_seconds({_,_} = Datetime, utc) -> +to_seconds({_,_} = Datetime, universal) -> erlang:universaltime_to_seconds(Datetime); to_seconds({_,_} = Datetime, local) -> erlang:universaltime_to_seconds(erlang:localtime_to_universaltime(Datetime)). diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index 035817a8bc..e6e0974a95 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -1098,7 +1098,7 @@ file_write_file_info_opts(Config) when is_list(Config) -> ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, FI, Opts]) end, [ {#file_info{ mode=8#600, atime = Time, mtime = Time, ctime = Time}, Opts} || - Opts <- [[{time, epoch}]], + Opts <- [[{time, posix}]], Time <- [ 0,1,-1,100,-100,1000,-1000,10000,-10000 ] ]), @@ -1107,7 +1107,7 @@ file_write_file_info_opts(Config) when is_list(Config) -> ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, FI, Opts]) end, [ {#file_info{ mode=8#400, atime = Time, mtime = Time, ctime = Time}, Opts} || - Opts <- [[{time, utc}],[{time, local}]], + Opts <- [[{time, universal}],[{time, local}]], Time <- [ {{1970,1,1},{0,0,0}}, {{1970,1,1},{0,0,1}}, @@ -1135,7 +1135,7 @@ file_read_file_info_opts(Config) when is_list(Config) -> lists:foreach(fun (Opts) -> {ok,_} = ?PRIM_FILE_call(read_file_info, Handle, [Name, Opts]) - end, [[{time, Type}] || Type <- [local, utc, epoch]]), + end, [[{time, Type}] || Type <- [local, universal, posix]]), ok = ?PRIM_FILE:stop(Handle), test_server:timetrap_cancel(Dog), ok. @@ -1154,14 +1154,14 @@ file_write_read_file_info_opts(Config) when is_list(Config) -> ok = ?PRIM_FILE:write_file(Name, "hello_opts2"), ok = file_write_read_file_info_opts(Handle, Name, {{1989, 04, 28}, {19,30,22}}, [{time, local}]), - ok = file_write_read_file_info_opts(Handle, Name, {{1989, 04, 28}, {19,30,22}}, [{time, utc}]), + ok = file_write_read_file_info_opts(Handle, Name, {{1989, 04, 28}, {19,30,22}}, [{time, universal}]), ok = file_write_read_file_info_opts(Handle, Name, {{1930, 04, 28}, {19,30,22}}, [{time, local}]), - ok = file_write_read_file_info_opts(Handle, Name, {{1930, 04, 28}, {19,30,22}}, [{time, utc}]), - ok = file_write_read_file_info_opts(Handle, Name, 1, [{time, epoch}]), - ok = file_write_read_file_info_opts(Handle, Name, -1, [{time, epoch}]), - ok = file_write_read_file_info_opts(Handle, Name, 300000, [{time, epoch}]), - ok = file_write_read_file_info_opts(Handle, Name, -300000, [{time, epoch}]), - ok = file_write_read_file_info_opts(Handle, Name, 0, [{time, epoch}]), + ok = file_write_read_file_info_opts(Handle, Name, {{1930, 04, 28}, {19,30,22}}, [{time, universal}]), + ok = file_write_read_file_info_opts(Handle, Name, 1, [{time, posix}]), + ok = file_write_read_file_info_opts(Handle, Name, -1, [{time, posix}]), + ok = file_write_read_file_info_opts(Handle, Name, 300000, [{time, posix}]), + ok = file_write_read_file_info_opts(Handle, Name, -300000, [{time, posix}]), + ok = file_write_read_file_info_opts(Handle, Name, 0, [{time, posix}]), ok = ?PRIM_FILE:stop(Handle), test_server:timetrap_cancel(Dog), -- cgit v1.2.3 From 9baa361811a4dd936e73136ea20320423980604b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 7 Dec 2011 16:08:55 +0100 Subject: Change name of bif universaltime_to_seconds/1 * erlang:universaltime_to_seconds/1 changed to erlang:universaltime_to_posixtime/1 * erlang:seconds_to_universaltime/1 changed to erlang:posixtime_to_universaltime/1 Let prim_file.erl reflect these changes. --- erts/emulator/beam/bif.c | 4 ++-- erts/emulator/beam/bif.tab | 4 ++-- erts/emulator/test/time_SUITE.erl | 4 ++-- erts/preloaded/src/prim_file.erl | 10 +++++----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 12dc7b3a48..55f4798892 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -3387,7 +3387,7 @@ BIF_RETTYPE universaltime_to_localtime_1(BIF_ALIST_1) /* convert calendar:universaltime_to_seconds/1 */ -BIF_RETTYPE universaltime_to_seconds_1(BIF_ALIST_1) +BIF_RETTYPE universaltime_to_posixtime_1(BIF_ALIST_1) { Sint year, month, day; Sint hour, minute, second; @@ -3411,7 +3411,7 @@ BIF_RETTYPE universaltime_to_seconds_1(BIF_ALIST_1) /* convert calendar:seconds_to_universaltime/1 */ -BIF_RETTYPE seconds_to_universaltime_1(BIF_ALIST_1) +BIF_RETTYPE posixtime_to_universaltime_1(BIF_ALIST_1) { Sint year, month, day; Sint hour, minute, second; diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 0d6af46aa5..8cc568b16c 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -810,8 +810,8 @@ bif erlang:check_old_code/1 # # New in R15B # -bif erlang:universaltime_to_seconds/1 -bif erlang:seconds_to_universaltime/1 +bif erlang:universaltime_to_posixtime/1 +bif erlang:posixtime_to_universaltime/1 # # Obsolete # diff --git a/erts/emulator/test/time_SUITE.erl b/erts/emulator/test/time_SUITE.erl index b8e2cf51d2..4d12e3449c 100644 --- a/erts/emulator/test/time_SUITE.erl +++ b/erts/emulator/test/time_SUITE.erl @@ -172,7 +172,7 @@ univ_to_seconds(Config) when is_list(Config) -> test_univ_to_seconds([{Datetime, Seconds}|DSs]) -> io:format("universaltime = ~p -> seconds = ~p", [Datetime, Seconds]), - Seconds = erlang:universaltime_to_seconds(Datetime), + Seconds = erlang:universaltime_to_posixtime(Datetime), test_univ_to_seconds(DSs); test_univ_to_seconds([]) -> ok. @@ -183,7 +183,7 @@ seconds_to_univ(Config) when is_list(Config) -> test_seconds_to_univ([{Datetime, Seconds}|DSs]) -> io:format("universaltime = ~p <- seconds = ~p", [Datetime, Seconds]), - Datetime = erlang:seconds_to_universaltime(Seconds), + Datetime = erlang:posixtime_to_universaltime(Seconds), test_seconds_to_univ(DSs); test_seconds_to_univ([]) -> ok. diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index e5cb1d5c03..36cbe329e8 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -812,7 +812,7 @@ write_file_info_int(Port, File, file_info_validate_atime(Atime, _) when Atime =/= undefined -> Atime; file_info_validate_atime(undefined, local) -> erlang:localtime(); file_info_validate_atime(undefined, universal) -> erlang:universaltime(); -file_info_validate_atime(undefined, posix) -> erlang:universaltime_to_seconds((erlang:universaltime())). +file_info_validate_atime(undefined, posix) -> erlang:universaltime_to_posixtime(erlang:universaltime()). file_info_validate_mtime(undefined, Atime) -> Atime; file_info_validate_mtime(Mtime, _) -> Mtime. @@ -1349,13 +1349,13 @@ plgv(_, [], D) -> D. from_seconds(Seconds, posix) when is_integer(Seconds) -> Seconds; from_seconds(Seconds, universal) when is_integer(Seconds) -> - erlang:seconds_to_universaltime(Seconds); + erlang:posixtime_to_universaltime(Seconds); from_seconds(Seconds, local) when is_integer(Seconds) -> - erlang:universaltime_to_localtime(erlang:seconds_to_universaltime(Seconds)). + erlang:universaltime_to_localtime(erlang:posixtime_to_universaltime(Seconds)). to_seconds(Seconds, posix) when is_integer(Seconds) -> Seconds; to_seconds({_,_} = Datetime, universal) -> - erlang:universaltime_to_seconds(Datetime); + erlang:universaltime_to_posixtime(Datetime); to_seconds({_,_} = Datetime, local) -> - erlang:universaltime_to_seconds(erlang:localtime_to_universaltime(Datetime)). + erlang:universaltime_to_posixtime(erlang:localtime_to_universaltime(Datetime)). -- cgit v1.2.3 From 9dd83933601f3c933718874c13d83ca952febc3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 7 Dec 2011 18:52:35 +0100 Subject: Fix compiler warning in unix_efile.c --- erts/emulator/drivers/unix/unix_efile.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 2e6aa15b06..d2d8713c1e 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -900,6 +900,8 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, int efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) { + struct utimbuf tval; + CHECK_PATHLEN(name, errInfo); #ifdef VXWORKS @@ -952,8 +954,6 @@ efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) #endif /* !VXWORKS */ - struct utimbuf tval; - tval.actime = pInfo->accessTime; tval.modtime = pInfo->modifyTime; -- cgit v1.2.3 From 965db6494f80e4c784aa3bb1cd96dd925ce8b284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 7 Dec 2011 23:37:11 +0100 Subject: Document file:*_file_info/2 * file:read_file_info/2 * file:write_file_info/3 Document options and time behavior. --- lib/kernel/doc/src/file.xml | 52 ++++++++++++++++++++++++++++++++++----------- lib/kernel/src/file.erl | 10 ++++++--- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml index c6a1f25dd9..b2e6962be8 100644 --- a/lib/kernel/doc/src/file.xml +++ b/lib/kernel/doc/src/file.xml @@ -149,6 +149,9 @@ + + + @@ -412,7 +415,7 @@ file_info(Filename) -> {ok, FileInfo} | {error, Reason} Get information about a file (deprecated) -

This function is obsolete. Use read_file_info/1 +

This function is obsolete. Use read_file_info/1,2 instead.

@@ -1188,6 +1191,7 @@ + Get information about a file

Retrieves information about a file. Returns @@ -1199,6 +1203,20 @@ from which the function is called:

-include_lib("kernel/include/file.hrl"). +

The time type returned in atime, mtime and ctime + is dependent on the time type set in Opts :: {time, Type}. + Type local will return local time, universal will + return universal time and posix will return seconds since + or before unix time epoch which is 1970-01-01 00:00 UTC. + Default is {time, local}. +

+ +

+ Since file times is stored in posix time on most OS it is + faster to query file information with the posix option. +

+
+

The record file_info contains the following fields.

size = integer() @@ -1213,15 +1231,15 @@

The current system access to the file.

- atime = date_time() + atime = date_time() | integer() -

The last (local) time the file was read.

+

The last time the file was read.

- mtime = date_time() + mtime = date_time() | integer() -

The last (local) time the file was written.

+

The last time the file was written.

- ctime = date_time() + ctime = date_time() | integer()

The interpretation of this time field depends on the operating system. On Unix, it is the last time @@ -1377,9 +1395,11 @@ + Get information about a link or file -

This function works like read_file_info/1, except that +

This function works like + read_file_info/1,2 except that if Name is a symbolic link, information about the link will be returned in the file_info record and the type field of the record will be set to @@ -1690,6 +1710,7 @@ + Change information about a file

Change file information. Returns ok if successful, @@ -1700,18 +1721,25 @@ from which the function is called:

-include_lib("kernel/include/file.hrl"). +

The time type set in atime, mtime and ctime + is dependent on the time type set in Opts :: {time, Type}. + Type local will interpret the time set as local, universal will + interpret it as universal time and posix must be seconds since + or before unix time epoch which is 1970-01-01 00:00 UTC. + Default is {time, local}. +

The following fields are used from the record, if they are given.

- atime = date_time() + atime = date_time() | integer() -

The last (local) time the file was read.

+

The last time the file was read.

- mtime = date_time() + mtime = date_time() | integer() -

The last (local) time the file was written.

+

The last time the file was written.

- ctime = date_time() + ctime = date_time() | integer()

On Unix, any value give for this field will be ignored (the "ctime" for the file will be set to the current diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index 7a48d34a09..b253b3e901 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -109,6 +109,10 @@ -type posix_file_advise() :: 'normal' | 'sequential' | 'random' | 'no_reuse' | 'will_need' | 'dont_need'. -type sendfile_option() :: {chunk_size, non_neg_integer()}. +-type file_info_option() :: {'time', 'local'} | {'time', 'universal'} + | {'time', 'posix'}. + + %%%----------------------------------------------------------------- %%% General functions @@ -218,7 +222,7 @@ read_file_info(Name) -> -spec read_file_info(Filename, Opts) -> {ok, FileInfo} | {error, Reason} when Filename :: name(), - Opts :: list(), + Opts :: [file_info_option()], FileInfo :: file_info(), Reason :: posix() | badarg. @@ -240,7 +244,7 @@ read_link_info(Name) -> -spec read_link_info(Name, Opts) -> {ok, FileInfo} | {error, Reason} when Name :: name(), - Opts :: list(), + Opts :: [file_info_option()], FileInfo :: file_info(), Reason :: posix() | badarg. @@ -266,7 +270,7 @@ write_file_info(Name, Info = #file_info{}) -> -spec write_file_info(Filename, FileInfo, Opts) -> ok | {error, Reason} when Filename :: name(), - Opts :: list(), + Opts :: [file_info_option()], FileInfo :: file_info(), Reason :: posix() | badarg. -- cgit v1.2.3 From 46eb4359b05b220861453a869dc734480ec045a6 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Tue, 6 Dec 2011 19:07:40 +0100 Subject: Emulate localtime, gmtime and mktime to enable negative time_t --- erts/emulator/beam/erl_time_sup.c | 9 +- erts/emulator/sys/win32/erl_win_sys.h | 5 + erts/emulator/sys/win32/sys_time.c | 286 ++++++++++++++++++++++++++++++++-- 3 files changed, 285 insertions(+), 15 deletions(-) diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index 54d732000b..53a2ba456b 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -491,7 +491,7 @@ get_time(int *hour, int *minute, int *second) the_clock = time((time_t *)0); #ifdef HAVE_LOCALTIME_R - localtime_r(&the_clock, (tm = &tmbuf)); + tm = localtime_r(&the_clock, &tmbuf); #else tm = localtime(&the_clock); #endif @@ -513,7 +513,7 @@ get_date(int *year, int *month, int *day) the_clock = time((time_t *)0); #ifdef HAVE_LOCALTIME_R - localtime_r(&the_clock, (tm = &tmbuf)); + tm = localtime_r(&the_clock, &tmbuf); #else tm = localtime(&the_clock); #endif @@ -762,10 +762,13 @@ local_to_univ(Sint *year, Sint *month, Sint *day, } } #ifdef HAVE_GMTIME_R - gmtime_r(&the_clock, (tm = &tmbuf)); + tm = gmtime_r(&the_clock, &tmbuf); #else tm = gmtime(&the_clock); #endif + if (!tm) { + return 0; + } *year = tm->tm_year + 1900; *month = tm->tm_mon +1; *day = tm->tm_mday; diff --git a/erts/emulator/sys/win32/erl_win_sys.h b/erts/emulator/sys/win32/erl_win_sys.h index 4ed0b94e2d..ac5639b701 100644 --- a/erts/emulator/sys/win32/erl_win_sys.h +++ b/erts/emulator/sys/win32/erl_win_sys.h @@ -118,9 +118,14 @@ int erts_check_io_debug(void); #define SYS_CLOCK_RESOLUTION 1 struct tm *sys_localtime_r(time_t *epochs, struct tm *ptm); +struct tm *sys_gmtime_r(time_t *epochs, struct tm *ptm); +time_t sys_mktime( struct tm *ptm); #define localtime_r sys_localtime_r #define HAVE_LOCALTIME_R 1 +#define gmtime_r sys_gmtime_r +#define HAVE_GMTIME_R +#define mktime sys_mktime typedef struct { long tv_sec; diff --git a/erts/emulator/sys/win32/sys_time.c b/erts/emulator/sys/win32/sys_time.c index af903aacfd..6362c1a06d 100644 --- a/erts/emulator/sys/win32/sys_time.c +++ b/erts/emulator/sys/win32/sys_time.c @@ -35,49 +35,222 @@ /******************* Routines for time measurement *********************/ #define EPOCH_JULIAN_DIFF LL_LITERAL(11644473600) -#define TICKS_PER_SECOND (10000000LL) +#define TICKS_PER_SECOND LL_LITERAL(10000000) +#define SECONDS_PER_DAY LL_LITERAL(86400) + +#define ULI_TO_FILETIME(ft,ull) \ + do { \ + (ft).dwLowDateTime = (ull).LowPart; \ + (ft).dwHighDateTime = (ull).HighPart; \ + } while (0) + +#define FILETIME_TO_ULI(ull,ft) \ + do { \ + (ull).LowPart = (ft).dwLowDateTime; \ + (ull).HighPart = (ft).dwHighDateTime; \ + } while (0) + #define EPOCH_TO_FILETIME(ft, epoch) \ do { \ ULARGE_INTEGER ull; \ ull.QuadPart = (((epoch) + EPOCH_JULIAN_DIFF) * TICKS_PER_SECOND); \ - (ft).dwLowDateTime = ull.LowPart; \ - (ft).dwHighDateTime = ull.HighPart; \ + ULI_TO_FILETIME(ft,ull); \ } while(0) #define FILETIME_TO_EPOCH(epoch, ft) \ do { \ ULARGE_INTEGER ull; \ - ull.LowPart = (ft).dwLowDateTime; \ - ull.HighPart = (ft).dwHighDateTime; \ + FILETIME_TO_ULI(ull,ft); \ (epoch) = ((ull.QuadPart / TICKS_PER_SECOND) - EPOCH_JULIAN_DIFF); \ } while(0) static SysHrTime wrap = 0; static DWORD last_tick_count = 0; +/* Getting timezone information is a heavy operation, so we want to do this + only once */ + +static TIME_ZONE_INFORMATION static_tzi; +static int have_static_tzi = 0; + +static int days_in_month[2][13] = { + {0,31,28,31,30,31,30,31,31,30,31,30,31}, + {0,31,29,31,30,31,30,31,31,30,31,30,31}}; + int sys_init_time(void) { + if(GetTimeZoneInformation(&static_tzi) && + static_tzi.StandardDate.wMonth != 0 && + static_tzi.DaylightDate.wMonth != 0) { + have_static_tzi = 1; + } return 1; } -struct tm * sys_localtime_r(time_t *epochs, struct tm *ptm) +/* Returns a switchtimes for DST as UTC filetimes given data from a + TIME_ZONE_INFORMATION, see sys_localtime_r for usage. */ +static void +get_dst_switchtime(DWORD year, + SYSTEMTIME dstinfo, LONG bias, + FILETIME *utc_switchtime) +{ + DWORD occu; + DWORD weekday,wday_1st; + DWORD day, days_in; + FILETIME tmp,tmp2; + ULARGE_INTEGER ull; + int leap_year = 0; + if (dstinfo.wYear != 0) { + /* A year specific transition, in which case the data in the structure + is already properly set for a specific year. Compare year + with parameter and see if they correspond, in that case generate a + filetime directly, otherwise set the filetime to 0 */ + if (year != dstinfo.wYear) { + utc_switchtime->dwLowDateTime = utc_switchtime->dwHighDateTime = 0; + return; + } + } else { + occu = dstinfo.wDay; + weekday = dstinfo.wDayOfWeek; + + dstinfo.wDayOfWeek = 0; + dstinfo.wDay = 1; + dstinfo.wYear = year; + + SystemTimeToFileTime(&dstinfo,&tmp); + ull.LowPart = tmp.dwLowDateTime; + ull.HighPart = tmp.dwHighDateTime; + + ull.QuadPart /= (TICKS_PER_SECOND*SECONDS_PER_DAY); /* Julian Day */ + wday_1st = (DWORD) ((ull.QuadPart + LL_LITERAL(1)) % LL_LITERAL(7)); + day = (weekday >= wday_1st) ? + weekday - wday_1st + 1 : + weekday - wday_1st + 8; + --occu; + if (((dstinfo.wYear % 4) == 0 && (dstinfo.wYear % 100) > 0) || + ((dstinfo.wYear % 400) == 0)) { + leap_year = 1; + } + days_in = days_in_month[leap_year][dstinfo.wMonth]; + while (occu > 0 && (day + 7 <= days_in)) { + --occu; + day += 7; + } + dstinfo.wDay = day; + } + SystemTimeToFileTime(&dstinfo,&tmp); + /* correct for bias */ + ull.LowPart = tmp.dwLowDateTime; + ull.HighPart = tmp.dwHighDateTime; + ull.QuadPart += (((LONGLONG) bias) * LL_LITERAL(60) * TICKS_PER_SECOND); + utc_switchtime->dwLowDateTime = ull.LowPart; + utc_switchtime->dwHighDateTime = ull.HighPart; + return; +} + +/* This function gives approximately the correct year from a FILETIME + Around the actual new year, it may return the wrong value, but that's OK + as DST never switches around new year. */ +static DWORD +approx_year(FILETIME ft) +{ + ULARGE_INTEGER ull; + FILETIME_TO_ULI(ull,ft); + ull.QuadPart /= LL_LITERAL(1000); + ull.QuadPart /= SECONDS_PER_DAY; + ull.QuadPart /= LL_LITERAL(3652425); + ull.QuadPart += 1601; + return (DWORD) ull.QuadPart; +} + +struct tm * +sys_localtime_r(time_t *epochs, struct tm *ptm) { FILETIME ft,lft; SYSTEMTIME st; if ((((*epochs) + EPOCH_JULIAN_DIFF) * TICKS_PER_SECOND) < 0LL) { + fprintf(stderr,"1\r\n"); fflush(stderr); return NULL; } EPOCH_TO_FILETIME(ft,*epochs); + ptm->tm_isdst = 0; + if (have_static_tzi) { + FILETIME dst_start, dst_stop; + ULARGE_INTEGER ull; + DWORD year = approx_year(ft); + get_dst_switchtime(year,static_tzi.DaylightDate, + static_tzi.Bias+static_tzi.StandardBias,&dst_start); + get_dst_switchtime(year,static_tzi.StandardDate, + static_tzi.Bias+static_tzi.StandardBias+ + static_tzi.DaylightBias, + &dst_stop); + FILETIME_TO_ULI(ull,ft); + + if (CompareFileTime(&ft,&dst_start) >= 0 && + CompareFileTime(&ft,&dst_stop) < 0) { + ull.QuadPart -= + ((LONGLONG) static_tzi.Bias+static_tzi.StandardBias+ + static_tzi.DaylightBias) * + LL_LITERAL(60) * TICKS_PER_SECOND; + ptm->tm_isdst = 1; + } else { + ull.QuadPart -= + ((LONGLONG) static_tzi.Bias+static_tzi.StandardBias) + * LL_LITERAL(60) * TICKS_PER_SECOND; + } + ULI_TO_FILETIME(ft,ull); + } else { + if (!FileTimeToLocalFileTime(&ft,&lft)) { + return NULL; + } + ft = lft; + } + + if (!FileTimeToSystemTime(&ft,&st)) { + return NULL; + } + + ptm->tm_year = (int) st.wYear - 1900; + ptm->tm_mon = (int) st.wMonth - 1; + ptm->tm_mday = (int) st.wDay; + ptm->tm_hour = (int) st.wHour; + ptm->tm_min = (int) st.wMinute; + ptm->tm_sec = (int) st.wSecond; + ptm->tm_wday = (int) st.wDayOfWeek; + { + int yday = ptm->tm_mday - 1; + int m = ptm->tm_mon; + int leap_year = 0; + if (((st.wYear % 4) == 0 && (st.wYear % 100) > 0) || + ((st.wYear % 400) == 0)) { + leap_year = 1; + } + while (m > 0) { + yday +=days_in_month[leap_year][m]; + --m; + } + ptm->tm_yday = yday; + } + return ptm; +} + +struct tm * +sys_gmtime_r(time_t *epochs, struct tm *ptm) +{ + FILETIME ft; + SYSTEMTIME st; - if (!FileTimeToLocalFileTime(&ft,&lft)) { + if ((((*epochs) + EPOCH_JULIAN_DIFF) * TICKS_PER_SECOND) < 0LL) { return NULL; } - if (!FileTimeToSystemTime(&lft,&st)) { + EPOCH_TO_FILETIME(ft,*epochs); + + if (!FileTimeToSystemTime(&ft,&st)) { return NULL; } @@ -87,22 +260,111 @@ struct tm * sys_localtime_r(time_t *epochs, struct tm *ptm) ptm->tm_hour = (int) st.wHour; ptm->tm_min = (int) st.wMinute; ptm->tm_sec = (int) st.wSecond; + ptm->tm_wday = (int) st.wDayOfWeek; + ptm->tm_isdst = 0; + { + int yday = ptm->tm_mday - 1; + int m = ptm->tm_mon; + int leap_year = 0; + if (((st.wYear % 4) == 0 && (st.wYear % 100) > 0) || + ((st.wYear % 400) == 0)) { + leap_year = 1; + } + while (m > 0) { + yday +=days_in_month[leap_year][m]; + --m; + } + ptm->tm_yday = yday; + } return ptm; } +time_t +sys_mktime(struct tm *ptm) +{ + FILETIME ft; + SYSTEMTIME st; + int dst = 0; + time_t epochs; + + memset(&st,0,sizeof(st)); + /* Convert relevant parts of truct tm to SYSTEMTIME */ + st.wYear = (USHORT) (ptm->tm_year + 1900); + st.wMonth = (USHORT) (ptm->tm_mon + 1); + st.wDay = (USHORT) ptm->tm_mday; + st.wHour = (USHORT) ptm->tm_hour; + st.wMinute = (USHORT) ptm->tm_min; + st.wSecond = (USHORT) ptm->tm_sec; + + SystemTimeToFileTime(&st,&ft); + + /* ft is now some kind of local file time, but it may be wrong depending + on what is in the tm_dst field. We need to manually convert it to + UTC before turning it into epochs */ + + if (have_static_tzi) { + FILETIME dst_start, dst_stop; + ULARGE_INTEGER ull_start,ull_stop,ull_ft; + + FILETIME_TO_ULI(ull_ft,ft); + + /* Correct everything except DST */ + ull_ft.QuadPart += (static_tzi.Bias+static_tzi.StandardBias) + * LL_LITERAL(60) * TICKS_PER_SECOND; + + /* Determine if DST is active */ + if (ptm->tm_isdst >= 0) { + dst = ptm->tm_isdst; + } else if (static_tzi.DaylightDate.wMonth != 0){ + /* This is how windows mktime does it, meaning it does not + take nonexisting local times into account */ + get_dst_switchtime(st.wYear,static_tzi.DaylightDate, + static_tzi.Bias+static_tzi.StandardBias, + &dst_start); + get_dst_switchtime(st.wYear,static_tzi.StandardDate, + static_tzi.Bias+static_tzi.StandardBias+ + static_tzi.DaylightBias, + &dst_stop); + FILETIME_TO_ULI(ull_start,dst_start); + FILETIME_TO_ULI(ull_stop,dst_stop); + if ((ull_ft.QuadPart >= ull_start.QuadPart) && + (ull_ft.QuadPart < ull_stop.QuadPart)) { + /* We are in DST */ + dst = 1; + } + } + /* Correct for DST */ + if (dst) { + ull_ft.QuadPart += static_tzi.DaylightBias * + LL_LITERAL(60) * TICKS_PER_SECOND; + } + epochs = ((ull_ft.QuadPart / TICKS_PER_SECOND) - EPOCH_JULIAN_DIFF); + } else { + /* No DST, life is easy... */ + FILETIME lft; + LocalFileTimeToFileTime(&ft,&lft); + FILETIME_TO_EPOCH(epochs,lft); + } + /* Normalize the struct tm */ + sys_localtime_r(&epochs,ptm); + return epochs; +} + void sys_gettimeofday(SysTimeval *tv) { SYSTEMTIME t; FILETIME ft; - LONGLONG lft; + ULARGE_INTEGER ull; GetSystemTime(&t); SystemTimeToFileTime(&t, &ft); - memcpy(&lft, &ft, sizeof(lft)); - tv->tv_usec = (long) ((lft / LL_LITERAL(10)) % LL_LITERAL(1000000)); - tv->tv_sec = (long) ((lft / LL_LITERAL(10000000)) - EPOCH_JULIAN_DIFF); + FILETIME_TO_ULI(ull,ft); + tv->tv_usec = (long) ((ull.QuadPart / LL_LITERAL(10)) % + LL_LITERAL(1000000)); + tv->tv_sec = (long) ((ull.QuadPart / LL_LITERAL(10000000)) - + EPOCH_JULIAN_DIFF); } SysHrTime -- cgit v1.2.3 From dc244a2b3a9be89700f3b15013ea1f41a4016347 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Wed, 7 Dec 2011 16:20:58 +0100 Subject: Set lower limit of years handled to 1601 --- erts/emulator/beam/erl_time_sup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index 53a2ba456b..ab491036f2 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -583,7 +583,7 @@ static const int mdays[14] = {0, 31, 28, 31, 30, 31, 30, (((y) % 100) != 0)) || \ (((y) % 400) == 0)) -#define BASEYEAR INT_MIN +#define BASEYEAR 1601 /* A more "clever" mktime * return 1, if successful -- cgit v1.2.3 From 5b51d7679230e0dff82bc7250ab59126742e283a Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Wed, 7 Dec 2011 17:35:18 +0100 Subject: Set BASEYEAR to 1902 --- erts/emulator/beam/erl_time_sup.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index ab491036f2..ed906f210d 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -583,7 +583,9 @@ static const int mdays[14] = {0, 31, 28, 31, 30, 31, 30, (((y) % 100) != 0)) || \ (((y) % 400) == 0)) -#define BASEYEAR 1601 +/* This is the earliest year we are sure to be able to handle + on all platforms w/o problems */ +#define BASEYEAR 1902 /* A more "clever" mktime * return 1, if successful @@ -629,8 +631,8 @@ static int erl_mktime(time_t *c, struct tm *tm) { */ static time_t gregday(Sint year, Sint month, Sint day) { - int long ndays = 0; - int gyear, pyear, m; + Sint ndays = 0; + Sint gyear, pyear, m; /* number of days in previous years */ gyear = year - 1600; @@ -645,7 +647,7 @@ static time_t gregday(Sint year, Sint month, Sint day) if (is_leap_year(year) && (month > 2)) ndays++; ndays += day - 1; - return ndays - 135140; /* 135140 = Jan 1, 1970 */ + return (time_t) (ndays - 135140); /* 135140 = Jan 1, 1970 */ } #define SECONDS_PER_MINUTE (60) -- cgit v1.2.3 From ddd1a16402a95c521f5aaa1a51624c65d28309bd Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Wed, 7 Dec 2011 17:40:02 +0100 Subject: Add types for posixtime_to_universaltime and the reverse --- lib/hipe/cerl/erl_bif_types.erl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 6f0141b0ca..cee399e861 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -1321,6 +1321,9 @@ type(erlang, resume_process, 1, Xs) -> fun (_) -> t_any() end); %% TODO: overapproximation -- fix this type(erlang, round, 1, Xs) -> strict(arg_types(erlang, round, 1), Xs, fun (_) -> t_integer() end); +type(erlang, posixtime_to_universaltime, 1, Xs) -> + strict(arg_types(erlang, posixtime_to_universaltime, 1), Xs, + fun(_) -> t_tuple([t_date(), t_time()]) end); type(erlang, self, 0, _) -> t_pid(); type(erlang, send, 2, Xs) -> type(erlang, '!', 2, Xs); % alias type(erlang, send, 3, Xs) -> @@ -1717,6 +1720,9 @@ type(erlang, universaltime, 0, _) -> type(erlang, universaltime_to_localtime, 1, Xs) -> strict(arg_types(erlang, universaltime_to_localtime, 1), Xs, fun ([T]) -> T end); +type(erlang, universaltime_to_posixtime, 1, Xs) -> + strict(arg_types(erlang, universaltime_to_posixtime,1), Xs, + fun(_) -> t_integer() end); type(erlang, unlink, 1, Xs) -> strict(arg_types(erlang, unlink, 1), Xs, fun (_) -> t_atom('true') end); type(erlang, unregister, 1, Xs) -> @@ -3776,6 +3782,8 @@ arg_types(erlang, resume_process, 1) -> [t_pid()]; % intended for debugging only arg_types(erlang, round, 1) -> [t_number()]; +arg_types(erlang, posixtime_to_universaltime, 1) -> + [t_integer()]; arg_types(erlang, self, 0) -> []; arg_types(erlang, send, 2) -> @@ -3942,6 +3950,8 @@ arg_types(erlang, universaltime, 0) -> []; arg_types(erlang, universaltime_to_localtime, 1) -> [t_tuple([t_date(), t_time()])]; +arg_types(erlang, universaltime_to_posixtime, 1) -> + [t_tuple([t_date(), t_time()])]; arg_types(erlang, unlink, 1) -> [t_sup(t_pid(), t_port())]; arg_types(erlang, unregister, 1) -> -- cgit v1.2.3 From 474be24e335b03d64eb389993e110f07fe0d3f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 8 Dec 2011 14:27:05 +0100 Subject: Update prim_file.beam and prim_zip.beam --- erts/preloaded/ebin/prim_file.beam | Bin 34780 -> 37716 bytes erts/preloaded/ebin/prim_zip.beam | Bin 22532 -> 22436 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam index ad1d7031a3..bc5631f3dd 100644 Binary files a/erts/preloaded/ebin/prim_file.beam and b/erts/preloaded/ebin/prim_file.beam differ diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam index 7e1a5d1fdb..b6c49d5c0c 100644 Binary files a/erts/preloaded/ebin/prim_zip.beam and b/erts/preloaded/ebin/prim_zip.beam differ -- cgit v1.2.3 From 4091bb7785c488f65f686f2f92de1ef420d7c81b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 8 Dec 2011 14:51:56 +0100 Subject: Remove time_t specific test in prim_file_SUITE Remove time_t = Sint64 | Uint32 testcase only. The year 2040 does not exist on Sint32. --- lib/kernel/test/prim_file_SUITE.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index e6e0974a95..ccf26ee034 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -1102,6 +1102,8 @@ file_write_file_info_opts(Config) when is_list(Config) -> Time <- [ 0,1,-1,100,-100,1000,-1000,10000,-10000 ] ]), + % REM: determine date range dependent on time_t = Uint32 | Sint32 | Sint64 + % Determine time_t on os:type()? lists:foreach(fun ({FI, Opts}) -> ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, FI, Opts]) @@ -1114,7 +1116,7 @@ file_write_file_info_opts(Config) when is_list(Config) -> {{1969,12,31},{23,59,59}}, {{1908,2,3},{23,59,59}}, {{2012,2,3},{23,59,59}}, - {{2040,2,3},{23,59,59}}, + {{2037,2,3},{23,59,59}}, erlang:localtime() ]]), ok = ?PRIM_FILE:stop(Handle), -- cgit v1.2.3