aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbryan newbold <bnewbold@snark.mit.edu>2008-07-29 02:32:16 -0400
committerbryan newbold <bnewbold@snark.mit.edu>2008-07-29 02:32:16 -0400
commitc56c18320506152db25277f49c05733c73a1043a (patch)
tree81ab207f882fb8d96236fb5be5a95a6d89c14785
downloadpynsfs-c56c18320506152db25277f49c05733c73a1043a.tar.gz
pynsfs-c56c18320506152db25277f49c05733c73a1043a.zip
initialization of repo
-rw-r--r--first_try.py269
-rw-r--r--nsfs.py401
2 files changed, 670 insertions, 0 deletions
diff --git a/first_try.py b/first_try.py
new file mode 100644
index 0000000..04a831e
--- /dev/null
+++ b/first_try.py
@@ -0,0 +1,269 @@
+#!/usr/bin/env python
+
+# July 2008: Bryan Newbold <bryannewbold.com>
+# Based on xmp.py
+
+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 PyNamespace(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 locals()[path].__repr__
+
+ def readlink(self, path):
+ return str(path)
+
+ def readdir(self, path, offset):
+ for e in os.listdir("." + path):
+ yield fuse.Direntry(e)
+
+ def unlink(self, path):
+ del locals()[path]
+
+ def rmdir(self, path):
+ del locals()[path]
+
+ def symlink(self, path, path1):
+ locals()[path1] = locals()[path]
+
+ def rename(self, path, path1):
+ locals()[path1] = locals()[path]
+ del locals()[path]
+
+ def link(self, path, path1):
+ locals()[path1] = locals()[path]
+
+ def chmod(self, path, mode):
+ return -EPFNOSUPPORT
+
+ def chown(self, path, user, group):
+ return -EPFNOSUPPORT
+
+ def truncate(self, path, len):
+ return -EPFNOSUPPORT
+
+ def mknod(self, path, mode, dev):
+ return -EPFNOSUPPORT
+
+ def mkdir(self, path, mode):
+ return -EPFNOSUPPORT
+
+ def utime(self, path, times):
+ return -EPFNOSUPPORT
+
+# 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
+ """
+ rval = os.statvfs(".")
+ rval[3] = len(locals())
+ rval[5] = len(locals())
+ return rval
+
+ def fsinit(self):
+ #os.chdir(self.root)
+ pass
+
+ class PyNamespaceFile(object):
+
+ def __init__(self, path, flags, *mode):
+ self.fobject = locals()[path]
+ self.fstr = StringIO(str(self.fobject))
+
+ def read(self, length, offset):
+ return self.fstr.read(length)
+
+ def write(self, buf, offset):
+ self.fstr.seek(offset)
+ self.fstr.write(buf)
+ return len(buf)
+
+ def release(self, flags):
+ self.fstr.close()
+
+ def _fflush(self):
+ if 'w' in self.fstr.mode or 'a' in self.fstr.mode:
+ self.fstr.flush()
+
+ def fsync(self, isfsyncfile):
+ pass
+
+ def flush(self):
+ pass
+
+ def fgetattr(self):
+ pass
+
+ def ftruncate(self, len):
+ self.fstr.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...
+ return -EOPNOTSUPP
+ #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.PyNamespaceFile
+
+ return Fuse.main(self, *a, **kw)
+
+
+def main():
+
+ usage = """
+Presents a python namespace as a filesystem for aesthetic reasons
+""" + Fuse.fusage
+
+ server = PyNamespace(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/nsfs.py b/nsfs.py
new file mode 100644
index 0000000..740598a
--- /dev/null
+++ b/nsfs.py
@@ -0,0 +1,401 @@
+#!/usr/bin/python
+
+from time import time
+from StringIO import StringIO
+
+import stat # for file properties
+import os # for filesystem modes (O_RDONLY, etc)
+import errno # for error number codes (ENOENT, etc)
+ # - note: these must be returned as negatives
+
+
+# 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)
+
+class DefaultStat(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 DefaultStatVfs(fuse.StatVfs):
+ def __init__(self):
+ self.f_bavail = 0
+ self.f_bfree = 0
+ self.f_blocks = 0
+ self.f_bsize = 0
+ self.f_favail = 0
+ self.f_ffree = 0
+ self.f_files = 0
+ self.f_flag = 0
+ self.f_frsize = 0
+ self.f_namemax = 0
+ self.n_fields = 0
+ self.n_sequence_fields = 0
+ self.n_unamed_fields = 0
+
+class NamespaceFS(Fuse):
+ """Generates a file system from a python namespace, for kicks.
+ """
+
+ def __init__(self, *args, **kw):
+ Fuse.__init__(self, *args, **kw)
+
+ self.context = self.GetContext()
+ #self.file_class = NsfsFile
+ print '*** init complete'
+
+ def getattr(self, path):
+ """
+ - st_mode (protection bits)
+ - st_ino (inode number)
+ - st_dev (device)
+ - st_nlink (number of hard links)
+ - st_uid (user ID of owner)
+ - st_gid (group ID of owner)
+ - st_size (size of file, in bytes)
+ - st_atime (time of most recent access)
+ - st_mtime (time of most recent content modification)
+ - st_ctime (platform dependent; time of most recent metadata change on
+ Unix, or the time of creation on Windows).
+ """
+ print '*** getattr', path
+
+ st = DefaultStat()
+ #st.st_uid = self.context['uid']
+ #st.st_gid = self.context['gid']
+
+ if path == '/':
+ # root directory
+ st.st_mode = stat.S_IFDIR | 0755
+ st.st_nlink = 2
+ return st
+
+ # we want this in the form 'module/submod/stuff'
+ l = path.strip('/').split('/')
+
+ # recursively check the namespace
+ try:
+ l[0] = globals()[l[0]]
+ if len(l) > 1:
+ thing = reduce(getattr, l)
+ else:
+ thing = l[0]
+ except:
+ return -errno.ENOENT # nope, not there
+
+ # for now, only modules are directories
+ if isinstance(thing, type(fuse)):
+ st.st_mode = stat.S_IFDIR | 0755
+ st.st_nlink = 2
+ else:
+ st.st_mode = stat.S_IFREG | 0444
+ st.st_size = len(str(thing)) # how big?
+ st.st_nlink = 1
+ return st
+
+ def readdir(self, path, offset):
+ print '*** readdir', path, offset
+ if path == '/':
+ retl = globals().keys()
+ else:
+ # we want this in the form 'module/submod/stuff'
+ l = path.strip('/').split('/')
+
+ # recursively check the namespace
+ try:
+ print '* trying ', l
+ l[0] = globals()[l[0]]
+ if len(l) == 1:
+ retl = l[0].__dict__.keys()
+ else:
+ retl = reduce(getattr, l).__dict__.keys()
+ except:
+ raise IOError(-errno.ENOENT) # nope, not there
+
+ retl.insert(0, '..')
+ retl.insert(0, '.')
+ for r in retl:
+ yield fuse.Direntry(r)
+
+ def open ( self, path, flags ):
+ print '*** open', path, flags
+
+ # we want this in the form 'module/submod/stuff'
+ l = path.strip('/').split('/')
+
+ # recursively check the namespace
+ try:
+ print '* trying ', l
+ l[0] = globals()[l[0]]
+ if len(l) == 1:
+ thing = l[0]
+ else:
+ thing = reduce(getattr, l)
+ except:
+ raise IOError(-errno.ENOENT) # nope, not there
+
+ # only allow read unless it's a string
+ writeok = False
+ if isinstance(thing, type(".")):
+ writeok = True
+ accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR
+ if (flags & accmode) and writeok:
+ return
+ elif (flags & accmode) != os.O_RDONLY:
+ return -errno.EACCES
+
+ def read ( self, path, length, offset ):
+ print '*** read', path, length, offset
+ # we want this in the form 'module/submod/stuff'
+ l = path.strip('/').split('/')
+
+ # recursively check the namespace
+ try:
+ print '* trying ', l
+ l[0] = globals()[l[0]]
+ if len(l) == 1:
+ thing = l[0]
+ else:
+ thing = reduce(getattr, l)
+ except:
+ raise IOError(-errno.ENOENT) # nope, not there
+
+ tstr = str(thing)
+ slen = len(tstr)
+ if offset < tstr:
+ if offset + length > slen:
+ size = slen - offset
+ buf = tstr[offset:offset+length]
+ else:
+ buf = ''
+ return buf
+
+ def statfs ( self ):
+ print '*** statfs'
+ #return -errno.ENOSYS
+ fst = DefaultStatVfs()
+ fst.f_namemax = 256
+ return fst
+
+ def link ( self, targetPath, linkPath ):
+ print '*** link', targetPath, linkPath
+ t = targetPath.strip('/').split('/')
+
+ # recursively check the namespace; target can't be / for now
+ try:
+ print '* trying ', t
+ t[0] = globals()[t[0]]
+ if len(t) == 1:
+ target = t[0]
+ else:
+ target = reduce(getattr, t)
+ except:
+ return -errno.ENOENT # nope, not there
+
+ l = linkPath.strip('/').split('/')
+ if (len(l) == 1) and (l[0] != '') and not (l[0] in globals().keys()):
+ # easy, good to go
+ globals()[l[0]] = target
+ print '* trying easy ', l[0], target
+ return
+
+ # otherwise...
+ # recursively check the namespace; link can't be /
+ try:
+ print '* trying ', l
+ l[0] = globals()[l[0]]
+ if len(l) == 1:
+ raise IOError(-errno.ENOENT) # can't do root or existing
+ elif len(l) == 2:
+ lp = l[0]
+ else:
+ lp = reduce(getattr, l[:-1]) # want the parent of the link
+ except:
+ return -errno.ENOENT # nope, not there
+
+ # if that all worked out with no errors...
+ lp.__setattr__(l[-1], target)
+
+ def unlink ( self, path ):
+ print '*** unlink', path
+
+ l = path.strip('/').split('/')
+ if (len(l) == 1) and (l[0] != '') and (l[0] in globals().keys()):
+ # easy, good to go
+ del globals()[l[0]]
+ return
+
+ try:
+ print '* trying ', l
+ l[0] = globals()[l[0]]
+ if len(l) == 1:
+ return -errno.ENOENT # something is wrong, shouldn't get here
+ elif len(l) == 2:
+ lp = l[0]
+ else:
+ lp = reduce(getattr, l[:-1]) # want the parent of the link
+ except:
+ return -errno.ENOENT # nope, not there
+ lp.__delattr__(l[-1])
+
+ def write ( self, path, buf, offset ):
+ print '*** write', path, buf, offset
+ # we want this in the form 'module/submod/stuff'
+ l = path.strip('/').split('/')
+
+ # recursively check the namespace
+ try:
+ print '* trying ', l
+ l[0] = globals()[l[0]]
+ if len(l) == 1:
+ thing = l[0]
+ else:
+ thing = reduce(getattr, l)
+ except:
+ print '* ACTUALLY CAN\'T FIND'
+ raise IOError(-errno.ENOENT) # nope, not there
+
+ if not isinstance(thing, type(".")):
+ print '* WRONG TYPE'
+ raise IOError(-errno.ENOENT) # wrong file type
+
+ # Kind of a slow way to go?
+ sfile = StringIO(thing)
+ sfile.seek(offset)
+ sfile.write(buf)
+ sfile.flush()
+ thing = sfile.getvalue()
+ sfile.close()
+
+ # recursively check the namespace
+ l = path.strip('/').split('/')
+ #try:
+ if len(l) == 1:
+ globals()[l[0]] = thing
+ return len(buf)
+ l[0] = globals()[l[0]]
+ tp = reduce(getattr, l[:-1])
+ tp.__setattr__(l[-1], thing)
+ print '* TRIED ', thing
+ return len(buf)
+ #except: # raise IOError(-errno.ENOENT) # nope, not there
+
+ def release ( self, path, flags ):
+ print '*** release', path, flags
+ return -errno.ENOSYS
+
+ def fsync ( self, path, isFsyncFile ):
+ print '*** fsync', path, isFsyncFile
+ return -errno.ENOSYS
+
+ def mknod ( self, path, mode, dev ):
+ print '*** mknod', path, oct(mode), dev
+ return -errno.ENOSYS
+
+ def rmdir ( self, path ):
+ print '*** rmdir', path
+ return -errno.ENOSYS
+
+ def getdir(self, path):
+ print '*** getdir', path
+ return self.readdir(path, 0)
+
+ def mythread ( self ):
+ print '*** mythread'
+ return -errno.ENOSYS
+
+ def chmod ( self, path, mode ):
+ print '*** chmod', path, oct(mode)
+ return -errno.ENOSYS
+
+ def chown ( self, path, uid, gid ):
+ print '*** chown', path, uid, gid
+ return -errno.ENOSYS
+
+ def mkdir ( self, path, mode ):
+ print '*** mkdir', path, oct(mode)
+ return -errno.ENOSYS
+
+ def readlink ( self, path ):
+ print '*** readlink', path
+ return -errno.ENOSYS
+
+ def rename ( self, oldPath, newPath ):
+ print '*** rename', oldPath, newPath
+ globals()[path1] = globals()[path]
+ del globals()[path]
+ #return -errno.ENOSYS
+
+ def symlink ( self, targetPath, linkPath ):
+ print '*** symlink', targetPath, linkPath
+ return -errno.ENOSYS
+
+ def truncate ( self, path, size ):
+ print '*** truncate', path, size
+ return -errno.ENOSYS
+
+ def utime ( self, path, times ):
+ print '*** utime', path, times
+ return -errno.ENOSYS
+
+# This isn't actually used yet
+class NsfsFile(object):
+
+ def init(self, path, flags, mode=None):
+
+ # if mode != None: NEW FILE
+
+ # we want this in the form 'module/submod/stuff'
+ l = path.strip('/').split('/')
+
+ # recursively check the namespace
+ try:
+ l[0] = globals()[l[0]]
+ self.thing = reduce(getattr, l)
+ except:
+ return -errno.ENOENT # nope, not there
+ self.tstr = str(self.thing)
+ self.tfile = StringIO(self.tfile)
+
+ def read(self, len, offset):
+ #return -errno.ENOSYS
+ return read(self.tfile, len, offset)
+
+ def release(self, flags):
+ self.tfile.close()
+
+def main():
+ usage="""
+Experimental Python Namespace Filesystem
+
+""" + Fuse.fusage
+ server = NamespaceFS(version="%prog " + fuse.__version__,
+ usage=usage,
+ dash_s_do='setsingle')
+ server.parse(errex=1)
+ server.flags = 0
+ server.multithreaded = 0
+ print "let's go!"
+ server.main()
+
+if __name__ == '__main__':
+ main()