mirror of
https://git.sr.ht/~cismonx/bookmarkfs
synced 2025-07-17 06:38:53 +00:00
2592 lines
73 KiB
Text
2592 lines
73 KiB
Text
\input texinfo @c -*-texinfo-*-
|
|
|
|
@setfilename bookmarkfs.info
|
|
@include version.texi
|
|
@settitle BookmarkFS User Manual
|
|
|
|
@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 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 GNU General
|
|
Public License, either version 3, or any later version of the license.
|
|
You should have received a copy of the GNU General Public License along with
|
|
BookmarkFS. If not, see @uref{https://www.gnu.org/licenses/}.
|
|
|
|
BookmarkFS is
|
|
@uref{https://savannah.nongnu.org/projects/bookmarkfs, hosted on Savannah}.
|
|
Write to the
|
|
@uref{https://savannah.nongnu.org/mail/?group=bookmarkfs, mailing lists}
|
|
for bug reports, feature requests, and other discussions.
|
|
|
|
|
|
@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.
|
|
While OpenBSD does provide a libfuse-compatible library, however,
|
|
it only covers the high-level API, and 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.
|
|
|
|
|
|
@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 Permute directory entries (@pxref{Permute Directory Entries})
|
|
@item Online filesystem check (@pxref{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 Sandboxing
|
|
@section Sandboxing
|
|
|
|
A BookmarkFS backend can be instructed to enter a sandboxed state,
|
|
where it 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.
|
|
|
|
Examples of what ``untrusted input'' may include:
|
|
|
|
@itemize @bullet{}
|
|
@item Bookmark files that are @emph{not} created by the user using a trusted
|
|
program (e.g., a file obtained from some random person on the internet).
|
|
@item Filesystem calls from untrusted programs.
|
|
The program itself may be isolated, but it has a chance to escape
|
|
the isolated environment if it can exploit BookmarkFS.
|
|
@end itemize
|
|
|
|
On Linux, sandboxing is achieved using @linuxmanpage{seccomp, 2} and
|
|
@linuxmanpage{landlock, 7}.
|
|
On FreeBSD, @freebsdmanpage{capsicum, 4} is used.
|
|
|
|
|
|
@node The Utility Library
|
|
@section 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.
|
|
|
|
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
|
|
|
|
Public headers are installed under @file{@var{$@{pkgincludedir@}}}
|
|
(presumably @file{@var{$@{prefix@}}/include/bookmarkfs}).
|
|
To use the library functions, include the following headers as needed:
|
|
|
|
@table @file
|
|
@item hash.h
|
|
Non-cryptographic hash function.
|
|
|
|
@item hashmap.h
|
|
A simple hashtable implementation.
|
|
|
|
@item prng.h
|
|
Non-cryptographic pseudo-random number generator.
|
|
|
|
@item sandbox.h
|
|
A simple sandbox implementation. @xref{Sandboxing}.
|
|
|
|
@item version.h
|
|
Get version and feature information of the library.
|
|
|
|
@item watcher.h
|
|
Single-file filesystem watcher.
|
|
@end table
|
|
|
|
Usage of the library functions is rather simple and straightforward,
|
|
thus there's currently no dedicated manual sections.
|
|
Refer to the comments in the corresponding header files for details.
|
|
|
|
|
|
@node Programs
|
|
@chapter Programs
|
|
|
|
BookmarkFS ships with programs that provide users with a command-line
|
|
interface 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 option is backend-defined.
|
|
|
|
@item target
|
|
Pathname of the directory where the filesystem shall be mounted to
|
|
(i.e., the ``mountpoint'').
|
|
@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 @t{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{File Modification/Change Time}
|
|
@cindex File Modification/Change Time
|
|
@item -o ctime
|
|
Maintain file change time, while modification time follows change time.
|
|
If this option is not provided, maintain file modification time instead.
|
|
|
|
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 modification time
|
|
ctime only updates when mtime does.
|
|
|
|
@item 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 @t{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 process 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 ``access time'' attribute of a bookmark necessarily means
|
|
``the last time it was accessed from the browser''.
|
|
As a bookmark management tool independent 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}).
|
|
@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()} (@pxref{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 (@pxref{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 (@pxref{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
|
|
I/O controls of a BookmarkFS filesystem.
|
|
|
|
@example
|
|
bookmarkctl @var{subcmd} [@var{args}]
|
|
@end example
|
|
|
|
Sub-commands:
|
|
|
|
@table @command
|
|
@item permd
|
|
Re-arranges the order of the directory entries obtained from @code{readdir()}.
|
|
@xref{Permute Directory Entries}.
|
|
|
|
@example
|
|
bookmarkctl permd @var{pathname} @var{op} @var{name1} @var{name2}
|
|
@end example
|
|
|
|
@table @var
|
|
@item pathname
|
|
Path to the directory.
|
|
|
|
@item name1
|
|
@item name2
|
|
Filename of entries under the directory.
|
|
|
|
@item op
|
|
Operation to perform on the directory:
|
|
|
|
@table @samp
|
|
@item swap
|
|
Exchange the positions of the directory entries represented by @var{name1}
|
|
and @var{name2}.
|
|
|
|
@item move-before
|
|
Move the directory entry represented by @var{name1} to the position just
|
|
@emph{before} the one represented by @var{name2}.
|
|
|
|
@item move-after
|
|
Move the directory entry represented by @var{name1} to the position just
|
|
@emph{after} the one represented by @var{name2}.
|
|
@end table
|
|
@end table
|
|
|
|
@item fsck
|
|
Check for errors within a BookmarkFS filesystem.
|
|
@xref{Filesystem Check}.
|
|
|
|
@example
|
|
bookmarkctl fsck @var{pathname} @var{op}
|
|
@end example
|
|
|
|
@table @var
|
|
@item pathname
|
|
Path to the directory to perform checks on.
|
|
|
|
@item op
|
|
Operation to perform on the directory:
|
|
|
|
@table @samp
|
|
@item list
|
|
Display a list of errors found under the given directory.
|
|
Will not recurse into subdirectories.
|
|
@end table
|
|
@end table
|
|
|
|
For the full fsck functionalities, @pxref{fsck.bookmarkfs}.
|
|
|
|
@item help
|
|
Print help text, and then exit.
|
|
|
|
@item version
|
|
Print version information, and then exit.
|
|
@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{File 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 (@pxref{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 @code{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 makes 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 daemon process.
|
|
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.
|
|
@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 attributes have a @samp{bookmarkfs.} name 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 decides which attributes are available during initialization,
|
|
and all bookmark files 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}).
|
|
|
|
@item Ordering of directory entries
|
|
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, it is guaranteed to be equivalent to the
|
|
directory traversal order.
|
|
New entries are appended to the end; removed entries do not affect
|
|
the order of other entries.
|
|
|
|
To change the ordering 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
|
|
|
|
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 enum @code{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
|
|
|
|
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 enum @code{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}.
|
|
|
|
@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 enum @code{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}.
|
|
|
|
Firefox bookmarks are stored in a SQLite database under the profile directory:
|
|
|
|
@example
|
|
~/.mozilla/firefox/@var{$@{profile_name@}}/places.sqlite
|
|
@end example
|
|
|
|
When mounting the filesystem, this pathname shall be passed as the @var{src}
|
|
argument (@pxref{mount.bookmarkfs}).
|
|
Actual path for the profile directories may differ across distributions.
|
|
|
|
Backend name: @samp{firefox}.
|
|
|
|
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
|
|
@uref{https://www.sqlite.org/pragma.html#pragma_locking_mode,
|
|
@code{locking_mode}} pragma on SQLite.
|
|
With @option{lock=exclusive}, other process 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 @code{storage.sqlite.exclusiveLock.enabled} browser preference
|
|
to @code{false}.
|
|
|
|
@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.
|
|
@end table
|
|
|
|
|
|
@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}.
|
|
|
|
Chromium bookmarks are stored in a text file (in JSON format)
|
|
under the profile directory:
|
|
|
|
@example
|
|
~/.config/chromium/@var{$@{profile_name@}}/Bookmarks
|
|
@end example
|
|
|
|
When mounting the filesystem, this pathname shall be passed as the @var{src}
|
|
argument (@pxref{mount.bookmarkfs}).
|
|
Actual path for the profile directories may differ across distributions.
|
|
|
|
Backend name: @samp{chromium}.
|
|
|
|
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.
|
|
The GUID string has a ``8-4-4-4-12'' format, while all alphabetic characters
|
|
are 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
|
|
Watch for file changes using platform-specific features:
|
|
|
|
@table @asis
|
|
@item Linux
|
|
@linuxmanpage{fanotify, 7} is used.
|
|
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
|
|
@freebsdmanpage{kevent, 2} with @code{EVFILT_VNODE} is used.
|
|
@end table
|
|
|
|
@item fallback
|
|
Watch for file changes by checking @code{st_ino} and @code{st_mtim} attributes
|
|
with @code{fstatat()} periodically.
|
|
|
|
Less efficient than ``native'' implementations, but should work on any
|
|
POSIX-compatible system.
|
|
|
|
@item none
|
|
Do not watch for file changes.
|
|
|
|
With @option{watcher=none}, changes on the bookmark storage are not visible
|
|
to the filesystem.
|
|
@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_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_fsck_func *bookmark_fsck;
|
|
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_object_free_func *object_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 Initialize Backend
|
|
@subsection Initialize Backend
|
|
|
|
The @code{backend_init} function is called by the frontend program
|
|
before calling 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
|
|
@item BOOKMARKFS_FRONTEND_MOUNT
|
|
@item 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
|
|
|
|
If not @code{NULL}, the @code{backend_info} function is called when the user
|
|
instructs the frontend program to print information about the backend.
|
|
|
|
When this function is called, the backend 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 backend 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 backend 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
|
|
@item BOOKMARKFS_FRONTEND_MOUNT
|
|
@item 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
|
|
|
|
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.
|
|
Operations on the filesystem, if applicable, are fulfilled by invoking
|
|
the corresponding backend functions on the context.
|
|
|
|
To create a backend context, the @code{backend_create} function is called.
|
|
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{bookmarkfs/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 frontend program
|
|
will not call functions that may write to the bookmark storage.
|
|
|
|
@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}.
|
|
|
|
The backend must claim exclusive access to the bookmark storage, and only
|
|
the @code{bookmark_lookup}, @code{bookmark_list}, @code{bookmark_fsck}
|
|
and @code{bookmark_sync} functions will be called on the bookmarks.
|
|
@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 backend 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
|
|
@item 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 backend 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 backend 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 *bookmark_attrs;
|
|
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 (@pxref{Tags}).
|
|
@end itemize
|
|
|
|
@item bookmark_attrs
|
|
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.
|
|
|
|
In exclusive mode, modifications to the bookmark storage only come from
|
|
the frontend, and the frontend program may perform optimizations based on
|
|
this assumption.
|
|
|
|
@item BOOKMARKFS_BACKEND_HAS_KEYWORD
|
|
Indicates that the backend supports keywords for this context
|
|
(@pxref{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
|
|
|
|
When a backend context is no longer used, the @code{backend_destroy} function
|
|
is called.
|
|
It must not be @code{NULL}.
|
|
|
|
Upon destruction, the backend should release all system resources
|
|
associated with this context.
|
|
If changes have been made to the bookmark storage, the backend should
|
|
try to persist them.
|
|
|
|
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} given to @code{backend_create} when creating the current context.
|
|
It can be @code{NULL} if the backend context does not support sandboxing.
|
|
|
|
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.
|
|
|
|
Currently, the backends shipped with BookmarkFS use the sandbox implementation
|
|
in the utility library (@pxref{The Utility Library}).
|
|
It may require some tweaking to be used for other backends.
|
|
|
|
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 the
|
|
@code{bookmarkfs_backend_create_resp} structure.
|
|
|
|
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
|
|
The subsystem object ID to be used for lookup.
|
|
It could either be a bookmark ID or a tag ID,
|
|
depending on the value of @code{flags}.
|
|
|
|
@item name
|
|
Name of the subsystem 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
|
|
Indicates that the function should operate on the ``bookmarks'' subsystem.
|
|
@xref{Bookmarks}.
|
|
|
|
@code{id} and @code{name} refers to bookmark ID and bookmark name.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_TAG
|
|
Indicates that the function should operate on the ``tags'' subsystem.
|
|
@xref{Tags}.
|
|
|
|
@code{id} and @code{name} refers to tag ID and tag name.
|
|
|
|
@item BOOKMARKFS_BOOKMARK_TYPE_KEYWORD
|
|
Indicates that the function should operate on the ``keywords'' subsystem.
|
|
@xref{Keywords}.
|
|
|
|
@code{name} refers to keyword name (must not be @code{NULL}).
|
|
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 backend should populate
|
|
this argument with appropriate values.
|
|
|
|
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
|
|
@item mtime
|
|
Last access and modification time of the object.
|
|
Must not be earlier than 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.
|
|
|
|
Generally, the error code should follow filesystem conventions,
|
|
but the backend may return other error codes which it sees fit.
|
|
Also @pxref{Error Codes}.
|
|
|
|
|
|
@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.
|
|
|
|
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 the
|
|
@code{bookmarkfs_backend_conf} structure.
|
|
|
|
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 backend 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 is responsible for instructing the
|
|
@command{fsck.bookmarkfs} program on what to do with each invalid
|
|
bookmark name.
|
|
|
|
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 message
|
|
to standard output explaining why the bookmark name is invalid.
|
|
|
|
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
|
|
@item 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 rename for the current entry.
|
|
|
|
@item e[-] @var{new_name}
|
|
Change the proposed rename 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 Tcl-based filesystem-check handler allows fsck entries to be handled
|
|
via Tcl scripting.
|
|
|
|
Handler name: @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
|
|
@item $::bookmarkfs::fsck::result::nameBadChar
|
|
@item $::bookmarkfs::fsck::result::nameBadLen
|
|
@item $::bookmarkfs::fsck::result::nameDotDot
|
|
@item $::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 structure @code{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, the handler 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
|
|
@item BOOKMARKFS_FSCK_HANDLER_INFO_VERSION
|
|
Indicates that the backend 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
|
|
|
|
When a handler context is no longer used, the @code{destroy} function
|
|
is called.
|
|
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 the
|
|
@code{bookmarkfs_fsck_data} structure.
|
|
@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 handler 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 handler 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 General Index
|
|
@appendix General Index
|
|
|
|
@printindex cp
|
|
|
|
|
|
@node GNU Free Documentation License
|
|
@appendix GNU Free Documentation License
|
|
|
|
@include fdl.texi
|
|
|
|
|
|
@bye
|