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