This manual is for BookmarkFS, version 0.1.6.
Copyright © 2024 CismonX <admin@cismon.net>
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled “GNU Free Documentation License”.
BookmarkFS is a FUSE-based pseudo-filesystem which provides an interface to the bookmark data of web browsers.
Currently, the following browsers (and their derivatives) are supported:
BookmarkFS is free software, distributed under the terms of the GNU General Public License, either version 3, or any later version of the license.
For instructions on how to build and install BookmarkFS, see the INSTALL.md file under the root directory of the project codebase.
BookmarkFS is hosted on Savannah, where latest releases, development sources and other information are available. Also see builds.sr.ht for CI build logs.
Currently, BookmarkFS only runs on GNU/Linux and FreeBSD.
Although BookmarkFS sticks hard to POSIX and avoids platform-specific features, porting it to other operating systems is not trivial.
The major pitfall is the FUSE dependency. FUSE was originally Linux-only. Recent versions of the FreeBSD kernel partially implements the FUSE protocol, however, that’s not the case for other operating systems.
For example, OpenBSD implements its own FUSE protocol, which is incompatible with the Linux one. OpenBSD does provide a libfuse-compatible library, however, it only covers the high-level API, while BookmarkFS uses the low-level API.
Other notable portability issues:
Not all operating system kernels provide sandboxing mechanisms similar to Linux and FreeBSD. See Sandboxing.
If unsupported, operations that require sandboxing should fail, unless sandboxing is explicitly disabled by the caller.
Before 16.0 (not yet released), the FreeBSD fusefs(5)
implementation does not support FUSE_IOCTL.
All custom ioctl(2) calls on a FUSE filesystem fail
with ENOTTY without the requests being sent to the FUSE server.
Thus, BookmarkFS features that depend on ioctl() do not work
on FreeBSD, which includes:
Meanwhile, FreeBSD does not support FUSE_READDIRPLUS and directory
entry caching, which makes listing directory entries less efficient.
Write to the mailing lists for bug reports, feature requests, and other discussions.
Please do not send feature patches, since BookmarkFS is currently in experimental stage, and is not yet ready for collaboration. Trivial patches, such as bugfix and typo corrections, are okay.
For security-related problems, please email directly to the project maintainer.
BookmarkFS ships with command-line programs to create, mount, fix, and manage BookmarkFS filesystems.
Those programs do not work on their own, and usually require a “backend” for low-level functionalities. See Backends.
mount.bookmarkfs ¶The mount.bookmarkfs program mounts a BookmarkFS filesystem.
mount.bookmarkfs [options] src target
The bookmark storage, presumably the pathname of a regular file that contains bookmark data.
The exact interpretation of this argument is backend-defined.
Pathname of the directory to mount the filesystem.
Files under the filesystem are assigned ownership according to
the effective user ID and group ID of the calling process.
On FreeBSD, you may wish to set the ‘vfs.usermount’
sysctl(8) to 1 for unprivileged mounts.
To unmount a BookmarkFS filesystem, run fusermount3(1)
(with the -u option) or umount(8) on target.
Options:
The backend used by the filesystem (see Backends). This option is mandatory.
Alternatively, name could be specified in ‘lib_path:sym_name’ format, where:
Presumably the pathname to the backend library.
Its exact interpretation is equivalent to the first argument for
dlopen(3p).
A backend-specific option. This option can be provided multiple times.
File access mode. Defaults to ‘0700’.
This option applies to both directories and regular files. Execution bits on regular files are masked off.
Should be used in combination with -o allow_other for other users to access the files.
Maintain last status change time instead of last modification time.
From a browser’s perspective, the “modification time” attribute of a bookmark behaves differently from both mtime and ctime. In Chromium, for instance, when a bookmark is renamed, neither itself nor the parent directory changes timestamp accordingly.
In BookmarkFS, mtime behavior mostly stays compatible with POSIX, with a few caveats. Since a bookmark has only one “modification time” attribute instead of two, the user has to choose which one to maintain:
mtime updates normally; ctime value always follow mtime.
The kernel may automatically update and cache ctime, making it appear more “correct” than expected. However, this behavior should not be relied upon.
ctime updates normally; mtime value always follow ctime, even if the file content is not modified.
This behavior may be inefficient, but makes applications that depend on ctime less fragile.
Add a newline (ASCII LF character) to the end of each file.
Before writing the file content back to the backend, a trailing newline is automatically removed (if one exists).
Max file size limit. Defaults to ‘32768’.
This limit also applies to extended attribute values.
Do not enable sandboxing features (see Sandboxing).
Do not use Landlock for sandboxing. This option is ignored on non-Linux platforms.
Without Landlock, sandboxing offers less security. Nonetheless, we provide an option to disable it separately, since Landlock is a rather new feature (requires kernel version 5.13 or later).
Stay in the foreground, do not daemonize.
Print help text, and then exit.
If also given the -o backend=name option,
print help text of the corresponding backend.
This also applies to fsck.bookmarkfs and mkfs.bookmarkfs.
Print version and feature information, and then exit.
If also given the -o backend=name option,
print version information of the corresponding backend.
This also applies to fsck.bookmarkfs and mkfs.bookmarkfs.
Unrecognized options specified with -o are passed to libfuse (and subsequently to the kernel, if applicable) as-is. Notable options:
Mount the filesystem read/write.
Warning: Always backup the bookmark storage before mounting it read/write, or risk losing your data!
By default, the filesystem is mounted read-only. This behavior won’t change in the future, due to the hackish nature of most BookmarkFS backends.
When mounted read/write, other processes must not write to the underlying bookmark storage, otherwise data corruption may occur.
Set libfuse log level to FUSE_LOG_DEBUG.
Log messages related to each FUSE request will be printed to standard error.
Name for the filesystem. Defaults to the backend name.
This name is equivalent to the fs_spec field in fstab(5),
and appears as the ‘SOURCE’ column in findmnt(8) output.
These options (and other atime-related ones) are ignored.
BookmarkFS only supports noatime mounts, since the “last access time” attribute of a bookmark necessarily means “the last time it was accessed from the browser”. BookmarkFS should never update that time automatically.
Nonetheless, the user is still allowed to explicitly update atime
(e.g., with futimens(3p)).
Instruct libfuse to fork-exec a helper process, which automatically dismounts
the filesystem when the filesystem daemon terminates without unmounting,
so that the user don’t have to manually dismount the inactive filesystem.
See mount.fuse3(8) for details.
This option is helpful when sandboxing is enabled, especially when
given the -F option, since a sandboxed process itself can neither
umount(2) nor fork-exec.
Currently, this option is not available on FreeBSD.
fsck.bookmarkfs ¶The fsck.bookmarkfs program checks and optionally repairs a
BookmarkFS filesystem.
fsck.bookmarkfs [options] pathname
Filesystem check on BookmarkFS has a different purpose compared to on-disk filesystems. See Filesystem Check.
Depending on the options specified, filesystem check works either in online or offline mode:
In online mode, fsck is performed on a mounted BookmarkFS filesystem
using ioctl(2).
See Online Filesystem Check.
The pathname argument refers to the directory to operate on.
In offline mode, fsck is performed directly on the bookmark storage via the corresponding backend.
The pathname argument should be specified in ‘src:dir’ format:
Path to the bookmark storage, equivalent to the src argument given to
mount.bookmarkfs.
The bookmark directory to operate on, relative to the root directory of the BookmarkFS filesystem referred to by src.
Options:
The backend used by the filesystem. See Backends.
Value of name could be specified in an alternative format. See Alternative Backend Name.
If this option is not provided, or name is empty, performs online fsck. Otherwise perform offline fsck.
A backend-specific option. This option can be provided multiple times.
The handler for resolving errors found during fsck (see Filesystem-Check Handlers).
Alternatively, name could be specified in ‘lib_path:sym_name’ format, where:
Presumably the pathname to the fsck handler library.
Its exact interpretation is equivalent to the first argument for
dlopen(3p).
If this option is not provided, or name is empty, a built-in handler will be used. See Built-in Handler.
A handler-specific option. This option can be provided multiple times.
Attempt to repair errors found during fsck.
Warning: Always backup the bookmark storage before repairing, or risk losing your data!
Readline application name in interactive mode. Defaults to ‘fsck.bookmarkfs’.
See Conditional Init Constructs in GNU Readline Library.
Enable interactive mode.
Perform fsck on subdirectories recursively.
Cannot recurse across subsystems (subsystem root directory must be part of pathname).
Do not enable sandboxing features. See Sandboxing.
Do not use Landlock for sandboxing. This option is ignored on non-Linux platforms.
Also see Disabling Landlock.
Print help text, and then exit.
If also given the -o handler=name option, print help text of the corresponding fsck handler.
Print version and feature information, and then exit.
If also given the -o handler=name option, print version information of the corresponding fsck handler.
mkfs.bookmarkfs ¶The mkfs.bookmarkfs program creates a new BookmarkFS filesystem.
mkfs.bookmarkfs [options] pathname
The underlying bookmark storage for the new filesystem.
This option is equivalent to the src argument for
mount.bookmarkfs.
Options:
The backend used by the filesystem (see Backends). This option is mandatory.
Value of name could be specified in an alternative format. See Alternative Backend Name.
A backend-specific option. This option can be provided multiple times.
If the file referred to by pathname already exists, overwrite it.
Print help text, and then exit.
Print version and feature information, and then exit.
bookmarkctl ¶The bookmarkctl program is a command-line wrapper for various
operations on a BookmarkFS filesystem that cannot be done portably using
POSIX utilities alone, including I/O controls and managing extended attributes.
bookmarkctl subcmd [args]
Sub-commands:
permdRearranges the order of the directory entries to be returned from
future calls to readdir().
See Permute Directory Entries.
bookmarkctl permd [options] name1 name2 pathname
Filename of entries under the directory.
Path to the parent directory.
Options:
Exchange the positions of the directory entries represented by name1 and name2.
Move the directory entry represented by name1 to the position just before the one represented by name2.
Move the directory entry represented by name1 to the position just after the one represented by name2.
The -s, -b and -a options are mutually exclusive. If multiple options are provided, the last one takes effect.
fsckDisplays a list of filesystem errors found under the given directory. See Filesystem Check.
Does not recurse into subdirectories.
bookmarkctl fsck pathname
Path to the directory to perform checks on.
The output shares the same format with the built-in fsck handler. See Filesystem-Check Output Format.
For the full fsck functionalities, see fsck.bookmarkfs.
xattr-listDisplays a list of extended attribute names. See Extended Attributes.
bookmarkctl xattr-list pathname
Path to the file to obtain extended attribute names.
Only the names prefixed with ‘user.bookmarkfs.’ are listed, with the prefix removed.
xattr-getDisplays extended attribute values. See Extended Attributes.
bookmarkctl xattr-get [options] attrname pathname... bookmarkctl xattr-get [options] -a attrname... pathname
Name of the extended attribute, without the ‘user.bookmarkfs.’ prefix.
Path to the file to obtain extended attribute values.
Options:
Treat the value as binary, and print it verbatim.
If this option is not provided, non-printable characters are replaced with ‘?’.
Switch to multi-attrname mode, where multiple extended attribute names can be specified instead of multiple files.
Also, the corresponding attrname is printed alongside with the value, instead of pathname.
Print values only, do not print names.
If provided twice, do not print the suffix character after each value.
The character separating each name and value. Defaults to the ASCII HT character.
The character suffixing each value. Defaults to the ASCII LF character.
For the -s and -n options, if char contains multiple characters, the first one is used. If empty, the ASCII NUL character is used.
xattr-setUpdate the value of an extended attribute. See Extended Attributes.
bookmarkctl xattr-set [options] attrname pathname
Name of the extended attribute to update, without the ‘user.bookmarkfs.’ prefix.
Path to the file to update extended attribute value.
Options:
New value for the extended attribute.
If this option is not provided, the new value is read from standard input.
helpPrint help text, and then exit.
bookmarkctl help
versionPrint version information, and then exit.
bookmarkctl version
When a BookmarkFS filesystem is mounted using the mount.bookmarkfs
program, a daemon process acts as a proxy between the kernel (which relays
filesystem requests to FUSE requests) and the backend (which manipulates
actual bookmark data, see Backends), thus providing POSIX
(and platform-specific) filesystem API access to bookmarks.
BookmarkFS is designed in the hope that web browser bookmarks can be managed flexibly using a combination of existing software, without having to “reinvent the wheel”. However, like most other pseudo-filesystems, it cannot be considered fully POSIX-compliant. Users should be aware of the limitations when using BookmarkFS.
BookmarkFS has multiple subsystems. Each one appears as a directory under the mountpoint:
${mountpoint}/bookmarks
${mountpoint}/tags
${mountpoint}/keywords
If the backend does not support a subsystem, the corresponding directory does not exist.
Currently all subsystem definitions are hard-coded within the
mount.bookmarkfs program, and cannot be extended by the backend.
The “bookmarks” subsystem maintains the hierarchical structure, names, URLs and other information of a bookmark storage.
${mountpoint}/bookmarks/${bookmark_dir...}/${bookmark}
Each bookmark folder name appears as the filename for directory ${bookmark_dir}, and each ${bookmark} is a regular file that refers to a bookmark.
The name of a bookmark file is usually the “bookmark title”, which is the name that appears in the browser’s bookmark manager. The content of a bookmark file is usually the URL associated with the bookmark.
Not all bookmark names can be represented as a filename.
For a bookmark or bookmark folder with an invalid name, the corresponding file
is not visible to lookups and readdir() calls.
To deal with such bookmarks, see Filesystem Check;
or you can instruct the backend to identify bookmarks using GUIDs
instead of titles (and then access the titles via extended attributes).
Some file attributes are used to represent bookmark metadata:
st_inoID of the bookmark (stored as lower bits).
st_sizeLength of the bookmark URL in bytes.
Always 0 for directories.
st_atimLast access time of the bookmark.
st_mtimLast modification time of the bookmark. See Last Modification/Change Time.
Additional information of a bookmark or bookmark folder can be accessed via the extended attributes of the corresponding file, for backends that supports it. See Extended Attributes.
The “tags” subsystem maintains a many-to-many mapping between bookmarks and their alternative names.
${mountpoint}/tags/${tag_dir}/${bookmark}
Each tag name appears as the filename for directory ${tag_dir}, and ${bookmark} is a hard link to the bookmark file. A bookmark directory cannot be associated with a tag.
If multiple bookmark files with identical names are both associated with a tag,
it is unspecified which one appears as an entry for the tag directory.
However, consecutive lookups and readdir()s should produce consistent
results for that file, provided that it is not renamed or deleted.
Tag files behave differently from traditional hard links. If the associated bookmark file of a tag is renamed or deleted, it may change accordingly. It may even link to another file that was previously shadowed. Applications should tread lightly if they wish to cache tag directory entries.
To associate a bookmark with a tag, use link(3p):
fd = open("tags/gnu/readline", O_CREAT | O_WRONLY, 0600); // Oops, fd == -1, errno == EPERM fd = link("bookmarks/other/readline", "tags/gnu/readline", 0); // OK!
Make sure that the two files have identical names, otherwise link()
fails with EPERM.
The “keywords” subsystem maintains a one-to-one mapping between bookmarks and their alternative names, independent from tag names.
${mountpoint}/keywords/${keyword_name}
Each keyword name appears as the filename for regular file ${keyword_name}, which is a hard link to the bookmark file. A bookmark directory cannot be associated with a keyword.
To associate a bookmark with a keyword, use link(3p)
like we do with tags.
If the original file is already associated with another keyword,
link() fails with EEXIST.
When a filesystem operation fails, the kernel returns an error code for the system call. In addition to common error codes, there are a few more in BookmarkFS:
EPERMAttempting to perform an unsupported operation. For example:
chmod(), chown(), and other operations that make no sense
for web browser bookmarks.
EIOAn unexpected internal error occurred, likely due to a bug in BookmarkFS, or a corruption in the bookmark storage.
Once this error occurs, behavior of any further operations on the filesystem is undefined.
A log message describing the situation may be printed to the standard error of the filesystem daemon. Sometimes the error comes from the kernel, and there’s no error message.
ESTALEThe file associated with the file descriptor no longer exists.
The error may occur when the underlying bookmark storage has been modified by another process (e.g., a web browser) after opening a file.
If the filesystem is mounted in exclusive mode, this error should not occur. See Exclusive Mode.
Other BookmarkFS-specific errors may occur. See the corresponding manual section for details.
BookmarkFS uses extended attributes to manage additional information associated with a bookmark.
Extended attributes is a platform-specific feature.
On Linux, see xattr(7).
On FreeBSD, see extattr(2).
All BookmarkFS extended attributes fall under the “user” namespace,
which means they have a ‘user.’ name prefix on Linux, and should be
accessed with EXTATTR_NAMESPACE_USER on FreeBSD.
All attribute names have a ‘bookmarkfs.’ prefix.
For example, to get the GUID of a bookmark file (Firefox backend):
// Linux len = fgetxattr(fd, "user.bookmarkfs.guid", buf, sizeof(buf)); // FreeBSD len = extattr_get_fd(fd, EXTATTR_NAMESPACE_USER, "bookmarkfs.guid", buf, sizeof(buf));
BookmarkFS does not define any common attributes, neither can users create arbitrary ones. The backend context decides which attributes are available (see Create Backend Context), and all bookmark files under it share the same set of attributes.
POSIX consider ‘.’ and ‘..’ as “special” filenames, which must refer to the current and parent directory, if they exist.
These entries are optional, and BookmarkFS does not support them, for the sake of simplicity. Additionally, bookmarks with such names are hidden from the filesystem until fixed with fsck (see Filesystem Check).
POSIX does not specify the ordering of the directory entries retrieved from
the directory stream using readdir(3p).
It only guarantees that if an entry is not added or removed from the directory
after the most recent call to opendir(3p) or
rewinddir(3p), that entry is returned once and only once.
This allows filesystem implementations to organize directory entries in a more relaxed manner. There could be extra overhead to maintain a predictable ordering of directory entries, since they may not have a linear structure on modern on-disk filesystems (e.g., ext4 uses htree for large directories).
As for users of a filesystem, the order of directory entries generally does not matter. If they care, they can add a prefix to the filename, and let the application do the sorting.
However, the order of which a bookmark entry appears in the web browser sometimes does matter. In BookmarkFS, the directory traversal order is guaranteed to be equivalent to that order. New entries are appended to the end; removed entries do not affect the order of other entries.
To change the order of directory entries, see Permute Directory Entries.
BookmarkFS provides an I/O control for rearranging directory entries:
struct bookmarkfs_permd_data permd_data = { /* ... */ }; status = ioctl(dirfd, BOOKMARKFS_IOC_PERMD, &permd_data); // ...
The bookmarkfs_permd_data structure is defined as:
#include <bookmarkfs/ioctl.h> struct bookmarkfs_permd_data { enum bookmarkfs_permd_op op; char name1[NAME_MAX + 1]; char name2[NAME_MAX + 1]; };
The op field denotes the operation to perform on the directory:
BOOKMARKFS_PERMD_OP_SWAPExchange the positions of the directory entries represented by name1
and name2.
BOOKMARKFS_PERMD_OP_MOVE_BEFOREMove the directory entry represented by name1 to the position just
before the one represented by name2.
BOOKMARKFS_PERMD_OP_MOVE_AFTERMove the directory entry represented by name1 to the position just
after the one represented by name2.
On success, ioctl() returns 0.
Otherwise, it returns -1 and sets errno:
EACCESWrite or search permission is denied for the directory.
EINVALop is not one of the values defined in enum bookmarkfs_permd_op.
EINVALname1 or name2 is not a valid filename
(e.g., empty string; contains ‘/’ character).
ENOENTThe directory does not contain entries named name1 or name2.
ENOTTYThe kernel does not support FUSE_IOCTL.
See Limitations on FreeBSD.
EPERMThe backend does not support rearranging entries for this directory.
To ensure that the order change is visible to further readdir() calls,
fsync() or close() the directory.
On-disk filesystems may suffer from data corruption due to power loss or hardware failures, thus they usually provide a “filesystem check” mechanism to detect and fix those problems.
As a pseudo-filesystem, BookmarkFS does not check for data integrity, and “filesystem check” is given a new purpose: To check if a bookmark name is valid as a filename, and “repair” (rename) it if it isn’t.
A POSIX-compliant filesystem has various restrictions regarding filenames:
NAME_MAX
It is commonplace for bookmark names to not meet such criteria, thus a filesystem check is often necessary when switching to BookmarkFS from another bookmark management software.
BookmarkFS provides I/O controls to perform online filesystem checks:
struct bookmarkfs_fsck_data fsck_data = { /* ... */ }; result = ioctl(dirfd, BOOKMARKFS_IOC_FSCK_NEXT, &fsck_data); // ... result = ioctl(dirfd, BOOKMARKFS_IOC_FSCK_APPLY, &fsck_data); // ... result = ioctl(dirfd, BOOKMARKFS_IOC_FSCK_REWIND); // ...
The bookmarkfs_fsck_data structure is defined as:
#include <bookmarkfs/ioctl.h> struct bookmarkfs_fsck_data { uint64_t id; uint64_t extra; char name[NAME_MAX + 1]; };
Filesystem-check commands:
BOOKMARKFS_IOC_FSCK_NEXTFind the next bookmark with invalid name under the directory.
On success, ioctl() updates fsck_data, and returns
one of the values defined in enum bookmarkfs_fsck_result:
BOOKMARKFS_FSCK_RESULT_ENDThere are no more bookmarks with invalid name under the directory.
Fields in fsck_data have unspecified values.
BOOKMARKFS_FSCK_RESULT_NAME_DUPLICATEThe bookmark name duplicates with another bookmark which appears earlier in the directory stream.
Value of extra is the ID of the other bookmark.
BOOKMARKFS_FSCK_RESULT_NAME_BADCHARThe bookmark contains a bad character (i.e., the ASCII ‘/’ character).
Value of extra is the byte offset where the bad character first appears
in name.
BOOKMARKFS_FSCK_RESULT_NAME_BADLENThe bookmark name is either longer than NAME_MAX, or an empty string.
Value of extra is the length of the bookmark name, and name
is truncated if longer than NAME_MAX.
BOOKMARKFS_FSCK_RESULT_NAME_DOTDOTThe bookmark name is either ‘.’ or ‘..’.
Value of extra is unspecified.
On failure, ioctl() returns -1, and sets errno.
BOOKMARKFS_IOC_FSCK_APPLY“Repair” a bookmark by renaming it.
The id field must be set to a value previously obtained from
BOOKMARKFS_IOC_FSCK_NEXT with the same dirfd,
otherwise the behavior is undefined.
The name field should be set to the new name for the bookmark.
The extra field is unused.
On success, ioctl() updates fsck_data, and returns
one of the values defined in enum bookmarkfs_fsck_result,
like with BOOKMARKFS_IOC_FSCK_NEXT.
Additionally, it may also return:
BOOKMARKFS_FSCK_RESULT_NAME_INVALIDThe new name is not a valid bookmark name.
Value of extra is a backend-specific reason code
explaining why the bookmark name is invalid.
It may equal to one of the following predefined values:
BOOKMARKFS_NAME_INVALID_REASON_NOTUTF8The name is not valid UTF-8.
On failure, ioctl() returns -1, and sets errno:
EACCESWrite or search permission is denied for the directory.
To ensure that the rename is visible to further lookups and readdir()
calls, fsync() or close() the directory.
BOOKMARKFS_IOC_FSCK_REWINDReset the fsck state for the directory.
Further BOOKMARKFS_IOC_FSCK_NEXT requests will start from the
beginning of the directory stream.
On success, ioctl() returns 0.
Otherwise, it returns -1, and sets errno.
Common error codes for all filesystem-check ioctls:
ENOTTYThe kernel does not support FUSE_IOCTL.
See Limitations on FreeBSD.
EPERMThe backend does not support fsck for this directory.
In BookmarkFS, each backend provides a way to manipulate a certain kind of application bookmarks.
Typically, backends are built into shared libraries, and are installed as:
${pkglibdir}/backend_${name}${shlib_suffix}
Presumably ${prefix}/lib/bookmarkfs. See The Uniform Naming Scheme in GNU Automake.
The backend name, equivalent to the value given to the -o backend=name option of frontend programs.
The common filename extension for shared library files on the current platform (e.g., .so on GNU/Linux and FreeBSD).
The Firefox backend provides access to the bookmark data of the web browser Mozilla Firefox and its derivatives, notably Tor Browser and Librewolf.
Backend name (for the -o backend=name option): ‘firefox’.
Firefox bookmarks are stored in a SQLite database under the profile directory.
When mounting the filesystem, this pathname shall be passed as the src
argument (see mount.bookmarkfs):
~/.mozilla/firefox/${profile_name}/places.sqlite
Actual path for the profile directories may differ across distributions.
When in doubt, visit ‘about:profiles’ in your browser.
Backend-specific options (mount.bookmarkfs only):
Whether to use the bookmark title or GUID as the bookmark file name. Defaults to ‘title’.
A bookmark GUID is a base64url-encoded 128-bit string uniquely associated with a bookmark or bookmark folder.
When creating a new file:
The GUID is randomly generated by the backend.
The filename must be a valid GUID, and must not duplicate with other files
on the same filesystem, otherwise open() or mkdir() fails
with EPERM.
Also set the GUID string as the bookmark title.
The database connection locking mode for the bookmark storage. Defaults to ‘normal’ when the filesystem is mounted read-only, ‘exclusive’ otherwise.
This option corresponds to the locking_mode pragma on SQLite.
With lock=exclusive, other processes cannot access
the bookmark storage until the filesystem is dismounted.
The Firefox browser holds an exclusive lock on the database by default. If you wish to mount the bookmarks while keeping the browser session open, set the ‘storage.sqlite.exclusiveLock.enabled’ browser preference to ‘false’.
The lock=exclusive option also enables exclusive mode (see Exclusive Mode).
If this options is provided, the backend assumes that bookmark names are distinct under the same bookmark folder. This option is ignored with filename=guid.
This option may improve readdir() performance, however,
making a false assumption results in a directory entry with duplicate names.
It is recommended to perform a full filesystem check (see Filesystem Check)
on the bookmark storage before mounting with this option.
If launched from fsck.bookmarkfs, all backend-specific options
are ignored, and always enforces the lock=exclusive option.
Backend-specific options (mkfs.bookmarkfs only):
File creation time for the predefined bookmark directories. Defaults to the current time.
Format of timestamp is equivalent to the ‘date_added’ extended attribute (see below).
Extended attributes:
The bookmark title. Only available with filename=guid.
This value is allowed be set to any string that does not contain a NUL character, and does not have to be valid as a filename.
The bookmark GUID. Only available with filename=title.
An arbitrary text associated with the bookmark.
Usually, when bookmarking a page in the browser, this value is
set to the content attribute of the <meta> element
whose name is ‘description’.
The bookmark creation time.
Value is a decimal integer representing number of microseconds since the Unix epoch.
The keyword associated with the bookmark. See Keywords.
This attribute is read-only.
Notable limitations:
The Chromium backend provides access to the bookmark data of the web browser Chromium and its derivatives, notably ungoogled-chromium.
Backend name (for the -o backend=name option): ‘chromium’.
Chromium bookmarks are stored in a text file (in JSON format)
under the profile directory.
When mounting the filesystem, this pathname shall be passed as the src
argument (see mount.bookmarkfs):
~/.config/chromium/${profile_name}/Bookmarks
Actual path for the profile directories may differ across distributions.
When in doubt, visit ‘chrome://profile-internals/’ in your browser.
Backend-specific options (mount.bookmarkfs only):
Whether to use the bookmark title or GUID as the bookmark file name. Defaults to ‘title’.
A bookmark GUID is a hex-encoded 128-bit string uniquely associated with a bookmark or bookmark folder. It has a “8-4-4-4-12” format, with all alphabetic characters in lowercase. For example:
0bc5d13f-2cba-5d74-951f-3f233fe6c908
When creating a new file:
The GUID is randomly generated by the backend. It is guaranteed to be a valid version 4 UUID as specified by RFC 4122.
The filename must be a valid GUID, and must not duplicate with other files
on the same filesystem, otherwise open() or mkdir() fails
with EPERM.
Also set the GUID string as the bookmark title.
The file watcher to use for the bookmark storage. Defaults to ‘native’ when the filesystem is mounted read-only, ‘none’ otherwise.
Watch for changes of the bookmark storage, either using a “native” implementation using platform-specific features, or a “fallback” one which is less efficient but more portable.
See File Watcher.
Do not watch for changes of the bookmark storage.
External changes are not visible to the BookmarkFS filesystem, and will be lost if the backend writes to the bookmark storage.
This option also enables exclusive mode (see Exclusive Mode).
If launched from fsck.bookmarkfs, all backend-specific options
are ignored, and always enforces the watcher=none option.
Backend-specific options (mkfs.bookmarkfs only):
File creation time for the predefined bookmark directories. Defaults to the current time.
Format of timestamp is equivalent to the ‘date_added’ extended attribute (see below).
Extended attributes:
The bookmark title. Only available with filename=guid.
This value is allowed be set to any UTF-8 string that does not contain a NUL character, and does not have to be valid as a filename.
The bookmark GUID. Only available with filename=title.
The bookmark creation time.
Value is a decimal integer representing number of microseconds since
the Windows FILETIME epoch (134774 days ahead of the Unix epoch).
Notable limitations:
The Backend API specifies how a BookmarkFS backend communicates with a
frontend program (e.g., mount.bookmarkfs).
Warning: Currently BookmarkFS is experimental. The Backend API may change drastically without prior notice.
To implement the Backend API, a backend library should expose a symbol with the following name:
bookmarkfs_backend_${name}
Where ${name} is equivalent to the value given to the -o backend=name option of frontend programs.
The symbol should name a data object identifier of the following type:
#include <bookmarkfs/backend.h> struct bookmarkfs_backend { bookmarkfs_backend_create_func *backend_create; bookmarkfs_backend_destroy_func *backend_destroy; bookmarkfs_backend_info_func *backend_info; bookmarkfs_backend_init_func *backend_init; bookmarkfs_backend_mkfs_func *backend_mkfs; bookmarkfs_backend_sandbox_func *backend_sandbox; bookmarkfs_bookmark_check_func *bookmark_check; bookmarkfs_bookmark_get_func *bookmark_get; bookmarkfs_bookmark_list_func *bookmark_list; bookmarkfs_bookmark_lookup_func *bookmark_lookup; bookmarkfs_bookmark_create_func *bookmark_create; bookmarkfs_bookmark_delete_func *bookmark_delete; bookmarkfs_bookmark_permute_func *bookmark_permute; bookmarkfs_bookmark_rename_func *bookmark_rename; bookmarkfs_bookmark_set_func *bookmark_set; bookmarkfs_bookmark_sync_func *bookmark_sync; bookmarkfs_cookie_free_func *cookie_free; };
Each field is a function pointer provided by the backend.
Some can be optional and set to NULL, if the backend
does not support the corresponding features.
Currently, all BookmarkFS programs are single-threaded, and backend functions are called sequentially. This is an intended design to keep BookmarkFS simple. Multithreading may help with performance in some scenarios, but not much, and we choose not to bother with it.
A downside of the this design is that backends should refrain from spending too much time in a function, especially waiting for I/O. Once a backend function blocks, the entire filesystem hangs. Future iterations of the Backend API may introduce event notification mechanisms to improve the situation.
Sometimes a backend may wish to use multithreading internally for whatever reason. If it does, a few more precautions should be taken in mind:
SIGINT, SIGTERM and SIGHUP signals should
be blocked with pthread_sigmask(3p) for the child threads.
If a signal is delivered to a child thread, the program may not be terminated
promptly, since libfuse relies on EINTR to break out of the event loop.
A backend context maintains internal states for manipulating a specific bookmark storage.
Each BookmarkFS filesystem mounted by mount.bookmarkfs is
backed by a backend context.
The context is created before mount, and destroyed after dismount.
Backend functions that operate on a single context accept an argument
(usually named backend_ctx) which refers to the context.
Some backend functions (e.g., bookmark_get) accept a function pointer
argument, usually named callback, to be invoked by the backend.
It is guaranteed that backend functions are never called from within a callback function.
If exclusive mode is enabled for a backend context, modifications to the corresponding bookmark storage should only be performed by calling backend functions on the current context. If the bookmark storage is modified by other means, filesystem and backend behavior is undefined.
Frontend programs may perform optimizations based on this assumption.
The backend decides whether exclusive mode should be enabled for a context
during backend_create (see Create Backend Context),
by setting the BOOKMARKFS_BACKEND_EXCLUSIVE response flag.
Some backend functions return an error code on failure instead of
just -1.
For backend functions analogous to the corresponding filesystem calls, the error code should honor POSIX as well as platform-specific conventions. For example:
bookmark_rename,
the function should fail with EEXIST or ENOTEMPTY as specified
in rename(3p).
ENODATA on Linux, and ENOATTR
on FreeBSD.
See Extended Attributes.
Also see Error Codes for BookmarkFS-specific error codes.
A backend function may also return other error codes which it sees fit, however, they should be chosen carefully. A bad error code may confuse filesystem users or even break applications.
The backend_init function is called before any other functions
(except for backend_info).
If not NULL, it is guaranteed to be called exactly once
throughout the lifetime of the process.
Type of the backend_init function is defined as:
typedef int (bookmarkfs_backend_init_func) ( uint32_t flags );
Function arguments:
flagsA bit array of the following flags:
BOOKMARKFS_BACKEND_LIB_READYIndicates that the utility library is already initialized. See The Utility Library.
Some frontend programs use the utility library. If they do, they always initialize it before initializing the backend. The utility library must not be initialized multiple times, otherwise the behavior is undefined.
BOOKMARKFS_FRONTEND_FSCKBOOKMARKFS_FRONTEND_MOUNTBOOKMARKFS_FRONTEND_MKFSDenotes the frontend program that launches the backend. These flags are mutually exclusive.
The function should return 0 on success, and -1 on error.
The backend_info function is called to print information
about the backend.
It can be NULL.
When this function is called, it should write a human-readable message of the corresponding information to standard output.
Type of the backend_info function is defined as:
typedef void (bookmarkfs_backend_info_func) ( uint32_t flags );
Function arguments:
flagsA bit array of the following flags:
BOOKMARKFS_BACKEND_INFO_HELPIndicates that the function should print a help message.
Mutually exclusive with BOOKMARKFS_BACKEND_INFO_VERSION.
The message should contain a brief description of this backend, as well as a list of backend-specific options.
BOOKMARKFS_BACKEND_INFO_VERSIONIndicates that the function should print a version message.
Mutually exclusive with BOOKMARKFS_BACKEND_INFO_HELP.
In addition to the version number, the version message may contain dependency versions, compile-time options, and other information that can be used to determine a specific version of the backend.
BOOKMARKFS_FRONTEND_FSCKBOOKMARKFS_FRONTEND_MOUNTBOOKMARKFS_FRONTEND_MKFSDenotes the frontend program that launches the backend. These flags are mutually exclusive.
The backend_create function is called to create a backend context.
It must not be NULL.
Type of the backend_create function is defined as:
typedef int (bookmarkfs_backend_create_func) ( struct bookmarkfs_backend_conf const *conf, struct bookmarkfs_backend_create_resp *resp );
Function arguments:
confBackend configuration items.
The bookmarkfs_backend_conf structure is defined as:
struct bookmarkfs_backend_conf { uint32_t version; uint32_t flags; char *store_path; struct bookmarkfs_conf_opt *opts; };
versionVersion number of the frontend program, equivalent to the
BOOKMARKFS_VERNUM macro in ${pkgincludedir}/version.h.
flagsA bit array of the following flags:
BOOKMARKFS_BACKEND_READONLYIndicates that the filesystem is mounted read-only, and the functions that may write to the bookmark storage will not be called for this session.
BOOKMARKFS_BACKEND_CTIMEIndicates that the -o ctime option is given to
mount.bookmarkfs.
BOOKMARKFS_BACKEND_NO_SANDBOXIndicates that the -o no_sandbox option is given to
mount.bookmarkfs.
If the backend does not support sandboxing, backend_create should fail.
Otherwise, function backend_sandbox should be implemented.
See Enter Sandbox.
BOOKMARKFS_BACKEND_NO_LANDLOCKIndicates that the -o no_landlock option is given to
mount.bookmarkfs.
BOOKMARKFS_BACKEND_FSCK_ONLYIndicates that the backend is launched from fsck.bookmarkfs.
Exclusive mode must be enabled for this context (see Exclusive Mode), and
only the bookmark_lookup, bookmark_list, bookmark_check
and bookmark_sync functions will be called on the bookmark objects.
store_pathPath to the bookmark storage, equivalent to the src argument passed to
mount.bookmarkfs.
The string is guaranteed to be NUL-terminated, and valid throughout the lifetime of the current backend. The function is free to modify the string, however, it must not write past the string boundary.
optsLinked list of backend-specific options, NULL if there are none.
The bookmarkfs_conf_opt structure is defined as:
struct bookmarkfs_conf_opt { char *key; char *val; struct bookmarkfs_conf_opt *next; };
keyvalKey and value of the current option.
If the option does not have a value (no ‘=’ character present),
val is NULL.
When not NULL, the strings are guaranteed to be NUL-terminated,
and valid throughout the lifetime of the current backend context.
The function is free to modify the strings, however, it must not write past
the string boundary.
nextPointer to the next option, NULL if there are no more options.
The backend must not re-assign the fields in opt.
respInformation of the new backend context.
The initial content of this argument is unspecified. When the backend context is successfully created, the function should populate this argument with appropriate values.
The bookmarkfs_backend_create_resp structure is defined as:
struct bookmarkfs_backend_create_resp { char const *name; void *backend_ctx; uint64_t bookmarks_root_id; uint64_t tags_root_id; char const *xattr_names; uint32_t flags; };
nameName of the backend context, used as default value for the
-o fsname=name option of mount.bookmarkfs.
Must be a NUL-terminated string valid at least until the next function call on this backend context.
backend_ctxAn opaque pointer referring to the backend context.
The pointer will be passed to further function calls on this context.
bookmarks_root_idID of the bookmarks root directory
(i.e., ${mountpoint}/bookmarks).
Must not be greater than BOOKMARKFS_MAX_ID.
If sandboxing is requested, and the ID cannot be determined in a safe way
before entering sandbox, the backend may leave this field as-is or set it
to UINT64_MAX.
tags_root_idID of the tags root directory (i.e., ${mountpoint}/tags).
Must not be greater than BOOKMARKFS_MAX_ID.
This field should be left as-is or set to UINT64_MAX,
if one of the following conditions is met:
xattr_namesNames of extended attributes (see Extended Attributes) supported for this backend context.
Must be a concatenation of NUL-terminated strings valid throughout the lifetime of this backend context. An empty string denotes the end of list.
flagsA bit array of the following flags:
BOOKMARKFS_BACKEND_EXCLUSIVEIndicates that the backend claims exclusive access to the bookmark storage. See Exclusive Mode.
BOOKMARKFS_BACKEND_HAS_KEYWORDIndicates that the backend supports keywords for this context. See Keywords.
The function should return 0 on success, and -1 on error.
The backend_destroy function is called to destroy a backend context.
It must not be NULL.
Upon destruction, the backend should release all system resources associated with this context. Changes made to the bookmark storage should be persisted.
Type of the backend_destroy function is defined as:
typedef void (bookmarkfs_backend_destroy_func) ( void *backend_ctx );
Function arguments:
backend_ctxThe pointer referring to the backend context.
The backend_sandbox function is called to instruct the backend to
enter a sandboxed state, where it has limited access to system resources,
thereby improving security.
See Sandboxing.
This function is only called if the BOOKMARKFS_BACKEND_NO_SANDBOX flag
is not set for this context.
Considering how sandboxing is usually implemented,
it may be complicated or even impractical for multiple backend contexts
to enter sandbox separately without affecting one another.
Thus it is guaranteed that, when launched from a frontend program like
mount.bookmarkfs which requires sandboxing, only one
backend context will be created throughout the lifetime of the process.
Type of the backend_sandbox function is defined as:
typedef int (bookmarkfs_backend_sandbox_func) ( void *backend_ctx, struct bookmarkfs_backend_create_resp *resp );
Function arguments:
backend_ctxThe pointer referring to the backend context.
respSee Backend-Create Response for the definition of
struct bookmarkfs_backend_create_resp.
Fields in this argument should be left as-is, except for:
bookmarks_root_idThis field must be set to the ID of the bookmarks root directory,
if not already done so in backend_create.
tags_root_idThis field should be set to the ID of the tags root directory,
if not already done so in backend_create.
If the backend does not support tags for this context, this field should be
left as-is or set to UINT64_MAX.
The function should return 0 on success, and -1 on error.
Once this function fails, no further function calls will be performed
on the backend except for backend_destroy.
The bookmark_lookup function is called to obtain the attributes of
a bookmark or a bookmark-related object.
It must not be NULL.
Type of the bookmark_lookup function is defined as:
typedef int (bookmarkfs_bookmark_lookup_func) ( void *backend_ctx, uint64_t id, char const *name, uint32_t flags, struct bookmarkfs_bookmark_stat *stat_buf );
Function arguments:
backend_ctxThe pointer referring to the backend context.
idID of the object to be used for lookup.
It could be a bookmark ID or tag ID, depending on the value of flags.
nameName of the object to lookup.
It could be a bookmark name, tag name or keyword name,
depending on the value of flags.
When not NULL, name is guaranteed to be a valid filename,
which should be used to lookup an object under the directory referred to
by id.
Otherwise, the function should operate on the object referred to
by id itself.
flagsA bit array of the following flags:
BOOKMARKFS_BOOKMARK_TYPE_MASKThe subsystem to operate on.
Equals to one of the following values (after shifting):
stat_bufAttributes of the object to lookup.
The initial content of this argument is unspecified. When the object is successfully found, the function should populate this argument with appropriate values.
The bookmarkfs_bookmark_stat structure is defined as:
struct bookmarkfs_bookmark_stat { uint64_t id; ssize_t value_len; struct timespec atime; struct timespec mtime; };
idID of the object.
value_lenLength of the object value in bytes.
-1 if the object refers to a directory.
atimemtimeLast access and modification time of the object.
Values should be the time elapsed since the Unix epoch.
On success, the function should return 0.
Otherwise, it should return a negated errno indicating
the error encountered.
The bookmark_list function is called to list the bookmarks or
bookmark-related objects under a directory.
It must not be NULL.
Type of the bookmark_list function is defined as:
typedef int (bookmarkfs_bookmark_list_func) ( void *backend_ctx, uint64_t id, off_t off, uint32_t flags, bookmarkfs_bookmark_list_cb *callback, void *user_data, void **cookie_ptr );
Function arguments:
backend_ctxThe pointer referring to the backend context.
idObject ID of the directory.
It could be a bookmark ID or tag ID, depending on the value of flags.
offPosition of the current bookmark_list operation, equivalent to
the second argument for seekdir(3p).
Initially, the value is always 0.
Subsequent calls (with the same cookie) use the values obtained from
entry->off of callback function calls.
If not, the position is unspecified.
A subsequent call with a 0 value indicates rewinddir(3p).
flagsA bit array of the following flags:
BOOKMARKFS_BOOKMARK_LIST_WITHSTATIndicates that the caller requires the attributes of the objects in the list.
BOOKMARKFS_BOOKMARK_TYPE_MASKThe subsystem to operate on.
Equals to one of the following values (after shifting):
callbackFunction to be called for each object found under the directory.
If NULL, bookmark_list should return immediately
without changing current position.
Ordering of the objects should follow the ordering of which they appear in the browser. See Directory Entry Ordering.
Type of the callback function is defined as:
typedef int (bookmarkfs_bookmark_list_cb) ( void *user_data, struct bookmarkfs_bookmark_entry const *entry );
Function arguments:
user_dataMust be equal to the user_data argument value for the current
bookmark_list call.
entryInformation of this object.
The bookmarkfs_bookmark_entry structure is defined as:
struct bookmarkfs_bookmark_entry { char const *name; off_t off; struct bookmarkfs_bookmark_stat stat; };
nameName of the object entry. Must be a valid filename.
Objects with invalid name should be exempted from the list. See Filesystem Check.
offPosition of the current entry, to be used for subsequent calls to
bookmark_list.
statAttributes of the object entry.
See Bookmark Attributes for the definition of
struct bookmarkfs_bookmark_stat.
If the BOOKMARKFS_BOOKMARK_LIST_WITHSTAT flag is not given,
the caller ignores atime and mtime, and only use value_len
to determine whether the entry refers to a directory.
Values of entry and name only need to be valid
until the callback function returns.
Return value:
0Continue to the next entry, if one exists.
Stop listing entries, and use this value as the return value for
the current bookmark_list call.
user_dataAn opaque pointer which should be passed as-is to the callback function.
cookie_ptrPointer to the “cookie” for the current bookmark_list operation.
NULL if not used by the caller.
The “cookie” is an opaque pointer which stores internal states to be used for subsequent operations on the same directory.
If the value pointed to by cookie_ptr is NULL, it indicates
that this is an initial operation.
The function should set the value to a pointer which is not NULL.
The cookie obtained from bookmark_list may be used for
bookmark_check, and vise versa.
However, the position of each operation should be maintained separately.
The function must not change the cookie value.
Return value:
0All entries in the directory have been listed.
errnoAn error occurred.
The function is terminated by a call to callback that
returns a non-zero value.
If returning a negative value, the position of the current
bookmark_list operation is unspecified.
The bookmark_get function is called to get the content or
extended attribute value of a bookmark.
The “content” of a bookmark is equivalent to the content of a regular file on a BookmarkFS filesystem that refers to a bookmark. See Bookmarks.
Type of the bookmark_get function is defined as:
typedef int (bookmarkfs_bookmark_get_func) ( void *backend_ctx, uint64_t id, char const *xattr_name, bookmarkfs_bookmark_get_cb *callback, void *user_data, void **cookie_ptr );
Function arguments:
backend_ctxThe pointer referring to the backend context.
idID of the bookmark (could be a bookmark folder if xattr_name
is not NULL).
xattr_nameName of an extended attribute.
If not NULL, xattr_name is guaranteed to be a NUL-terminated
string, and the function should get the corresponding extended attribute value
instead of the bookmark content.
callbackFunction to be called for the required bookmark data.
It is guaranteed not to be NULL.
Type of the callback function is defined as:
typedef int (bookmarkfs_bookmark_get_cb) ( void *user_data, void const *value, size_t value_len );
Function arguments:
user_dataMust be equal to the user_data argument value of the current
bookmark_get call.
valueBookmark content (or extended attribute) data.
Must not be NULL.
It may contain arbitrary bytes, and only need to be valid until the
callback function returns.
value_lenLength of value in bytes.
The function returns 0 on success.
Otherwise, the function returns a negated errno which should be
used as the return value for the current bookmark_get call.
user_dataAn opaque pointer which should be passed as-is to the callback function.
cookie_ptrPointer to the “cookie” for the current bookmark_get operation.
NULL if not used by the caller.
The “cookie” is an opaque pointer which stores internal states
for subsequent operations on the same bookmark (and xattr_name)
to determine whether the corresponding data has changed.
If the value pointered to by cookie_ptr is NULL,
it indicates that this is an initial operation.
If the backend supports watching for changes of bookmark content,
it may set the value to a pointer which is not NULL.
The function must not change the cookie value.
On success, the function should return 0.
Otherwise, it should return a negated errno indicating the error
encountered.
Notable error codes:
EAGAINBookmark data has not been changed externally since
the last call to bookmark_get with the same cookie.
If this error code is returned, callback must not be called.
“Externally” means that the modification comes from another process
which has access to the bookmark storage.
In exclusive mode, this is not expected to happen, and bookmark_list
is always called with a cookie_ptr of NULL value.
See Exclusive Mode.
If changes cannot be detected in an efficient way, false positives are acceptable. False negatives are also acceptable for a short time duration (preferably no more than a few seconds).
When a cookie obtained from bookmark_list,
bookmark_get or bookmark_check is no longer used,
the cookie_free function is called.
It must not be NULL.
The function should release all system resources associated with this cookie.
Type of the cookie_free function is defined as:
typedef void (bookmarkfs_cookie_free_func) ( void *backend_ctx, void *cookie, enum bookmarkfs_cookie_type cookie_type );
Function arguments:
backend_ctxThe pointer referring to the backend context.
cookieCookie to be freed.
cookie_typeType of the cookie.
It must be one of the values defined in enum bookmarkfs_cookie_type:
BOOKMARKFS_COOKIE_TYPE_WATCHIndicates that the cookie is obtained from bookmark_get.
BOOKMARKFS_COOKIE_TYPE_LISTIndicates that the cookie is obtained from bookmark_list or
bookmark_check.
The bookmark_set function is called to update the data associated
with a bookmark or bookmark-related object.
It is never called when the filesystem is mounted read-only.
Type of the bookmark_set function is defined as:
typedef int (bookmarkfs_bookmark_set_func) ( void *backend_ctx, uint64_t id, char const *xattr_name, uint32_t flags, void const *val, size_t val_len );
Function arguments:
backend_ctxThe pointer referring to the backend context.
idID of the object to update.
It could be a bookmark ID or tag ID, depending on the value of flags.
xattr_nameName of an extended attribute.
If not NULL, xattr_name is guaranteed to be a NUL-terminated
string, and the function should update the corresponding extended attribute
value instead of the bookmark content.
flagsA bit array of the following flags:
BOOKMARKFS_BOOKMARK_SET_ATIMEBOOKMARKFS_BOOKMARK_SET_MTIMEIndicates that the function should update the timestamps associated with the object, instead of the bookmark content or extended attribute value.
The val argument points to an array of struct timespec,
the first element refers to the last access time, and the second element
refers to the last modification time for the object.
If a flag is not set, the corresponding timestamp should be left as-is.
Values of xattr_name and val_len are unspecified.
BOOKMARKFS_BOOKMARK_TYPE_MASKThe subsystem to operate on.
Equals to one of the following values (after shifting):
valPointer to the new value of the object data.
val_lenLength of the new value in bytes.
On success, the function should return 0.
Otherwise, it should return a negated errno indicating the error
encountered.
The backend does not need to update the last modification time of a bookmark upon bookmark content update, since the caller knows better when the bookmark content is actually modified, and always explicitly updates the mtime after a writeback.
However, if the BOOKMARKFS_BACKEND_CTIME flag is set for this context,
the function should automatically update the bookmark mtime to
the current time upon extended attribute update.
The bookmark_create function is called to create a new bookmark
or bookmark-related object.
It is never called when the filesystem is mounted read-only.
Type of the bookmark_create function is defined as:
typedef int (bookmarkfs_bookmark_create_func) ( void *backend_ctx, uint64_t parent_id, char const *name, uint32_t flags, struct bookmarkfs_bookmark_stat *stat_buf );
Function arguments:
backend_ctxThe pointer referring to the backend context.
parent_idID of the parent directory to create the new object.
It could be a bookmark ID or tag ID, depending on the value of flags.
nameName of the new object.
It could be a bookmark name, tag name or keyword name,
depending on the value of flags.
flagsA bit array of the following flags:
BOOKMARKFS_BOOKMARK_CREATE_DIRIndicates that the new object to be created should be a directory.
If this flag is not set, the new object should be a bookmark.
BOOKMARKFS_BOOKMARK_TYPE_MASKThe subsystem to operate on.
Equals to one of the following values (after shifting):
BOOKMARKFS_BOOKMARK_TYPE_BOOKMARKCreate a bookmark or bookmark folder. See Bookmarks.
BOOKMARKFS_BOOKMARK_TYPE_TAGCreate a tag, or associate an existing bookmark with a tag. See Tags.
BOOKMARKFS_BOOKMARK_TYPE_KEYWORDAssociate an existing bookmark with a new keyword. See Keywords.
The value of parent_id is unspecified.
stat_bufAttributes of the new object.
See Bookmark Attributes for the definition of
struct bookmarkfs_bookmark_stat.
Except for the id field, the initial content of this argument
is unspecified.
When the object is successfully found, the function should populate
this argument with appropriate values.
When associating an existing bookmark with a tag or keyword, the initial
value of the id field refers to the bookmark to be associated.
Generally it should be left as-is, but the backend is allowed to
re-assign it to the ID of another bookmark (see below for restrictions).
On success, the function should return 0.
Otherwise, it should return a negated errno indicating the error
encountered.
Restrictions for the new object:
Bookmark content should be empty if possible.
Other reasonable values (e.g., ‘about:blank’) are also acceptable if the bookmark storage does not allow empty bookmark content.
Should not contain any entries.
Should appear to be the same object as the associated bookmark, or at least contain the same content.
When a new object is successfully created, the function should automatically update the last modification time of the parent directory to the current time.
The bookmark_rename function is called to rename and/or reparent
a bookmark or a bookmark-related object.
It is never called when the filesystem is mounted read-only.
Type of the bookmark_rename function is defined as:
typedef int (bookmarkfs_bookmark_rename_func) ( void *backend_ctx, uint64_t old_parent_id, char const *old_name, uint64_t new_parent_id, char const *new_name, uint32_t flags );
Function arguments:
backend_ctxThe pointer referring to the backend context.
old_parent_idID of the parent directory containing the object to be renamed.
It could be a bookmark ID or tag ID, depending on the value of flags.
old_nameName of the object to be renamed.
It could be a bookmark name, tag name or keyword name,
depending on the value of flags.
new_parent_idID of the new parent directory for the object.
new_nameNew name of the object.
flagsA bit array of the following flags:
BOOKMARKFS_BOOKMARK_RENAME_NOREPLACEIndicates that the function should not replace an existing object.
This flag is analogous to the RENAME_NOREPLACE flag for
renameat2(2).
BOOKMARKFS_BOOKMARK_TYPE_MASKThe subsystem to operate on.
Equals to one of the following values (after shifting):
BOOKMARKFS_BOOKMARK_TYPE_BOOKMARKRename a bookmark. See Bookmarks.
BOOKMARKFS_BOOKMARK_TYPE_TAGRename a tag. See Tags.
The function should fail with EPERM if either old_parent_id
or new_parent_id does not refer to the tags root directory,
since renaming a tag association makes no sense.
BOOKMARKFS_BOOKMARK_TYPE_KEYWORDRename a keyword. See Keywords.
Values of old_parent_id and new_parent_id are unspecified.
On success, the function should return 0.
Otherwise, it should return a negated errno indicating the error
encountered.
When replacing an existing object:
Upon successful completion, the function should automatically update the last modification time of the parent directories.
The bookmark_delete function is called to remove a bookmark or
a bookmark-related object.
It is never called when the filesystem is mounted read-only.
Type of the bookmark_delete function is defined as:
typedef int (bookmarkfs_bookmark_delete_func) ( void *backend_ctx, uint64_t parent_id, char const *name, uint32_t flags );
Function arguments:
backend_ctxThe pointer referring to the backend context.
parent_idID of the parent directory containing the object to be removed.
It could be a bookmark ID or tag ID, depending on the value of flags.
nameName of the object to be removed.
It could be a bookmark name, tag name or keyword name,
depending on the value of flags.
flagsA bit array of the following flags:
BOOKMARKFS_BOOKMARK_DELETE_DIRIndicates that the object to be removed is a directory.
If the current backend context is not in exclusive mode
(see Exclusive Mode), this information may be incorrect.
If so, the function should fail with ENOTDIR or EISDIR.
BOOKMARKFS_BOOKMARK_TYPE_MASKThe subsystem to operate on.
Equals to one of the following values (after shifting):
On success, the function should return 0.
Otherwise, it should return a negated errno indicating the error
encountered.
Upon successful completion, the function should automatically update the last modification time of the parent directory.
The bookmark_permute function is called to rearrange bookmarks
or bookmark-related objects under a directory.
It is never called when the filesystem is mounted read-only.
This function should implement the BOOKMARKFS_IOC_PERMD I/O control.
See Permute Directory Entries.
Type of the bookmark_permute function is defined as:
typedef int (bookmarkfs_bookmark_permute_func) ( void *backend_ctx, uint64_t parent_id, enum bookmarkfs_permd_op op, char const *name1, char const *name2, uint32_t flags );
Function arguments:
backend_ctxThe pointer referring to the backend context.
parent_idID of the parent directory containing the objects to be rearranged.
It could be a bookmark ID or tag ID, depending on the value of flags.
opOperation to perform on objects represented by name1 and name2.
See Rearrange Operations for the meaning of each value.
name1name2Names of the objects to be rearranged.
They could be bookmark names, tag names or keyword names,
depending on the value of flags.
flagsA bit array of the following flags:
BOOKMARKFS_BOOKMARK_TYPE_MASKThe subsystem to operate on.
Equals to one of the following values (after shifting):
On success, the function should return 0.
Otherwise, it should return a negated errno indicating the error
encountered.
The bookmark_check function is called when a “filesystem check”
operation is performed on a BookmarkFS directory.
See Filesystem Check.
Type of the bookmark_check function is defined as:
typedef int (bookmarkfs_bookmark_check_func) ( void *backend_ctx, uint64_t parent_id, struct bookmarkfs_fsck_data const *fsck_data, uint32_t flags, bookmarkfs_bookmark_check_cb *callback, void *user_data, void **cookie_ptr );
Function arguments:
backend_ctxThe pointer referring to the backend context.
parent_idID of the parent directory containing the objects to be checked.
It could be a bookmark ID or tag ID, depending on the value of flags.
fsck_dataAlways NULL if the filesystem is mounted read-only.
Otherwise, a non-NULL value indicates BOOKMARKFS_IOC_FSCK_APPLY.
See Repair Bookmark.
See Filesystem-Check Data for the definition of
struct bookmarkfs_fsck_data.
Value of each field:
idID of the object to rename.
The function should check whether the object is under the directory
referred to by parent_id.
If not, it should fail with ENOENT.
If the object ID was not previously passed to the callback function
during a bookmark_check call with the same cookie, the function may:
nameNew name for the object. The string may not be NUL-terminated.
extraUnspecified value.
If fsck_data is not NULL, the function should only check whether
the new name is valid, instead of going through the rest of the directory.
flagsA bit array of the following flags:
BOOKMARKFS_BOOKMARK_TYPE_MASKThe subsystem to operate on.
Equals to one of the following values (after shifting):
BOOKMARKFS_BOOKMARK_TYPE_BOOKMARKCheck bookmark and bookmark folder names. See Bookmarks.
BOOKMARKFS_BOOKMARK_TYPE_TAGCheck tag names. See Tags.
The function should fail with EPERM if parent_id does not
refer to the tags root directory.
BOOKMARKFS_BOOKMARK_TYPE_KEYWORDCheck keyword names. See Keywords.
The value of parent_id is unspecified.
callbackFunction to be called for each object with invalid name.
A NULL value indicates BOOKMARKFS_IOC_FSCK_REWIND,
in which case the function should reset the position of the current
bookmark_check operation.
Type of the callback function is defined as:
typedef int (bookmarkfs_bookmark_check_cb) ( void *user_data, int result, uint64_t id, uint64_t extra, char const *name );
Function arguments:
user_dataMust be equal to the user_data argument for the current
bookmark_check call.
resultShould be one of the values defined in enum bookmarkfs_fsck_result
indicating why this name is invalid.
See Filesystem-Check Result Code.
idextranameEquivalent to the corresponding fields in struct bookmarkfs_fsck_data.
See Filesystem-Check Data.
Return value:
0Continue to the next entry, if one exists.
Stop listing entries, and use this value as the return value for the current
bookmark_check call.
user_dataAn opaque pointer which should be passed as-is to the callback function.
cookie_ptrPointer to the “cookie” for the current bookmark_check operation.
It is guaranteed not to be NULL.
Except for the position of operation, this cookie shares the same semantics
as the one for bookmark_list.
See Bookmark-List Cookie.
Return value:
0The operation completes successfully.
errnoAn error occurred.
The function is terminated by a call to callback that returns a
non-zero value.
If returning a negative value, the position of the current
bookmark_check operation is unspecified.
The bookmark_sync function is called to persist changes to the
bookmark storage.
It is never called when the filesystem is mounted read-only.
If the bookmark storage is also changed from another process, function behavior is undefined. However, the backend should try not to corrupt the bookmark storage, and prefer changes from the caller, if possible.
Type of the bookmark_sync function is defined as:
typedef int (bookmarkfs_bookmark_sync_func) ( void *backend_ctx );
Function arguments:
backend_ctxThe pointer referring to the backend context.
On success, the function should return 0.
Otherwise, it should return a negated errno indicating the error
encountered.
The backend_mkfs function is called by the mkfs.bookmarkfs
program to create a new bookmark storage.
It can be NULL.
The new bookmark storage should be able to be opened directly, by both
backend_create and the application that owns the bookmark storage
(typically a web browser).
Type of the backend_mkfs function is defined as:
typedef int (bookmarkfs_backend_mkfs_func) ( struct bookmarkfs_backend_conf const *conf );
Function arguments:
confSee Backend Configuration for the definition of
struct bookmarkfs_backend_conf.
Some fields should be handled differently from backend_create:
flagsA bit array of the following flags:
BOOKMARKFS_BACKEND_MKFS_FORCEIndicates that the -o force option is given to
mkfs.bookmarkfs.
store_pathPath to the bookmark storage to be created, equivalent to the
store_path passed to backend_create.
The function should not overwrite existing bookmark storage, unless
the BOOKMARKFS_BACKEND_MKFS_FORCE flag is given.
The function should return 0 on success, and -1 on error.
The filesystem-check handler instructs the fsck.bookmarkfs program
on what to do with invalid bookmark names.
Like backends, filesystem-check handlers are typically built into shared libraries, and are installed as:
${pkglibdir}/fsck_handler_${name}${shlib_suffix}
Presumably ${prefix}/lib/bookmarkfs. See The Uniform Naming Scheme in GNU Automake.
The handler name, equivalent to the value given to the
-o handler=name option of fsck.bookmarkfs.
The common filename extension for shared library files on the current platform (e.g., .so on GNU/Linux and FreeBSD).
The built-in filesystem-check handler is linked into the
fsck.bookmarkfs program.
It has minimal functionalities, but is capable enough to handle most
common fsck scenarios.
Handler-specific options:
Readline prompt string. Defaults to ‘% ’.
This option is ignored in non-interactive mode.
Transliterate bad (‘/’) characters into char (must be a single ASCII character). Defaults to ‘_’.
For each bookmark entry, the built-in handler prints a line to standard output explaining why the bookmark name is invalid.
Output format (with an ASCII HT character separating each item):
id why extra name
Name of the result code, without the ‘BOOKMARKFS_FSCK_RESULT_’ prefix.
Information of this entry. See Filesystem-Check Data.
Integers are printed in decimal format. ASCII control characters in name are replaced with ‘?’.
When the -o repair option is given, the handler renames the bookmark according to the following rules:
BOOKMARKFS_FSCK_RESULT_NAME_DUPLICATEAppend a ‘_${counter}’ suffix to the name, where ${counter} is a self-incrementing 32-bit integer in decimal format.
If appending the suffix would exceed max name length, truncate the name first.
BOOKMARKFS_FSCK_RESULT_NAME_BADCHARTransliterate the bad character into another character.
BOOKMARKFS_FSCK_RESULT_NAME_BADLENIf the name is too long, truncate it to NAME_MAX bytes.
If the name is empty, see below:
BOOKMARKFS_FSCK_RESULT_NAME_DOTDOTBOOKMARKFS_FSCK_RESULT_NAME_INVALIDRename to ‘fsck-${id}’, where ${id} is the bookmark ID in decimal format.
In interactive mode, the handler prompts the user before applying the rename. The user may issue a command to indicate what to do with each entry:
pPrint the ID and new name of current entry.
a[-]Apply the proposed new name for the current entry.
e[-] new_nameChange the proposed new name to new_name and then apply.
cContinue to the next entry.
s[-]Skip current directory.
S[-]Skip current directory and all subdirectories.
r[-]Rewind current directory.
R[-]Rewind all.
w[-]Save applied changes.
qSave applied changes and quit.
The optional ‘-’ suffix inhibits the default behavior of continuing to the next entry, after the command completes successfully.
The Tcl-based filesystem-check handler allows fsck entries to be handled via Tcl scripting.
Handler name (for the -o handler option): ‘tcl’.
Handler-specific options:
Path to the Tcl script file. This option is mandatory.
The script is evaluated after interpreter initialization. Later executions use the evaluation result as command name.
The following variables are set before script evaluation:
$::bookmarkfs::fsck::isInteractiveEquals to 1 if the -i option is given to fsck.bookmarkfs,
0 otherwise.
$::bookmarkfs::fsck::isReadonlyEquals to 0 if the -o repair option is given to
fsck.bookmarkfs, 1 otherwise.
Enable unsafe Tcl interpreter features.
Should be used in combination with the -o no_sandbox option if you wish to access extra system resources (e.g., open local files).
Without this option, the Tcl interpreter has limited functionalities
as if created with interp create -safe.
See Safe Interpreters.
Each time fsck.bookmarkfs finds an entry,
or completes a handler-initiated operation,
the command returned from the script is executed with a single list argument.
The first element of the list is an integer indicating the reason for
this handler call:
$::bookmarkfs::fsck::result::nameDuplicate$::bookmarkfs::fsck::result::nameBadChar$::bookmarkfs::fsck::result::nameBadLen$::bookmarkfs::fsck::result::nameDotDot$::bookmarkfs::fsck::result::nameInvalidSee Filesystem-Check Result Code for the meaning of each value.
The second element is a list of information about the current entry:
extra field in struct bookmarkfs_fsck_data.
-1If the command is being executed for the first time, or the previous execution
returns $::bookmarkfs::fsck::handler::next, this value never appears.
If the previous execution of the command returns
$::bookmarkfs::fsck::handler::userInput,
the second element of the list is a string of user input.
Otherwise, this value indicates that the previous operation is successfully performed on the entry.
The command should return a list indicating the operation to perform on the entry. First element of the list should be one of the following values:
$::bookmarkfs::fsck::handler::nextContinue to the next entry.
$::bookmarkfs::fsck::handler::applyApply change for the current entry. Not available in read-only mode.
Second element of the list should be a string for the new name of the bookmark.
$::bookmarkfs::fsck::handler::userInputRequest for user input. Only available in interactive mode.
Second element of the list should be a string for Readline prompt, equivalent to the prompt=str option of the built-in handler.
$::bookmarkfs::fsck::handler::saveSave applied changes.
$::bookmarkfs::fsck::handler::stopSave applied changes and quit.
Once this value is returned, the command will never be executed again.
$::bookmarkfs::fsck::handler::rewindRewind current directory.
$::bookmarkfs::fsck::handler::skipSkip current directory.
$::bookmarkfs::fsck::handler::skipChildrenSkip current directory and all subdirectories.
$::bookmarkfs::fsck::handler::resetRewind all.
Here is an example Tcl script that simply prints each fsck entry (requires the unsafe option):
chan configure stdout -encoding utf-8 coroutine whatever apply {{} { set args [yield [info coroutine]] while 1 { lassign $args why data if {$why > -1} { lassign $data id extra name parent puts "id: $id, extra: $extra, name: $name, parent: $parent" } set args [yield [list $::bookmarkfs::fsck::handler::next]] } }}
The Filesystem-Check Handler API specifies how a fsck handler communicates with
fsck.bookmarkfs.
Warning: Currently BookmarkFS is experimental. The Handler API may change drastically without prior notice.
To implement the Filesystem-Check Handler API, a fsck handler library should expose a symbol with the following name:
bookmarkfs_fsck_handler_${name}
Where ${name} is equivalent to the value given to the
-o handler=name option of fsck.bookmarkfs.
The symbol should name a data object identifier of the following type:
#include <bookmarkfs/fsck_handler.h> struct bookmarkfs_fsck_handler { bookmarkfs_fsck_handler_info_func *info; bookmarkfs_fsck_handler_create_func *create; bookmarkfs_fsck_handler_destroy_func *destroy; bookmarkfs_fsck_handler_run_func *run; };
Each field is a function pointer provided by the fsck handler.
Some can be optional and set to NULL, if the backend
does not support the corresponding features.
If not NULL, the info function is called when the user
instructs fsck.bookmarkfs to print information about the handler.
When this function is called, it should write a human-readable message of the corresponding information to standard output.
Type of the info function is defined as:
typedef void (bookmarkfs_fsck_handler_info_func) ( uint32_t flags );
Function arguments:
flagsA bit array of the following flags:
BOOKMARKFS_FSCK_HANDLER_INFO_HELPBOOKMARKFS_FSCK_HANDLER_INFO_VERSIONIndicates that the function should print a help/version message.
These flags are analogous to the corresponding flags in the
backend_info function of the backend API.
See Get Backend Information.
A filesystem-check handler context maintains internal states for handling fsck entries.
To create a handler context, the create function is called.
It must not be NULL.
Type of the create function is defined as:
typedef int (bookmarkfs_fsck_handler_create_func) ( struct bookmarkfs_conf_opt const *opts, uint32_t flags, void **handler_ctx_ptr );
Function arguments:
optsLinked list of handler-specific options, NULL if there are none.
Handler-specific option should be processed in the same way as backend-specific options. See Backend-Specific Options.
flagsA bit array of the following flags:
BOOKMARKFS_FSCK_HANDLER_INTERACTIVEIndicates that the -i option is given to fsck.bookmarkfs.
BOOKMARKFS_FSCK_HANDLER_READONLYIndicates that the -o repair option is not given to
fsck.bookmarkfs.
handler_ctx_ptrPointer to an opaque pointer referring to the handler context.
The initial value of that pointer is unspecified. It should be set by the handler when the handler context is successfully created.
The function should return 0 on success, and -1 on error.
The destroy function is called to destroy a handler context.
It must not be NULL.
Upon destruction, The handler should release all system resources associated with this context.
Type of the destroy function is defined as:
typedef void (bookmarkfs_fsck_handler_destroy_func) ( void *handler_ctx );
Function arguments:
handler_ctxThe pointer referring to the handler context.
Each time fsck.bookmarkfs finds and entry, or completes a
handler-initiated operation, the run function is called.
It must not be NULL.
Type of the run function is defined as:
typedef int (bookmarkfs_fsck_handler_run_func) ( void *handler_ctx, int why, union bookmarkfs_fsck_handler_data *data );
Function arguments:
handler_ctxThe pointer referring to the handler context.
whyReason code for this handler call:
The fsck.bookmarkfs program has found an entry.
See Filesystem-Check Result Code for possible values.
However, BOOKMARKFS_FSCK_RESULT_END is handled by
fsck.bookmarkfs and never appears.
-1Indicates that an operation instructed by the previous return value of this function is successfully performed.
If run is being called for the first time, or the previous invocation
returns BOOKMARKFS_FSCK_NEXT, this value never appears.
dataInformation for this handler call.
The bookmarkfs_fsck_handler_data union is defined as:
union bookmarkfs_fsck_handler_data { struct bookmarkfs_fsck_handler_entry entry; char *str; };
entryInformation for the bookmark entry.
This field is set when why is non-negative.
The bookmarkfs_fsck_handler_entry structure is defined as:
struct bookmarkfs_fsck_handler_entry { uint64_t parent_id; struct bookmarkfs_fsck_data data; };
parent_idID of the bookmark folder that contains this bookmark entry.
dataSee Online Filesystem Check for the definition of
struct bookmarkfs_fsck_data.
strA NUL-terminated string.
This field is set to the user input string when why is -1, and the
previous invocation of run returns BOOKMARKFS_FSCK_USER_INPUT.
The string is only guaranteed to be valid until the function returns.
On success, the function should return one of the following values, indicating the operation to perform:
BOOKMARKFS_FSCK_NEXTContinue to the next entry.
BOOKMARKFS_FSCK_APPLYApply change for the current entry. Not available in read-only mode.
The function should copy the new name for the bookmark to
data->entry.data.name.
BOOKMARKFS_FSCK_USER_INPUTRequest for user input. Only available in interactive mode.
The function should set data->str to a prompt string for Readline.
The string must be valid until the next function call on this handler context.
BOOKMARKFS_FSCK_SAVESave applied changes.
BOOKMARKFS_FSCK_STOPSave applied changes and quit.
The run function is guaranteed not to be called again for this context.
BOOKMARKFS_FSCK_REWINDRewind current directory.
BOOKMARKFS_FSCK_SKIPSkip current directory.
BOOKMARKFS_FSCK_SKIP_CHILDRENSkip current directory and all subdirectories.
BOOKMARKFS_FSCK_RESETRewind all.
On error, the function should return -1.
The BookmarkFS Utility Library implements various common utility functions.
It is used internally by most of BookmarkFS’s components, including
the backends (see Backends) and the mount.bookmarkfs program.
Warning: Currently BookmarkFS is experimental. Functions provided by the utility library may change drastically without prior notice.
Typically, the library is built into a shared object, and installed as:
${libdir}/bookmarkfs_util${shlib_suffix}
Presumably ${prefix}/lib. See The Uniform Naming Scheme in GNU Automake.
The common filename extension for shared library files on the current platform (e.g., .so on GNU/Linux and FreeBSD).
Non-cryptographic hash function with 64-bit seed and digest, suitable for hash tables.
Currently, the xxHash (XXH3) algorithm is used.
Functions:
hash_seedUpdates the seed used by the hash function.
#include <bookmarkfs/hash.h> void hash_seed ( uint64_t seed );
With the same seed, the hash function always produces the same digest
for the same input.
If this function is never called, the hash function bahaves as if it is seeded with all bits zero.
hash_initCreates a new hash context.
struct hash_ctx * hash_init (void);
hash_updateAppends more data to the the given hash context.
void hash_update ( struct hash_ctx *ctx, void const *src, size_t src_len );
The src_len argument is the number of bytes to read from src.
hash_digestCalculates the digest of the given hash context.
uint64_t hash_digest ( struct hash_ctx *ctx );
Upon return, the hash context referred to by ctx is destroyed.
hash_digest_oneCalculates the digest of the data referred to by src and src_len.
uint64_t hash_digest_one ( void const *src, size_t src_len );
Equivalent to calling hash_update() only once on a hash context,
and then call hash_digest().
A simple hash table implementation, based on a variant of Hopscotch Hashing.
Time complexity:
| Operation | Average | Worst case |
|---|---|---|
| Insert | Θ(1) | O(n) |
| Search | Θ(1) | O(log n) |
| Delete | Θ(1) | O(log n) |
Functions:
hashmap_createCreates a new hash table.
#include <bookmarkfs/hashmap.h> struct hashmap * hashmap_create ( hashmap_comp_func *entry_comp, hashmap_hash_func *entry_hash );
Function arguments:
entry_compThe callback function for checking whether a key matches an entry.
Type of entry_comp is defined as:
typedef int (hashmap_comp_func) ( union hashmap_key key, void const *entry );
The function should return 0 if the objects match, non-zero if not.
entry_hashThe callback function for obtaining the hashcode for an entry.
Type of entry_hash is defined as:
typedef unsigned long (hashmap_hash_func) ( void const *entry );
This function is only called during rehashing,
and during hashmap_delete with a negative entry_id.
Returns an opaque pointer referring to the new hash table.
hashmap_insertInserts a new entry into a hash table.
void hashmap_insert ( struct hashmap *map, unsigned long hashcode, void *entry );
Function arguments:
mapThe hash table to insert entry into.
hashcodeThe hash code for the new entry.
entryAn arbitrary pointer to be associated with the new entry.
It must not be NULL.
hashmap_searchSearches for an entry in a hash table.
void * hashmap_search ( struct hashmap const *map, union hashmap_key key, unsigned long hashcode, unsigned long *entry_id_ptr );
Function arguments:
mapThe hash table to search from.
keyAn object to identify the entry being searched.
Type of the hashmap_key union is defined as:
union hashmap_key { void const *ptr; uint64_t u64; };
For each entry in the hash table with the given hashcode,
the entry_comp callback function is called with key
as the first argument, until a matching entry is found.
hashcodeThe hash code for the entry to search.
entry_id_ptrIf not NULL, and a matching entry is found,
the function sets *entry_id_ptr to an opaque integer value,
which can be used to identify the entry when calling hashmap_delete().
A subsequent call to hashmap_insert() and hashmap_delete()
on this hash table invalidates that value.
Returns the pointer associated with the entry,
or NULL if no matching entry is found.
hashmap_deleteRemoves an entry from a hash table.
void hashmap_delete ( struct hashmap *map, void const *entry, long entry_id );
Function arguments:
mapThe hash table to delete entry from.
entryThe entry to be deleted from the hash table.
If the hash table does not contain this entry, function behavior is undefined.
entry_idAn opaque integer obtained from hashmap_search() which identifies
the entry to be deleted.
If not readily available, -1 should be used.
If provided, the delete operation is always of O(1) time complexity.
hashmap_foreachIterates through all entries of a hash table.
void hashmap_foreach ( struct hashmap const *map, hashmap_walk_func *walk_func, void *user_data );
Function arguments:
mapThe hash table to traverse.
walk_funcThe callback function to be called for each entry.
Type of walk_func is defined as:
typedef void (hashmap_walk_func) ( void *entry, void *user_data );
The callback function must not insert to or delete from the current hash table.
user_dataAn opaque pointer to be passed to walk_func.
hashmap_destroyDestroys a hash table.
void hashmap_destroy ( struct hashmap *map );
Function arguments:
mapThe hash table to destroy.
If NULL, this function has no effect.
Limitations:
With a good-quality hash function, the average load factor of a hash table should be around 70%~75% before it must rehash.
Non-cryptographic pseudo-random number generator with 64-bit output and 256-bit state.
Currently, the xoshiro256++ algorithm is used.
Functions:
prng_seedUpdates the seed used by the PRNG.
#include <bookmarkfs/prng.h> int prng_seed ( uint64_t const seed[4] );
Function arguments:
sThe new seed (i.e., the internal state) for the PRNG.
Note: It is recommended to seed the PRNG with values that “appear to be random”.
A seed with all bits zero (equivalent to never calling
prng_seed()) results inprng_rand()producing a bad-quality number sequence.
If NULL, the seed will be obtained using getrandom(2).
The function returns 0 on success, and -1 on error.
If seed is not NULL, the function never fails.
prng_randReturns the next value in the pseudo-random number sequence.
uint64_t prng_rand (void);
With the same seed, the prng_rand() function always produces the same
number sequence.
Note: This function is MT-Unsafe.
prng_stateRetrieves the current state of the PRNG.
void prng_state ( uint64_t dst[4] );
The function stores the current state of the PRNG to dst,
which could later be used as the argument for prng_seed()
to set the PRNG to a previous state.
While entering sandbox, the calling process/thread irrevocably relinquishes most access to the system resources that it’s not supposed to touch. For example:
This mechanism reduces the attack surface for exploit, if a vulnerability is discovered in BookmarkFS and/or its dependencies. However, it only deals with untrusted input, and cannot help if the operating system has already been compromised.
“Untrusted input” includes but not limited to:
The utility library provides a helper function for sandboxing:
#include <bookmarkfs/sandbox.h> int sandbox_enter ( int dirfd, uint32_t flags );
Function arguments:
dirfdFile descriptor of a directory to grant access.
-1 if not needed.
The process may access, modify and create filesystem objects under the
directory using the *at() family of system calls.
For other directory file descriptors, it is unspecified whether they can be used in any way. A security-aware program should close such file descriptors before entering sandbox.
flagsA bit array of the following flags:
SANDBOX_READONLYGrants read-only access to the directory referred to by dirfd,
instead of read/write access.
This option is ignored when dirfd is -1.
SANDBOX_NO_LANDLOCKDo not use Landlock for sandboxing.
This option is ignored on non-Linux platforms.
SANDBOX_NOOPThe sandbox does nothing, and always returns successfully.
The function should return 0 on success, and -1 on error.
Despite the return value, the function should not be called again for the calling process/thread. Upon failure, the sandboxing state of the calling process/thread is unspecified.
Note: The
sandbox_enter()function is designed to work with BookmarkFS components, and may require some tweaking to be used for other programs.
Sandboxing is implemented using platform-specific features, and may behave differently across platforms:
Implemented using seccomp(2) and landlock(7).
Sandbox applies to the calling thread.
Implemented using capsicum(4).
Sandbox applies to the calling process.
Refer to the source code in src/sandbox.c for implementation details.
Each file watcher watches for changes of a single file on the filesystem.
Functions:
watcher_createCreates a new watcher.
#include <bookmarkfs/watcher.h> struct watcher * watcher_create ( int dirfd, char const *name, uint32_t flags );
Function arguments:
dirfdFile descriptor of the directory holding the file to be watched.
nameName of the file to be watched.
flagsA bit array of the following flags:
WATCHER_FALLBACKBy default, the file watcher uses platform-specific API to detect filesystem changes:
Implemented with fanotify(7).
Requires kernel version 5.13 or later for unprivileged users.
inotify(7) does not have this limitation, however,
it is incompatible with our sandboxing design.
Implemented with the EVFILT_VNODE filter of kevent(2).
With this flag, the watcher instead periodically checks the st_ino and
st_mtim attributes of the watched file with fstatat(3p).
The fallback implementation is less efficient than “native” ones, but should work on any POSIX-compatible system.
WATCHER_NOOPThe watcher does nothing, and watcher_poll() always return
-EAGAIN.
Values of dirfd, name and other flags are ignored.
Flags for sandbox_enter(), shifted
WATCHER_SANDBOX_FLAGS_OFFSET bits.
The sandbox flags apply to the worker thread used internally by the watcher.
SANDBOX_READONLY is always applied.
See Sandboxing.
On success, the function returns a pointer referring to the watcher.
On error, it returns NULL.
watcher_destroyStop watching, and release all system resources associated with the watcher.
void watcher_destroy ( struct watcher *w );
watcher_pollChecks whether the file being watched has changed. This function never blocks.
int watcher_poll ( struct watcher *w );
Return value:
0The file has changed since the last call to watcher_poll();
if it hasn’t been called, since watcher initialization.
-EAGAINThe file hasn’t changed since the last call to watcher_poll() that
returns 0.
If no previous watcher_poll() calls return 0, it indicates that
the watcher is being initialized.
-ENOENTThe file being watched does not exist.
-EIOAn internal error has occurred.
Further calls to watcher_poll() on this watcher will always fail.
| Jump to: | B D E F L |
|---|
| Jump to: | B D E F L |
|---|
Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. https://fsf.org/ Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
The purpose of this License is to make a manual, textbook, or other functional and useful document free in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.
This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.
We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.
This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.
A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.
A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.
The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.
The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.
A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”.
Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.
The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work’s title, preceding the beginning of the body of the text.
The “publisher” means any person or entity that distributes copies of the Document to the public.
A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition.
The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.
You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and you may publicly display copies.
If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.
If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.
It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.
You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:
If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles.
You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties—for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.
You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.
You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements.”
You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.
A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation’s users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.
Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.
If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.
You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License.
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it.
The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See https://www.gnu.org/licenses/.
Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Document.
“Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A “Massive Multiauthor Collaboration” (or “MMC”) contained in the site means any set of copyrightable works thus published on the MMC site.
“CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization.
“Incorporate” means to publish or republish a Document, in whole or in part, as part of another Document.
An MMC is “eligible for relicensing” if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008.
The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing.
To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:
Copyright (C) year your name. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''.
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the “with…Texts.” line with this:
with the Invariant Sections being list their titles, with
the Front-Cover Texts being list, and with the Back-Cover Texts
being list.
If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.
If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.