summaryrefslogtreecommitdiff
path: root/src/perm.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/perm.erl')
-rw-r--r--src/perm.erl75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/perm.erl b/src/perm.erl
new file mode 100644
index 0000000..ccb23bc
--- /dev/null
+++ b/src/perm.erl
@@ -0,0 +1,75 @@
+%%
+%% Copyright (c) 2014 Kungliga Tekniska Högskolan
+%% (KTH Royal Institute of Technology, Stockholm, Sweden).
+%%
+
+-module(perm).
+-export([ensurefile/3, readfile/2]).
+
+-spec readfile_and_verify(string(), binary()) -> ok | differ | {error, atom()}.
+readfile_and_verify(Name, Content) ->
+ case file:read_file(Name) of
+ {ok, ContentsRead} when Content == ContentsRead ->
+ ok;
+ {ok, _ContentsRead} ->
+ differ;
+ {error, Error} ->
+ {error, Error}
+ end.
+
+-spec make_dir(string()) -> ok | {error, atom()}.
+make_dir(Name) ->
+ case file:make_dir(Name) of
+ ok ->
+ ok;
+ {error, eexist} ->
+ ok;
+ {error, Error} ->
+ {error, Error}
+ end.
+
+-spec make_dirs([string()]) -> ok | {error, atom()}.
+make_dirs([]) ->
+ ok;
+make_dirs([Name | Rest]) ->
+ case make_dir(Name) of
+ ok ->
+ make_dirs(Rest);
+ {error, Error} ->
+ {error, Error}
+ end.
+
+-spec path_for_key(string(), binary()) -> {[string()], string()}.
+path_for_key(Rootdir, Key) ->
+ Name = hex:bin_to_hexstr(Key),
+ [C1, C2, C3, C4, C5, C6 | _] = Name,
+ Firstlevel = Rootdir ++ [C1, C2],
+ Secondlevel = Firstlevel ++ "/" ++ [C3, C4],
+ Thirdlevel = Secondlevel ++ "/" ++ [C5, C6],
+ Fullpath = Thirdlevel ++ "/" ++ Name,
+ {[Firstlevel, Secondlevel, Thirdlevel], Fullpath}.
+
+-spec ensurefile(string(), binary(), binary()) -> ok | differ.
+ensurefile(Rootdir, Key, Content) ->
+ {Dirs, Path} = path_for_key(Rootdir, Key),
+ case readfile_and_verify(Path, Content) of
+ ok ->
+ util:fsync([Path, Rootdir | Dirs]);
+ differ ->
+ differ;
+ {error, enoent} ->
+ util:check_error(make_dirs([Rootdir, Rootdir ++ "nursery/"]
+ ++ Dirs),
+ makedir, "Error creating directory"),
+ NurseryName = Rootdir ++ "nursery/" ++
+ util:tempfilename(hex:bin_to_hexstr(Key)),
+ util:write_tempfile_and_rename(Path, NurseryName, Content),
+ util:fsync([Path, Rootdir | Dirs]);
+ {error, Error} ->
+ util:exit_with_error(Error, readfile, "Error reading file")
+ end.
+
+-spec readfile(string(), binary()) -> binary().
+readfile(Rootdir, Key) ->
+ {_Dirs, Path} = path_for_key(Rootdir, Key),
+ atomic:readfile(Path).