예제 #1
0
    def __init__(self, *args, **kw):
        self._cache = CacheClass()
        self._services = ["DropBox", "GoogleCloud", "SugarSync"]  
        self._tldWritable = ["DropBox", "GoogleCloud"]
        self._servobjs = {}
        self._directory = {} # Directory map
        self._perms = {}
        self._truepath = {}
        self._dupes = {}

        ## Initialize Classes
        #TODO: Handle errors of unauthenticated services
        self._servobjs["GoogleCloud"] = GoogleCloudService("cs699wisc_samanas")
        #self._servobjs["SugarSync"] = SugarSyncWrapper("conf.cfg")
        self._servobjs["DropBox"] = DropboxService()

        if self._servobjs["GoogleCloud"] == None:
            self._tldWritable.remove("GoogleCloud")
        if self._servobjs["DropBox"] == None:
            self._tldWritable.remove("DropBox")

        ## loop over all successfully created interfaces
        for s in self._servobjs:
            serv = self._servobjs.get(s, None)
            # If successful...
            if serv != None:
                # get TLDs and add to directory structure
                tmp_tld = serv.GetTLD()
                if tmp_tld["status"] == True:
                    del tmp_tld["status"]
                    for direntry in tmp_tld.keys():
                        tld_key = unfusify_path(direntry)

                        # Handle duplicate file names
                        #TODO: I'm confused about policy, so I'm just
                        # skipping duplicates right now...
                        if tld_key in self._directory:
                            print "Found duplicate: " + str(tld_key)
                            if tld_key in self._dupes:
                                self._dupes[fusify_path(tld_key)].append(tmp_tld[direntry])
                            else:
                                self._dupes[fusify_path(tld_key)] = [tmp_tld[direntry]]
                        else:
                            # tmp_tld could just be replaced by serv??
                            self._directory[tld_key] = tmp_tld[direntry]

                else:
                    print "Getting top-level directory of "+str(s)+" failed."
                # Get permissions
                print "Setting up permissions for " + str(serv)
                tmp_perms = serv.GetPermissionFile()
                self._perms[serv] = {}
                if tmp_perms["status"] == True:
                    print "data we got: " + str(tmp_perms["data"])
                    for fn in tmp_perms["data"].keys():
                        print "Key: " + str(fn)
                        if fn not in self._perms[serv]:
                            print "Add perm " + str(fusify_path(fn)) + " to " + str(serv)
                            print "thing: " + str(tmp_perms["data"][fn])
                            self._perms[serv][fusify_path(fn)] = tmp_perms["data"][fn]
                        else:
                            print "Warning! duplicate permission records for the same cloud service"
                else:
                    print "Did not find permission file, attempting to create it."
                    wp_ret = serv.WritePermissions({})
                    if wp_ret["status"] == False:
                        print "Failed to create permission file for " + str(s)

        for dup_key in self._dupes:
            for d in self._dupes[dup_key]:
                dup_num = 1
                # Construct string with integer for duplicate
                attempt = str(dup_key) + "[" + str(dup_num) + "]"
                while unfusify_path(attempt) in self._directory:
                    dup_num += 1
                    attempt = str(dup_key) + "[" + str(dup_num) + "]"
                print "Adding " + str(attempt) + " which has value " + str(d)
                self._directory[unfusify_path(attempt)] = d
                self._truepath[attempt] = dup_key

        print "Finished with building TLD index: "
        print self._directory
        print "Resulting permissions: "
        print self._perms
            

        Fuse.__init__(self, *args, **kw)
        self._root = "/"
