boot_fprim.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 408 行
ERL
408 行
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 2002, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%%%% Purpose : A simple file server.%% This bit just does primitive *atomic* operations%% on files. For comments and revision history see%% file.erl-module(boot_fprim).%% Notes these routines EXIT if any of the arguments are incorrect%% FileNames must be flat strings, etc.%% -compile(export_all).-export([change_group/2, change_mode/2, change_owner/2, change_owner/3, change_time/2, change_time/3, delete/1, del_dir/1, list_dir/1, make_dir/1, read_file/1, read_file_info/1, rename/2, write_file/2, write_file_info/2 ]).-include_lib("kernel/include/file.hrl").-define(FILE_OPEN, 1).-define(FILE_READ, 2).-define(FILE_LSEEK, 3).-define(FILE_WRITE, 4).-define(FILE_FSTAT, 5).-define(FILE_PWD, 6).-define(FILE_READDIR, 7).-define(FILE_CHDIR, 8).-define(FILE_FSYNC, 9).-define(FILE_MKDIR, 10).-define(FILE_DELETE, 11).-define(FILE_RENAME, 12).-define(FILE_RMDIR, 13).-define(FILE_TRUNCATE, 14).-define(FILE_READ_FILE, 15).-define(FILE_WRITE_INFO, 16).-define(FILE_PREAD, 17).-define(FILE_PWRITE, 18).-define(FILE_RESP_OK, 0).-define(FILE_RESP_ERROR, 1).-define(FILE_RESP_DATA, 2).-define(FILE_RESP_NUMBER, 3).-define(FILE_RESP_INFO, 4).-record(fd, {port, number}).%% Open modes for the efile driver's open function.-define(EFILE_MODE_READ, 1).-define(EFILE_MODE_WRITE, 2).-define(EFILE_MODE_READ_WRITE, 3). -define(EFILE_COMPRESS, 4).%% Use this mask to get just the mode bits to be passed to the driver.-define(EFILE_MODE_MASK, 7).%% These are used internally in this module, and never passed to the driver.-define(BINARY_FILE, 2#10000000000).-define(RAW_PORT, 2#01000000000).%% Seek modes for the efile driver's seek function.-define(EFILE_SEEK_SET, 0).-define(EFILE_SEEK_CUR, 1).-define(EFILE_SEEK_END, 2).delete(File) -> valid_filename(File), fm_op(?FILE_DELETE, File).rename(From, To) -> valid_filename(From), valid_filename(To), fm_op(?FILE_RENAME, [From, 0, To]).make_dir(Dir) -> valid_filename(Dir), fm_op(?FILE_MKDIR, Dir).del_dir(Dir) -> valid_filename(Dir), fm_op(?FILE_RMDIR, Dir).read_file_info(File) -> valid_filename(File), fm_op(?FILE_FSTAT, File).write_file_info(Name, Info) when record(Info, file_info) -> valid_filename(Name), write_file_info_op(?FILE_WRITE_INFO, Name, Info).list_dir(Dir) -> valid_filename(Dir), list_dir_op(Dir).read_file(File) -> valid_filename(File), do_read_file(File).write_file(File, IOL) -> valid_filename(File), valid_io_list(IOL), Bin = coerse_to_binary(IOL), do_write_file(File, Bin).change_mode(Name, Mode) when integer(Mode) -> write_file_info(Name, #file_info{mode=Mode}).change_owner(Name, OwnerId) when integer(OwnerId) -> write_file_info(Name, #file_info{uid=OwnerId}).change_owner(Name, OwnerId, GroupId) when integer(OwnerId), integer(GroupId) -> write_file_info(Name, #file_info{uid=OwnerId, gid=GroupId}).change_group(Name, GroupId) when integer(GroupId) -> write_file_info(Name, #file_info{gid=GroupId}).change_time(Name, Time) when tuple(Time) -> write_file_info(Name, #file_info{mtime=Time}).change_time(Name, Atime, Mtime) when tuple(Atime), tuple(Mtime) -> write_file_info(Name, #file_info{atime=Atime, mtime=Mtime}).%%______________________________________________________________________%% Now the routines that actually do the work%% this is usefulwith_port(Fun) -> case catch open_port({spawn, efile}, [binary]) of {'EXIT', Reason} -> {error, Reason}; Port -> Result = case (catch Fun(Port)) of {'EXIT', Reason2} -> {error, file_prim1}; Ret -> Ret end, close_port(Port), Result end. do_read_file(Name) -> with_port(fun(P) -> Command = [?FILE_READ_FILE, Name, 0], port_command(P, Command), case get_response(P) of {error, enomem} -> erlang:garbage_collect(), port_command(P, Command), get_response(P); Other -> Other end end).do_write_file(File, Bin) -> %% here the arguments are checked %% File is a flat string and Bin is a binary case open(File, [binary, write, raw]) of {ok, Port} -> Result = case write(Port, Bin) of {ok, _} -> ok; Error -> Error end, close_port(Port), Result; Error -> Error end.open(File, Mode0) -> Mode = open_mode(Mode0), Cmd = [?FILE_OPEN, i32(Mode band ?EFILE_MODE_MASK), File, 0], case mkport(Cmd, Mode band ?BINARY_FILE) of {'EXIT', _} -> {error, emfile}; P -> case get_response(P) of {ok, Number} -> {ok, P}; Error -> close_port(P), Error end end.write(Port, Bytes) -> port_command(Port, [?FILE_WRITE, Bytes]), case get_response(Port) of {ok, _Size} -> ok; Other -> Other end.close_port(Port) -> unlink(Port), exit(Port, die), ok.fm_op(Op, Chars) -> with_port(fun(Port) -> port_command(Port, [Op, Chars, 0]), get_response(Port) end).list_dir_op(Chars) -> with_port(fun(Port) -> port_command(Port, [?FILE_READDIR|[Chars, 0]]), collect_files(Port, []) end).collect_files(Port, Result) -> case get_response(Port) of ok -> {ok, Result}; {ok, Name} -> collect_files(Port, [Name|Result]); Error -> Error end.get_response(Port) -> receive {Port, {data, [Response|Rest]}} -> get_response(Response, Rest); {'EXIT', Port, Reason} -> {error, port_died} end.get_response(?FILE_RESP_OK, []) -> ok;get_response(?FILE_RESP_OK, Data) -> {ok, Data};get_response(?FILE_RESP_ERROR, List) when list(List) -> {error, list_to_atom(List)};get_response(?FILE_RESP_NUMBER, [X1, X2, X3, X4]) -> {ok, i32(X1, X2, X3, X4)};get_response(?FILE_RESP_DATA, [X1, X2, X3, X4|Data]) -> {ok, {i32(X1, X2, X3, X4), Data}};get_response(?FILE_RESP_INFO, List) when list(List) -> {ok, transform_ints(getints(List))};get_response(X, Data) -> {error, {bad_response_from_port, X, Data}}.transform_ints(Ints) -> [HighSize, LowSize, Type|Tail0] = Ints, Size = HighSize * 16#100000000 + LowSize, [Ay, Am, Ad, Ah, Ami, As|Tail1] = Tail0, [My, Mm, Md, Mh, Mmi, Ms|Tail2] = Tail1, [Cy, Cm, Cd, Ch, Cmi, Cs|Tail3] = Tail2, [Mode, Links, Major, Minor, Inode, Uid, Gid, Access] = Tail3, #file_info { size = Size, type = file_type(Type), access = file_access(Access), atime = {{Ay, Am, Ad}, {Ah, Ami, As}}, mtime = {{My, Mm, Md}, {Mh, Mmi, Ms}}, ctime = {{Cy, Cm, Cd}, {Ch, Cmi, Cs}}, mode = Mode, links = Links, major_device = Major, minor_device = Minor, inode = Inode, uid = Uid, gid = Gid}. file_type(1) -> device;file_type(2) -> directory;file_type(3) -> regular;file_type(4) -> symlink;file_type(_) -> other.file_access(0) -> none; file_access(1) -> write;file_access(2) -> read;file_access(3) -> read_write.write_file_info_op(Op, Name, Info) -> with_port(fun(Port) -> port_command(Port, [Op, info_to_list(Name, Info)]), get_response(Port) end).info_to_list(Name, #file_info {mode=Mode, uid=Uid, gid=Gid, atime=Atime0, mtime=Mtime0, ctime=Ctime}) -> {Atime, Mtime} = case {Atime0, Mtime0} of {undefined, Mtime0} -> {erlang:localtime(), Mtime0}; {Atime0, undefined} -> {Atime0, Atime0}; Complete -> Complete end, [int_to_bytes(Mode), int_to_bytes(Uid), int_to_bytes(Gid), date_to_bytes(Atime), date_to_bytes(Mtime), date_to_bytes(Ctime), Name, 0].open_mode(Flags) when list(Flags) -> case open_mode(Flags, 0) of Mode when Mode band (?EFILE_MODE_READ bor ?EFILE_MODE_WRITE) == 0 -> Mode bor ?EFILE_MODE_READ; Other -> Other end.open_mode([read|Rest], Result) -> open_mode(Rest, Result bor ?EFILE_MODE_READ);open_mode([write|Rest], Result) -> open_mode(Rest, Result bor ?EFILE_MODE_WRITE);open_mode([binary|Rest], Result) -> open_mode(Rest, Result bor ?BINARY_FILE);open_mode([raw|Rest], Result) -> open_mode(Rest, Result bor ?RAW_PORT);open_mode([compressed|Rest], Result) -> open_mode(Rest, Result bor ?EFILE_COMPRESS);open_mode([], Result) -> Result;open_mode([H|T], _) -> exit(badMode).mkport(Cmd, BinaryFile) -> Opts = if BinaryFile == 0 -> []; true -> [binary] %% flag is set end, case catch open_port({spawn, efile}, Opts) of P -> port_command(P, Cmd), P; {'EXIT', Reason} -> {error, {'EXIT', Reason}} end.%%----------------------------------------------------------------------%% valid_filename -> ok | exit(..) if the argument is%% invalidvalid_filename([H|T]) when integer(H), H > 0, H =< 255 -> valid_filename(T);valid_filename([H|_]) -> exit(badFileName);valid_filename([]) -> ok.valid_io_list(B) when binary(B) -> ok;valid_io_list([H|T]) -> valid_io_list(H),valid_io_list(T);valid_io_list(I) when I >= 0, I =< 255 -> ok;valid_io_list([]) -> ok;valid_io_list(_) -> exit(badIOList).coerse_to_binary(B) when binary(B) -> B;coerse_to_binary(L) when list(L) -> list_to_binary(L).int_to_bytes(Int) when integer(Int) -> i32(Int);int_to_bytes(undefined) -> [255, 255, 255, 255].date_to_bytes(undefined) -> MinusOne = [255, 255, 255, 255], [MinusOne, MinusOne, MinusOne, MinusOne, MinusOne, MinusOne];date_to_bytes({{Y, Mon, D}, {H, Min, S}}) -> [i32(Y), i32(Mon), i32(D), i32(H), i32(Min), i32(S)].i32(Int) when binary(Int) -> i32(binary_to_list(Int));i32(Int) when integer(Int) -> [(Int bsr 24) band 255, (Int bsr 16) band 255, (Int bsr 8) band 255, Int band 255];i32([X1,X2,X3,X4]) -> (X1 bsl 24) bor (X2 bsl 16) bor (X3 bsl 8) bor X4.i32(X1,X2,X3,X4) -> (X1 bsl 24) bor (X2 bsl 16) bor (X3 bsl 8) bor X4. getints([X1,X2,X3,X4|Tail]) -> [i32(X1,X2,X3,X4) | getints(Tail)];getints([]) -> [].
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?