#!/usr/bin/env python # -*- coding: UTF-8 -*- # afiolzofs : Support to mount afio archives with lzop compression. # Copyright (c) 2010, Yoshiteru Ishimaru # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the Yoshiteru Ishimaru nor the names of its contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # 0.0.29 (08 Jan 2011) # data,afio_inode buffer # 0.0.28 (08 Jan 2011) # long lzop file >256K block decompress, but non buffered # 0.0.27 (07 Jan 2011) # long lzop file >256K block decompress(experimental) # AFIO header class # 0.0.26 (01 Jan 2011) # long lzop file >256K # 0.0.25 (29 Dec 2010) # Xattr,Attr,Dir function # get_items,items,et,set_inode_data function # 0.0.24 (24 Dec 2010) # _setnlink(calc_nlnk) # fix mount option # access # 0.0.23 (23 Dec 2010) # atime at readonly # fix write,trunc # fix mount option # 0.0.22 (22 Dec 2010) # error message of 'cannot find fuse.py' # 0.0.21 (21 Dec 2010) # options # 0.0.20 (19 Dec 2010) # Ramfs,AfioLzofs # 0.0.19 (18 Dec 2010) # bug fix # 0.0.18 (18 Dec 2010) # fix open,opendir,use_ino # inode dict -> class # 0.0.17 (17 Dec 2010) # fix rm # fix open # 0.0.16 (12 Dec 2010) # fix some error # 0.0.15 (08 Dec 2010) # Ramfs Class and Afiolzofs Class # 0.0.14 (08 Dec 2010) # start to separate Temp Ramfs Block and AFIO access Block # 0.0.13 (07 Dec 2010) # _get_inode # read_afio_symlink no read symlinkpath at first # read_afio_item_offsetsize no read all and store for non compressed data at only read. # 0.0.12 (06 Dec 2010) # fix some error # 0.0.11 (05 Dec 2010) # x permission # 0.0.10 (04 Dec 2010) # r,w permission # 0.0.9 (03 Dec 2010) # test implementation for permission to dirread # 0.0.8 (02 Dec 2010) # fix some error # 0.0.7 (01 Dec 2010) # fix some of the atime,mtime,ctime # fix some error code # 0.0.6 (30 Nov 2010) # fix some of the atime,mtime,ctime # use get_fuse_context # 0.0.5 (29 Nov 2010) # list many item shuld be fix. # fix some of them. # 0.0.4 (27 Nov 2010) # support extended ASCII format # fix "unlink error" # fix "other magic number" # not to use defaultdict # fix "rename error" # change inode structure # 0.0.3 (26 Nov 2010) # fix "cannot mount XXXXXX.afio.lzo" # 0.0.2 (26 Nov 2010) # BUG fix "REG FILE" # 0.0.1 (21 Nov 2010) # New release # This program is based on fusepy. And it is started by coping the 'fuse.py' and 'memory.py' # # Copyright of the fuse.py and memory.py # # Copyright (c) 2008 Giorgos Verigakis # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISCHR, S_ISBLK # function from stat import S_IMODE # function (or 0007777) get bitmask to be able to change with os.chmod() from stat import S_IFMT # function (or 0170000) get bitmask for the file type bitfields from stat import S_IFSOCK # 0140000 socket from stat import S_IFLNK # 0120000 symbolic link from stat import S_IFREG # 0100000 regular file from stat import S_IFBLK # 0060000 block device from stat import S_IFDIR # 0040000 directory from stat import S_IFCHR # 0020000 character device from stat import S_IFIFO # 0010000 FIFO from stat import S_ISUID # 0004000 set UID bit from stat import S_ISGID # 0002000 set-group-ID bit (see below) from stat import S_ISVTX # 0001000 sticky bit (see below) from stat import S_IRWXU # 00700 mask for file owner permissions from stat import S_IRUSR # 00400 owner has read permission from stat import S_IWUSR # 00200 owner has write permission from stat import S_IXUSR # 00100 owner has execute permission from stat import S_IRWXG # 00070 mask for group permissions from stat import S_IRGRP # 00040 group has read permission from stat import S_IWGRP # 00020 group has write permission from stat import S_IXGRP # 00010 group has execute permission from stat import S_IRWXO # 00007 mask for permissions for others (not in group) from stat import S_IROTH # 00004 others have read permission from stat import S_IWOTH # 00002 others have write permission from stat import S_IXOTH # 00001 others have execute permission from sys import argv, exit from time import time,mktime ,strptime import subprocess import pwd import grp import os from errno import * try: from fuse import FUSE, FuseOSError, Operations, LoggingMixIn ,fuse_get_context except: print 'I cannot find fuse.py.' print 'Please download fuse.py from http://code.google.com/p/fusepy.' print 'And put it in the same dir.' exit() """ ENOSYS (Function not implemented) EPERM (Operation not permitted) ENOENT (No such file or directory) EIO (I/O error) ENXIO (No such device or address) EBADF (Bad file number) ENOMEM (Out of memory) EACCES (Permission denied) EFAULT (Bad address) ENOTBLK (Block device required) EBUSY (Device or resource busy) EEXIST (File exists) EXDEV (Cross-device link) ENODEV (No such device) ENOTDIR (Not a directory) EISDIR (Is a directory) ENOSPC (No space left on device) ESPIPE (Illegal seek) EROFS (Read-only file system) EPIPE (Broken pipe) ENAMETOOLONG (File name too long) ENOTEMPTY (Directory not empty) """ ################################################################################################################# # # # Inode Class # # # ################################################################################################################# class Inode(): def __init__(self,time,context): self.st_ctime=time self.st_mtime=time self.st_atime=time self.st_uid=context[0] self.st_gid=context[1] ### Inode Dir access functions ### def set_dentry(self,name,inode): # set or add dir entry if hasattr(self,'i_dentry'): if hasattr(self.i_dentry,name): return True # return True if name is exist -> error(file exist) self.i_dentry[name]=inode # if exist else: self.i_dentry={name:inode} # if no i_dentry def get_dentry(self,name): return getattr(self,'i_dentry',{})[name] # get dir entry def pop_dentry(self,name): return getattr(self,'i_dentry',{}).pop(name) # delete or move dir entry def ls_dentry(self): return getattr(self,'i_dentry',{}).keys() # list dir entry def len_dentry(self): return len(getattr(self,'i_dentry',{})) # number of the dir entrys (for delete check) ### Inode Xattr access functions ### def set_xattr(self,name,val): # set or add xattr if hasattr(self,'i_xattr'): self.i_xattr[name]=val # else: self.i_xattr={name:val} # def get_xattr(self,name): return getattr(self,'i_xattr',{})[name] # def pop_xattr(self,name): return getattr(self,'i_xattr',{}).pop(name) # def ls_xattr(self): return getattr(self,'i_xattr',{}).keys() # ### Inode Set Attr functions ### def set_nlink(self,n=1): if n!=1 or hasattr(self,'st_nlink'): self.st_nlink=n def inc_nlink(self): if hasattr(self,'st_nlink'): self.st_nlink+=1 else: self.st_nlink=2 def dec_nlink(self): if hasattr(self,'st_nlink'): self.st_nlink-=1 else: self.st_nlink=0 def update_atime(self,time): self.st_atime=time def update_mtime(self,time): self.st_mtime=time def update_ctime(self,time): self.st_ctime=time def set_rdev(self,n=0): self.st_rdev=n def set_mode(self,mode): self.st_mode=mode def set_gid(self,gid): self.st_gid=gid def set_uid(self,uid): self.st_uid=uid ### Inode Get Attr functions ### def get_items(self,keys=('st_mode','st_uid','st_gid')): # called to get mode,uid,gid return [val for key,val in self.items(keys)] def items(self,keys=('st_mode','st_uid','st_gid','st_rdev','st_atime','st_ctime','st_mtime','st_ino','st_size','st_nlink')): inode=None # called at 'getattr' from fuse.py. for key in keys: if key=='st_ino': yield ('st_ino',id(self)) elif key=='st_nlink': yield (key,getattr(self,key,1)) elif key=='st_size': key='st_size';val=getattr(self,'i_data',None) if val==None: if inode==None:inode=self.get_default_inode() val=inode.get(key,0) else:val=len(val) yield (key,val) else: val=getattr(self,key,None) if val==None: if inode==None:inode=self.get_default_inode() val=inode.get(key,0) yield (key,val) ### Inode File IO functions ### def get_default_inode(self): return {} # if no attr is, use from this dict or 0 in the 'items'. def get_inode_data(self,offset=0,size=None): # get data for read. if size==None:return getattr(self,'i_data','')[offset:] else:return getattr(self,'i_data','')[offset:(offset + size)] def set_inode_data(self,data,offset=0): # set data for write i_data=self.get_inode_data() self.i_data = i_data[0:offset]+data+i_data[offset+len(data):] return len(data) # return write length def trunc_inode_data(self,offset): # truncate data length self.i_data=self.get_inode_data(0,offset) ################################################################################################################# # # # FUSE Operation Ramfs Class # # # ################################################################################################################# class Ramfs(Operations): # for normal use """Temporaly Read Write Memory filesystem. No Saving files. """ def __init__(self,mountpoint): self.mountpoint=mountpoint # abspath of the mount point self.fd = 0 # self.uid=os.getuid() self.inode=Inode(time(),(self.uid,os.getgid())) # root inode of the file system self.inode.set_mode(S_IFDIR | 0755) self.inode.set_nlink(2) ######## Ramfs function (Permission check) ######## def _is_inode_USER(self,inode,context,uname,items,filesystem=False): # filesystem is set 'True' at 'chown' if (context[0]==items[1])or(context[0]==0):return if filesystem and(context[0]==self.uid):return # -> filesystem owner can change UID of any files. raise FuseOSError(EPERM) # (Operation not permitted) def _is_inode_R_OK(self,inode,context,uname,items): if not (items[0] & S_IROTH) and not((items[0] & S_IRUSR) and (items[1] == context[0])): if (items[0] & S_IRGRP): if not(uname in grp.getgrgid(items[2]).gr_mem): if context[1] != items[2]: raise FuseOSError(EACCES) # (Permission denied) else: raise FuseOSError(EACCES) # (Permission denied) def _is_inode_W_OK(self,inode,context,uname,items): if not (items[0] & S_IWOTH) and not((items[0] & S_IWUSR) and (items[1] == context[0])): if (items[0] & S_IWGRP): if not(uname in grp.getgrgid(items[2]).gr_mem): if context[1] != items[2]: raise FuseOSError(EACCES) # (Permission denied) else: raise FuseOSError(EACCES) # (Permission denied) def _is_inode_X_OK(self,inode,context,uname,items): if not (items[0] & S_IXOTH) and not((items[0] & S_IXUSR) and (items[1] == context[0])): if (items[0] & S_IXGRP): if not(uname in grp.getgrgid(items[1]).gr_mem): if context[1] != items[1]: raise FuseOSError(EACCES) # (Permission denied) else: raise FuseOSError(EACCES) # (Permission denied) ######## Ramfs function (Get inode with Permission check) ######## def _get_dir_inode_nopermisson(self,path): ###### Get inode without any permission checking ###### if path=="/": # if path is root return self.inode # return root inode of the file system pname=os.path.split(path) inode_dir=self._get_dir_inode_nopermisson(pname[0]) try:inode=inode_dir.get_dentry(pname[1]) # get inode except: # if no inode inode=Inode(time(),(self.uid,os.getgid())) # make one as dir inode inode.set_mode( S_IMODE(0755) | S_IFDIR ) # set mode (dir) inode.set_nlink(2) inode_dir.set_dentry(pname[1],inode) inode_dir.inc_nlink() return inode def _get_inode(self,path,context,uname): ###### Get inode from path,context,uname ####### if path=="/": # if path is root of the file system inode=self.inode else: # not root of the file system pname=os.path.split(path) inode_dir=self._get_inode(pname[0],context,uname) items=inode_dir.get_items() self._is_inode_X_OK(inode_dir,context,uname,items) # dir access permission check try:inode=inode_dir.get_dentry(pname[1]) # if 'no name in dir list' or 'not dir' -> error except:raise FuseOSError(ENOENT) # (No such file or directory) return inode def _get_inode_for_access(self,path): ###### Get inode for Access ###### context=fuse_get_context() # get system call uid and gid uname=pwd.getpwuid(context[0]).pw_name # get system call uname inode=self._get_inode(path,context,uname) items=inode.get_items() return inode,context,uname,items def _get_inode_for_user(self,path,filesystem=False): ###### Get inode for user (or root) ###### inode,context,uname,items=self._get_inode_for_access(path) # access permission check self._is_inode_USER(inode,context,uname,items,filesystem) # read permission check return inode,items def _get_inode_for_read(self,path): ###### Get inode for Read ###### inode,context,uname,items=self._get_inode_for_access(path) # access permission check items=inode.get_items() self._is_inode_R_OK(inode,context,uname,items) # read permission check return inode,items def _get_inode_for_write(self,path): ###### Get inode for Write ###### inode,context,uname,items=self._get_inode_for_access(path) # access permission check self._is_inode_W_OK(inode,context,uname,items) # write permission check return inode,items def _get_dir_inode_for_create(self,path): ###### Get dir inode for Rename or Link ###### pname=os.path.split(path) # split to dirpath and filename inode,context,uname,items=self._get_inode_for_access(pname[0]) # access permission check self._is_inode_W_OK(inode,context,uname,items) # dir write permission check return inode,pname[1] # return inode_dir and filename def _get_inode_for_delete(self,path): ###### Get inode for Delete ###### pname=os.path.split(path) # split to dirpath and filename inode,context,uname,items=self._get_inode_for_access(pname[0]) # access permission check self._is_inode_W_OK(inode,context,uname,items) # dir write permission check now=time() inode_file=inode.get_dentry(pname[1]) return inode_file,inode,pname[1],now # return inode_file, inode_dir, filename and now def _get_inode_for_create(self,path): ###### Get default inode for Create File,Dir,Symlink or Node ###### pname=os.path.split(path) # split to dirpath and filename inode,context,uname,items=self._get_inode_for_access(pname[0]) # access permission check self._is_inode_W_OK(inode,context,uname,items) # dir write permission check now=time() inode_file = Inode(now,context) return inode_file,inode,pname[1],now # return inode_file(new inode), inode_dir, filename and now ######## Ramfs function (inode Operation) ######## def _update_atime(self,inode,now): inode.update_atime(now) # write file data -> change mtime def _add_inode_nopermisson(self,path,inode,dirinode=False): # add inode without any permission checking # fix me ! if no dir,create or error? pname=os.path.split(path) inode_dir=self._get_dir_inode_nopermisson(pname[0]) if inode_dir.set_dentry(pname[1],inode): raise FuseOSError(EEXIST) # (File exists) if dirinode:inode_dir.inc_nlink() def _add_inode_as_dir(self,inode_dir,inode,filename,now): # if inode_dir.set_dentry(filename,inode): raise FuseOSError(EEXIST) # (File exists) inode_dir.update_mtime(now) # write to dir list -> change mtime inode_dir.inc_nlink() inode_dir.update_ctime(now) # change nlink -> change ctime inode.update_ctime(now) # change nlink -> change ctime inode.update_mtime(now) # change dir list -> change mtime def _removedir_inode(self,inode,inode_dir,filename,now): # inode_dir.pop_dentry(filename) inode_dir.update_mtime(now) # change dir list -> change mtime inode_dir.dec_nlink() inode_dir.update_ctime(now) # change nlink -> change ctime def _add_inode_as_file(self,inode_dir,inode,filename,now): # if inode_dir.set_dentry(filename,inode): raise FuseOSError(EEXIST) # (File exists) inode_dir.update_mtime(now) # write to dir list -> change mtime inode_dir.update_ctime(now) # ??? inode.update_ctime(now) # change nlink -> change ctime def _removefile_inode(self,inode,inode_dir,filename,now): # inode_dir.pop_dentry(filename) # fix me ! no name ? inode_dir.update_mtime(now) # change dir list -> change mtime inode_dir.update_ctime(now) # change mtime -> change ctime inode.update_ctime(now) # change nlink -> change ctime ######## FUSE Operating function (Start File System) ######## def init(self, path): """Called on filesystem initialization. Path is always / Use it instead of __init__ if you start threads on initialization.""" pass def statfs(self, path): return dict(f_bsize=0x00040000, f_blocks=4096, f_bavail=2048) def destroy(self, path): """Called on filesystem destruction. Path is always /""" pass ######## FUSE Operating function (Attr) ######## def access(self, path, amode): inode,context,uname,items=self._get_inode_for_access(path) # access permission check if os.X_OK & amode:self._is_inode_X_OK(inode,context,uname,items) if os.W_OK & amode:self._is_inode_W_OK(inode,context,uname,items) if os.R_OK & amode:self._is_inode_R_OK(inode,context,uname,items) def getattr(self, path, fh=None): ###### getattr ###### inode,context,uname,items=self._get_inode_for_access(path) # access permission check return inode # return inode def chmod(self, path, mode): ###### chmod ###### inode,items=self._get_inode_for_user(path) # user check inode.set_mode( S_IFMT(items[0]) | S_IMODE(mode) ) # see S_IFMT,S_IMODE now=time() inode.update_ctime(now) # change inode data -> change ctime def chown(self, path, uid, gid): ###### chown ###### inode,items=self._get_inode_for_user(path,filesystem=True) # user check if uid != -1:inode.set_uid(uid) # set uid with check -1 if gid != -1:inode.set_gid(gid) # set gid with check -1 now=time() inode.update_ctime(now) # change inode data -> change ctime def utimens(self, path, times=None): ###### utime ###### inode,items=self._get_inode_for_user(path) # user check now = time() atime, mtime = times if times else (now, now) # atime mtime can be changed by touch (utimes),but not ctime inode.update_atime(atime) # In BSD symlink's atime,mtime,ctime is can changed with lutimes, cannot change read NG inode.update_mtime(mtime) # but not in Linux because no lutimes. can change if dir mode ok inode.update_ctime(now) # change atime,mtime -> change ctime # def lock(self,path, fh, cmd, lock): pass # fix me! # def bmap(self,path, blocksize, idx): pass # fix me! ######## FUSE Operating function (XAttr) ######## def listxattr(self, path): inode,context,uname,items=self._get_inode_for_access(path) # access permission check return inode.ls_xattr() def getxattr(self, path, name, position=0): inode,context,uname,items=self._get_inode_for_access(path) # access permission check try:return inode.get_xattr(name) except KeyError:raise FuseOSError(ENOSYS) # (Function not implemented) # fix me! what error should be. def setxattr(self, path, name, value, options, position=0): # Ignore options inode,items=self._get_inode_for_user(path) # user check inode.set_xattr(value) def removexattr(self, path, name): inode,items=self._get_inode_for_user(path) # user check try:inode.pop_xattr(value) except KeyError:raise FuseOSError(ENOSYS) # (Function not implemented) # fix me! what error should be. ######## FUSE Operating function (Read Dir) ######## def opendir(self, path): inode,context,uname,items=self._get_inode_for_access(path) # access permission check if not S_ISDIR(items[0]):raise FuseOSError(ENOSYS) # Function not implemented self._is_inode_R_OK(inode,context,uname,items) # fix me change by read ??? or not. change atime? """Returns a numerical file handle.""" self.fd += 1 return self.fd # return fd def readdir(self, path, fh): ###### readdir ###### inode,items=self._get_inode_for_read(path) # read permission check if not S_ISDIR(items[0]):raise FuseOSError(ENOSYS) # Function not implemented dirnames=inode.ls_dentry() # read dir list dirnames.append('..') # append parent dir '..' dirnames.append('.') # append parent dir '.' self._update_atime(inode,time()) # read data -> change atime return dirnames # return dir list def releasedir(self, path, fh): return 0 def fsyncdir(self, path, datasync, fh): return 0 ######## FUSE Operating function (Create or Remove Dir) ######## def mkdir(self, path, mode): ###### mkdir ###### inode,inode_dir,filename,now=self._get_inode_for_create(path) # write permission check inode.set_mode( S_IMODE(mode) | S_IFDIR ) # set mode (dir) inode.set_nlink(2) self._add_inode_as_dir(inode_dir,inode,filename,now) # add inode as dir def rmdir(self, path): ###### rmdir ###### inode,inode_dir,filename,now=self._get_inode_for_delete(path) # write permission check items=inode.get_items() if not S_ISDIR(items[0]):raise FuseOSError(ENOSYS) # Function not implemented (not Dir shuld be delete unlink) if filename == '/': # Shuld be check root? ?? raise FuseOSError(EPERM) # Operation not permitted elif inode.len_dentry()>0: # raise FuseOSError(ENOTEMPTY) # Directory not empty else: self._removedir_inode(inode,inode_dir,filename,now) # remove dir ######## FUSE Operating function (Create or Remove File) ######## def mknod(self, path, mode, dev): ###### mknod ###### mask=S_IFSOCK | S_IFBLK | S_IFCHR | S_IFIFO # ??? S_IFREG ? # fix me! if (mode & mask) == 0 :raise FuseOSError(EPERM) # (Operation not permitted) # inode,inode_dir,filename,now=self._get_inode_for_create(path) # write permission check inode.set_mode( S_IMODE(mode) | (mode & mask) ) # set node mode # fix me! inode.set_rdev(dev) # set rdev # fix me! self._add_inode_as_file(inode_dir,inode,filename,now) # add inode as file def create(self, path, mode): ###### create ###### inode,inode_dir,filename,now=self._get_inode_for_create(path) # write permission check inode.set_mode( S_IFREG | S_IMODE(mode) ) # set reguler file mode inode.set_inode_data('') # set no data self._add_inode_as_file(inode_dir,inode,filename,now) # add inode as file self.fd += 1 return self.fd # return fd def unlink(self, path): ###### unlink ###### inode,inode_dir,filename,now=self._get_inode_for_delete(path) # write permission check items=inode.get_items() if S_ISDIR(items[0]):raise FuseOSError(ENOSYS) # Function not implemented (Dir shuld be delete rmdir) inode.dec_nlink() self._removefile_inode(inode,inode_dir,filename,now) # remove file def rename(self, old, new): inode,old_dir,old_name,now=self._get_inode_for_delete(old) # write permission check inode_dir,filename=self._get_dir_inode_for_create(new) # write permission check items=inode.get_items() if S_ISDIR(items[0]): self._add_inode_as_dir(inode_dir,inode,filename,now) # add dir link self._removedir_inode(inode,old_dir,old_name,now) # remove dir (Should be first ?) else: self._add_inode_as_file(inode_dir,inode,filename,now) # add file link self._removefile_inode(inode,old_dir,old_name,now) # remove file def link(self, target, source): ###### link ###### inode_dir,filename=self._get_dir_inode_for_create(target) # write permission check inode,context,uname,items=self._get_inode_for_access(source) # we can make link of other's file now=time() # get time now if S_ISDIR(items[0]):raise FuseOSError(ENOSYS) # Function not implemented # fix me! error NO self._add_inode_as_file(inode_dir,inode,filename,now) # add inode as file ######## FUSE Operating function (Sym Link) ######## def readlink(self, path): ###### readlink ###### inode,items=self._get_inode_for_read(path) # read permission check if not S_ISLNK(items[0]):raise FuseOSError(EPERM) # (Operation not permitted) self._update_atime(inode,time()) # read data -> change atime return inode.get_inode_data() def symlink(self, target, source): ###### symlink ###### inode,inode_dir,filename,now=self._get_inode_for_create(target) # write permission check inode.set_mode(S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO ) # set symlink mode inode.set_inode_data(source) # set source path as data self._add_inode_as_file(inode_dir,inode,filename,now) # add inode as file ######## FUSE Operating function (Read or Write File) ######## def open(self, path, flags): inode,context,uname,items=self._get_inode_for_access(path) # access permission check if S_ISDIR(items[0]):raise FuseOSError(ENOSYS) # Function not implemented (Dir shuld be delete rmdir) if (flags & 3) == os.O_RDONLY: self._is_inode_R_OK(inode,context,uname,items) elif (flags & 3) == os.O_RDWR: self._is_inode_R_OK(inode,context,uname,items) self._is_inode_W_OK(inode,context,uname,items) elif (flags & 3)== os.O_WRONLY: self._is_inode_W_OK(inode,context,uname,items) self.fd += 1 # any time shuld not be changed with only open return self.fd # shuld return file handle pointer. Can I use inode instead? Then Where shuld i save flags ? def read(self, path, size, offset, fh): ###### read ###### print "=== read === %04x %04x" % (size,offset) inode,items=self._get_inode_for_read(path) # read permission check if not S_ISREG(items[0]):raise FuseOSError(EPERM) # (Operation not permitted) self._update_atime(inode,time()) # read data -> change atime return inode.get_inode_data(offset,size) # return read data def write(self, path, data, offset, fh): ###### write ###### inode,items=self._get_inode_for_write(path) # write permission check if not S_ISREG(items[0]):raise FuseOSError(EPERM) # (Operation not permitted) now=time() inode.update_mtime(now) # write file data -> change mtime inode.update_ctime(now) # change size -> change ctime return inode.set_inode_data(data,offset) def truncate(self, path, length, fh=None): ###### truncate ###### inode,items=self._get_inode_for_write(path) # write permission check if not S_ISREG(items[0]):raise FuseOSError(EPERM) # (Operation not permitted) now=time() inode.update_mtime(now) # write file data -> change mtime inode.update_ctime(now) # change size -> change ctime inode.trunc_inode_data(length) def release(self, path, fh): return 0 def flush(self, path, fh): return 0 def fsync(self, path, datasync, fh): return 0 ################################################################################################################# # # # FUSE Operation Romfs Class # # # ################################################################################################################# class Romfs(Ramfs): """Read only Memory filesystem. """ def _update_atime(self,inode,now): pass ######## FUSE Operating function (Attr) ######## def access(self, path, amode): inode,context,uname,items=self._get_inode_for_access(path) # access permission check if os.X_OK & amode:self._is_inode_X_OK(inode,context,uname,items) if os.W_OK & amode:raise FuseOSError(EROFS) # (Read-only file system) if os.R_OK & amode:self._is_inode_R_OK(inode,context,uname,items) def chmod(self, path, mode): ###### chmod ###### raise FuseOSError(EROFS) # (Read-only file system) def chown(self, path, uid, gid): ###### chown ###### raise FuseOSError(EROFS) # (Read-only file system) def utimens(self, path, times=None): ###### utime ###### raise FuseOSError(EROFS) # (Read-only file system) ######## FUSE Operating function (XAttr) ######## def setxattr(self, path, name, value, options, position=0): # Ignore options raise FuseOSError(EROFS) # (Read-only file system) def removexattr(self, path, name): raise FuseOSError(EROFS) # (Read-only file system) ######## FUSE Operating function (Create or Remove Dir) ######## def mkdir(self, path, mode): ###### mkdir ###### raise FuseOSError(EROFS) # (Read-only file system) def rmdir(self, path): ###### rmdir ###### raise FuseOSError(EROFS) # (Read-only file system) ######## FUSE Operating function (Create or Remove File) ######## def mknod(self, path, mode, dev): ###### mknod ###### raise FuseOSError(EROFS) # (Read-only file system) def create(self, path, mode): ###### create ###### raise FuseOSError(EROFS) # (Read-only file system) def unlink(self, path): ###### unlink ###### raise FuseOSError(EROFS) # (Read-only file system) def rename(self, old, new): raise FuseOSError(EROFS) # (Read-only file system) def link(self, target, source): ###### link ###### raise FuseOSError(EROFS) # (Read-only file system) ######## FUSE Operating function (Sym Link) ######## def symlink(self, target, source): ###### symlink ###### raise FuseOSError(EROFS) # (Read-only file system) ######## FUSE Operating function (Read or Write File) ######## def open(self, path, flags): inode,context,uname,items=self._get_inode_for_access(path) # access permission check if S_ISDIR(items[0]):raise FuseOSError(ENOSYS) # Function not implemented (Dir shuld be delete rmdir) if (flags & 3) == os.O_RDONLY: self._is_inode_R_OK(inode,context,uname,items) elif (flags & 3) == os.O_RDWR: raise FuseOSError(EROFS) # (Read-only file system) elif (flags & 3)== os.O_WRONLY: raise FuseOSError(EROFS) # (Read-only file system) self.fd += 1 # any time shuld not be changed with only open return self.fd # shuld return file handle pointer. Can I use inode instead? Then Where shuld i save flags ? def write(self, path, data, offset, fh): ###### write ###### raise FuseOSError(EROFS) # (Read-only file system) def truncate(self, path, length, fh=None): ###### truncate ###### raise FuseOSError(EROFS) # (Read-only file system) ################################################################################################################# # # # AfioLzoFs Function # # # ################################################################################################################# def _filetype(data): pipe=subprocess.Popen("file -" ,shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE) pipe.stdin.write(data); pipe.stdin.close() s=pipe.stdout.read().split(); pipe.stdout.close() return " ".join(s[1:4]) #def _lzop(data,compress=False): # if compress: args=['lzop','-c9'] # else: args=['lzop','-dc'] # proc = subprocess.Popen(args, # stdin=subprocess.PIPE, # stdout=subprocess.PIPE, # close_fds=True, # ) # pid = os.fork() # if pid==0: # child # proc.stdout.close() # proc.stdin.write(data) # proc.stdin.flush() # proc.stdin.close() # os._exit(os.EX_OSERR) # else: # parent # proc.stdin.close() # data=proc.stdout.read() # proc.stdout.close() # return data ################################################################################################################# # # # Header Afio Class # # # ################################################################################################################# class Header_Afio_Base(): ID=6 LEN=0 s1= "" s2= "" def __init__(self,inode): self.inode=inode self.header_address=inode.header_address self.abspath=inode.abspath print afiolzofs def read_data(self,addr,size): f=open(self.abspath,"r") f.seek(addr) data=f.read(size) f.close() return data def print_header(self): print self.s1 print self.s2 print "%s%s" % (self.get_hdr2(),self.get_st_raw_path()) def get_hdr2(self): if not hasattr(self,'hdr2'):self.hdr2=self.read_data(self.header_address+self.ID,self.LEN) return self.hdr2 def get_st_atime(self): return self.get_st_mtime() def get_st_ctime(self): return self.get_st_mtime() def get_st_raw_path(self): return self.read_data(self.header_address+self.ID+self.LEN,self.get_st_nlen()-1) def get_st_data_addr(self): return self.header_address+self.ID+self.LEN+self.get_st_nlen() def get_st_compress(self): path=self.get_st_raw_path() if len(path)<2: return False else: return ((self.get_st_rdev() & 1)==0)and(path[-2:]=='.z') def get_st_path(self): if self.get_st_compress(): return self.get_st_raw_path()[:-2] else: return self.get_st_raw_path() def get_st_size(self): if self.get_st_compress(): return self.get_st_comp_size() else: return self.get_st_raw_size() def get(self,name,default): # x=getattr(self,name,None) if x != None: return x x=getattr(self,'get_'+name,None) if x != None: return x() return default def __getitem__(self,name): # x=getattr(self,name,None) if x != None: return x x=getattr(self,'get_'+name,None) if x != None: return x() print 'ERROR 123' #def __setitem__(self,name,data): # # setattr(self,name,data) def get_st_raw_data(self,offset=0,size=None): data_offset=self.header_address+self.ID+self.LEN+self.get_st_nlen()+offset data_size=self.get_st_raw_size()-offset if size==None: return self.read_data(data_offset,data_size) else: return self.read_data(data_offset,min(data_size,size)) def get_st_data(self,offset=0,size=None): if self.get_st_compress(): if not hasattr(self,'lzop_data'):self.get_st_comp_size() lzop_data=self.lzop_data if size==None:size=lzop_data[-1] endoffset=offset+size for start_block in xrange(0,len(lzop_data)): if offset0:offset=offset-lzop_data[start_block-1] break else: return '' for end_block in xrange(start_block,len(lzop_data)): if endoffset0x0940: lzop_ver_x=1 # 'ext_2' 'level_1' 'mtimeH_4' are exist else: lzop_ver_x=0 # num=14+lzop_ver_x*3 # lib_2 (ext_2) method_1 (level_1) lzop_flags=(ord(s[num])<<24)|(ord(s[num+1])<<16)|(ord(s[num+2])<<8)|ord(s[num+3]) # flags_4 F_H_FILTER=0x00000800L if lzop_flags & F_H_FILTER: lzop_filter_x=1 # 'filter_4' is exist else: lzop_filter_x=0 num=26+lzop_ver_x*7+lzop_filter_x*4 # mode_4 mtimeL_4 (mtimeH_4) lzop_nlen=ord(s[num]) # nlen_1 num=31+lzop_ver_x*7+lzop_filter_x+lzop_nlen # csum_4 F_H_EXTRA_FIELD = 0x00000040L if lzop_flags & F_H_EXTRA_FIELD: # No 'EXTRA_FIELD' in lzop yet lzop_extr=(ord(s[num])<<24)|(ord(s[num+1])<<16)|(ord(s[num+2])<<8)|ord(s[num+3])+8 # extrlen_4 extr_n extr_csum_4 else: lzop_extr=0 lzop_header=s[:31+lzop_ver_x*7+lzop_filter_x+lzop_nlen+lzop_extr] lzop_data_len=0 lzop_raw_len=len(lzop_header) lzop_raw_data=[] lzop_data=[] F_ADLER32_D=0x00000001L F_ADLER32_C=0x00000002L F_CRC32_D=0x00000100L F_CRC32_C=0x00000200L lzop_raw_data.append(lzop_raw_len) while True: if lzop_raw_len>size:raise FuseOSError(EIO) # (I/O error) f.seek(seek+lzop_raw_len) s=f.read(8) num=0;d_len=(ord(s[num])<<24)|(ord(s[num+1])<<16)|(ord(s[num+2])<<8)|ord(s[num+3]) if d_len==0:break num=4;c_len=(ord(s[num])<<24)|(ord(s[num+1])<<16)|(ord(s[num+2])<<8)|ord(s[num+3]) lzop_data_len+=d_len lzop_raw_len+=c_len+8 # lzop if lzop_flags & F_ADLER32_D :lzop_raw_len+=4 if lzop_flags & F_CRC32_D :lzop_raw_len+=4 if d_len>c_len: if lzop_flags & F_ADLER32_C :lzop_raw_len+=4 if lzop_flags & F_CRC32_C :lzop_raw_len+=4 lzop_data.append(lzop_data_len) lzop_raw_data.append(lzop_raw_len) #print "--------> %08x %08x %08x %08x %08x" % (size,lzop_raw_len,lzop_data_len,d_len,c_len) f.close() self.lzop_data=lzop_data self.lzop_raw_data=lzop_raw_data return self.lzop_data[-1] class Header_Afio_070707(Header_Afio_Base): LEN=70 s1= "|23456|23456|23456|23456|23456|23456|23456|23456789ab|23456|23456789ab|..." s2= "| dev| ino| mode| uid| gid|nlink| rdev| mtime|nmlen| size|pathname" def get_st_dev(self): self.get_hdr2();return int(self.hdr2[ 0: 6],8) def get_st_ino(self): self.get_hdr2();return int(self.hdr2[ 6:12],8) def get_st_mode(self): self.get_hdr2();return int(self.hdr2[12:18],8) def get_st_uid(self): self.get_hdr2();return int(self.hdr2[18:24],8) def get_st_gid(self): self.get_hdr2();return int(self.hdr2[24:30],8) def get_st_nlink(self): self.get_hdr2();return int(self.hdr2[30:36],8) def get_st_rdev(self): self.get_hdr2();return int(self.hdr2[36:42],8) def get_st_mtime(self): self.get_hdr2();return int(self.hdr2[42:53],8) def get_st_nlen(self): self.get_hdr2();return int(self.hdr2[53:59],8) def get_st_raw_size(self): self.get_hdr2();return int(self.hdr2[59:70],8) class Header_Afio_070717(Header_Afio_Base): LEN=75 s1= "|23456|23456|23456789ab|23456|23456|23456|23456|23456|23456789ab|23456|23456789ab|..." s2= "| hdr| dev| ino| mode| uid| gid|nlink| rdev| mtime|nmlen| size|pathname" def get_st_dev(self): self.get_hdr2();return int(self.hdr2[ 0: 6],8) def get_st_ino(self): self.get_hdr2();return int(self.hdr2[ 6:17],8) def get_st_mode(self): self.get_hdr2();return int(self.hdr2[17:23],8) def get_st_uid(self): self.get_hdr2();return int(self.hdr2[23:29],8) def get_st_gid(self): self.get_hdr2();return int(self.hdr2[29:35],8) def get_st_nlink(self): self.get_hdr2();return int(self.hdr2[35:41],8) def get_st_rdev(self): self.get_hdr2();return int(self.hdr2[41:47],8) def get_st_mtime(self): self.get_hdr2();return int(self.hdr2[47:58],8) def get_st_nlen(self): self.get_hdr2();return int(self.hdr2[58:64],8) def get_st_raw_size(self): self.get_hdr2();return int(self.hdr2[64:75],8) class Header_Afio_070727(Header_Afio_Base): LEN=110 s1= "|23456|2345678|234567890123456m|23456|2345678|2345678|2345678|2345678|234567890123456n|234|234|234s|234567890123456:|..." s2= "| hdr| dev| inoM| mod| uid| gid| nlink| rdev| mtimeN|nml|flg|xszS| size:|pathname" def get_st_dev(self): self.get_hdr2();return int(self.hdr2[ 0: 8],8) def get_st_ino(self): self.get_hdr2();return int(self.hdr2[ 8:25],8) def get_st_mode(self): self.get_hdr2();return int(self.hdr2[25:31],8) def get_st_uid(self): self.get_hdr2();return int(self.hdr2[31:39],8) def get_st_gid(self): self.get_hdr2();return int(self.hdr2[39:47],8) def get_st_nlink(self): self.get_hdr2();return int(self.hdr2[47:55],8) def get_st_rdev(self): self.get_hdr2();return int(self.hdr2[55:63],8) def get_st_mtime(self): self.get_hdr2();return int(self.hdr2[63:80],8) def get_st_nlen(self): self.get_hdr2();return int(self.hdr2[80:84],8) def get_st_flag(self): self.get_hdr2();return int(self.hdr2[84:88],8) # ??? def get_st_xszS(self): self.get_hdr2();return int(self.hdr2[88:93],8) # ??? def get_st_raw_size(self): self.get_hdr2();return int(self.hdr2[93:110],8) ################################################################################################################# # # # Inode Afio Base Class # # # ################################################################################################################# class Inode_Afio_Base(Inode): def __init__(self,seek=None,abspath=None): self.abspath=abspath # save abspath self.header_address=seek # save first address in the archive def get_inode_data(self,offset=0,size=None): # call from read, if i_data=None data=getattr(self,'i_data',None) if data==None: afio_inode=self.get_default_inode() return afio_inode.get_st_data(offset,size) #if afio_inode.get_st_compress(): # data=afio_inode.get_st_data() # self.i_data=data # fix me! release data #else: return afio_inode.get_st_raw_data(offset,size) if size==None: return data[offset:] # return read data else: return data[offset:(offset + size)] # return read data ################################################################################################################# # # # Inode Afio Class # # # ################################################################################################################# class Inode_Afio_070707(Inode_Afio_Base): # old ASCII magic number def get_default_inode(self): afio_inode=buffers.get(id(self),None) if afio_inode==None: afio_inode=Header_Afio_070707(self) buffers[id(self)]=afio_inode return afio_inode class Inode_Afio_070717(Inode_Afio_Base): # extended ASCII magic number def get_default_inode(self): afio_inode=buffers.get(id(self),None) if afio_inode==None: afio_inode=Header_Afio_070717(self) buffers[id(self)]=afio_inode return afio_inode class Inode_Afio_070727(Inode_Afio_Base): # large ASCII magic number def get_default_inode(self): afio_inode=buffers.get(id(self),None) if afio_inode==None: afio_inode=Header_Afio_070727(self) buffers[id(self)]=afio_inode return afio_inode ################################################################################################################# # # # Load Archive Class # # # ################################################################################################################# class Afio_load(): def __init__(self,target,abspath,fs): self.target=target # path to mount afio file in the file system self.abspath=abspath # abspath of the afio file self.fs=fs # file system self.ino={} # init st_ino(in afio file) Dict pipe=subprocess.Popen('afio -tvBZ "%s"' % self.abspath, shell=True,stdout=subprocess.PIPE).stdout f=open(self.abspath,"r") for line in pipe: i=int(line.split(None,2)[0]) f.seek(i) hdr=f.read(6) self.load_header(i,hdr) f.close() pipe.close() delattr(self,'ino') def load_header(self,seek=None,hdr=''): if hdr=='070707':inode=Inode_Afio_070707(seek=seek,abspath=self.abspath) # old ASCII magic number elif hdr=='070717':inode=Inode_Afio_070717(seek=seek,abspath=self.abspath) # extended ASCII magic number elif hdr=='070727':inode=Inode_Afio_070727(seek=seek,abspath=self.abspath) # large ASCII magic number not implemented yet elif hdr=='070701':return # cpio new ASCII magic number length: 110 not implemented yet elif hdr=='070702':return # cpio new ASCII magic number with CRC not implemented yet elif hdr=='070703':return # Tcpio magic number of TI/E not implemented yet else:return afio_inode=inode.get_default_inode() # get afio_inode afio_inode.print_header() is_dir=False if S_ISDIR(afio_inode.get_st_mode()): # DIR inode.set_nlink(2);is_dir=True # nlink = 2 elif afio_inode.get_st_nlink()>1: # count up st_nlink, if inode is exist afio_ino_key=(afio_inode.get_st_dev(),afio_inode.get_st_ino()) inode2=self.ino.get(afio_ino_key,None) if inode2==None: self.ino[afio_ino_key]=inode # LinkedFile is first time, save inode. else: inode=inode2;inode.inc_nlink() # LinkedFile is second time, use saved inode. path='%s/%s' % (self.target,afio_inode.get_st_path()) self.fs._add_inode_nopermisson(path,inode,dirinode=is_dir) ################################################################################################################# # # # FUSE Operation Afiolzofs Class # # # ################################################################################################################# class Afiolzofs(): """Afio Lzo filesystem. """ def _check_symlink(self,target,source): ####### Symlink Check (root of the file system or not) ####### targetpath=os.path.split(target) if targetpath[0]=="/": # if target is root of the mountpoint sourceabspath=os.path.normpath(os.path.join(self.mountpoint,source)) # get abspath of the file f=open(sourceabspath);top50=f.read(50);f.close() # read top 50 byte of the file # if source is dir? filetype=_filetype(top50) # get file type if "ASCII cpio archive": # if 'ASCII cpio archive' targetname=".%s" % targetpath[1] # 'file name in the file system' for loading afio archive targetdir=os.path.join(targetpath[0],targetname) # 'path name in the file system' for loading afio archive Ramfs.mkdir(self,targetdir, S_IMODE(0755)) # make dir for load the archive Afio_load(targetdir,sourceabspath,self) # load the archive return targetname # afio.lzo file return source # return 'file name in the file system' def _symlink(self, target, source): ###### symlink ###### source=self._check_symlink(target,source) # check root of the file system -> mount afio.lzo Ramfs.symlink(self,target, source) # make normal symlink class Afiolzofs_SymlinkLoading(Afiolzofs): def symlink(self, target, source): ###### symlink ###### self._symlink(target, source) class AfiolzoRamfs(Afiolzofs,Ramfs): pass class AfiolzoRomfs(Afiolzofs,Romfs): pass class AfiolzoSLRamfs(Afiolzofs_SymlinkLoading,Ramfs): pass class AfiolzoSLRomfs(Afiolzofs_SymlinkLoading,Romfs): pass class LogAfiolzoRamfs(LoggingMixIn,Afiolzofs,Ramfs): pass class LogAfiolzoRomfs(LoggingMixIn,Afiolzofs,Romfs): pass class LogAfiolzoSLRamfs(LoggingMixIn,Afiolzofs_SymlinkLoading,Ramfs): pass class LogAfiolzoSLRomfs(LoggingMixIn,Afiolzofs_SymlinkLoading,Romfs): pass ################################################################################################################# # # # Buffers # # # ################################################################################################################# class Buffers(): def __init__(self): self.data={} self.key=[] def get(self,key,default): val=self.data.get(key,None) if val != None:print "exist in the Buffer" else:print "not extst in the Buffer" return val def __setitem__(self,key,val): if not key in self.data: self.key.append(key) self.data[key]=val print "keys:",len(self.key) if len(self.key)>20: i=self.key.pop(0) del self.data[i] ################################################################################################################# # # # Main # # # ################################################################################################################# if __name__ == "__main__": if len(argv) < 2: print 'usage: %s [options] [archives ...] ' % argv[0] print ' "old ASCII cpio archive" or "afio archive" files will be loaded.' print ' (Options) ' print ' --ramfs : allow temporaly write' print ' --nosymlink : do not allow archive loading with symlink' print ' --logging : with logging' print ' --debug : enable debug output (implies -f)' print ' --foreground : foreground operation' print ' --nothreads : disable multi-threaded operation' print ' --allow_other : allow access to other users' print ' --allow_root : allow access to root' print ' --kernel_cache : allow kernel cache' # print ' --direct_io : allow directio (not implemented)' # print ' --big_writes : allow big writes (not implemented)' print ' (Archive loading with symlink)' print ' Please make symlink of the archive file under the to load it.' print ' (Example)' print ' %s mountpoint # mount afiolzofs to mountpoint' % argv[0] print ' ln -s XXX.afio.lzo mountpoint/XXX # make symlink' print ' ls mountpoint/XXX # list the archive' print ' Afiolzofs makes symlink not to the archive, but to mountpoint/.XXX instead,' print ' and loads the archive inode data to mountpoint/.XXX' print ' If you read file contents, Afiolzofs will read it from the archive.' exit(1) args=argv[1:] keyargs={} mountpoint=os.path.abspath(args.pop()) key=('--logging','--nosymlink','--ramfs','--debug','--foreground','--nothreads','--allow_other','--allow_root','--kernel_cache') if key[0] in args: if key[1] in args: if key[2] in args: afiolzofs= LogAfiolzoRamfs(mountpoint) else: afiolzofs= LogAfiolzoRomfs(mountpoint) else: if key[2] in args: afiolzofs= LogAfiolzoSLRamfs(mountpoint) else: afiolzofs= LogAfiolzoSLRomfs(mountpoint) else: if key[1] in args: if key[2] in args: afiolzofs= AfiolzoRamfs(mountpoint) else: afiolzofs= AfiolzoRomfs(mountpoint) else: if key[2] in args: afiolzofs= AfiolzoSLRamfs(mountpoint) else: afiolzofs= AfiolzoSLRomfs(mountpoint) if key[3] in args:keyargs[key[3][2:]]=True if (key[4] in args)or(key[0] in args):keyargs[key[4][2:]]=True if key[5] in args:keyargs[key[5][2:]]=True if key[6] in args:keyargs[key[6][2:]]=True if (key[7] in args)and(not key[6] in args):keyargs[key[7][2:]]=True if key[8] in args:keyargs[key[8][2:]]=True # if key[9] in args:keyargs[key[9][2:]]=True for i in key: while i in args:args.remove(i) buffers=Buffers() for i in args: basename=os.path.basename(i) target=os.path.join(mountpoint,'.'+basename) afiolzofs._symlink(target,i) fuse = FUSE(afiolzofs, mountpoint,use_ino=True,**keyargs)