PageRenderTime 53ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/kernel/src/file.erl

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