1
%% ``The contents of this file are subject to the Erlang Public License,
2
%% Version 1.1, (the "License"); you may not use this file except in
3
%% compliance with the License. You should have received a copy of the
4
%% Erlang Public License along with this software. If not, it can be
5
%% retrieved via the world wide web at http://www.erlang.org/.
7
%% Software distributed under the License is distributed on an "AS IS"
8
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
%% the License for the specific language governing rights and limitations
12
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
13
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
14
%% AB. All Rights Reserved.''
20
%% Interface module to the file driver.
24
%%% Interface towards a single file's contents. Uses ?FD_DRV.
26
%% Generic file contents operations
27
-export([open/2, close/1, sync/1, position/2, truncate/1,
28
write/2, pwrite/2, pwrite/3, read/2, pread/2, pread/3, copy/3]).
30
%% Specialized file operations
31
-export([open/1, open/3]).
32
-export([read_file/1, read_file/2, write_file/2]).
33
-export([ipread_s32bu_p32bu/3]).
37
%%% Interface towards file system and metadata. Uses ?DRV.
39
%% Takes an optional port (opens a ?DRV port per default) as first argument.
40
-export([get_cwd/0, get_cwd/1, get_cwd/2,
44
make_dir/1, make_dir/2,
46
read_file_info/1, read_file_info/2,
48
write_file_info/2, write_file_info/3,
49
make_link/2, make_link/3,
50
make_symlink/2, make_symlink/3,
51
read_link/1, read_link/2,
52
read_link_info/1, read_link_info/2,
53
list_dir/1, list_dir/2]).
54
%% How to start and stop the ?DRV port.
55
-export([start/0, stop/1]).
58
-export([open_int/4, open_mode/1, open_mode/4]).
60
%%%-----------------------------------------------------------------
61
%%% Includes and defines
66
-define(FD_DRV, efile).
68
-define(LARGEFILESIZE, (1 bsl 63)).
71
-define(FILE_OPEN, 1).
72
-define(FILE_READ, 2).
73
-define(FILE_LSEEK, 3).
74
-define(FILE_WRITE, 4).
75
-define(FILE_FSTAT, 5).
77
-define(FILE_READDIR, 7).
78
-define(FILE_CHDIR, 8).
79
-define(FILE_FSYNC, 9).
80
-define(FILE_MKDIR, 10).
81
-define(FILE_DELETE, 11).
82
-define(FILE_RENAME, 12).
83
-define(FILE_RMDIR, 13).
84
-define(FILE_TRUNCATE, 14).
85
-define(FILE_READ_FILE, 15).
86
-define(FILE_WRITE_INFO, 16).
87
-define(FILE_LSTAT, 19).
88
-define(FILE_READLINK, 20).
89
-define(FILE_LINK, 21).
90
-define(FILE_SYMLINK, 22).
91
-define(FILE_CLOSE, 23).
92
-define(FILE_PWRITEV, 24).
93
-define(FILE_PREADV, 25).
94
-define(FILE_SETOPT, 26).
95
-define(FILE_IPREAD, 27).
96
-define(FILE_ALTNAME, 28).
99
-define(FILE_RESP_OK, 0).
100
-define(FILE_RESP_ERROR, 1).
101
-define(FILE_RESP_DATA, 2).
102
-define(FILE_RESP_NUMBER, 3).
103
-define(FILE_RESP_INFO, 4).
104
-define(FILE_RESP_NUMERR, 5).
105
-define(FILE_RESP_LDATA, 6).
106
-define(FILE_RESP_N2DATA, 7).
107
-define(FILE_RESP_EOF, 8).
109
%% Open modes for the driver's open function.
110
-define(EFILE_MODE_READ, 1).
111
-define(EFILE_MODE_WRITE, 2).
112
-define(EFILE_MODE_READ_WRITE, 3).
113
-define(EFILE_MODE_APPEND, 4).
114
-define(EFILE_COMPRESSED, 8).
116
%% Use this mask to get just the mode bits to be passed to the driver.
117
-define(EFILE_MODE_MASK, 15).
119
%% Seek modes for the driver's seek function.
120
-define(EFILE_SEEK_SET, 0).
121
-define(EFILE_SEEK_CUR, 1).
122
-define(EFILE_SEEK_END, 2).
125
-define(FILE_OPT_DELAYED_WRITE, 0).
126
-define(FILE_OPT_READ_AHEAD, 1).
129
-define(IPREAD_S32BU_P32BU, 0).
133
%%%-----------------------------------------------------------------
134
%%% Functions operating on a file through a handle. ?FD_DRV.
136
%%% Generic file contents operations.
138
%%% Supposed to be called by applications through module file.
141
%% Opens a file using the driver port Port. Returns {error, Reason}
142
%% | {ok, FileDescriptor}
143
open(Port, File, ModeList) when is_port(Port),
146
case open_mode(ModeList) of
147
{Mode, _Portopts, _Setopts} ->
148
open_int(Port, File, Mode, []);
155
%% Opens a file. Returns {error, Reason} | {ok, FileDescriptor}.
156
open(File, ModeList) when is_list(File), is_list(ModeList) ->
157
case open_mode(ModeList) of
158
{Mode, Portopts, Setopts} ->
159
open_int({?FD_DRV, Portopts}, File, Mode, Setopts);
166
%% Opens a port that can be used for open/3 or read_file/2.
167
%% Returns {ok, Port} | {error, Reason}.
168
open(Portopts) when is_list(Portopts) ->
169
% drv_open(?FD_DRV, Portopts).
170
case drv_open(?FD_DRV, Portopts) of
171
{error, _} = Error ->
179
open_int({Driver, Portopts}, File, Mode, Setopts) ->
180
case drv_open(Driver, Portopts) of
182
open_int(Port, File, Mode, Setopts);
183
{error, _} = Error ->
186
open_int(Port, File, Mode, Setopts) ->
187
M = Mode band ?EFILE_MODE_MASK,
188
case drv_command(Port, [<<?FILE_OPEN, M:32>>, File, 0]) of
190
open_int_setopts(Port, Number, Setopts);
196
open_int_setopts(Port, Number, []) ->
197
{ok, #file_descriptor{module = ?MODULE, data = {Port, Number}}};
198
open_int_setopts(Port, Number, [Cmd | Tail]) ->
199
case drv_command(Port, Cmd) of
201
open_int_setopts(Port, Number, Tail);
211
close(#file_descriptor{module = ?MODULE, data = {Port, _}}) ->
212
case drv_command(Port, <<?FILE_CLOSE>>) of
218
%% Closes a port opened with open/1.
219
close(Port) when is_port(Port) ->
224
%% Returns {error, Reason} | ok.
225
write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes) ->
226
case drv_command(Port, [?FILE_WRITE,Bytes]) of
233
%% Returns ok | {error, {WrittenCount, Reason}}
234
pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, L)
236
pwrite_int(Port, L, 0, [], []).
238
pwrite_int(_, [], 0, [], []) ->
240
pwrite_int(Port, [], N, Spec, Data) ->
241
Header = list_to_binary([<<?FILE_PWRITEV, N:32>> | reverse(Spec)]),
242
case drv_command_raw(Port, [Header | reverse(Data)]) of
248
pwrite_int(Port, [{Offs, Bytes} | T], N, Spec, Data)
249
when is_integer(Offs) ->
251
-(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE ->
252
pwrite_int(Port, T, N, Spec, Data, Offs, Bytes);
256
pwrite_int(_, [_|_], _N, _Spec, _Data) ->
259
pwrite_int(Port, T, N, Spec, Data, Offs, Bin)
260
when is_binary(Bin) ->
261
Size = byte_size(Bin),
262
pwrite_int(Port, T, N+1,
263
[<<Offs:64/signed, Size:64>> | Spec],
265
pwrite_int(Port, T, N, Spec, Data, Offs, Bytes) ->
266
try list_to_binary(Bytes) of
268
pwrite_int(Port, T, N, Spec, Data, Offs, Bin)
276
%% Returns {error, Reason} | ok.
277
pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes)
278
when is_integer(Offs) ->
280
-(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE ->
281
case pwrite_int(Port, [], 0, [], [], Offs, Bytes) of
282
{error, {_, Reason}} ->
290
pwrite(#file_descriptor{module = ?MODULE}, _, _) ->
295
%% Returns {error, Reason} | ok.
296
sync(#file_descriptor{module = ?MODULE, data = {Port, _}}) ->
297
drv_command(Port, [?FILE_FSYNC]).
299
%% Returns {ok, Data} | eof | {error, Reason}.
300
read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size)
301
when is_integer(Size), 0 =< Size ->
303
Size < ?LARGEFILESIZE ->
304
case drv_command(Port, <<?FILE_READ, Size:64>>) of
305
{ok, {0, _Data}} when Size =/= 0 ->
307
{ok, {_Size, Data}} ->
310
%% Garbage collecting here might help if
311
%% the current processes has some old binaries left.
312
erlang:garbage_collect(),
313
case drv_command(Port, <<?FILE_READ, Size:64>>) of
314
{ok, {0, _Data}} when Size =/= 0 ->
316
{ok, {_Size, Data}} ->
328
%% Returns {ok, [Data|eof, ...]} | {error, Reason}
329
pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, L)
331
pread_int(Port, L, 0, []).
333
pread_int(_, [], 0, []) ->
335
pread_int(Port, [], N, Spec) ->
336
drv_command(Port, [<<?FILE_PREADV, 0:32, N:32>> | reverse(Spec)]);
337
pread_int(Port, [{Offs, Size} | T], N, Spec)
338
when is_integer(Offs), is_integer(Size), 0 =< Size ->
340
-(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE,
341
Size < ?LARGEFILESIZE ->
342
pread_int(Port, T, N+1, [<<Offs:64/signed, Size:64>> | Spec]);
346
pread_int(_, [_|_], _N, _Spec) ->
351
%% Returns {ok, Data} | eof | {error, Reason}.
352
pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size)
353
when is_integer(Offs), is_integer(Size), 0 =< Size ->
355
-(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE,
356
Size < ?LARGEFILESIZE ->
357
case drv_command(Port,
358
<<?FILE_PREADV, 0:32, 1:32,
359
Offs:64/signed, Size:64>>) of
370
pread(#file_descriptor{module = ?MODULE, data = {_, _}}, _, _) ->
375
%% Returns {ok, Position} | {error, Reason}.
376
position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At) ->
377
case lseek_position(At) of
379
when -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE ->
380
drv_command(Port, <<?FILE_LSEEK, Offs:64/signed, Whence:32>>);
387
%% Returns {error, Reaseon} | ok.
388
truncate(#file_descriptor{module = ?MODULE, data = {Port, _}}) ->
389
drv_command(Port, <<?FILE_TRUNCATE>>).
393
%% Returns {error, Reason} | {ok, BytesCopied}
394
copy(#file_descriptor{module = ?MODULE} = Source,
395
#file_descriptor{module = ?MODULE} = Dest,
397
when is_integer(Length), Length >= 0;
399
%% XXX Should be moved down to the driver for optimization.
400
file:copy_opened(Source, Dest, Length).
404
ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE,
405
data = {_, _}} = Handle,
407
Infinity) when is_atom(Infinity) ->
408
ipread_s32bu_p32bu(Handle, Offs, (1 bsl 31)-1);
409
ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {Port, _}},
412
when is_integer(Offs), is_integer(MaxSize) ->
414
-(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE,
415
0 =< MaxSize, MaxSize < (1 bsl 31) ->
416
drv_command(Port, <<?FILE_IPREAD, ?IPREAD_S32BU_P32BU,
417
Offs:64, MaxSize:32>>);
421
ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {_, _}},
428
%% Returns {ok, Contents} | {error, Reason}
430
case drv_open(?FD_DRV, [binary]) of
432
Result = read_file(Port, File),
435
{error, _} = Error ->
439
%% Takes a Port opened with open/1.
440
read_file(Port, File) when is_port(Port) ->
441
Cmd = [?FILE_READ_FILE | File],
442
case drv_command(Port, Cmd) of
444
%% It could possibly help to do a
445
%% garbage collection here,
446
%% if the file server has some references
447
%% to binaries read earlier.
448
erlang:garbage_collect(),
449
drv_command(Port, Cmd);
456
%% Returns {error, Reason} | ok.
457
write_file(File, Bin) ->
458
case open(File, [binary, write]) of
460
Result = write(Handle, Bin),
469
%%%-----------------------------------------------------------------
470
%%% Functions operating on files without handle to the file. ?DRV.
472
%%% Supposed to be called by applications through module file.
476
%% Returns {ok, Port}, the Port should be used as first argument in all
477
%% the following functions. Returns {error, Reason} upon failure.
479
try erlang:open_port({spawn, ?DRV}, []) of
487
stop(Port) when is_port(Port) ->
488
try erlang:port_close(Port) of
498
%%% The following functions take an optional Port as first argument.
499
%%% If the port is not supplied, a temporary one is opened and then
500
%%% closed after the request has been performed.
509
get_cwd(Port) when is_port(Port) ->
510
get_cwd_int(Port, 0);
513
get_cwd([Letter, $: | _]) when $a =< Letter, Letter =< $z ->
514
get_cwd_int(Letter - $a + 1);
515
get_cwd([Letter, $: | _]) when $A =< Letter, Letter =< $Z ->
516
get_cwd_int(Letter - $A + 1);
522
get_cwd(Port, []) when is_port(Port) ->
523
get_cwd_int(Port, 0);
524
get_cwd(Port, [Letter, $: | _])
525
when is_port(Port), $a =< Letter, Letter =< $z ->
526
get_cwd_int(Port, Letter - $a + 1);
527
get_cwd(Port, [Letter, $: | _])
528
when is_port(Port), $A =< Letter, Letter =< $Z ->
529
get_cwd_int(Port, Letter - $A + 1);
530
get_cwd(Port, [_|_]) when is_port(Port) ->
535
get_cwd_int(Drive) ->
536
get_cwd_int({?DRV, []}, Drive).
538
get_cwd_int(Port, Drive) ->
539
drv_command(Port, <<?FILE_PWD, Drive>>).
546
set_cwd_int({?DRV, []}, Dir).
548
set_cwd(Port, Dir) when is_port(Port) ->
549
set_cwd_int(Port, Dir).
551
set_cwd_int(Port, Dir0) ->
556
%% chdir on vxworks doesn't support
558
%% must call get_cwd from here and use
560
%% absname/1 uses file:get_cwd ...
561
case get_cwd_int(Port, 0) of
563
filename:absname(Dir0, AbsPath);
570
%% Dir is now either a string or an EXIT tuple.
571
%% An EXIT tuple will fail in the following catch.
572
drv_command(Port, [?FILE_CHDIR, Dir, 0]).
579
delete_int({?DRV, []}, File).
581
delete(Port, File) when is_port(Port) ->
582
delete_int(Port, File).
584
delete_int(Port, File) ->
585
drv_command(Port, [?FILE_DELETE, File, 0]).
592
rename_int({?DRV, []}, From, To).
594
rename(Port, From, To) when is_port(Port) ->
595
rename_int(Port, From, To).
597
rename_int(Port, From, To) ->
598
drv_command(Port, [?FILE_RENAME, From, 0, To, 0]).
605
make_dir_int({?DRV, []}, Dir).
607
make_dir(Port, Dir) when is_port(Port) ->
608
make_dir_int(Port, Dir).
610
make_dir_int(Port, Dir) ->
611
drv_command(Port, [?FILE_MKDIR, Dir, 0]).
618
del_dir_int({?DRV, []}, Dir).
620
del_dir(Port, Dir) when is_port(Port) ->
621
del_dir_int(Port, Dir).
623
del_dir_int(Port, Dir) ->
624
drv_command(Port, [?FILE_RMDIR, Dir, 0]).
628
%% read_file_info/{1,2}
630
read_file_info(File) ->
631
read_file_info_int({?DRV, []}, File).
633
read_file_info(Port, File) when is_port(Port) ->
634
read_file_info_int(Port, File).
636
read_file_info_int(Port, File) ->
637
drv_command(Port, [?FILE_FSTAT, File, 0]).
642
altname_int({?DRV, []}, File).
644
altname(Port, File) when is_port(Port) ->
645
altname_int(Port, File).
647
altname_int(Port, File) ->
648
drv_command(Port, [?FILE_ALTNAME, File, 0]).
651
%% write_file_info/{2,3}
653
write_file_info(File, Info) ->
654
write_file_info_int({?DRV, []}, File, Info).
656
write_file_info(Port, File, Info) when is_port(Port) ->
657
write_file_info_int(Port, File, Info).
659
write_file_info_int(Port,
661
#file_info{mode=Mode,
668
case {Atime0, Mtime0} of
669
{undefined, Mtime0} -> {erlang:localtime(), Mtime0};
670
{Atime0, undefined} -> {Atime0, Atime0};
673
drv_command(Port, [?FILE_WRITE_INFO,
677
date_to_bytes(Atime),
678
date_to_bytes(Mtime),
679
date_to_bytes(Ctime),
686
make_link(Old, New) ->
687
make_link_int({?DRV, []}, Old, New).
689
make_link(Port, Old, New) when is_port(Port) ->
690
make_link_int(Port, Old, New).
692
make_link_int(Port, Old, New) ->
693
drv_command(Port, [?FILE_LINK, Old, 0, New, 0]).
697
%% make_symlink/{2,3}
699
make_symlink(Old, New) ->
700
make_symlink_int({?DRV, []}, Old, New).
702
make_symlink(Port, Old, New) when is_port(Port) ->
703
make_symlink_int(Port, Old, New).
705
make_symlink_int(Port, Old, New) ->
706
drv_command(Port, [?FILE_SYMLINK, Old, 0, New, 0]).
713
read_link_int({?DRV, []}, Link).
715
read_link(Port, Link) when is_port(Port) ->
716
read_link_int(Port, Link).
718
read_link_int(Port, Link) ->
719
drv_command(Port, [?FILE_READLINK, Link, 0]).
723
%% read_link_info/{2,3}
725
read_link_info(Link) ->
726
read_link_info_int({?DRV, []}, Link).
728
read_link_info(Port, Link) when is_port(Port) ->
729
read_link_info_int(Port, Link).
731
read_link_info_int(Port, Link) ->
732
drv_command(Port, [?FILE_LSTAT, Link, 0]).
739
list_dir_int({?DRV, []}, Dir).
741
list_dir(Port, Dir) when is_port(Port) ->
742
list_dir_int(Port, Dir).
744
list_dir_int(Port, Dir) ->
745
drv_command(Port, [?FILE_READDIR, Dir, 0], []).
749
%%%-----------------------------------------------------------------
750
%%% Functions to communicate with the driver
754
%% Opens a driver port and converts any problems into {error, emfile}.
755
%% Returns {ok, Port} when succesful.
757
drv_open(Driver, Portopts) ->
758
try erlang:open_port({spawn, Driver}, Portopts) of
768
%% Closes a port in a safe way. Returns ok.
771
try erlang:port_close(Port) catch error:_ -> ok end,
772
receive %% Ugly workaround in case the caller==owner traps exits
773
{'EXIT', Port, _Reason} ->
781
%% Issues a command to a port and gets the response.
782
%% If Port is {Driver, Portopts} a port is first opened and
783
%% then closed after the result has been received.
784
%% Returns {ok, Result} or {error, Reason}.
786
drv_command_raw(Port, Command) ->
787
drv_command(Port, Command, false, undefined).
789
drv_command(Port, Command) ->
790
drv_command(Port, Command, undefined).
792
drv_command(Port, Command, R) when is_binary(Command) ->
793
drv_command(Port, Command, true, R);
794
drv_command(Port, Command, R) ->
795
try erlang:iolist_to_binary(Command) of
797
drv_command(Port, Bin, true, R)
803
drv_command(Port, Command, Validated, R) when is_port(Port) ->
804
try erlang:port_command(Port, Command) of
806
drv_get_response(Port, R)
808
%% If the Command is valid, knowing that the port is a port,
809
%% a badarg error must mean it is a dead port, that is:
810
%% a currently invalid filehandle, -> einval, not badarg.
811
error:badarg when Validated ->
814
try erlang:iolist_size(Command) of
824
drv_command({Driver, Portopts}, Command, Validated, R) ->
825
case drv_open(Driver, Portopts) of
827
Result = drv_command(Port, Command, Validated, R),
836
%% Receives the response from a driver port.
837
%% Returns: {ok, ListOrBinary}|{error, Reason}
839
drv_get_response(Port, R) when is_list(R) ->
840
case drv_get_response(Port) of
844
drv_get_response(Port, [Name|R]);
848
drv_get_response(Port, _) ->
849
drv_get_response(Port).
851
drv_get_response(Port) ->
852
erlang:bump_reductions(100),
854
{Port, {data, [Response|Rest] = Data}} ->
855
try translate_response(Response, Rest)
858
{error, {bad_response_from_port, Data,
859
{Reason, erlang:get_stacktrace()}}}
861
{'EXIT', Port, Reason} ->
862
{error, {port_died, Reason}}
866
%%%-----------------------------------------------------------------
867
%%% Utility functions.
871
%% Converts a list of mode atoms into an mode word for the driver.
872
%% Returns {Mode, Portopts, Setopts} where Portopts is a list of
873
%% options for erlang:open_port/2 and Setopts is a list of
874
%% setopt commands to send to the port, or error Reason upon failure.
876
open_mode(List) when is_list(List) ->
877
case open_mode(List, 0, [], []) of
878
{Mode, Portopts, Setopts} when Mode band
879
(?EFILE_MODE_READ bor ?EFILE_MODE_WRITE)
881
{Mode bor ?EFILE_MODE_READ, Portopts, Setopts};
886
open_mode([raw|Rest], Mode, Portopts, Setopts) ->
887
open_mode(Rest, Mode, Portopts, Setopts);
888
open_mode([read|Rest], Mode, Portopts, Setopts) ->
889
open_mode(Rest, Mode bor ?EFILE_MODE_READ, Portopts, Setopts);
890
open_mode([write|Rest], Mode, Portopts, Setopts) ->
891
open_mode(Rest, Mode bor ?EFILE_MODE_WRITE, Portopts, Setopts);
892
open_mode([binary|Rest], Mode, Portopts, Setopts) ->
893
open_mode(Rest, Mode, [binary | Portopts], Setopts);
894
open_mode([compressed|Rest], Mode, Portopts, Setopts) ->
895
open_mode(Rest, Mode bor ?EFILE_COMPRESSED, Portopts, Setopts);
896
open_mode([append|Rest], Mode, Portopts, Setopts) ->
897
open_mode(Rest, Mode bor ?EFILE_MODE_APPEND bor ?EFILE_MODE_WRITE,
899
open_mode([delayed_write|Rest], Mode, Portopts, Setopts) ->
900
open_mode([{delayed_write, 64*1024, 2000}|Rest], Mode,
902
open_mode([{delayed_write, Size, Delay}|Rest], Mode, Portopts, Setopts)
903
when is_integer(Size), 0 =< Size, is_integer(Delay), 0 =< Delay ->
905
Size < ?LARGEFILESIZE, Delay < 1 bsl 64 ->
906
open_mode(Rest, Mode, Portopts,
907
[<<?FILE_SETOPT, ?FILE_OPT_DELAYED_WRITE,
913
open_mode([read_ahead|Rest], Mode, Portopts, Setopts) ->
914
open_mode([{read_ahead, 64*1024}|Rest], Mode, Portopts, Setopts);
915
open_mode([{read_ahead, Size}|Rest], Mode, Portopts, Setopts)
916
when is_integer(Size), 0 =< Size ->
918
Size < ?LARGEFILESIZE ->
919
open_mode(Rest, Mode, Portopts,
920
[<<?FILE_SETOPT, ?FILE_OPT_READ_AHEAD,
921
Size:64>> | Setopts]);
925
open_mode([], Mode, Portopts, Setopts) ->
926
{Mode, reverse(Portopts), reverse(Setopts)};
927
open_mode(_, _Mode, _Portopts, _Setopts) ->
932
%% Converts a position tuple {bof, X} | {cur, X} | {eof, X} into
933
%% {Offset, OriginCode} for the driver.
934
%% Returns badarg upon failure.
937
when is_integer(Pos) ->
938
lseek_position({bof, Pos});
939
lseek_position(bof) ->
940
lseek_position({bof, 0});
941
lseek_position(cur) ->
942
lseek_position({cur, 0});
943
lseek_position(eof) ->
944
lseek_position({eof, 0});
945
lseek_position({bof, Offset})
946
when is_integer(Offset) ->
947
{Offset, ?EFILE_SEEK_SET};
948
lseek_position({cur, Offset})
949
when is_integer(Offset) ->
950
{Offset, ?EFILE_SEEK_CUR};
951
lseek_position({eof, Offset})
952
when is_integer(Offset) ->
953
{Offset, ?EFILE_SEEK_END};
959
%% Translates the response from the driver into
960
%% {ok, Result} or {error, Reason}.
962
translate_response(?FILE_RESP_OK, []) ->
964
translate_response(?FILE_RESP_OK, Data) ->
966
translate_response(?FILE_RESP_ERROR, List) when is_list(List) ->
967
{error, list_to_atom(List)};
968
translate_response(?FILE_RESP_NUMBER, List) ->
969
{N, []} = get_uint64(List),
971
translate_response(?FILE_RESP_DATA, List) ->
972
{N, Data} = get_uint64(List),
974
translate_response(?FILE_RESP_INFO, List) when is_list(List) ->
975
{ok, transform_info_ints(get_uint32s(List))};
976
translate_response(?FILE_RESP_NUMERR, L0) ->
977
{N, L1} = get_uint64(L0),
978
{error, {N, list_to_atom(L1)}};
979
translate_response(?FILE_RESP_LDATA, List) ->
980
{ok, transform_ldata(List)};
981
translate_response(?FILE_RESP_N2DATA,
982
<<Offset:64, 0:64, Size:64>>) ->
983
{ok, {Size, Offset, eof}};
984
translate_response(?FILE_RESP_N2DATA,
985
[<<Offset:64, 0:64, Size:64>> | <<>>]) ->
986
{ok, {Size, Offset, eof}};
987
translate_response(?FILE_RESP_N2DATA = X,
988
[<<_:64, 0:64, _:64>> | _] = Data) ->
989
{error, {bad_response_from_port, [X | Data]}};
990
translate_response(?FILE_RESP_N2DATA = X,
991
[<<_:64, _:64, _:64>> | <<>>] = Data) ->
992
{error, {bad_response_from_port, [X | Data]}};
993
translate_response(?FILE_RESP_N2DATA,
994
[<<Offset:64, _ReadSize:64, Size:64>> | D]) ->
995
{ok, {Size, Offset, D}};
996
translate_response(?FILE_RESP_N2DATA = X, L0) when is_list(L0) ->
997
{Offset, L1} = get_uint64(L0),
998
{ReadSize, L2} = get_uint64(L1),
999
{Size, L3} = get_uint64(L2),
1000
case {ReadSize, L3} of
1002
{ok, {Size, Offset, eof}};
1004
{error, {bad_response_from_port, [X | L0]}};
1006
{error, {bad_response_from_port, [X | L0]}};
1008
{ok, {Size, Offset, L3}}
1010
translate_response(?FILE_RESP_EOF, []) ->
1012
translate_response(X, Data) ->
1013
{error, {bad_response_from_port, [X | Data]}}.
1015
transform_info_ints(Ints) ->
1016
[HighSize, LowSize, Type|Tail0] = Ints,
1017
Size = HighSize * 16#100000000 + LowSize,
1018
[Ay, Am, Ad, Ah, Ami, As|Tail1] = Tail0,
1019
[My, Mm, Md, Mh, Mmi, Ms|Tail2] = Tail1,
1020
[Cy, Cm, Cd, Ch, Cmi, Cs|Tail3] = Tail2,
1021
[Mode, Links, Major, Minor, Inode, Uid, Gid, Access] = Tail3,
1024
type = file_type(Type),
1025
access = file_access(Access),
1026
atime = {{Ay, Am, Ad}, {Ah, Ami, As}},
1027
mtime = {{My, Mm, Md}, {Mh, Mmi, Ms}},
1028
ctime = {{Cy, Cm, Cd}, {Ch, Cmi, Cs}},
1031
major_device = Major,
1032
minor_device = Minor,
1037
file_type(1) -> device;
1038
file_type(2) -> directory;
1039
file_type(3) -> regular;
1040
file_type(4) -> symlink;
1041
file_type(_) -> other.
1043
file_access(0) -> none;
1044
file_access(1) -> write;
1045
file_access(2) -> read;
1046
file_access(3) -> read_write.
1048
int_to_bytes(Int) when is_integer(Int) ->
1050
int_to_bytes(undefined) ->
1053
date_to_bytes(undefined) ->
1054
<<-1:32, -1:32, -1:32, -1:32, -1:32, -1:32>>;
1055
date_to_bytes({{Y, Mon, D}, {H, Min, S}}) ->
1056
<<Y:32, Mon:32, D:32, H:32, Min:32, S:32>>.
1058
% uint64([[X1, X2, X3, X4] = Y1 | [X5, X6, X7, X8] = Y2]) ->
1059
% (uint32(Y1) bsl 32) bor uint32(Y2).
1061
% uint64(X1, X2, X3, X4, X5, X6, X7, X8) ->
1062
% (uint32(X1, X2, X3, X4) bsl 32) bor uint32(X5, X6, X7, X8).
1064
% uint32([X1,X2,X3,X4]) ->
1065
% (X1 bsl 24) bor (X2 bsl 16) bor (X3 bsl 8) bor X4.
1067
uint32(X1,X2,X3,X4) ->
1068
(X1 bsl 24) bor (X2 bsl 16) bor (X3 bsl 8) bor X4.
1071
{X1, L1} = get_uint32(L0),
1072
{X2, L2} = get_uint32(L1),
1073
{(X1 bsl 32) bor X2, L2}.
1075
get_uint32([X1,X2,X3,X4|List]) ->
1076
{(((((X1 bsl 8) bor X2) bsl 8) bor X3) bsl 8) bor X4, List}.
1078
get_uint32s([X1,X2,X3,X4|Tail]) ->
1079
[uint32(X1,X2,X3,X4) | get_uint32s(Tail)];
1080
get_uint32s([]) -> [].
1085
transform_ldata(<<0:32, 0:32>>) ->
1087
transform_ldata([<<0:32, N:32, Sizes/binary>> | Datas]) ->
1088
transform_ldata(N, Sizes, Datas, []);
1090
transform_ldata([_,_,_,_,_,_,_,_|_] = L0) ->
1091
{0, L1} = get_uint32(L0),
1092
{N, L2} = get_uint32(L1),
1093
transform_ldata(N, L2, []).
1096
transform_ldata(0, List, Sizes) ->
1097
transform_ldata(0, List, reverse(Sizes), []);
1098
transform_ldata(N, L0, Sizes) ->
1099
{Size, L1} = get_uint64(L0),
1100
transform_ldata(N-1, L1, [Size | Sizes]).
1103
transform_ldata(1, <<0:64>>, <<>>, R) ->
1105
transform_ldata(1, <<Size:64>>, Data, R)
1106
when byte_size(Data) =:= Size ->
1108
transform_ldata(N, <<0:64, Sizes/binary>>, [<<>> | Datas], R) ->
1109
transform_ldata(N-1, Sizes, Datas, [eof | R]);
1110
transform_ldata(N, <<Size:64, Sizes/binary>>, [Data | Datas], R)
1111
when byte_size(Data) =:= Size ->
1112
transform_ldata(N-1, Sizes, Datas, [Data | R]);
1114
transform_ldata(0, [], [], R) ->
1116
transform_ldata(0, List, [0 | Sizes], R) ->
1117
transform_ldata(0, List, Sizes, [eof | R]);
1118
transform_ldata(0, List, [Size | Sizes], R) ->
1119
{Front, Rear} = lists_split(List, Size),
1120
transform_ldata(0, Rear, Sizes, [Front | R]).
1124
lists_split(List, 0) when is_list(List) ->
1126
lists_split(List, N) when is_list(List), is_integer(N), N < 0 ->
1127
erlang:error(badarg, [List, N]);
1128
lists_split(List, N) when is_list(List), is_integer(N) ->
1129
case lists_split(List, N, []) of
1130
premature_end_of_list ->
1131
erlang:error(badarg, [List, N]);
1136
lists_split(List, 0, Rev) ->
1137
{reverse(Rev), List};
1138
lists_split([], _, _) ->
1139
premature_end_of_list;
1140
lists_split([Hd | Tl], N, Rev) ->
1141
lists_split(Tl, N-1, [Hd | Rev]).
1143
%% We KNOW that lists:reverse/2 is a BIF.
1145
reverse(X) -> lists:reverse(X, []).
1146
reverse(L, T) -> lists:reverse(L, T).