Current section

Files

Jump to
grisp_updater src grisp_updater_filesystem.erl
Raw

src/grisp_updater_filesystem.erl

-module(grisp_updater_filesystem).
-behaviour(grisp_updater_storage).
%--- Includes ------------------------------------------------------------------
-include_lib("kernel/include/logger.hrl").
-include_lib("kernel/include/file.hrl").
-include("grisp_updater.hrl").
%--- Exports -------------------------------------------------------------------
% Behaviour grisp_updater_storage callbacks
-export([storage_init/1]).
-export([storage_prepare/3]).
-export([storage_open/2]).
-export([storage_write/4]).
-export([storage_read/4]).
-export([storage_close/2]).
-export([storage_terminate/2]).
%--- Behaviour grisp_updater_storage Callbacks ---------------------------------
storage_init(_Opts) ->
?LOG_INFO("Initializing GRiSP updater's filesystem storage", []),
{ok, undefined}.
storage_prepare(State, #target{device = Device} = Target, ObjSize)
when is_binary(Device) ->
case file:read_file_info(Device) of
{ok, #file_info{type = device, access = read_write}} -> {ok, State};
{ok, #file_info{type = device}} -> {error, device_access_error};
{ok, #file_info{type = regular, access = read_write}} ->
case truncate_file(Device, file_size(Target, ObjSize)) of
{error, _Reason} = Error -> Error;
ok -> {ok, State}
end;
{ok, #file_info{type = regular}} -> {error, device_access_error};
{ok, #file_info{}} -> {error, bad_device};
{error, enoent} ->
% Assume that if it doesn't exists it is a regular file
case truncate_file(Device, file_size(Target, ObjSize)) of
{error, _Reason} = Error -> Error;
ok -> {ok, State}
end
end.
storage_open(State, Device) when is_binary(Device) ->
case file:open(Device, [raw, read, write, binary, sync]) of
{ok, File} -> {ok, File, State};
{error, _Reason} = Error -> Error
end;
storage_open(_State, Device) ->
{error, {invalid_device, Device}}.
storage_write(State, Descriptor, Offset, Data) ->
case file:pwrite(Descriptor, Offset, Data) of
ok -> {ok, State};
{error, _Reason} = Error -> Error
end.
storage_read(State, Descriptor, Offset, Size) ->
case file:pread(Descriptor, Offset, Size) of
eof -> {ok, <<>>, State};
{ok, Data} -> {ok, Data, State};
{error, _Reason} = Error -> Error
end.
storage_close(State, Descriptor) ->
ok = file:close(Descriptor),
{ok, State}.
storage_terminate(_State, _Reason) ->
?LOG_INFO("Terminating filesystem update storage", []),
ok.
%--- Internal Functions --------------------------------------------------------
file_size(#target{offset = Offset, size = undefined, total = undefined}, ObjSize) ->
Offset + ObjSize;
file_size(#target{offset = Offset, size = Size, total = undefined}, _ObjSize) ->
Offset + Size;
file_size(#target{total = Total}, _ObjSize) ->
Total.
truncate_file(Filename, Size) ->
case file:open(Filename, [raw, read, write, binary, sync]) of
{error, _Reason} = Error -> Error;
{ok, F} ->
try file:position(F, {bof, Size}) of
{error, _Reason} = Error -> Error;
{ok, _} ->
file:truncate(F),
ok
after
file:close(F)
end
end.