PageRenderTime 5ms CodeModel.GetById 59ms app.highlight 132ms RepoModel.GetById 1ms app.codeStats 1ms

/lib/kernel/src/file.erl

https://github.com/bsmr-erlang/otp
Erlang | 1531 lines | 1199 code | 202 blank | 130 comment | 8 complexity | 095a7cac235b66da1d4032bbc2e9f908 MD5 | raw file
   1%%
   2%% %CopyrightBegin%
   3%%
   4%% Copyright Ericsson AB 1996-2018. 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, 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 read_file_info(Filename) -> {ok, FileInfo} | {error, Reason} when
 243      Filename :: name_all(),
 244      FileInfo :: file_info(),
 245      Reason :: posix() | badarg.
 246
 247read_file_info(Name) ->
 248    check_and_call(read_file_info, [file_name(Name)]).
 249
 250-spec read_file_info(Filename, Opts) -> {ok, FileInfo} | {error, Reason} when
 251      Filename :: name_all(),
 252      Opts :: [file_info_option()],
 253      FileInfo :: file_info(),
 254      Reason :: posix() | badarg.
 255
 256read_file_info(Name, Opts) when is_list(Opts) ->
 257    Args = [file_name(Name), Opts],
 258    case check_args(Args) of
 259        ok ->
 260            case lists:member(raw, Opts) of
 261                true ->
 262                    [FileName|_] = Args,
 263                    ?PRIM_FILE:read_file_info(FileName, Opts);
 264                false ->
 265                    call(read_file_info, Args)
 266            end;
 267        Error ->
 268            Error
 269    end.
 270
 271-spec altname(Name :: name_all()) -> any().
 272
 273altname(Name) ->
 274    check_and_call(altname, [file_name(Name)]).
 275
 276-spec read_link_info(Name) -> {ok, FileInfo} | {error, Reason} when
 277      Name :: name_all(),
 278      FileInfo :: file_info(),
 279      Reason :: posix() | badarg.
 280
 281read_link_info(Name) ->
 282    check_and_call(read_link_info, [file_name(Name)]).
 283
 284-spec read_link_info(Name, Opts) -> {ok, FileInfo} | {error, Reason} when
 285      Name :: name_all(),
 286      Opts :: [file_info_option()],
 287      FileInfo :: file_info(),
 288      Reason :: posix() | badarg.
 289
 290read_link_info(Name, Opts) when is_list(Opts) ->
 291    Args = [file_name(Name), Opts],
 292    case check_args(Args) of
 293        ok ->
 294            case lists:member(raw, Opts) of
 295                true ->
 296                    [FileName|_] = Args,
 297                    ?PRIM_FILE:read_link_info(FileName, Opts);
 298                false ->
 299                    call(read_link_info, Args)
 300            end;
 301        Error ->
 302            Error
 303    end.
 304
 305
 306-spec read_link(Name) -> {ok, Filename} | {error, Reason} when
 307      Name :: name_all(),
 308      Filename :: filename(),
 309      Reason :: posix() | badarg.
 310
 311read_link(Name) ->
 312    check_and_call(read_link, [file_name(Name)]).
 313
 314-spec read_link_all(Name) -> {ok, Filename} | {error, Reason} when
 315      Name :: name_all(),
 316      Filename :: filename_all(),
 317      Reason :: posix() | badarg.
 318
 319read_link_all(Name) ->
 320    check_and_call(read_link_all, [file_name(Name)]).
 321
 322-spec write_file_info(Filename, FileInfo) -> ok | {error, Reason} when
 323      Filename :: name_all(),
 324      FileInfo :: file_info(),
 325      Reason :: posix() | badarg.
 326
 327write_file_info(Name, Info = #file_info{}) ->
 328    check_and_call(write_file_info, [file_name(Name), Info]).
 329
 330-spec write_file_info(Filename, FileInfo, Opts) -> ok | {error, Reason} when
 331      Filename :: name_all(),
 332      Opts :: [file_info_option()],
 333      FileInfo :: file_info(),
 334      Reason :: posix() | badarg.
 335
 336write_file_info(Name, Info = #file_info{}, Opts) when is_list(Opts) ->
 337    Args = [file_name(Name), Info, Opts],
 338    case check_args(Args) of
 339        ok ->
 340            case lists:member(raw, Opts) of
 341                true ->
 342                    [FileName|_] = Args,
 343                    ?PRIM_FILE:write_file_info(FileName, Info, Opts);
 344                false ->
 345                    call(write_file_info, Args)
 346            end;
 347        Error ->
 348            Error
 349    end.
 350
 351-spec list_dir(Dir) -> {ok, Filenames} | {error, Reason} when
 352      Dir :: name_all(),
 353      Filenames :: [filename()],
 354      Reason :: posix()
 355              | badarg
 356              | {no_translation, Filename :: unicode:latin1_binary()}.
 357
 358list_dir(Name) ->
 359    check_and_call(list_dir, [file_name(Name)]).
 360
 361-spec list_dir_all(Dir) -> {ok, Filenames} | {error, Reason} when
 362      Dir :: name_all(),
 363      Filenames :: [filename_all()],
 364      Reason :: posix() | badarg.
 365
 366list_dir_all(Name) ->
 367    check_and_call(list_dir_all, [file_name(Name)]).
 368
 369-spec read_file(Filename) -> {ok, Binary} | {error, Reason} when
 370      Filename :: name_all(),
 371      Binary :: binary(),
 372      Reason :: posix() | badarg | terminated | system_limit.
 373
 374read_file(Name) ->
 375    check_and_call(read_file, [file_name(Name)]).
 376
 377-spec make_link(Existing, New) -> ok | {error, Reason} when
 378      Existing :: name_all(),
 379      New :: name_all(),
 380      Reason :: posix() | badarg.
 381
 382make_link(Old, New) ->
 383    check_and_call(make_link, [file_name(Old), file_name(New)]).
 384
 385-spec make_symlink(Existing, New) -> ok | {error, Reason} when
 386      Existing :: name_all(),
 387      New :: name_all(),
 388      Reason :: posix() | badarg.
 389
 390make_symlink(Old, New) ->
 391    check_and_call(make_symlink, [file_name(Old), file_name(New)]).
 392
 393-spec write_file(Filename, Bytes) -> ok | {error, Reason} when
 394      Filename :: name_all(),
 395      Bytes :: iodata(),
 396      Reason :: posix() | badarg | terminated | system_limit.
 397
 398write_file(Name, Bin) ->
 399    check_and_call(write_file, [file_name(Name), make_binary(Bin)]).
 400
 401%% This whole operation should be moved to the file_server and prim_file
 402%% when it is time to change file server protocol again.
 403%% Meanwhile, it is implemented here, slightly less efficient.
 404
 405-spec write_file(Filename, Bytes, Modes) -> ok | {error, Reason} when
 406      Filename :: name_all(),
 407      Bytes :: iodata(),
 408      Modes :: [mode()],
 409      Reason :: posix() | badarg | terminated | system_limit.
 410
 411write_file(Name, IOData, ModeList) when is_list(ModeList) ->
 412    case lists:member(raw, ModeList) of
 413        true ->
 414          %% For backwards compatibility of error messages
 415            try iolist_size(IOData) of
 416                _Size -> do_write_file(Name, IOData, ModeList)
 417            catch
 418                error:Error -> {error, Error}
 419            end;
 420        false ->
 421            case make_binary(IOData) of
 422                Bin when is_binary(Bin) ->
 423                    do_write_file(Name, Bin, ModeList);
 424                Error ->
 425                    Error
 426            end
 427    end.
 428
 429do_write_file(Name, IOData, ModeList) ->
 430    case open(Name, [binary, write | ModeList]) of
 431        {ok, Handle} ->
 432            case write(Handle, IOData) of
 433                ok ->
 434                    close(Handle);
 435                E1 ->
 436                    _ = close(Handle),
 437                    E1
 438            end;
 439        E2 ->
 440            E2
 441    end.
 442
 443%% Obsolete, undocumented, local node only, don't use!.
 444%% XXX to be removed.
 445raw_read_file_info(Name) ->
 446    read_file_info(Name, [raw]).
 447
 448%% Obsolete, undocumented, local node only, don't use!.
 449%% XXX to be removed.
 450raw_write_file_info(Name, #file_info{} = Info) ->
 451    write_file_info(Name, Info, [raw]).
 452
 453%%%-----------------------------------------------------------------
 454%%% File io server functions.
 455%%% They operate on a single open file.
 456%%% Stateful.
 457
 458%% Contemporary mode specification - list of options
 459
 460-spec open(File, Modes) -> {ok, IoDevice} | {error, Reason} when
 461      File :: Filename | iodata(),
 462      Filename :: name_all(),
 463      Modes :: [mode() | ram],
 464      IoDevice :: io_device(),
 465      Reason :: posix() | badarg | system_limit.
 466
 467open(Item, ModeList) when is_list(ModeList) ->
 468    case {lists:member(raw, ModeList), lists:member(ram, ModeList)} of
 469        {false, false} ->
 470            %% File server file
 471            Args = [file_name(Item) | ModeList],
 472            case check_args(Args) of
 473                ok ->
 474                    [FileName | _] = Args,
 475                    call(open, [FileName, ModeList]);
 476                Error ->
 477                    Error
 478            end;
 479        {true, _Either} ->
 480            raw_file_io:open(file_name(Item), ModeList);
 481        {false, true} ->
 482            ram_file:open(Item, ModeList)
 483    end;
 484
 485%% Old obsolete mode specification in atom or 2-tuple format
 486open(Item, Mode) ->
 487    open(Item, mode_list(Mode)).
 488
 489%%%-----------------------------------------------------------------
 490%%% The following interface functions operate on open files.
 491%%% The File argument must be either a Pid or a handle 
 492%%% returned from ?PRIM_FILE:open.
 493
 494-spec close(IoDevice) -> ok | {error, Reason} when
 495      IoDevice :: io_device(),
 496      Reason :: posix() | badarg | terminated.
 497
 498close(File) when is_pid(File) ->
 499    case file_request(File, close) of
 500	{error, terminated} ->
 501	    ok;
 502	Other ->
 503	    Other
 504    end;
 505%%    unlink(File),
 506%%    exit(File, close),
 507%%    ok;
 508close(#file_descriptor{module = Module} = Handle) ->
 509    Module:close(Handle);
 510close(_) ->
 511    {error, badarg}.
 512
 513-spec advise(IoDevice, Offset, Length, Advise) -> ok | {error, Reason} when
 514      IoDevice :: io_device(),
 515      Offset :: integer(),
 516      Length :: integer(),
 517      Advise :: posix_file_advise(),
 518      Reason :: posix() | badarg.
 519
 520advise(File, Offset, Length, Advise) when is_pid(File) ->
 521    file_request(File, {advise, Offset, Length, Advise});
 522advise(#file_descriptor{module = Module} = Handle, Offset, Length, Advise) ->
 523    Module:advise(Handle, Offset, Length, Advise);
 524advise(_, _, _, _) ->
 525    {error, badarg}.
 526
 527-spec allocate(File, Offset, Length) ->
 528	'ok' | {'error', posix()} when
 529      File :: io_device(),
 530      Offset :: non_neg_integer(),
 531      Length :: non_neg_integer().
 532
 533allocate(File, Offset, Length) when is_pid(File) ->
 534    file_request(File, {allocate, Offset, Length});
 535allocate(#file_descriptor{module = Module} = Handle, Offset, Length) ->
 536    Module:allocate(Handle, Offset, Length).
 537
 538-spec read(IoDevice, Number) -> {ok, Data} | eof | {error, Reason} when
 539      IoDevice :: io_device() | atom(),
 540      Number :: non_neg_integer(),
 541      Data :: string() | binary(),
 542      Reason :: posix()
 543              | badarg
 544              | terminated
 545              | {no_translation, unicode, latin1}.
 546
 547read(File, Sz) when (is_pid(File) orelse is_atom(File)), is_integer(Sz), Sz >= 0 ->
 548    case io:request(File, {get_chars, '', Sz}) of
 549	Data when is_list(Data); is_binary(Data) ->
 550	    {ok, Data};
 551	Other ->
 552	    Other
 553    end;
 554read(#file_descriptor{module = Module} = Handle, Sz) 
 555  when is_integer(Sz), Sz >= 0 ->
 556    Module:read(Handle, Sz);
 557read(_, _) ->
 558    {error, badarg}.
 559
 560-spec read_line(IoDevice) -> {ok, Data} | eof | {error, Reason} when
 561      IoDevice :: io_device() | atom(),
 562      Data :: string() | binary(),
 563      Reason :: posix()
 564              | badarg
 565              | terminated
 566              | {no_translation, unicode, latin1}.
 567
 568read_line(File) when (is_pid(File) orelse is_atom(File)) ->
 569    case io:request(File, {get_line, ''}) of
 570	Data when is_list(Data); is_binary(Data) ->
 571	    {ok, Data};
 572	Other ->
 573	    Other
 574    end;
 575read_line(#file_descriptor{module = Module} = Handle) ->
 576    Module:read_line(Handle);
 577read_line(_) ->
 578    {error, badarg}.
 579
 580-spec pread(IoDevice, LocNums) -> {ok, DataL} | eof | {error, Reason} when
 581      IoDevice :: io_device(),
 582      LocNums :: [{Location :: location(), Number :: non_neg_integer()}],
 583      DataL :: [Data],
 584      Data :: string() | binary() | eof,
 585      Reason :: posix() | badarg | terminated.
 586
 587pread(File, L) when is_pid(File), is_list(L) ->
 588    pread_int(File, L, []);
 589pread(#file_descriptor{module = Module} = Handle, L) when is_list(L) ->
 590    Module:pread(Handle, L);
 591pread(_, _) ->
 592    {error, badarg}.
 593
 594pread_int(_File, [], R) ->
 595    {ok, lists:reverse(R)};
 596pread_int(File, [{At, Sz} | T], R) when is_integer(Sz), Sz >= 0 ->
 597    case pread(File, At, Sz) of
 598	{ok, Data} ->
 599	    pread_int(File, T, [Data | R]);
 600	eof ->
 601	    pread_int(File, T, [eof | R]);
 602	{error, _} = Error ->
 603	    Error
 604    end;
 605pread_int(_, _, _) ->
 606    {error, badarg}.
 607
 608-spec pread(IoDevice, Location, Number) ->
 609             {ok, Data} | eof | {error, Reason} when
 610      IoDevice :: io_device(),
 611      Location :: location(),
 612      Number :: non_neg_integer(),
 613      Data :: string() | binary(),
 614      Reason :: posix() | badarg | terminated.
 615
 616pread(File, At, Sz) when is_pid(File), is_integer(Sz), Sz >= 0 ->
 617    file_request(File, {pread, At, Sz});
 618pread(#file_descriptor{module = Module} = Handle, Offs, Sz) 
 619  when is_integer(Sz), Sz >= 0 ->
 620    Module:pread(Handle, Offs, Sz);
 621pread(_, _, _) ->
 622    {error, badarg}.
 623
 624-spec write(IoDevice, Bytes) -> ok | {error, Reason} when
 625      IoDevice :: io_device() | atom(),
 626      Bytes :: iodata(),
 627      Reason :: posix() | badarg | terminated.
 628
 629write(File, Bytes) when (is_pid(File) orelse is_atom(File)) ->
 630    case make_binary(Bytes) of
 631	Bin when is_binary(Bin) ->
 632	    io:request(File, {put_chars,latin1,Bin});
 633	Error ->
 634	    Error
 635    end;
 636write(#file_descriptor{module = Module} = Handle, Bytes) ->
 637    Module:write(Handle, Bytes);
 638write(_, _) ->
 639    {error, badarg}.
 640
 641-spec pwrite(IoDevice, LocBytes) -> ok | {error, {N, Reason}} when
 642      IoDevice :: io_device(),
 643      LocBytes :: [{Location :: location(), Bytes :: iodata()}],
 644      N :: non_neg_integer(),
 645      Reason :: posix() | badarg | terminated.
 646
 647pwrite(File, L) when is_pid(File), is_list(L) ->
 648    pwrite_int(File, L, 0);
 649pwrite(#file_descriptor{module = Module} = Handle, L) when is_list(L) ->
 650    Module:pwrite(Handle, L);
 651pwrite(_, _) ->
 652    {error, badarg}.
 653
 654pwrite_int(_File, [], _R) ->
 655    ok;
 656pwrite_int(File, [{At, Bytes} | T], R) ->
 657    case pwrite(File, At, Bytes) of
 658	ok ->
 659	    pwrite_int(File, T, R+1);
 660	{error, Reason} ->
 661	    {error, {R, Reason}}
 662    end;
 663pwrite_int(_, _, _) ->
 664    {error, badarg}.
 665
 666-spec pwrite(IoDevice, Location, Bytes) -> ok | {error, Reason} when
 667      IoDevice :: io_device(),
 668      Location :: location(),
 669      Bytes :: iodata(),
 670      Reason :: posix() | badarg | terminated.
 671
 672pwrite(File, At, Bytes) when is_pid(File) ->
 673    file_request(File, {pwrite, At, Bytes});
 674pwrite(#file_descriptor{module = Module} = Handle, Offs, Bytes) ->
 675    Module:pwrite(Handle, Offs, Bytes);
 676pwrite(_, _, _) ->
 677    {error, badarg}.
 678
 679-spec datasync(IoDevice) -> ok | {error, Reason} when
 680      IoDevice :: io_device(),
 681      Reason :: posix() | badarg | terminated.
 682
 683datasync(File) when is_pid(File) ->
 684    file_request(File, datasync);
 685datasync(#file_descriptor{module = Module} = Handle) ->
 686    Module:datasync(Handle);
 687datasync(_) ->
 688    {error, badarg}.
 689
 690-spec sync(IoDevice) -> ok | {error, Reason} when
 691      IoDevice :: io_device(),
 692      Reason :: posix() | badarg | terminated.
 693
 694sync(File) when is_pid(File) ->
 695    file_request(File, sync);
 696sync(#file_descriptor{module = Module} = Handle) ->
 697    Module:sync(Handle);
 698sync(_) ->
 699    {error, badarg}.
 700
 701-spec position(IoDevice, Location) -> {ok, NewPosition} | {error, Reason} when
 702      IoDevice :: io_device(),
 703      Location :: location(),
 704      NewPosition :: integer(),
 705      Reason :: posix() | badarg | terminated.
 706
 707position(File, At) when is_pid(File) ->
 708    file_request(File, {position,At});
 709position(#file_descriptor{module = Module} = Handle, At) ->
 710    Module:position(Handle, At);
 711position(_, _) ->
 712    {error, badarg}.
 713
 714-spec truncate(IoDevice) -> ok | {error, Reason} when
 715      IoDevice :: io_device(),
 716      Reason :: posix() | badarg | terminated.
 717
 718truncate(File) when is_pid(File) ->
 719    file_request(File, truncate);
 720truncate(#file_descriptor{module = Module} = Handle) ->
 721    Module:truncate(Handle);
 722truncate(_) ->
 723    {error, badarg}.
 724
 725-spec copy(Source, Destination) -> {ok, BytesCopied} | {error, Reason} when
 726      Source :: io_device() | Filename | {Filename, Modes},
 727      Destination :: io_device() | Filename | {Filename, Modes},
 728      Filename :: name_all(),
 729      Modes :: [mode()],
 730      BytesCopied :: non_neg_integer(),
 731      Reason :: posix() | badarg | terminated.
 732
 733copy(Source, Dest) ->
 734    copy_int(Source, Dest, infinity).
 735
 736-spec copy(Source, Destination, ByteCount) ->
 737             {ok, BytesCopied} | {error, Reason} when
 738      Source :: io_device() | Filename | {Filename, Modes},
 739      Destination :: io_device() | Filename | {Filename, Modes},
 740      Filename :: name_all(),
 741      Modes :: [mode()],
 742      ByteCount :: non_neg_integer() | infinity,
 743      BytesCopied :: non_neg_integer(),
 744      Reason :: posix() | badarg | terminated.
 745
 746copy(Source, Dest, Length) 
 747  when is_integer(Length), Length >= 0;
 748       is_atom(Length) ->
 749    copy_int(Source, Dest, Length);
 750copy(_, _, _) ->
 751    {error, badarg}.
 752
 753%% Here we know that Length is either an atom or an integer >= 0
 754%% (by the way, atoms > integers)
 755%%
 756%% Copy between open files. 
 757copy_int(Source, Dest, Length) 
 758  when is_pid(Source), is_pid(Dest);
 759       is_pid(Source), is_record(Dest, file_descriptor);
 760       is_record(Source, file_descriptor), is_pid(Dest) ->
 761    copy_opened_int(Source, Dest, Length, 0);
 762%% Copy between open raw files, both handled by the same module
 763copy_int(#file_descriptor{module = Module} = Source,
 764	 #file_descriptor{module = Module} = Dest,
 765	 Length) ->
 766    Module:copy(Source, Dest, Length);
 767%% Copy between open raw files of different modules
 768copy_int(#file_descriptor{} = Source, 
 769	 #file_descriptor{} = Dest, Length) ->
 770    copy_opened_int(Source, Dest, Length, 0);
 771%% Copy between filenames, let the server do the copy
 772copy_int({SourceName, SourceOpts}, {DestName, DestOpts}, Length) 
 773  when is_list(SourceOpts), is_list(DestOpts) ->
 774    check_and_call(copy, 
 775		   [file_name(SourceName), SourceOpts,
 776		    file_name(DestName), DestOpts,
 777		    Length]);
 778%% Filename -> open file; must open Source and do client copy
 779copy_int({SourceName, SourceOpts}, Dest, Length) 
 780  when is_list(SourceOpts), is_pid(Dest);
 781       is_list(SourceOpts), is_record(Dest, file_descriptor) ->
 782    case file_name(SourceName) of
 783	{error, _} = Error ->
 784	    Error;
 785	Source ->
 786	    case open(Source, [read | SourceOpts]) of
 787		{ok, Handle} ->
 788		    Result = copy_opened_int(Handle, Dest, Length, 0),
 789		    _ = close(Handle),
 790		    Result;
 791		{error, _} = Error ->
 792		    Error
 793	    end
 794    end;
 795%% Open file -> filename; must open Dest and do client copy
 796copy_int(Source, {DestName, DestOpts}, Length)
 797  when is_pid(Source), is_list(DestOpts);
 798       is_record(Source, file_descriptor), is_list(DestOpts) ->
 799    case file_name(DestName) of
 800	{error, _} = Error ->
 801	    Error;
 802	Dest ->
 803	    case open(Dest, [write | DestOpts]) of
 804		{ok, Handle} ->
 805                    case copy_opened_int(Source, Handle, Length, 0) of
 806                        {ok, _} = OK ->
 807                            case close(Handle) of
 808                                ok -> OK;
 809                                Error -> Error
 810                            end;
 811                        Error ->
 812                            _ = close(Handle),
 813                            Error
 814                    end;
 815		{error, _} = Error ->
 816		    Error
 817	    end
 818    end;
 819%%
 820%% That was all combinations of {Name, Opts} tuples
 821%% and open files. At least one of Source and Dest has
 822%% to be a bare filename.
 823%%
 824%% If Source is not a bare filename; Dest must be
 825copy_int(Source, Dest, Length) 
 826  when is_pid(Source);
 827       is_record(Source, file_descriptor) ->
 828    copy_int(Source, {Dest, []}, Length);
 829copy_int({_SourceName, SourceOpts} = Source, Dest, Length) 
 830  when is_list(SourceOpts) ->
 831    copy_int(Source, {Dest, []}, Length);
 832%% If Dest is not a bare filename; Source must be
 833copy_int(Source, Dest, Length) 
 834  when is_pid(Dest);
 835       is_record(Dest, file_descriptor) ->
 836    copy_int({Source, []}, Dest, Length);
 837copy_int(Source, {_DestName, DestOpts} = Dest, Length) 
 838  when is_list(DestOpts) ->
 839    copy_int({Source, []}, Dest, Length);
 840%% Both must be bare filenames. If they are not,
 841%% the filename check in the copy operation will yell.
 842copy_int(Source, Dest, Length) ->
 843    copy_int({Source, []}, {Dest, []}, Length).
 844
 845
 846
 847copy_opened(Source, Dest, Length)
 848  when is_integer(Length), Length >= 0;
 849       is_atom(Length) ->
 850    copy_opened_int(Source, Dest, Length);
 851copy_opened(_, _, _) ->
 852    {error, badarg}.
 853
 854%% Here we know that Length is either an atom or an integer >= 0
 855%% (by the way, atoms > integers)
 856
 857copy_opened_int(Source, Dest, Length)
 858  when is_pid(Source), is_pid(Dest) ->
 859    copy_opened_int(Source, Dest, Length, 0);
 860copy_opened_int(Source, Dest, Length)
 861  when is_pid(Source), is_record(Dest, file_descriptor) ->
 862    copy_opened_int(Source, Dest, Length, 0);
 863copy_opened_int(Source, Dest, Length)
 864  when is_record(Source, file_descriptor), is_pid(Dest) ->
 865    copy_opened_int(Source, Dest, Length, 0);
 866copy_opened_int(Source, Dest, Length)
 867  when is_record(Source, file_descriptor), is_record(Dest, file_descriptor) ->
 868    copy_opened_int(Source, Dest, Length, 0);
 869copy_opened_int(_, _, _) ->
 870    {error, badarg}.
 871
 872%% Here we know that Source and Dest are handles to open files, Length is
 873%% as above, and Copied is an integer >= 0
 874
 875%% Copy loop in client process
 876copy_opened_int(_, _, Length, Copied) when Length =< 0 -> % atom() > integer()
 877    {ok, Copied};
 878copy_opened_int(Source, Dest, Length, Copied) ->
 879    N = if Length > 65536 -> 65536; true -> Length end, % atom() > integer() !
 880    case read(Source, N) of
 881	{ok, Data} ->
 882	    M = if is_binary(Data) -> byte_size(Data);
 883		   is_list(Data)   -> length(Data)
 884		end,
 885	    case write(Dest, Data) of
 886		ok ->
 887		    if M < N ->
 888			    %% Got less than asked for - must be end of file
 889			    {ok, Copied+M};
 890		       true ->
 891			    %% Decrement Length (might be an atom (infinity))
 892			    NewLength = if is_atom(Length) -> Length;
 893					   true         -> Length-M
 894					end,
 895			    copy_opened_int(Source, Dest, NewLength, Copied+M)
 896		    end;
 897		{error, _} = Error ->
 898		    Error
 899	    end;
 900	eof ->
 901	    {ok, Copied};
 902	{error, _} = Error ->
 903	    Error
 904    end.
 905
 906
 907%% Special indirect pread function. Introduced for Dets.
 908%% Reads a header from pos 'Pos', the header is first a size encoded as
 909%% 32 bit big endian unsigned and then a position also encoded as
 910%% 32 bit big endian. Finally it preads the data from that pos and size 
 911%% in the file.
 912
 913ipread_s32bu_p32bu(File, Pos, MaxSize) when is_pid(File) ->
 914    ipread_s32bu_p32bu_int(File, Pos, MaxSize);
 915ipread_s32bu_p32bu(#file_descriptor{module = Module} = Handle, Pos, MaxSize) ->
 916    Module:ipread_s32bu_p32bu(Handle, Pos, MaxSize);
 917ipread_s32bu_p32bu(_, _, _) ->
 918    {error, badarg}.
 919
 920ipread_s32bu_p32bu_int(File, Pos, Infinity) when is_atom(Infinity) ->
 921    ipread_s32bu_p32bu_int(File, Pos, (1 bsl 31)-1);
 922ipread_s32bu_p32bu_int(File, Pos, MaxSize) 
 923  when is_integer(MaxSize), MaxSize >= 0 ->
 924    if
 925	MaxSize < (1 bsl 31) ->
 926	    case pread(File, Pos, 8) of
 927		{ok, Header} ->
 928		    ipread_s32bu_p32bu_2(File, Header, MaxSize);
 929		Error ->
 930		    Error
 931	    end;
 932	true ->
 933	    {error, einval}
 934    end;
 935ipread_s32bu_p32bu_int(_File, _Pos, _MaxSize) ->
 936    {error, badarg}.
 937
 938ipread_s32bu_p32bu_2(_File, 
 939		     <<0:32/big-unsigned, Pos:32/big-unsigned>>,
 940		     _MaxSize) ->
 941    {ok, {0, Pos, eof}};
 942ipread_s32bu_p32bu_2(File, 
 943		     <<Size:32/big-unsigned, Pos:32/big-unsigned>>,
 944		     MaxSize) 
 945  when Size =< MaxSize ->
 946    case pread(File, Pos, Size) of
 947	{ok, Data} ->
 948	    {ok, {Size, Pos, Data}};
 949	eof ->
 950	    {ok, {Size, Pos, eof}};
 951	Error ->
 952	    Error
 953    end;
 954ipread_s32bu_p32bu_2(_File, 
 955		     <<_:8/binary>>,
 956		     _MaxSize) ->
 957    eof;
 958ipread_s32bu_p32bu_2(_File,
 959		     <<_/binary>>,
 960		     _MaxSize) ->
 961    eof;
 962ipread_s32bu_p32bu_2(File,
 963		    Header,
 964		    MaxSize) when is_list(Header) ->
 965    ipread_s32bu_p32bu_2(File, list_to_binary(Header), MaxSize).
 966
 967
 968
 969%%%-----------------------------------------------------------------
 970%%% The following functions, built upon the other interface functions,
 971%%% provide a higher-lever interface to files.
 972
 973-spec consult(Filename) -> {ok, Terms} | {error, Reason} when
 974      Filename :: name_all(),
 975      Terms :: [term()],
 976      Reason :: posix() | badarg | terminated | system_limit
 977              | {Line :: integer(), Mod :: module(), Term :: term()}.
 978
 979consult(File) ->
 980    case open(File, [read]) of
 981	{ok, Fd} ->
 982	    R = consult_stream(Fd),
 983	    _ = close(Fd),
 984	    R;
 985	Error ->
 986	    Error
 987    end.
 988
 989-spec path_consult(Path, Filename) -> {ok, Terms, FullName} | {error, Reason} when
 990      Path :: [Dir],
 991      Dir :: name_all(),
 992      Filename :: name_all(),
 993      Terms :: [term()],
 994      FullName :: filename_all(),
 995      Reason :: posix() | badarg | terminated | system_limit
 996              | {Line :: integer(), Mod :: module(), Term :: term()}.
 997
 998path_consult(Path, File) ->
 999    case path_open(Path, File, [read]) of
1000	{ok, Fd, Full} ->
1001	    case consult_stream(Fd) of
1002		{ok, List} ->
1003		    _ = close(Fd),
1004		    {ok, List, Full};
1005		E1 ->
1006		    _ = close(Fd),
1007		    E1
1008	    end;
1009	E2 ->
1010	    E2
1011    end.
1012
1013-spec eval(Filename) -> ok | {error, Reason} when
1014      Filename :: name_all(),
1015      Reason :: posix() | badarg | terminated | system_limit
1016              | {Line :: integer(), Mod :: module(), Term :: term()}.
1017
1018eval(File) ->
1019    eval(File, erl_eval:new_bindings()).
1020
1021-spec eval(Filename, Bindings) -> ok | {error, Reason} when
1022      Filename :: name_all(),
1023      Bindings :: erl_eval:binding_struct(),
1024      Reason :: posix() | badarg | terminated | system_limit
1025              | {Line :: integer(), Mod :: module(), Term :: term()}.
1026
1027eval(File, Bs) ->
1028    case open(File, [read]) of
1029	{ok, Fd} ->
1030	    R = eval_stream(Fd, ignore, Bs),
1031	    _ = close(Fd),
1032	    R;
1033	Error ->
1034	    Error
1035    end.
1036
1037-spec path_eval(Path, Filename) -> {ok, FullName} | {error, Reason} when
1038      Path :: [Dir :: name_all()],
1039      Filename :: name_all(),
1040      FullName :: filename_all(),
1041      Reason :: posix() | badarg | terminated | system_limit
1042              | {Line :: integer(), Mod :: module(), Term :: term()}.
1043
1044path_eval(Path, File) ->
1045    path_eval(Path, File, erl_eval:new_bindings()).
1046
1047-spec path_eval(Path, Filename, Bindings) ->
1048             {ok, FullName} | {error, Reason} when
1049      Path :: [Dir :: name_all()],
1050      Filename :: name_all(),
1051      Bindings :: erl_eval:binding_struct(),
1052      FullName :: filename_all(),
1053      Reason :: posix() | badarg | terminated | system_limit
1054              | {Line :: integer(), Mod :: module(), Term :: term()}.
1055
1056path_eval(Path, File, Bs) ->
1057    case path_open(Path, File, [read]) of
1058	{ok, Fd, Full} ->
1059	    case eval_stream(Fd, ignore, Bs) of
1060		ok ->
1061		    _ = close(Fd),
1062		    {ok, Full};
1063		E1 ->
1064		    _ = close(Fd),
1065		    E1
1066	    end;
1067	E2 ->
1068	    E2
1069    end.
1070
1071-spec script(Filename) -> {ok, Value} | {error, Reason} when
1072      Filename :: name_all(),
1073      Value :: term(),
1074      Reason :: posix() | badarg | terminated | system_limit
1075              | {Line :: integer(), Mod :: module(), Term :: term()}.
1076
1077script(File) ->
1078    script(File, erl_eval:new_bindings()).
1079
1080-spec script(Filename, Bindings) -> {ok, Value} | {error, Reason} when
1081      Filename :: name_all(),
1082      Bindings :: erl_eval:binding_struct(),
1083      Value :: term(),
1084      Reason :: posix() | badarg | terminated | system_limit
1085              | {Line :: integer(), Mod :: module(), Term :: term()}.
1086
1087script(File, Bs) ->
1088    case open(File, [read]) of
1089	{ok, Fd} ->
1090	    R = eval_stream(Fd, return, Bs),
1091	    _ = close(Fd),
1092	    R;
1093	Error ->
1094	    Error
1095    end.
1096
1097-spec path_script(Path, Filename) ->
1098             {ok, Value, FullName} | {error, Reason} when
1099      Path :: [Dir :: name_all()],
1100      Filename :: name_all(),
1101      Value :: term(),
1102      FullName :: filename_all(),
1103      Reason :: posix() | badarg | terminated | system_limit
1104              | {Line :: integer(), Mod :: module(), Term :: term()}.
1105
1106path_script(Path, File) ->
1107    path_script(Path, File, erl_eval:new_bindings()).
1108
1109-spec path_script(Path, Filename, Bindings) ->
1110          {ok, Value, FullName} | {error, Reason} when
1111      Path :: [Dir :: name_all()],
1112      Filename :: name_all(),
1113      Bindings :: erl_eval:binding_struct(),
1114      Value :: term(),
1115      FullName :: filename_all(),
1116      Reason :: posix() | badarg | terminated | system_limit
1117              | {Line :: integer(), Mod :: module(), Term :: term()}.
1118
1119path_script(Path, File, Bs) ->
1120    case path_open(Path, File, [read]) of
1121	{ok,Fd,Full} ->
1122	    case eval_stream(Fd, return, Bs) of
1123		{ok,R} ->
1124		    _ = close(Fd),
1125		    {ok, R, Full};
1126		E1 ->
1127		    _ = close(Fd),
1128		    E1
1129	    end;
1130	E2 ->
1131	    E2
1132    end.
1133    
1134
1135%% path_open(Paths, Filename, Mode) ->
1136%%	{ok,FileDescriptor,FullName}
1137%%	{error,Reason}
1138%%
1139%% Searches the Paths for file Filename which can be opened with Mode.
1140%% The path list is ignored if Filename contains an absolute path.
1141
1142-spec path_open(Path, Filename, Modes) ->
1143             {ok, IoDevice, FullName} | {error, Reason} when
1144      Path :: [Dir :: name_all()],
1145      Filename :: name_all(),
1146      Modes :: [mode()],
1147      IoDevice :: io_device(),
1148      FullName :: filename_all(),
1149      Reason :: posix() | badarg | system_limit.
1150
1151path_open(PathList, Name, Mode) ->
1152    case file_name(Name) of
1153	{error, _} = Error ->
1154	    Error;
1155	FileName ->
1156	    case filename:pathtype(FileName) of
1157		relative ->
1158		    path_open_first(PathList, FileName, Mode, enoent);
1159		_ ->
1160		    case open(Name, Mode) of
1161			{ok, Fd} ->
1162			    {ok, Fd, Name};
1163			Error ->
1164			    Error
1165		    end
1166	    end
1167    end.
1168
1169-spec change_mode(Filename, Mode) -> ok | {error, Reason} when
1170      Filename :: name_all(),
1171      Mode :: integer(),
1172      Reason :: posix() | badarg.
1173
1174change_mode(Name, Mode) 
1175  when is_integer(Mode) ->
1176    write_file_info(Name, #file_info{mode=Mode}).
1177
1178-spec change_owner(Filename, Uid) -> ok | {error, Reason} when
1179      Filename :: name_all(),
1180      Uid :: integer(),
1181      Reason :: posix() | badarg.
1182
1183change_owner(Name, OwnerId) 
1184  when is_integer(OwnerId) ->
1185    write_file_info(Name, #file_info{uid=OwnerId}).
1186
1187-spec change_owner(Filename, Uid, Gid) -> ok | {error, Reason} when
1188      Filename :: name_all(),
1189      Uid :: integer(),
1190      Gid :: integer(),
1191      Reason :: posix() | badarg.
1192
1193change_owner(Name, OwnerId, GroupId) 
1194  when is_integer(OwnerId), is_integer(GroupId) ->
1195    write_file_info(Name, #file_info{uid=OwnerId, gid=GroupId}).
1196
1197-spec change_group(Filename, Gid) -> ok | {error, Reason} when
1198      Filename :: name_all(),
1199      Gid :: integer(),
1200      Reason :: posix() | badarg.
1201
1202change_group(Name, GroupId) 
1203  when is_integer(GroupId) ->
1204    write_file_info(Name, #file_info{gid=GroupId}).
1205
1206-spec change_time(Filename, Mtime) -> ok | {error, Reason} when
1207      Filename :: name_all(),
1208      Mtime :: date_time(),
1209      Reason :: posix() | badarg.
1210
1211change_time(Name, {{Y, M, D}, {H, Min, Sec}}=Time)
1212  when is_integer(Y), is_integer(M), is_integer(D),
1213       is_integer(H), is_integer(Min), is_integer(Sec)->
1214    write_file_info(Name, #file_info{mtime=Time}).
1215
1216-spec change_time(Filename, Atime, Mtime) -> ok | {error, Reason} when
1217      Filename :: name_all(),
1218      Atime :: date_time(),
1219      Mtime :: date_time(),
1220      Reason :: posix() | badarg.
1221
1222change_time(Name, {{AY, AM, AD}, {AH, AMin, ASec}}=Atime,
1223         {{MY, MM, MD}, {MH, MMin, MSec}}=Mtime)
1224  when is_integer(AY), is_integer(AM), is_integer(AD),
1225       is_integer(AH), is_integer(AMin), is_integer(ASec),
1226       is_integer(MY), is_integer(MM), is_integer(MD),
1227       is_integer(MH), is_integer(MMin), is_integer(MSec)->
1228    write_file_info(Name, #file_info{atime=Atime, mtime=Mtime}).
1229
1230%%
1231%% Send data using sendfile
1232%%
1233
1234%% 1 MB, Windows seems to behave badly if it is much larger then this
1235-define(MAX_CHUNK_SIZE, (1 bsl 20)).
1236
1237-spec sendfile(RawFile, Socket, Offset, Bytes, Opts) ->
1238   {'ok', non_neg_integer()} | {'error', inet:posix() | 
1239				closed | badarg | not_owner} when
1240      RawFile :: fd(),
1241      Socket :: inet:socket(),
1242      Offset :: non_neg_integer(),
1243      Bytes :: non_neg_integer(),
1244      Opts :: [sendfile_option()].
1245sendfile(File, _Sock, _Offet, _Bytes, _Opts) when is_pid(File) ->
1246    {error, badarg};
1247sendfile(File, Sock, Offset, Bytes, []) ->
1248    sendfile(File, Sock, Offset, Bytes, ?MAX_CHUNK_SIZE, [], [], []);
1249sendfile(File, Sock, Offset, Bytes, Opts) ->
1250    try proplists:get_value(chunk_size, Opts, ?MAX_CHUNK_SIZE) of
1251        ChunkSize0 when is_integer(ChunkSize0) ->
1252            ChunkSize = erlang:min(ChunkSize0, ?MAX_CHUNK_SIZE),
1253            %% Support for headers, trailers and options has been removed
1254            %% because the Darwin and BSD API for using it does not play nice
1255            %% with non-blocking sockets. See unix_efile.c for more info.
1256            sendfile(File, Sock, Offset, Bytes, ChunkSize, [], [], Opts);
1257        _Other ->
1258            {error, badarg}
1259    catch
1260        error:_ -> {error, badarg}
1261    end.
1262
1263%% sendfile/2
1264-spec sendfile(Filename, Socket) ->
1265   {'ok', non_neg_integer()} | {'error', inet:posix() | 
1266				closed | badarg | not_owner}
1267      when Filename :: name_all(),
1268	   Socket :: inet:socket().
1269sendfile(Filename, Sock)  ->
1270    case file:open(Filename, [read, raw, binary]) of
1271	{error, Reason} ->
1272	    {error, Reason};
1273	{ok, Fd} ->
1274	    Res = sendfile(Fd, Sock, 0, 0, []),
1275	    _ = file:close(Fd),
1276	    Res
1277    end.
1278
1279%% Internal sendfile functions
1280sendfile(#file_descriptor{ module = Mod } = Fd, Sock, Offset, Bytes,
1281	 ChunkSize, Headers, Trailers, Opts)
1282  when is_port(Sock) ->
1283    case Mod:sendfile(Fd, Sock, Offset, Bytes, ChunkSize, Headers, Trailers,
1284		      Opts) of
1285	{error, enotsup} ->
1286	    sendfile_fallback(Fd, Sock, Offset, Bytes, ChunkSize,
1287			      Headers, Trailers);
1288	Else ->
1289	    Else
1290    end;
1291sendfile(_,_,_,_,_,_,_,_) ->
1292    {error, badarg}.
1293
1294%%%
1295%% Sendfile Fallback
1296%%%
1297sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize,
1298		  Headers, Trailers)
1299  when Headers == []; is_integer(Headers) ->
1300    case sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize) of
1301	{ok, BytesSent} when is_list(Trailers),
1302			     Trailers =/= [],
1303			     is_integer(Headers) ->
1304	    sendfile_send(Sock, Trailers, BytesSent+Headers);
1305	{ok, BytesSent} when is_list(Trailers), Trailers =/= [] ->
1306	    sendfile_send(Sock, Trailers, BytesSent);
1307	{ok, BytesSent} when is_integer(Headers) ->
1308	    {ok, BytesSent + Headers};
1309	Else ->
1310	    Else
1311    end;
1312sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, Headers, Trailers) ->
1313    case sendfile_send(Sock, Headers, 0) of
1314	{ok, BytesSent} ->
1315	    sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, BytesSent,
1316			      Trailers);
1317	Else ->
1318	    Else
1319    end.
1320
1321
1322sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize) ->
1323    {ok, CurrPos} = file:position(File, {cur, 0}),
1324    {ok, _NewPos} = file:position(File, {bof, Offset}),
1325    Res = sendfile_fallback_int(File, Sock, Bytes, ChunkSize, 0),
1326    _ = file:position(File, {bof, CurrPos}),
1327    Res.
1328
1329
1330sendfile_fallback_int(File, Sock, Bytes, ChunkSize, BytesSent)
1331  when Bytes > BytesSent; Bytes == 0 ->
1332    Size = if Bytes == 0 ->
1333		   ChunkSize;
1334	       (Bytes - BytesSent) < ChunkSize ->
1335		   Bytes - BytesSent;
1336	      true ->
1337		   ChunkSize
1338	   end,
1339    case file:read(File, Size) of
1340	{ok, Data} ->
1341	    case sendfile_send(Sock, Data, BytesSent) of
1342		{ok,NewBytesSent} ->
1343		    sendfile_fallback_int(
1344		      File, Sock, Bytes, ChunkSize,
1345		      NewBytesSent);
1346		Error ->
1347		    Error
1348	    end;
1349	eof ->
1350	    {ok, BytesSent};
1351	Error ->
1352	    Error
1353    end;
1354sendfile_fallback_int(_File, _Sock, BytesSent, _ChunkSize, BytesSent) ->
1355    {ok, BytesSent}.
1356
1357sendfile_send(Sock, Data, Old) ->
1358    Len = iolist_size(Data),
1359    case gen_tcp:send(Sock, Data) of
1360	ok ->
1361	    {ok, Len+Old};
1362	Else ->
1363	    Else
1364    end.
1365
1366
1367
1368%%%-----------------------------------------------------------------
1369%%% Helpers
1370
1371consult_stream(Fd) ->
1372    _ = epp:set_encoding(Fd),
1373    consult_stream(Fd, 1, []).
1374
1375consult_stream(Fd, Line, Acc) ->
1376    case io:read(Fd, '', Line) of
1377	{ok,Term,EndLine} ->
1378	    consult_stream(Fd, EndLine, [Term|Acc]);
1379	{error,Error,_Line} ->
1380	    {error,Error};
1381	{eof,_Line} ->
1382	    {ok,lists:reverse(Acc)}
1383    end.
1384
1385eval_stream(Fd, Handling, Bs) ->
1386    _ = epp:set_encoding(Fd),
1387    eval_stream(Fd, Handling, 1, undefined, [], Bs).
1388
1389eval_stream(Fd, H, Line, Last, E, Bs) ->
1390    eval_stream2(io:parse_erl_exprs(Fd, '', Line), Fd, H, Last, E, Bs).
1391
1392eval_stream2({ok,Form,EndLine}, Fd, H, Last, E, Bs0) ->
1393    try erl_eval:exprs(Form, Bs0) of
1394	{value,V,Bs} ->
1395	    eval_stream(Fd, H, EndLine, {V}, E, Bs)
1396    catch Class:Reason:StackTrace ->
1397            Error = {EndLine,?MODULE,{Class,Reason,StackTrace}},
1398	    eval_stream(Fd, H, EndLine, Last, [Error|E], Bs0)
1399    end;
1400eval_stream2({error,What,EndLine}, Fd, H, Last, E, Bs) ->
1401    eval_stream(Fd, H, EndLine, Last, [What | E], Bs);
1402eval_stream2({eof,EndLine}, _Fd, H, Last, E, _Bs) ->
1403    case {H, Last, E} of
1404	{return, {Val}, []} ->
1405	    {ok, Val};
1406	{return, undefined, E} ->
1407	    {error, hd(lists:reverse(E, [{EndLine,?MODULE,undefined_script}]))};
1408	{ignore, _, []} ->
1409	    ok;
1410	{_, _, [_|_] = E} ->
1411	    {error, hd(lists:reverse(E))}
1412    end.
1413
1414path_open_first([Path|Rest], Name, Mode, LastError) ->
1415    case file_name(Path) of
1416	{error, _} = Error ->
1417	    Error;
1418	FilePath ->
1419	    FileName = fname_join(FilePath, Name),
1420	    case open(FileName, Mode) of
1421		{ok, Fd} ->
1422		    {ok, Fd, FileName};
1423		{error, Reason} when Reason =:= enoent; Reason =:= enotdir ->
1424		    path_open_first(Rest, Name, Mode, LastError);
1425		Error ->
1426		    Error
1427	    end
1428    end;
1429path_open_first([], _Name, _Mode, LastError) ->
1430    {error, LastError}.
1431
1432fname_join(".", Name) ->
1433    Name;
1434fname_join(Dir, Name) ->
1435    filename:join(Dir, Name).
1436
1437%%%-----------------------------------------------------------------
1438%%% Utility functions.
1439
1440%% file_name(FileName)
1441%% 	Generates a flat file name from a deep list of atoms and 
1442%% 	characters (integers).
1443
1444file_name(N) when is_binary(N) ->
1445    N;
1446file_name(N) ->
1447    try 
1448        file_name_1(N,file:native_name_encoding())
1449    catch Reason ->
1450        {error, Reason}
1451    end.
1452
1453file_name_1([C|T],latin1) when is_integer(C), C < 256->
1454    [C|file_name_1(T,latin1)];
1455file_name_1([C|T],utf8) when is_integer(C) ->
1456    [C|file_name_1(T,utf8)];
1457file_name_1([H|T],E) ->
1458    file_name_1(H,E) ++ file_name_1(T,E);
1459file_name_1([],_) ->
1460    [];
1461file_name_1(N,_) when is_atom(N) ->
1462    atom_to_list(N);
1463file_name_1(_,_) ->
1464    throw(badarg).
1465
1466make_binary(Bin) when is_binary(Bin) ->
1467    Bin;
1468make_binary(List) ->
1469    %% Convert the list to a binary in order to avoid copying a list
1470    %% to the file server.
1471    try 
1472        erlang:iolist_to_binary(List)
1473    catch error:Reason ->
1474        {error, Reason}
1475    end.
1476
1477mode_list(read) ->
1478    [read];
1479mode_list(write) ->
1480    [write];
1481mode_list(read_write) ->
1482    [read, write];
1483mode_list({binary, Mode}) when is_atom(Mode) ->
1484    [binary | mode_list(Mode)];
1485mode_list({character, Mode}) when is_atom(Mode) ->
1486    mode_list(Mode);
1487mode_list(_) ->
1488    [{error, badarg}].
1489
1490%%-----------------------------------------------------------------
1491%% Functions for communicating with the file server
1492
1493call(Command, Args) when is_list(Args) ->
1494    X = erlang:dt_spread_tag(true),
1495    Y = gen_server:call(?FILE_SERVER, list_to_tuple([Command | Args]), 
1496			infinity),
1497    erlang:dt_restore_tag(X),
1498    Y.
1499
1500check_and_call(Command, Args) when is_list(Args) ->
1501    case check_args(Args) of
1502	ok ->
1503	    call(Command, Args);
1504	Error ->
1505	    Error
1506    end.
1507
1508check_args([{error, _}=Error|_Rest]) ->
1509    Error;
1510check_args([_Name|Rest]) ->
1511    check_args(Rest);
1512check_args([]) ->
1513    ok.
1514
1515%%-----------------------------------------------------------------
1516%% Function for communicating with a file io server.
1517%% The messages sent have the following formats:
1518%%
1519%%	{file_request,From,ReplyAs,Request}
1520%%	{file_reply,ReplyAs,Reply}
1521
1522file_request(Io, Request) ->
1523    Ref = erlang:monitor(process, Io),
1524    Io ! {file_request,self(),Ref,Request},
1525    receive
1526	{file_reply,Ref,Reply} ->
1527	    erlang:demonitor(Ref, [flush]),
1528	    Reply;
1529	{'DOWN', Ref, _, _, _} ->
1530	    {error, terminated}
1531    end.