bookmarkfs/doc/bookmarkfs.texi

493 lines
15 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
@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; ...
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 Utilities
@chapter Utility Programs
@node mount.bookmarkfs
@section @code{mount.bookmarkfs}
@node fsck.bookmarkfs
@section @code{fsck.bookmarkfs}
@node mkfs.bookmarkfs
@section @code{mkfs.bookmarkfs}
@node bookmarkctl
@section @code{bookmarkctl}
@node Filesystem
@chapter The Filesystem
When a BookmarkFS filesystem is mounted using the @code{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
$@{mountpoint@}/bookmarks
$@{mountpoint@}/tags
$@{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
@code{mount.bookmarkfs} program, and cannot be extended by the backend.
@node Bookmarks
@subsection Bookmarks
@example
$@{mountpoint@}/bookmarks/$@{bookmark_dir...@}/$@{bookmark_name@}
@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
@code{$@{bookmark_dir@}}, and each @code{$@{bookmark_name@}} 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{Check for Errors};
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
$@{mountpoint@}/tags/$@{tag_name@}/$@{bookmark_name@}
@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 @code{$@{tag_name@}},
and @code{$@{bookmark_name@}} 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
$@{mountpoint@}/keywords/$@{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
@code{$@{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 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 @var{dirfd}, BOOKMARKFS_IOC_PERMD,
struct bookmarkfs_permd_data const *@var{argp});
@end example
The @code{bookmarkfs_permd_data} structure is defined as:
@example
struct bookmarkfs_permd_data @{
enum bookmarkfs_permd_op @var{op};
char @var{name1}[NAME_MAX + 1];
char @var{name2}[NAME_MAX + 1];
@};
@end example
The @code{op} field denotes the operation to perform on @code{dirfd}:
@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, ...).
@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,
call @code{fsync()} or @code{close()} on @code{dirfd}.
@node Check for Errors
@section Check for Errors
@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
$@{libdir@}/bookmarkfs/backend-$@{short_name@}$@{shlib_suffix@}
@end example
Where @code{$@{short_name@}} is the name passed to the frontend program, and
@code{$@{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