Please note that the CVS and issue trackers have moved to GitHub. These Trac pages are no longer kept up-to-date.

root/seattle/branches/nacl_repy/fuse/lind_fuse.py@5546

Revision 5546, 14.9 KB (checked in by cmatthew, 7 years ago)

Move the lind-fuse code from the github to seattle repo.

  • Property svn:executable set to *
Line 
1#!/usr/bin/env python
2
3#    Chris Matthews - University of Victoria - July 2012
4
5import sys
6import os
7import stat
8
9
10# We need lind_test_server.py, lind_fs_calls.py and lind_fs_constants.py.
11# They should be in the REPY_PATH OR copy them in to this folder so python
12# can import the lind_test_server
13
14# add repy install path to script
15path = os.getenv("REPY_PATH")
16if path == None:
17    print "Error: REPY_PATH enviroment variable must be set, using default"
18    path = "/home/lind/tmp/lind/"
19
20path = os.path.join(path, "repy/")
21sys.path.append(path)
22
23
24# change dir so the execfile in test server works
25cur = os.getcwd()
26os.chdir(path)
27import lind_test_server as lind
28# and now back to where we started.
29os.chdir(cur)
30
31
32# pull in some spaghetti to make this stuff work without fuse-py being installed
33try:
34    import _find_fuse_parts
35except ImportError:
36    pass
37import fuse
38from fuse import Fuse
39
40LOGGING = False
41
42def log(*messages):
43    if LOGGING:
44       print ' '.join(map(str, messages))
45
46# Convert a string errno value to the numeric value
47# see the POSIX errno.h for the real thing
48errno = {
49    'EPERM': 1, # Operation not permitted
50    'ENOENT': 2, # No such file or directory
51    'ESRCH': 3, # No such process
52    'EINTR': 4, # Interrupted system call
53    'EIO': 5,   # I/O error
54    'ENXIO': 6, # No such device or address
55    'E2BIG': 7, # Argument list too long
56    'ENOEXEC': 8,       # Exec format error
57    'EBADF': 9, # Bad file number
58    'ECHILD': 10,       # No child processes
59    'EAGAIN': 11,       # Try again
60    'ENOMEM': 12,       # Out of memory
61    'EACCES': 13,       # Permission denied
62    'EACESS': 13,       # Permission denied
63    'EFAULT': 14,       # Bad address
64    'ENOTBLK': 15,      # Block device required
65    'EBUSY': 16,        # Device or resource busy
66    'EEXIST': 17,       # File exists
67    'EXDEV': 18,        # Cross-device link
68    'ENODEV': 19,       # No such device
69    'ENOTDIR': 20,      # Not a directory
70    'EISDIR': 21,       # Is a directory
71    'EINVAL': 22,       # Invalid argument
72    'ENFILE': 23,       # File table overflow
73    'EMFILE': 24,       # Too many open files
74    'ENOTTY': 25,       # Not a typewriter
75    'ETXTBSY': 26,      # Text file busy
76    'EFBIG': 27,        # File too large
77    'ENOSPC': 28,       # No space left on device
78    'ESPIPE': 29,       # Illegal seek
79    'EROFS': 30,        # Read-only file system
80    'EMLINK': 31,       # Too many links
81    'EPIPE': 32,        # Broken pipe
82    'EDOM': 33, # Math argument out of domain of func
83    'ERANGE': 34,       # Math result not representable
84
85    'EDEADLK':35,       # Resource deadlock would occur
86    'ENAMETOOLONG':36,  # File name too long
87    'ENOLCK':37,  # No record locks available
88    'ENOSYS':38,        # Function not implemented
89    'ENOTEMPTY':39,     # Directory not empty
90    'ELOOP':40, # Too many symbolic links encountered
91#    'EWOULDBLOCK':EAGAIN,      # Operation would block
92    'ENOMSG':42,        # No message of desired type
93    'EIDRM':43, # Identifier removed
94    'ECHRNG':44,        # Channel number out of range
95    'EL2NSYNC':45,      # Level 2 not synchronized
96    'EL3HLT':46,        # Level 3 halted
97    'EL3RST':47,        # Level 3 reset
98    'ELNRNG':48,        # Link number out of range
99    'EUNATCH':49,       # Protocol driver not attached
100    'ENOCSI':50,        # No CSI structure available
101    'EL2HLT':51,        # Level 2 halted
102    'EBADE':52, # Invalid exchange
103    'EBADR':53, # Invalid request descriptor
104    'EXFULL':54,        # Exchange full
105    'ENOANO':55,        # No anode
106    'EBADRQC':56,       # Invalid request code
107    'EBADSLT':57,       # Invalid slot
108    'EBFONT':59,        # Bad font file format
109    'ENOSTR':60,        # Device not a stream
110    'ENODATA':61,       # No data available
111    'ETIME':62, # Timer expired
112    'ENOSR':63, # Out of streams resources
113    'ENONET':64,        # Machine is not on the network
114    'ENOPKG':65,        # Package not installed
115    'EREMOTE':66,       # Object is remote
116    'ENOLINK':67,       # Link has been severed
117    'EADV':68,  # Advertise error
118    'ESRMNT':69,        # Srmount error
119    'ECOMM':70, # Communication error on send
120    'EPROTO':71,        # Protocol error
121    'EMULTIHOP':72,     # Multihop attempted
122    'EDOTDOT':73,       # RFS specific error
123    'EBADMSG':74,       # Not a data message
124    'EOVERFLOW':75,     # Value too large for defined data type
125    'ENOTUNIQ':76,      # Name not unique on network
126    'EBADFD':77,        # File descriptor in bad state
127    'EREMCHG':78,       # Remote address changed
128    'ELIBACC':79,       # Can not access a needed shared library
129    'ELIBBAD':80,       # Accessing a corrupted shared library
130    'ELIBSCN':81,       # .lib section in a.out corrupted
131    'ELIBMAX':82,       # Attempting to link in too many shared libraries
132    'ELIBEXEC':83,      # Cannot exec a shared library directly
133    'EILSEQ':84,        # Illegal byte sequence
134    'ERESTART':85,      # Interrupted system call should be restarted
135    'ESTRPIPE':86,      # Streams pipe error
136    'EUSERS':87,        # Too many users
137    'ENOTSOCK':88,      # Socket operation on non-socket
138    'EDESTADDRREQ':89,  # Destination address required
139    'EMSGSIZE':90,      # Message too long
140    'EPROTOTYPE':91,    # Protocol wrong type for socket
141    'ENOPROTOOPT':92,   # Protocol not available
142    'EPROTONOSUPPORT':93,       # Protocol not supported
143    'ESOCKTNOSUPPORT':94,       # Socket type not supported
144    'EOPNOTSUPP':95,    # Operation not supported on transport endpoint
145    'EPFNOSUPPORT':96,  # Protocol family not supported
146    'EAFNOSUPPORT':97,  # Address family not supported by protocol
147    'EADDRINUSE':98,    # Address already in use
148    'EADDRNOTAVAIL':99, # Cannot assign requested address
149    'ENETDOWN':100,     # Network is down
150    'ENETUNREACH':101,  # Network is unreachable
151    'ENETRESET':102,    # Network dropped connection because of reset
152    'ECONNABORTED':103, # Software caused connection abort
153    'ECONNRESET':104,   # Connection reset by peer
154    'ENOBUFS':105,      # No buffer space available
155    'EISCONN':106,      # Transport endpoint is already connected
156    'ENOTCONN':107,     # Transport endpoint is not connected
157    'ESHUTDOWN':108,    # Cannot send after transport endpoint shutdown
158    'ETOOMANYREFS':109, # Too many references: cannot splice
159    'ETIMEDOUT':110,    # Connection timed out
160    'ECONNREFUSED':111, # Connection refused
161    'EHOSTDOWN':112,    # Host is down
162    'EHOSTUNREACH':113, # No route to host
163    'EALREADY':114,     # Operation already in progress
164    'EINPROGRESS':115,  # Operation now in progress
165    'ESTALE':116,       # Stale NFS file handle
166    'EUCLEAN':117,      # Structure needs cleaning
167    'ENOTNAM':118,      # Not a XENIX named type file
168    'ENAVAIL':119,      # No XENIX semaphores available
169    'EISNAM':120,       # Is a named type file
170    'EREMOTEIO':121,    # Remote I/O error
171    'EDQUOT':122,       # Quota exceeded
172    'ENOMEDIUM':123,    # No medium found
173    'EMEDIUMTYPE':124,  # Wrong medium type
174    'ECANCELED':125,    # Operation Canceled
175    'ENOKEY':126,       # Required key not available
176    'EKEYEXPIRED':127,  # Key has expired
177    'EKEYREVOKED':128,  # Key has been revoked
178    'EKEYREJECTED':129, # Key was rejected by service
179    # for robust mutexes
180    'EOWNERDEAD':130,   # Owner died
181    'ENOTRECOVERABLE':131} # State not recoverable
182
183
184if not hasattr(fuse, '__version__'):
185    raise RuntimeError, \
186        "your fuse-py doesn't know of fuse.__version__, probably it's too old."
187
188
189fuse.fuse_python_api = (0, 2)
190
191
192fuse.feature_assert('stateful_files', 'has_init')
193
194
195class LindFileStat(fuse.Stat):
196    """ File attributes.
197
198    See stat and fstat.
199
200    http://linux.die.net/man/2/stat
201
202    """
203    def __init__(self):
204        self.st_mode = 0
205        self.st_ino = 0
206        self.st_dev = 0
207        self.st_nlink = 0
208        self.st_uid = 0
209        self.st_gid = 0
210        self.st_size = 0
211        self.st_atime = 0
212        self.st_mtime = 0
213        self.st_ctime = 0
214
215
216class LindFileStatFS(fuse.Stat):
217    """File system attributes.
218
219    See man statfs and fstatfs.
220   
221    http://linux.die.net/man/2/fstatfs
222
223    """
224    def __init__(self):
225        self.f_bsize = 0  # preferred size of file  blocks, in bytes
226        self.f_frsize = 0  # fundamental size of file blcoks, in bytes
227        self.f_blocks = 0  # total number of blocks in the filesystem
228        self.f_bfree = 0  # number of free blocks
229        self.f_files = 0  # total number of file inodes
230        self.f_ffree = 0  # number of free file inodes
231
232
233class LindFuseFS(Fuse):
234
235    def __init__(self, *args, **kw):
236
237        Fuse.__init__(self, *args, **kw)
238
239        # You can enable multithreading here
240        #import thread
241        #thread.start_new_thread(self.mythread, ())
242        self.root = '/'
243
244
245    def getattr(self, path):
246        log("getattr", path)
247        try:
248            stats = lind.stat_syscall(path)
249        except lind.SyscallError, e:
250            return -errno[e[1]]
251        devid, inode, mode, linkcount, uid, gid, rdev,size, blocksize, blocks, \
252               atime, atimens, mtime, mtimens, ctime, ctimens = stats
253        st = LindFileStat()
254       
255        # treat root specially
256        if path == '/':
257            st.st_mode = stat.S_IFDIR | 0755
258            st.st_nlink = 2
259        else:
260            st.st_mode = mode # stat.S_IFREG | 0444
261            st.st_nlink = linkcount
262            st.st_size = size
263            st.st_dev = devid
264            st.st_uid = uid
265            st.st_gid = gid
266            st.st_ino = inode
267            st.st_atime = atime
268            st.st_ctime = ctime
269            st.st_mtime = mtime
270
271        return st
272
273
274    def readlink(self, path):
275        log("readlink (unimplemented)", path)
276        return errno["ENOSYS"]
277
278
279    def readdir(self, path, offset):
280        log("readdir", path, offset)
281        lindfd = lind.open_syscall(path, lind.O_RDONLY, lind.S_IRWXU)
282        dents = map(lambda x:x[1], lind.getdents_syscall(lindfd, 999))
283
284        assert len(dents) < 998, "Readdir max was hit..."
285        for e in dents:
286            yield fuse.Direntry(e)
287
288
289    def unlink(self, path):
290        log("unlink (unimplemented)", path)
291        return errno["ENOSYS"]
292
293
294    def rmdir(self, path):
295        log("rmdir", path)
296        try:
297            ret = lind.rmdir_syscall(path)
298        except lind.SyscallError, e:
299            ret = -errno[e[1]]
300        return ret
301
302
303    def symlink(self, path, path1):
304        log("symlink", path, path1)
305        try:
306            ret = lind.link_syscall(path, path1)
307        except lind.SyscallError, e:
308            ret = -errno[e[1]]
309        return ret
310
311
312    def rename(self, path, path1):
313        log("rename (unimplemented)", path, path1)
314        return errno["ENOSYS"]
315
316
317    def link(self, path, path1):
318        log("link", path, path1)
319        try:
320            ret = lind.link_syscall(path, path1)
321        except lind.SyscallError, e:
322            ret = -errno[e[1]]
323        return ret
324
325
326    def chmod(self, path, mode):
327        log("chmod (unimplemented)", path, hex(mode))
328        return errno["ENOSYS"]
329
330
331    def chown(self, path, user, group):
332        log("chown (unimplemented)", path, user, group)
333        return errno["ENOSYS"]
334
335
336    def truncate(self, path, len):
337        log("truncate (unimplemented)", path, len)
338        return errno["ENOSYS"]
339
340
341    def mknod(self, path, mode, dev):
342        log("mknod (unimplemented)", path, mode, dev)
343        return errno["ENOSYS"]
344
345
346    def mkdir(self, path, mode):
347        log("mkdir", path, mode)
348        try:
349            ret = lind.mkdir_syscall(path, mode)
350        except lind.SyscallError, e:
351            ret = -errno[e[1]]
352        return ret
353
354
355    def utime(self, path, times):
356        log("utime (unimplemented)", path, times)
357
358
359    def access(self, path, mode):
360        log("access", path, hex(mode))
361        try:
362            ret = lind.access_syscall(path, mode)
363        except lind.SyscallError, e:
364            ret = -errno[e[1]]
365        return ret
366
367
368    def statfs(self):
369        log("statfs")
370        try:
371            stats = lind.statfs_syscall("/")
372        except lind.SyscallError, e:
373            return -errno[e[1]]
374
375        st = LindFileStatFS()
376        st.f_bsize = stats['f_bsize']
377        st.f_frsize = stats['f_frsize']
378        st.f_blocks = stats['f_blocks']
379        st.f_bfree = stats['f_bfree']
380        st.f_files = stats['f_files']
381        st.f_ffree = stats['f_ffree']
382
383        return st
384
385
386    def fsinit(self):
387        print "Starting Lindfs"
388
389
390    class LindFuseFSFile(object):
391        """For each open file in the FS, there will be one of these."""
392
393        def __init__(self, path, flags, *mode):
394            log("open", path, hex(flags))
395            self.direct_io = False
396            self.keep_cache = False
397            lindfd = lind.open_syscall(path, flags, lind.S_IRWXA)
398
399            self.fd = lindfd
400
401
402        def read(self, length, offset):
403            log("read", self.fd, length, offset)
404            try:
405                lind.lseek_syscall(self.fd, offset, 0)
406                ret = lind.read_syscall(self.fd, length)
407            except lind.SyscallError, e:
408                ret = -errno[e[1]]
409
410            return ret
411
412
413        def write(self, buf, offset):
414            log("write", self.fd, buf, offset)
415            try:
416                lind.lseek_syscall(self.fd, offset, 0)
417                ret = lind.write_syscall(self.fd, buf)
418            except lind.SyscallError, e:
419                ret = -errno[e[1]]
420            return ret
421
422
423        def release(self, flags):
424            log("close", self.fd, flags)
425            return lind.close_syscall(self.fd)
426
427
428        def _fflush(self):
429            log("flush", self.fd)
430            return 0
431
432
433        def fsync(self, isfsyncfile):
434            log("fsync", self.fd, isfsyncfile)
435            lind.persist_metadata("lind.metadata")
436            return 0
437
438
439        def flush(self):
440            return self._fflush()
441
442
443        def fgetattr(self):
444            log("fstat", self.fd)
445            try:
446                stats = lind.fstat_syscall(self.fd)
447            except lind.SyscallError, e:
448                return -errno[e[1]]
449            devid, inode, mode, linkcount, uid, gid, rdev,size, blocksize, blocks, \
450                atime, atimens, mtime, mtimens, ctime, ctimens = stats
451            st = LindFileStat()
452            if path == '/':
453                st.st_mode = stat.S_IFDIR | 0755
454                st.st_nlink = 2
455            else:
456                st.st_mode = mode # stat.S_IFREG | 0444
457                st.st_nlink = linkcount
458                st.st_size = size
459                st.st_dev = devid
460                st.st_uid = uid
461                st.st_gid = gid
462                st.st_ino = inode
463                st.st_atime = atime
464                st.st_ctime = ctime
465                st.st_mtime = mtime
466
467            return st
468
469
470        def ftruncate(self, len):
471            return -errno["ENOSYS"]
472
473
474        def lock(self, cmd, owner, **kw):
475            return -errno["ENOSYS"]
476
477
478    def main(self, *a, **kw):
479
480        self.file_class = self.LindFuseFSFile
481
482        return Fuse.main(self, *a, **kw)
483
484
485def main():
486
487    usage = """
488Lind Fuse File System.
489
490""" + Fuse.fusage
491
492    lind.load_fs()
493
494
495    server = LindFuseFS(version="%prog " + fuse.__version__,
496                 usage=usage,
497                 dash_s_do='setsingle')
498
499    server.multithreaded = False  # if this is true, better add some locks!
500
501    server.parser.add_option(mountopt="root", metavar="PATH", default='/',
502                             help="mirror filesystem from under PATH [default: %default]")
503    server.parse(values=server, errex=1)
504    server.main()
505    lind.persist_metadata("lind.metadata")
506
507
508if __name__ == '__main__':
509    main()
Note: See TracBrowser for help on using the browser.