     [file version.texi not included]

BookmarkFS User Manual
**********************

This manual is for BookmarkFS, version VERSION.

     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''.

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:

  * Firefox

  * Chromium

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 https://www.gnu.org/licenses/.

BookmarkFS is hosted on Savannah (https://savannah.nongnu.org/projects/bookmarkfs). Write to the mailing lists (https://savannah.nongnu.org/mail/?group=bookmarkfs) for bug reports, feature requests, and other discussions.

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 FUSE (https://docs.kernel.org/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 low-level API (https://libfuse.github.io/doxygen/fuse__lowlevel_8h.html). For a similar reason, WinFsp (https://github.com/winfsp/winfsp) won't work if you're trying to port BookmarkFS to Microsoft Windows.

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:

  * access local files other than the bookmark storage

  * establish socket connections

  * execute other files

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:

  * Bookmark files that are not created by the user using a trusted program (e.g. a file obtained from some random person on the internet).

  * 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.

On Linux, sandboxing is achieved using seccomp(2) and landlock(7). On FreeBSD, capsicum(4) is used.

Programs
********

mount.bookmarkfs
================

The mount.bookmarkfs program mounts a BookmarkFS filesystem.

     mount.bookmarkfs [OPTIONS] SRC TARGET

src
     The bookmark storage, presumably the pathname of a regular file that contains bookmark data.

     The exact interpretation of this option is backend-defined.

target
     Pathname of the directory where the filesystem shall be mounted to (i.e. the ``mountpoint'').

Files under the filesystem are assigned ownership according to the effective user ID and group ID of the calling process. On FreeBSD, you may wish to set the vfs.usermount sysctl(8) to 1 for unprivileged mounts.

To unmount a BookmarkFS filesystem, run fusermount3(1) or umount(8) on TARGET. The daemon process will automatically dismount the filesystem upon SIGINT or SIGTERM receipt, however, it only works in non-sandbox mode.

Options:

-o backend=NAME
     The backend used by the filesystem (see Backends). This option is mandatory.

-o @KEY[=VALUE]
     A backend-specific option. This option can be provided multiple times.

-o accmode=MODE
     File access mode. Defaults to 0700.

     This option applies to both directories and regular files. Execution bits on regular files are masked off.

     Should be used in combination with -o allow_other for other users to access the files.

-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:

     modification time
          ctime only updates when mtime does.

     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.

     The kernel may cache file attributes, making ctime appear more ``correct'' than what we claim. However, this behavior should not be relied upon.

-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).

-o file_max=BYTES
     Max file size limit. Defaults to 32768.

-o no_sandbox
     Do not enable sandboxing features (see Sandboxing).

-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.

-F
     Stay in the foreground, do not daemonize.

-h
     Print help text, and then exit.

-V
     Print version and feature information, and then exit.

Unrecognized options specified with -o are passed to libfuse (and subsequently to the kernel, if applicable) as-is. Notable options:

-o rw
     Mount the filesystem read/write.

          Always backup the bookmark storage before mounting it read/write, or risk losing your data!

     By default, the filesystem is mounted read-only. This behavior won't change in the future, due to the hackish nature of most BookmarkFS backends.

     When mounted read/write, other process must not write to the underlying bookmark storage, otherwise data corruption may occur.

-o debug
     Set libfuse log level to FUSE_LOG_DEBUG. Log messages related to each FUSE request will be printed to standard error.

-o fsname=NAME
     Name for the filesystem. Defaults to the backend name.

     This name is equivalent to the fs_spec field in fstab(5), and appears as the SOURCE column in findmnt(8) output.

-o atime,diratime,relatime
     These options (and other atime-related ones) are ignored.

     BookmarkFS only supports 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 can still update atime explicitly (e.g. with futimens(3p)).

fsck.bookmarkfs
===============

The fsck.bookmarkfs program checks and optionally repairs a BookmarkFS filesystem.

     fsck.bookmarkfs [OPTIONS] PATHNAME

Filesystem check on BookmarkFS has a different purpose compared to on-disk filesystems. See Filesystem Check.

Options:

-o backend=NAME
     The backend used by the filesystem (see Backends).

     If this option is not provided, or NAME is empty, performs online fsck.

     Online Mode
          In online mode, fsck is performed on a mounted BookmarkFS filesystem using ioctl() (see Online Filesystem Check).

          The PATHNAME argument refers to the directory to operate on.

     Offline Mode
          In offline mode, fsck is performed directly on the bookmark storage via the corresponding backend.

          The PATHNAME argument is the path to the bookmark storage, equivalent to the SRC argument given to mount.bookmarkfs.

          Alternatively, PATHNAME could be specified in SRC:DIR format, where DIR refers to the directory to operate on, relative to the root directory of the subsystem.

-o @KEY[=VALUE]
     A backend-specific option. This option can be provided multiple times.

-o handler=NAME
     The handler for resolving errors found during fsck (see Filesystem-Check Handlers).

     If this option is not provided, or NAME is empty, a built-in handler will be used. See Built-in Filesystem-Check Handler.

-o %KEY[=VALUE]
     A handler-specific option. This option can be provided multiple times.

-o repair
     Attempt to repair errors found during fsck.

          Always backup the bookmark storage before repairing, or risk losing your data!

-o rl_app=NAME
     Readline application name in interactive mode. Defaults to fsck.bookmarkfs.

-o type=bookmark|tag|keyword
     Subsystem type (see Hierarchy). Defaults to bookmark.

     This option is ignored when performing online fsck.

-i
     Enable interactive mode.

-R
     Perform fsck on subdirectories recursively.

     This option is ignored when performing fsck on tags or keywords.

-o no_sandbox
     Do not enable sandboxing features (see Sandboxing).

-o no_landlock
     Do not use Landlock for sandboxing. This option is ignored on non-Linux platforms.

     Also see Disabling Landlock.

-h
     Print help text, and then exit.

-V
     Print version and feature information, and then exit.

mkfs.bookmarkfs
===============

The mkfs.bookmarkfs program creates a new BookmarkFS filesystem.

     mkfs.bookmarkfs [OPTIONS] PATHNAME

pathname
     The underlying bookmark storage for the new filesystem.

     This option is equivalent to the SRC argument for mount.bookmarkfs.

Options:

-o backend=NAME
     The backend used by the filesystem (see Backends). This option is mandatory.

-o @KEY[=VALUE]
     A backend-specific option. This option can be provided multiple times.

-o force
     If the file referred to by PATHNAME already exists, overwrite it.

-h
     Print help text, and then exit.

-V
     Print version and feature information, and then exit.

bookmarkctl
===========

The bookmarkctl program is a command-line wrapper for various I/O controls of a BookmarkFS filesystem.

     bookmarkctl SUBCMD [ARGS]

Sub-commands:

permd
     Re-arranges the order of the directory entries obtained from readdir(). See Permute Directory Entries.

          bookmarkctl permd PATHNAME OP NAME1 NAME2

     pathname
          Path to the directory.

     name1

     name2
          Filename of entries under the directory.

     op
          Operation to perform on the directory:

          swap
               Exchange the positions of the directory entries represented by NAME1 and NAME2.

          move-before
               Move the directory entry represented by NAME1 to the position just before the one represented by NAME2.

          move-after
               Move the directory entry represented by NAME1 to the position just after the one represented by NAME2.

fsck
     Check for errors within a BookmarkFS filesystem. See Filesystem Check.

          bookmarkctl fsck PATHNAME OP

     pathname
          Path to the directory to perform checks on.

     op
          Operation to perform on the directory:

          list
               Display a list of errors found under the given directory. Will not recurse into subdirectories.

     For the full fsck functionalities, see fsck.bookmarkfs.

help
     Print help text, and then exit.

version
     Print version information, and then exit.

The Filesystem
**************

When a BookmarkFS filesystem is mounted using the mount.bookmarkfs program, a daemon process acts as a proxy between the kernel (which relays filesystem requests to FUSE requests) and the backend (which manipulates actual bookmark data, see Backends), thus providing POSIX (and platform-specific) filesystem API access to bookmarks.

BookmarkFS is designed in the hope that web browser bookmarks can be managed flexibly using a combination of existing software, without having to reinvent the wheel. However, like most other pseudo-filesystems, it cannot be considered fully POSIX-compliant. Users should be aware of the limitations when using BookmarkFS.

Filesystem Hierarchy
====================

BookmarkFS has multiple subsystems. Each one appears as a directory under the mountpoint:

     ${MOUNTPOINT}/bookmarks
     ${MOUNTPOINT}/tags
     ${MOUNTPOINT}/keywords

If the backend does not support a subsystem, the corresponding directory does not exist.

Currently all subsystem definitions are hard-coded within the mount.bookmarkfs program, and cannot be extended by the backend.

Bookmarks
---------

The ``bookmarks'' subsystem maintains the hierarchical structure, names, URLs and other information of a bookmark storage.

     ${MOUNTPOINT}/bookmarks/${BOOKMARK_DIR...}/${BOOKMARK}

Each bookmark folder name appears as the filename for directory ${BOOKMARK_DIR}, and each ${BOOKMARK} is a regular file that refers to a bookmark.

The name of a bookmark file is usually the ``bookmark title'', which is the name that appears in the browser's bookmark manager. The content of a bookmark file is usually the URL associated with the bookmark.

Not all bookmark names can be represented as a filename. For a bookmark or bookmark folder with an invalid name, the corresponding file does not exist on the filesystem. To deal with such bookmarks, see Filesystem Check; or you can instruct the backend to identify bookmarks using GUIDs instead of titles (and then access the titles via extended attributes).

Some file attributes are used to represent bookmark metadata:

st_ino
     ID of the bookmark (stored as lower bits).

st_size
     Length of the bookmark URL in bytes. Always 0 for directories.

st_atim
     Last access time of the bookmark.

st_mtim
     Last modification time of the bookmark. See File Modification/Change Time.

Additional information of a bookmark or bookmark folder can be accessed via the extended attributes of the corresponding file, for backends that supports it (see Extended Attributes).

Tags
----

The ``tags'' subsystem maintains a many-to-many mapping between bookmarks and their alternative names.

     ${MOUNTPOINT}/tags/${TAG_DIR}/${BOOKMARK}

Each tag name appears as the filename for directory ${TAG_DIR}, and ${BOOKMARK} is a hard link to the bookmark file. A bookmark directory cannot be associated with a tag.

If multiple bookmark files with identical names are both associated with a tag, it is unspecified which one appears as an entry for the tag directory. However, consecutive lookups and readdir()s should produce consistent results for that file, provided that it is not renamed or deleted.

Tag files behave differently from traditional hard links. If the 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 link(3p):

     fd = open("tags/gnu/readline", O_CREAT | O_WRONLY, 0600);
     // Oops, fd == -1, errno == EPERM

     fd = link("bookmarks/other/readline", "tags/gnu/readline", 0);
     // OK!

Make sure that the two files have identical names, otherwise link() fails with EPERM.

Keywords
--------

The ``keywords'' subsystem maintains a one-to-one mapping between bookmarks and their alternative names, independent from tag names.

     ${MOUNTPOINT}/keywords/${KEYWORD_NAME}

Each keyword name appears as the filename for regular file ${KEYWORD_NAME}, which is a hard link to the bookmark file. A bookmark directory cannot be associated with a keyword.

To associate a bookmark with a keyword, use link() like we do with tags. If the original file is already associated with another keyword, link() fails with EEXIST.

Error Codes
===========

When a filesystem operation fails, the kernel returns an error code for the system call. In addition to common error codes, there's few more in BookmarkFS:

EPERM
     Attempting to perform an unsupported operation. For example:

       * chmod(), chown(), and other operations that makes no sense for web browser bookmarks.

       * Moving a file across subsystems.

       * Creating a bookmark file with a name that is not valid UTF-8 (on Chromium backend).

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.

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.

Other BookmarkFS-specific errors may occur. See the corresponding manual section for details.

Extended Attributes
===================

BookmarkFS uses extended attributes to manage additional information associated with a bookmark.

Extended attributes is a platform-specific feature. On Linux, see xattr(7). On FreeBSD, see extattr(2).

All BookmarkFS extended attributes fall under the ``user'' namespace, which means they have a user. name prefix on Linux, and should be accessed with EXTATTR_NAMESPACE_USER on FreeBSD. All attributes have a bookmarkfs. name prefix.

For example, to get the GUID of a bookmark file (Firefox backend):

     // Linux
     len = fgetxattr(fd, "user.bookmarkfs.guid", buf, sizeof(buf));

     // FreeBSD
     len = extattr_get_fd(fd, EXTATTR_NAMESPACE_USER, "bookmarkfs.guid",
             buf, sizeof(buf));

BookmarkFS does not define any common attributes, neither can users create arbitrary ones. The backend decides which attributes are available during initialization, and all bookmark files share the same set of attributes.

Directory Entry Ordering
========================

POSIX does not specify the ordering of the directory entries retrieved from the directory stream using readdir(3p). It only guarantees that if an entry is not added or removed from the directory after the most recent call to opendir(3p) or rewinddir(3p), that entry is returned once and only once.

This allows filesystem implementations to organize directory entries in a more relaxed manner. There could be extra overhead to maintain a predictable ordering of directory entries, since they may not have a linear structure on modern on-disk filesystems (e.g. ext4 uses htree (https://docs.kernel.org/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.

Permute Directory Entries
-------------------------

BookmarkFS provides an I/O control for rearranging directory entries:

     #include <bookmarkfs/ioctl.h>

     int ioctl (int dirfd, BOOKMARKFS_IOC_PERMD,
             struct bookmarkfs_permd_data const *argp);

The bookmarkfs_permd_data structure is defined as:

     struct bookmarkfs_permd_data {
         enum bookmarkfs_permd_op op;

         char name1[NAME_MAX + 1];
         char name2[NAME_MAX + 1];
     };

The op field denotes the operation to perform on the directory:

BOOKMARKFS_PERMD_OP_SWAP
     Exchange the positions of the directory entries represented by name1 and name2.

BOOKMARKFS_PERMD_OP_MOVE_BEFORE
     Move the directory entry represented by name1 to the position just before the one represented by name2.

BOOKMARKFS_PERMD_OP_MOVE_AFTER
     Move the directory entry represented by name1 to the position just after the one represented by name2.

On success, ioctl() returns 0. Otherwise, it returns -1 and sets errno:

EACCES
     Write or search permission is denied for the directory.

EINVAL
     op is not one of the values defined in enum bookmarkfs_permd_op.

EINVAL
     name1 or name2 is not a valid filename (e.g. empty string; contains / character).

ENOENT
     The directory does not contain entries named name1 or name2.

EPERM
     The backend does not support rearranging entries for this directory.

To ensure that the order change is visible to further readdir() calls, fsync() or close() the directory.

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:

  * must not contain / characters

  * must not be empty or longer than NAME_MAX

  * must not duplicate with another file in the same directory

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.

Online Filesystem Check
-----------------------

To perform filesystem check on a mounted BookmarkFS filesystem, use the following I/O controls:

     #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);

The bookmarkfs_fsck_data structure is defined as:

     struct bookmarkfs_fsck_data {
         uint64_t id;
         uint64_t extra;
         char     name[NAME_MAX + 1];
     };

Filesystem-check commands:

BOOKMARKFS_IOC_FSCK_NEXT

     Find the next bookmark with invalid name under the directory.

     On success, ioctl() updates ARGP, and returns one of the values defined in enum bookmarkfs_fsck_result:

     BOOKMARKFS_FSCK_RESULT_END
          There are no more bookmarks with invalid name under the directory.

          Fields in ARGP have unspecified values.

     BOOKMARKFS_FSCK_RESULT_NAME_DUPLICATE
          The bookmark name duplicates with another bookmark which appears earlier in the directory stream.

          Value of extra is the ID of the other bookmark.

     BOOKMARKFS_FSCK_RESULT_NAME_BADCHAR
          The bookmark contains a bad character (i.e. the ASCII / character).

          Value of extra is the byte offset where the bad character first appears in name.

     BOOKMARKFS_FSCK_RESULT_NAME_BADLEN
          The bookmark name is either longer than NAME_MAX, or an empty string.

          Value of extra is the length of the bookmark name, and name is truncated if longer than NAME_MAX.

     BOOKMARKFS_FSCK_RESULT_NAME_DOTDOT
          The bookmark name is either . or ...

          Value of extra is unspecified.

     On failure, ioctl() returns -1, and sets errno:

     EACCES
          Read permission is denied for the directory.

     EPERM
          The backend does not support fsck for this directory.

BOOKMARKFS_IOC_FSCK_APPLY

     ``Repair'' a bookmark by renaming it.

     The id field must be set to a value previously obtained from BOOKMARKFS_IOC_FSCK_NEXT on the directory, otherwise the behavior is undefined.

     The name field should be set to the new name for the bookmark. The extra field is unused.

     On success, ioctl() updates ARGP, and returns one of the values defined in enum bookmarkfs_fsck_result, like with BOOKMARKFS_IOC_FSCK_NEXT. Additionally, it may also return:

     BOOKMARKFS_FSCK_RESULT_NAME_INVALID
          The new name is not a valid bookmark name.

          Value of extra is a backend-specific reason code explaining why the bookmark name is invalid. It may equal to one of the following predefined values:

          BOOKMARKFS_NAME_INVALID_REASON_NOTUTF8
               The name is not valid UTF-8.

     On failure, ioctl() returns -1, and sets errno:

     EACCES
          Write or search permission is denied for the directory.

     To ensure that the rename is visible to further lookups and readdir() calls, fsync() or close() the directory.

BOOKMARKFS_IOC_FSCK_REWIND
     Reset the fsck state for the directory.

     Further BOOKMARKFS_IOC_FSCK_NEXT requests will start from the beginning of the directory stream.

     On success, ioctl() returns 0. Otherwise, it returns -1, and sets errno.

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:

     ${PKGLIBDIR}/backend-${NAME}${SHLIB_SUFFIX}

Where ${NAME} is the backend name, equivalent to value given to the -o backend=NAME option of frontend programs, and ${SHLIB_SUFFIX} is the common filename extension for shared library files on the current platform (e.g. .so on GNU/Linux and FreeBSD).

Firefox Backend
===============

The Firefox backend provides access to the bookmark data of the web browser Mozilla Firefox (https://www.mozilla.org/en-US/firefox/new/) and its derivatives, notably Tor Browser (https://www.torproject.org/) and Librewolf (https://librewolf.net/).

Firefox bookmarks are stored in a SQLite database under the profile directory:

     ~/.mozilla/firefox/${PROFILE_NAME}/places.sqlite

When mounting the filesystem, this pathname shall be passed as the SRC argument (see mount.bookmarkfs). Actual path for the profile directories may differ across distributions.

Backend name: firefox.

Backend-specific options (mount.bookmarkfs only):

filename=title|guid
     Whether to use the bookmark title or GUID as the bookmark file name. Defaults to title.

     A bookmark GUID is a base64url-encoded (https://datatracker.ietf.org/doc/html/rfc4648#section-5) 128-bit string uniquely associated with a bookmark or bookmark folder.

     When creating a new file:

     title
          The GUID is randomly generated by the backend.

     guid
          The filename must be a valid GUID, and must not duplicate with other files on the same filesystem, otherwise open() or mkdir() fails with EPERM.

          Also set the GUID string as the bookmark title.

     With filename=title, the GUID is available as an extended attribute (see Extended Attributes), and vise versa.

lock=exclusive|normal
     The database connection locking mode for the bookmark storage. Defaults to normal when the filesystem is mounted read-only, exclusive otherwise.

     This option corresponds to the locking_mode (https://www.sqlite.org/pragma.html#pragma_locking_mode) pragma on SQLite. With 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 storage.sqlite.exclusiveLock.enabled browser preference to false.

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 filename=guid.

     This option may improve readdir() performance, however, making a false assumption results in a directory entry with duplicate names. It is recommended to perform a full filesystem check (see Filesystem Check) on the bookmark storage before mounting with this option.

If launched from fsck.bookmarkfs, all backend-specific options are ignored, and always enforces the lock=exclusive option.

Backend-specific options (mkfs.bookmarkfs only):

date_added=TIMESTAMP
     File creation time for the bookmark root directories. Defaults to the current time.

     Value of TIMESTAMP must be a decimal representing number of microseconds since the Unix epoch.

Chromium Backend
================

The Chromium backend provides access to the bookmark data of the web browser Chromium (https://www.chromium.org/Home/) and its derivatives, notably ungoogled-chromium (https://github.com/ungoogled-software/ungoogled-chromium).

Chromium bookmarks are stored in a text file (in JSON format) under the profile directory:

     ~/.config/chromium/${PROFILE_NAME}/Bookmarks

When mounting the filesystem, this pathname shall be passed as the SRC argument (see mount.bookmarkfs). Actual path for the profile directories may differ across distributions.

Backend name: chromium.

Backend-specific options (mount.bookmarkfs only):

filename=title|guid
     Whether to use the bookmark title or GUID as the bookmark file name. Defaults to title.

     A bookmark GUID is a hex-encoded 128-bit string uniquely associated with a bookmark or bookmark folder. The GUID string has a ``8-4-4-4-12'' format, while all alphabetic characters are in lowercase. For example:

          0bc5d13f-2cba-5d74-951f-3f233fe6c908

     When creating a new file:

     title
          The GUID is randomly generated by the backend. It is guaranteed to be a valid version 4 UUID as specified by RFC 4122 (https://datatracker.ietf.org/doc/html/rfc4122).

     guid
          The filename must be a valid GUID, and must not duplicate with other files on the same filesystem, otherwise open() or mkdir() fails with EPERM.

          Also set the GUID string as the bookmark title.

     With filename=title, the GUID is available as an extended attribute (see Extended Attributes), and vise versa.

watcher=native|fallback|none
     The file watcher to use for the bookmark storage. Defaults to native when the filesystem is mounted read-only, none otherwise.

     native
          Watch for file changes using platform-specific features:

          Linux
               fanotify(7) is used. Requires kernel version 5.13 or later for unprivileged users.

               inotify(7) does not have this limitation, however, it is incompatible with our sandboxing design.

          FreeBSD
               kevent(2) with EVFILT_VNODE is used.

     fallback
          Watch for file changes by checking st_ino and st_mtim attributes with fstatat() periodically.

          Less efficient than ``native'' implementations, but should work on any POSIX-compatible system.

     none
          Do not watch for file changes.

          With watcher=none, changes on the bookmark storage are not visible to the filesystem.

If launched from fsck.bookmarkfs, all backend-specific options are ignored, and always enforces the watcher=none option.

Backend-specific options (mkfs.bookmarkfs only):

date_added=TIMESTAMP
     File creation time for the bookmark root directories. Defaults to the current time.

     Value of TIMESTAMP must be a decimal representing number of microseconds since the Windows FILETIME epoch (134774 days ahead of the Unix epoch).

The Chromium backend does not scale well with large bookmark storage, since it keeps everything in memory, and has to parse the entire JSON file whenever a reload is required.

Another limitation is the lack of tags (see Tags) and keywords (see Keywords) support. Chromium does not have such concepts.

Backend API
===========

Filesystem-Check Handlers
*************************

The filesystem-check handler is responsible for instructing the 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:

     ${PKGLIBDIR}/fsck-handler-${NAME}${SHLIB_SUFFIX}

Where ${NAME} is the handler name, equivalent to the value given to the -o handler=NAME option of fsck.bookmarkfs, and ${SHLIB_SUFFIX} is the common filename extension for shared library files on the current platform (e.g. .so on GNU/Linux and FreeBSD).

Built-in Handler
================

The built-in handler is linked into the fsck.bookmarkfs program. It has minimal functionalities, but is capable enough to handle most common fsck scenarios.

Handler-specific options:

prompt=STR
     Readline prompt string. Defaults to % .

     This option is ignored in non-interactive mode.

translit=CHAR
     Transliterate bad characters into CHAR. Defaults to _.

For each bookmark entry, the built-in handler prints a message to standard output explaining why the bookmark name is invalid.

When the -o repair option is given, the handler renames the bookmark according to the following rules:

BOOKMARKFS_FSCK_RESULT_NAME_DUPLICATE
     Append a _${COUNTER} suffix to the name, where ${COUNTER} is a self-incrementing 32-bit integer in decimal format.

     If appending the suffix would exceed max name length, truncate the name first.

BOOKMARKFS_FSCK_RESULT_NAME_BADCHAR
     Transliterate the bad character into another character.

BOOKMARKFS_FSCK_RESULT_NAME_BADLEN
     If the name is too long, truncate it to NAME_MAX bytes.

     If the name is empty, see below:

BOOKMARKFS_FSCK_RESULT_NAME_DOTDOT

BOOKMARKFS_FSCK_RESULT_NAME_INVALID
     Rename to fsck-${ID}, where ${ID} is the bookmark ID in decimal format.

In interactive mode, the handler prompts the user before applying the rename. The user may issue a command to indicate what to do with each entry:

p
     Print the ID and new name of current entry.

a[-]
     Apply the proposed rename for the current entry.

e[-] NEW_NAME
     Change the proposed rename to NEW_NAME and then apply.

c
     Continue to the next entry.

s[-]
     Skip current directory.

S[-]
     Skip current directory and all subdirectories.

r[-]
     Rewind current directory.

R[-]
     Rewind all.

w[-]
     Save applied changes.

q
     Save applied changes and quit.

The optional - suffix inhibits the default behavior of continuing to the next entry, after the command completes successfully.

Tcl-Based Handler
=================

Handler API
===========

GNU Free Documentation License
******************************

     [file fdl.texi not included]