1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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).
|