#!/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.32 (14 Jan 2011) # Header Class # 0.0.31 (09 Jan 2011) # comment # 0.0.30 (09 Jan 2011) # separate inode_buffer,data_buffer # filetype # 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 types import MethodType import copy from sys import argv, exit from time import time 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(): """Inode Class of the Ramfs,Romfs""" 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): # add inode to the dir entry (create it if no i_dentry) i_dentry=getattr(self,'i_dentry',None) if i_dentry==None: self.i_dentry={name:inode} # create dentry & add inode elif hasattr(i_dentry,name): return True # name is exist & return True -> should be error(file exist) else: i_dentry[name]=inode # add inode 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 dir delete check) ### Inode Xattr access functions ### def set_xattr(self,name,val): # add parameter to the xattr entry (create it if no i_xattr) i_xattr=getattr(self,'i_xattr',None) if i_xattr==None: self.i_xattr={name:val} # create xattr & add parameter else: i_xattr[name]=val # add parameter def get_xattr(self,name): return getattr(self,'i_xattr',{})[name] # get xattr entry def pop_xattr(self,name): return getattr(self,'i_xattr',{}).pop(name) # delete xattr entry def ls_xattr(self): return getattr(self,'i_xattr',{}).keys() # list xattr entry ### Inode Set Attr functions ### def set_nlink(self,n=1): if n!=1 or hasattr(self,'st_nlink'): self.st_nlink=n # 'No st_nlink' means st_nlink=1 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 for getting 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')): header=None # called for '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: # no data in the inode if header==None:header=self.get_header() # if no header -> get header from archive file val=header.get(key,0) # read from archive file else:val=len(val) yield (key,val) else: val=getattr(self,key,None) if val==None: # no data in the inode if header==None:header=self.get_header() # if no header -> get header from archive file val=header.get(key,0) # read from archive file yield (key,val) ### Inode File IO functions ### def get_header(self): return {} # dummy header def get_inode_data(self,offset=0,size=None): # data=getattr(self,'i_data',None) if data==None: # no data in the inode -> read from archive file header=self.get_header() # if no header -> get header from archive file if header=={}:return '' # fix me! return header.get_st_data(offset,size) # read from archive file if size==None: return data[offset:] else: return 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) def trunc_inode_data(self,offset): # truncate data length self.i_data=self.get_inode_data(0,offset) ################################################################################################################# # # # Inode Afio Class # # # ################################################################################################################# class Inode_Afio(Inode): """Inode Class of the AfioLzoFs for Old ASCII magic number Header""" def __init__(self,header_address=None,header=None): self.header=header self.header_address=header_address def get_header(self):return self.header.copy(inode=self) ################################################################################################################# # # # FUSE Operation Ramfs Class # # # ################################################################################################################# class Ramfs(Operations): # for normal use """Memory File System Class (Read Write but No Save)""" def __init__(self,mountpoint): self.mountpoint=mountpoint # abspath of the mount point self.fd = 0 # self.uid=os.getuid() # file system owner id self.inode=Inode(time(),(self.uid,os.getgid())) # root inode of the file system self.inode.set_mode(S_IFDIR | 0755) # set as dir self.inode.set_nlink(2) # empty dir nlink is 2 ######## Ramfs function (Permission check) ######## def _is_inode_USER(self,inode,context,uname,items,filesystem=False): # Permission check(file owner,root or filesystem owner) if (context[0]==items[1])or(context[0]==0):return # items='st_mode','st_uid','st_gid' 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): # Permission check(Readable) if items[0] & S_IROTH: return # allow other if (items[0] & S_IRUSR) and (items[1] == context[0]): return # allow owner & I'm owner if not(items[0] & S_IRGRP): raise FuseOSError(EACCES) # don't allow group if uname in grp.getgrgid(items[2]).gr_mem: return # user is the group member if context[1] != items[2]: raise FuseOSError(EACCES) # group is not same def _is_inode_W_OK(self,inode,context,uname,items): # Permission check(writable) if items[0] & S_IWOTH: return # allow other if (items[0] & S_IWUSR) and (items[1] == context[0]): return # allow owner & I'm owner if not (items[0] & S_IWGRP): raise FuseOSError(EACCES) # don't allow group if uname in grp.getgrgid(items[2]).gr_mem: return # user is the group member if context[1] != items[2]: raise FuseOSError(EACCES) # group is not same def _is_inode_X_OK(self,inode,context,uname,items): # Permission check(Excutable) if items[0] & S_IXOTH: return # allow other if (items[0] & S_IXUSR) and (items[1] == context[0]): return # allow owner & I'm owner if not(items[0] & S_IXGRP): raise FuseOSError(EACCES) # don't allow group if uname in grp.getgrgid(items[1]).gr_mem: return # user is the group member if context[1] != items[1]: raise FuseOSError(EACCES) # group is not same ######## Ramfs function (Get inode with Permission check) ######## def _get_dir_inode_nopermisson(self,path): ###### Get inode without any permission checking ###### if path=="/":return self.inode # if path is root, return root inode of the file system pname=os.path.split(path) inode_dir=self._get_dir_inode_nopermisson(pname[0]) try:return 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=="/":return self.inode # if path is root, return root inode of the file system 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:return 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) 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): """Memory File System Class (Read only)""" def _update_atime(self,inode,now): pass # no update atime ######## 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): raise FuseOSError(EROFS) # (Read-only file system) def chown(self, path, uid, gid): raise FuseOSError(EROFS) # (Read-only file system) def utimens(self, path, times=None): raise FuseOSError(EROFS) # (Read-only file system) ######## FUSE Operating function (XAttr) ######## def setxattr(self, path, name, value, options, position=0): 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): raise FuseOSError(EROFS) # (Read-only file system) def rmdir(self, path): raise FuseOSError(EROFS) # (Read-only file system) ######## FUSE Operating function (Create or Remove File) ######## def mknod(self, path, mode, dev): raise FuseOSError(EROFS) # (Read-only file system) def create(self, path, mode): raise FuseOSError(EROFS) # (Read-only file system) def unlink(self, path): raise FuseOSError(EROFS) # (Read-only file system) def rename(self, old, new): raise FuseOSError(EROFS) # (Read-only file system) def link(self, target, source): raise FuseOSError(EROFS) # (Read-only file system) ######## FUSE Operating function (Sym Link) ######## def symlink(self, target, source): 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 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): raise FuseOSError(EROFS) # (Read-only file system) def truncate(self, path, length, fh=None): 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= "" header_base_buffer={} def __init__(self,abspath): self.abspath=abspath def print_header(self): print self.s1 print self.s2 print "%s%s" % (self._get_hdr2(),self.get_st_path()) def init(self,inode): self.inode=inode header_address=inode.header_address+self.ID self.header_address=header_address self.hdr2=self._read_data(header_address,self.LEN) def copy(self,inode): inode_id=id(inode) copied_header=header_buffers.get(inode_id) # try to get from header buffer if copied_header==None: copied_header=copy.copy(self) copied_header.init(inode) header_buffers.add(inode_id,copied_header) # add header to header buffer return copied_header 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' #### get Header Data Function #### def get_st_path(self): # path is read once when archive is loaded if self.get_st_compress(): return self._read_data(self.header_address+self.LEN,self.get_st_nlen()-3) else: return self._read_data(self.header_address+self.LEN,self.get_st_nlen()-1) def get_st_compress(self): st_compress=getattr(self,'st_compress',None) if st_compress != None:return st_compress st_nlen=self.get_st_nlen() # st_nlen= name length +1 if st_nlen<=3:st_compress=False else: path=self._read_data(self.header_address+self.LEN+st_nlen-3,2) if (path=='.z') and ((self.get_st_rdev() & 1)==0):st_compress=True else:st_compress=False self.st_compress=st_compress # store the data self.inode.header=self._copy_base() # change inode header fot next time return st_compress def get_st_comp_size(self): return self._get_lzop_data_size() 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_st_raw_data(self,offset=0,size=None): data_offset=self._get_data_address()+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_comp_data(self,offset=0,size=None): print "comp data",len(self._get_lzop_data(offset,size)) return self._get_lzop_data(offset,size) def get_st_data(self,offset=0,size=None): if self.get_st_compress(): return self.get_st_comp_data(offset,size) else: return self.get_st_raw_data(offset,size) #### Local Function #### def _copy_base(self): # make new header for next time keys=['abspath','st_compress','lzop_header_size','lzop_flags'] header_id=[id(self.__class__)] for key in keys:header_id.append(getattr(self,key,None)) copied_header=self.header_base_buffer.get(tuple(header_id)) # try to get from header base buffer if copied_header==None: copied_header=copy.copy(self.inode.header) for key in keys:setattr(copied_header,key,getattr(self,key,None)) return copied_header def _read_data(self,addr,size): # read archive file f=open(self.abspath,"r") f.seek(addr) data=f.read(size) f.close() return data def _get_hdr2(self,name='',s=0,e=0): # get hdr2 parameter if name != '': val=getattr(self,name,None) if val==None: if not hasattr(self,'hdr2'):self.hdr2=self._read_data(self.header_address,self.LEN) val=int(self.hdr2[s:e],8);setattr(self,name,val) return val if e != 0: if not hasattr(self,'hdr2'):self.hdr2=self._read_data(self.header_address,self.LEN) return int(self.hdr2[s:e],8) return self.hdr2 def _get_data_address(self): return self.header_address+self.LEN+self.get_st_nlen() ### lzop functions ### def _get_lzop_header_size(self): # get lzop header length & flags lzop_header_size=getattr(self,'lzop_header_size',None) if lzop_header_size !=None: return lzop_header_size,self.lzop_flags #size=self.get_st_raw_size() f=open(self.abspath) f.seek(self._get_data_address()) s=f.read(512) # enough length is 42byte in afio, because no filename. f.close() num= 9 # 89 4c 5a 4f 00 0d 0a 1a 0a #lzop file signature lzop_ver=(ord(s[num])<<8)|ord(s[num+1]) # ver_2 if lzop_ver>0x0940: 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_size=31+lzop_ver_x*7+lzop_filter_x+lzop_nlen+lzop_extr if lzop_nlen==0: # if lzop_nlen is 0 self.lzop_header_size=lzop_header_size # store size and flags self.lzop_flags=lzop_flags # self.inode.header=self._copy_base() # change inode's header for next time return lzop_header_size,lzop_flags def _get_lzop_data_size(self): # get lzop data block length (compressed & decompressed) lzop_data=getattr(self,'lzop_data',None) if lzop_data != None:return self.lzop_data[-1] lzop_raw_len,lzop_flags=self._get_lzop_header_size() lzop_data_len=0 seek=self._get_data_address() size=self.get_st_raw_size() f=open(self.abspath) 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 1: # sum each block size 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 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] def _get_lzop_data(self,offset=0,size=None): # get lzop data if not hasattr(self,'lzop_data'):self.get_st_comp_size() # to get compressed block 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 '' # read after the end -> return '' for end_block in xrange(start_block,len(lzop_data)): if endoffset",len(data) return data[offset:(offset+size)] def _get_lzop_data_block_buffered(self,i): # decompress lzop data block (buffered) key=(id(self.inode),i) # make key data_block=data_buffers.get(key) # try to get block from buffer if data_block==None: data_block=self._get_lzop_data_block(i) data_buffers.add(key,data_block) return data_block def _get_lzop_data_block(self,i): # decompress lzop data block lzop_raw_data=self.lzop_raw_data args=['lzop','-dc'] proc = subprocess.Popen(args,stdin=subprocess.PIPE,stdout=subprocess.PIPE,close_fds=True,) # make subprocess(lzop -dc) for decompress pid = os.fork() # fork if pid==0: # child (read compressed data and send then to lzop) proc.stdout.close() data=self.get_st_raw_data(0,self.lzop_raw_data[0]) # lzop header proc.stdin.write(data) data=self.get_st_raw_data(lzop_raw_data[i],lzop_raw_data[i+1]-lzop_raw_data[i]) # one of the lzop data block proc.stdin.write(data) proc.stdin.write('\0\0\0\0') # lzop data end proc.stdin.flush() proc.stdin.close() os._exit(os.EX_OSERR) else: # parent (read decompressed data from lzop) proc.stdin.close() data_block=proc.stdout.read() proc.stdout.close() return data_block # fix me! if data is broken -> error -> raise IOERROR 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): return self._get_hdr2('' , 0, 6) def get_st_ino(self): return self._get_hdr2('' , 6,12) def get_st_mode(self): return self._get_hdr2('st_mode' ,12,18) def get_st_uid(self): return self._get_hdr2('st_uid' ,18,24) def get_st_gid(self): return self._get_hdr2('st_gid' ,24,30) def get_st_nlink(self): return self._get_hdr2('' ,30,36) def get_st_rdev(self): return self._get_hdr2('st_rdev' ,36,42) def get_st_mtime(self): return self._get_hdr2('mtime' ,42,53) def get_st_nlen(self): return self._get_hdr2('st_nlen' ,53,59) def get_st_raw_size(self): return self._get_hdr2('st_raw_size' ,59,70) get_st_atime=get_st_mtime get_st_ctime=get_st_mtime 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): return self._get_hdr2('' , 0, 6) def get_st_ino(self): return self._get_hdr2('' , 6,17) def get_st_mode(self): return self._get_hdr2('st_mode' ,17,23) def get_st_uid(self): return self._get_hdr2('st_uid' ,23,29) def get_st_gid(self): return self._get_hdr2('st_gid' ,29,35) def get_st_nlink(self): return self._get_hdr2('' ,35,41) def get_st_rdev(self): return self._get_hdr2('st_rdev' ,41,47) def get_st_mtime(self): return self._get_hdr2('mtime' ,47,58) def get_st_nlen(self): return self._get_hdr2('st_nlen' ,58,64) def get_st_raw_size(self): return self._get_hdr2('st_raw_size' ,64,75) get_st_atime=get_st_mtime get_st_ctime=get_st_mtime 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): return self._get_hdr2('' , 0, 8) def get_st_ino(self): return self._get_hdr2('' , 8,25) def get_st_mode(self): return self._get_hdr2('st_mode' ,25,31) def get_st_uid(self): return self._get_hdr2('st_uid' ,31,39) def get_st_gid(self): return self._get_hdr2('st_gid' ,39,47) def get_st_nlink(self): return self._get_hdr2('' ,47,55) def get_st_rdev(self): return self._get_hdr2('st_rdev' ,55,63) def get_st_mtime(self): return self._get_hdr2('mtime' ,63,80) def get_st_nlen(self): return self._get_hdr2('st_nlen' ,80,84) def get_st_flag(self): return self._get_hdr2('' ,84,88) # ??? def get_st_xszS(self): return self._get_hdr2('' ,88,93) # ??? def get_st_raw_size(self): return self._get_hdr2('st_raw_size' ,93,110) get_st_atime=get_st_mtime get_st_ctime=get_st_mtime ################################################################################################################# # # # Load Archive Class # # # ################################################################################################################# class Afio_load(): """Load afio file(abspath) to target path in the filesystem""" def __init__(self,target,abspath,filesystem): self.header_070707=Header_Afio_070707(abspath) self.header_070717=Header_Afio_070717(abspath) self.header_070727=Header_Afio_070727(abspath) self.target=target # path to mount afio file in the file system self.fs=filesystem # file system self.ino={} # init st_ino(in afio file) Dict pipe=subprocess.Popen('afio -tvBZ "%s"' % abspath, shell=True,stdout=subprocess.PIPE).stdout f=open(abspath,"r") for line in pipe: i=int(line.split(None,2)[0]) # get header address in the archive file 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(seek,self.header_070707) # Old ASCII magic number elif hdr=='070717':inode=Inode_Afio(seek,self.header_070717) # Extended ASCII magic number elif hdr=='070727':inode=Inode_Afio(seek,self.header_070727) # Large ASCII magic number 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 header=inode.get_header() # get header header.print_header() is_dir=False if S_ISDIR(header.get_st_mode()): # 'DIR' inode.set_nlink(2);is_dir=True # nlink = 2 elif header.get_st_nlink()>1: # 'not DIR' and 'Hard Linked' ino_key=(header.get_st_dev(),header.get_st_ino()) inode2=self.ino.get(ino_key,None) if inode2==None: self.ino[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,header.get_st_path()) self.fs._add_inode_nopermisson(path,inode,dirinode=is_dir) ################################################################################################################# # # # FUSE Operation Afiolzofs Class # # # ################################################################################################################# class Afiolzofs(): """Base Class of the 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 filesystem sourceabspath=os.path.normpath(os.path.join(self.mountpoint,source)) # get abspath of the file # fix me! frozen if afio file is in this filesystem 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 filetype=="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): """Base Class of the Afio Lzo Filesystem with SymlinkLoading option""" def symlink(self, target, source):self._symlink(target, source) ###### symlink ###### ### Real File System Class ### 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,num1=10,num2=10): self.num1=num1 self.num2=num2 self.data1={} self.key1=[] self.data2={} self.key2=[] def get(self,key,default=None): # fix me! if inode is same address deleted inode val=self.data1.get(key,None) if val != None: print "exist in the Buffer1" else: val=self.data2.pop(key,None) if val != None: self.key2.remove(key) # fix me! key2 is list -> slow self.add(key,val) print "exist in the Buffer2" else: print "not extst in the Buffer" return val def add(self,key,val): if not key in self.data1: self.key1.append(key) self.data1[key]=val print "key1,key2:",len(self.key1),len(self.key2) while len(self.key1)>self.num1: key=self.key1.pop(0) val=self.data1.pop(key) if not key in self.data2: self.key2.append(key) self.data2[key]=val while len(self.key2)>self.num2: key=self.key2.pop(0) val=self.data2.pop(key) ################################################################################################################# # # # Main # # # ################################################################################################################# if __name__ == "__main__": if len(argv) < 2: # print usage 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:] mountpoint=os.path.abspath(args.pop()) key=('--logging','--nosymlink','--ramfs','--debug','--foreground','--nothreads','--allow_other','--allow_root','--kernel_cache') if key[0] in args: # select file system 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) keyargs={} # args for FUSE 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: # delete overlaped arguments from 'args' while i in args:args.remove(i) # data_buffers=Buffers(20,20) # data buffer # fix me! global -> header header_buffers=Buffers(50,50) # header buffer # fix me! global -> header for i in args: # mount afio files in the 'args' basename=os.path.basename(i) # make symlink name target=os.path.join(mountpoint,'.'+basename) # make 'target dir' name afiolzofs._symlink(target,i) # load afio file to the 'target dir' fuse = FUSE(afiolzofs, mountpoint,use_ino=True,**keyargs) # fuse operation start