예제 #2
0
class PyCloudGate(Fuse):

    def __init__(self, *args, **kw):
        self._cache = CacheClass()
        self._services = ["DropBox", "GoogleCloud", "SugarSync"]  
        self._tldWritable = ["DropBox", "GoogleCloud"]
        self._servobjs = {}
        self._directory = {} # Directory map
        self._perms = {}
        self._truepath = {}
        self._dupes = {}

        ## Initialize Classes
        #TODO: Handle errors of unauthenticated services
        self._servobjs["GoogleCloud"] = GoogleCloudService("cs699wisc_samanas")
        #self._servobjs["SugarSync"] = SugarSyncWrapper("conf.cfg")
        self._servobjs["DropBox"] = DropboxService()

        if self._servobjs["GoogleCloud"] == None:
            self._tldWritable.remove("GoogleCloud")
        if self._servobjs["DropBox"] == None:
            self._tldWritable.remove("DropBox")

        ## loop over all successfully created interfaces
        for s in self._servobjs:
            serv = self._servobjs.get(s, None)
            # If successful...
            if serv != None:
                # get TLDs and add to directory structure
                tmp_tld = serv.GetTLD()
                if tmp_tld["status"] == True:
                    del tmp_tld["status"]
                    for direntry in tmp_tld.keys():
                        tld_key = unfusify_path(direntry)

                        # Handle duplicate file names
                        #TODO: I'm confused about policy, so I'm just
                        # skipping duplicates right now...
                        if tld_key in self._directory:
                            print "Found duplicate: " + str(tld_key)
                            if tld_key in self._dupes:
                                self._dupes[fusify_path(tld_key)].append(tmp_tld[direntry])
                            else:
                                self._dupes[fusify_path(tld_key)] = [tmp_tld[direntry]]
                        else:
                            # tmp_tld could just be replaced by serv??
                            self._directory[tld_key] = tmp_tld[direntry]

                else:
                    print "Getting top-level directory of "+str(s)+" failed."
                # Get permissions
                print "Setting up permissions for " + str(serv)
                tmp_perms = serv.GetPermissionFile()
                self._perms[serv] = {}
                if tmp_perms["status"] == True:
                    print "data we got: " + str(tmp_perms["data"])
                    for fn in tmp_perms["data"].keys():
                        print "Key: " + str(fn)
                        if fn not in self._perms[serv]:
                            print "Add perm " + str(fusify_path(fn)) + " to " + str(serv)
                            print "thing: " + str(tmp_perms["data"][fn])
                            self._perms[serv][fusify_path(fn)] = tmp_perms["data"][fn]
                        else:
                            print "Warning! duplicate permission records for the same cloud service"
                else:
                    print "Did not find permission file, attempting to create it."
                    wp_ret = serv.WritePermissions({})
                    if wp_ret["status"] == False:
                        print "Failed to create permission file for " + str(s)

        for dup_key in self._dupes:
            for d in self._dupes[dup_key]:
                dup_num = 1
                # Construct string with integer for duplicate
                attempt = str(dup_key) + "[" + str(dup_num) + "]"
                while unfusify_path(attempt) in self._directory:
                    dup_num += 1
                    attempt = str(dup_key) + "[" + str(dup_num) + "]"
                print "Adding " + str(attempt) + " which has value " + str(d)
                self._directory[unfusify_path(attempt)] = d
                self._truepath[attempt] = dup_key

        print "Finished with building TLD index: "
        print self._directory
        print "Resulting permissions: "
        print self._perms
            

        Fuse.__init__(self, *args, **kw)
        self._root = "/"

    ## shortlist
    ##
    ## Get creation of permissions if not there working
    ## get file[1,2,3,etc.] working, for now we skip duplicates
    def getattr(self, path):
        if (not self._CheckPerms(path, os.R_OK)) and (not self._IsOwner(path)):
            return -errno.EACCES
        print "LOOKING UP: " + path
        # Special case for the root
        if path == self._root:
            st = MyStat()
            #TODO: For now, just assuming that if you mounted this, you have
            # permission to do stuff with it
            st.st_mode = stat.S_IFDIR | 0777
            st.st_nlink = 2
            return st

        # retrieve top-level dir name
        path_parts = path.split("/")
        tld = path_parts[1]
        if tld in self._directory:
            # Choose appropriate object to call GetAttr on with tld
            print self._truepath
            ga_ret = self._directory[tld].GetAttr(self._GetTruePath(path))
            if ga_ret["status"] == False:
                return -errno.ENOENT
            st = MyStat()
            if not self._cache.CheckOpen(path):
                st.st_size = ga_ret["st_size"]
            else:
                st.st_size = self._cache.Size(path)
            st.st_mtime = ga_ret["st_mtime"]
            st.st_mode = ga_ret["st_mode"]
            # Handle permissions
            perm_list = None
            if self._directory[tld] in self._perms:
                perm_list = self._perms[self._directory[tld]].get(self._GetTruePath(path), None)
            else:
                print "getattr did not find " + str(self._directory[tld]) + " in perms " + str(path)
            if perm_list != None:
                st.st_uid = perm_list[0]
                st.st_gid = perm_list[1]
                st.st_mode = st.st_mode | perm_list[2]
            # No permissions found, set user/group to current user
            else:
                st.st_uid = os.getuid()
                st.st_gid = os.getgid()
                st.st_mode = st.st_mode | stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC 
            st.print_stat()
            return st
        else:
            return -errno.ENOENT
    
    def _GetTruePath(self, path):
        tmp_path = path
        path_appendage = ""
        if path.count('/') > 1:
            path_list = path.split('/')
            tmp_path = "/" + str(path_list[1])
            path_list2 = path.split(tmp_path)
            path_appendage = path_list2[-1]

        if tmp_path in self._truepath:
            return self._truepath[tmp_path] + str(path_appendage)
        return path
    
    def readdir(self, path, offset):
        # Special case for top-level directory
        if path == self._root:
            for tld in self._directory:
                yield fuse.Direntry(tld)
        else:
            path_parts = path.split("/")
            tld = path_parts[1]
            if tld in self._directory:
                rd_ret = self._directory[tld].Readdir(self._GetTruePath(path))
                if rd_ret["status"] == True:
                    for name in rd_ret["filenames"]:
                        yield fuse.Direntry(name)

    def _FindTLD (self, path):
        """ Find the top level directory mapping for the path specified

            returns the class to call operation on (or None if not availible)
        """
        #print self._directory
        tmp = path[1:]
        tmp = tmp.split("/")
        if tmp[0] in self._directory:
            return self._directory[tmp[0]]
        return None

    def _PickService(self):
        #TODO: If we are making a file in the TLD, use policy to choose which
        # service to place it in. 
        if len(self._tldWritable) < 1:
            return None
        dt1 = datetime.now()
        rand_index = dt1.microsecond % len(self._tldWritable)

        print "Picked " + str(self._tldWritable[rand_index])
        return self._servobjs[self._tldWritable[rand_index]]

    def _CheckPerms(self, path, rwx):
        """ 
        path: pathname of what is desired to be operated on (expects slash in front)
        rwx: Which operation the caller would like to perform
             os.R_OK = read
             os.W_OK = write
             os.X_OK = execute

        returns True if operation is allowed, False if not
        """
        # Recover correct object for perms
        p = self._FindTLD(path)
        if p == None:
            return True
        # If no permission is set, it is assumed the user can do anything
        true_path = self._GetTruePath(path)
        if true_path not in self._perms[p]:
            return True

        cur_perms = self._perms[p][true_path]
        cur_uid = os.getuid()
        cur_gid = os.getgid()
        perm_level = 0
        stat_var = None

        if cur_perms[0] == cur_uid:
            perm_level = 1
        elif cur_perms[1] == cur_gid:
            perm_level = 2
        else:
            perm_level = 3

        if rwx == os.R_OK:
            if perm_level == 1:
                stat_var = stat.S_IRUSR
            elif perm_level == 2:
                stat_var = stat.S_IRGRP
            elif perm_level == 3:
                stat_var = stat.S_IROTH
        elif rwx == os.W_OK:
            if perm_level == 1:
                stat_var = stat.S_IWUSR
            elif perm_level == 2:
                stat_var = stat.S_IWGRP
            elif perm_level == 3:
                stat_var = stat.S_IWOTH
        elif rwx == os.X_OK:
            if perm_level == 1:
                stat_var = stat.S_IXUSR
            elif perm_level == 2:
                stat_var = stat.S_IXGRP
            elif perm_level == 3:
                stat_var = stat.S_IXOTH
        else:
            print "Warning: Invalid rwx parameter passed to _CheckPerms"
            return False

        if stat_var == None:
            return False

        if (cur_perms[2] & stat_var) == stat_var:
            return True
        
        return False
    
    def _CheckDirPerms(self, path, rwx):
        path_parts = path.split("/")
        file_name = "/"+str(path_parts[-1])
        dir_name = path.split(file_name)
        return self._CheckPerms(dir_name[0], rwx)

    def _IsOwner(self, path):
        p = self._FindTLD(path)
        true_path = self._GetTruePath(path)
        if true_path in self._perms[p]:
            if os.getuid() != self._perms[p][true_path][0]:
                return False
        return True

    def readlink (self, path):
        """ Do nothing here, we dont use symlinks """
        return path

    def unlink(self, path):
        # Only owner of file can delete it
        print "UNLINKING FILE - " + path
        if self._IsOwner(path) == False:
            return -errno.EACCES

        p = self._FindTLD(path)
        uf_path = unfusify_path(path)
        if p != None:
            print "CALLING UNLINK + " + path
            ret = p.Unlink(self._GetTruePath(path))
            if ret["status"] == False:
                return -errno.ENOENT

            # Remove record from permissions
            true_path = self._GetTruePath(path)
            if true_path in self._perms[p]:
                del self._perms[p][true_path]

            # Remove from TLD
            path_parts = uf_path.split("/")
            if len(path_parts) == 1:
                del self._directory[uf_path]

            if path in self._truepath:
                del self._truepath[path]
        else:
            return -errno.ENOENT

        
    def rmdir(self, path):
        ## Calls unlink() since in our case they both do the same thing
        return self.unlink(path)

 
    def symlink(self, path, path1):
        ## We do not support symlinks
        return -errno.ENOENT     

    def read(self, path, length, offset):
        if self._CheckPerms(path, os.R_OK) == False:
            return -errno.EACCES
        if self._cache.CheckOpen(path):
            print "FB: read cache hit"
            return self._cache.Read(path, offset, length)
        else:
            print "FB: read cache miss"
            p = self._FindTLD(path)
            if p != None:
                a = p.GetAttr(self._GetTruePath(path))
                ## Read the entire current file if size < 10 MB
                if a["st_size"] < 10000000:
                    
                    r = p.Read(self._GetTruePath(path), 0, a["st_size"])
                    if r["status"] == False:
                        return -errno.EINVAL
                    data = r["data"]
                    self._cache.OpenCache(path, data)
                    if len(data) >= offset + length:
                        return data[offset:offset+length]
                    elif len(data) >= offset:
                        return data[offset:]
                    else:
                        return -errno.ENOENT
                else:
                    data = p.Read(self._GetTruePath(path), offset, length)
                    if data["status"] == False:
                        return -errno.EINVAL
                    else:
                        return data["data"]
            else:
                return -errno.ENOENT
        
    def write(self, path, buf, offset):
        if self._CheckPerms(path, os.W_OK) == False:
            return -errno.EACCES
        if self._cache.CheckOpen(path):
            self._cache.Write(path, buf, offset)
        else:
            p = self._FindTLD(path)
            if p != None:
                a = p.GetAttr(self._GetTruePath(path))
                r = p.Read(self._GetTruePath(path), 0, a["st_size"])
                if r["status"] == False:
                    return -errno.EINVAL
                data = r["data"]
                self._cache.OpenCache(path, data)
                if not self._cache.Write(path, buf, offset):
                    return -errno.ENOENT
            else:
                return -errno.ENOENT

        return len(buf)
    def chmod(self, path, mode):
        if self._IsOwner(path) == False:
            return -errno.EACCES
        p = self._FindTLD(path)
        if p != None:
            ga_ret = p.GetAttr(self._GetTruePath(path))
            if ga_ret["status"] == False:
                return -errno.ENOENT
        else:
            return -errno.ENOENT

        ap_ret = self._AddPermEntry(p, path, mode)
        if ap_ret == None:
            return -errno.EIO

        return 0

    def _AddPermEntry(self, serv_obj, path, mode):
        # TODO: We don't store sticky bit
        true_path = self._GetTruePath(path)
        old_perms = self._perms[serv_obj].get(true_path, None)
        self._perms[serv_obj][true_path] = [os.getuid(), os.getgid(), stat.S_IMODE(mode)]
        print serv_obj
        wp_ret = serv_obj.WritePermissions(self._perms[serv_obj])
        if wp_ret["status"] == False:
            if old_perms == None:
                del self._perms[serv_obj][true_path]
            else:
                self._perms[serv_obj][path] = old_perms
            return None
        return 0
    
    def utime(self, path, times):
        pass ## Stub

    def chown(self, path, times):
        print "chown path: " + str(path)
        print "chown times: " + str(times)
        # Only root can execute chown
        if os.getuid() != 0:
            return -errno.EACCES
    
    def truncate(self, path, len):
        if self._CheckPerms(path, os.W_OK) == False:
            return -errno.EACCES
        print "FB: truncate " + path
        if self._cache.CheckOpen(path):
            print "FB: Truncate hit in cache"
            self._cache.Truncate(path, len)
        else:
            print "FB: Truncate missed in cache"
            p = self._FindTLD(path)
            if p != None:
                status = p.Truncate(self._GetTruePath(path), len) 
                if status["status"] != True:
                    return -errno.ENOENT
            else:
                return -errno.ENOENT

    def removexattr(self, path, name):
        print "REMOVE X ATTR" + name
        return 0

    def access(self, path, mode):
        print "access path: " + str(path)
        print "access mode: " + str(mode)
        return 0

    def getxattr(self, path, name, size): 
        
        print "getxattr - " + path
        print "getxattr - " + name
        return 0

    def release(self, path, flags):
        if self._CheckPerms(path, os.R_OK) == False:
            return -errno.EACCES
        data = self._cache.Close(path)
        if data == None:
            return 0
        p = self._FindTLD(path)
        if p != None:
            status = p.Write(self._GetTruePath(path), data)
            if status["status"] == False:
                return -errno.ENOENT
        else:
            return -errno.ENOENT               
    
    def mknod(self, path, mode, dev):
        print "mknod path: " + str(path)
        print "mknod mode: " + str(mode)
        print "mknod dev: " + str(dev)
        if self._CheckDirPerms(path, os.R_OK) == False:
            return -errno.EACCES
        
        # Make sure mode is S_IFREG, otherwise we don't support mknod for it
        if (mode & stat.S_IFREG) != stat.S_IFREG:
            return -errno.EINVAL


        path_parts = unfusify_path(path).split("/")
        p = None
        if len(path_parts) > 1:
            p = self._FindTLD(path)
        else:
            # Check if file exists...only need to do this for TLD
            if path_parts[0] in self._directory:
                return -errno.EEXIST
            
            # Pick what service this file will go to
            p = self._PickService()

            if p == None:
                return -errno.BADF

        mk_ret = p.Mknode(path)
        if mk_ret["status"] == False:
            return mk_ret["errno"]

        if len(path_parts) == 1:
            # Add to TLD. Needs to be after Mknode to make sure it was successful
            self._directory[path_parts[0]] = p

        # Add to permissions
        ap_ret = self._AddPermEntry(p, path, mode)
        if ap_ret == None:
            return -errno.EIO

        return 0

    def mkdir(self, path, mode):
        if self._CheckDirPerms(path, os.R_OK) == False:
            return -errno.EACCES

        p = self._FindTLD(path)
        uf_path = unfusify_path(path)
        path_parts = uf_path.split("/")
        if p == None:
            # Check if we're trying to write to the TLD
            if len(path_parts) == 1:
                p = self._PickService()
                if p == None:
                    return -errno.EINVAL ## Replace with appropriate error
            else:
                return -errno.EINVAL
        ret = p.Mkdir(path) 
        if ret["status"] == False:
            return -errno.EINVAL ## Replace with appropriate error
        if len(path_parts) == 1:
            self._directory[uf_path] = p
        self._perms[p][path] = [os.getuid(), os.getgid(), stat.S_IMODE(mode)]

        return 0
            

    def flush(self, filename):
        #TODO: Check permissions for this?
        if self._cache.CheckOpen(filename) == False:
            return ## We have nothing to flush 

        p = self._FindTLD(filename)
        if p != None:
            total_size = self._cache.Size(filename)
            if self._cache.isWritten(filename): 
                data = self._cache.Read(filename, 0, total_size)
                if self.write(filename, data, 0) > 0:
                    return 0
                else: 
                    return -errno.EINVAL
        else:
            return -errno.EINVAL
        
    def fsync(self, filename, isfilesync):
        ## isfilesync doesnt matter to us
        return self.flush(filename)