1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1997-2016. 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(ram_file). 21 22%% Binary RAM file interface 23 24%% Generic file contents operations 25-export([open/2, close/1]). 26-export([write/2, read/2, copy/3, 27 pread/2, pread/3, pwrite/2, pwrite/3, 28 position/2, truncate/1, datasync/1, sync/1]). 29 30%% Specialized file operations 31-export([get_size/1, get_file/1, advise/4]). 32-export([allocate/3]). 33-export([ipread_s32bu_p32bu/3]). 34 35%% Includes and defines 36-define(RAM_FILE_DRV, "ram_file_drv"). 37-define(MAX_I32, (1 bsl 31)). 38-define(G_I32(X), is_integer(X), X >= -?MAX_I32, X < ?MAX_I32). 39 40-include("file.hrl"). 41 42%% -------------------------------------------------------------------------- 43%% These operation codes were once identical between efile_drv.c 44%% and ram_file_drv.c, but now these drivers are not depeding on each other. 45%% So, the codes could be changed to more logical values now, but why indeed? 46 47%% Defined "file" functions 48-define(RAM_FILE_OPEN, 1). 49-define(RAM_FILE_READ, 2). 50-define(RAM_FILE_LSEEK, 3). 51-define(RAM_FILE_WRITE, 4). 52-define(RAM_FILE_FSYNC, 9). 53-define(RAM_FILE_TRUNCATE, 14). 54-define(RAM_FILE_PREAD, 17). 55-define(RAM_FILE_PWRITE, 18). 56-define(RAM_FILE_FDATASYNC, 19). 57 58%% Other operations 59-define(RAM_FILE_GET, 30). 60-define(RAM_FILE_COMPRESS, 33). 61-define(RAM_FILE_UNCOMPRESS, 34). 62-define(RAM_FILE_SIZE, 37). 63-define(RAM_FILE_ADVISE, 38). 64-define(RAM_FILE_ALLOCATE, 39). 65 66%% Open modes for RAM_FILE_OPEN 67-define(RAM_FILE_MODE_READ, 1). 68-define(RAM_FILE_MODE_WRITE, 2). 69-define(RAM_FILE_MODE_READ_WRITE, 3). 70%% Use this mask to get just the mode bits to be passed to the driver. 71-define(RAM_FILE_MODE_MASK, 3). 72 73%% Seek modes for RAM_FILE_LSEEK 74-define(RAM_FILE_SEEK_SET, 0). 75-define(RAM_FILE_SEEK_CUR, 1). 76-define(RAM_FILE_SEEK_END, 2). 77 78%% Return codes 79-define(RAM_FILE_RESP_OK, 0). 80-define(RAM_FILE_RESP_ERROR, 1). 81-define(RAM_FILE_RESP_DATA, 2). 82-define(RAM_FILE_RESP_NUMBER, 3). 83-define(RAM_FILE_RESP_INFO, 4). 84 85%% POSIX file advises 86-define(POSIX_FADV_NORMAL, 0). 87-define(POSIX_FADV_RANDOM, 1). 88-define(POSIX_FADV_SEQUENTIAL, 2). 89-define(POSIX_FADV_WILLNEED, 3). 90-define(POSIX_FADV_DONTNEED, 4). 91-define(POSIX_FADV_NOREUSE, 5). 92 93%% -------------------------------------------------------------------------- 94%% Generic file contents operations. 95%% 96%% Supposed to be called by applications through module file. 97 98open(Data, ModeList) when is_list(ModeList) -> 99 case open_mode(ModeList) of 100 {Mode,Opts} when is_integer(Mode) -> 101 case ll_open(Data, Mode, Opts) of 102 {ok,Port} -> 103 {ok,#file_descriptor{module=?MODULE, data=Port}}; 104 Error -> 105 Error 106 end; 107 {error,_}=Error -> 108 Error 109 end. 110 111close(#file_descriptor{module = ?MODULE, data = Port}) -> 112 ll_close(Port). 113 114read(#file_descriptor{module = ?MODULE, data = Port}, Sz) 115 when is_integer(Sz), Sz >= 0 -> 116 if 117 ?G_I32(Sz) -> 118 Cmd = <<?RAM_FILE_READ:8,Sz:32>>, 119 case call_port(Port, Cmd) of 120 {ok, {0, _Data}} when Sz =/= 0 -> 121 eof; 122 {ok, {_Sz, Data}} -> 123 {ok, Data}; 124 {error, enomem} -> 125 %% Garbage collecting here might help if 126 %% the current processes has some old binaries left. 127 erlang:garbage_collect(), 128 case call_port(Port, Cmd) of 129 {ok, {0, _Data}} when Sz =/= 0 -> 130 eof; 131 {ok, {_Sz, Data}} -> 132 {ok, Data}; 133 Error -> 134 Error 135 end; 136 Error -> 137 Error 138 end; 139 true -> 140 {error, einval} 141 end. 142 143write(#file_descriptor{module = ?MODULE, data = Port}, Bytes) -> 144 case call_port(Port, [?RAM_FILE_WRITE | Bytes]) of 145 {ok, _Sz} -> 146 ok; 147 Error -> 148 Error 149 end. 150 151 152 153 154copy(#file_descriptor{module = ?MODULE} = Source, 155 #file_descriptor{module = ?MODULE} = Dest, 156 Length) 157 when is_integer(Length), Length >= 0; 158 is_atom(Length) -> 159 %% XXX Should be moved down to the driver for optimization. 160 file:copy_opened(Source, Dest, Length). 161 162datasync(#file_descriptor{module = ?MODULE, data = Port}) -> 163 call_port(Port, <<?RAM_FILE_FDATASYNC>>). 164 165sync(#file_descriptor{module = ?MODULE, data = Port}) -> 166 call_port(Port, <<?RAM_FILE_FSYNC>>). 167 168truncate(#file_descriptor{module = ?MODULE, data = Port}) -> 169 call_port(Port, <<?RAM_FILE_TRUNCATE>>). 170 171position(#file_descriptor{module = ?MODULE, data = Port}, Pos) -> 172 case lseek_position(Pos) of 173 {ok, Offs, Whence} when ?G_I32(Offs) -> 174 call_port(Port, <<?RAM_FILE_LSEEK:8,Offs:32,Whence:32>>); 175 {ok, _, _} -> 176 {error, einval}; 177 Error -> 178 Error 179 end. 180 181 182 183pread(#file_descriptor{module = ?MODULE, data = Port}, L) when is_list(L) -> 184 pread_1(Port, L, []). 185 186pread_1(Port, [], Cs) -> 187 pread_2(Port, lists:reverse(Cs), []); 188pread_1(Port, [{At, Sz} | T], Cs) 189 when is_integer(At), is_integer(Sz), Sz >= 0 -> 190 if 191 ?G_I32(At), ?G_I32(Sz) -> 192 pread_1(Port, T, [{Sz,<<?RAM_FILE_PREAD:8,At:32,Sz:32>>}|Cs]); 193 true -> 194 {error, einval} 195 end; 196pread_1(_, _, _243) -> 197 {error, badarg}. 198 199pread_2(_Port, [], R) -> 200 {ok, lists:reverse(R)}; 201pread_2(Port, [{Sz,Command}|Commands], R) -> 202 case call_port(Port, Command) of 203 {ok, {0,_Data}} when Sz =/= 0 -> 204 pread_2(Port, Commands, [eof | R]); 205 {ok, {_Sz,Data}} -> 206 pread_2(Port, Commands, [Data | R]); 207 Error -> 208 Error 209 end. 210 211pread(#file_descriptor{module = ?MODULE, data = Port}, At, Sz) 212 when is_integer(At), is_integer(Sz), Sz >= 0 -> 213 if 214 ?G_I32(At), ?G_I32(Sz) -> 215 case call_port(Port, <<?RAM_FILE_PREAD:8,At:32,Sz:32>>) of 216 {ok, {0,_Data}} when Sz =/= 0 -> 217 eof; 218 {ok, {_Sz,Data}} -> 219 {ok, Data}; 220 Error -> 221 Error 222 end; 223 true -> 224 {error, einval} 225 end; 226pread(#file_descriptor{module = ?MODULE}, _, _) -> 227 {error, badarg}. 228 229 230 231pwrite(#file_descriptor{module = ?MODULE, data = Port}, L) when is_list(L) -> 232 pwrite_1(Port, L, 0, []). 233 234pwrite_1(Port, [], _, Cs) -> 235 pwrite_2(Port, lists:reverse(Cs), 0); 236pwrite_1(Port, [{At, Bytes} | T], R, Cs) when is_integer(At) -> 237 if 238 ?G_I32(At), is_binary(Bytes) -> 239 pwrite_1(Port, T, R+1, 240 [<<?RAM_FILE_PWRITE:8,At:32,Bytes/binary>> | Cs]); 241 ?G_I32(At) -> 242 try erlang:iolist_to_binary(Bytes) of 243 Bin -> 244 pwrite_1(Port, T, R+1, 245 [<<?RAM_FILE_PWRITE:8,At:32,Bin/binary>> | Cs]) 246 catch 247 error:Reason -> 248 {error, Reason} 249 end; 250 true -> 251 {error, {R, einval}} 252 end; 253pwrite_1(_, _, _, _) -> 254 {error, badarg}. 255 256pwrite_2(_Port, [], _R) -> 257 ok; 258pwrite_2(Port, [Command|Commands], R) -> 259 case call_port(Port, Command) of 260 {ok, _Sz} -> 261 pwrite_2(Port, Commands, R+1); 262 {error, badarg} = Error -> 263 Error; 264 {error, Reason} -> 265 {error, {R, Reason}} 266 end. 267 268pwrite(#file_descriptor{module = ?MODULE, data = Port}, At, Bytes) 269 when is_integer(At) -> 270 if 271 ?G_I32(At) -> 272 case call_port(Port, [<<?RAM_FILE_PWRITE:8,At:32>>|Bytes]) of 273 {ok, _Sz} -> 274 ok; 275 Error -> 276 Error 277 end; 278 true -> 279 {error, einval} 280 end; 281pwrite(#file_descriptor{module = ?MODULE}, _, _) -> 282 {error, badarg}. 283 284 285ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE} = Handle, Pos, MaxSz) -> 286 file:ipread_s32bu_p32bu_int(Handle, Pos, MaxSz). 287 288 289 290%% -------------------------------------------------------------------------- 291%% Specialized ram_file API for functions not in file, unique to ram_file. 292%% 293 294 295get_file(#file_descriptor{module = ?MODULE, data = Port}) -> 296 case call_port(Port, [?RAM_FILE_GET]) of 297 {ok, {_Sz, Data}} -> 298 {ok, Data}; 299 Error -> 300 Error 301 end; 302get_file(#file_descriptor{}) -> 303 {error, enotsup}. 304 305get_size(#file_descriptor{module = ?MODULE, data = Port}) -> 306 call_port(Port, [?RAM_FILE_SIZE]); 307get_size(#file_descriptor{}) -> 308 {error, enotsup}. 309 310advise(#file_descriptor{module = ?MODULE, data = Port}, Offset, 311 Length, Advise) -> 312 Cmd0 = <<?RAM_FILE_ADVISE, Offset:64/signed, Length:64/signed>>, 313 case Advise of 314 normal -> 315 call_port(Port, <<Cmd0/binary, ?POSIX_FADV_NORMAL:32/signed>>); 316 random -> 317 call_port(Port, <<Cmd0/binary, ?POSIX_FADV_RANDOM:32/signed>>); 318 sequential -> 319 call_port(Port, <<Cmd0/binary, ?POSIX_FADV_SEQUENTIAL:32/signed>>); 320 will_need -> 321 call_port(Port, <<Cmd0/binary, ?POSIX_FADV_WILLNEED:32/signed>>); 322 dont_need -> 323 call_port(Port, <<Cmd0/binary, ?POSIX_FADV_DONTNEED:32/signed>>); 324 no_reuse -> 325 call_port(Port, <<Cmd0/binary, ?POSIX_FADV_NOREUSE:32/signed>>); 326 _ -> 327 {error, einval} 328 end; 329advise(#file_descriptor{}, _Offset, _Length, _Advise) -> 330 {error, enotsup}. 331 332allocate(#file_descriptor{module = ?MODULE, data = Port}, Offset, Length) -> 333 call_port(Port, <<?RAM_FILE_ALLOCATE, Offset:64/signed, Length:64/signed>>); 334allocate(#file_descriptor{}, _Offset, _Length) -> 335 {error, enotsup}. 336 337 338 339%%%----------------------------------------------------------------- 340%%% Functions to communicate with the driver 341 342ll_open(Data, Mode, Opts) -> 343 try erlang:open_port({spawn, ?RAM_FILE_DRV}, Opts) of 344 Port -> 345 case call_port(Port, [<<?RAM_FILE_OPEN:8,Mode:32>>|Data]) of 346 {error, _} = Error -> 347 ll_close(Port), 348 Error; 349 {ok, _} -> 350 {ok, Port} 351 end 352 catch 353 error:Reason -> 354 {error, Reason} 355 end. 356 357call_port(Port, Command) when is_port(Port), is_binary(Command) -> 358 try erlang:port_command(Port, Command) of 359 true -> 360 get_response(Port) 361 catch 362 error:badarg -> 363 {error, einval}; % Since Command is valid, Port must be dead 364 error:Reason -> 365 {error, Reason} 366 end; 367call_port(Port, Command) -> 368 try erlang:iolist_to_binary(Command) of 369 Bin -> 370 call_port(Port, Bin) 371 catch 372 error:Reason -> 373 {error, Reason} 374 end. 375 376get_response(Port) -> 377 receive 378 {Port, {data, [Response|Rest]}} -> 379 translate_response(Response, Rest); 380 {'EXIT', Port, _Reason} -> 381 {error, port_died} 382 end. 383 384ll_close(Port) -> 385 try erlang:port_close(Port) catch error:_ -> ok end, 386 receive %% In case the caller is the owner and traps exits 387 {'EXIT', Port, _} -> 388 ok 389 after 0 -> 390 ok 391 end. 392 393%%%----------------------------------------------------------------- 394%%% Utility functions. 395 396%% Converts a list of mode atoms into an mode word for the driver. 397%% Returns {Mode, Opts} wher Opts is a list of options for 398%% erlang:open_port/2, or {error, einval} upon failure. 399 400open_mode(List) when is_list(List) -> 401 case open_mode(List, {0, []}) of 402 {Mode, Opts} when Mode band 403 (?RAM_FILE_MODE_READ bor ?RAM_FILE_MODE_WRITE) 404 =:= 0 -> 405 {Mode bor ?RAM_FILE_MODE_READ, Opts}; 406 Other -> 407 Other 408 end. 409 410open_mode([ram|Rest], {Mode, Opts}) -> 411 open_mode(Rest, {Mode, Opts}); 412open_mode([read|Rest], {Mode, Opts}) -> 413 open_mode(Rest, {Mode bor ?RAM_FILE_MODE_READ, Opts}); 414open_mode([write|Rest], {Mode, Opts}) -> 415 open_mode(Rest, {Mode bor ?RAM_FILE_MODE_WRITE, Opts}); 416open_mode([binary|Rest], {Mode, Opts}) -> 417 open_mode(Rest, {Mode, [binary | Opts]}); 418open_mode([], {Mode, Opts}) -> 419 {Mode, Opts}; 420open_mode(_, _) -> 421 {error, badarg}. 422 423 424 425%% Converts a position tuple {bof, X} | {cur, X} | {eof, X} into 426%% {ok, Offset, OriginCode} for the driver. 427%% Returns {error, einval} upon failure. 428 429lseek_position(Pos) when is_integer(Pos) -> 430 lseek_position({bof, Pos}); 431lseek_position(bof) -> 432 lseek_position({bof, 0}); 433lseek_position(cur) -> 434 lseek_position({cur, 0}); 435lseek_position(eof) -> 436 lseek_position({eof, 0}); 437lseek_position({bof, Offset}) when is_integer(Offset) -> 438 {ok, Offset, ?RAM_FILE_SEEK_SET}; 439lseek_position({cur, Offset}) when is_integer(Offset) -> 440 {ok, Offset, ?RAM_FILE_SEEK_CUR}; 441lseek_position({eof, Offset}) when is_integer(Offset) -> 442 {ok, Offset, ?RAM_FILE_SEEK_END}; 443lseek_position(_) -> 444 {error, badarg}. 445 446 447 448translate_response(?RAM_FILE_RESP_OK, []) -> 449 ok; 450translate_response(?RAM_FILE_RESP_OK, Data) -> 451 {ok, Data}; 452translate_response(?RAM_FILE_RESP_ERROR, List) when is_list(List) -> 453 {error, list_to_atom(List)}; 454translate_response(?RAM_FILE_RESP_NUMBER, [X1, X2, X3, X4]) -> 455 {ok, i32(X1, X2, X3, X4)}; 456translate_response(?RAM_FILE_RESP_DATA, [X1, X2, X3, X4|Data]) -> 457 {ok, {i32(X1, X2, X3, X4), Data}}; 458translate_response(X, Data) -> 459 {error, {bad_response_from_port, X, Data}}. 460 461i32(X1,X2,X3,X4) -> 462 (X1 bsl 24) bor (X2 bsl 16) bor (X3 bsl 8) bor X4. 463