mirror of https://gitee.com/openkylin/gvfs.git
110 lines
2.9 KiB
Plaintext
110 lines
2.9 KiB
Plaintext
Tree file:
|
|
|
|
Generic:
|
|
Breath-first stored, first tree, then data
|
|
offsets and sizes are uint32
|
|
time_t are uint32 with base stored in header
|
|
data stored in big endian
|
|
non-string blocks padded to 32bit
|
|
all key names and values are utf8, without zeros
|
|
filenames are byte strings
|
|
|
|
|
|
Detailed:
|
|
magic
|
|
file type version
|
|
|
|
guint32 rotated # != 0 => new file has been written, changed at runtime
|
|
guint32 random_tag
|
|
offset to root
|
|
offset to keywords
|
|
gint64 time_t base (other time_ts stored as offsets)
|
|
|
|
keywords:
|
|
n_keywords
|
|
array of offset to keywords, sorted by keyword
|
|
string block for keywords
|
|
|
|
root dirent:
|
|
offset to name ("/")
|
|
offset to children for root
|
|
offset to root metadata
|
|
time_t last_change for root metadata
|
|
|
|
children:
|
|
Each dir in breath-first order:
|
|
int num_children
|
|
children, array of: (sorted by name)
|
|
offset name
|
|
offset children
|
|
offset metadata
|
|
time_t last_change_metadata
|
|
string block for names:
|
|
zero terminated strings
|
|
|
|
metadata:
|
|
each metadata block: (in breath first order)
|
|
int num_keys
|
|
keys, array of: sorted by keyword
|
|
guint32 keyword | high bit set => is_list
|
|
offset value (pointer to string, or array of strings)
|
|
block of string arrays for values
|
|
for each directory, string block of values for metadata in dir
|
|
|
|
----------------------------------------
|
|
------------- Journal ------------------
|
|
----------------------------------------
|
|
|
|
Fixed size, rotated when full
|
|
Array of operations, each with a checksum
|
|
Readers handle only up to first non-ok checksum
|
|
Writer periodically rewrites stable tree and creates new journal
|
|
|
|
strings are stored as plain zero terminated c-strings
|
|
|
|
Updates to stable:
|
|
1 block writes
|
|
2 write new stable to tmp file, w/ fsync
|
|
3 create new empty journal (name based on random_tag)
|
|
4 rename new stable over old
|
|
5 set rotated to true in old (via open fd)
|
|
6 sync old fd
|
|
7 remove old journal
|
|
8 re-enable writes
|
|
|
|
When opening a stable file + journal there is a race where we can open the
|
|
old tree, but then the old journal is removed before we read it. To
|
|
handle this, on open you must always re-check "rotated" after the
|
|
journal has been opened (or failed to open) and verified
|
|
|
|
Journal file header:
|
|
char[6] magic
|
|
char[2] file type version
|
|
guint32 random_tag
|
|
guint32 file_size # Must be same as file size
|
|
guint32 num_entries
|
|
|
|
Journal entry:
|
|
|
|
guint32 entry_size # Must verify wrt file size (includes entry_size, etc)
|
|
guint32 crc32 # crc32 of following data, including padding and last size
|
|
guint64 mtime
|
|
byte operation type (set: 0, set_list: 1: unset: 2, move: 3, copy: 4)
|
|
cstring path # target if copy/move
|
|
set:
|
|
cstring key
|
|
cstring value
|
|
set_list:
|
|
cstring key
|
|
<zero padding to even 32bit address>
|
|
guint32 n_values
|
|
cstring value
|
|
uset:
|
|
cstring key
|
|
copy: (overwrites all destination data)
|
|
cstring source_path
|
|
remove:
|
|
<nothing>
|
|
<zero padding to even 32bit address>
|
|
guint32 entry_size_end # Must be same as entry_size, for reverse skipping
|