aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/preloaded/src/prim_file.erl236
-rw-r--r--lib/kernel/src/file.erl135
-rw-r--r--lib/kernel/src/file_server.erl9
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};