When a bookmark is deleted, if there are no other bookmarks
referencing the corresponding `moz_place` entry, tag and keyword
references to that entry are considered "dangling" references,
and shall be automatically removed.
Also reverts commit b5fa6960ef,
since the NULL title check is no longer necessary.
When a bookmark associated with a keyword is deleted,
there may still be dangling references (e.g., tags) to the
corresponding `moz_places` entry.
By filtering out NULL titles, `bookmark_lookup()` and
`bookmark_list()` now only give keywords associated with
valid bookmarks.
This allows users to quickly discover which keyword is
associated with a given bookmark.
Updating keywords via xattr is not implemented,
since it can be done trivially using existing API.
In commit 348f13df02, we replaced
`length(url)` with `octet_length(url)`.
However, `octet_length` was added in SQLite 3.43, while we claim to
support SQLite 3.35 and later.
Stable GNU/Linux distros like Debian may still be using pre-3.43
releases of SQLite, so don't bump that version too soon.
Instead, use `length(CAST(url AS BLOB))`, which is a bit less
efficient than `octet_length(url)`, but O(1) nonetheless.
Following commit 2e3685f217,
make sure all backends check this flag and return correct error codes.
Normally this is not mandatory, since the kernel looks up
the directory entry to be removed, and fails if the system call
is inappropriate (e.g., calling rmdir() on a regular file).
This happens before FUSE_UNLINK or FUSE_RMDIR is sent to the server.
However, when not in exclusive mode, there is a short window that
TOCTOU problem may occur, which may lead to undesired behavior
(e.g., deletion of a non-empty directory) or even the corruption of
bookmark storage if not properly checked.
Also explain this flag in the user manual.
In readonly mode, we're not using the current time as timestamp,
thus a bad system time won't hurt.
Also in Chromium backend, use zero timestamp for the bookmark root
dir, to accomodate this change (no one cares about it anyway).
When updating timestamps, make sure that the corresponding
microsecond value fits in a single signed 64-bit integer,
so that it won't result in an integer overflow, which is UB.
Also forbid timestamps before the Unix epoch, since working with
negative time_t is problematic.
This check does not apply to current timestamp, however,
add a check on backend startup to ensure sane system time.
There's no need to validate `tv_nsec`, since the kernel already
does that for us.
Do not expose UTIME_OMIT to backends, but instead specify
which timestamps to update with flags.
This allows us to further refactor backend code, especially
the Chromium backend.
- Follow the "best practice" in the SQLite manual, where calls to
sqlite3_column_bytes() should come after sqlite3_column_text().
This change does not affect the values returned.
- Other misc updates.
If a bookmark is assigned SYNC_STATUS_NORMAL (value 2),
a "tombstone" has to be inserted upon deletion,
so that the browser could purge it from remote.
- `hashmap_insert()` no longer takes key as argument, and
takes the pointer to be associated with the entry as argument.
- Rename `hashmap_entry_delete` -> `hashmap_delete`.
- Make `user_data` the first argument for `hashmap_walk_func`.
- Other misc renames.
There's a special kind of bookmark in Firefox known as "separator",
which appears as vertical or horizontal bars in the browser.
BookmarkFS currently does not support managing separators, but
the backend should be aware of their existence, and must not break
when one appears.
A separator always has a NULL `title` and `fk` in `moz_bookmarks`,
so it doesn't break `bookmark_list()` and `bookmark_lookup()`,
but breaks `bookmark_check()` since it could be mistaken for a
bookmark or bookmark folder with NULL title.
Fix by checking the bookmark type in `bookmark_check_cb()`.
The SQLite builtin function `length()` calculates the number of
Unicode code points of the given argument, while `octet_length()`
calculates the number of bytes.
The two functions should produce the same result for a URL since it's
always ASCII-only, however, with `octet_length()` the length can be
directly fetched from metadata without actually reading the URL text,
thereby improving performance.
Following commit 35d4a93a41, now only perform `PRAGMA quick_check`
in non-sandbox mode before querying data on the database.
Although in practice SQLite does well in terms of memory safety,
most likely way better than BookmarkFS itself, we consider
sandboxing a stronger security guarantee than `PRAGMA quick_check`.
Fix a regression in commit d1dac54b72 where sys/stat.h is no longer
included in backend_firefox.c and backend_chromium.c.
It has to be explicitly included for the UTIME_xxx macros.
Switch to schema version 74, so that it is compatible with
browsers (e.g., GNU IceCat) which are still based on
Firefox 115 ESR (now end-of-life), as well as saving us
a bit more space since there are fewer tables to be created.
Do not check if the bookmark title is a valid filename,
as we said in the user manual.
However, we should ensure that the string does not contain
NUL characters, since we assume that a valid bookmark storage
should not contain bookmarks with such names.
- Make sure all tables and indices are created for the database,
even the ones that are not used by BookmarkFS.
- Maintain the schema version in `PRAGMA user_version`.
- Always use `INT` for integer type, and `TEXT` for text type,
so that we could save a little space. This does not affect the
actual datatype (more precisely, type affinity) of the columns.
- Allow fdatasync(), since it is used by SQLite when commiting.
- Move `PRAGMA quick_check` to backend_create(), since it sometimes
calls stat() and cannot be sandboxed.