mirror of
https://git.sr.ht/~cismonx/bookmarkfs
synced 2025-06-07 11:48:51 +00:00
4443 lines
119 KiB
Text
4443 lines
119 KiB
Text
\input texinfo @c -*-texinfo-*-
|
|
|
|
@setfilename bookmarkfs.info
|
|
@include version.texi
|
|
@settitle BookmarkFS User Manual
|
|
@documentlanguage en_US
|
|
@paragraphindent 0
|
|
|
|
@macro manpage {name, section, url}
|
|
@uref{\url\,, @code{\name\(\section\)}}
|
|
@end macro
|
|
|
|
@macro linuxmanpage {name, section}
|
|
@manpage{\name\, \section\,
|
|
https://man7.org/linux/man-pages/man\section\/\name\.\section\.html}
|
|
@end macro
|
|
|
|
@macro freebsdmanpage {name, section}
|
|
@manpage{\name\, \section\,
|
|
https://man.freebsd.org/cgi/man.cgi?\name\(\section\)}
|
|
@end macro
|
|
|
|
@macro posixfuncmanpage {name}
|
|
@manpage{\name\, 3p,
|
|
https://pubs.opengroup.org/onlinepubs/9799919799/functions/\name\.html}
|
|
@end macro
|
|
|
|
@macro linuxdoc {name, path}
|
|
@uref{https://docs.kernel.org/\path\, \name\}
|
|
@end macro
|
|
|
|
@macro rfcdoc {name, path}
|
|
@uref{https://datatracker.ietf.org/doc/html/\path\, \name\}
|
|
@end macro
|
|
|
|
@macro sqlitedoc {name, path}
|
|
@uref{https://www.sqlite.org/\path\, \name\}
|
|
@end macro
|
|
|
|
@macro tcldoc {name, path}
|
|
@uref{https://www.tcl.tk/man/tcl8.6.13/\path\, \name\}
|
|
@end macro
|
|
|
|
@copying
|
|
This manual is for BookmarkFS, version @value{VERSION}.
|
|
|
|
@quotation
|
|
Copyright @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''.
|
|
@end quotation
|
|
@end copying
|
|
|
|
@titlepage
|
|
@title BookmarkFS
|
|
@subtitle version @value{VERSION}
|
|
@author CismonX
|
|
|
|
@page
|
|
@vskip 0pt plus 1filll
|
|
@insertcopying
|
|
@end titlepage
|
|
|
|
|
|
@summarycontents
|
|
@contents
|
|
|
|
@node Top
|
|
@top BookmarkFS User Manual
|
|
|
|
@insertcopying
|
|
|
|
|
|
@node Overview
|
|
@chapter Overview
|
|
|
|
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:
|
|
|
|
@itemize @bullet{}
|
|
@item Firefox
|
|
@item Chromium
|
|
@end itemize
|
|
|
|
BookmarkFS is free software, distributed under the terms of the
|
|
@uref{https://www.gnu.org/licenses/#GPL, GNU General Public License},
|
|
either version 3, or any later version of the license.
|
|
|
|
To install BookmarkFS, refer to the @file{INSTALL.md} file under the
|
|
root directory of the project codebase.
|
|
|
|
BookmarkFS is
|
|
@uref{https://savannah.nongnu.org/projects/bookmarkfs, hosted on Savannah},
|
|
where latest releases, development sources and other information are available.
|
|
Also see @uref{https://builds.sr.ht/~cismonx/bookmarkfs, builds.sr.ht}
|
|
for CI build logs.
|
|
|
|
@node Porting BookmarkFS
|
|
@section Porting BookmarkFS
|
|
|
|
Currently, BookmarkFS only runs on GNU/Linux and FreeBSD.
|
|
|
|
Although BookmarkFS sticks hard to POSIX and avoids using platform-specific
|
|
features, porting it to other operating systems is not trivial.
|
|
|
|
The major pitfall is the @linuxdoc{FUSE, filesystems/fuse.html} dependency.
|
|
Generally speaking, FUSE is Linux-only.
|
|
FreeBSD partially implements the FUSE protocol in its kernel,
|
|
to the extent that BookmarkFS is mostly usable.
|
|
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
|
|
@uref{https://libfuse.github.io/doxygen/fuse__lowlevel_8h.html, low-level API}.
|
|
For a similar reason, @uref{https://github.com/winfsp/winfsp, WinFsp}
|
|
won't work if you're trying to port BookmarkFS to Microsoft Windows.
|
|
|
|
Other notable portability issues:
|
|
|
|
@table @asis
|
|
@item Sandboxing
|
|
Not all operating system kernels provide sandboxing mechanisms similar to
|
|
Linux and FreeBSD.
|
|
|
|
If not supported, operations that require sandboxing should fail.
|
|
Users should not be provided with a false sense of security.
|
|
If they wish, they could pass a @option{-o no_sandbox} option to
|
|
explicitly disable sandboxing.
|
|
|
|
Also @pxref{Sandboxing}.
|
|
@end table
|
|
|
|
|
|
@node Limitations on FreeBSD
|
|
@section Limitations on FreeBSD
|
|
|
|
Currently, the FreeBSD @freebsdmanpage{fusefs, 5} implementation does not
|
|
support @code{FUSE_IOCTL}.
|
|
All custom @freebsdmanpage{ioctl, 2} calls on a FUSE filesystem fail
|
|
with @code{ENOTTY} without the requests being sent to the FUSE server.
|
|
|
|
Thus, BookmarkFS features that depend on @code{ioctl()} do not work
|
|
on FreeBSD, which includes:
|
|
|
|
@itemize @bullet{}
|
|
@item @ref{Permute Directory Entries}
|
|
@item @ref{Online Filesystem Check}
|
|
@end itemize
|
|
|
|
Meanwhile, FreeBSD does not support @code{FUSE_READDIRPLUS} and directory
|
|
entry caching, which makes listing directory entries less efficient.
|
|
|
|
|
|
@node Mailing Lists
|
|
@section Mailing Lists
|
|
|
|
Write to the
|
|
@uref{https://savannah.nongnu.org/mail/?group=bookmarkfs, mailing lists}
|
|
for bug reports, feature requests, and other discussions.
|
|
|
|
Please do @emph{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.
|
|
|
|
|
|
@node Programs
|
|
@chapter Programs
|
|
|
|
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.
|
|
@xref{Backends}.
|
|
|
|
|
|
@node mount.bookmarkfs
|
|
@section @command{mount.bookmarkfs}
|
|
|
|
The @command{mount.bookmarkfs} program mounts a BookmarkFS filesystem.
|
|
|
|
@example
|
|
mount.bookmarkfs [@var{options}] @var{src} @var{target}
|
|
@end example
|
|
|
|
@table @var
|
|
@item src
|
|
The bookmark storage, presumably the pathname of a regular file
|
|
that contains bookmark data.
|
|
|
|
The exact interpretation of this argument is backend-defined.
|
|
|
|
@item target
|
|
Pathname of the directory to mount the filesystem.
|
|
@end table
|
|
|
|
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 @samp{vfs.usermount}
|
|
@freebsdmanpage{sysctl, 8} to @t{1} for unprivileged mounts.
|
|
|
|
To unmount a BookmarkFS filesystem, run @linuxmanpage{fusermount3, 1} or
|
|
@linuxmanpage{umount, 8} on @var{target}.
|
|
The daemon process will automatically dismount the filesystem upon
|
|
@code{SIGINT} or @code{SIGTERM} receipt, however, it only works in
|
|
non-sandbox mode.
|
|
|
|
Options:
|
|
|
|
@table @option
|
|
@item -o backend=@var{name}
|
|
The backend used by the filesystem (@pxref{Backends}).
|
|
This option is mandatory.
|
|
|
|
@anchor{Alternative Backend Name}
|
|
Alternatively, @var{name} could be specified in
|
|
@samp{@var{lib_path}:@var{sym_name}} format, where:
|
|
|
|
@table @var
|
|
@item lib_path
|
|
Presumably the pathname to the backend library.
|
|
Its exact interpretation is equivalent to the first argument for
|
|
@posixfuncmanpage{dlopen}.
|
|
|
|
@item sym_name
|
|
@xref{Backend Symbol Name Format}.
|
|
@end table
|
|
|
|
@item -o @@@var{key}[=@var{value}]
|
|
A backend-specific option.
|
|
This option can be provided multiple times.
|
|
|
|
@item -o accmode=@var{mode}
|
|
File access mode.
|
|
Defaults to @samp{0700}.
|
|
|
|
This option applies to both directories and regular files.
|
|
Execution bits on regular files are masked off.
|
|
|
|
Should be used in combination with @option{-o allow_other} for other users to
|
|
access the files.
|
|
|
|
@anchor{Last Modification/Change Time}
|
|
@cindex Last Modification/Change Time
|
|
@item -o ctime
|
|
Maintain last status change time instead of last modification time.
|
|
|
|
Usually, a bookmark's ``modification time'' attribute 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.
|
|
|
|
BookmarkFS do not follow browser behavior here, and instead try to stay
|
|
compatible with POSIX.
|
|
Since a bookmark has only one ``modification time'' attribute instead of two,
|
|
the user has to choose which one to maintain:
|
|
|
|
@table @asis
|
|
@item Last modification time
|
|
ctime only updates when mtime does.
|
|
|
|
@item Last status change time
|
|
ctime updates normally; mtime always updates when ctime does,
|
|
even if the file content is not modified.
|
|
|
|
This behavior may be inefficient, but makes applications that depend on ctime
|
|
less fragile.
|
|
@end table
|
|
|
|
The kernel may automatically update and cache ctime,
|
|
making it more ``correct'' than what we expect.
|
|
However, this behavior should not be relied upon.
|
|
|
|
@item -o eol
|
|
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).
|
|
|
|
@item -o file_max=@var{bytes}
|
|
Max file size limit.
|
|
Defaults to @samp{32768}.
|
|
|
|
This limit also applies to extended attribute values.
|
|
|
|
@item -o no_sandbox
|
|
Do not enable sandboxing features (@pxref{Sandboxing}).
|
|
|
|
@anchor{Disabling Landlock}
|
|
@item -o no_landlock
|
|
Do not use Landlock for sandboxing.
|
|
This option is ignored on non-Linux platforms.
|
|
|
|
Without Landlock, sandboxing offers less security.
|
|
However, Landlock is a rather new feature (requires kernel version 5.13
|
|
or later), thus we provide an option to disable it separately.
|
|
|
|
@item -F
|
|
Stay in the foreground, do not daemonize.
|
|
|
|
@item -h
|
|
Print help text, and then exit.
|
|
|
|
@item -V
|
|
Print version and feature information, and then exit.
|
|
@end table
|
|
|
|
Unrecognized options specified with @option{-o} are passed to libfuse
|
|
(and subsequently to the kernel, if applicable) as-is.
|
|
Notable options:
|
|
|
|
@table @option
|
|
@item -o rw
|
|
Mount the filesystem read/write.
|
|
|
|
@quotation Warning
|
|
Always backup the bookmark storage before mounting it read/write,
|
|
or risk losing your data!
|
|
@end quotation
|
|
|
|
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.
|
|
|
|
@item -o debug
|
|
Set libfuse log level to @code{FUSE_LOG_DEBUG}.
|
|
Log messages related to each FUSE request will be printed to standard error.
|
|
|
|
@item -o fsname=@var{name}
|
|
Name for the filesystem.
|
|
Defaults to the backend name.
|
|
|
|
This name is equivalent to the @code{fs_spec} field in @linuxmanpage{fstab, 5},
|
|
and appears as the @samp{SOURCE} column in @linuxmanpage{findmnt, 8} output.
|
|
|
|
@item -o atime,diratime,relatime
|
|
These options (and other atime-related ones) are ignored.
|
|
|
|
BookmarkFS only supports @option{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 @posixfuncmanpage{futimens}).
|
|
|
|
@item -o auto_unmount
|
|
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 @linuxmanpage{mount.fuse3, 8} for details.
|
|
|
|
This option is helpful when sandboxing is enabled, especially when
|
|
the @option{-F} option is given, since a sandboxed process itself can neither
|
|
@linuxmanpage{umount, 2} nor fork-exec.
|
|
|
|
Currently, this option is not available on FreeBSD.
|
|
@end table
|
|
|
|
|
|
@node fsck.bookmarkfs
|
|
@section @command{fsck.bookmarkfs}
|
|
|
|
The @command{fsck.bookmarkfs} program checks and optionally repairs a
|
|
BookmarkFS filesystem.
|
|
|
|
@example
|
|
fsck.bookmarkfs [@var{options}] @var{pathname}
|
|
@end example
|
|
|
|
Filesystem check on BookmarkFS has a different purpose compared to
|
|
on-disk filesystems.
|
|
@xref{Filesystem Check}.
|
|
|
|
Depending on the options specified, filesystem check works either in
|
|
online or offline mode:
|
|
|
|
@table @asis
|
|
@item Online Mode
|
|
In online mode, fsck is performed on a mounted BookmarkFS filesystem
|
|
using @code{ioctl()}.
|
|
@xref{Online Filesystem Check}.
|
|
|
|
The @var{pathname} argument refers to the directory to operate on.
|
|
|
|
@item Offline Mode
|
|
In offline mode, fsck is performed directly on the bookmark storage via the
|
|
corresponding backend.
|
|
|
|
The @var{pathname} argument is the path to the bookmark storage, equivalent to
|
|
the @var{src} argument given to @command{mount.bookmarkfs}.
|
|
|
|
Alternatively, @var{pathname} could be specified in @samp{@var{src}:@var{dir}}
|
|
format, where @var{dir} refers to the directory to operate on,
|
|
relative to the root directory of the subsystem.
|
|
@end table
|
|
|
|
Options:
|
|
|
|
@table @option
|
|
@item -o backend=@var{name}
|
|
The backend used by the filesystem.
|
|
@xref{Backends}.
|
|
|
|
Value of @var{name} could be specified in an alternative format.
|
|
@xref{Alternative Backend Name}.
|
|
|
|
If this option is not provided, or @var{name} is empty, performs online fsck.
|
|
Otherwise perform offline fsck.
|
|
|
|
@item -o @@@var{key}[=@var{value}]
|
|
A backend-specific option.
|
|
This option can be provided multiple times.
|
|
|
|
@item -o handler=@var{name}
|
|
The handler for resolving errors found during fsck
|
|
(@pxref{Filesystem-Check Handlers}).
|
|
|
|
Alternatively, @var{name} could be specified in
|
|
@samp{@var{lib_path}:@var{sym_name}} format, where:
|
|
|
|
@table @var
|
|
@item lib_path
|
|
Presumably the pathname to the fsck handler library.
|
|
Its exact interpretation is equivalent to the first argument for
|
|
@posixfuncmanpage{dlopen}.
|
|
|
|
@item sym_name
|
|
@xref{Filesystem-Check Handler Symbol Name Format}.
|
|
@end table
|
|
|
|
If this option is not provided, or @var{name} is empty,
|
|
a built-in handler will be used.
|
|
@xref{Built-in Handler}.
|
|
|
|
@item -o %@var{key}[=@var{value}]
|
|
A handler-specific option.
|
|
This option can be provided multiple times.
|
|
|
|
@item -o repair
|
|
Attempt to repair errors found during fsck.
|
|
|
|
@quotation Warning
|
|
Always backup the bookmark storage before repairing, or risk losing your data!
|
|
@end quotation
|
|
|
|
@item -o rl_app=@var{name}
|
|
Readline application name in interactive mode.
|
|
Defaults to @samp{fsck.bookmarkfs}.
|
|
|
|
@xref{Conditional Init Constructs,,, readline, GNU Readline Library}.
|
|
|
|
@item -o type=bookmark|tag|keyword
|
|
Subsystem type (@pxref{Filesystem Hierarchy}).
|
|
Defaults to @samp{bookmark}.
|
|
|
|
This option is ignored when performing online fsck.
|
|
|
|
@item -i
|
|
Enable interactive mode.
|
|
|
|
@item -R
|
|
Perform fsck on subdirectories recursively.
|
|
|
|
This option is ignored when performing fsck on tags or keywords.
|
|
|
|
@item -o no_sandbox
|
|
Do not enable sandboxing features.
|
|
@xref{Sandboxing}.
|
|
|
|
@item -o no_landlock
|
|
Do not use Landlock for sandboxing.
|
|
This option is ignored on non-Linux platforms.
|
|
|
|
Also @pxref{Disabling Landlock}.
|
|
|
|
@item -h
|
|
Print help text, and then exit.
|
|
|
|
@item -V
|
|
Print version and feature information, and then exit.
|
|
@end table
|
|
|
|
|
|
@node mkfs.bookmarkfs
|
|
@section @command{mkfs.bookmarkfs}
|
|
|
|
The @command{mkfs.bookmarkfs} program creates a new BookmarkFS filesystem.
|
|
|
|
@example
|
|
mkfs.bookmarkfs [@var{options}] @var{pathname}
|
|
@end example
|
|
|
|
@table @var
|
|
@item pathname
|
|
The underlying bookmark storage for the new filesystem.
|
|
|
|
This option is equivalent to the @var{src} argument for
|
|
@command{mount.bookmarkfs}.
|
|
@end table
|
|
|
|
Options:
|
|
|
|
@table @option
|
|
@item -o backend=@var{name}
|
|
The backend used by the filesystem (@pxref{Backends}).
|
|
This option is mandatory.
|
|
|
|
Value of @var{name} could be specified in an alternative format.
|
|
@xref{Alternative Backend Name}.
|
|
|
|
@item -o @@@var{key}[=@var{value}]
|
|
A backend-specific option.
|
|
This option can be provided multiple times.
|
|
|
|
@item -o force
|
|
If the file referred to by @var{pathname} already exists, overwrite it.
|
|
|
|
@item -h
|
|
Print help text, and then exit.
|
|
|
|
@item -V
|
|
Print version and feature information, and then exit.
|
|
@end table
|
|
|
|
|
|
@node bookmarkctl
|
|
@section @command{bookmarkctl}
|
|
|
|
The @command{bookmarkctl} program is a command-line wrapper for various
|
|
operations on a BookmarkFS filesystem that cannot be done portably with
|
|
POSIX utilities alone, including I/O controls and managing extended attributes.
|
|
|
|
@example
|
|
bookmarkctl @var{subcmd} [@var{args}]
|
|
@end example
|
|
|
|
Sub-commands:
|
|
|
|
@table @command
|
|
@item permd
|
|
Rearranges the order of the directory entries to be returned from
|
|
future calls to @code{readdir()}.
|
|
@xref{Permute Directory Entries}.
|
|
|
|
@example
|
|
bookmarkctl permd [@var{options}] @var{name1} @var{name2} @var{pathname}
|
|
@end example
|
|
|
|
@table @var
|
|
@item name1
|
|
@itemx name2
|
|
Filename of entries under the directory.
|
|
|
|
@item pathname
|
|
Path to the parent directory.
|
|
@end table
|
|
|
|
Options:
|
|
|
|
@table @option
|
|
@item -s
|
|
Exchange the positions of the directory entries represented by @var{name1}
|
|
and @var{name2}.
|
|
|
|
@item -b
|
|
Move the directory entry represented by @var{name1} to the position just
|
|
@emph{before} the one represented by @var{name2}.
|
|
|
|
@item -a
|
|
Move the directory entry represented by @var{name1} to the position just
|
|
@emph{after} the one represented by @var{name2}.
|
|
@end table
|
|
|
|
The @option{-s}, @option{-b} and @option{-a} options are mutually exclusive.
|
|
If multiple options are provided, the last one takes effect.
|
|
|
|
@item fsck
|
|
Displays a list of filesystem errors found under the given directory.
|
|
@xref{Filesystem Check}.
|
|
|
|
Does not recurse into subdirectories.
|
|
|
|
@example
|
|
bookmarkctl fsck @var{pathname}
|
|
@end example
|
|
|
|
@table @var
|
|
@item pathname
|
|
Path to the directory to perform checks on.
|
|
@end table
|
|
|
|
The output shares the same format with the built-in fsck handler.
|
|
@xref{Filesystem-Check Output Format}.
|
|
|
|
For the full fsck functionalities, @pxref{fsck.bookmarkfs}.
|
|
|
|
@item xattr-list
|
|
Displays a list of extended attribute names.
|
|
@xref{Extended Attributes}.
|
|
|
|
@example
|
|
bookmarkctl xattr-list @var{pathname}
|
|
@end example
|
|
|
|
@table @var
|
|
@item pathname
|
|
Path to the file to obtain extended attribute names.
|
|
@end table
|
|
|
|
Only the names prefixed with @samp{user.bookmarkfs.} are listed,
|
|
with the prefix removed.
|
|
|
|
@item xattr-get
|
|
Displays extended attribute values.
|
|
@xref{Extended Attributes}.
|
|
|
|
@example
|
|
bookmarkctl xattr-get [@var{options}] @var{attrname} @var{pathname}...
|
|
bookmarkctl xattr-get [@var{options}] -a @var{attrname}... @var{pathname}
|
|
@end example
|
|
|
|
@table @var
|
|
@item attrname
|
|
Name of the extended attribute, without the @samp{user.bookmarkfs.} prefix.
|
|
|
|
@item pathname
|
|
Path to the file to obtain extended attribute values.
|
|
@end table
|
|
|
|
Options:
|
|
|
|
@table @option
|
|
@item -b
|
|
Treat the value as binary, and print it verbatim.
|
|
|
|
If this option is not provided, non-printable characters are replaced with
|
|
@samp{?}.
|
|
|
|
@item -a
|
|
Switch to multi-attrname mode, where multiple extended attribute names
|
|
can be specified instead of multiple files.
|
|
|
|
Also, the corresponding @var{attrname} is printed alongside with the value,
|
|
instead of @var{pathname}.
|
|
|
|
@item -q
|
|
Print values only, do not print names.
|
|
|
|
If provided twice, do not print the suffix character after each value.
|
|
|
|
@item -s @var{char}
|
|
The character separating each name and value.
|
|
Defaults to the ASCII HT character.
|
|
|
|
@item -n @var{char}
|
|
The character suffixing each value.
|
|
Defaults to the ASCII LF character.
|
|
@end table
|
|
|
|
For the @option{-s} and @option{-n} options,
|
|
if @var{char} contains multiple characters, the first one is used.
|
|
If empty, the ASCII NUL character is used.
|
|
|
|
@item xattr-set
|
|
Update the value of an extended attribute.
|
|
@xref{Extended Attributes}.
|
|
|
|
@example
|
|
bookmarkctl xattr-set [@var{options}] @var{attrname} @var{pathname}
|
|
@end example
|
|
|
|
@table @var
|
|
@item attrname
|
|
Name of the extended attribute to update,
|
|
without the @samp{user.bookmarkfs.} prefix.
|
|
|
|
@item pathname
|
|
Path to the file to update extended attribute value.
|
|
@end table
|
|
|
|
Options:
|
|
|
|
@table @option
|
|
@item -v @var{value}
|
|
New value for the extended attribute.
|
|
|
|
If this option is not provided, the new value is read from standard input.
|
|
@end table
|
|
|
|
@item help
|
|
Print help text, and then exit.
|
|
|
|
@example
|
|
bookmarkctl help
|
|
@end example
|
|
|
|
@item version
|
|
Print version information, and then exit.
|
|
|
|
@example
|
|
bookmarkctl version
|
|
@end example
|
|
@end table
|
|
|
|
|
|
@node Filesystem
|
|
@chapter The Filesystem
|
|
|
|
When a BookmarkFS filesystem is mounted using the @command{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, @pxref{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.
|
|
|
|
|
|
@node Filesystem Hierarchy
|
|
@section Filesystem Hierarchy
|
|
|
|
BookmarkFS has multiple subsystems.
|
|
Each one appears as a directory under the mountpoint:
|
|
|
|
@example
|
|
@var{$@{mountpoint@}}/bookmarks
|
|
@var{$@{mountpoint@}}/tags
|
|
@var{$@{mountpoint@}}/keywords
|
|
@end example
|
|
|
|
If the backend does not support a subsystem, the corresponding directory
|
|
does not exist.
|
|
|
|
Currently all subsystem definitions are hard-coded within the
|
|
@command{mount.bookmarkfs} program, and cannot be extended by the backend.
|
|
|
|
|
|
@node Bookmarks
|
|
@subsection Bookmarks
|
|
|
|
The ``bookmarks'' subsystem maintains the hierarchical structure, names, URLs
|
|
and other information of a bookmark storage.
|
|
|
|
@example
|
|
@var{$@{mountpoint@}}/bookmarks/@var{$@{bookmark_dir...@}}/@var{$@{bookmark@}}
|
|
@end example
|
|
|
|
Each bookmark folder name appears as the filename for directory
|
|
@var{$@{bookmark_dir@}}, and each @var{$@{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 @code{readdir()} calls.
|
|
To deal with such bookmarks, @pxref{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:
|
|
|
|
@table @code
|
|
@item st_ino
|
|
ID of the bookmark (stored as lower bits).
|
|
|
|
@item st_size
|
|
Length of the bookmark URL in bytes.
|
|
Always @t{0} for directories.
|
|
|
|
@item st_atim
|
|
Last access time of the bookmark.
|
|
|
|
@item st_mtim
|
|
Last modification time of the bookmark.
|
|
@xref{Last Modification/Change Time}.
|
|
@end table
|
|
|
|
Additional information of a bookmark or bookmark folder can be accessed via
|
|
the extended attributes of the corresponding file, for backends that
|
|
supports it.
|
|
@xref{Extended Attributes}.
|
|
|
|
|
|
@node Tags
|
|
@subsection Tags
|
|
|
|
The ``tags'' subsystem maintains a many-to-many mapping between bookmarks and
|
|
their alternative names.
|
|
|
|
@example
|
|
@var{$@{mountpoint@}}/tags/@var{$@{tag_dir@}}/@var{$@{bookmark@}}
|
|
@end example
|
|
|
|
Each tag name appears as the filename for directory @var{$@{tag_dir@}},
|
|
and @var{$@{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 @code{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 original bookmark file is renamed or deleted,
|
|
it may also 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 @posixfuncmanpage{link}:
|
|
|
|
@example c
|
|
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!
|
|
@end example
|
|
|
|
Make sure that the two files have identical names, otherwise @code{link()}
|
|
fails with @code{EPERM}.
|
|
|
|
|
|
@node Keywords
|
|
@subsection Keywords
|
|
|
|
The ``keywords'' subsystem maintains a one-to-one mapping between bookmarks
|
|
and their alternative names, independent from tag names.
|
|
|
|
@example
|
|
@var{$@{mountpoint@}}/keywords/@var{$@{keyword_name@}}
|
|
@end example
|
|
|
|
Each keyword name appears as the filename for regular file
|
|
@var{$@{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 @posixfuncmanpage{link}
|
|
like we do with tags.
|
|
If the original file is already associated with another keyword,
|
|
@code{link()} fails with @code{EEXIST}.
|
|
|
|
|
|
@node Error Codes
|
|
@section Error Codes
|
|
|
|
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:
|
|
|
|
@table @code
|
|
@item EPERM
|
|
Attempting to perform an unsupported operation.
|
|
For example:
|
|
|
|
@itemize @bullet{}
|
|
@item @code{chmod()}, @code{chown()}, and other operations that make no sense
|
|
for web browser bookmarks.
|
|
|
|
@item Moving a file across subsystems.
|
|
|
|
@item Creating a bookmark file with a name that is not valid UTF-8
|
|
(on Chromium backend).
|
|
@end itemize
|
|
|
|
@item EIO
|
|
An unexpected internal error occurred, likely due to a bug in BookmarkFS,
|
|
or a corruption in the bookmark storage.
|
|
|
|
When this error occurs, a log message describing the situation may be printed
|
|
to the standard error of the filesystem daemon.
|
|
Sometimes this error comes from the kernel-side FUSE implementation,
|
|
and there's no error message.
|
|
|
|
Once this error occurs, behavior of any further operations on the filesystem
|
|
is undefined.
|
|
|
|
@item ESTALE
|
|
The 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.
|
|
@xref{Exclusive Mode}.
|
|
@end table
|
|
|
|
Other BookmarkFS-specific errors may occur.
|
|
See the corresponding manual section for details.
|
|
|
|
|
|
@node Extended Attributes
|
|
@section Extended Attributes
|
|
|
|
BookmarkFS uses extended attributes to manage additional information associated
|
|
with a bookmark.
|
|
|
|
Extended attributes is a platform-specific feature.
|
|
On Linux, see @linuxmanpage{xattr, 7}.
|
|
On FreeBSD, see @freebsdmanpage{extattr, 2}.
|
|
|
|
All BookmarkFS extended attributes fall under the ``user'' namespace,
|
|
which means they have a @samp{user.} name prefix on Linux, and should be
|
|
accessed with @code{EXTATTR_NAMESPACE_USER} on FreeBSD.
|
|
All attribute names have a @samp{bookmarkfs.} prefix.
|
|
|
|
For example, to get the GUID of a bookmark file (Firefox backend):
|
|
|
|
@example c
|
|
// Linux
|
|
len = fgetxattr(fd, "user.bookmarkfs.guid", buf, sizeof(buf));
|
|
|
|
// FreeBSD
|
|
len = extattr_get_fd(fd, EXTATTR_NAMESPACE_USER, "bookmarkfs.guid",
|
|
buf, sizeof(buf));
|
|
@end example
|
|
|
|
BookmarkFS does not define any common attributes, neither can users create
|
|
arbitrary ones.
|
|
The backend context decides which attributes are available
|
|
(@pxref{Create Backend Context}),
|
|
and all bookmark files under it share the same set of attributes.
|
|
|
|
|
|
@node Directory Entries
|
|
@section Directory Entries
|
|
|
|
@table @asis
|
|
@item The @samp{.} and @samp{..} Entries
|
|
POSIX consider @samp{.} and @samp{..} 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 (@pxref{Filesystem Check}).
|
|
|
|
@anchor{Directory Entry Ordering}
|
|
@cindex Directory Entry Ordering
|
|
@item Directory Entry Ordering
|
|
POSIX does not specify the ordering of the directory entries retrieved from
|
|
the directory stream using @posixfuncmanpage{readdir}.
|
|
It only guarantees that if an entry is not added or removed from the directory
|
|
after the most recent call to @posixfuncmanpage{opendir} or
|
|
@posixfuncmanpage{rewinddir}, 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
|
|
@linuxdoc{htree, filesystems/ext4/dynamic.html#hash-tree-directories}
|
|
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, @pxref{Permute Directory Entries}.
|
|
@end table
|
|
|
|
|
|
@node Permute Directory Entries
|
|
@subsection Permute Directory Entries
|
|
|
|
BookmarkFS provides an I/O control for rearranging directory entries:
|
|
|
|
@example c
|
|
#include <bookmarkfs/ioctl.h>
|
|
|
|
int ioctl (int dirfd, BOOKMARKFS_IOC_PERMD,
|
|
struct bookmarkfs_permd_data const *argp);
|
|
@end example
|
|
|
|
The @code{bookmarkfs_permd_data} structure is defined as:
|
|
|
|
@example c
|
|
struct bookmarkfs_permd_data @{
|
|
enum bookmarkfs_permd_op op;
|
|
|
|
char name1[NAME_MAX + 1];
|
|
char name2[NAME_MAX + 1];
|
|
@};
|
|
@end example
|
|
|
|
@anchor{Rearrange Operations}
|
|
The @code{op} field denotes the operation to perform on the directory:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_PERMD_OP_SWAP
|
|
Exchange the positions of the directory entries represented by @code{name1}
|
|
and @code{name2}.
|
|
|
|
@item BOOKMARKFS_PERMD_OP_MOVE_BEFORE
|
|
Move the directory entry represented by @code{name1} to the position just
|
|
@emph{before} the one represented by @code{name2}.
|
|
|
|
@item BOOKMARKFS_PERMD_OP_MOVE_AFTER
|
|
Move the directory entry represented by @code{name1} to the position just
|
|
@emph{after} the one represented by @code{name2}.
|
|
@end table
|
|
|
|
On success, @code{ioctl()} returns @t{0}.
|
|
Otherwise, it returns @t{-1} and sets @code{errno}:
|
|
|
|
@table @code
|
|
@item EACCES
|
|
Write or search permission is denied for the directory.
|
|
|
|
@item EINVAL
|
|
@code{op} is not one of the values defined in @code{enum bookmarkfs_permd_op}.
|
|
|
|
@item EINVAL
|
|
@code{name1} or @code{name2} is not a valid filename
|
|
(e.g., empty string; contains @samp{/} character).
|
|
|
|
@item ENOENT
|
|
The directory does not contain entries named @code{name1} or @code{name2}.
|
|
|
|
@item ENOTTY
|
|
The kernel does not support @code{FUSE_IOCTL}.
|
|
@xref{Limitations on FreeBSD}.
|
|
|
|
@item EPERM
|
|
The backend does not support rearranging entries for this directory.
|
|
@end table
|
|
|
|
To ensure that the order change is visible to further @code{readdir()} calls,
|
|
@code{fsync()} or @code{close()} the directory.
|
|
|
|
|
|
@node Filesystem Check
|
|
@section Filesystem Check
|
|
|
|
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:
|
|
|
|
@itemize @bullet{}
|
|
@item must not contain @samp{/} characters
|
|
@item must not be empty or longer than @code{NAME_MAX}
|
|
@item must not duplicate with another file in the same directory
|
|
@item @samp{.} and @samp{..} must refer to the current and parent directory
|
|
@end itemize
|
|
|
|
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.
|
|
|
|
|
|
@node Online Filesystem Check
|
|
@subsection Online Filesystem Check
|
|
|
|
To perform filesystem check on a mounted BookmarkFS filesystem,
|
|
use the following I/O controls:
|
|
|
|
@example c
|
|
#include <bookmarkfs/ioctl.h>
|
|
|
|
int ioctl (int dirfd, BOOKMARKFS_IOC_FSCK_NEXT,
|
|
struct bookmarkfs_fsck_data *argp);
|
|
|
|
int ioctl (int dirfd, BOOKMARKFS_IOC_FSCK_APPLY,
|
|
struct bookmarkfs_fsck_data *argp);
|
|
|
|
int ioctl (int dirfd, BOOKMARKFS_IOC_FSCK_REWIND);
|
|
@end example
|
|
|
|
@anchor{Filesystem-Check Data}
|
|
The @code{bookmarkfs_fsck_data} structure is defined as:
|
|
|
|
@example c
|
|
struct bookmarkfs_fsck_data @{
|
|
uint64_t id;
|
|
uint64_t extra;
|
|
char name[NAME_MAX + 1];
|
|
@};
|
|
@end example
|
|
|
|
Filesystem-check commands:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_IOC_FSCK_NEXT
|
|
Find the next bookmark with invalid name under the directory.
|
|
|
|
@anchor{Filesystem-Check Result Code}
|
|
@cindex Filesystem-Check Result Code
|
|
On success, @code{ioctl()} updates @var{argp}, and returns
|
|
one of the values defined in @code{enum bookmarkfs_fsck_result}:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_FSCK_RESULT_END
|
|
There are no more bookmarks with invalid name under the directory.
|
|
|
|
Fields in @var{argp} have unspecified values.
|
|
|
|
@item BOOKMARKFS_FSCK_RESULT_NAME_DUPLICATE
|
|
The bookmark name duplicates with another bookmark which appears earlier
|
|
in the directory stream.
|
|
|
|
Value of @code{extra} is the ID of the other bookmark.
|
|
|
|
@item BOOKMARKFS_FSCK_RESULT_NAME_BADCHAR
|
|
The bookmark contains a bad character (i.e., the ASCII @samp{/} character).
|
|
|
|
Value of @code{extra} is the byte offset where the bad character first appears
|
|
in @code{name}.
|
|
|
|
@item BOOKMARKFS_FSCK_RESULT_NAME_BADLEN
|
|
The bookmark name is either longer than @code{NAME_MAX}, or an empty string.
|
|
|
|
Value of @code{extra} is the length of the bookmark name, and @code{name}
|
|
is truncated if longer than @code{NAME_MAX}.
|
|
|
|
@item BOOKMARKFS_FSCK_RESULT_NAME_DOTDOT
|
|
The bookmark name is either @samp{.} or @samp{..}.
|
|
|
|
Value of @code{extra} is unspecified.
|
|
@end table
|
|
|
|
On failure, @code{ioctl()} returns @t{-1}, and sets @code{errno}.
|
|
|
|
@anchor{Repair Bookmark}
|
|
@item BOOKMARKFS_IOC_FSCK_APPLY
|
|
``Repair'' a bookmark by renaming it.
|
|
|
|
The @code{id} field must be set to a value previously obtained from
|
|
@code{BOOKMARKFS_IOC_FSCK_NEXT} with the same @var{dirfd},
|
|
otherwise the behavior is undefined.
|
|
|
|
The @code{name} field should be set to the new name for the bookmark.
|
|
The @code{extra} field is unused.
|
|
|
|
On success, @code{ioctl()} updates @var{argp}, and returns
|
|
one of the values defined in @code{enum bookmarkfs_fsck_result},
|
|
like with @code{BOOKMARKFS_IOC_FSCK_NEXT}.
|
|
Additionally, it may also return:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_FSCK_RESULT_NAME_INVALID
|
|
The new name is not a valid bookmark name.
|
|
|
|
Value of @code{extra} is a backend-specific reason code
|
|
explaining why the bookmark name is invalid.
|
|
It may equal to one of the following predefined values:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_NAME_INVALID_REASON_NOTUTF8
|
|
The name is not valid UTF-8.
|
|
@end table
|
|
@end table
|
|
|
|
On failure, @code{ioctl()} returns @t{-1}, and sets @code{errno}:
|
|
|
|
@table @code
|
|
@item EACCES
|
|
Write or search permission is denied for the directory.
|
|
@end table
|
|
|
|
To ensure that the rename is visible to further lookups and @code{readdir()}
|
|
calls, @code{fsync()} or @code{close()} the directory.
|
|
|
|
@item BOOKMARKFS_IOC_FSCK_REWIND
|
|
Reset the fsck state for the directory.
|
|
|
|
Further @code{BOOKMARKFS_IOC_FSCK_NEXT} requests will start from the
|
|
beginning of the directory stream.
|
|
|
|
On success, @code{ioctl()} returns @t{0}.
|
|
Otherwise, it returns @t{-1}, and sets @code{errno}.
|
|
@end table
|
|
|
|
Common error codes for all filesystem-check ioctls:
|
|
|
|
@table @code
|
|
@item ENOTTY
|
|
The kernel does not support @code{FUSE_IOCTL}.
|
|
@xref{Limitations on FreeBSD}.
|
|
|
|
@item EPERM
|
|
The backend does not support fsck for this directory.
|
|
@end table
|
|
|
|
|
|
@node Backends
|
|
@chapter Backends
|
|
|
|
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:
|
|
|
|
@example
|
|
@var{$@{pkglibdir@}}/backend_@var{$@{name@}}@var{$@{shlib_suffix@}}
|
|
@end example
|
|
|
|
@table @var
|
|
@item $@{pkglibdir@}
|
|
Presumably @file{@var{$@{prefix@}}/lib/bookmarkfs}.
|
|
@xref{Uniform,, The Uniform Naming Scheme, automake, GNU Automake}.
|
|
|
|
@item $@{name@}
|
|
The backend name, equivalent to the value given to the
|
|
@option{-o backend=@var{name}} option of frontend programs.
|
|
|
|
@item $@{shlib_suffix@}
|
|
The common filename extension for shared library files on the current platform
|
|
(e.g., @file{.so} on GNU/Linux and FreeBSD).
|
|
@end table
|
|
|
|
|
|
@node Firefox Backend
|
|
@section Firefox Backend
|
|
|
|
The Firefox backend provides access to the bookmark data of the web browser
|
|
@uref{https://www.mozilla.org/en-US/firefox/new/, Mozilla Firefox}
|
|
and its derivatives, notably @uref{https://www.torproject.org/, Tor Browser}
|
|
and @uref{https://librewolf.net/, Librewolf}.
|
|
|
|
Backend name (for the @option{-o backend} option): @samp{firefox}.
|
|
|
|
Firefox bookmarks are stored in a SQLite database under the profile directory.
|
|
When mounting the filesystem, this pathname shall be passed as the @var{src}
|
|
argument (@pxref{mount.bookmarkfs}):
|
|
|
|
@example
|
|
~/.mozilla/firefox/@var{$@{profile_name@}}/places.sqlite
|
|
@end example
|
|
|
|
Actual path for the profile directories may differ across distributions.
|
|
When in doubt, visit @url{about:profiles} in your browser.
|
|
|
|
Backend-specific options (@command{mount.bookmarkfs} only):
|
|
|
|
@table @option
|
|
@item filename=title|guid
|
|
Whether to use the bookmark title or GUID as the bookmark file name.
|
|
Defaults to @samp{title}.
|
|
|
|
A bookmark GUID is a @rfcdoc{base64url-encoded, rfc4648#section-5}
|
|
128-bit string uniquely associated with a bookmark or bookmark folder.
|
|
|
|
When creating a new file:
|
|
|
|
@table @samp
|
|
@item title
|
|
The GUID is randomly generated by the backend.
|
|
|
|
@item guid
|
|
The filename must be a valid GUID, and must not duplicate with other files
|
|
on the same filesystem, otherwise @code{open()} or @code{mkdir()} fails
|
|
with @code{EPERM}.
|
|
|
|
Also set the GUID string as the bookmark title.
|
|
@end table
|
|
|
|
@item lock=exclusive|normal
|
|
The database connection locking mode for the bookmark storage.
|
|
Defaults to @samp{normal} when the filesystem is mounted read-only,
|
|
@samp{exclusive} otherwise.
|
|
|
|
This option corresponds to the @sqlitedoc{@code{locking_mode},
|
|
pragma.html#pragma_locking_mode} pragma on SQLite.
|
|
With @option{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 @samp{storage.sqlite.exclusiveLock.enabled} browser preference
|
|
to @samp{false}.
|
|
|
|
The @option{lock=exclusive} option also enables exclusive mode
|
|
(@pxref{Exclusive Mode}).
|
|
|
|
@item assume_title_distinct
|
|
If this options is provided, the backend assumes that bookmark names are
|
|
distinct under the same bookmark folder.
|
|
This option is ignored with @option{filename=guid}.
|
|
|
|
This option may improve @code{readdir()} performance, however,
|
|
making a false assumption results in a directory entry with duplicate names.
|
|
It is recommended to perform a full filesystem check (@pxref{Filesystem Check})
|
|
on the bookmark storage before mounting with this option.
|
|
@end table
|
|
|
|
If launched from @command{fsck.bookmarkfs}, all backend-specific options
|
|
are ignored, and always enforces the @option{lock=exclusive} option.
|
|
|
|
Backend-specific options (@command{mkfs.bookmarkfs} only):
|
|
|
|
@table @option
|
|
@item date_added=@var{timestamp}
|
|
File creation time for the predefined bookmark directories.
|
|
Defaults to the current time.
|
|
|
|
Format of @var{timestamp} is equivalent to the @samp{date_added}
|
|
extended attribute (see below).
|
|
@end table
|
|
|
|
Extended attributes:
|
|
|
|
@table @samp
|
|
@item title
|
|
The bookmark title.
|
|
Only available with @option{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.
|
|
|
|
@item guid
|
|
The bookmark GUID.
|
|
Only available with @option{filename=title}.
|
|
|
|
@item description
|
|
An arbitrary text associated with the bookmark.
|
|
|
|
Usually, when bookmarking a page in the browser, this value is
|
|
set to the @code{content} attribute of the @code{<meta>} element
|
|
whose @code{name} is @samp{description}.
|
|
|
|
@item date_added
|
|
The bookmark creation time.
|
|
|
|
Value is a decimal integer representing number of microseconds since
|
|
the Unix epoch.
|
|
|
|
@item keyword
|
|
The keyword associated with the bookmark.
|
|
@xref{Keywords}.
|
|
|
|
This attribute is read-only.
|
|
@end table
|
|
|
|
Notable limitations:
|
|
|
|
@itemize @bullet{}
|
|
@item If multiple bookmarks share the same URL, changing the last access time
|
|
of a bookmark may affect that of other bookmarks,
|
|
due to the way bookmarks are associated with the URLs.
|
|
|
|
@item The bookmark storage (SQLite database file) should be writable even if
|
|
the BookmarkFS filesystem is mounted read-only, due to the limitations
|
|
of WAL-mode.
|
|
See @sqlitedoc{Write-Ahead Logging, wal.html#readonly}.
|
|
@end itemize
|
|
|
|
|
|
@node Chromium Backend
|
|
@section Chromium Backend
|
|
|
|
The Chromium backend provides access to the bookmark data of the web browser
|
|
@uref{https://www.chromium.org/Home/, Chromium} and its derivatives,
|
|
notably @uref{https://github.com/ungoogled-software/ungoogled-chromium,
|
|
ungoogled-chromium}.
|
|
|
|
Backend name (for the @option{-o backend} option): @samp{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 @var{src}
|
|
argument (@pxref{mount.bookmarkfs}):
|
|
|
|
@example
|
|
~/.config/chromium/@var{$@{profile_name@}}/Bookmarks
|
|
@end example
|
|
|
|
Actual path for the profile directories may differ across distributions.
|
|
When in doubt, visit @url{chrome://profile-internals/} in your browser.
|
|
|
|
Backend-specific options (@command{mount.bookmarkfs} only):
|
|
|
|
@table @option
|
|
@item filename=title|guid
|
|
Whether to use the bookmark title or GUID as the bookmark file name.
|
|
Defaults to @samp{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:
|
|
|
|
@example
|
|
0bc5d13f-2cba-5d74-951f-3f233fe6c908
|
|
@end example
|
|
|
|
When creating a new file:
|
|
|
|
@table @samp
|
|
@item title
|
|
The GUID is randomly generated by the backend.
|
|
It is guaranteed to be a valid version 4 UUID as specified by
|
|
@rfcdoc{RFC 4122, rfc4122}.
|
|
|
|
@item guid
|
|
The filename must be a valid GUID, and must not duplicate with other files
|
|
on the same filesystem, otherwise @code{open()} or @code{mkdir()} fails
|
|
with @code{EPERM}.
|
|
|
|
Also set the GUID string as the bookmark title.
|
|
@end table
|
|
|
|
@item watcher=native|fallback|none
|
|
The file watcher to use for the bookmark storage.
|
|
Defaults to @samp{native} when the filesystem is mounted read-only,
|
|
@samp{none} otherwise.
|
|
|
|
@table @samp
|
|
@item native
|
|
@itemx fallback
|
|
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.
|
|
|
|
@xref{File Watcher}.
|
|
|
|
@item none
|
|
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 (@pxref{Exclusive Mode}).
|
|
@end table
|
|
@end table
|
|
|
|
If launched from @command{fsck.bookmarkfs}, all backend-specific options
|
|
are ignored, and always enforces the @option{watcher=none} option.
|
|
|
|
Backend-specific options (@command{mkfs.bookmarkfs} only):
|
|
|
|
@table @option
|
|
@item date_added=@var{timestamp}
|
|
File creation time for the predefined bookmark directories.
|
|
Defaults to the current time.
|
|
|
|
Format of @var{timestamp} is equivalent to the @samp{date_added}
|
|
extended attribute (see below).
|
|
@end table
|
|
|
|
Extended attributes:
|
|
|
|
@table @samp
|
|
@item title
|
|
The bookmark title.
|
|
Only available with @option{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.
|
|
|
|
@item guid
|
|
The bookmark GUID.
|
|
Only available with @option{filename=title}.
|
|
|
|
@item date_added
|
|
The bookmark creation time.
|
|
|
|
Value is a decimal integer representing number of microseconds since
|
|
the Windows @code{FILETIME} epoch (134774 days ahead of the Unix epoch).
|
|
@end table
|
|
|
|
Notable limitations:
|
|
|
|
@itemize @bullet{}
|
|
@item Does not scale well with large bookmark storage,
|
|
since everything is kept in memory, and the entire JSON file has to be parsed
|
|
whenever a reload is required.
|
|
|
|
@item No support for tags (@pxref{Tags}) and keywords (@pxref{Keywords}),
|
|
since Chromium does not have such concepts.
|
|
@end itemize
|
|
|
|
|
|
@node Backend API
|
|
@section Backend API
|
|
|
|
The Backend API specifies how a BookmarkFS backend communicates with a
|
|
frontend program (e.g., @command{mount.bookmarkfs}).
|
|
|
|
@quotation Warning
|
|
Currently BookmarkFS is experimental.
|
|
The Backend API may change drastically without prior notice.
|
|
@end quotation
|
|
|
|
@anchor{Backend Symbol Name Format}
|
|
@cindex Backend Symbol Name Format
|
|
To implement the Backend API, a backend library should expose a symbol
|
|
with the following name:
|
|
|
|
@example
|
|
bookmarkfs_backend_@var{$@{name@}}
|
|
@end example
|
|
|
|
Where @var{$@{name@}} is equivalent to the value given to the
|
|
@option{-o backend=@var{name}} option of frontend programs.
|
|
|
|
The symbol should name a data object identifier of the following type:
|
|
|
|
@example c
|
|
#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;
|
|
@};
|
|
@end example
|
|
|
|
Each field is a function pointer provided by the backend.
|
|
Some can be optional and set to @code{NULL}, if the backend
|
|
does not support the corresponding features.
|
|
|
|
|
|
@node General Information
|
|
@subsection General Information
|
|
|
|
@table @asis
|
|
@item Multithreading
|
|
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:
|
|
|
|
@itemize @bullet{}
|
|
@item The @code{SIGINT}, @code{SIGTERM} and @code{SIGHUP} signals should
|
|
be blocked with @posixfuncmanpage{pthread_sigmask} for the child threads.
|
|
If a signal is delivered to a child thread, the program may not be terminated
|
|
promptly, since libfuse relies on @code{EINTR} to break out of the event loop.
|
|
@end itemize
|
|
|
|
@cindex Backend Context
|
|
@item Backend Contexts
|
|
A backend context maintains internal states for manipulating a specific
|
|
bookmark storage.
|
|
|
|
Each BookmarkFS filesystem mounted by @command{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 @code{backend_ctx}) which refers to the context.
|
|
|
|
@item Callback Functions
|
|
Some backend functions (e.g., @code{bookmark_get}) accept a function pointer
|
|
argument, usually named @code{callback}, to be invoked by the backend.
|
|
|
|
It is guaranteed that backend functions are never called from within
|
|
a callback function.
|
|
|
|
@anchor{Exclusive Mode}
|
|
@cindex Exclusive Mode
|
|
@item Exclusive Mode
|
|
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 @code{backend_create} (@pxref{Create Backend Context}),
|
|
by setting the @code{BOOKMARKFS_BACKEND_EXCLUSIVE} response flag.
|
|
|
|
@item Error Codes
|
|
Some backend functions return an error code on failure instead of
|
|
just @code{-1}.
|
|
|
|
For backend functions analogous to the corresponding filesystem calls,
|
|
the error code should honor POSIX as well as platform-specific conventions.
|
|
For example:
|
|
|
|
@itemize @bullet{}
|
|
@item When replacing a non-empty directory with @code{bookmark_rename},
|
|
the function should fail with @code{EEXIST} or @code{ENOTEMPTY} as specified
|
|
in @posixfuncmanpage{rename}.
|
|
|
|
@item When trying to get/set the value of a non-existent extended attribute,
|
|
the function should fail with @code{ENODATA} on Linux, and @code{ENOATTR}
|
|
on FreeBSD.
|
|
@xref{Extended Attributes}.
|
|
@end itemize
|
|
|
|
Also @pxref{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.
|
|
@end table
|
|
|
|
|
|
@node Initialize Backend
|
|
@subsection Initialize Backend
|
|
|
|
The @code{backend_init} function is called before any other functions
|
|
(except for @code{backend_info}).
|
|
If not @code{NULL}, it is guaranteed to be called exactly once
|
|
throughout the lifetime of the process.
|
|
|
|
Type of the @code{backend_init} function is defined as:
|
|
|
|
@example c
|
|
typedef int (bookmarkfs_backend_init_func) (
|
|
uint32_t flags
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BACKEND_LIB_READY
|
|
Indicates that the utility library is already initialized.
|
|
@xref{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.
|
|
|
|
@item BOOKMARKFS_FRONTEND_FSCK
|
|
@itemx BOOKMARKFS_FRONTEND_MOUNT
|
|
@itemx BOOKMARKFS_FRONTEND_MKFS
|
|
Denotes the frontend program that launches the backend.
|
|
These flags are mutually exclusive.
|
|
@end table
|
|
@end table
|
|
|
|
The function should return @t{0} on success, and @t{-1} on error.
|
|
|
|
|
|
@node Get Backend Information
|
|
@subsection Get Backend Information
|
|
|
|
The @code{backend_info} function is called to print information
|
|
about the backend.
|
|
It can be @code{NULL}.
|
|
|
|
When this function is called, it should write a human-readable
|
|
message of the corresponding information to standard output.
|
|
|
|
Type of the @code{backend_info} function is defined as:
|
|
|
|
@example c
|
|
typedef void (bookmarkfs_backend_info_func) (
|
|
uint32_t flags
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BACKEND_INFO_HELP
|
|
Indicates that the function should print a help message.
|
|
Mutually exclusive with @code{BOOKMARKFS_BACKEND_INFO_VERSION}.
|
|
|
|
The message should contain a brief description of this backend,
|
|
as well as a list of backend-specific options.
|
|
|
|
@item BOOKMARKFS_BACKEND_INFO_VERSION
|
|
Indicates that the function should print a version message.
|
|
Mutually exclusive with @code{BOOKMARKFS_BACKEND_INFO_HELP}.
|
|
|
|
In addition to the version number, the version message may also contain
|
|
dependency versions, compile-time options, and other information
|
|
that can be used to determine a specific version of the backend.
|
|
|
|
@item BOOKMARKFS_FRONTEND_FSCK
|
|
@itemx BOOKMARKFS_FRONTEND_MOUNT
|
|
@itemx BOOKMARKFS_FRONTEND_MKFS
|
|
Denotes the frontend program that launches the backend.
|
|
These flags are mutually exclusive.
|
|
@end table
|
|
@end table
|
|
|
|
|
|
@node Create Backend Context
|
|
@subsection Create Backend Context
|
|
|
|
The @code{backend_create} function is called to create a backend context.
|
|
It must not be @code{NULL}.
|
|
|
|
Type of the @code{backend_create} function is defined as:
|
|
|
|
@example c
|
|
typedef int (bookmarkfs_backend_create_func) (
|
|
struct bookmarkfs_backend_conf const *conf,
|
|
struct bookmarkfs_backend_create_resp *resp
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item conf
|
|
Backend configuration items.
|
|
|
|
@anchor{Backend Configuration}
|
|
The @code{bookmarkfs_backend_conf} structure is defined as:
|
|
|
|
@example c
|
|
struct bookmarkfs_backend_conf @{
|
|
uint32_t version;
|
|
uint32_t flags;
|
|
char *store_path;
|
|
|
|
struct bookmarkfs_conf_opt *opts;
|
|
@};
|
|
@end example
|
|
|
|
@table @code
|
|
@item version
|
|
Version number of the frontend program, equivalent to the
|
|
@code{BOOKMARKFS_VERNUM} macro in @file{@var{$@{pkgincludedir@}}/version.h}.
|
|
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BACKEND_READONLY
|
|
Indicates that the filesystem is mounted read-only, and the functions that
|
|
may write to the bookmark storage will not be called for this session.
|
|
|
|
@item BOOKMARKFS_BACKEND_CTIME
|
|
Indicates that the @option{-o ctime} option is given to
|
|
@code{mount.bookmarkfs}.
|
|
|
|
@item BOOKMARKFS_BACKEND_NO_SANDBOX
|
|
Indicates that the @option{-o no_sandbox} option is given to
|
|
@code{mount.bookmarkfs}.
|
|
|
|
If the backend does not support sandboxing, @code{backend_create} should fail.
|
|
Otherwise, function @code{backend_sandbox} should be implemented.
|
|
@xref{Enter Sandbox}.
|
|
|
|
@item BOOKMARKFS_BACKEND_NO_LANDLOCK
|
|
Indicates that the @option{-o no_landlock} option is given to
|
|
@code{mount.bookmarkfs}.
|
|
|
|
@item BOOKMARKFS_BACKEND_FSCK_ONLY
|
|
Indicates that the backend is launched from @command{fsck.bookmarkfs}.
|
|
|
|
Exclusive mode must be enabled for this context (@pxref{Exclusive Mode}), and
|
|
only the @code{bookmark_lookup}, @code{bookmark_list}, @code{bookmark_check}
|
|
and @code{bookmark_sync} functions will be called on the bookmark objects.
|
|
@end table
|
|
|
|
@item store_path
|
|
Path to the bookmark storage, equivalent to the @var{src} argument passed to
|
|
@command{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.
|
|
|
|
@item opts
|
|
Linked list of backend-specific options, @code{NULL} if there are none.
|
|
|
|
@anchor{Backend-Specific Options}
|
|
The @code{bookmarkfs_conf_opt} structure is defined as:
|
|
|
|
@example c
|
|
struct bookmarkfs_conf_opt @{
|
|
char *key;
|
|
char *val;
|
|
|
|
struct bookmarkfs_conf_opt *next;
|
|
@};
|
|
@end example
|
|
|
|
@table @code
|
|
@item key
|
|
@itemx val
|
|
Key and value of the current option.
|
|
If the option does not have a value (no @samp{=} character present),
|
|
@code{val} is @code{NULL}.
|
|
|
|
When not @code{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.
|
|
|
|
@item next
|
|
Pointer to the next option, @code{NULL} if there are no more options.
|
|
@end table
|
|
|
|
The backend must not re-assign the fields in @code{opt}.
|
|
@end table
|
|
|
|
@item resp
|
|
Information 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.
|
|
|
|
@anchor{Backend-Create Response}
|
|
The @code{bookmarkfs_backend_create_resp} structure is defined as:
|
|
|
|
@example c
|
|
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;
|
|
@};
|
|
@end example
|
|
|
|
@table @code
|
|
@item name
|
|
Name of the backend context, used as default value for the
|
|
@option{-o fsname=@var{name}} option of @command{mount.bookmarkfs}.
|
|
|
|
Must be a NUL-terminated string valid at least until the next function call
|
|
on this backend context.
|
|
|
|
@item backend_ctx
|
|
An opaque pointer referring to the backend context.
|
|
|
|
The pointer will be passed to further function calls on this context.
|
|
|
|
@item bookmarks_root_id
|
|
ID of the bookmarks root directory
|
|
(i.e., @file{@var{$@{mountpoint@}}/bookmarks}).
|
|
Must not be greater than @code{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 @code{UINT64_MAX}.
|
|
|
|
@item tags_root_id
|
|
ID of the tags root directory (i.e., @file{@var{$@{mountpoint@}}/tags}).
|
|
Must not be greater than @code{BOOKMARKFS_MAX_ID}.
|
|
|
|
This field should be left as-is or set to @code{UINT64_MAX},
|
|
if one of the following conditions is met:
|
|
|
|
@itemize @bullet{}
|
|
@item Sandboxing is requested, and the ID cannot be determined in a safe way
|
|
before entering sandbox.
|
|
|
|
@item The backend does not support tags for this context.
|
|
@xref{Tags}.
|
|
@end itemize
|
|
|
|
@item xattr_names
|
|
Names of extended attributes (@pxref{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.
|
|
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BACKEND_EXCLUSIVE
|
|
Indicates that the backend claims exclusive access to the bookmark storage.
|
|
@xref{Exclusive Mode}.
|
|
|
|
@item BOOKMARKFS_BACKEND_HAS_KEYWORD
|
|
Indicates that the backend supports keywords for this context.
|
|
@xref{Keywords}.
|
|
@end table
|
|
@end table
|
|
@end table
|
|
|
|
The function should return @t{0} on success, and @t{-1} on error.
|
|
|
|
|
|
@node Destroy Backend Context
|
|
@subsection Destroy Backend Context
|
|
|
|
The @code{backend_destroy} function is called to destroy a backend context.
|
|
It must not be @code{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 @code{backend_destroy} function is defined as:
|
|
|
|
@example c
|
|
typedef void (bookmarkfs_backend_destroy_func) (
|
|
void *backend_ctx
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item backend_ctx
|
|
The pointer referring to the backend context.
|
|
@end table
|
|
|
|
|
|
@node Enter Sandbox
|
|
@subsection Enter Sandbox
|
|
|
|
The @code{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.
|
|
@xref{Sandboxing}.
|
|
|
|
This function is only called if the @code{BOOKMARKFS_BACKEND_NO_SANDBOX} flag
|
|
is @emph{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 other ones.
|
|
Thus it is guaranteed that, when launched from a frontend program like
|
|
@command{mount.bookmarkfs}, only one backend context will be created
|
|
throughout the lifetime of the process if sandboxing is ever needed.
|
|
|
|
Type of the @code{backend_sandbox} function is defined as:
|
|
|
|
@example c
|
|
typedef int (bookmarkfs_backend_sandbox_func) (
|
|
void *backend_ctx,
|
|
struct bookmarkfs_backend_create_resp *resp
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item backend_ctx
|
|
The pointer referring to the backend context.
|
|
|
|
@item resp
|
|
@xref{Backend-Create Response} for the definition of
|
|
@code{struct bookmarkfs_backend_create_resp}.
|
|
|
|
Fields in this argument should be left as-is, except for:
|
|
|
|
@table @code
|
|
@item bookmarks_root_id
|
|
This field must be set to the ID of the bookmarks root directory,
|
|
if not already done so in @code{backend_create}.
|
|
|
|
@item tags_root_id
|
|
This field should be set to the ID of the tags root directory,
|
|
if not already done so in @code{backend_create}.
|
|
|
|
If the backend does not support tags for this context, this field should be
|
|
left as-is or set to @code{UINT64_MAX}.
|
|
@end table
|
|
@end table
|
|
|
|
The function should return @t{0} on success, and @t{-1} on error.
|
|
|
|
Once this function fails, no further function calls will be performed
|
|
on the backend except for @code{backend_destroy}.
|
|
|
|
|
|
@node Lookup Bookmark
|
|
@subsection Lookup Bookmark
|
|
|
|
The @code{bookmark_lookup} function is called to obtain the attributes of
|
|
a bookmark or a bookmark-related object.
|
|
It must not be @code{NULL}.
|
|
|
|
Type of the @code{bookmark_lookup} function is defined as:
|
|
|
|
@example c
|
|
typedef int (bookmarkfs_bookmark_lookup_func) (
|
|
void *backend_ctx,
|
|
uint64_t id,
|
|
char const *name,
|
|
uint32_t flags,
|
|
struct bookmarkfs_bookmark_stat *stat_buf
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item backend_ctx
|
|
The pointer referring to the backend context.
|
|
|
|
@item id
|
|
ID of the object to be used for lookup.
|
|
It could be a bookmark ID or tag ID, depending on the value of @code{flags}.
|
|
|
|
@item name
|
|
Name of the object to lookup.
|
|
It could be a bookmark name, tag name or keyword name,
|
|
depending on the value of @code{flags}.
|
|
|
|
When not @code{NULL}, @code{name} is guaranteed to be a valid filename,
|
|
which should be used to lookup an object under the directory referred to
|
|
by @code{id}.
|
|
Otherwise, the function should operate on the object referred to
|
|
by @code{id} itself.
|
|
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_MASK
|
|
The subsystem to operate on.
|
|
|
|
Equals to one of the following values (after shifting):
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_BOOKMARK
|
|
Lookup a bookmark or bookmark folder.
|
|
@xref{Bookmarks}.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_TAG
|
|
Lookup a tag, or a bookmark under a tag.
|
|
@xref{Tags}.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_KEYWORD
|
|
Lookup a keyword.
|
|
@xref{Keywords}.
|
|
|
|
The value of @code{id} is unspecified.
|
|
@end table
|
|
@end table
|
|
|
|
@item stat_buf
|
|
Attributes 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.
|
|
|
|
@anchor{Bookmark Attributes}
|
|
The @code{bookmarkfs_bookmark_stat} structure is defined as:
|
|
|
|
@example c
|
|
struct bookmarkfs_bookmark_stat @{
|
|
uint64_t id;
|
|
ssize_t value_len;
|
|
|
|
struct timespec atime;
|
|
struct timespec mtime;
|
|
@};
|
|
@end example
|
|
|
|
@table @code
|
|
@item id
|
|
ID of the object.
|
|
|
|
@item value_len
|
|
Length of the object value in bytes.
|
|
@t{-1} if the object refers to a directory.
|
|
|
|
@item atime
|
|
@itemx mtime
|
|
Last access and modification time of the object.
|
|
|
|
Values should be the time elapsed since the Unix epoch.
|
|
@end table
|
|
@end table
|
|
|
|
On success, the function should return @t{0}.
|
|
Otherwise, it should return a negated @code{errno} indicating
|
|
the error encountered.
|
|
|
|
|
|
@node List Bookmarks
|
|
@subsection List Bookmarks
|
|
|
|
The @code{bookmark_list} function is called to list the bookmarks or
|
|
bookmark-related objects under a directory.
|
|
It must not be @code{NULL}.
|
|
|
|
Type of the @code{bookmark_list} function is defined as:
|
|
|
|
@example c
|
|
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
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item backend_ctx
|
|
The pointer referring to the backend context.
|
|
|
|
@item id
|
|
Object ID of the directory.
|
|
It could be a bookmark ID or tag ID, depending on the value of @code{flags}.
|
|
|
|
@item off
|
|
Position of the current @code{bookmark_list} operation, equivalent to
|
|
the second argument for @posixfuncmanpage{seekdir}.
|
|
|
|
Initially, the value is always @t{0}.
|
|
Subsequent calls (with the same cookie) use the values obtained from
|
|
@code{entry->off} of @code{callback} function calls.
|
|
If not, the position is unspecified.
|
|
|
|
A subsequent call with a @t{0} value indicates @posixfuncmanpage{rewinddir}.
|
|
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BOOKMARK_LIST_WITHSTAT
|
|
Indicates that the caller requires the attributes of the objects in the list.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_MASK
|
|
The subsystem to operate on.
|
|
|
|
Equals to one of the following values (after shifting):
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_BOOKMARK
|
|
List bookmarks (and bookmark folders) under a bookmark folder.
|
|
@xref{Bookmarks}.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_TAG
|
|
List tags, or bookmarks under a tag.
|
|
@xref{Tags}.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_KEYWORD
|
|
List keywords.
|
|
@xref{Keywords}.
|
|
|
|
The value of @code{id} is unspecified.
|
|
@end table
|
|
@end table
|
|
|
|
@item callback
|
|
Function to be called for each object found under the directory.
|
|
If @code{NULL}, @code{bookmark_list} should return immediately
|
|
without changing current position.
|
|
|
|
Ordering of the objects should follow the ordering of which they appear
|
|
in the browser.
|
|
@xref{Directory Entry Ordering}.
|
|
|
|
Type of the @code{callback} function is defined as:
|
|
|
|
@example c
|
|
typedef int (bookmarkfs_bookmark_list_cb) (
|
|
void *user_data,
|
|
struct bookmarkfs_bookmark_entry const *entry
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item user_data
|
|
Must be equal to the @code{user_data} argument value for the current
|
|
@code{bookmark_list} call.
|
|
|
|
@item entry
|
|
Information of this object.
|
|
|
|
The @code{bookmarkfs_bookmark_entry} structure is defined as:
|
|
|
|
@example c
|
|
struct bookmarkfs_bookmark_entry @{
|
|
char const *name;
|
|
off_t off;
|
|
|
|
struct bookmarkfs_bookmark_stat stat;
|
|
@};
|
|
@end example
|
|
|
|
@table @code
|
|
@item name
|
|
Name of the object entry.
|
|
Must be a valid filename.
|
|
|
|
Objects with invalid name should be exempted from the list.
|
|
@xref{Filesystem Check}.
|
|
|
|
@item off
|
|
Position of the current entry, to be used for subsequent calls to
|
|
@code{bookmark_list}.
|
|
|
|
@item stat
|
|
Attributes of the object entry.
|
|
|
|
@xref{Bookmark Attributes} for the definition of
|
|
@code{struct bookmarkfs_bookmark_stat}.
|
|
|
|
If the @code{BOOKMARKFS_BOOKMARK_LIST_WITHSTAT} flag is @emph{not} given,
|
|
the caller ignores @code{atime} and @code{mtime}, and only use @code{value_len}
|
|
to determine whether the entry refers to a directory.
|
|
@end table
|
|
|
|
Values of @code{entry} and @code{name} only need to be valid
|
|
until the @code{callback} function returns.
|
|
@end table
|
|
|
|
Return value:
|
|
|
|
@table @asis
|
|
@item @t{0}
|
|
Continue to the next entry, if one exists.
|
|
|
|
@item Non-zero value
|
|
Stop listing entries, and use this value as the return value for
|
|
the current @code{bookmark_list} call.
|
|
@end table
|
|
|
|
@item user_data
|
|
An opaque pointer which should be passed as-is to the @code{callback} function.
|
|
|
|
@item cookie_ptr
|
|
Pointer to the ``cookie'' for the current @code{bookmark_list} operation.
|
|
@code{NULL} if not used by the caller.
|
|
|
|
@anchor{Bookmark-List Cookie}
|
|
@cindex Bookmark-List Cookie
|
|
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 @code{cookie_ptr} is @code{NULL}, it indicates
|
|
that this is an initial operation.
|
|
The function should set the value to a pointer which is not @code{NULL}.
|
|
|
|
The cookie obtained from @code{bookmark_list} may be used for
|
|
@code{bookmark_check}, and vise versa.
|
|
However, the position of each operation should be maintained separately.
|
|
|
|
The function must not change the cookie value.
|
|
@end table
|
|
|
|
Return value:
|
|
|
|
@table @asis
|
|
@item @t{0}
|
|
All entries in the directory have been listed.
|
|
|
|
@item Negated @code{errno}
|
|
An error occurred.
|
|
|
|
@item Arbitrary non-zero value
|
|
The function is terminated by a call to @code{callback} that
|
|
returns a non-zero value.
|
|
@end table
|
|
|
|
If returning a negative value, the position of the current
|
|
@code{bookmark_list} operation is unspecified.
|
|
|
|
|
|
@node Get Bookmark Content
|
|
@subsection Get Bookmark Content
|
|
|
|
The @code{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.
|
|
@xref{Bookmarks}.
|
|
|
|
Type of the @code{bookmark_get} function is defined as:
|
|
|
|
@example c
|
|
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
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item backend_ctx
|
|
The pointer referring to the backend context.
|
|
|
|
@item id
|
|
ID of the bookmark (could be a bookmark folder if @code{xattr_name}
|
|
is not @code{NULL}).
|
|
|
|
@item xattr_name
|
|
Name of an extended attribute.
|
|
|
|
If not @code{NULL}, @code{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.
|
|
|
|
@item callback
|
|
Function to be called for the required bookmark data.
|
|
It is guaranteed not to be @code{NULL}.
|
|
|
|
Type of the @code{callback} function is defined as:
|
|
|
|
@example c
|
|
typedef int (bookmarkfs_bookmark_get_cb) (
|
|
void *user_data,
|
|
void const *value,
|
|
size_t value_len
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item user_data
|
|
Must be equal to the @code{user_data} argument value of the current
|
|
@code{bookmark_get} call.
|
|
|
|
@item value
|
|
Bookmark content (or extended attribute) data.
|
|
Must not be @code{NULL}.
|
|
|
|
It may contain arbitrary bytes, and only need to be valid until the
|
|
@code{callback} function returns.
|
|
|
|
@item value_len
|
|
Length of @code{value} in bytes.
|
|
@end table
|
|
|
|
The function returns @t{0} on success.
|
|
Otherwise, the function returns a negated @code{errno} which should be
|
|
used as the return value for the current @code{bookmark_get} call.
|
|
|
|
@item user_data
|
|
An opaque pointer which should be passed as-is to the @code{callback} function.
|
|
|
|
@item cookie_ptr
|
|
Pointer to the ``cookie'' for the current @code{bookmark_get} operation.
|
|
@code{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 @code{xattr_name})
|
|
to determine whether the corresponding data has changed.
|
|
|
|
If the value pointered to by @code{cookie_ptr} is @code{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 @code{NULL}.
|
|
|
|
The function must not change the cookie value.
|
|
@end table
|
|
|
|
On success, the function should return @t{0}.
|
|
Otherwise, it should return a negated @code{errno} indicating the error
|
|
encountered.
|
|
|
|
Notable error codes:
|
|
|
|
@table @code
|
|
@item EAGAIN
|
|
Bookmark data has not been changed @emph{externally} since
|
|
the last call to @code{bookmark_get} with the same cookie.
|
|
If this error code is returned, @code{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 @code{bookmark_list}
|
|
is always called with a @code{cookie_ptr} of @code{NULL} value.
|
|
@xref{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).
|
|
@end table
|
|
|
|
|
|
@node Free Cookie
|
|
@subsection Free Cookie
|
|
|
|
When a cookie obtained from @code{bookmark_list},
|
|
@code{bookmark_get} or @code{bookmark_check} is no longer used,
|
|
the @code{cookie_free} function is called.
|
|
It must not be @code{NULL}.
|
|
|
|
The function should release all system resources associated with this cookie.
|
|
|
|
Type of the @code{cookie_free} function is defined as:
|
|
|
|
@example c
|
|
typedef void (bookmarkfs_cookie_free_func) (
|
|
void *backend_ctx,
|
|
void *cookie,
|
|
enum bookmarkfs_cookie_type cookie_type
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item backend_ctx
|
|
The pointer referring to the backend context.
|
|
|
|
@item cookie
|
|
Cookie to be freed.
|
|
|
|
@item cookie_type
|
|
Type of the cookie.
|
|
It must be one of the values defined in @code{enum bookmarkfs_cookie_type}:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_COOKIE_TYPE_WATCH
|
|
Indicates that the cookie is obtained from @code{bookmark_get}.
|
|
|
|
@item BOOKMARKFS_COOKIE_TYPE_LIST
|
|
Indicates that the cookie is obtained from @code{bookmark_list} or
|
|
@code{bookmark_check}.
|
|
@end table
|
|
@end table
|
|
|
|
|
|
@node Set Bookmark Content
|
|
@subsection Set Bookmark Content
|
|
|
|
The @code{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 @code{bookmark_set} function is defined as:
|
|
|
|
@example c
|
|
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
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item backend_ctx
|
|
The pointer referring to the backend context.
|
|
|
|
@item id
|
|
ID of the object to update.
|
|
It could be a bookmark ID or tag ID, depending on the value of @code{flags}.
|
|
|
|
@item xattr_name
|
|
Name of an extended attribute.
|
|
|
|
If not @code{NULL}, @code{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.
|
|
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BOOKMARK_SET_ATIME
|
|
@itemx BOOKMARKFS_BOOKMARK_SET_MTIME
|
|
Indicates that the function should update the timestamps associated with
|
|
the object, instead of the bookmark content or extended attribute value.
|
|
|
|
The @code{val} argument points to an array of @code{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 @code{xattr_name} and @code{val_len} are unspecified.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_MASK
|
|
The subsystem to operate on.
|
|
|
|
Equals to one of the following values (after shifting):
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_BOOKMARK
|
|
Update the data associated with a bookmark or bookmark folder.
|
|
@xref{Bookmarks}.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_TAG
|
|
Update the data associated with a tag.
|
|
@xref{Tags}.
|
|
@end table
|
|
@end table
|
|
|
|
@item val
|
|
Pointer to the new value of the object data.
|
|
|
|
@item val_len
|
|
Length of the new value in bytes.
|
|
@end table
|
|
|
|
On success, the function should return @t{0}.
|
|
Otherwise, it should return a negated @code{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 @code{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.
|
|
|
|
|
|
@node Create Bookmark
|
|
@subsection Create Bookmark
|
|
|
|
The @code{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 @code{bookmark_create} function is defined as:
|
|
|
|
@example c
|
|
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
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item backend_ctx
|
|
The pointer referring to the backend context.
|
|
|
|
@item parent_id
|
|
ID of the parent directory to create the new object.
|
|
It could be a bookmark ID or tag ID, depending on the value of @code{flags}.
|
|
|
|
@item name
|
|
Name of the new object.
|
|
It could be a bookmark name, tag name or keyword name,
|
|
depending on the value of @code{flags}.
|
|
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BOOKMARK_CREATE_DIR
|
|
Indicates that the new object to be created should be a directory.
|
|
|
|
If this flag is not set, the new object should be a bookmark.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_MASK
|
|
The subsystem to operate on.
|
|
|
|
Equals to one of the following values (after shifting):
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_BOOKMARK
|
|
Create a bookmark or bookmark folder.
|
|
@xref{Bookmarks}.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_TAG
|
|
Create a tag, or associate an existing bookmark with a tag.
|
|
@xref{Tags}.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_KEYWORD
|
|
Associate an existing bookmark with a new keyword.
|
|
@xref{Keywords}.
|
|
|
|
The value of @code{parent_id} is unspecified.
|
|
@end table
|
|
@end table
|
|
|
|
@item stat_buf
|
|
Attributes of the new object.
|
|
|
|
@xref{Bookmark Attributes} for the definition of
|
|
@code{struct bookmarkfs_bookmark_stat}.
|
|
|
|
Except for the @code{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 @code{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).
|
|
@end table
|
|
|
|
On success, the function should return @t{0}.
|
|
Otherwise, it should return a negated @code{errno} indicating the error
|
|
encountered.
|
|
|
|
Restrictions for the new object:
|
|
|
|
@table @asis
|
|
@item New bookmark
|
|
Bookmark content should be empty if possible.
|
|
|
|
Other reasonable values (e.g., @samp{about:blank}) are also acceptable
|
|
if the bookmark storage does not allow empty bookmark content.
|
|
|
|
@item New directory
|
|
Should not contain any entries.
|
|
|
|
@item New association
|
|
Should appear to be the same object as the associated bookmark,
|
|
or at least contain the same content.
|
|
@end table
|
|
|
|
When a new object is successfully created, the function should automatically
|
|
update the last modification time of the parent directory to the current time.
|
|
|
|
|
|
@node Rename Bookmark
|
|
@subsection Rename Bookmark
|
|
|
|
The @code{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 @code{bookmark_rename} function is defined as:
|
|
|
|
@example c
|
|
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
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item backend_ctx
|
|
The pointer referring to the backend context.
|
|
|
|
@item old_parent_id
|
|
ID of the parent directory containing the object to be renamed.
|
|
It could be a bookmark ID or tag ID, depending on the value of @code{flags}.
|
|
|
|
@item old_name
|
|
Name of the object to be renamed.
|
|
It could be a bookmark name, tag name or keyword name,
|
|
depending on the value of @code{flags}.
|
|
|
|
@item new_parent_id
|
|
ID of the new parent directory for the object.
|
|
|
|
@item new_name
|
|
New name of the object.
|
|
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BOOKMARK_RENAME_NOREPLACE
|
|
Indicates that the function should not replace an existing object.
|
|
|
|
This flag is analogous to the @code{RENAME_NOREPLACE} flag for
|
|
@linuxmanpage{renameat2}.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_MASK
|
|
The subsystem to operate on.
|
|
|
|
Equals to one of the following values (after shifting):
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_BOOKMARK
|
|
Rename a bookmark.
|
|
@xref{Bookmarks}.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_TAG
|
|
Rename a tag.
|
|
@xref{Tags}.
|
|
|
|
The function should fail with @code{EPERM} if either @code{old_parent_id}
|
|
or @code{new_parent_id} does not refer to the tags root directory,
|
|
since renaming a tag association makes no sense.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_KEYWORD
|
|
Rename a keyword.
|
|
@xref{Keywords}.
|
|
|
|
Values of @code{old_parent_id} and @code{new_parent_id} are unspecified.
|
|
@end table
|
|
@end table
|
|
@end table
|
|
|
|
On success, the function should return @t{0}.
|
|
Otherwise, it should return a negated @code{errno} indicating the error
|
|
encountered.
|
|
|
|
When replacing an existing object:
|
|
|
|
@itemize @bullet{}
|
|
@item The two objects should be of the same type
|
|
(e.g., a bookmark cannot replace a bookmark folder).
|
|
|
|
@item When replacing a directory, the destination object must be empty.
|
|
|
|
@item If two objects are the same, the function should do nothing and return
|
|
successfully.
|
|
@end itemize
|
|
|
|
Upon successful completion, the function should automatically update the
|
|
last modification time of the parent directories.
|
|
|
|
|
|
@node Delete Bookmark
|
|
@subsection Delete Bookmark
|
|
|
|
The @code{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 @code{bookmark_delete} function is defined as:
|
|
|
|
@example c
|
|
typedef int (bookmarkfs_bookmark_delete_func) (
|
|
void *backend_ctx,
|
|
uint64_t parent_id,
|
|
char const *name,
|
|
uint32_t flags
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item backend_ctx
|
|
The pointer referring to the backend context.
|
|
|
|
@item parent_id
|
|
ID of the parent directory containing the object to be removed.
|
|
It could be a bookmark ID or tag ID, depending on the value of @code{flags}.
|
|
|
|
@item name
|
|
Name of the object to be removed.
|
|
It could be a bookmark name, tag name or keyword name,
|
|
depending on the value of @code{flags}.
|
|
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BOOKMARK_DELETE_DIR
|
|
Indicates that the object to be removed is a directory.
|
|
|
|
If the current backend context is not in exclusive mode
|
|
(@pxref{Exclusive Mode}), this information may be incorrect.
|
|
If so, the function should fail with @code{ENOTDIR} or @code{EISDIR}.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_MASK
|
|
The subsystem to operate on.
|
|
|
|
Equals to one of the following values (after shifting):
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_BOOKMARK
|
|
Remove a bookmark or an empty bookmark folder.
|
|
@xref{Bookmarks}.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_TAG
|
|
Remove a tag, or dissociate a bookmark from a tag.
|
|
@xref{Tags}.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_KEYWORD
|
|
Remove a keyword.
|
|
@xref{Keywords}.
|
|
|
|
The value of @code{parent_id} is unspecified.
|
|
@end table
|
|
@end table
|
|
@end table
|
|
|
|
On success, the function should return @t{0}.
|
|
Otherwise, it should return a negated @code{errno} indicating the error
|
|
encountered.
|
|
|
|
Upon successful completion, the function should automatically update the
|
|
last modification time of the parent directory.
|
|
|
|
|
|
@node Permute Bookmarks
|
|
@subsection Permute Bookmarks
|
|
|
|
The @code{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 @code{BOOKMARKFS_IOC_PERMD} I/O control.
|
|
@xref{Permute Directory Entries}.
|
|
|
|
Type of the @code{bookmark_permute} function is defined as:
|
|
|
|
@example c
|
|
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
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item backend_ctx
|
|
The pointer referring to the backend context.
|
|
|
|
@item parent_id
|
|
ID of the parent directory containing the objects to be rearranged.
|
|
It could be a bookmark ID or tag ID, depending on the value of @code{flags}.
|
|
|
|
@item op
|
|
Operation to perform on objects represented by @code{name1} and @code{name2}.
|
|
|
|
@xref{Rearrange Operations} for the meaning of each value.
|
|
|
|
@item name1
|
|
@itemx name2
|
|
Names of the objects to be rearranged.
|
|
They could be bookmark names, tag names or keyword names,
|
|
depending on the value of @code{flags}.
|
|
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_MASK
|
|
The subsystem to operate on.
|
|
|
|
Equals to one of the following values (after shifting):
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_BOOKMARK
|
|
Rearrange entries under a bookmark folder.
|
|
@xref{Bookmarks}.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_TAG
|
|
Rearrange tags or tag associations.
|
|
@xref{Tags}.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_KEYWORD
|
|
Rearrange keywords.
|
|
@xref{Keywords}.
|
|
|
|
The value of @code{parent_id} is unspecified.
|
|
@end table
|
|
@end table
|
|
@end table
|
|
|
|
On success, the function should return @t{0}.
|
|
Otherwise, it should return a negated @code{errno} indicating the error
|
|
encountered.
|
|
|
|
|
|
@node Check Bookmarks
|
|
@subsection Check Bookmarks
|
|
|
|
The @code{bookmark_check} function is called when a ``filesystem check''
|
|
operation is performed on a BookmarkFS directory.
|
|
@xref{Filesystem Check}.
|
|
|
|
Type of the @code{bookmark_check} function is defined as:
|
|
|
|
@example c
|
|
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
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item backend_ctx
|
|
The pointer referring to the backend context.
|
|
|
|
@item parent_id
|
|
ID of the parent directory containing the objects to be checked.
|
|
It could be a bookmark ID or tag ID, depending on the value of @code{flags}.
|
|
|
|
@item fsck_data
|
|
Always @code{NULL} if the filesystem is mounted read-only.
|
|
Otherwise, a non-@code{NULL} value indicates @code{BOOKMARKFS_IOC_FSCK_APPLY}.
|
|
@xref{Repair Bookmark}.
|
|
|
|
@xref{Filesystem-Check Data} for the definition of
|
|
@code{struct bookmarkfs_fsck_data}.
|
|
|
|
Value of each field:
|
|
|
|
@table @code
|
|
@item id
|
|
ID of the object to rename.
|
|
|
|
The function should check whether the object is under the directory
|
|
referred to by @code{parent_id}.
|
|
If not, it should fail with @code{ENOENT}.
|
|
|
|
If the object ID was not previously passed to the @code{callback} function
|
|
during a @code{bookmark_check} call with the same cookie, the function may:
|
|
|
|
@itemize @bullet{}
|
|
@item Fail with an arbitrary error code.
|
|
@item Perform the rename, even if the original name is a valid filename.
|
|
@end itemize
|
|
|
|
@item name
|
|
New name for the object.
|
|
The string may @emph{not} be NUL-terminated.
|
|
|
|
@item extra
|
|
Unspecified value.
|
|
@end table
|
|
|
|
If @code{fsck_data} is not @code{NULL}, the function should only check whether
|
|
the new name is valid, instead of going through the rest of the directory.
|
|
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_MASK
|
|
The subsystem to operate on.
|
|
|
|
Equals to one of the following values (after shifting):
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_BOOKMARK
|
|
Check bookmark and bookmark folder names.
|
|
@xref{Bookmarks}.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_TAG
|
|
Check tag names.
|
|
@xref{Tags}.
|
|
|
|
The function should fail with @code{EPERM} if @code{parent_id} does not
|
|
refer to the tags root directory.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_KEYWORD
|
|
Check keyword names.
|
|
@xref{Keywords}.
|
|
|
|
The value of @code{parent_id} is unspecified.
|
|
@end table
|
|
@end table
|
|
|
|
@item callback
|
|
Function to be called for each object with invalid name.
|
|
|
|
A @code{NULL} value indicates @code{BOOKMARKFS_IOC_FSCK_REWIND},
|
|
in which case the function should reset the position of the current
|
|
@code{bookmark_check} operation.
|
|
|
|
Type of the @code{callback} function is defined as:
|
|
|
|
@example c
|
|
typedef int (bookmarkfs_bookmark_check_cb) (
|
|
void *user_data,
|
|
int result,
|
|
uint64_t id,
|
|
uint64_t extra,
|
|
char const *name
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item user_data
|
|
Must be equal to the @code{user_data} argument for the current
|
|
@code{bookmark_check} call.
|
|
|
|
@item result
|
|
Should be one of the values defined in @code{enum bookmarkfs_fsck_result}
|
|
indicating why this name is invalid.
|
|
@xref{Filesystem-Check Result Code}.
|
|
|
|
@item id
|
|
@itemx extra
|
|
@itemx name
|
|
Equivalent to the corresponding fields in @code{struct bookmarkfs_fsck_data}.
|
|
@xref{Filesystem-Check Data}.
|
|
@end table
|
|
|
|
Return value:
|
|
|
|
@table @asis
|
|
@item @t{0}
|
|
Continue to the next entry, if one exists.
|
|
|
|
@item Non-zero value
|
|
Stop listing entries, and use this value as the return value for the current
|
|
@code{bookmark_check} call.
|
|
@end table
|
|
|
|
@item user_data
|
|
An opaque pointer which should be passed as-is to the @code{callback} function.
|
|
|
|
@item cookie_ptr
|
|
Pointer to the ``cookie'' for the current @code{bookmark_check} operation.
|
|
It is guaranteed not to be @code{NULL}.
|
|
|
|
Except for the position of operation, this cookie shares the same semantics
|
|
as the one for @code{bookmark_list}.
|
|
@xref{Bookmark-List Cookie}.
|
|
@end table
|
|
|
|
Return value:
|
|
|
|
@table @asis
|
|
@item @t{0}
|
|
The operation completes successfully.
|
|
|
|
@item Negated @code{errno}
|
|
An error occurred.
|
|
|
|
@item Arbitrary non-zero value
|
|
The function is terminated by a call to @code{callback} that returns a
|
|
non-zero value.
|
|
@end table
|
|
|
|
If returning a negative value, the position of the current
|
|
@code{bookmark_check} operation is unspecified.
|
|
|
|
|
|
@node Sync Bookmarks
|
|
@subsection Sync Bookmarks
|
|
|
|
The @code{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 @code{bookmark_sync} function is defined as:
|
|
|
|
@example c
|
|
typedef int (bookmarkfs_bookmark_sync_func) (
|
|
void *backend_ctx
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item backend_ctx
|
|
The pointer referring to the backend context.
|
|
@end table
|
|
|
|
On success, the function should return @t{0}.
|
|
Otherwise, it should return a negated @code{errno} indicating the error
|
|
encountered.
|
|
|
|
|
|
@node Create Bookmark Storage
|
|
@subsection Create Bookmark Storage
|
|
|
|
The @code{backend_mkfs} function is called by the @command{mkfs.bookmarkfs}
|
|
program to create a new bookmark storage.
|
|
It can be @code{NULL}.
|
|
|
|
The new bookmark storage should be able to be opened directly, by both
|
|
@code{backend_create} and the application that owns the bookmark storage
|
|
(typically a web browser).
|
|
|
|
Type of the @code{backend_mkfs} function is defined as:
|
|
|
|
@example c
|
|
typedef int (bookmarkfs_backend_mkfs_func) (
|
|
struct bookmarkfs_backend_conf const *conf
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item conf
|
|
@xref{Backend Configuration} for the definition of
|
|
@code{struct bookmarkfs_backend_conf}.
|
|
|
|
Some fields should be handled differently from @code{backend_create}:
|
|
|
|
@table @code
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_BACKEND_MKFS_FORCE
|
|
Indicates that the @option{-o force} option is given to
|
|
@command{mkfs.bookmarkfs}.
|
|
@end table
|
|
|
|
@item store_path
|
|
Path to the bookmark storage to be created, equivalent to the
|
|
@code{store_path} passed to @code{backend_create}.
|
|
|
|
The function should not overwrite existing bookmark storage, unless
|
|
the @code{BOOKMARKFS_BACKEND_MKFS_FORCE} flag is given.
|
|
@end table
|
|
@end table
|
|
|
|
The function should return @t{0} on success, and @t{-1} on error.
|
|
|
|
|
|
@node Filesystem-Check Handlers
|
|
@chapter Filesystem-Check Handlers
|
|
|
|
The filesystem-check handler instructs the @command{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:
|
|
|
|
@example
|
|
@var{$@{pkglibdir@}}/fsck_handler_@var{$@{name@}}@var{$@{shlib_suffix@}}
|
|
@end example
|
|
|
|
@table @var
|
|
@item $@{pkglibdir@}
|
|
Presumably @file{@var{$@{prefix@}}/lib/bookmarkfs}.
|
|
@xref{Uniform,, The Uniform Naming Scheme, automake, GNU Automake}.
|
|
|
|
@item $@{name@}
|
|
The handler name, equivalent to the value given to the
|
|
@option{-o handler=@var{name}} option of @command{fsck.bookmarkfs}.
|
|
|
|
@item $@{shlib_suffix@}
|
|
The common filename extension for shared library files on the current platform
|
|
(e.g., @file{.so} on GNU/Linux and FreeBSD).
|
|
@end table
|
|
|
|
|
|
@node Built-in Handler
|
|
@section Built-in Handler
|
|
|
|
The built-in filesystem-check handler is linked into the
|
|
@command{fsck.bookmarkfs} program.
|
|
It has minimal functionalities, but is capable enough to handle most
|
|
common fsck scenarios.
|
|
|
|
Handler-specific options:
|
|
|
|
@table @option
|
|
@item prompt=@var{str}
|
|
Readline prompt string.
|
|
Defaults to @samp{% }.
|
|
|
|
This option is ignored in non-interactive mode.
|
|
|
|
@item translit=@var{char}
|
|
Transliterate bad (@samp{/}) characters into @var{char}
|
|
(must be a single ASCII character).
|
|
Defaults to @samp{_}.
|
|
@end table
|
|
|
|
For each bookmark entry, the built-in handler prints a line
|
|
to standard output explaining why the bookmark name is invalid.
|
|
|
|
@anchor{Filesystem-Check Output Format}
|
|
@cindex Filesystem-Check Output Format
|
|
Output format (with an ASCII HT character separating each item):
|
|
|
|
@example
|
|
@var{id} @var{why} @var{extra} @var{name}
|
|
@end example
|
|
|
|
@table @var
|
|
@item why
|
|
Name of the result code, without the @samp{BOOKMARKFS_FSCK_RESULT_} prefix.
|
|
|
|
@xref{Filesystem-Check Result Code}.
|
|
|
|
@item id
|
|
@itemx extra
|
|
@itemx name
|
|
Information of this entry.
|
|
@xref{Filesystem-Check Data}.
|
|
|
|
Integers are printed in decimal format.
|
|
ASCII control characters in @var{name} are replaced with @samp{?}.
|
|
@end table
|
|
|
|
When the @option{-o repair} option is given, the handler renames the bookmark
|
|
according to the following rules:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_FSCK_RESULT_NAME_DUPLICATE
|
|
Append a @samp{_@var{$@{counter@}}} suffix to the name, where
|
|
@var{$@{counter@}} is a self-incrementing 32-bit integer in decimal format.
|
|
|
|
If appending the suffix would exceed max name length, truncate the name first.
|
|
|
|
@item BOOKMARKFS_FSCK_RESULT_NAME_BADCHAR
|
|
Transliterate the bad character into another character.
|
|
|
|
@item BOOKMARKFS_FSCK_RESULT_NAME_BADLEN
|
|
If the name is too long, truncate it to @code{NAME_MAX} bytes.
|
|
|
|
If the name is empty, see below:
|
|
|
|
@item BOOKMARKFS_FSCK_RESULT_NAME_DOTDOT
|
|
@itemx BOOKMARKFS_FSCK_RESULT_NAME_INVALID
|
|
Rename to @samp{fsck-@var{$@{id@}}}, where @var{$@{id@}} is the bookmark ID
|
|
in decimal format.
|
|
@end table
|
|
|
|
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:
|
|
|
|
@table @command
|
|
@item p
|
|
Print the ID and new name of current entry.
|
|
|
|
@item a[-]
|
|
Apply the proposed new name for the current entry.
|
|
|
|
@item e[-] @var{new_name}
|
|
Change the proposed new name to @var{new_name} and then apply.
|
|
|
|
@item c
|
|
Continue to the next entry.
|
|
|
|
@item s[-]
|
|
Skip current directory.
|
|
|
|
@item S[-]
|
|
Skip current directory and all subdirectories.
|
|
|
|
@item r[-]
|
|
Rewind current directory.
|
|
|
|
@item R[-]
|
|
Rewind all.
|
|
|
|
@item w[-]
|
|
Save applied changes.
|
|
|
|
@item q
|
|
Save applied changes and quit.
|
|
@end table
|
|
|
|
The optional @samp{-} suffix inhibits the default behavior of continuing
|
|
to the next entry, after the command completes successfully.
|
|
|
|
|
|
@node Tcl-Based Handler
|
|
@section Tcl-Based Handler
|
|
|
|
The @uref{https://www.tcl-lang.org/,, Tcl}-based filesystem-check handler
|
|
allows fsck entries to be handled via Tcl scripting.
|
|
|
|
Handler name (for the @option{-o handler} option): @samp{tcl}.
|
|
|
|
Handler-specific options:
|
|
|
|
@table @option
|
|
@item script=@var{path}
|
|
Path to the Tcl script file.
|
|
This option is mandatory.
|
|
|
|
The script is evaluated once after interpreter initialization.
|
|
The evaluation result will be used as the command name for later executions.
|
|
|
|
The following variables are set before script evaluation:
|
|
|
|
@table @code
|
|
@item $::bookmarkfs::fsck::isInteractive
|
|
Equals to @t{1} if the @option{-i} option is given to @code{fsck.bookmarkfs},
|
|
@t{0} otherwise.
|
|
|
|
@item $::bookmarkfs::fsck::isReadonly
|
|
Equals to @t{0} if the @option{-o repair} option is given to
|
|
@code{fsck.bookmarkfs}, @t{1} otherwise.
|
|
@end table
|
|
|
|
@item unsafe
|
|
Enable unsafe Tcl interpreter features.
|
|
|
|
Should be used in combination with the @option{-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 @code{interp create -safe}.
|
|
See @tcldoc{Safe Interpreters, TclCmd/interp.htm#M45}.
|
|
@end table
|
|
|
|
Each time @command{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:
|
|
|
|
@table @code
|
|
@item $::bookmarkfs::fsck::result::nameDuplicate
|
|
@itemx $::bookmarkfs::fsck::result::nameBadChar
|
|
@itemx $::bookmarkfs::fsck::result::nameBadLen
|
|
@itemx $::bookmarkfs::fsck::result::nameDotDot
|
|
@itemx $::bookmarkfs::fsck::result::nameInvalid
|
|
@xref{Filesystem-Check Result Code} for the meaning of each value.
|
|
|
|
The second element is a list of information about the current entry:
|
|
|
|
@enumerate 0
|
|
@item The bookmark ID
|
|
@item Extra information regarding the invalid name, equivalent to the
|
|
@code{extra} field in @code{struct bookmarkfs_fsck_data}.
|
|
@item Name of the bookmark
|
|
@item ID of the parent directory
|
|
@end enumerate
|
|
|
|
@item -1
|
|
If the command is being executed for the first time, or the previous execution
|
|
returns @code{$::bookmarkfs::fsck::handler::next}, this value never appears.
|
|
|
|
If the previous execution of the command returns
|
|
@code{$::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.
|
|
@end table
|
|
|
|
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:
|
|
|
|
@table @code
|
|
@item $::bookmarkfs::fsck::handler::next
|
|
Continue to the next entry.
|
|
|
|
@item $::bookmarkfs::fsck::handler::apply
|
|
Apply 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.
|
|
|
|
@item $::bookmarkfs::fsck::handler::userInput
|
|
Request for user input.
|
|
Only available in interactive mode.
|
|
|
|
Second element of the list should be a string for Readline prompt,
|
|
equivalent to the @option{prompt=@var{str}} option of the built-in handler.
|
|
|
|
@item $::bookmarkfs::fsck::handler::save
|
|
Save applied changes.
|
|
|
|
@item $::bookmarkfs::fsck::handler::stop
|
|
Save applied changes and quit.
|
|
|
|
Once this value is returned, the command will never be executed again.
|
|
|
|
@item $::bookmarkfs::fsck::handler::rewind
|
|
Rewind current directory.
|
|
|
|
@item $::bookmarkfs::fsck::handler::skip
|
|
Skip current directory.
|
|
|
|
@item $::bookmarkfs::fsck::handler::skipChildren
|
|
Skip current directory and all subdirectories.
|
|
|
|
@item $::bookmarkfs::fsck::handler::reset
|
|
Rewind all.
|
|
@end table
|
|
|
|
Here is an example Tcl script that simply prints each fsck entry
|
|
(requires the @option{unsafe} option):
|
|
|
|
@example tcl
|
|
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]]
|
|
@}
|
|
@}@}
|
|
@end example
|
|
|
|
|
|
@node Handler API
|
|
@section Handler API
|
|
|
|
The Filesystem-Check Handler API specifies how a fsck handler communicates with
|
|
@command{fsck.bookmarkfs}.
|
|
|
|
@quotation Warning
|
|
Currently BookmarkFS is experimental.
|
|
The Handler API may change drastically without prior notice.
|
|
@end quotation
|
|
|
|
@anchor{Filesystem-Check Handler Symbol Name Format}
|
|
@cindex Filesystem-Check Handler Symbol Name Format
|
|
To implement the Filesystem-Check Handler API, a fsck handler library
|
|
should expose a symbol with the following name:
|
|
|
|
@example
|
|
bookmarkfs_fsck_handler_@var{$@{name@}}
|
|
@end example
|
|
|
|
Where @var{$@{name@}} is equivalent to the value given to the
|
|
@option{-o handler=@var{name}} option of @command{fsck.bookmarkfs}.
|
|
|
|
The symbol should name a data object identifier of the following type:
|
|
|
|
@example c
|
|
#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;
|
|
@};
|
|
@end example
|
|
|
|
Each field is a function pointer provided by the fsck handler.
|
|
Some can be optional and set to @code{NULL}, if the backend
|
|
does not support the corresponding features.
|
|
|
|
|
|
@node Get Handler Information
|
|
@subsection Get Handler Information
|
|
|
|
If not @code{NULL}, the @code{info} function is called when the user
|
|
instructs @command{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 @code{info} function is defined as:
|
|
|
|
@example c
|
|
typedef void (bookmarkfs_fsck_handler_info_func) (
|
|
uint32_t flags
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_FSCK_HANDLER_INFO_HELP
|
|
@itemx BOOKMARKFS_FSCK_HANDLER_INFO_VERSION
|
|
Indicates that the function should print a help/version message.
|
|
|
|
These flags are analogous to the corresponding flags in the
|
|
@code{backend_info} function of the backend API.
|
|
@xref{Get Backend Information}.
|
|
@end table
|
|
@end table
|
|
|
|
|
|
@node Create Handler Context
|
|
@subsection Create Handler Context
|
|
|
|
A filesystem-check handler context maintains internal states for
|
|
handling fsck entries.
|
|
|
|
To create a handler context, the @code{create} function is called.
|
|
It must not be @code{NULL}.
|
|
|
|
Type of the @code{create} function is defined as:
|
|
|
|
@example c
|
|
typedef int (bookmarkfs_fsck_handler_create_func) (
|
|
struct bookmarkfs_conf_opt const *opts,
|
|
uint32_t flags,
|
|
void **handler_ctx_ptr
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item opts
|
|
Linked list of handler-specific options, @code{NULL} if there are none.
|
|
|
|
Handler-specific option should be processed in the same way as
|
|
backend-specific options.
|
|
@xref{Backend-Specific Options}.
|
|
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_FSCK_HANDLER_INTERACTIVE
|
|
Indicates that the @option{-i} option is given to @command{fsck.bookmarkfs}.
|
|
|
|
@item BOOKMARKFS_FSCK_HANDLER_READONLY
|
|
Indicates that the @option{-o repair} option is @emph{not} given to
|
|
@command{fsck.bookmarkfs}.
|
|
@end table
|
|
|
|
@item handler_ctx_ptr
|
|
Pointer 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.
|
|
@end table
|
|
|
|
The function should return @t{0} on success, and @t{-1} on error.
|
|
|
|
|
|
@node Destroy Handler Context
|
|
@subsection Destroy Handler Context
|
|
|
|
The @code{destroy} function is called to destroy a handler context.
|
|
It must not be @code{NULL}.
|
|
|
|
Upon destruction, The handler should release all system resources
|
|
associated with this context.
|
|
|
|
Type of the @code{destroy} function is defined as:
|
|
|
|
@example c
|
|
typedef void (bookmarkfs_fsck_handler_destroy_func) (
|
|
void *handler_ctx
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item handler_ctx
|
|
The pointer referring to the handler context.
|
|
@end table
|
|
|
|
|
|
@node Run Handler
|
|
@subsection Run Handler
|
|
|
|
Each time @command{fsck.bookmarkfs} finds and entry, or completes a
|
|
handler-initiated operation, the @code{run} function is called.
|
|
It must not be @code{NULL}.
|
|
|
|
Type of the @code{run} function is defined as:
|
|
|
|
@example c
|
|
typedef int (bookmarkfs_fsck_handler_run_func) (
|
|
void *handler_ctx,
|
|
int why,
|
|
union bookmarkfs_fsck_handler_data *data
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item handler_ctx
|
|
The pointer referring to the handler context.
|
|
|
|
@item why
|
|
Reason code for this handler call:
|
|
|
|
@table @asis
|
|
@item Non-negative value
|
|
The @command{fsck.bookmarkfs} program has found an entry.
|
|
|
|
@xref{Filesystem-Check Result Code} for possible values.
|
|
However, @code{BOOKMARKFS_FSCK_RESULT_END} is handled by
|
|
@command{fsck.bookmarkfs} and never appears.
|
|
|
|
@item @t{-1}
|
|
Indicates that an operation instructed by the previous return value
|
|
of this function is successfully performed.
|
|
|
|
If @code{run} is being called for the first time, or the previous invocation
|
|
returns @code{BOOKMARKFS_FSCK_NEXT}, this value never appears.
|
|
@end table
|
|
|
|
@item data
|
|
Information for this handler call.
|
|
|
|
The @code{bookmarkfs_fsck_handler_data} union is defined as:
|
|
|
|
@example c
|
|
union bookmarkfs_fsck_handler_data @{
|
|
struct bookmarkfs_fsck_handler_entry entry;
|
|
char *str;
|
|
@};
|
|
@end example
|
|
|
|
@table @code
|
|
@item entry
|
|
Information for the bookmark entry.
|
|
This field is set when @code{why} is non-negative.
|
|
|
|
The @code{bookmarkfs_fsck_handler_entry} structure is defined as:
|
|
|
|
@example c
|
|
struct bookmarkfs_fsck_handler_entry @{
|
|
uint64_t parent_id;
|
|
|
|
struct bookmarkfs_fsck_data data;
|
|
@};
|
|
@end example
|
|
|
|
@table @code
|
|
@item parent_id
|
|
ID of the bookmark folder that contains this bookmark entry.
|
|
|
|
@item data
|
|
@xref{Online Filesystem Check} for the definition of
|
|
@code{struct bookmarkfs_fsck_data}.
|
|
@end table
|
|
|
|
@item str
|
|
A NUL-terminated string.
|
|
|
|
This field is set to the user input string when @code{why} is @t{-1}, and the
|
|
previous invocation of @code{run} returns @code{BOOKMARKFS_FSCK_USER_INPUT}.
|
|
|
|
The string is only guaranteed to be valid until the function returns.
|
|
@end table
|
|
@end table
|
|
|
|
On success, the function should return one of the following values,
|
|
indicating the operation to perform:
|
|
|
|
@table @code
|
|
@item BOOKMARKFS_FSCK_NEXT
|
|
Continue to the next entry.
|
|
|
|
@item BOOKMARKFS_FSCK_APPLY
|
|
Apply change for the current entry.
|
|
Not available in read-only mode.
|
|
|
|
The function should copy the new name for the bookmark to
|
|
@code{data->entry.data.name}.
|
|
|
|
@item BOOKMARKFS_FSCK_USER_INPUT
|
|
Request for user input.
|
|
Only available in interactive mode.
|
|
|
|
The function should set @code{data->str} to a prompt string for Readline.
|
|
The string must be valid until the next function call on this handler context.
|
|
|
|
@item BOOKMARKFS_FSCK_SAVE
|
|
Save applied changes.
|
|
|
|
@item BOOKMARKFS_FSCK_STOP
|
|
Save applied changes and quit.
|
|
|
|
The @code{run} function is guaranteed not to be called again for this context.
|
|
|
|
@item BOOKMARKFS_FSCK_REWIND
|
|
Rewind current directory.
|
|
|
|
@item BOOKMARKFS_FSCK_SKIP
|
|
Skip current directory.
|
|
|
|
@item BOOKMARKFS_FSCK_SKIP_CHILDREN
|
|
Skip current directory and all subdirectories.
|
|
|
|
@item BOOKMARKFS_FSCK_RESET
|
|
Rewind all.
|
|
@end table
|
|
|
|
On error, the function should return @t{-1}.
|
|
|
|
|
|
@node The Utility Library
|
|
@chapter The Utility Library
|
|
|
|
The BookmarkFS Utility Library implements various common utility functions.
|
|
It is used internally by most of BookmarkFS's components, including
|
|
the backends (@pxref{Backends}) and the @command{mount.bookmarkfs} program.
|
|
|
|
@quotation Warning
|
|
Currently BookmarkFS is experimental.
|
|
Functions provided by the utility library may change drastically
|
|
without prior notice.
|
|
@end quotation
|
|
|
|
Typically, the library is built into a shared object, and installed as:
|
|
|
|
@example
|
|
@var{$@{libdir@}}/bookmarkfs_util@var{$@{shlib_suffix@}}
|
|
@end example
|
|
|
|
@table @var
|
|
@item $@{libdir@}
|
|
Presumably @file{@var{$@{prefix@}}/lib}.
|
|
@xref{Uniform,, The Uniform Naming Scheme, automake, GNU Automake}.
|
|
|
|
@item $@{shlib_suffix@}
|
|
The common filename extension for shared library files on the current platform
|
|
(e.g., @file{.so} on GNU/Linux and FreeBSD).
|
|
@end table
|
|
|
|
|
|
@node Hash Function
|
|
@section Hash Function
|
|
|
|
Non-cryptographic hash function with 64-bit seed and digest,
|
|
suitable for hash tables.
|
|
|
|
Currently, the @uref{https://xxhash.com/, xxHash} (XXH3) algorithm is used.
|
|
|
|
Functions:
|
|
|
|
@table @code
|
|
@item hash_seed
|
|
Updates the seed used by the hash function.
|
|
|
|
@example c
|
|
#include <bookmarkfs/hash.h>
|
|
|
|
void
|
|
hash_seed (
|
|
uint64_t s
|
|
);
|
|
@end example
|
|
|
|
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.
|
|
|
|
@item hash_digest
|
|
Calculates the digest of the given input.
|
|
|
|
@example c
|
|
uint64_t
|
|
hash_digest (
|
|
void const *input,
|
|
size_t len
|
|
);
|
|
@end example
|
|
|
|
@item hash_digestv
|
|
Like @code{hash_digest()}, but takes input from multiple buffers.
|
|
|
|
@example c
|
|
uint64_t
|
|
hash_digestv (
|
|
struct iovec const *bufv,
|
|
int bufcnt
|
|
);
|
|
@end example
|
|
|
|
The function is guaranteed not to modify the buffer data of each
|
|
@code{struct iovec} object.
|
|
|
|
@item hash_digestcb
|
|
Like @code{hash_digestv()}, but takes input buffers from a callback function.
|
|
|
|
@example c
|
|
uint64_t
|
|
hash_digestcb (
|
|
hash_digestcb_func *callback,
|
|
void *user_data
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item callback
|
|
The function to provide input buffers.
|
|
It must not be @code{NULL}.
|
|
|
|
Type of the @code{callback} function is defined as:
|
|
|
|
@example c
|
|
typedef size_t (hash_digestcb_func) (
|
|
void *user_data,
|
|
void const **buf_ptr
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item user_data
|
|
Equals to the @code{user_data} pointer passed to the current
|
|
@code{hash_digest} function call.
|
|
|
|
@item buf_ptr
|
|
Unless returning @t{0}, the callback function should store the pointer to
|
|
an input buffer to the location pointed to by @code{buf_ptr}.
|
|
|
|
The buffer must be valid until the next call to the callback function,
|
|
or until @code{hash_digestcb()} returns.
|
|
@end table
|
|
|
|
The callback function should return the number of bytes to be read from
|
|
the input buffer.
|
|
It is called continuously until it returns @t{0}.
|
|
|
|
@item user_data
|
|
An opaque pointer to be passed to the @code{callback} function.
|
|
@end table
|
|
@end table
|
|
|
|
|
|
@node Hash Tables
|
|
@section Hash Tables
|
|
|
|
A simple hash table implementation, based on a variant of
|
|
@uref{https://en.wikipedia.org/wiki/Hopscotch_hashing, Hopscotch Hashing}.
|
|
|
|
Time complexity:
|
|
|
|
@multitable @columnfractions .33 .33 .33
|
|
@headitem Operation @tab Average @tab Worst case
|
|
@item Insert @tab @t{Θ(1)} @tab @t{O(n)}
|
|
@item Search @tab @t{Θ(1)} @tab @t{O(log n)}
|
|
@item Delete @tab @t{Θ(1)} @tab @t{O(log n)}
|
|
@end multitable
|
|
|
|
Functions:
|
|
|
|
@table @code
|
|
@item hashmap_create
|
|
Creates a new hash table.
|
|
|
|
@example c
|
|
#include <bookmarkfs/hashmap.h>
|
|
|
|
struct hashmap *
|
|
hashmap_create (
|
|
hashmap_comp_func *entry_comp,
|
|
hashmap_hash_func *entry_hash
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item entry_comp
|
|
The callback function for checking whether a key matches an entry.
|
|
|
|
Type of @code{entry_comp} is defined as:
|
|
|
|
@example c
|
|
typedef int (hashmap_comp_func) (
|
|
union hashmap_key key,
|
|
void const *entry
|
|
);
|
|
@end example
|
|
|
|
The function should return @t{0} if the objects match, non-zero if not.
|
|
|
|
@item entry_hash
|
|
The callback function for obtaining the hashcode for an entry.
|
|
|
|
Type of @code{entry_hash} is defined as:
|
|
|
|
@example c
|
|
typedef unsigned long (hashmap_hash_func) (
|
|
void const *entry
|
|
);
|
|
@end example
|
|
|
|
This function is only called during rehashing,
|
|
and during @code{hashmap_delete} with a negative @code{entry_id}.
|
|
@end table
|
|
|
|
Returns an opaque pointer referring to the new hash table.
|
|
|
|
@item hashmap_insert
|
|
Inserts a new entry into a hash table.
|
|
|
|
@example c
|
|
void
|
|
hashmap_insert (
|
|
struct hashmap *map,
|
|
unsigned long hashcode,
|
|
void *entry
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item map
|
|
The hash table to insert entry into.
|
|
|
|
@item hashcode
|
|
The hash code for the new entry.
|
|
|
|
@item entry
|
|
An arbitrary pointer to be associated with the new entry.
|
|
It must not be @code{NULL}.
|
|
@end table
|
|
|
|
@item hashmap_search
|
|
Searches for an entry in a hash table.
|
|
|
|
@example c
|
|
void *
|
|
hashmap_search (
|
|
struct hashmap const *map,
|
|
union hashmap_key key,
|
|
unsigned long hashcode,
|
|
unsigned long *entry_id_ptr
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item map
|
|
The hash table to search from.
|
|
|
|
@item key
|
|
An object to identify the entry being searched.
|
|
|
|
Type of the @code{hashmap_key} union is defined as:
|
|
|
|
@example c
|
|
union hashmap_key @{
|
|
void const *ptr;
|
|
uint64_t u64;
|
|
@};
|
|
@end example
|
|
|
|
For each entry in the hash table with the given @code{hashcode},
|
|
the @code{entry_comp} callback function is called with @code{key}
|
|
as the first argument, until a matching entry is found.
|
|
|
|
@item hashcode
|
|
The hash code for the entry to search.
|
|
|
|
@item entry_id_ptr
|
|
If not @code{NULL}, and a matching entry is found,
|
|
the function sets @code{*entry_id_ptr} to an opaque integer value,
|
|
which can be used to identify the entry when calling @code{hashmap_delete()}.
|
|
|
|
A subsequent call to @code{hashmap_insert()} and @code{hashmap_delete()}
|
|
on this hash table invalidates that value.
|
|
@end table
|
|
|
|
Returns the pointer associated with the entry,
|
|
or @code{NULL} if no matching entry is found.
|
|
|
|
@item hashmap_delete
|
|
Removes an entry from a hash table.
|
|
|
|
@example c
|
|
void
|
|
hashmap_delete (
|
|
struct hashmap *map,
|
|
void const *entry,
|
|
long entry_id
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item map
|
|
The hash table to delete entry from.
|
|
|
|
@item entry
|
|
The entry to be deleted from the hash table.
|
|
|
|
If the hash table does not contain this entry, function behavior is undefined.
|
|
|
|
@item entry_id
|
|
An opaque integer obtained from @code{hashmap_search()} which identifies
|
|
the entry to be deleted.
|
|
If not readily available, @t{-1} should be used.
|
|
|
|
If provided, the delete operation is always of @t{O(1)} time complexity.
|
|
@end table
|
|
|
|
@item hashmap_foreach
|
|
Iterates through all entries of a hash table.
|
|
|
|
@example c
|
|
void
|
|
hashmap_foreach (
|
|
struct hashmap const *map,
|
|
hashmap_walk_func *walk_func,
|
|
void *user_data
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item map
|
|
The hash table to traverse.
|
|
|
|
@item walk_func
|
|
The callback function to be called for each entry.
|
|
|
|
Type of @code{walk_func} is defined as:
|
|
|
|
@example c
|
|
typedef void (hashmap_walk_func) (
|
|
void *entry,
|
|
void *user_data
|
|
);
|
|
@end example
|
|
|
|
The callback function must not insert to or delete from the current hash table.
|
|
|
|
@item user_data
|
|
An opaque pointer to be passed to @code{walk_func}.
|
|
@end table
|
|
|
|
@item hashmap_destroy
|
|
Destroys a hash table.
|
|
|
|
@example c
|
|
void
|
|
hashmap_destroy (
|
|
struct hashmap *map
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item map
|
|
The hash table to destroy.
|
|
If @code{NULL}, this function has no effect.
|
|
@end table
|
|
@end table
|
|
|
|
Limitations:
|
|
|
|
@itemize @bullet{}
|
|
@item Insertion performance is sacrificed in favor of search performance.
|
|
|
|
@item Suffers more from collisions than traditional open addressing.
|
|
Too many collisions on a single bucket forces a rehash.
|
|
|
|
With a good-quality hash function, the average load factor of a hash table
|
|
should be around 70%~75% before it must rehash.
|
|
|
|
@item Performance is suboptimal without hardware support for
|
|
@uref{https://en.wikipedia.org/wiki/Find_first_set, Find First Set}.
|
|
|
|
@item Concurrent writes on the same hash table is MT-Unsafe.
|
|
@end itemize
|
|
|
|
|
|
@node Pseudo-Random Number Generator
|
|
@section Pseudo-Random Number Generator
|
|
|
|
Non-cryptographic pseudo-random number generator with 64-bit output
|
|
and 256-bit state.
|
|
|
|
Currently, the @uref{https://prng.di.unimi.it/, xoshiro256++} algorithm
|
|
is used.
|
|
|
|
Functions:
|
|
|
|
@table @code
|
|
@item prng_seed
|
|
Updates the seed used by the PRNG.
|
|
|
|
@example c
|
|
#include <bookmarkfs/prng.h>
|
|
|
|
int
|
|
prng_seed (
|
|
uint64_t const s[4]
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item s
|
|
The new seed (i.e., the internal state) for the PRNG.
|
|
|
|
@quotation Note
|
|
It is recommended to seed the PRNG with values that ``appear to be random''
|
|
(have a uniform distribution of bits).
|
|
|
|
A seed with all bits zero (equivalent to never calling @code{prng_seed()})
|
|
results in @code{prng_rand()} producing a bad-quality number sequence.
|
|
@end quotation
|
|
|
|
If @code{NULL}, the seed will be obtained using @linuxmanpage{getrandom, 2}.
|
|
@end table
|
|
|
|
The function returns @t{0} on success, and @t{-1} on error.
|
|
If @code{s} is not @code{NULL}, the function never fails.
|
|
|
|
@item prng_rand
|
|
Returns the next value in the pseudo-random number sequence.
|
|
|
|
@example c
|
|
uint64_t
|
|
prng_rand (void);
|
|
@end example
|
|
|
|
With the same seed, the @code{prng_rand()} function always produces the same
|
|
number sequence.
|
|
|
|
@quotation Note
|
|
This function is MT-Unsafe.
|
|
@end quotation
|
|
@end table
|
|
|
|
|
|
@node Sandboxing
|
|
@section Sandboxing
|
|
|
|
While entering sandbox, the calling process/thread irrevocably relinquishes
|
|
most access to the system resources that it's not supposed to touch.
|
|
For example:
|
|
|
|
@itemize @bullet{}
|
|
@item access local files other than the bookmark storage
|
|
@item establish socket connections
|
|
@item execute other files
|
|
@end itemize
|
|
|
|
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:
|
|
|
|
@itemize @bullet{}
|
|
@item Bookmark storage @emph{not} created by the user with a trusted program
|
|
(e.g., obtained from some random person on the internet).
|
|
|
|
@item Filesystem calls from untrusted programs.
|
|
The program may be running in an isolated environment,
|
|
but it has a chance to escape if BookmarkFS can be exploited.
|
|
@end itemize
|
|
|
|
The utility library provides a helper function for sandboxing:
|
|
|
|
@example c
|
|
#include <bookmarkfs/sandbox.h>
|
|
|
|
int
|
|
sandbox_enter (
|
|
int dirfd,
|
|
uint32_t flags
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item dirfd
|
|
File descriptor of a directory to grant access.
|
|
@code{-1} if not needed.
|
|
|
|
The process may access, modify and create filesystem objects under the
|
|
directory using the @code{*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.
|
|
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @code
|
|
@item SANDBOX_READONLY
|
|
Grants read-only access to the directory referred to by @code{dirfd},
|
|
instead of read/write access.
|
|
|
|
This option is ignored when @code{dirfd} is @code{-1}.
|
|
|
|
@item SANDBOX_NO_LANDLOCK
|
|
Do not use Landlock for sandboxing.
|
|
|
|
This option is ignored on non-Linux platforms.
|
|
|
|
@item SANDBOX_NOOP
|
|
The sandbox does nothing, and always returns successfully.
|
|
@end table
|
|
@end table
|
|
|
|
The function should return @t{0} on success, and @t{-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.
|
|
|
|
@quotation Note
|
|
The @code{sandbox_enter()} function is designed to work with BookmarkFS
|
|
components, and may require some tweaking to be used for other programs.
|
|
@end quotation
|
|
|
|
Sandboxing is implemented using platform-specific features,
|
|
and may behave differently across platforms:
|
|
|
|
@table @asis
|
|
@item Linux
|
|
Implemented using @linuxmanpage{seccomp, 2} and @linuxmanpage{landlock, 7}.
|
|
|
|
Sandbox applies to the calling thread.
|
|
|
|
@item FreeBSD
|
|
Implemented using @freebsdmanpage{capsicum, 4}.
|
|
|
|
Sandbox applies to the calling process.
|
|
@end table
|
|
|
|
Refer to the source code in @file{src/sandbox.c} for implementation details.
|
|
|
|
|
|
@node File Watcher
|
|
@section File Watcher
|
|
|
|
File watchers detect filesystem changes using platform-specific features:
|
|
|
|
@table @asis
|
|
@item Linux
|
|
Implemented with @linuxmanpage{fanotify, 7}.
|
|
Requires kernel version 5.13 or later for unprivileged users.
|
|
|
|
@linuxmanpage{inotify, 7} does not have this limitation, however,
|
|
it is incompatible with our sandboxing design.
|
|
|
|
@item FreeBSD
|
|
Implemented with the @code{EVFILT_VNODE} filter of @freebsdmanpage{kevent, 2}.
|
|
|
|
@item Fallback
|
|
When no platform-specific filesystem watching mechanism is available,
|
|
periodically checks the @code{st_ino} and @code{st_mtim} attributes
|
|
of the watched file with @posixfuncmanpage{fstatat}.
|
|
|
|
This approach is less efficient than ``native'' implementations,
|
|
but should work on any POSIX-compatible system.
|
|
@end table
|
|
|
|
Functions:
|
|
|
|
@table @code
|
|
@item watcher_create
|
|
Creates a new watcher.
|
|
|
|
@example c
|
|
#include <bookmarkfs/watcher.h>
|
|
|
|
struct watcher *
|
|
watcher_create (
|
|
int dirfd,
|
|
char const *name,
|
|
uint32_t flags
|
|
);
|
|
@end example
|
|
|
|
Function arguments:
|
|
|
|
@table @code
|
|
@item dirfd
|
|
File descriptor of the directory holding the file to be watched.
|
|
|
|
@item name
|
|
Name of the file to be watched.
|
|
|
|
@item flags
|
|
A bit array of the following flags:
|
|
|
|
@table @asis
|
|
@item @code{WATCHER_FALLBACK}
|
|
Do not use platform-specific features.
|
|
|
|
@item @code{WATCHER_NOOP}
|
|
The watcher does nothing, and @code{watcher_poll()} always return
|
|
@code{-EAGAIN}.
|
|
|
|
Values of @code{dirfd}, @code{name} and other flags are ignored.
|
|
|
|
@item Sandbox Flags
|
|
Flags for @code{sandbox_enter()}, shifted
|
|
@code{WATCHER_SANDBOX_FLAGS_OFFSET} bits.
|
|
|
|
The sandbox flags apply to the worker thread used internally by the watcher.
|
|
@code{SANDBOX_READONLY} is always applied.
|
|
|
|
@xref{Sandboxing}.
|
|
@end table
|
|
@end table
|
|
|
|
On success, the function returns a pointer referring to the watcher.
|
|
On error, it returns @code{NULL}.
|
|
|
|
@item watcher_destroy
|
|
Stop watching, and release all system resources associated with the watcher.
|
|
|
|
@example c
|
|
void
|
|
watcher_destroy (
|
|
struct watcher *w
|
|
);
|
|
@end example
|
|
|
|
@item watcher_poll
|
|
Checks whether the file being watched has changed.
|
|
This function never blocks.
|
|
|
|
@example c
|
|
int
|
|
watcher_poll (
|
|
struct watcher *w
|
|
);
|
|
@end example
|
|
|
|
Return value:
|
|
|
|
@table @asis
|
|
@item @t{0}
|
|
The file has changed since the last call to @code{watcher_poll()};
|
|
if it hasn't been called, since watcher initialization.
|
|
|
|
@item @code{-EAGAIN}
|
|
The file hasn't changed since the last call to @code{watcher_poll()} that
|
|
returns @t{0}.
|
|
|
|
If no previous @code{watcher_poll()} calls return @t{0}, it indicates that
|
|
the watcher is being initialized.
|
|
|
|
@item @code{-ENOENT}
|
|
The file being watched does not exist.
|
|
|
|
@item @code{-EIO}
|
|
An internal error has occurred.
|
|
|
|
Further calls to @code{watcher_poll()} on this watcher will always fail.
|
|
@end table
|
|
@end table
|
|
|
|
|
|
@node General Index
|
|
@appendix General Index
|
|
|
|
@printindex cp
|
|
|
|
|
|
@node GNU Free Documentation License
|
|
@appendix GNU Free Documentation License
|
|
|
|
@include fdl.texi
|
|
|
|
|
|
@bye
|