Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
280 lines (195 sloc) 8.73 KB
FuseFS API DOCUMENT
===================
Last updated: 2005.09.19 by Greg Millam
WARNING
-------
Note: If you use DirLink (in demo.rb) or in any way access a FuseFS filesystem
from *within* the ruby script accessing the FuseFS, then FuseFS will hang, and
the only recourse is a kill -KILL.
Also: If there are any open files or shells with 'pwd's in your filesystem
when you exit your ruby script, fuse *might* not actually be unmounted. To
unmount a path yourself, run the command:
fusermount -u <path>
to unmount any FUSE filesystems mounted at <path>.
FuseFS API
----------
FuseFS provides a layer of abstraction to a programmer who wants to create a
virtual filesystem via FUSE.
FuseFS programs consist of two parts:
1) FuseFS, which is defined in 'fusefs.rb'
2) An object that defines a virtual directory. This must define a number of
methods (given below, in "Directory Methods" section) in order to be
usable.
To write a FuseFS program, you must:
* Define and create a Directory object that responds to the methods required
by FuseFS for its desired use.
* Call FuseFS.set_root <virtualdir> with the object defining your virtual
directory.
* Mount FuseFS under a real directory on your filesystem.
* Call FuseFS.run to start receiving and executing events.
Happy Filesystem Hacking!
Hello World FS
--------------
helloworld.rb
This creates a filesystem that contains exactly 1 file: "hello.txt" that, when
read, returns "Hello, World!"
This is not writable to, and contains no other files.
require 'fusefs'
class HelloDir
def contents(path)
['hello.txt']
end
def file?(path)
path -- '/hello.txt'
end
def read_file(path)
"Hello, World!\n"
end
end
hellodir = HelloDir.new
FuseFS.set_root( hellodir )
# Mount under a directory given on the command line.
FuseFS.mount_under ARGV.shift
FuseFS.run
Directory Methods
-----------------
Without any methods defined, any object is by default a content-less,
file-less directory.
The following are necessary for most or all filesystems:
Directory listing and file type methods:
:contents(path) # Return an array of file and dirnames within <path>.
:directory?(path) # Return true if <path> is a directory.
:file?(path) # Return true if <path> is a file (not a directory).
:executable?(path) # Return true if <path> is an executable file.
:size(path) # Return the file size. Necessary for apache, xmms,
etc.
File reading:
:read_file(path) # Return the contents of the file at location <path>.
The following are only necessary if you want a filesystem that can be modified
by the user. Without defining any of the below, the contents of the filesystem
are automatically read-only.
File manipulation:
:can_write?(path) # Return true if the user can write to file at <path>.
:write_to(path,str) # Write the contents of <str> to file at <path>.
:can_delete?(path) # Return true if the user can delete file at <path>.
:delete(path) # Delete the file at <path>
Directory manipulation:
:can_mkdir?(path) # Return true if user can make a directory at <path>.
:mkdir(path) # Make a directory at path.
:can_rmdir?(path) # Return true if user can remove directory at <path>.
:rmdir(path) # Remove it.
Neat "toy":
:touch(path) # Called when a file is 'touch'd or otherwise has
their timestamps explicitly modified. I envision
this as a neat toy, maybe you can use it for a
push-button file?
"touch button" -> unmounts fusefs?
"touch musicfile.mp3" -> Play the mp3.
If you want a lower level control of your file, then you can use:
:raw_open(path,mode) # mode is "r" "w" or "rw", with "a" if the file
is opened for append. If raw_open returns true,
then the following calls are made:
:raw_read(path,off,sz) # Read sz bites from file at path starting at
offset off
:raw_write(path,off,sz,buf) # Write sz bites of buf to path starting at
offset off
:raw_close(path) # Close the file.
Method call flow
================
List contents:
:directory? will be checked before :contents
(Most 'ls' or 'dir' functions will go on next
to getattr() for all contents)
Read file:
:file? will be checked before :read_file
Getattr
:directory? will be checked first.
:file? will be checked before :can_write?
:file? will be checked before :executable?
Writing files:
* directory? is usually called on the directory
The FS wants to write a new file to, before this
can occur.
:can_write? will be checked before :write_to
Deleting files:
:file? will be checked before :can_delete?
:can_delete? will be checked before :delete
Creating dirs:
* directory? is usually called on the directory
The FS wants to make a new directory in, before
this can occur.
:directory? will be checked.
:can_mkdir? is called only if :directory? is false.
:can_mkdir? will be checked before :mkdir
Deleting dirs:
:directory? will be checked before :can_rmdir?
:can_rmdir? will be checked before :rmdir
module FuseFS
-------------
FuseFS methods:
FuseFS.set_root(object)
Set the root virtual directory to <object>. All queries for obtaining
file information is directed at object.
FuseFS.mount_under(path[,opt[,opt,...]])
This will cause FuseFS to virtually mount itself under the given path.
'path' is required to be a valid directory in your actual filesystem.
'opt's are FUSE options. Most likely, you will only want 'allow_other'
or 'allow_root'. The two are mutually exclusive in FUSE, but allow_other
will let other users, including root, access your filesystem. allow_root
will only allow root to access it.
Also available for FuseFS users are:
default_permissions, max_read=N, fsname=NAME.
For more information, look at FUSE.
(P.S: I know FUSE allows other options, but I don't think any of the
rest will do any good with FuseFS. If you think otherwise, please let me
know!)
FuseFS.run
This is the final step to make your virtual filesystem accessible. It is
recommended you run this as your main thread, but you can thread off to
run this.
FuseFS.handle_editor = bool (true by default)
If handle_editor is true, then FuseFS will attempt to capture all editor
files and prevent them from being passed to FuseRoot. It also prevents
created and unmodified files from being passed as well, as vim (among
others) will attempt to create and then remove a file that does not
exist.
FuseFS.reader_uid and FuseFS.reader_gid
When the filesystem is accessed, the accessor's uid or gid is returned
by FuseFS.reader_uid and FuseFS.reader_gid. You can use this in
determining your permissions, or even provide different files for
different users!
FuseFS.fuse_fd and FuseFS.process
These are not intended for use by the programmer. If you want to muck
with this, read the code to see what they do :D.
FuseDir
----------
FuseFS::FuseDir defines the methods "split_path" and "scan_path". You
should typically inherit from FuseDir in your own directory objects.
base, rest = split_path(path) # base is the file or directory in the
current context. rest is either nil,
or a path that is requested. If 'rest'
exists, then you should recurse the paths.
base, *rest = scan_path(path) # scan_path returns an array of all
directory and file elements given by
<path>. This is useful when you're
encapsulating an entire fs into one
object.
MetaDir
-------
MetaDir is a full filesystem defined with hashes. It is writable, and the user
can create and edit files within it, as well as the programmer.
Usage:
root = MetaDir.new
root.mkdir("/hello")
root.write_to("/hello/world","Hello, World!\n")
root.write_to("/hello/everybody","Hello, Everybody!\n")
FuseFS.set_root(root)
Because MetaDir is fully recursive, you can mount your own or other defined
directory structures under it. For example, to mount a dictionary filesystem
(as demonstrated in samples/dictfs.rb), use:
root.mkdir("/dict",DictFS.new)
Conclusion
----------
Happy Hacking! If you do anything neat with this, please let me know!
My email address is walker@deafcode.com
Thanks for using FuseFS!