1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(file).
21
22%% Interface module for the file server and the file io servers.
23
24
25
26%%% External exports
27
28-export([format_error/1]).
29%% File system and metadata.
30-export([get_cwd/0, get_cwd/1, set_cwd/1, delete/1, rename/2,
31	 make_dir/1, del_dir/1, del_dir_r/1, list_dir/1, list_dir_all/1,
32	 read_file_info/1, read_file_info/2,
33	 write_file_info/2, write_file_info/3,
34	 altname/1,
35	 read_link_info/1, read_link_info/2,
36	 read_link/1, read_link_all/1,
37	 make_link/2, make_symlink/2,
38	 read_file/1, write_file/2, write_file/3]).
39%% Specialized
40-export([ipread_s32bu_p32bu/3]).
41%% Generic file contents.
42-export([open/2, close/1, advise/4, allocate/3,
43	 read/2, write/2,
44	 pread/2, pread/3, pwrite/2, pwrite/3,
45	 read_line/1,
46	 position/2, truncate/1, datasync/1, sync/1,
47	 copy/2, copy/3]).
48%% High level operations
49-export([consult/1, path_consult/2]).
50-export([eval/1, eval/2, path_eval/2, path_eval/3, path_open/3]).
51-export([script/1, script/2, path_script/2, path_script/3]).
52-export([change_owner/2, change_owner/3, change_group/2,
53	 change_mode/2, change_time/2, change_time/3]).
54
55-export([pid2name/1]).
56
57%% Sendfile functions
58-export([sendfile/2,sendfile/5]).
59
60%%% Obsolete exported functions
61
62-export([raw_read_file_info/1, raw_write_file_info/2]).
63
64%% Internal export to prim_file and ram_file until they implement
65%% an efficient copy themselves.
66-export([copy_opened/3]).
67
68-export([ipread_s32bu_p32bu_int/3]).
69
70%% Types that can be used from other modules -- alphabetically ordered.
71-export_type([date_time/0, fd/0, file_info/0, filename/0, filename_all/0,
72              io_device/0, mode/0, name/0, name_all/0, posix/0]).
73
74%%% Includes and defines
75-include("file_int.hrl").
76
77-define(FILE_IO_SERVER_TABLE, file_io_servers).
78
79-define(FILE_SERVER, file_server_2).   % Registered name
80-define(PRIM_FILE, prim_file).         % Module
81-define(RAM_FILE, ram_file).           % Module
82
83%% data types
84-type filename()  :: string().
85-type filename_all() :: string() | binary().
86-type file_info() :: #file_info{}.
87-type fd()        :: #file_descriptor{}.
88-type io_device() :: pid() | fd().
89-type location()  :: integer() | {'bof', Offset :: integer()}
90                   | {'cur', Offset :: integer()}
91		   | {'eof', Offset :: integer()} | 'bof' | 'cur' | 'eof'.
92-type mode()      :: 'read' | 'write' | 'append'
93                   | 'exclusive' | 'raw' | 'binary'
94		   | {'delayed_write',
95                      Size :: non_neg_integer(),
96                      Delay :: non_neg_integer()}
97		   | 'delayed_write' | {'read_ahead', Size :: pos_integer()}
98		   | 'read_ahead' | 'compressed'
99		   | {'encoding', unicode:encoding()}
100		   | sync.
101-type deep_list() :: [char() | atom() | deep_list()].
102-type name()      :: string() | atom() | deep_list().
103-type name_all()  :: string() | atom() | deep_list() | (RawFilename :: binary()).
104-type posix() ::
105        'eacces' | 'eagain' |
106        'ebadf' | 'ebadmsg' | 'ebusy' |
107        'edeadlk' | 'edeadlock' | 'edquot' |
108        'eexist' |
109        'efault' | 'efbig' | 'eftype' |
110        'eintr' | 'einval' | 'eio' | 'eisdir' |
111        'eloop' |
112        'emfile' | 'emlink' | 'emultihop' |
113        'enametoolong' | 'enfile' |
114        'enobufs' | 'enodev' | 'enolck' | 'enolink' | 'enoent' |
115        'enomem' | 'enospc' | 'enosr' | 'enostr' | 'enosys' |
116        'enotblk' | 'enotdir' | 'enotsup' | 'enxio' |
117        'eopnotsupp' | 'eoverflow' |
118        'eperm' | 'epipe' |
119        'erange' | 'erofs' |
120        'espipe'  | 'esrch'  | 'estale' |
121        'etxtbsy' |
122        'exdev'.
123-type date_time() :: calendar:datetime().
124-type posix_file_advise() :: 'normal' | 'sequential' | 'random'
125                           | 'no_reuse' | 'will_need' | 'dont_need'.
126-type sendfile_option() :: {chunk_size, non_neg_integer()}
127			 | {use_threads, boolean()}.
128-type file_info_option() :: {'time', 'local'} | {'time', 'universal'}
129			  | {'time', 'posix'} | raw.
130%%% BIFs
131
132-export([native_name_encoding/0]).
133
134-spec native_name_encoding() -> latin1 | utf8.
135
136native_name_encoding() ->
137    erlang:nif_error(undef).
138
139%%% End of BIFs
140
141
142%%%-----------------------------------------------------------------
143%%% General functions
144
145-spec format_error(Reason) -> Chars when
146      Reason :: posix() | badarg | terminated | system_limit
147              | {Line :: integer(), Mod :: module(), Term :: term()},
148      Chars :: string().
149
150format_error({_Line, ?MODULE, undefined_script}) ->
151    "no value returned from script";
152format_error({Line, ?MODULE, {Class, Reason, Stacktrace}}) ->
153    io_lib:format("~w: evaluation failed with reason ~w:~w and stacktrace ~w",
154                  [Line, Class, Reason, Stacktrace]);
155format_error({Line, ?MODULE, {Reason, Stacktrace}}) ->
156    io_lib:format("~w: evaluation failed with reason ~w and stacktrace ~w",
157                  [Line, Reason, Stacktrace]);
158format_error({Line, Mod, Reason}) ->
159    io_lib:format("~w: ~ts", [Line, Mod:format_error(Reason)]);
160format_error(badarg) ->
161    "bad argument";
162format_error(system_limit) ->
163    "a system limit was hit, probably not enough ports";
164format_error(terminated) ->
165    "the file server process is terminated";
166format_error(ErrorId) ->
167    erl_posix_msg:message(ErrorId).
168
169-spec pid2name(Pid) -> {ok, Filename} | undefined when
170      Filename :: filename_all(),
171      Pid :: pid().
172
173pid2name(Pid) when is_pid(Pid) ->
174    case whereis(?FILE_SERVER) of
175	undefined ->
176	    undefined;
177	_ ->
178	    case ets:lookup(?FILE_IO_SERVER_TABLE, Pid) of
179		[{_, Name} | _] ->
180		    {ok, Name};
181		_ ->
182		    undefined
183	    end
184    end.
185
186%%%-----------------------------------------------------------------
187%%% File server functions.
188%%% Functions that do not operate on a single open file.
189%%% Stateless.
190-spec get_cwd() -> {ok, Dir} | {error, Reason} when
191      Dir :: filename(),
192      Reason :: posix().
193
194get_cwd() ->
195    call(get_cwd, []).
196
197-spec get_cwd(Drive) -> {ok, Dir} | {error, Reason} when
198      Drive :: string(),
199      Dir :: filename(),
200      Reason :: posix() | badarg.
201
202get_cwd(Drive) ->
203    check_and_call(get_cwd, [file_name(Drive)]).
204
205-spec set_cwd(Dir) -> ok | {error, Reason} when
206      Dir :: name() | EncodedBinary,
207      EncodedBinary :: binary(),
208      Reason :: posix() | badarg | no_translation.
209
210set_cwd(Dirname) ->
211    check_and_call(set_cwd, [file_name(Dirname)]).
212
213-spec delete(Filename) -> ok | {error, Reason} when
214      Filename :: name_all(),
215      Reason :: posix() | badarg.
216
217delete(Name) ->
218    check_and_call(delete, [file_name(Name)]).
219
220-spec rename(Source, Destination) -> ok | {error, Reason} when
221      Source :: name_all(),
222      Destination :: name_all(),
223      Reason :: posix() | badarg.
224
225rename(From, To) ->
226    check_and_call(rename, [file_name(From), file_name(To)]).
227
228-spec make_dir(Dir) -> ok | {error, Reason} when
229      Dir :: name_all(),
230      Reason :: posix() | badarg.
231
232make_dir(Name) ->
233    check_and_call(make_dir, [file_name(Name)]).
234
235-spec del_dir(Dir) -> ok | {error, Reason} when
236      Dir :: name_all(),
237      Reason :: posix() | badarg.
238
239del_dir(Name) ->
240    check_and_call(del_dir, [file_name(Name)]).
241
242-spec del_dir_r(File) -> ok | {error, Reason} when
243      File :: name_all(),
244      Reason :: posix() | badarg.
245
246del_dir_r(File) -> % rm -rf File
247    case read_link_info(File) of
248	{ok, #file_info{type = directory}} ->
249	    case list_dir_all(File) of
250		{ok, Names} ->
251		    lists:foreach(fun(Name) ->
252				      del_dir_r(filename:join(File, Name))
253				  end, Names);
254		{error, _Reason} -> ok
255	    end,
256	    del_dir(File);
257	{ok, _FileInfo} -> delete(File);
258	{error, _Reason} = Error -> Error
259    end.
260
261-spec read_file_info(File) -> {ok, FileInfo} | {error, Reason} when
262      File :: name_all() | io_device(),
263      FileInfo :: file_info(),
264      Reason :: posix() | badarg.
265
266read_file_info(IoDevice)
267  when is_pid(IoDevice); is_record(IoDevice, file_descriptor) ->
268    read_file_info(IoDevice, []);
269
270read_file_info(Name) ->
271    check_and_call(read_file_info, [file_name(Name)]).
272
273-spec read_file_info(File, Opts) -> {ok, FileInfo} | {error, Reason} when
274      File :: name_all() | io_device(),
275      Opts :: [file_info_option()],
276      FileInfo :: file_info(),
277      Reason :: posix() | badarg.
278
279read_file_info(IoDevice, Opts) when is_pid(IoDevice), is_list(Opts) ->
280    file_request(IoDevice, {read_handle_info, Opts});
281
282read_file_info(#file_descriptor{module = Module} = Handle, Opts) when is_list(Opts) ->
283    Module:read_handle_info(Handle, Opts);
284
285read_file_info(Name, Opts) when is_list(Opts) ->
286    Args = [file_name(Name), Opts],
287    case check_args(Args) of
288        ok ->
289            case lists:member(raw, Opts) of
290                true ->
291                    [FileName|_] = Args,
292                    ?PRIM_FILE:read_file_info(FileName, Opts);
293                false ->
294                    call(read_file_info, Args)
295            end;
296        Error ->
297            Error
298    end.
299
300-spec altname(Name :: name_all()) -> any().
301
302altname(Name) ->
303    check_and_call(altname, [file_name(Name)]).
304
305-spec read_link_info(Name) -> {ok, FileInfo} | {error, Reason} when
306      Name :: name_all(),
307      FileInfo :: file_info(),
308      Reason :: posix() | badarg.
309
310read_link_info(Name) ->
311    check_and_call(read_link_info, [file_name(Name)]).
312
313-spec read_link_info(Name, Opts) -> {ok, FileInfo} | {error, Reason} when
314      Name :: name_all(),
315      Opts :: [file_info_option()],
316      FileInfo :: file_info(),
317      Reason :: posix() | badarg.
318
319read_link_info(Name, Opts) when is_list(Opts) ->
320    Args = [file_name(Name), Opts],
321    case check_args(Args) of
322        ok ->
323            case lists:member(raw, Opts) of
324                true ->
325                    [FileName|_] = Args,
326                    ?PRIM_FILE:read_link_info(FileName, Opts);
327                false ->
328                    call(read_link_info, Args)
329            end;
330        Error ->
331            Error
332    end.
333
334
335-spec read_link(Name) -> {ok, Filename} | {error, Reason} when
336      Name :: name_all(),
337      Filename :: filename(),
338      Reason :: posix() | badarg.
339
340read_link(Name) ->
341    check_and_call(read_link, [file_name(Name)]).
342
343-spec read_link_all(Name) -> {ok, Filename} | {error, Reason} when
344      Name :: name_all(),
345      Filename :: filename_all(),
346      Reason :: posix() | badarg.
347
348read_link_all(Name) ->
349    check_and_call(read_link_all, [file_name(Name)]).
350
351-spec write_file_info(Filename, FileInfo) -> ok | {error, Reason} when
352      Filename :: name_all(),
353      FileInfo :: file_info(),
354      Reason :: posix() | badarg.
355
356write_file_info(Name, Info = #file_info{}) ->
357    check_and_call(write_file_info, [file_name(Name), Info]).
358
359-spec write_file_info(Filename, FileInfo, Opts) -> ok | {error, Reason} when
360      Filename :: name_all(),
361      Opts :: [file_info_option()],
362      FileInfo :: file_info(),
363      Reason :: posix() | badarg.
364
365write_file_info(Name, Info = #file_info{}, Opts) when is_list(Opts) ->
366    Args = [file_name(Name), Info, Opts],
367    case check_args(Args) of
368        ok ->
369            case lists:member(raw, Opts) of
370                true ->
371                    [FileName|_] = Args,
372                    ?PRIM_FILE:write_file_info(FileName, Info, Opts);
373                false ->
374                    call(write_file_info, Args)
375            end;
376        Error ->
377            Error
378    end.
379
380-spec list_dir(Dir) -> {ok, Filenames} | {error, Reason} when
381      Dir :: name_all(),
382      Filenames :: [filename()],
383      Reason :: posix()
384              | badarg
385              | {no_translation, Filename :: unicode:latin1_binary()}.
386
387list_dir(Name) ->
388    check_and_call(list_dir, [file_name(Name)]).
389
390-spec list_dir_all(Dir) -> {ok, Filenames} | {error, Reason} when
391      Dir :: name_all(),
392      Filenames :: [filename_all()],
393      Reason :: posix() | badarg.
394
395list_dir_all(Name) ->
396    check_and_call(list_dir_all, [file_name(Name)]).
397
398-spec read_file(Filename) -> {ok, Binary} | {error, Reason} when
399      Filename :: name_all(),
400      Binary :: binary(),
401      Reason :: posix() | badarg | terminated | system_limit.
402
403read_file(Name) ->
404    check_and_call(read_file, [file_name(Name)]).
405
406-spec make_link(Existing, New) -> ok | {error, Reason} when
407      Existing :: name_all(),
408      New :: name_all(),
409      Reason :: posix() | badarg.
410
411make_link(Old, New) ->
412    check_and_call(make_link, [file_name(Old), file_name(New)]).
413
414-spec make_symlink(Existing, New) -> ok | {error, Reason} when
415      Existing :: name_all(),
416      New :: name_all(),
417      Reason :: posix() | badarg.
418
419make_symlink(Old, New) ->
420    check_and_call(make_symlink, [file_name(Old), file_name(New)]).
421
422-spec write_file(Filename, Bytes) -> ok | {error, Reason} when
423      Filename :: name_all(),
424      Bytes :: iodata(),
425      Reason :: posix() | badarg | terminated | system_limit.
426
427write_file(Name, Bin) ->
428    check_and_call(write_file, [file_name(Name), make_binary(Bin)]).
429
430%% This whole operation should be moved to the file_server and prim_file
431%% when it is time to change file server protocol again.
432%% Meanwhile, it is implemented here, slightly less efficient.
433
434-spec write_file(Filename, Bytes, Modes) -> ok | {error, Reason} when
435      Filename :: name_all(),
436      Bytes :: iodata(),
437      Modes :: [mode()],
438      Reason :: posix() | badarg | terminated | system_limit.
439
440write_file(Name, IOData, ModeList) when is_list(ModeList) ->
441    case lists:member(raw, ModeList) of
442        true ->
443          %% For backwards compatibility of error messages
444            try iolist_size(IOData) of
445                _Size -> do_write_file(Name, IOData, ModeList)
446            catch
447                error:Error -> {error, Error}
448            end;
449        false ->
450            case make_binary(IOData) of
451                Bin when is_binary(Bin) ->
452                    do_write_file(Name, Bin, ModeList);
453                Error ->
454                    Error
455            end
456    end.
457
458do_write_file(Name, IOData, ModeList) ->
459    case open(Name, [binary, write | ModeList]) of
460        {ok, Handle} ->
461            case write(Handle, IOData) of
462                ok ->
463                    close(Handle);
464                E1 ->
465                    _ = close(Handle),
466                    E1
467            end;
468        E2 ->
469            E2
470    end.
471
472%% Obsolete, undocumented, local node only, don't use!.
473%% XXX to be removed.
474raw_read_file_info(Name) ->
475    read_file_info(Name, [raw]).
476
477%% Obsolete, undocumented, local node only, don't use!.
478%% XXX to be removed.
479raw_write_file_info(Name, #file_info{} = Info) ->
480    write_file_info(Name, Info, [raw]).
481
482%%%-----------------------------------------------------------------
483%%% File io server functions.
484%%% They operate on a single open file.
485%%% Stateful.
486
487%% Contemporary mode specification - list of options
488
489-spec open(File, Modes) -> {ok, IoDevice} | {error, Reason} when
490      File :: Filename | iodata(),
491      Filename :: name_all(),
492      Modes :: [mode() | ram | directory],
493      IoDevice :: io_device(),
494      Reason :: posix() | badarg | system_limit.
495
496open(Item, ModeList) when is_list(ModeList) ->
497    case {lists:member(raw, ModeList), lists:member(ram, ModeList)} of
498        {false, false} ->
499            %% File server file
500            Args = [file_name(Item) | ModeList],
501            case check_args(Args) of
502                ok ->
503                    [FileName | _] = Args,
504                    call(open, [FileName, ModeList]);
505                Error ->
506                    Error
507            end;
508        {true, _Either} ->
509            raw_file_io:open(file_name(Item), ModeList);
510        {false, true} ->
511            ram_file:open(Item, ModeList)
512    end;
513
514%% Old obsolete mode specification in atom or 2-tuple format
515open(Item, Mode) ->
516    open(Item, mode_list(Mode)).
517
518%%%-----------------------------------------------------------------
519%%% The following interface functions operate on open files.
520%%% The File argument must be either a Pid or a handle
521%%% returned from ?PRIM_FILE:open.
522
523-spec close(IoDevice) -> ok | {error, Reason} when
524      IoDevice :: io_device(),
525      Reason :: posix() | badarg | terminated.
526
527close(File) when is_pid(File) ->
528    case file_request(File, close) of
529	{error, terminated} ->
530	    ok;
531	Other ->
532	    Other
533    end;
534%%    unlink(File),
535%%    exit(File, close),
536%%    ok;
537close(#file_descriptor{module = Module} = Handle) ->
538    Module:close(Handle);
539close(_) ->
540    {error, badarg}.
541
542-spec advise(IoDevice, Offset, Length, Advise) -> ok | {error, Reason} when
543      IoDevice :: io_device(),
544      Offset :: integer(),
545      Length :: integer(),
546      Advise :: posix_file_advise(),
547      Reason :: posix() | badarg.
548
549advise(File, Offset, Length, Advise) when is_pid(File) ->
550    file_request(File, {advise, Offset, Length, Advise});
551advise(#file_descriptor{module = Module} = Handle, Offset, Length, Advise) ->
552    Module:advise(Handle, Offset, Length, Advise);
553advise(_, _, _, _) ->
554    {error, badarg}.
555
556-spec allocate(File, Offset, Length) ->
557	'ok' | {'error', posix()} when
558      File :: io_device(),
559      Offset :: non_neg_integer(),
560      Length :: non_neg_integer().
561
562allocate(File, Offset, Length) when is_pid(File) ->
563    file_request(File, {allocate, Offset, Length});
564allocate(#file_descriptor{module = Module} = Handle, Offset, Length) ->
565    Module:allocate(Handle, Offset, Length).
566
567-spec read(IoDevice, Number) -> {ok, Data} | eof | {error, Reason} when
568      IoDevice :: io_device() | atom(),
569      Number :: non_neg_integer(),
570      Data :: string() | binary(),
571      Reason :: posix()
572              | badarg
573              | terminated
574              | {no_translation, unicode, latin1}.
575
576read(File, Sz) when (is_pid(File) orelse is_atom(File)), is_integer(Sz), Sz >= 0 ->
577    case io:request(File, {get_chars, latin1, '', Sz}) of
578	Data when is_list(Data); is_binary(Data) ->
579	    {ok, Data};
580	Other ->
581	    Other
582    end;
583read(#file_descriptor{module = Module} = Handle, Sz)
584  when is_integer(Sz), Sz >= 0 ->
585    Module:read(Handle, Sz);
586read(_, _) ->
587    {error, badarg}.
588
589-spec read_line(IoDevice) -> {ok, Data} | eof | {error, Reason} when
590      IoDevice :: io_device() | atom(),
591      Data :: string() | binary(),
592      Reason :: posix()
593              | badarg
594              | terminated
595              | {no_translation, unicode, latin1}.
596
597read_line(File) when (is_pid(File) orelse is_atom(File)) ->
598    case io:request(File, {get_line, latin1, ''}) of
599	Data when is_list(Data); is_binary(Data) ->
600	    {ok, Data};
601	Other ->
602	    Other
603    end;
604read_line(#file_descriptor{module = Module} = Handle) ->
605    Module:read_line(Handle);
606read_line(_) ->
607    {error, badarg}.
608
609-spec pread(IoDevice, LocNums) -> {ok, DataL} | eof | {error, Reason} when
610      IoDevice :: io_device(),
611      LocNums :: [{Location :: location(), Number :: non_neg_integer()}],
612      DataL :: [Data],
613      Data :: string() | binary() | eof,
614      Reason :: posix() | badarg | terminated.
615
616pread(File, L) when is_pid(File), is_list(L) ->
617    pread_int(File, L, []);
618pread(#file_descriptor{module = Module} = Handle, L) when is_list(L) ->
619    Module:pread(Handle, L);
620pread(_, _) ->
621    {error, badarg}.
622
623pread_int(_File, [], R) ->
624    {ok, lists:reverse(R)};
625pread_int(File, [{At, Sz} | T], R) when is_integer(Sz), Sz >= 0 ->
626    case pread(File, At, Sz) of
627	{ok, Data} ->
628	    pread_int(File, T, [Data | R]);
629	eof ->
630	    pread_int(File, T, [eof | R]);
631	{error, _} = Error ->
632	    Error
633    end;
634pread_int(_, _, _) ->
635    {error, badarg}.
636
637-spec pread(IoDevice, Location, Number) ->
638             {ok, Data} | eof | {error, Reason} when
639      IoDevice :: io_device(),
640      Location :: location(),
641      Number :: non_neg_integer(),
642      Data :: string() | binary(),
643      Reason :: posix() | badarg | terminated.
644
645pread(File, At, Sz) when is_pid(File), is_integer(Sz), Sz >= 0 ->
646    file_request(File, {pread, At, Sz});
647pread(#file_descriptor{module = Module} = Handle, Offs, Sz)
648  when is_integer(Sz), Sz >= 0 ->
649    Module:pread(Handle, Offs, Sz);
650pread(_, _, _) ->
651    {error, badarg}.
652
653-spec write(IoDevice, Bytes) -> ok | {error, Reason} when
654      IoDevice :: io_device() | atom(),
655      Bytes :: iodata(),
656      Reason :: posix() | badarg | terminated.
657
658write(File, Bytes) when (is_pid(File) orelse is_atom(File)) ->
659    case make_binary(Bytes) of
660	Bin when is_binary(Bin) ->
661	    io:request(File, {put_chars,latin1,Bin});
662	Error ->
663	    Error
664    end;
665write(#file_descriptor{module = Module} = Handle, Bytes) ->
666    Module:write(Handle, Bytes);
667write(_, _) ->
668    {error, badarg}.
669
670-spec pwrite(IoDevice, LocBytes) -> ok | {error, {N, Reason}} when
671      IoDevice :: io_device(),
672      LocBytes :: [{Location :: location(), Bytes :: iodata()}],
673      N :: non_neg_integer(),
674      Reason :: posix() | badarg | terminated.
675
676pwrite(File, L) when is_pid(File), is_list(L) ->
677    pwrite_int(File, L, 0);
678pwrite(#file_descriptor{module = Module} = Handle, L) when is_list(L) ->
679    Module:pwrite(Handle, L);
680pwrite(_, _) ->
681    {error, badarg}.
682
683pwrite_int(_File, [], _R) ->
684    ok;
685pwrite_int(File, [{At, Bytes} | T], R) ->
686    case pwrite(File, At, Bytes) of
687	ok ->
688	    pwrite_int(File, T, R+1);
689	{error, Reason} ->
690	    {error, {R, Reason}}
691    end;
692pwrite_int(_, _, _) ->
693    {error, badarg}.
694
695-spec pwrite(IoDevice, Location, Bytes) -> ok | {error, Reason} when
696      IoDevice :: io_device(),
697      Location :: location(),
698      Bytes :: iodata(),
699      Reason :: posix() | badarg | terminated.
700
701pwrite(File, At, Bytes) when is_pid(File) ->
702    file_request(File, {pwrite, At, Bytes});
703pwrite(#file_descriptor{module = Module} = Handle, Offs, Bytes) ->
704    Module:pwrite(Handle, Offs, Bytes);
705pwrite(_, _, _) ->
706    {error, badarg}.
707
708-spec datasync(IoDevice) -> ok | {error, Reason} when
709      IoDevice :: io_device(),
710      Reason :: posix() | badarg | terminated.
711
712datasync(File) when is_pid(File) ->
713    file_request(File, datasync);
714datasync(#file_descriptor{module = Module} = Handle) ->
715    Module:datasync(Handle);
716datasync(_) ->
717    {error, badarg}.
718
719-spec sync(IoDevice) -> ok | {error, Reason} when
720      IoDevice :: io_device(),
721      Reason :: posix() | badarg | terminated.
722
723sync(File) when is_pid(File) ->
724    file_request(File, sync);
725sync(#file_descriptor{module = Module} = Handle) ->
726    Module:sync(Handle);
727sync(_) ->
728    {error, badarg}.
729
730-spec position(IoDevice, Location) -> {ok, NewPosition} | {error, Reason} when
731      IoDevice :: io_device(),
732      Location :: location(),
733      NewPosition :: integer(),
734      Reason :: posix() | badarg | terminated.
735
736position(File, At) when is_pid(File) ->
737    file_request(File, {position,At});
738position(#file_descriptor{module = Module} = Handle, At) ->
739    Module:position(Handle, At);
740position(_, _) ->
741    {error, badarg}.
742
743-spec truncate(IoDevice) -> ok | {error, Reason} when
744      IoDevice :: io_device(),
745      Reason :: posix() | badarg | terminated.
746
747truncate(File) when is_pid(File) ->
748    file_request(File, truncate);
749truncate(#file_descriptor{module = Module} = Handle) ->
750    Module:truncate(Handle);
751truncate(_) ->
752    {error, badarg}.
753
754-spec copy(Source, Destination) -> {ok, BytesCopied} | {error, Reason} when
755      Source :: io_device() | Filename | {Filename, Modes},
756      Destination :: io_device() | Filename | {Filename, Modes},
757      Filename :: name_all(),
758      Modes :: [mode()],
759      BytesCopied :: non_neg_integer(),
760      Reason :: posix() | badarg | terminated.
761
762copy(Source, Dest) ->
763    copy_int(Source, Dest, infinity).
764
765-spec copy(Source, Destination, ByteCount) ->
766             {ok, BytesCopied} | {error, Reason} when
767      Source :: io_device() | Filename | {Filename, Modes},
768      Destination :: io_device() | Filename | {Filename, Modes},
769      Filename :: name_all(),
770      Modes :: [mode()],
771      ByteCount :: non_neg_integer() | infinity,
772      BytesCopied :: non_neg_integer(),
773      Reason :: posix() | badarg | terminated.
774
775copy(Source, Dest, Length)
776  when is_integer(Length), Length >= 0;
777       is_atom(Length) ->
778    copy_int(Source, Dest, Length);
779copy(_, _, _) ->
780    {error, badarg}.
781
782%% Here we know that Length is either an atom or an integer >= 0
783%% (by the way, atoms > integers)
784%%
785%% Copy between open files.
786copy_int(Source, Dest, Length)
787  when is_pid(Source), is_pid(Dest);
788       is_pid(Source), is_record(Dest, file_descriptor);
789       is_record(Source, file_descriptor), is_pid(Dest) ->
790    copy_opened_int(Source, Dest, Length, 0);
791%% Copy between open raw files, both handled by the same module
792copy_int(#file_descriptor{module = Module} = Source,
793	 #file_descriptor{module = Module} = Dest,
794	 Length) ->
795    Module:copy(Source, Dest, Length);
796%% Copy between open raw files of different modules
797copy_int(#file_descriptor{} = Source,
798	 #file_descriptor{} = Dest, Length) ->
799    copy_opened_int(Source, Dest, Length, 0);
800%% Copy between filenames, let the server do the copy
801copy_int({SourceName, SourceOpts}, {DestName, DestOpts}, Length)
802  when is_list(SourceOpts), is_list(DestOpts) ->
803    check_and_call(copy,
804		   [file_name(SourceName), SourceOpts,
805		    file_name(DestName), DestOpts,
806		    Length]);
807%% Filename -> open file; must open Source and do client copy
808copy_int({SourceName, SourceOpts}, Dest, Length)
809  when is_list(SourceOpts), is_pid(Dest);
810       is_list(SourceOpts), is_record(Dest, file_descriptor) ->
811    case file_name(SourceName) of
812	{error, _} = Error ->
813	    Error;
814	Source ->
815	    case open(Source, [read | SourceOpts]) of
816		{ok, Handle} ->
817		    Result = copy_opened_int(Handle, Dest, Length, 0),
818		    _ = close(Handle),
819		    Result;
820		{error, _} = Error ->
821		    Error
822	    end
823    end;
824%% Open file -> filename; must open Dest and do client copy
825copy_int(Source, {DestName, DestOpts}, Length)
826  when is_pid(Source), is_list(DestOpts);
827       is_record(Source, file_descriptor), is_list(DestOpts) ->
828    case file_name(DestName) of
829	{error, _} = Error ->
830	    Error;
831	Dest ->
832	    case open(Dest, [write | DestOpts]) of
833		{ok, Handle} ->
834                    case copy_opened_int(Source, Handle, Length, 0) of
835                        {ok, _} = OK ->
836                            case close(Handle) of
837                                ok -> OK;
838                                Error -> Error
839                            end;
840                        Error ->
841                            _ = close(Handle),
842                            Error
843                    end;
844		{error, _} = Error ->
845		    Error
846	    end
847    end;
848%%
849%% That was all combinations of {Name, Opts} tuples
850%% and open files. At least one of Source and Dest has
851%% to be a bare filename.
852%%
853%% If Source is not a bare filename; Dest must be
854copy_int(Source, Dest, Length)
855  when is_pid(Source);
856       is_record(Source, file_descriptor) ->
857    copy_int(Source, {Dest, []}, Length);
858copy_int({_SourceName, SourceOpts} = Source, Dest, Length)
859  when is_list(SourceOpts) ->
860    copy_int(Source, {Dest, []}, Length);
861%% If Dest is not a bare filename; Source must be
862copy_int(Source, Dest, Length)
863  when is_pid(Dest);
864       is_record(Dest, file_descriptor) ->
865    copy_int({Source, []}, Dest, Length);
866copy_int(Source, {_DestName, DestOpts} = Dest, Length)
867  when is_list(DestOpts) ->
868    copy_int({Source, []}, Dest, Length);
869%% Both must be bare filenames. If they are not,
870%% the filename check in the copy operation will yell.
871copy_int(Source, Dest, Length) ->
872    copy_int({Source, []}, {Dest, []}, Length).
873
874
875
876copy_opened(Source, Dest, Length)
877  when is_integer(Length), Length >= 0;
878       is_atom(Length) ->
879    copy_opened_int(Source, Dest, Length);
880copy_opened(_, _, _) ->
881    {error, badarg}.
882
883%% Here we know that Length is either an atom or an integer >= 0
884%% (by the way, atoms > integers)
885
886copy_opened_int(Source, Dest, Length)
887  when is_pid(Source), is_pid(Dest) ->
888    copy_opened_int(Source, Dest, Length, 0);
889copy_opened_int(Source, Dest, Length)
890  when is_pid(Source), is_record(Dest, file_descriptor) ->
891    copy_opened_int(Source, Dest, Length, 0);
892copy_opened_int(Source, Dest, Length)
893  when is_record(Source, file_descriptor), is_pid(Dest) ->
894    copy_opened_int(Source, Dest, Length, 0);
895copy_opened_int(Source, Dest, Length)
896  when is_record(Source, file_descriptor), is_record(Dest, file_descriptor) ->
897    copy_opened_int(Source, Dest, Length, 0);
898copy_opened_int(_, _, _) ->
899    {error, badarg}.
900
901%% Here we know that Source and Dest are handles to open files, Length is
902%% as above, and Copied is an integer >= 0
903
904%% Copy loop in client process
905copy_opened_int(_, _, Length, Copied) when Length =< 0 -> % atom() > integer()
906    {ok, Copied};
907copy_opened_int(Source, Dest, Length, Copied) ->
908    N = if Length > 65536 -> 65536; true -> Length end, % atom() > integer() !
909    case read(Source, N) of
910	{ok, Data} ->
911	    M = if is_binary(Data) -> byte_size(Data);
912		   is_list(Data)   -> length(Data)
913		end,
914	    case write(Dest, Data) of
915		ok ->
916		    if M < N ->
917			    %% Got less than asked for - must be end of file
918			    {ok, Copied+M};
919		       true ->
920			    %% Decrement Length (might be an atom (infinity))
921			    NewLength = if is_atom(Length) -> Length;
922					   true         -> Length-M
923					end,
924			    copy_opened_int(Source, Dest, NewLength, Copied+M)
925		    end;
926		{error, _} = Error ->
927		    Error
928	    end;
929	eof ->
930	    {ok, Copied};
931	{error, _} = Error ->
932	    Error
933    end.
934
935
936%% Special indirect pread function. Introduced for Dets.
937%% Reads a header from pos 'Pos', the header is first a size encoded as
938%% 32 bit big endian unsigned and then a position also encoded as
939%% 32 bit big endian. Finally it preads the data from that pos and size
940%% in the file.
941
942ipread_s32bu_p32bu(File, Pos, MaxSize) when is_pid(File) ->
943    ipread_s32bu_p32bu_int(File, Pos, MaxSize);
944ipread_s32bu_p32bu(#file_descriptor{module = Module} = Handle, Pos, MaxSize) ->
945    Module:ipread_s32bu_p32bu(Handle, Pos, MaxSize);
946ipread_s32bu_p32bu(_, _, _) ->
947    {error, badarg}.
948
949ipread_s32bu_p32bu_int(File, Pos, Infinity) when is_atom(Infinity) ->
950    ipread_s32bu_p32bu_int(File, Pos, (1 bsl 31)-1);
951ipread_s32bu_p32bu_int(File, Pos, MaxSize)
952  when is_integer(MaxSize), MaxSize >= 0 ->
953    if
954	MaxSize < (1 bsl 31) ->
955	    case pread(File, Pos, 8) of
956		{ok, Header} ->
957		    ipread_s32bu_p32bu_2(File, Header, MaxSize);
958		Error ->
959		    Error
960	    end;
961	true ->
962	    {error, einval}
963    end;
964ipread_s32bu_p32bu_int(_File, _Pos, _MaxSize) ->
965    {error, badarg}.
966
967ipread_s32bu_p32bu_2(_File,
968		     <<0:32/big-unsigned, Pos:32/big-unsigned>>,
969		     _MaxSize) ->
970    {ok, {0, Pos, eof}};
971ipread_s32bu_p32bu_2(File,
972		     <<Size:32/big-unsigned, Pos:32/big-unsigned>>,
973		     MaxSize)
974  when Size =< MaxSize ->
975    case pread(File, Pos, Size) of
976	{ok, Data} ->
977	    {ok, {Size, Pos, Data}};
978	eof ->
979	    {ok, {Size, Pos, eof}};
980	Error ->
981	    Error
982    end;
983ipread_s32bu_p32bu_2(_File,
984		     <<_:8/binary>>,
985		     _MaxSize) ->
986    eof;
987ipread_s32bu_p32bu_2(_File,
988		     <<_/binary>>,
989		     _MaxSize) ->
990    eof;
991ipread_s32bu_p32bu_2(File,
992		    Header,
993		    MaxSize) when is_list(Header) ->
994    ipread_s32bu_p32bu_2(File, list_to_binary(Header), MaxSize).
995
996
997
998%%%-----------------------------------------------------------------
999%%% The following functions, built upon the other interface functions,
1000%%% provide a higher-lever interface to files.
1001
1002-spec consult(Filename) -> {ok, Terms} | {error, Reason} when
1003      Filename :: name_all(),
1004      Terms :: [term()],
1005      Reason :: posix() | badarg | terminated | system_limit
1006              | {Line :: integer(), Mod :: module(), Term :: term()}.
1007
1008consult(File) ->
1009    case open(File, [read]) of
1010	{ok, Fd} ->
1011	    R = consult_stream(Fd),
1012	    _ = close(Fd),
1013	    R;
1014	Error ->
1015	    Error
1016    end.
1017
1018-spec path_consult(Path, Filename) -> {ok, Terms, FullName} | {error, Reason} when
1019      Path :: [Dir],
1020      Dir :: name_all(),
1021      Filename :: name_all(),
1022      Terms :: [term()],
1023      FullName :: filename_all(),
1024      Reason :: posix() | badarg | terminated | system_limit
1025              | {Line :: integer(), Mod :: module(), Term :: term()}.
1026
1027path_consult(Path, File) ->
1028    case path_open(Path, File, [read]) of
1029	{ok, Fd, Full} ->
1030	    case consult_stream(Fd) of
1031		{ok, List} ->
1032		    _ = close(Fd),
1033		    {ok, List, Full};
1034		E1 ->
1035		    _ = close(Fd),
1036		    E1
1037	    end;
1038	E2 ->
1039	    E2
1040    end.
1041
1042-spec eval(Filename) -> ok | {error, Reason} when
1043      Filename :: name_all(),
1044      Reason :: posix() | badarg | terminated | system_limit
1045              | {Line :: integer(), Mod :: module(), Term :: term()}.
1046
1047eval(File) ->
1048    eval(File, erl_eval:new_bindings()).
1049
1050-spec eval(Filename, Bindings) -> ok | {error, Reason} when
1051      Filename :: name_all(),
1052      Bindings :: erl_eval:binding_struct(),
1053      Reason :: posix() | badarg | terminated | system_limit
1054              | {Line :: integer(), Mod :: module(), Term :: term()}.
1055
1056eval(File, Bs) ->
1057    case open(File, [read]) of
1058	{ok, Fd} ->
1059	    R = eval_stream(Fd, ignore, Bs),
1060	    _ = close(Fd),
1061	    R;
1062	Error ->
1063	    Error
1064    end.
1065
1066-spec path_eval(Path, Filename) -> {ok, FullName} | {error, Reason} when
1067      Path :: [Dir :: name_all()],
1068      Filename :: name_all(),
1069      FullName :: filename_all(),
1070      Reason :: posix() | badarg | terminated | system_limit
1071              | {Line :: integer(), Mod :: module(), Term :: term()}.
1072
1073path_eval(Path, File) ->
1074    path_eval(Path, File, erl_eval:new_bindings()).
1075
1076-spec path_eval(Path, Filename, Bindings) ->
1077             {ok, FullName} | {error, Reason} when
1078      Path :: [Dir :: name_all()],
1079      Filename :: name_all(),
1080      Bindings :: erl_eval:binding_struct(),
1081      FullName :: filename_all(),
1082      Reason :: posix() | badarg | terminated | system_limit
1083              | {Line :: integer(), Mod :: module(), Term :: term()}.
1084
1085path_eval(Path, File, Bs) ->
1086    case path_open(Path, File, [read]) of
1087	{ok, Fd, Full} ->
1088	    case eval_stream(Fd, ignore, Bs) of
1089		ok ->
1090		    _ = close(Fd),
1091		    {ok, Full};
1092		E1 ->
1093		    _ = close(Fd),
1094		    E1
1095	    end;
1096	E2 ->
1097	    E2
1098    end.
1099
1100-spec script(Filename) -> {ok, Value} | {error, Reason} when
1101      Filename :: name_all(),
1102      Value :: term(),
1103      Reason :: posix() | badarg | terminated | system_limit
1104              | {Line :: integer(), Mod :: module(), Term :: term()}.
1105
1106script(File) ->
1107    script(File, erl_eval:new_bindings()).
1108
1109-spec script(Filename, Bindings) -> {ok, Value} | {error, Reason} when
1110      Filename :: name_all(),
1111      Bindings :: erl_eval:binding_struct(),
1112      Value :: term(),
1113      Reason :: posix() | badarg | terminated | system_limit
1114              | {Line :: integer(), Mod :: module(), Term :: term()}.
1115
1116script(File, Bs) ->
1117    case open(File, [read]) of
1118	{ok, Fd} ->
1119	    R = eval_stream(Fd, return, Bs),
1120	    _ = close(Fd),
1121	    R;
1122	Error ->
1123	    Error
1124    end.
1125
1126-spec path_script(Path, Filename) ->
1127             {ok, Value, FullName} | {error, Reason} when
1128      Path :: [Dir :: name_all()],
1129      Filename :: name_all(),
1130      Value :: term(),
1131      FullName :: filename_all(),
1132      Reason :: posix() | badarg | terminated | system_limit
1133              | {Line :: integer(), Mod :: module(), Term :: term()}.
1134
1135path_script(Path, File) ->
1136    path_script(Path, File, erl_eval:new_bindings()).
1137
1138-spec path_script(Path, Filename, Bindings) ->
1139          {ok, Value, FullName} | {error, Reason} when
1140      Path :: [Dir :: name_all()],
1141      Filename :: name_all(),
1142      Bindings :: erl_eval:binding_struct(),
1143      Value :: term(),
1144      FullName :: filename_all(),
1145      Reason :: posix() | badarg | terminated | system_limit
1146              | {Line :: integer(), Mod :: module(), Term :: term()}.
1147
1148path_script(Path, File, Bs) ->
1149    case path_open(Path, File, [read]) of
1150	{ok,Fd,Full} ->
1151	    case eval_stream(Fd, return, Bs) of
1152		{ok,R} ->
1153		    _ = close(Fd),
1154		    {ok, R, Full};
1155		E1 ->
1156		    _ = close(Fd),
1157		    E1
1158	    end;
1159	E2 ->
1160	    E2
1161    end.
1162
1163
1164%% path_open(Paths, Filename, Mode) ->
1165%%	{ok,FileDescriptor,FullName}
1166%%	{error,Reason}
1167%%
1168%% Searches the Paths for file Filename which can be opened with Mode.
1169%% The path list is ignored if Filename contains an absolute path.
1170
1171-spec path_open(Path, Filename, Modes) ->
1172             {ok, IoDevice, FullName} | {error, Reason} when
1173      Path :: [Dir :: name_all()],
1174      Filename :: name_all(),
1175      Modes :: [mode() | directory],
1176      IoDevice :: io_device(),
1177      FullName :: filename_all(),
1178      Reason :: posix() | badarg | system_limit.
1179
1180path_open(PathList, Name, Mode) ->
1181    case file_name(Name) of
1182	{error, _} = Error ->
1183	    Error;
1184	FileName ->
1185	    case filename:pathtype(FileName) of
1186		relative ->
1187		    path_open_first(PathList, FileName, Mode, enoent);
1188		_ ->
1189		    case open(Name, Mode) of
1190			{ok, Fd} ->
1191			    {ok, Fd, Name};
1192			Error ->
1193			    Error
1194		    end
1195	    end
1196    end.
1197
1198-spec change_mode(Filename, Mode) -> ok | {error, Reason} when
1199      Filename :: name_all(),
1200      Mode :: integer(),
1201      Reason :: posix() | badarg.
1202
1203change_mode(Name, Mode)
1204  when is_integer(Mode) ->
1205    write_file_info(Name, #file_info{mode=Mode}).
1206
1207-spec change_owner(Filename, Uid) -> ok | {error, Reason} when
1208      Filename :: name_all(),
1209      Uid :: integer(),
1210      Reason :: posix() | badarg.
1211
1212change_owner(Name, OwnerId)
1213  when is_integer(OwnerId) ->
1214    write_file_info(Name, #file_info{uid=OwnerId}).
1215
1216-spec change_owner(Filename, Uid, Gid) -> ok | {error, Reason} when
1217      Filename :: name_all(),
1218      Uid :: integer(),
1219      Gid :: integer(),
1220      Reason :: posix() | badarg.
1221
1222change_owner(Name, OwnerId, GroupId)
1223  when is_integer(OwnerId), is_integer(GroupId) ->
1224    write_file_info(Name, #file_info{uid=OwnerId, gid=GroupId}).
1225
1226-spec change_group(Filename, Gid) -> ok | {error, Reason} when
1227      Filename :: name_all(),
1228      Gid :: integer(),
1229      Reason :: posix() | badarg.
1230
1231change_group(Name, GroupId)
1232  when is_integer(GroupId) ->
1233    write_file_info(Name, #file_info{gid=GroupId}).
1234
1235-spec change_time(Filename, Mtime) -> ok | {error, Reason} when
1236      Filename :: name_all(),
1237      Mtime :: date_time(),
1238      Reason :: posix() | badarg.
1239
1240change_time(Name, {{Y, M, D}, {H, Min, Sec}}=Time)
1241  when is_integer(Y), is_integer(M), is_integer(D),
1242       is_integer(H), is_integer(Min), is_integer(Sec)->
1243    write_file_info(Name, #file_info{mtime=Time}).
1244
1245-spec change_time(Filename, Atime, Mtime) -> ok | {error, Reason} when
1246      Filename :: name_all(),
1247      Atime :: date_time(),
1248      Mtime :: date_time(),
1249      Reason :: posix() | badarg.
1250
1251change_time(Name, {{AY, AM, AD}, {AH, AMin, ASec}}=Atime,
1252         {{MY, MM, MD}, {MH, MMin, MSec}}=Mtime)
1253  when is_integer(AY), is_integer(AM), is_integer(AD),
1254       is_integer(AH), is_integer(AMin), is_integer(ASec),
1255       is_integer(MY), is_integer(MM), is_integer(MD),
1256       is_integer(MH), is_integer(MMin), is_integer(MSec)->
1257    write_file_info(Name, #file_info{atime=Atime, mtime=Mtime}).
1258
1259%%
1260%% Send data using sendfile
1261%%
1262
1263%% 1 MB, Windows seems to behave badly if it is much larger then this
1264-define(MAX_CHUNK_SIZE, (1 bsl 20)).
1265
1266-spec sendfile(RawFile, Socket, Offset, Bytes, Opts) ->
1267   {'ok', non_neg_integer()} | {'error', inet:posix() |
1268				closed | badarg | not_owner} when
1269      RawFile :: fd(),
1270      Socket :: inet:socket(),
1271      Offset :: non_neg_integer(),
1272      Bytes :: non_neg_integer(),
1273      Opts :: [sendfile_option()].
1274sendfile(File, _Sock, _Offet, _Bytes, _Opts) when is_pid(File) ->
1275    {error, badarg};
1276sendfile(File, Sock, Offset, Bytes, []) ->
1277    sendfile(File, Sock, Offset, Bytes, ?MAX_CHUNK_SIZE, [], [], []);
1278sendfile(File, Sock, Offset, Bytes, Opts) ->
1279    try proplists:get_value(chunk_size, Opts, ?MAX_CHUNK_SIZE) of
1280        ChunkSize0 when is_integer(ChunkSize0) ->
1281            ChunkSize = erlang:min(ChunkSize0, ?MAX_CHUNK_SIZE),
1282            %% Support for headers, trailers and options has been removed
1283            %% because the Darwin and BSD API for using it does not play nice
1284            %% with non-blocking sockets. See unix_efile.c for more info.
1285            sendfile(File, Sock, Offset, Bytes, ChunkSize, [], [], Opts);
1286        _Other ->
1287            {error, badarg}
1288    catch
1289        error:_ -> {error, badarg}
1290    end.
1291
1292%% sendfile/2
1293-spec sendfile(Filename, Socket) ->
1294   {'ok', non_neg_integer()} | {'error', inet:posix() |
1295				closed | badarg | not_owner}
1296      when Filename :: name_all(),
1297	   Socket :: inet:socket().
1298sendfile(Filename, Sock)  ->
1299    case file:open(Filename, [read, raw, binary]) of
1300	{error, Reason} ->
1301	    {error, Reason};
1302	{ok, Fd} ->
1303	    Res = sendfile(Fd, Sock, 0, 0, []),
1304	    _ = file:close(Fd),
1305	    Res
1306    end.
1307
1308%% Internal sendfile functions
1309sendfile(#file_descriptor{ module = Mod } = Fd, Sock, Offset, Bytes,
1310	 ChunkSize, Headers, Trailers, Opts)
1311  when is_integer(Offset), is_integer(Bytes) ->
1312    case Sock of
1313        {'$inet', _, _} ->
1314            sendfile_fallback(
1315              Fd, Sock, Offset, Bytes, ChunkSize,
1316              Headers, Trailers);
1317        _ when is_port(Sock) ->
1318            case Mod:sendfile(
1319                   Fd, Sock, Offset, Bytes, ChunkSize,
1320                   Headers, Trailers, Opts) of
1321                {error, enotsup} ->
1322                    sendfile_fallback(
1323                      Fd, Sock, Offset, Bytes, ChunkSize,
1324                      Headers, Trailers);
1325                Else ->
1326                    Else
1327            end
1328    end;
1329sendfile(_,_,_,_,_,_,_,_) ->
1330    {error, badarg}.
1331
1332%%%
1333%% Sendfile Fallback
1334%%%
1335sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize,
1336		  Headers, Trailers)
1337  when Headers == []; is_integer(Headers) ->
1338    case sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize) of
1339	{ok, BytesSent} when is_list(Trailers),
1340			     Trailers =/= [],
1341			     is_integer(Headers) ->
1342	    sendfile_send(Sock, Trailers, BytesSent+Headers);
1343	{ok, BytesSent} when is_list(Trailers), Trailers =/= [] ->
1344	    sendfile_send(Sock, Trailers, BytesSent);
1345	{ok, BytesSent} when is_integer(Headers) ->
1346	    {ok, BytesSent + Headers};
1347	Else ->
1348	    Else
1349    end;
1350sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, Headers, Trailers) ->
1351    case sendfile_send(Sock, Headers, 0) of
1352	{ok, BytesSent} ->
1353	    sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, BytesSent,
1354			      Trailers);
1355	Else ->
1356	    Else
1357    end.
1358
1359
1360sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize)
1361  when 0 =< Bytes ->
1362    {ok, CurrPos} = file:position(File, {cur, 0}),
1363    case file:position(File, {bof, Offset}) of
1364        {ok, _NewPos} ->
1365            Res = sendfile_fallback_int(File, Sock, Bytes, ChunkSize, 0),
1366            _ = file:position(File, {bof, CurrPos}),
1367            Res;
1368        Error ->
1369            Error
1370    end;
1371sendfile_fallback(_, _, _, _, _) ->
1372    {error, einval}.
1373
1374
1375sendfile_fallback_int(File, Sock, Bytes, ChunkSize, BytesSent)
1376  when Bytes > BytesSent; Bytes == 0 ->
1377    Size = if Bytes == 0 ->
1378		   ChunkSize;
1379	       (Bytes - BytesSent) < ChunkSize ->
1380		   Bytes - BytesSent;
1381	      true ->
1382		   ChunkSize
1383	   end,
1384    case file:read(File, Size) of
1385	{ok, Data} ->
1386	    case sendfile_send(Sock, Data, BytesSent) of
1387		{ok,NewBytesSent} ->
1388		    sendfile_fallback_int(
1389		      File, Sock, Bytes, ChunkSize,
1390		      NewBytesSent);
1391		Error ->
1392		    Error
1393	    end;
1394	eof ->
1395	    {ok, BytesSent};
1396	Error ->
1397	    Error
1398    end;
1399sendfile_fallback_int(_File, _Sock, BytesSent, _ChunkSize, BytesSent) ->
1400    {ok, BytesSent}.
1401
1402sendfile_send(Sock, Data, Old) ->
1403    Len = iolist_size(Data),
1404    case gen_tcp:send(Sock, Data) of
1405	ok ->
1406	    {ok, Len+Old};
1407	Else ->
1408	    Else
1409    end.
1410
1411
1412
1413%%%-----------------------------------------------------------------
1414%%% Helpers
1415
1416consult_stream(Fd) ->
1417    _ = epp:set_encoding(Fd),
1418    consult_stream(Fd, 1, []).
1419
1420consult_stream(Fd, Line, Acc) ->
1421    case io:read(Fd, '', Line) of
1422	{ok,Term,EndLine} ->
1423	    consult_stream(Fd, EndLine, [Term|Acc]);
1424	{error,Error,_Line} ->
1425	    {error,Error};
1426	{eof,_Line} ->
1427	    {ok,lists:reverse(Acc)}
1428    end.
1429
1430eval_stream(Fd, Handling, Bs) ->
1431    _ = epp:set_encoding(Fd),
1432    eval_stream(Fd, Handling, 1, undefined, [], Bs).
1433
1434eval_stream(Fd, H, Line, Last, E, Bs) ->
1435    eval_stream2(io:parse_erl_exprs(Fd, '', Line), Fd, H, Last, E, Bs).
1436
1437eval_stream2({ok,Form,EndLine}, Fd, H, Last, E, Bs0) ->
1438    try erl_eval:exprs(Form, Bs0) of
1439	{value,V,Bs} ->
1440	    eval_stream(Fd, H, EndLine, {V}, E, Bs)
1441    catch Class:Reason:StackTrace ->
1442            Error = {EndLine,?MODULE,{Class,Reason,StackTrace}},
1443	    eval_stream(Fd, H, EndLine, Last, [Error|E], Bs0)
1444    end;
1445eval_stream2({error,What,EndLine}, Fd, H, Last, E, Bs) ->
1446    eval_stream(Fd, H, EndLine, Last, [What | E], Bs);
1447eval_stream2({eof,EndLine}, _Fd, H, Last, E, _Bs) ->
1448    case {H, Last, E} of
1449	{return, {Val}, []} ->
1450	    {ok, Val};
1451	{return, undefined, E} ->
1452	    {error, hd(lists:reverse(E, [{EndLine,?MODULE,undefined_script}]))};
1453	{ignore, _, []} ->
1454	    ok;
1455	{_, _, [_|_] = E} ->
1456	    {error, hd(lists:reverse(E))}
1457    end.
1458
1459path_open_first([Path|Rest], Name, Mode, LastError) ->
1460    case file_name(Path) of
1461	{error, _} = Error ->
1462	    Error;
1463	FilePath ->
1464	    FileName = fname_join(FilePath, Name),
1465	    case open(FileName, Mode) of
1466		{ok, Fd} ->
1467		    {ok, Fd, FileName};
1468		{error, Reason} when Reason =:= enoent; Reason =:= enotdir ->
1469		    path_open_first(Rest, Name, Mode, LastError);
1470		Error ->
1471		    Error
1472	    end
1473    end;
1474path_open_first([], _Name, _Mode, LastError) ->
1475    {error, LastError}.
1476
1477fname_join(".", Name) ->
1478    Name;
1479fname_join(Dir, Name) ->
1480    filename:join(Dir, Name).
1481
1482%%%-----------------------------------------------------------------
1483%%% Utility functions.
1484
1485%% file_name(FileName)
1486%% 	Generates a flat file name from a deep list of atoms and
1487%% 	characters (integers).
1488
1489file_name(N) when is_binary(N) ->
1490    N;
1491file_name(N) ->
1492    try
1493        file_name_1(N,file:native_name_encoding())
1494    catch Reason ->
1495        {error, Reason}
1496    end.
1497
1498file_name_1([C|T],latin1) when is_integer(C), C < 256->
1499    [C|file_name_1(T,latin1)];
1500file_name_1([C|T],utf8) when is_integer(C) ->
1501    [C|file_name_1(T,utf8)];
1502file_name_1([H|T],E) ->
1503    file_name_1(H,E) ++ file_name_1(T,E);
1504file_name_1([],_) ->
1505    [];
1506file_name_1(N,_) when is_atom(N) ->
1507    atom_to_list(N);
1508file_name_1(_,_) ->
1509    throw(badarg).
1510
1511make_binary(Bin) when is_binary(Bin) ->
1512    Bin;
1513make_binary(List) ->
1514    %% Convert the list to a binary in order to avoid copying a list
1515    %% to the file server.
1516    try
1517        erlang:iolist_to_binary(List)
1518    catch error:Reason ->
1519        {error, Reason}
1520    end.
1521
1522mode_list(read) ->
1523    [read];
1524mode_list(write) ->
1525    [write];
1526mode_list(read_write) ->
1527    [read, write];
1528mode_list({binary, Mode}) when is_atom(Mode) ->
1529    [binary | mode_list(Mode)];
1530mode_list({character, Mode}) when is_atom(Mode) ->
1531    mode_list(Mode);
1532mode_list(_) ->
1533    [{error, badarg}].
1534
1535%%-----------------------------------------------------------------
1536%% Functions for communicating with the file server
1537
1538call(Command, Args) when is_list(Args) ->
1539    X = erlang:dt_spread_tag(true),
1540    Y = gen_server:call(?FILE_SERVER, list_to_tuple([Command | Args]),
1541			infinity),
1542    erlang:dt_restore_tag(X),
1543    Y.
1544
1545check_and_call(Command, Args) when is_list(Args) ->
1546    case check_args(Args) of
1547	ok ->
1548	    call(Command, Args);
1549	Error ->
1550	    Error
1551    end.
1552
1553check_args([{error, _}=Error|_Rest]) ->
1554    Error;
1555check_args([_Name|Rest]) ->
1556    check_args(Rest);
1557check_args([]) ->
1558    ok.
1559
1560%%-----------------------------------------------------------------
1561%% Function for communicating with a file io server.
1562%% The messages sent have the following formats:
1563%%
1564%%	{file_request,From,ReplyAs,Request}
1565%%	{file_reply,ReplyAs,Reply}
1566
1567file_request(Io, Request) ->
1568    Ref = erlang:monitor(process, Io),
1569    Io ! {file_request,self(),Ref,Request},
1570    receive
1571	{file_reply,Ref,Reply} ->
1572	    erlang:demonitor(Ref, [flush]),
1573	    Reply;
1574	{'DOWN', Ref, _, _, _} ->
1575	    {error, terminated}
1576    end.
1577