/lib/kernel/src/file.erl
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.