#!/usr/bin/env escript %% -*- erlang -*- %%! -pa ebin -pa ../lager/ebin -pa ../lager/deps/goldrush/ebin -mode(compile). -include_lib("kernel/include/file.hrl"). -define(DATA_COMMIT_START_COOKIE, 16#75c2e4b3d5f643a1). -define(DATA_COMMIT_END_COOKIE, 16#2b05eed61b5af550). -define(INDEX_COMMIT_END_COOKIE, 16#2fb1778c74a402e4). -define(DATA_FILE_COOKIE, 16#99c99d588b1e7983). -define(INDEX_FILE_COOKIE, 16#b7e16b02ba8a6d1b). -define(DATA_ENTRY_COOKIE, 16#e7c1cdc2ba3dc77c). -define(INDEX_NODE_COOKIE, 16#2e0f555ad73210d1). openfile(Filename) -> {ok, File} = file:open(Filename, [read, write, binary, raw]), File. %% getroot(File) -> %% {ok, RootNodeBinary} = file:read(File, ?NODESIZE), %% Nodemagic = ?NODEMAGIC, %% <> = RootNodeBinary, %% ets:insert(State#state.cachename, {root, Node}), %% Node; %% [{root, Node}] -> %% Node %% end. printfile(<>) -> io:format("index file header~n", []), printcommit(Rest, index, 8); printfile(<>) -> io:format("data file header: blocksize ~p q ~p keylength ~p~n", [Blocksize, Q, Keylength]), printcommit(Rest, data, 8+4*3); printfile(<>) -> io:format("unknown byte: ~p at file start~n", [Unknown]), error. printnode(<<>>) -> ok; printnode(<>) -> case <> of <<0:1, Offset:63>> -> io:format(" child ~p~n", [Offset]); <<1:1, Offset:63>> -> io:format(" offset ~p~n", [Offset]) end, printnode(Rest). printcommit(Data, FileType, FileOffset) -> OneCommit = case FileType of index -> printindex(Data, FileOffset); data -> printdata(Data, FileOffset) end, case OneCommit of {{CommitLength, CommitChecksum, Rest}, FileOffset2, FileOffset3} -> io:format("------- commit ~p bytes at ~p-~p -------~n", [CommitLength, FileOffset, FileOffset3]), CalculatedChecksum = crypto:hash(sha256, binary:part(Data, 0, CommitLength)), if CommitChecksum /= CalculatedChecksum -> io:format("incorrect checksum~n", []), io:format("commit: length ~p checksum ~p~n", [CommitLength, CommitChecksum]), io:format("calculated length ~p checksum ~p~n", [FileOffset2 - FileOffset, crypto:hash(sha256, binary:part(Data, 0, CommitLength))]), io:format("checksummed data: ~p~n", [binary:part(Data, 0, CommitLength)]), exit(assert); CommitLength /= (FileOffset2 - FileOffset) -> io:format("length and offset mismatch~n", []), io:format("commit: length ~p checksum ~p~n", [CommitLength, CommitChecksum]), io:format("calculated length ~p checksum ~p~n", [FileOffset2 - FileOffset, crypto:hash(sha256, binary:part(Data, 0, CommitLength))]), io:format("checksummed data: ~p~n", [binary:part(Data, 0, CommitLength)]), exit(assert); true -> ok end, printcommit(Rest, FileType, FileOffset3); {ok, FileOffset2} -> io:format("ending at offset ~p~n", [FileOffset]), ok end. printindex(<<>>, FileOffset) -> {ok, FileOffset}; printindex(<>, FileOffset) -> FileOffset2 = FileOffset + 8, Q = 2, NChildren = 4, ChildrenLength = NChildren * 8, <> = Rest, io:format("node ~p~n", [FileOffset]), printnode(Children), printindex(Rest2, FileOffset2 + ChildrenLength); printindex(<>, FileOffset) -> {{CommitLength, CommitChecksum, Rest}, FileOffset + 8, FileOffset + 8 + 32 + 8}; printindex(<>, FileOffset) -> io:format("unknown byte: ~p at ~p~n", [Unknown, FileOffset]), error. printdata(<<>>, FileOffset) -> io:format("reached end of file~n", []), {ok, FileOffset}; printdata(<>, FileOffset) -> FileOffset2 = FileOffset + 8 + 32 + 4, io:format("data ~p key ~p length ~p~n", [FileOffset, Key, Length]), case Rest of <> -> printdata(Rest2, FileOffset2 + Length); _ -> io:format("data was truncated, remaining bytes: ~p ~p~n", [size(Rest), binary:part(Rest, 0, min(size(Rest), 16))]), error end; printdata(<> = Rest, FileOffset) -> Padding = case FileOffset rem 4 of 0 -> 0; 1 -> 3; 2 -> 2; 3 -> 1 end, io:format("printdata: ~p ~p~n", [Padding, FileOffset]), case Rest2 of <<0:Padding/unit:8, CommitLength:64, CommitChecksum:32/binary, ?DATA_COMMIT_END_COOKIE:64, Rest3/binary>> -> {{CommitLength, CommitChecksum, Rest3}, FileOffset + 8 + Padding + 8, FileOffset + 8 + Padding + 8 + 32 + 8}; _ -> io:format("commit trailer was not correctly formed at ~p, " ++ "expected padding ~p, remaining bytes: ~p ~w~n", [FileOffset, Padding, size(Rest), binary:part(Rest, 0, min(size(Rest), 64))]), error end; printdata(Data, FileOffset) -> Unknown = binary:part(Data, 0, min(size(Data), 16)), io:format("unknown byte: ~p at ~p~n", [Unknown, FileOffset]), error. read_whole_file(File, Size) -> case file:read(File, Size) of {ok, Data} -> RestData = read_whole_file(File, Size), <>; eof -> <<>> end. main([Filename]) -> {ok, FileInfo} = file:read_file_info(Filename), File = openfile(Filename), Data = read_whole_file(File, FileInfo#file_info.size), io:format("read ~p bytes, file size ~p~n", [size(Data), FileInfo#file_info.size]), ok = printfile(Data), ok.