コード例 #1
0
ファイル: inferatoFS.py プロジェクト: shaziajaved/InferatoFS
 def __init__(self, *args, **kw):
     Fuse.__init__(self, *args, **kw)
     self.root = '/'
     self.state = StateUtils();
コード例 #2
0
ファイル: inferatoFS.py プロジェクト: shaziajaved/InferatoFS
class InferatoFS(Fuse):#TODO: refactor this
    #Fuse has no information about the usage of these files.   
    forbidden = ["autorun.inf", ".Trash", ".Trash-1000", "BDMV", ".xdg-volume-info", ".directory", ".krcdirs", ".kateconfig"]
    #True - disable VF + sequence deleting functionality for this flag
    hide_vfs = False

    def __init__(self, *args, **kw):
        Fuse.__init__(self, *args, **kw)
        self.root = '/'
        self.state = StateUtils();
        #uncomment this to see what operation are supported
        #print Fuse._attrs

    def getattr(self, path):
        if os.path.split(path)[1] in self.forbidden:
            #ignore this stuff
            #TODO: find the right way of usage 
            pass        
        else:
            #capture the case, when user follows the symbolic link.
            if Parser(path).isMetaLink():
                st = MyStat()
                st.st_mode = stat.S_IFDIR | 0777
                st.st_nlink = 5
                return st
            elif not self.hide_vfs:               
                if Parser(path).isLenghFile():
                    st = MyStat()
                    st.st_mode = stat.S_IFREG 
                    st.st_nlink = 1
                    st.st_size = len(str(len(PathUtils(path).getName())))
                    return st
                elif str(path).endswith(FSTemplates.file_type):
                    st = MyStat()
                    st.st_mode = stat.S_IFREG 
                    st.st_nlink = 1
                    st.st_size = 0
                    return st
                elif str(path).endswith(FSTemplates.email_message):
                    st = MyStat()
                    st.st_mode = stat.S_IFREG 
                    st.st_nlink = 1
                    st.st_size = 0
                    return st
                else:
                    return os.lstat("." + path)
            return os.lstat("." + path)

    def readlink(self, path):        
        return os.readlink("." + path)
    
    def writeInferatoFSEmail(self, emailMessage):
        emailMessage.storagePath = emailMessage.storagePath + TransformerTemplate.forwardSlash
        
        #Create Message ID File
        if emailMessage.emailHeader._messageID != None:
            fileHandler = open(emailMessage.storagePath + TransformerTemplate._messageID, TransformerTemplate.fileWrite)
            fileHandler.write(emailMessage.emailHeader._messageID)
            fileHandler.close()
        
        #Create From File
        fileHandler = open(emailMessage.storagePath + TransformerTemplate._from, TransformerTemplate.fileWrite)
        if(emailMessage.emailHeader._from.fullName != emailMessage.emailHeader._from.emailAddress):
            fileHandler.write(emailMessage.emailHeader._from.fullName + TransformerTemplate.newLine)
        fileHandler.write(emailMessage.emailHeader._from.emailAddress)
        fileHandler.close()
        
        #Create Sender File
        if (emailMessage.emailHeader._sender != None and emailMessage.emailHeader._sender.fullName != TransformerTemplate.emptyString 
            and emailMessage.emailHeader._sender.emailAddress != TransformerTemplate.emptyString):
            fileHandler = open(emailMessage.storagePath + TransformerTemplate._sender, TransformerTemplate.fileWrite)
            if(emailMessage.emailHeader._sender.fullName != emailMessage.emailHeader._sender.emailAddress):
                fileHandler.write(emailMessage.emailHeader._sender.fullName + TransformerTemplate.newLine)
            fileHandler.write(emailMessage.emailHeader._sender.emailAddress)
            fileHandler.close()
        
        #Create Subject File
        if emailMessage.emailHeader._subject != None:
            fileHandler = open(emailMessage.storagePath + TransformerTemplate._subject, TransformerTemplate.fileWrite)
            fileHandler.write(emailMessage.emailHeader._subject)
            fileHandler.close()
            
        #Create Date File
        if emailMessage.emailHeader._dateTime != None:
            fileHandler = open(emailMessage.storagePath + TransformerTemplate._date, TransformerTemplate.fileWrite)
            fileHandler.write(emailMessage.emailHeader._dateTime)
            fileHandler.close()
        
        #Create Header File
        if emailMessage.actualFileName != None:
            headerFileName = TransformerTemplate.header + emailMessage.actualFileName
            #print "Header Path: " + emailMessage.storagePath + headerFileName
            fileHandler = open(emailMessage.storagePath + headerFileName, TransformerTemplate.fileWrite)
            fileHandler.write(emailMessage.entireHeader)
            fileHandler.close()
                
        #Create Body File
        if emailMessage.emailBody != None:
            fileHandler = open(emailMessage.storagePath + TransformerTemplate.body + emailMessage.emailBody._extension, TransformerTemplate.fileWrite)
            fileHandler.write(emailMessage.emailBody._body)
            fileHandler.close()
        
            #Create To Folder and Store Contacts
            if len(emailMessage.emailHeader._to) != 0:
                if not os.path.exists(emailMessage.storagePath + TransformerTemplate._to):
                    os.mkdir(emailMessage.storagePath + TransformerTemplate._to)
                    
                toPath = emailMessage.storagePath + TransformerTemplate._to + TransformerTemplate.forwardSlash
                
                for toContact in emailMessage.emailHeader._to:
                    fileHandler = open(toPath + toContact.fullName, TransformerTemplate.fileWrite)
                    if(toContact.fullName != toContact.emailAddress):
                        fileHandler.write(toContact.fullName + TransformerTemplate.newLine)
                    fileHandler.write(toContact.emailAddress)
                    fileHandler.close()
                            
            #Create Cc Folder and Store Contacts
            if len(emailMessage.emailHeader._cc) != 0:
                if not os.path.exists(emailMessage.storagePath + TransformerTemplate._cc):
                    os.mkdir(emailMessage.storagePath + TransformerTemplate._cc)
                    
                ccPath = emailMessage.storagePath + TransformerTemplate._cc + TransformerTemplate.forwardSlash
                
                for ccContact in emailMessage.emailHeader._cc:
                    fileHandler = open(ccPath + ccContact.fullName, TransformerTemplate.fileWrite)
                    if(ccContact.fullName != ccContact.emailAddress):
                        fileHandler.write(ccContact.fullName + TransformerTemplate.newLine)
                    fileHandler.write(ccContact.emailAddress)
                    fileHandler.close()
                    
            #Create Bcc Folder and Store Contacts
            if len(emailMessage.emailHeader._bcc) != 0:
                if not os.path.exists(emailMessage.storagePath + TransformerTemplate._bcc):
                    os.mkdir(emailMessage.storagePath + TransformerTemplate._bcc)
                    
                bccPath = emailMessage.storagePath + TransformerTemplate._bcc + TransformerTemplate.forwardSlash
                
                for bccContact in emailMessage.emailHeader._bcc:
                    fileHandler = open(bccPath + bccContact.fullName, TransformerTemplate.fileWrite)
                    if(bccContact.fullName != bccContact.emailAddress):
                        fileHandler.write(bccContact.fullName + TransformerTemplate.newLine)
                    fileHandler.write(bccContact.emailAddress)
                    fileHandler.close()
            
            #Create Attachments Folder and Store Attachments
            if len(emailMessage.emailBody._attachments) != 0:
                if not os.path.exists(emailMessage.storagePath + TransformerTemplate.attachments):
                    os.mkdir(emailMessage.storagePath + TransformerTemplate.attachments)
                
                if True: #self.duplicate != TransformerTemplate.attachmentsOnly:
                    attachmentsPath = emailMessage.storagePath + TransformerTemplate.attachments + TransformerTemplate.forwardSlash
                    
                    for attachment in emailMessage.emailBody._attachments:
                        fileHandler = open(attachmentsPath + attachment.attachmentName, TransformerTemplate.fileWrite)
                        fileHandler.write(attachment.attachedFile)
                        fileHandler.close()
                    
            del fileHandler
         
        return
    
    def readdir(self, path, offset):        
        global transform, transformer, duplicatePaths
        emailMessage = EmailMessage()
        
        yield fuse.Direntry(".")
        yield fuse.Direntry("..")
        
        if Parser(path).isMetaFolder():
            if not self.hide_vfs:
                # wanted to change the passed argument from 'file_len' to 'file_type
                #print "(1) " + path
                yield fuse.Direntry(FSTemplates.file_len)
                yield fuse.Direntry(FSTemplates.file_type)
                
                folder = path[str(path).rfind(os.sep):]
                if str(folder).find("From:") != -1 and str(folder).find("To:") != -1: 
                    yield fuse.Direntry(FSTemplates.email_message)
                
        if os.path.exists("." + path):
            for e in os.listdir("." + path):
                if transform:
                    #Check file type for email files
                    fileType = determineFileType(self, "." + path + TransformerTemplate.forwardSlash + e)
                    
                    #Process email file if found
                    if emailMessage and emailMessage.actualFileName and e.__eq__(emailMessage.actualFileName + FSTemplates._suffix):
                        pass
                    elif str(fileType).endswith(TransformerTemplate.email_message):
                        if str.find(e, TransformerTemplate.header) == -1:
                            transformer.workingPath = self.root + path + TransformerTemplate.forwardSlash + e
                            transformer.outputPath = emailMessage.pathToParent = "." + path + TransformerTemplate.forwardSlash
                            
                            #Read Input Email File
                            emailMessage.readEmailMessage(transformer)
                            
                            #Prepare Output Folder Name and Duplicity Count
                            emailMessage.prepareFolderName()
                            messageList = emailMessage.hashEmailMessage(transformer)        
                            emailNumber = emailMessage.occurenceNumber
                            if emailNumber != 0:
                                emailMessage.folderName += "[%(emailNumber)s]" % locals()        
                                
                                #Storage Path ~ Parent Folder for InferatoFS Email
                                emailMessage.storagePath = transformer.outputPath + emailMessage.folderName
                                
                                #Determine Nature of Duplication
                                if emailMessage.occurenceNumber != 1:
                                    emailMessage.determineDuplicate(messageList, transformer)
                                    #print emailMessage.duplicate + " - " + duplicate
                                    
                                if (os.path.exists(transformer.outputPath) and not os.path.exists(emailMessage.storagePath)
                                    and str(transformer.outputPath).find(emailMessage.folderName) == -1 
                                    ):#and emailMessage.duplicate != TransformerTemplate.absolute):
                                    #yield fuse.Direntry(emailMessage.folderName)
                                    if emailMessage.duplicate != TransformerTemplate.absolute:
                                        #print "Duplicate not found!"
                                        os.mkdir(emailMessage.storagePath)
                                        self.writeInferatoFSEmail(emailMessage)
                                    else:
                                        #os.mkdir(emailMessage.storagePath)
                                        self.symlink(os.path.realpath(emailMessage.duplicatePath), transformer.outputPath[1:] + emailMessage.folderName)
                                        
                                if emailMessage.duplicate != None and emailMessage.duplicate == TransformerTemplate.absolute:
                                    #os.link(emailMessage.duplicatePath, emailMessage.storagePath)
                                    #os.mkdir(emailMessage.storagePath[:-1] + FSTemplates._suffix)
                                    
                                    #You can't create a link on Mount's #. For renaming store the duplicate's path in global
                                    #and call rename after the # folder has been read and corresponding link on actual has been
                                    #created
                                    #print "Key: " + emailMessage.folderName[:-3]
                                    if emailMessage.folderName[:-3] not in duplicatePaths:
                                        duplicatePaths[emailMessage.folderName[:-3]] = emailMessage.duplicatePath 
                        else:
                            #For writing Header Files
                            yield fuse.Direntry(e)
                    elif not os.path.islink(e):
                        yield fuse.Direntry(e)
                        #print "Movement allowed for " + e
                        #if (str(e[-5:-4]).isdigit() and e[-6:-5] == TransformerTemplate.openingSquareBracket 
                            #and e[-4:-3] == TransformerTemplate.closingSquareBracket and e[-5:-4] != "1"):
                        if re.search("\[[2-9]\]\[\#\]\Z", e) != None:
                            hashedName = e[str.find(e, os.sep)+1:-6]
                            #print "Hash Key: " + hashedName
                            #print "Duplicate Path: " + duplicatePaths[hashedName]
                            if hashedName in duplicatePaths:
                                #print "Duplicate Path: " + duplicatePaths[hashedName]
                                self.rename(e[:-3], duplicatePaths[hashedName][:-1] + FSTemplates._suffix + os.sep + e[:-3])
                    else:
                        #print "(2) " + e
                        yield fuse.Direntry(e)
                else:
                    #print "\n(3) " + e
                    yield fuse.Direntry(e)
                    
                    if re.search("\[[2-9]\]\[\#\]\Z", e) != None:
                        ePath = self.root + path + TransformerTemplate.forwardSlash + e[:-3]
                        #print "Full Path: " + ePath
                        fileType = determineFileType(self, ePath)
                        #print "File Type is " + str(fileType)
                        if fileType != None and str.find(str.lower(fileType), "link") != -1:
                            pointedPath = fileType[str.find(fileType, os.sep):-1]
                            #print "Pointed Path is " + str(pointedPath[len(self.root):-1])
                            self.rename(e[:-3], "." + pointedPath[len(self.root):-1] + FSTemplates._suffix + os.sep + e[:-3])     
    #delete
    def unlink(self, path):
        if Parser(path).isMeta():
            
            if Parser(path).isTagFolder():                
                untagInMeta(self, self.getabs(path))                
                return
            
            elif Parser(path).isLenghFile():
                #do nothing since it is a virtual file
                return
            
            if self.state.cur_state[0] == 3:                
                #allow deleting VF for action 3    
                return
            print "Can not unlink " + str(path) + ". It is a system file."
            return
        else:
            mode = os.lstat("." + path)[0]
            #self.hide_vfs=True also means that first usr call was rmdir 
            #(folders could also contain meta-data links)
            if not self.hide_vfs:
                # if regular file, then delete meta-data before
                if  (mode & stat.S_IFREG) and (mode < stat.S_IFLNK):
                    metalink = os.path.realpath(self.root + path + FSTemplates._suffix)
                    os.unlink("." + path + FSTemplates._suffix)
                    shutil.rmtree(metalink)
            else:
                if Parser(path).isMeta() and (mode & stat.S_IFLNK) and (mode >= stat.S_IFLNK):
                    metalink = os.path.realpath(self.root + path)
                    shutil.rmtree(metalink)
        os.unlink("." + path)



    def rmdir(self, path):
        if Parser(path).isMeta():
            tulpe = PathUtils(self.getabs(path)).isAloneLink()
            print tulpe
            if tulpe[0]:
                untagInMeta(self, tulpe[1])
                return
            print " rmdir, this operation is restricted for path: " + path
        else:
            #disable temporary all virtual files
            self.hide_vfs = True
            metalink = os.path.realpath(self.root + path + FSTemplates._suffix)
            if os.path.exists("." + path + FSTemplates._suffix):
                os.unlink("." + path + FSTemplates._suffix)
            if os.path.exists(metalink):
                shutil.rmtree(metalink)
            os.rmdir("." + path)
            #enable vfiles
            
            self.hide_vfs = False

    def symlink(self, path, path1):
        #print "symlink - path: " + path
        #print "symlink - path1: " + path1
        
        #print "Path Exists: " + str(os.path.exists(path))
        #print "Path1 Exists: " + str(os.path.exists("." + path1))
                
        if Parser(path).isMeta():
            print "symlink: this operation is restricted for path: " + path
        else:
            os.symlink(path, "." + path1)

    def rename(self, path, path1):        
        
        print "Path: " + path
        print "Path1: " + path1
        
        #path to tag
        path_abs = self.getabs(path)
        
        #if not os.path.exists(path_abs):
            #pass
        
        #path of link in tags folder
        path1_abs = self.getabs(path1)
                    
        # equals to "[suffix]/tags"
        suf = FSTemplates._suffix + os.sep + FSTemplates.folder_tags
               
        # get ../tags abs_path
        path1_abs_minus = os.path.split(path1_abs)[0]
             
        # eliminate FSTemplates._suffix and get origin if exists
        path1_abs_minus_orig = str(path1_abs_minus).split(FSTemplates._suffix)[0]
                
        #destination root
        s = os.path.split(path1_abs)[0]
        
        print "====="
        
        #target and tag are equals
        if str(path_abs).__eq__(path1_abs_minus_orig):
            print "Can not tag itself!"
            return
                
        #expected sample input for path: [regular file/dir] and ...[FSTemplates._suffix]/[file/dir] where last one is metalink of directory
        if str(path1_abs_minus).endswith(FSTemplates._suffix) and not Parser(path_abs).isMeta() and os.path.isdir(path1_abs_minus_orig):
            print "tagging: multiple targets"
            self.state.initAction(1)
            self.state.next()
            tag(self, path_abs, path1_abs_minus_orig)
            self.state.finishAction()
        #expected sample input for path: ...[FSTemplates._suffix]/tags and [regular directory]
        elif os.path.isdir(path_abs):            
            print "tagging: multiple tags"
            self.state.initAction(2)
            self.state.next()            
            #already tagged with this name case
            if os.path.exists(str(path1_abs_minus + os.sep + os.path.split(path_abs)[1])):
                print str(path1_abs_minus + os.sep + os.path.split(path_abs)[1])
                print "Can not tag " + path1_abs_minus_orig + " with " + path_abs + ". You already tagged it with this name. Please, untag it first and then repeat."
            if  Parser(s).isTagFolder():                
                #candidate for tag can not be a special file/folder
                self.state.next()
                self.state
                if not Parser(path).isMeta():                    
                    obj_path = str(path1_abs).split(suf)[0]
                    self.state.next()
                    tag(self, obj_path, path_abs)
                    self.state.finishAction()
                else:
                    print "Restricted operation for tagging"
            else:
                print " forbidden operation for tagging: " + s + " is not a special folder as expected"
                #Still a Question: Should we actually allow the folder movement without considering various scenarios?
                print "Path-Suffix: ." + path + FSTemplates._suffix, "- ." + path1 + FSTemplates._suffix
                print "Just-Path: ." + path, "." + path1
                os.rename("." + path + FSTemplates._suffix, "." + path1 + FSTemplates._suffix)
                os.rename("." + path, "." + path1)
                
                #fix the broken link
                if os.path.isdir(s):
                    fixTaggedLink(self, s, path, path1) 

        elif Parser(path).isMeta() or Parser(path1).isMeta():
            print "rename: this operation is restricted for path " + path
        else:
            print "Here!"
            
            os.rename("." + path + FSTemplates._suffix, "." + path1 + FSTemplates._suffix)
            os.rename("." + path, "." + path1)
            
            if os.path.isdir(s):
                fixDeletedLink(self, s, path, path1)  
            
    def link(self, path, path1):
        #print "link - path: " + path
        #print "link - path1: " + path1
        
        os.link("." + path, "." + path1)

    def chmod(self, path, mode):
        if Parser(path).isMeta():
            print "chmod: this operation is restricted for path " + path
        else:
            os.chmod("." + path, mode)

    def chown(self, path, user, group):
        os.chown("." + path, user, group)

    def truncate(self, path, len):
        f = open("." + path, "a")
        f.truncate(len)
        f.close()

    def mknod(self, path, mode, dev):
        #print "mknod - path: " + path
        os.mknod("." + path, mode, dev)

    def mkdir(self, path, mode):
        if Parser(path).isMeta():
            print "mkdir: this operation is restricted for path " + path
        else:
            os.mkdir("." + path, mode)

    def utime(self, path, times):
        os.utime("." + path, times)

    def access(self, path, mode):
        #print "access - path: " + path
        if Parser(path).isMeta():
            pass
        elif not os.access("." + path, mode):
            #TODO: do custom access controls
            return -EACCES
            pass
        if not Parser(path).isMeta():
            checkMeta(self, path)
            #print "Done with checkMeta!"

    def statfs(self):
        """
        Should return an object with statvfs attributes (f_bsize, f_frsize...).
        Eg., the return value of os.statvfs() is such a thing (since py 2.2).
        If you are not reusing an existing statvfs object, start with
        fuse.StatVFS(), and define the attributes.

        To provide usable information (ie., you want sensible df(1)
        output, you are suggested to specify the following attributes:

            - f_bsize - preferred size of file blocks, in bytes
            - f_frsize - fundamental size of file blcoks, in bytes
                [if you have no idea, use the same as blocksize]
            - f_blocks - total number of blocks in the filesystem
            - f_bfree - number of free blocks
            - f_files - total number of file inodes
            - f_ffree - number of free file inodes
        """
        return os.statvfs(".")
    
    def fsinit(self):
        os.chdir(self.root)
        #TODO: make possible to resolve also relative path with data and mount folders
        if os.path.exists(FSTemplates._meta_storage):
            print " meta-storage found in '" + self.root + "'"
        else:
            print "creating meta-storage '" + self.root + "' ..."
            os.mkdir(FSTemplates._meta_storage)
            print "...done"
            
    #for local u
    #for local usage only
    def getabs(self, path):
        p = self.root + os.sep + path
        return os.path.normpath(p) 

    class InferatoFile(object):
        """
        Virtual File Manipulation
        TODO: Re-factor Class Name
        TODO: Relocate Class
        """
        
        direct_io = 1
        keep_cache = 0
        
        def __init__(self, path, flags, *mode):
            self.path = path
            if Parser(path).isLenghFile():
            #if cmp(path[str.rfind(path, '/')+1:len(path)], FSTemplates.file_len):
                self.file = tempfile.NamedTemporaryFile(mode='r+t')
                #File Name Length is being written to 'length' file here.
                self.file.writelines([str(len(PathUtils(path).getName()))])                
                self.fd = self.file.fileno()
            elif str(path).endswith(FSTemplates.file_type):
                self.file = tempfile.NamedTemporaryFile(mode='r+t')
                                
                actualPath = determineActualDataPath(self, path)
                fileType = determineFileType(self, actualPath)
                self.file.write(str(fileType))
                if fileType != None and str.find(str.lower(fileType), "link") != -1:
                    pointedPath = fileType[str.find(fileType, os.sep):-1]
                    #print "Link Target: " + pointedPath
                    fileType = determineFileType(self, pointedPath)
                    self.file.write("\nLink Target Type: ")
                    self.file.write(str(fileType))
                
                if(os.path.isdir(actualPath) and 
                   os.path.isdir(actualPath + os.sep + FSTemplates._to) and
                   os.path.isfile(actualPath + os.sep + FSTemplates._from)):
                    self.file.write("\n")
                    self.file.write(FSTemplates.inferatoFS_email)
                
                self.fd = self.file.fileno()
            elif str(path).endswith(FSTemplates.email_message):
                self.file = tempfile.NamedTemporaryFile(mode='r+t')
                tail = -1 * (len(FSTemplates.email_message) + len(FSTemplates._suffix) + 1)
                contentPath = determineActualDataPath(self, path[:tail])
                self.file.write(composeEmail(contentPath))
                self.fd = self.file.fileno()
            else:
                self.file = os.fdopen(os.open("." + path, flags, *mode), flag2mode(flags))
                #self.file = os.fdopen(os.open("." + path, flags, *mode), flag2mode(flags))
                self.fd = self.file.fileno()

        
        def read(self, length, offset):
            self.file.seek(offset)
            return self.file.read(length)

        def write(self, buf, offset):
            self.file.write(buf)
            return len(buf)

        def release(self, flags):
            self.file.close()

        def _fflush(self):
            if 'w' in self.file.mode or 'a' in self.file.mode:
                self.file.flush()

        def fsync(self, isfsyncfile):
            self._fflush()
            if isfsyncfile and hasattr(os, 'fdatasync'):
                os.fdatasync(self.fd)
            else:
                os.fsync(self.fd)

        def flush(self):
            self._fflush()
            # cf. xmp_flush() in fusexmp_fh.c
            os.close(os.dup(self.fd))


        def fgetattr(self):
            return os.fstat(self.fd)

        def ftruncate(self, len):
            self.file.truncate(len)

        def lock(self, cmd, owner, **kw):
            op = { fcntl.F_UNLCK : fcntl.LOCK_UN,
                   fcntl.F_RDLCK : fcntl.LOCK_SH,
                   fcntl.F_WRLCK : fcntl.LOCK_EX }[kw['l_type']]
            if cmd == fcntl.F_GETLK:
                return -EOPNOTSUPP
            elif cmd == fcntl.F_SETLK:
                if op != fcntl.LOCK_UN:
                    op |= fcntl.LOCK_NB
            elif cmd == fcntl.F_SETLKW:
                pass
            else:
                return -EINVAL
            fcntl.lockf(self.fd, op, kw['l_start'], kw['l_len'])

    def main(self, *a, **kw):        
        self.file_class = self.InferatoFile        
        return Fuse.main(self, *a, **kw)