fuse
1 Creating a filesystem
mount-filesystem
make-filesystem
2 Operations
init
destroy
lookup
forget
getattr
setattr
readlink
mknod
mkdir
unlink
rmdir
symlink
rename
link
access
open
create
read
write
flush
release
fsyncdir
statfs
setxattr
getxattr
listxattr
removexattr
getlk
setlk
bmap
fallocate
3 Responses
reply-error/  c
reply-empty/  c
reply-entry/  c
reply-attr/  c
reply-data/  c
reply-open/  c
reply-create/  c
reply-write/  c
reply-statfs/  c
reply-listxattr/  c
reply-lock/  c
reply-bmap/  c
4 Miscellaneous
timespec
request-pid
request-uid
request-gid
uint32?
uint64?
errno?
modes/  c
perms/  c
filetype?
oflags/  c
xattr-op?
lock-types/  c
fallocate-mode?
5 Example
6.12

fuse

Scott Moore

 (require fuse) package: fuse

A Racket library for implementing Filesystems in Userspace (FUSE).

This package implements communication routines for interfacing with the Linux FUSE kernel driver. Client programs can implement a userspace filesystem by providing a collection of functions that implement filesystem operations. Currently, racket-fuse depends on the libfuse C library to mount a FUSE filesystem. However, the communication protocol with the kernel and filesystem API does not reuse libfuse functionality, and this dependency will be removed in a future release.

See Example for an example FUSE filesystem.

1 Creating a filesystem

To mount a userspace filesystem, call mount-filesystem with a filesystem struct created by make-filesystem. The mount-filesystem procedure will not return until the filesystem is umounted.

To umount a userspace filesystem, invoke the program fusermount: fusermount -u /path/to/filesystem/mount. In exceptional circumstances (i.e., when using a buggy userspace filesystem), you may need to force the filesystem to unmount using the umount utility.

procedure

(mount-filesystem filesystem path options)  void

  filesystem : filesystem?
  path : path?
  options : (listof string?)
Mounts the userspace filesystem filesystem at path with FUSE options options. Does not return until the filesystem is unmounted. See fuse(8) for a list of permitted options.

procedure

(make-filesystem operation ...)

 
operation = #:init init
  | #:destroy destroy
  | #:lookup lookup
  | #:forget forget
  | #:getattr getattr
  | #:setattr setattr
  | #:readlink readlink
  | #:mknod mknod
  | #:mkdir mkdir
  | #:unlink unlink
  | #:rmdir rmdir
  | #:symlink symlink
  | #:rename rename
  | #:link link
  | #:access access
  | #:open open
  | #:create create
  | #:read read
  | #:write write
  | #:flush flush
  | #:release release
  | #:fsync fsync
  | #:opendir opendir
  | #:readdir readdir
  | #:releasedir releasedir
  | #:fsyncdir fsyncdir
  | #:statfs statfs
  | #:setxattr setxattr
  | #:getxattr getxattr
  | #:listxattr listxattr
  | #:removexattr removexattr
  | #:getlk getlk
  | #:setlk setlk
  | #:bmap bmap
  | #:fallocate fallocate
Creates a filesystem? struct for use with mount-filesystem. Each operation specifies a procedure that will be invoked when the corresponding filesystem operation is requested by the operating system. The default implementation of each operation does nothing and replies with the error 'ENOSYS. The specification for the procedure required for each operation is given below. Most hooks provide two response procedures: one marked #:reply to indicate success, and one marked #:error to indicate failure. The response specifications are given below, following descriptions of each operation. A filesystem can defer responding to an operation by spawning a thread which will call a response procedure when the operation completes. Each operation should respond only once by calling the appropriate procedure.

Filesystem procedures can access information about the process making a request using the parameters request-pid, request-uid, request-gid.

2 Operations

The following documentation was adapted from the reference low level FUSE API, available at https://github.com/libfuse/libfuse/blob/master/include/fuse_lowlevel.h.

procedure

