From fc80cc72b0e1900ea0e0dc540d6a52551e9b19c1 Mon Sep 17 00:00:00 2001 From: bnewbold Date: Fri, 29 Apr 2011 16:00:17 -0400 Subject: minor repo cleanup --- README | 154 +++++++++++++++++++++++++ README.nsfs | 150 ------------------------- _find_fuse_parts.py | 22 ---- bundled_examples/hello.py | 92 --------------- bundled_examples/xmp.py | 279 ---------------------------------------------- find_fuse_parts.py | 22 ++++ nsfs.py | 4 +- 7 files changed, 178 insertions(+), 545 deletions(-) create mode 100644 README delete mode 100644 README.nsfs delete mode 100644 _find_fuse_parts.py delete mode 100644 bundled_examples/hello.py delete mode 100644 bundled_examples/xmp.py create mode 100644 find_fuse_parts.py diff --git a/README b/README new file mode 100644 index 0000000..694541c --- /dev/null +++ b/README @@ -0,0 +1,154 @@ +============================================= +Python Namespace File System +============================================= + +:Author: Bryan Newbold +:Date: July 2008 +:URL: http://git.bnewbold.net?p=pynsfs.git;a=summary + +.. contents:: + +This is an experimental implementation of a python namespace as a virtual +file system, implemented using the python bindings for fusefs on unix. + +At this point only the global namespace of the filesystem instance itself is +accessible, and only limited access is available to that. If anything goes +wrong it can cause a hard lock and system crash; don't leave it running and +don't try to write anything substantial. + +The source code can be checked out from the above URL. + +Features +--------------- +An example session (as root) goes like:: + + snark# ls /mnt/python/ + + snark# python nsfs.py /mnt/python/ + *** init complete + let's go! + + snark# cd /mnt/python/ + + snark# ls -l + total 6 + -r--r--r-- 1 root wheel 30 Dec 31 1969 DefaultStat + -r--r--r-- 1 root wheel 33 Dec 31 1969 DefaultStatVfs + -r--r--r-- 1 root wheel 19 Dec 31 1969 Fuse + -r--r--r-- 1 root wheel 30 Dec 31 1969 NamespaceFS + -r--r--r-- 1 root wheel 27 Dec 31 1969 NsfsFile + -r--r--r-- 1 root wheel 17 Dec 31 1969 StringIO + drwxr-xr-x 2 root wheel 0 Dec 31 1969 __builtins__ + -r--r--r-- 1 root wheel 4 Dec 31 1969 __doc__ + -r--r--r-- 1 root wheel 7 Dec 31 1969 __file__ + -r--r--r-- 1 root wheel 8 Dec 31 1969 __name__ + drwxr-xr-x 2 root wheel 0 Dec 31 1969 _find_fuse_parts + drwxr-xr-x 2 root wheel 0 Dec 31 1969 errno + drwxr-xr-x 2 root wheel 0 Dec 31 1969 fuse + -r--r--r-- 1 root wheel 29 Dec 31 1969 main + drwxr-xr-x 2 root wheel 0 Dec 31 1969 os + drwxr-xr-x 2 root wheel 0 Dec 31 1969 stat + -r--r--r-- 1 root wheel 24 Dec 31 1969 time + + snark# ls stat/ + ST_ATIME S_ENFMT S_IMODE S_ISDIR S_IWRITE + ST_CTIME S_IEXEC S_IREAD S_ISFIFO S_IWUSR + ST_DEV S_IFBLK S_IRGRP S_ISGID S_IXGRP + ST_GID S_IFCHR S_IROTH S_ISLNK S_IXOTH + ST_INO S_IFDIR S_IRUSR S_ISREG S_IXUSR + ST_MODE S_IFIFO S_IRWXG S_ISSOCK __builtins__ + ST_MTIME S_IFLNK S_IRWXO S_ISUID __doc__ + ST_NLINK S_IFMT S_IRWXU S_ISVTX __file__ + ST_SIZE S_IFREG S_ISBLK S_IWGRP __name__ + ST_UID S_IFSOCK S_ISCHR S_IWOTH + + snark# cat time + + + snark# echo " Hello Python" >> os/__name__ + + snark# cat os/__name__ + os Hello Python + + snark# rm time + + snark# ls + DefaultStat __builtins__ fuse + DefaultStatVfs __doc__ main + Fuse __file__ os + NamespaceFS __name__ stat + NsfsFile _find_fuse_parts + StringIO errno + + snark# ln __nameofos__ os/__name__ + ln: __nameofos__: No such file or directory + + snark# ln os/__name__ __nameofos__ + + snark# cat __nameofos__ + os Hello Python + + snark# cd .. + + snark# umount /mnt/python/ + +The root directory is the global namespace; modules are available as +subdirectories and all other objects are accessible as files. Strings can +be appended to; all other "files" are read-only and return their string +representation. "Files" can be deleted; "directories" can not. Hard links to +files are possible. + +Requirements +--------------- + +This was developed on FreeBSD 7.0 with Python 2.5.1 version 0.2 of the +python-fuse bindings. It has also been tested on Ubuntu 10.04 with Python 2.6.5 +and the "python-fuse" package. + +* `FUSE Filesystem`__ installed and configured on a compatible operating system +* Recent version of Python__ +* `FUSE Python Bindings`__ + +Once everything is installed and configured, the script can just be run +as root. + +__ http://fuse.sourceforge.net/ +__ http://python.org +__ http://fuse.sourceforge.net/wiki/index.php/FusePython + +Usage +-------------- +Try ``# python nsfs.py -h`` to get a list of general FUSE options. A simple +mount command would look like:: + + # python nsfs.py /mnt/python + +To unmount:: + + # umount /mnt/python + +I like to run in foreground, single threaded, with debug info:: + + # python nsfs.py -dsf /mnt/python + +Really only basic command line tools work because they don't check for many +attributes; try ``echo "blah" >> file``, ``cat file``, ``df -h``, ``ls -l`` etc. + +TODO +----------------------- +Functions taking simple arguments (or no arguments) could be implemented as +character devices; ``function_name.doc``, ``function_name.repr``, etc could +give meta-information. + +File of the form ``__thing__`` should be renamed ``.thing``. + +New files should be allowed and saved as strings. + +CHANGELOG +----------------------- + +July 28, 2008 + First implementation +April 29, 2011 + Minor repo cleanup + diff --git a/README.nsfs b/README.nsfs deleted file mode 100644 index 9e37d08..0000000 --- a/README.nsfs +++ /dev/null @@ -1,150 +0,0 @@ -============================================= -Python Namespace File System -============================================= - -:Author: Bryan Newbold -:Date: July 2008 -:URL: http://git.bryannewbold.com?p=pynsfs.git;a=summary - -.. contents:: - -This is an experimental implementation of a python namespace as a virtual -file system, implemented using the python bindings for fusefs on unix. - -At this point only the global namespace of the filesystem instance itself is -accessible, and only limited access is available to that. If anything goes -wrong it can cause a hard lock and system crash; don't leave it running and -don't try to write anything substantial. - -The source code can be checked out from the above URL. - -Features ---------------- -An example session goes like:: - - snark# ls /mnt/python/ - - snark# python nsfs.py /mnt/python/ - *** init complete - let's go! - - snark# cd /mnt/python/ - - snark# ls -l - total 6 - -r--r--r-- 1 root wheel 30 Dec 31 1969 DefaultStat - -r--r--r-- 1 root wheel 33 Dec 31 1969 DefaultStatVfs - -r--r--r-- 1 root wheel 19 Dec 31 1969 Fuse - -r--r--r-- 1 root wheel 30 Dec 31 1969 NamespaceFS - -r--r--r-- 1 root wheel 27 Dec 31 1969 NsfsFile - -r--r--r-- 1 root wheel 17 Dec 31 1969 StringIO - drwxr-xr-x 2 root wheel 0 Dec 31 1969 __builtins__ - -r--r--r-- 1 root wheel 4 Dec 31 1969 __doc__ - -r--r--r-- 1 root wheel 7 Dec 31 1969 __file__ - -r--r--r-- 1 root wheel 8 Dec 31 1969 __name__ - drwxr-xr-x 2 root wheel 0 Dec 31 1969 _find_fuse_parts - drwxr-xr-x 2 root wheel 0 Dec 31 1969 errno - drwxr-xr-x 2 root wheel 0 Dec 31 1969 fuse - -r--r--r-- 1 root wheel 29 Dec 31 1969 main - drwxr-xr-x 2 root wheel 0 Dec 31 1969 os - drwxr-xr-x 2 root wheel 0 Dec 31 1969 stat - -r--r--r-- 1 root wheel 24 Dec 31 1969 time - - snark# ls stat/ - ST_ATIME S_ENFMT S_IMODE S_ISDIR S_IWRITE - ST_CTIME S_IEXEC S_IREAD S_ISFIFO S_IWUSR - ST_DEV S_IFBLK S_IRGRP S_ISGID S_IXGRP - ST_GID S_IFCHR S_IROTH S_ISLNK S_IXOTH - ST_INO S_IFDIR S_IRUSR S_ISREG S_IXUSR - ST_MODE S_IFIFO S_IRWXG S_ISSOCK __builtins__ - ST_MTIME S_IFLNK S_IRWXO S_ISUID __doc__ - ST_NLINK S_IFMT S_IRWXU S_ISVTX __file__ - ST_SIZE S_IFREG S_ISBLK S_IWGRP __name__ - ST_UID S_IFSOCK S_ISCHR S_IWOTH - - snark# cat time - - - snark# echo " Hello Python" >> os/__name__ - - snark# cat os/__name__ - os Hello Python - - snark# rm time - - snark# ls - DefaultStat __builtins__ fuse - DefaultStatVfs __doc__ main - Fuse __file__ os - NamespaceFS __name__ stat - NsfsFile _find_fuse_parts - StringIO errno - - snark# ln __nameofos__ os/__name__ - ln: __nameofos__: No such file or directory - - snark# ln os/__name__ __nameofos__ - - snark# cat __nameofos__ - os Hello Python - - snark# cd .. - - snark# umount /mnt/python/ - -The root directory is the global namespace; modules are available as -subdirectories and all other objects are accessible as files. Strings can -be appended to; all other "files" are readonly and return their string -representation. "Files" can be deleted; "directories" can not. Hard links to -files are possible. - -Requirements ---------------- - -This was developed and has only been tested on FreeBSD 7.0 with Python 2.5.1 -version 0.2 of the python-fuse bindings. - -* `FUSE Filesystem`__ installed and configured on a compatible operating system -* Recent version of Python__ -* `FUSE Python Bindings`__ - -Once everything is installed and configured, the script can just be run -as root; no installation necessary. - -__ http://fuse.sourceforge.net/ -__ http://python.org -__ http://fuse.sourceforge.net/wiki/index.php/FusePython - -Usage --------------- -Try ``# python nsfs.py -h`` to get a list of general FUSE options. A simple -mount command would look like:: - - # python nsfs.py /mnt/python - -To unmount:: - - # umount /mnt/python - -I like to run in foreground, single threaded, with debug info:: - - # python nsfs.py -dsf /mnt/python - -Really only basic command line tools work because they don't check for many -attributes; try ``echo "blah" >> file``, ``cat file``, ``df -h``, ``ls -l`` etc. - -TODO ------------------------ -Functions taking simple arguments (or no arguments) could be implemented as -character devices; ``function_name.doc``, ``function_name.repr``, etc could -give meta-information. - -File of the form ``__thing__`` should be renamed ``.thing``. - -New files should be allowed and saved as strings. - -CHANGELOG ------------------------ - -July 28, 2008 - First implementation diff --git a/_find_fuse_parts.py b/_find_fuse_parts.py deleted file mode 100644 index 2a04ab3..0000000 --- a/_find_fuse_parts.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys, os, glob -from os.path import realpath, dirname, join -from traceback import format_exception - -ddd = realpath(join(dirname(sys.argv[0]), '..')) - -for d in [ddd, '.']: - for p in glob.glob(join(d, 'build', 'lib.*')): - sys.path.insert(0, p) - -try: - import fuse -except ImportError: - raise RuntimeError, """ - -! Got exception: -""" + "".join([ "> " + x for x in format_exception(*sys.exc_info()) ]) + """ -! Have you ran `python setup.py build'? -! -! We've done our best to find the necessary components of the FUSE bindings -! even if it's not installed, we've got no clue what went wrong for you... -""" diff --git a/bundled_examples/hello.py b/bundled_examples/hello.py deleted file mode 100644 index b0775a6..0000000 --- a/bundled_examples/hello.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env python - -# Copyright (C) 2006 Andrew Straw -# -# This program can be distributed under the terms of the GNU LGPL. -# See the file COPYING. -# - -import os, stat, errno -# pull in some spaghetti to make this stuff work without fuse-py being installed -try: - import _find_fuse_parts -except ImportError: - pass -import fuse -from fuse import Fuse - - -if not hasattr(fuse, '__version__'): - raise RuntimeError, \ - "your fuse-py doesn't know of fuse.__version__, probably it's too old." - -fuse.fuse_python_api = (0, 2) - -hello_path = '/hello' -hello_str = 'Hello World!\n' - -class MyStat(fuse.Stat): - def __init__(self): - self.st_mode = 0 - self.st_ino = 0 - self.st_dev = 0 - self.st_nlink = 0 - self.st_uid = 0 - self.st_gid = 0 - self.st_size = 0 - self.st_atime = 0 - self.st_mtime = 0 - self.st_ctime = 0 - -class HelloFS(Fuse): - - def getattr(self, path): - st = MyStat() - if path == '/': - st.st_mode = stat.S_IFDIR | 0755 - st.st_nlink = 2 - elif path == hello_path: - st.st_mode = stat.S_IFREG | 0444 - st.st_nlink = 1 - st.st_size = len(hello_str) - else: - return -errno.ENOENT - return st - - def readdir(self, path, offset): - for r in '.', '..', hello_path[1:]: - yield fuse.Direntry(r) - - def open(self, path, flags): - if path != hello_path: - return -errno.ENOENT - accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR - if (flags & accmode) != os.O_RDONLY: - return -errno.EACCES - - def read(self, path, size, offset): - if path != hello_path: - return -errno.ENOENT - slen = len(hello_str) - if offset < slen: - if offset + size > slen: - size = slen - offset - buf = hello_str[offset:offset+size] - else: - buf = '' - return buf - -def main(): - usage=""" -Userspace hello example - -""" + Fuse.fusage - server = HelloFS(version="%prog " + fuse.__version__, - usage=usage, - dash_s_do='setsingle') - - server.parse(errex=1) - server.main() - -if __name__ == '__main__': - main() diff --git a/bundled_examples/xmp.py b/bundled_examples/xmp.py deleted file mode 100644 index a82c097..0000000 --- a/bundled_examples/xmp.py +++ /dev/null @@ -1,279 +0,0 @@ -#!/usr/bin/env python - -# Copyright (C) 2001 Jeff Epler -# Copyright (C) 2006 Csaba Henk -# -# This program can be distributed under the terms of the GNU LGPL. -# See the file COPYING. -# - -import os, sys -from errno import * -from stat import * -import fcntl -# pull in some spaghetti to make this stuff work without fuse-py being installed -try: - import _find_fuse_parts -except ImportError: - pass -import fuse -from fuse import Fuse - - -if not hasattr(fuse, '__version__'): - raise RuntimeError, \ - "your fuse-py doesn't know of fuse.__version__, probably it's too old." - -fuse.fuse_python_api = (0, 2) - -fuse.feature_assert('stateful_files', 'has_init') - - -def flag2mode(flags): - md = {os.O_RDONLY: 'r', os.O_WRONLY: 'w', os.O_RDWR: 'w+'} - m = md[flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)] - - if flags | os.O_APPEND: - m = m.replace('w', 'a', 1) - - return m - - -class Xmp(Fuse): - - def __init__(self, *args, **kw): - - Fuse.__init__(self, *args, **kw) - - # do stuff to set up your filesystem here, if you want - #import thread - #thread.start_new_thread(self.mythread, ()) - self.root = '/' - -# def mythread(self): -# -# """ -# The beauty of the FUSE python implementation is that with the python interp -# running in foreground, you can have threads -# """ -# print "mythread: started" -# while 1: -# time.sleep(120) -# print "mythread: ticking" - - def getattr(self, path): - return os.lstat("." + path) - - def readlink(self, path): - return os.readlink("." + path) - - def readdir(self, path, offset): - for e in os.listdir("." + path): - yield fuse.Direntry(e) - - def unlink(self, path): - os.unlink("." + path) - - def rmdir(self, path): - os.rmdir("." + path) - - def symlink(self, path, path1): - os.symlink(path, "." + path1) - - def rename(self, path, path1): - os.rename("." + path, "." + path1) - - def link(self, path, path1): - os.link("." + path, "." + path1) - - def chmod(self, path, mode): - os.chmod("." + path, mode) - - def chown(self, path, user, group): - os.chown("." + path, user, group) - - def truncate(self, path, len): - f = open("." + path, "a") - f.truncate(len) - f.close() - - def mknod(self, path, mode, dev): - os.mknod("." + path, mode, dev) - - def mkdir(self, path, mode): - os.mkdir("." + path, mode) - - def utime(self, path, times): - os.utime("." + path, times) - -# The following utimens method would do the same as the above utime method. -# We can't make it better though as the Python stdlib doesn't know of -# subsecond preciseness in acces/modify times. -# -# def utimens(self, path, ts_acc, ts_mod): -# os.utime("." + path, (ts_acc.tv_sec, ts_mod.tv_sec)) - - def access(self, path, mode): - if not os.access("." + path, mode): - return -EACCES - -# This is how we could add stub extended attribute handlers... -# (We can't have ones which aptly delegate requests to the underlying fs -# because Python lacks a standard xattr interface.) -# -# def getxattr(self, path, name, size): -# val = name.swapcase() + '@' + path -# if size == 0: -# # We are asked for size of the value. -# return len(val) -# return val -# -# def listxattr(self, path, size): -# # We use the "user" namespace to please XFS utils -# aa = ["user." + a for a in ("foo", "bar")] -# if size == 0: -# # We are asked for size of the attr list, ie. joint size of attrs -# # plus null separators. -# return len("".join(aa)) + len(aa) -# return aa - - def statfs(self): - """ - Should return an object with statvfs attributes (f_bsize, f_frsize...). - Eg., the return value of os.statvfs() is such a thing (since py 2.2). - If you are not reusing an existing statvfs object, start with - fuse.StatVFS(), and define the attributes. - - To provide usable information (ie., you want sensible df(1) - output, you are suggested to specify the following attributes: - - - f_bsize - preferred size of file blocks, in bytes - - f_frsize - fundamental size of file blcoks, in bytes - [if you have no idea, use the same as blocksize] - - f_blocks - total number of blocks in the filesystem - - f_bfree - number of free blocks - - f_files - total number of file inodes - - f_ffree - nunber of free file inodes - """ - - return os.statvfs(".") - - def fsinit(self): - os.chdir(self.root) - - class XmpFile(object): - - def __init__(self, path, flags, *mode): - self.file = os.fdopen(os.open("." + path, flags, *mode), - flag2mode(flags)) - self.fd = self.file.fileno() - - def read(self, length, offset): - self.file.seek(offset) - return self.file.read(length) - - def write(self, buf, offset): - self.file.seek(offset) - self.file.write(buf) - return len(buf) - - def release(self, flags): - self.file.close() - - def _fflush(self): - if 'w' in self.file.mode or 'a' in self.file.mode: - self.file.flush() - - def fsync(self, isfsyncfile): - self._fflush() - if isfsyncfile and hasattr(os, 'fdatasync'): - os.fdatasync(self.fd) - else: - os.fsync(self.fd) - - def flush(self): - self._fflush() - # cf. xmp_flush() in fusexmp_fh.c - os.close(os.dup(self.fd)) - - def fgetattr(self): - return os.fstat(self.fd) - - def ftruncate(self, len): - self.file.truncate(len) - - def lock(self, cmd, owner, **kw): - # The code here is much rather just a demonstration of the locking - # API than something which actually was seen to be useful. - - # Advisory file locking is pretty messy in Unix, and the Python - # interface to this doesn't make it better. - # We can't do fcntl(2)/F_GETLK from Python in a platfrom independent - # way. The following implementation *might* work under Linux. - # - # if cmd == fcntl.F_GETLK: - # import struct - # - # lockdata = struct.pack('hhQQi', kw['l_type'], os.SEEK_SET, - # kw['l_start'], kw['l_len'], kw['l_pid']) - # ld2 = fcntl.fcntl(self.fd, fcntl.F_GETLK, lockdata) - # flockfields = ('l_type', 'l_whence', 'l_start', 'l_len', 'l_pid') - # uld2 = struct.unpack('hhQQi', ld2) - # res = {} - # for i in xrange(len(uld2)): - # res[flockfields[i]] = uld2[i] - # - # return fuse.Flock(**res) - - # Convert fcntl-ish lock parameters to Python's weird - # lockf(3)/flock(2) medley locking API... - op = { fcntl.F_UNLCK : fcntl.LOCK_UN, - fcntl.F_RDLCK : fcntl.LOCK_SH, - fcntl.F_WRLCK : fcntl.LOCK_EX }[kw['l_type']] - if cmd == fcntl.F_GETLK: - return -EOPNOTSUPP - elif cmd == fcntl.F_SETLK: - if op != fcntl.LOCK_UN: - op |= fcntl.LOCK_NB - elif cmd == fcntl.F_SETLKW: - pass - else: - return -EINVAL - - fcntl.lockf(self.fd, op, kw['l_start'], kw['l_len']) - - - def main(self, *a, **kw): - - self.file_class = self.XmpFile - - return Fuse.main(self, *a, **kw) - - -def main(): - - usage = """ -Userspace nullfs-alike: mirror the filesystem tree from some point on. - -""" + Fuse.fusage - - server = Xmp(version="%prog " + fuse.__version__, - usage=usage, - dash_s_do='setsingle') - - server.parser.add_option(mountopt="root", metavar="PATH", default='/', - help="mirror filesystem from under PATH [default: %default]") - server.parse(values=server, errex=1) - - try: - if server.fuse_args.mount_expected(): - os.chdir(server.root) - except OSError: - print >> sys.stderr, "can't enter root of underlying filesystem" - sys.exit(1) - - server.main() - - -if __name__ == '__main__': - main() diff --git a/find_fuse_parts.py b/find_fuse_parts.py new file mode 100644 index 0000000..2a04ab3 --- /dev/null +++ b/find_fuse_parts.py @@ -0,0 +1,22 @@ +import sys, os, glob +from os.path import realpath, dirname, join +from traceback import format_exception + +ddd = realpath(join(dirname(sys.argv[0]), '..')) + +for d in [ddd, '.']: + for p in glob.glob(join(d, 'build', 'lib.*')): + sys.path.insert(0, p) + +try: + import fuse +except ImportError: + raise RuntimeError, """ + +! Got exception: +""" + "".join([ "> " + x for x in format_exception(*sys.exc_info()) ]) + """ +! Have you ran `python setup.py build'? +! +! We've done our best to find the necessary components of the FUSE bindings +! even if it's not installed, we've got no clue what went wrong for you... +""" diff --git a/nsfs.py b/nsfs.py index d306097..1189472 100644 --- a/nsfs.py +++ b/nsfs.py @@ -17,7 +17,7 @@ import errno # for error number codes (ENOENT, etc) # pull in some spaghetti to make this stuff work without fuse-py being installed try: - import _find_fuse_parts + import find_fuse_parts except ImportError: pass import fuse @@ -59,7 +59,7 @@ class DefaultStatVfs(fuse.StatVfs): self.n_unamed_fields = 0 class NamespaceFS(Fuse): - """Generates a file system from a python namespace, for kicks. + """Generates a virtual file system from a python namespace. """ def __init__(self, *args, **kw): -- cgit v1.2.3