mirror of
https://git.sr.ht/~cismonx/bookmarkfs
synced 2025-07-23 17:48:52 +00:00
552 lines
16 KiB
Text
552 lines
16 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
|
|
|
|
@c sometimes we don't want var name to be rendered UPPERCASE in Info
|
|
@macro varx {name}
|
|
@inlinefmtifelse{info, \name\, @var{\name\}}
|
|
@end macro
|
|
|
|
@tex
|
|
\global\def\linkcolor{0 0 1}
|
|
\global\def\urlcolor{0 0 1}
|
|
\global\urefurlonlylinktrue
|
|
@end tex
|
|
|
|
@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/}.
|
|
|
|
|
|
@node Porting
|
|
@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
|
|
@uref{https://docs.kernel.org/filesystems/fuse.html, FUSE} 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 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, it can only access the directory that contains the bookmark file;
|
|
it cannot establish socket connections; it cannot execute other files; @dots{}
|
|
|
|
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.
|
|
|
|
Example 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 Contributing
|
|
@section Contributing to BookmarkFS
|
|
|
|
BookmarkFS is hosted on Savannah.
|
|
Write to the
|
|
@uref{https://savannah.nongnu.org/mail/?group=bookmarkfs, mailing lists}
|
|
for bug reports, feature requests, and other discussions.
|
|
|
|
BookmarkFS is a personal hobby project, and is currently in
|
|
experimental stage.
|
|
Thus, it it not yet ready for open collaboration,
|
|
which means patches are generally rejected unless trivial (e.g. typo fix).
|
|
|
|
|
|
@node Programs
|
|
@chapter Programs
|
|
|
|
|
|
@node mount.bookmarkfs
|
|
@section @command{mount.bookmarkfs}
|
|
|
|
|
|
@node fsck.bookmarkfs
|
|
@section @command{fsck.bookmarkfs}
|
|
|
|
|
|
@node mkfs.bookmarkfs
|
|
@section @command{mkfs.bookmarkfs}
|
|
|
|
|
|
@node bookmarkctl
|
|
@section @command{bookmarkctl}
|
|
|
|
|
|
@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 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
|
|
|
|
@example
|
|
@var{$@{mountpoint@}}/bookmarks/@var{$@{bookmark_dir...@}}/@var{$@{bookmark@}}
|
|
@end example
|
|
|
|
The ``bookmarks'' subsystem maintains the hierarchical structure, names, URLs
|
|
and other information of a bookmark storage.
|
|
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 (e.g. contains
|
|
slash character; longer than @code{NAME_MAX}; @dots{}).
|
|
For a bookmark or bookmark folder with an invalid name, the corresponding file
|
|
does not exist on the filesystem.
|
|
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 @code{0} for directories.
|
|
|
|
@item st_atim
|
|
Last access time of the bookmark.
|
|
|
|
@item st_mtim
|
|
Last modification time of the bookmark.
|
|
@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
|
|
|
|
@example
|
|
@var{$@{mountpoint@}}/tags/@var{$@{tag_dir@}}/@var{$@{bookmark@}}
|
|
@end example
|
|
|
|
The ``tags'' subsystem maintains a many-to-many mapping between bookmarks and
|
|
their alternative names.
|
|
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
|
|
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
|
|
|
|
@example
|
|
@var{$@{mountpoint@}}/keywords/@var{$@{keyword_name@}}
|
|
@end example
|
|
|
|
The ``keywords'' subsystem maintains a one-to-one mapping between bookmarks
|
|
and their alternative names, independent from tag names.
|
|
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's 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 @code{user.} name prefix on Linux, and should be
|
|
accessed with @code{EXTATTR_NAMESPACE_USER} on FreeBSD.
|
|
|
|
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.
|
|
All attributes have a @code{bookmarkfs.} name prefix.
|
|
|
|
For example, to get the GUID of a bookmark file (Firefox backend):
|
|
|
|
@example
|
|
// 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
|
|
|
|
|
|
@node Directory Entry Ordering
|
|
@section Directory Entry Ordering
|
|
|
|
POSIX does not specify the ordering of the directory entries retrieved from
|
|
the directory stream using @posixfuncmanpage{readdir}.
|
|
It only guarantees that if an entry is not added or removed from the directory
|
|
after the most recent call to @posixfuncmanpage{opendir} or
|
|
@posixfuncmanpage{rewinddir}, that entry is returned once and only once.
|
|
|
|
This allows filesystem implementations to organize directory entries in a more
|
|
relaxed manner.
|
|
There could be extra overhead to maintain a predictable ordering of
|
|
directory entries, since they may not have a linear structure on modern
|
|
on-disk filesystems (e.g. ext4 uses ``HTree'' for large directories).
|
|
|
|
As for users of a filesystem, the order of directory entries generally
|
|
does not matter.
|
|
If they care, they can add a prefix to the filename, and let the application
|
|
do the sorting.
|
|
|
|
However, the order of which a bookmark entry appears in the web browser
|
|
sometimes does matter.
|
|
In BookmarkFS, 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.
|
|
|
|
|
|
@node Permute Directory Entries
|
|
@subsection Permute Directory Entries
|
|
|
|
BookmarkFS provides an I/O control for rearranging directory entries:
|
|
|
|
@example
|
|
#include <bookmarkfs/ioctl.h>
|
|
|
|
int ioctl (int @varx{dirfd}, BOOKMARKFS_IOC_PERMD,
|
|
struct bookmarkfs_permd_data const *@varx{argp});
|
|
@end example
|
|
|
|
The @code{bookmarkfs_permd_data} structure is defined as:
|
|
|
|
@example
|
|
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 @code{0}.
|
|
Otherwise, it returns @code{-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 slash character, @dots{}).
|
|
|
|
@item ENOENT
|
|
The directory does not contain @code{name1} or @code{name2}.
|
|
|
|
@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
|
|
|
|
|
|
@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{$@{short_name@}}@var{$@{shlib_suffix@}}
|
|
@end example
|
|
|
|
Where @var{$@{short_name@}} is the name passed to the frontend program, and
|
|
@var{$@{shlib_suffix@}} is the common filename extension for shared library
|
|
files on the current platform (e.g. @code{.so} on GNU/Linux and FreeBSD).
|
|
|
|
Currently, BookmarkFS ships with two backends.
|
|
One for Firefox, the other for Chromium.
|
|
If you which to add support for more backends,
|
|
you may submit a feature request or implement one using the Backend API.
|
|
|
|
|
|
@node Firefox
|
|
@section Firefox Backend
|
|
|
|
|
|
@node Chromium
|
|
@section Chromium Backend
|
|
|
|
|
|
@node Backend API
|
|
@section Backend API
|
|
|
|
|
|
@node Error Handlers
|
|
@chapter Error Handlers
|
|
|
|
|
|
@node Built-in Error Handler
|
|
@section Built-in Error Handler
|
|
|
|
|
|
@node Tcl-Based Error Handler
|
|
@section Tcl-Based Error Handler
|
|
|
|
|
|
@node Error Handler API
|
|
@section Error Handler API
|
|
|
|
|
|
@node General Index
|
|
@appendix General Index
|
|
|
|
@printindex cp
|
|
|
|
|
|
@node GNU Free Documentation License
|
|
@appendix GNU Free Documentation License
|
|
|
|
@include fdl.texi
|
|
|
|
|
|
@bye
|