(init)  (or/c #t errno?)

Called before any other filesystem operation. Use this to initialize any state required by the filesystem. Return true on success or an errno symbol on error.

procedure

(destroy)  void

Called on filesystem exit.

procedure

(lookup #:nodeid nodeid    
  #:name name    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  name : path-element?
  reply : reply-entry/c
  error : reply-error/c
Lookup the entry name in the directory with inode nodeid, returning its attributes.

procedure

(forget #:nodeid nodeid #:nlookup nlookup)  void

  nodeid : uint64?
  nlookup : uint64?
Each invocation of a reply-entry reply-create response increments the lookup count for the corresponding inode by one. Each time a reference to the inode is removed from the kernel’s cache, the lookup count is decremented. Subsequently, forget on the FUSE filesystem is invoked with nlookup set to the number of lookups to forget.

While an inode has a non-zero lookup count, the filesystem may receive requests to access the node (even following calls to unlink, rmdir, etc.). A filesystem should retain the underlying resources associated with the inode until the lookup count is zero (because a sufficient number of forget messages have been received).

If a file has been exported over NFS, the resources should be retained even longer. See the libfuse documentation for more details.

Operation forget may not be invoked on all active indoes when the filesystem is unmounted.

procedure

(getattr #:nodeid nodeid    
  #:info info    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  info : (maybe/c uint64?)
  reply : reply-attr/c
  error : reply-error/c
Get the file attributes of nodeid. The info argument may in future contain information provided by the filesystem when opening the node, but currently is always #f.

procedure

(setattr #:nodeid nodeid    
  #:info info    
  #:mode mode    
  #:uid uid    
  #:gid gid    
  #:size size    
  #:atime atime    
  #:mtime mtime    
  #:ctime ctime    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  info : uint64?
  mode : (maybe/c perms/c)
  uid : (maybe/c uint32?)
  gid : (maybe/c uint32?)
  size : (maybe/c uint64?)
  atime : (maybe/c timespec?)
  mtime : (maybe/c timespec?)
  ctime : (maybe/c timespec?)
  reply : reply-attr/c
  error : reply-error/c
Set the file attributes of nodeid. Each argument is either #f if the corresponding attribute should not be modified, or contains the new value for that attribute. If setattr was invoked by the ftruncate() system call (and the kernel is version 2.6.15 or later), info will contain the value set by the filesystem’s open procedure. Otherwise, it will be set to 0.

On success, the filesystem should respond with the updated file attributes.

procedure

(readlink #:nodeid nodeid    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  reply : reply-data/c
  error : reply-error/c
Read the symbolic link at inode nodeid.

procedure

(mknod #:nodeid nodeid    
  #:name path    
  #:kind kind    
  #:mode mode    
  #:umask umask    
  #:rdev rdev    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  path : path?
  kind : filetype?
  mode : perms/c
  umask : perms/c
  rdev : uint32?
  reply : reply-entry/c
  error : reply-error/c
Create a regular file, character device, fifo, or socket in the directory nodeid with name name. The desired filetype is given by kind along with the desired mode and current umask. If the filetype is a device type, the desired device number is given by rdev.

procedure

(mkdir #:nodeid nodeid    
  #:name name    
  #:mode mode    
  #:umask umask    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  name : path-element?
  mode : perms/c
  umask : perms/c
  reply : reply-entry/c
  error : reply-error/c
Create a directory with name name in directory nodeid. The requested file mode and current process umask are given by mode and umask.

procedure

(unlink #:nodeid nodeid    
  #:name name    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  name : path-element?
  reply : reply-empty/c
  error : reply-error/c
Remove the file with name name from directory nodeid. If the file’s lookup count is non-zero, the file system should retain any resources required to respond to operations on the file until the lookup count reaches zero. (See forget).

procedure

(rmdir #:nodeid nodeid    
  #:name name    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  name : path-element?
  reply : reply-empty/c
  error : reply-error/c
Remove the directory with the name name from directory nodeid. If the directory’s lookup count is non-zero, the file system should retain any resources required to respond to operations on the directory until the lookup count reaches zero. (See forget).

procedure

(symlink #:nodeid nodeid    
  #:name name    
  #:link link    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  name : path-element?
  link : path?
  reply : reply-entry/c
  error : reply-error/c
Create a symbolic link in directory nodeid with name name and content link.

procedure

(rename #:nodeid nodeid    
  #:name name    
  #:newnodeid newparent    
  #:newname newname    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  name : path-element?
  newparent : uint64?
  newname : path-element?
  reply : reply-empty/c
  error : reply-error/c
Move the directory entry name in nodeid to newname in newparent. If an entry newname in newparent already exists, it should be atomically replaced. If the replaced entry’s lookup count is non-zero, the file system should retain any resources required to respond to operations on the entry until the lookup count reaches zero. (See forget).

procedure

(link #:nodeid nodeid    
  #:newparent newparent    
  #:newname newname    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  newparent : uint64?
  newname : path-element?
  reply : reply-entry/c
  error : reply-error/c
Create a hard link to nodeid in the directory newparent with name newname.

procedure

(access #:nodeid nodeid    
  #:mask mask    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  mask : perms/c
  reply : reply-empty/c
  error : reply-error/c
Check file access permissions. If the ’default_permissions’ mount option is given, this method is not called. (See the libfuse documentation for important security information related to FUSE file access permissions).

procedure

(open #:nodeid nodeid    
  #:flags flags    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  flags : oflags/c
  reply : reply-open/c
  error : reply-error/c
Open the file at inode nodeid. Argument flags records the open flags passed to the originating system call, except for 'O_CREAT, O_EXCL, O_NOCTTY, and O_TRUNC, which are handled by FUSE by invoking create instead of open. When responding to an open operation, the filesystem can specify a value that will be passed to the filesystem as the #:info associated with an operation on the opened file.

procedure

(create #:nodeid nodeid    
  #:name name    
  #:mode mode    
  #:umask umask    
  #:flags flags    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  name : path-element?
  mode : perms/c
  umask : perms/c
  flags : oflags/c
  reply : reply-create/c
  error : reply-error/c
Create and open a file in the directory nodeid with name name. Argument flags lists the flags passed to the originating open system call. When responding to an create operation, the filesystem can specify a value that will be passed to the filesystem as the #:info associated with an operation on the created file.

procedure

(read #:nodeid nodeid    
  #:info info    
  #:offset offset    
  #:size size    
  #:lockowner owner    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  info : uint64?
  offset : uint64?
  size : uint32?
  owner : (or/c #f uint64?)
  reply : reply-data/c
  error : reply-error/c
Read size bytes from the file at offset offset. Read should respond with exactly the number of bytes requested (except on EOF or error), unless the 'FOPEN_DIRECT_IO flag was included in the response when opening the file or the filesystem was mounted using the option "direct_io". If direct IO is being used, the system call result for read will reflect the number of bytes returned by the filesystem’s response.

procedure

(write #:nodeid nodeid    
  #:info info    
  #:offset offset    
  #:data data    
  #:lockowner owner    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  info : uint64?
  offset : uint64?
  data : bytes?
  owner : (or/c #f uint64?)
  reply : reply-write/c
  error : reply-error/c
Unless the file was opened with the 'FOPEN_DIRECT_IO flag or the filesystem was mounted with the option "direct_io", write the entire request data to the file at offset offset. If direct_io is being used, the operation may write fewer bytes and return the number of bytes written.

procedure

(flush #:nodeid nodeid    
  #:info info    
  #:lockowner owner    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  info : uint64?
  owner : uint64?
  reply : reply-empty/c
  error : reply-error/c
Called whenever the close system call is invoked on a file. May be invoked zero or multiple times per open call depending on whether the file is closed and if the file descriptor of an open file has been duplicated.

If the filesystem supports locking, it should remove all locks belonging to owner.

procedure

(release #:nodeid nodeid    
  #:info info    
  #:lockowner owner    
  #:flush flush    
  #:unlock unlock    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  info : uint64?
  owner : uint64?
  flush : boolean?
  unlock : boolean?
  reply : reply-empty/c
  error : reply-error/c
Invoked when there are no outstanding file descriptors or memory mappings for a file. Will be called exactly once per open call.

procedure

(fsyncdir #:nodeid nodeid    
  #:info info    
  #:syncdataonly syncdata    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  info : uint64?
  syncdata : boolean?
  reply : reply-empty/c
  error : reply-error/c
Synchronize the contents of directory nodeid. If syncdata is #t, synchronize only the contents of the directory, and not meta data.

procedure

(statfs #:nodeid nodeid    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  reply : reply-statfs/c
  error : reply-error/c
Return filesystem statistics for the filesystem containing nodeid.

procedure

(setxattr #:nodeid nodeid    
  #:name name    
  #:value value    
  #:op op    
  #:size size    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  name : bytes?
  value : bytes?
  op : xattr-op?
  size : uint64?
  reply : reply-empty/c
  error : reply-error/c
Set the extended attribute name on file nodeid to value. Argument op is one of 'XATTR_DEFAULT, 'XATTR_CREATE, or 'XATTR_REPLACE. If op is 'XATTR_DEFAULT, the extended attribute should be created if it does not exist or, if it exists the value should be replaced. If op is 'XATTR_CREATE, the extended attribute should be created if it does not exist, otherwise the operation should fail. If op is 'XATTR_REPLACE, the operation should fail if the extended attribute does not exists, otherwise it should replce the current value.

procedure

(getxattr #:nodeid nodeid    
  #:name name    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  name : bytes?
  reply : reply-data/c
  error : reply-error/c
Retreive the extended attribute with name name for file nodeid.

procedure

(listxattr #:nodeid nodeid    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  reply : reply-listxattr/c
  error : reply-error/c
Retreive the names of all currently set extended attributes for nodeid.

procedure

(removexattr #:nodeid nodeid    
  #:name name    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  name : bytes?
  reply : reply-empty/c
  error : reply-error/c
Remove the extended attribute name for file nodeid.

procedure

(getlk #:nodeid nodeid    
  #:info info    
  #:owner owner    
  #:start start    
  #:end end    
  #:type type    
  #:pid pid    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  info : uint64?
  owner : uint64?
  start : uint64?
  end : uint64?
  type : lock-types/c
  pid : uint64?
  reply : reply-lock/c
  error : reply-error/c
Test for the existence of a POSIX lock on nodeid. According to libfuse, if getlk and setlk are not implemented, the kernel will implement file locking automatically, so these operations are only required in special cases (for example, to enable network filesystems to correctly implement distributed locking).

procedure

(setlk #:nodeid nodeid    
  #:info info    
  #:owner owner    
  #:start start    
  #:end end    
  #:type type    
  #:sleep sleep    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  info : uint64?
  owner : uint64?
  start : uint64?
  end : uint64?
  type : lock-types/c
  sleep : boolean?
  reply : reply-empty/c
  error : reply-error/c
Acquire, modify, or release a POSIX lock on nodeid. According to libfuse, if getlk and setlk are not implemented, the kernel will implement file locking automatically, so these operations are only required in special cases (for example, to enable network filesystems to correctly implement distributed locking).

procedure

(bmap #:nodeid nodeid    
  #:blocksize blocksize    
  #:index index    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  blocksize : uint32?
  index : uint64?
  reply : reply-bmap/c
  error : reply-error/c
Return the device block index for the block with index index of file nodeid. Only useful for block-device backed filesystems using where the filesystem was mounted with the "blkdev" FUSE option.

procedure

(fallocate #:nodeid nodeid    
  #:info info    
  #:mode mode    
  #:offset offset    
  #:length length    
  #:reply reply    
  #:error error)  void
  nodeid : uint64?
  info : uint64?
  mode : fallocate-mode?
  offset : uint64?
  length : uint64?
  reply : reply-empty/c
  error : reply-error/c
Allocate the requested space within file nodeid. Argument mode describes the particular fallocate operation requested. See fallocate(2) for more details.

3 Responses

value

reply-error/c : contract?

 = 
(use-once/c (-> errno?
                void))
Respond to an operation with an error.

value

reply-empty/c : contract? = (use-once/c (-> void))

Indicates that an operation succeeded without providing any additional information.

value

reply-entry/c : contract?

 = 
(use-once/c (-> #:generation uint64?
                #:entry-valid timespec?
                #:attr-valid timespec?
                #:inode uint64?
                #:rdev uint32?
                #:size uint64?
                #:blocks uint64?
                #:atime timespec?
                #:mtime timespec?
                #:ctime timespec?
                #:kind filetype?
                #:perm perms/c
                #:nlink uint32?
                #:uid uint32?
                #:gid uint32?
                void))
Respond to an operation with information about a filesystem entry. If the file system is exported as a network file system, #:generation and #:inode pairs must be unique over the lifetime of the filesystem. #:entry-valid and #:attr-valid indicate how long the kernel may cache the entry and attribute information for the inode. #:rdev is the device number of the device containing the inode. #:atime, #:mtime, and #:ctime are the last access, last modification, and creation times of the entry. #:kind indicates the type of filesystem object represented by the entry. #:perm, #:uid, and #:gid are the is UNIX file mode, owner, and group of the entry. #:nlink reports the number of links to the entry in the filesystem.

value

reply-attr/c : contract?

 = 
(use-once/c (-> #:attr-valid timespec?
                #:inode uint64?
                #:rdev uint32?
                #:size uint64?
                #:blocks uint64?
                #:atime timespec?
                #:mtime timespec?
                #:ctime timespec?
                #:kind filetype?
                #:perm perms/c
                #:nlink uint32?
                #:uid uint32?
                #:gid uint32?
                void))
Respond to an operation with a file’s attributes. #:attr-valid indicates how long the kernel may cache the attribute information for the inode. Argument #:rdev is the device number of the device containing the inode. Arguments #:atime, #:mtime, and #:ctime are the last access, last modification, and creation times of the entry. #:kind indicates the type of filesystem object represented by the entry. Arguments #:perm, #:uid, and #:gid are the is UNIX file mode, owner, and group of the entry. Argument #:nlink reports the number of links to the entry in the filesystem.

value

reply-data/c : contract?

 = 
(use-once/c (-> bytes?
                void))
Respond to an operation with a byte array.

value

reply-open/c : contract?

 = 
(use-once/c (-> #:info any/c
                #:flags open-out-flags/c
                void))
Respond to an open operation with a user defined value #:info and flags configuring future operations on the file.

value

reply-create/c : contract?

 = 
(use-once/c (-> #:generation uint64?
                #:entry-valid timespec?
                #:attr-valid timespec?
                #:inode uint64?
                #:rdev uint32?
                #:size uint64?
                #:blocks uint64?
                #:atime timespec?
                #:mtime timespec?
                #:ctime timespec?
                #:kind filetype?
                #:perm perms/c
                #:nlink uint32?
                #:uid uint32?
                #:gid uint32?
                #:info uint64?
                #:flags open-out-flags/c
                void))
Respond to a create operation with a user defined value #:info and flags configuring future operations on the file. In addition, provide information about the newly created entry and its attributes (see reply-entry/c for details).

value

reply-write/c : contract?

 = 
(use-once/c (-> #:written uint32?
                void))
Respond to a write operation with the number of bytes written.

value

reply-statfs/c : contract?

 = 
(use-once/c (-> #:blocks uint64?
                #:bfree uint64?
                #:bavail uint64?
                #:files uint64?
                #:ffree uint64?
                #:bsize uint32?
                #:namlen uint32?
                #:frsize uint32?
                void))
Respond to a statfs operation with information about a filesystem.

value

reply-listxattr/c : contract?

 = 
(use-once/c (-> (listof bytes?)
                void))
Respond to a listxattr operation with the list of names of currently set extended attributes.

value

reply-lock/c : contract?

 = 
(use-once/c (-> #:type lock-types/c
                #:whence lock-whence?
                #:start uint64?
                #:length uint64?
                #:pid uint64?
                void))
Respond to a lock operation with information about a POSIX lock.

value

reply-bmap/c : contract?

 = 
(use-once/c (-> #:index uint64?
                void))
Respond to a bmap operation with the device block index of a block within a file.

4 Miscellaneous

struct

(struct timespec (sec nsec))

  sec : (exact-positive-integer?)
  nsec : (exact-positive-integer?)
A time expressed as seconds (and nanoseconds) the since POSIX epoch, 1970-01-01 00:00:00 +0000 (UTC).

parameter

(request-pid)  uint64?

(request-pid pid)  void?
  pid : uint64?
 = #f
The process id of the process that triggered the current filesystem operation.

parameter

(request-uid)  uint64?

(request-uid uid)  void?
  uid : uint64?
 = #f
The effective user id of the process that triggered the current filesystem operation.

parameter

(request-gid)  uint64?

(request-gid gid)  void?
  gid : uint64?
 = #f
The effective group id of the process that triggered the current filesystem operation.

A flat-contract that requires the input to be an exact-positive-integer? that can be represented by a 32-bit unsigned integer.

A flat-contract that requires the input to be an exact-positive-integer? that can be represented by a 64-bit unsigned integer.

procedure

(errno? v)  boolean?

  v : any/c
Checks if v is either a member of '(ELIBMAX EISDIR ENOTTY EPIPE ECONNREFUSED ENOSYS ELIBEXEC EREMCHG ENODEV ECONNABORTED EMSGSIZE ELIBBAD EADV EFAULT EEXIST ENOMSG EUSERS ETIMEDOUT EPERM ENETRESET ENOLINK ENOSR ENOTDIR EISNAM ESRCH ESPIPE EAFNOSUPPORT ECHILD ELNRNG ENOTSOCK EPROTONOSUPPORT ENXIO EHOSTUNREACH EBADF EBADSLT EBADR ELIBSCN EUCLEAN EUNATCH ERANGE ENOBUFS ENOANO EPROTO ESTRPIPE EAGAIN EMEDIUMTYPE ENAMETOOLONG ENOPKG EBUSY EINPROGRESS ENOTUNIQ EXDEV ESHUTDOWN ERFKILL ENOTCONN EADDRNOTAVAIL ENOTSUP EINTR EKEYREVOKED ENOSTR ETIME EREMOTEIO EL3HLT EBADMSG ETXTBSY EDESTADDRREQ ELIBACC ECHRNG E2BIG ENOTBLK ECANCELED ECOMM EREMOTE EKEYEXPIRED EOVERFLOW ERESTART EHWPOISON EBFONT ENOTNAM EL2NSYNC EL2HLT ENOTRECOVERABLE ECONNRESET EIO ETOOMANYREFS EBADFD EXFULL ENOLCK EIDRM ENODATA EALREADY ENFILE EDOTDOT ENONET EPFNOSUPPORT EISCONN EADDRINUSE EMULTIHOP EMFILE EFBIG EROFS EBADRQC ESTALE ENOCSI EPROTOTYPE EMLINK EBADE EINVAL ENAVAIL ESRMNT EILSEQ ENOENT ENOMEDIUM ENOTEMPTY EKEYREJECTED ENOPROTOOPT ENOMEM ENOEXEC EHOSTDOWN EOWNERDEAD ENETDOWN EACCES EDEADLOCK ENETUNREACH ESOCKTNOSUPPORT EDQUOT EDOM ENOKEY ENOSPC ELOOP EL3RST).

procedure

(modes/c v)  boolean?

  v : any/c
Checks if v is either a member of or a sublist of '(S_IFSOCK S_IFLNK S_IFREG S_IFBLK S_IFDIR S_IFCHR S_IFIFO S_ISUID S_ISGID S_ISVTX S_IRUSR S_IWUSR S_IXUSR S_IRGRP S_IWGRP S_IXGRP S_IROTH S_IWOTH S_IXOTH).

procedure

(perms/c v)  boolean?

  v : any/c
Checks if v is either a member of or a sublist of '(S_ISUID S_ISGID S_ISVTX S_IRUSR S_IWUSR S_IXUSR S_IRGRP S_IWGRP S_IXGRP S_IROTH S_IWOTH S_IXOTH).

procedure

(filetype? v)  boolean?

  v : any/c
Checks if v is either a member of '(S_IFSOCK S_IFLNK S_IFREG S_IFBLK S_IFDIR S_IFCHR S_IFIFO).

procedure

(oflags/c v)  boolean?

  v : any/c
Checks if v is either a member of or a sublist of '(O_RDONLY O_WRONLY O_RDWR O_CLOEXEC O_CREAT O_DIRECTORY O_EXCL O_NOCTTY O_NOFOLLOW O_TMPFILE O_TRUNC O_APPEND O_NONBLOCK O_PATH O_DSYNC O_DIRECT O_LARGEFILE O_NOATIME).

procedure

(xattr-op? v)  boolean?

  v : any/c
Checks if v is either a member of '(XATTR_DEFAULT XATTR_CREATE XATTR_REPLACE).

procedure

(lock-types/c v)  boolean?

  v : any/c
Checks if v is either a member of or a sublist of '(LOCK_SH LOCK_EX LOCK_NB LOCK_UN LOCK_MAND LOCK_READ LOCK_WRITE LOCK_RW).

procedure

(fallocate-mode? v)  boolean?

  v : any/c
Checks if v is either a member of '(FALLOC_FL_KEEP_SIZE FALLOC_FL_PUNCH_HOLE FALLOC_FL_NO_HIDE_STALE FALLOC_FL_COLLAPSE_RANGE FALLOC_FL_ZERO_RANGE FALLOC_FL_INSERT_RANGE).

5 Example

The module fuse/examples/hello implements an example FUSE filesystem. It is reproduced below for convenience. To run the filesystem, invoke racket -l fuse/examples/hello /path/to/mount/point. (/path/to/mount/point must exist as an empty directory). You can then explore the mounted filesystem at /path/to/mount/point. To unmount the filesystem, invoke fusermount -u /path/to/mount/point.

"fuse/examples/hello"

  #lang racket/base
   
  ; This example was adapted from the hello filesystem example distributed with
  ; libfuse (https://github.com/libfuse/libfuse/blob/master/example/hello_ll.c)
  ; and the rust-fuse package (https://github.com/zargony/rust-fuse)
   
  (require racket/match
           racket/list
           fuse)
   
  (define (lookup #:nodeid nodeid #:name name #:reply reply-entry #:error error)
    (if (and (= nodeid 1) (equal? name (string->path "hello.txt")))
        (reply-entry #:generation 0 #:entry-valid (timespec 1 0) #:attr-valid (timespec 1 0)
                     #:inode 2 #:rdev 0 #:size 13 #:blocks 1
                     #:atime (timespec 1381237736 0) #:mtime (timespec 1381237736 0)
                     #:ctime (timespec 1381237736 0) #:kind 'S_IFREG
                     #:perm '(S_IRUSR S_IWUSR S_IRGRP S_IROTH)
                     #:nlink 1 #:uid 1000 #:gid 1000)
        (error 'ENOENT)))
   
  (define (getattr #:nodeid nodeid #:info info #:reply reply-attr #:error error)
    (match nodeid
      [1 (reply-attr #:attr-valid (timespec 1 0)
                     #:inode 1 #:rdev 0 #:size 0 #:blocks 0
                     #:atime (timespec 1381237736 0) #:mtime (timespec 1381237736 0)
                     #:ctime (timespec 1381237736 0) #:kind 'S_IFDIR
                     #:perm '(S_IRUSR S_IWUSR S_IXUSR S_IRGRP S_IXGRP S_IROTH S_IXOTH)
                     #:nlink 1 #:uid 1000 #:gid 1000)]
      [2 (reply-attr #:attr-valid (timespec 1 0)
                     #:inode 2 #:rdev 0 #:size 13 #:blocks 1
                     #:atime (timespec 1381237736 0) #:mtime (timespec 1381237736 0)
                     #:ctime (timespec 1381237736 0) #:kind 'S_IFREG
                     #:perm '(S_IRUSR S_IWUSR S_IRGRP S_IROTH)
                     #:nlink 1 #:uid 1000 #:gid 10000)]
      [_ (error 'ENOENT)]))
   
  (define (readdir #:nodeid nodeid #:info info #:offset offset #:add reply-add #:reply reply-done #:error error)
    (if (= nodeid 1)
        (begin
          (when (= offset 0)
            (reply-add #:inode 1 #:offset 0 #:kind 'S_IFDIR #:name (string->path "."))
            (reply-add #:inode 1 #:offset 1 #:kind 'S_IFDIR #:name (string->path ".."))
            (reply-add #:inode 1 #:offset 2 #:kind 'S_IFREG #:name (string->path "hello.txt")))
          (reply-done))
        (error 'ENOENT)))
   
  (define (open #:nodeid nodeid #:flags flags #:reply reply-open #:error error)
    (if (= nodeid 2)
        (reply-open #:info 0 #:flags empty)
        (error 'EISDIR)))
   
  (define (read #:nodeid nodeid #:info info #:offset offset #:size size #:lockowner lockowner #:reply reply-data #:error error)
    (reply-data (string->bytes/utf-8 "Hello world!\n")))
   
  (define hellofs (make-filesystem #:lookup lookup #:getattr getattr #:readdir readdir #:open open #:read read))
   
  (module+ main
    (unless (eq? (vector-length (current-command-line-arguments)) 1)
      (error "Must be invoked with an absolute path."))
    (define path (vector-ref (current-command-line-arguments) 0))
    (unless (directory-exists? path)
      (error "Mount directory does not exist."))
    (mount-filesystem hellofs (string->path path) (list "default_permissions" "large_read" "direct_io" "hard_remove")))