def __init__(self, host, username, password): self.client = CoredataClient(host, (username, password)) self.cache = {} self.file_cache = {}
class CoredataDisk(Operations): def __init__(self, host, username, password): self.client = CoredataClient(host, (username, password)) self.cache = {} self.file_cache = {} def access(self, path, mode): """ Check file access permissions. """ pass def chmod(self, path, mode): """ Changing permissions of file/folder """ pass def chown(self, path, uid, gid): """ Changing ownership of file/folder """ pass def getattr(self, path, fh=None): """ Get file attributes. Due to how systems work, this needs to be implemented properly so the operating system can reason about the files on the system. ie. checking if files exists before trying to create them. """ print 'Getting attributes for {path}'.format(path=path.encode('utf8')) if path == '/': return { 'st_ctime': 1402489488.4108176, 'st_mtime': 1402489488.4108176, 'st_nlink': 4, 'st_mode': 16893, 'st_size': 4096, 'st_gid': 1000, 'st_uid': 1000, 'st_atime': 1402383556.9949517} space, project, filename = Utils.split_path(path) if path in self.file_cache: if self.file_cache[path] == CacheStatus.File: return { 'st_mode': 33204, 'st_ino': 4852076, 'st_dev': 36L, 'st_nlink': 1, 'st_uid': 1000, 'st_gid': 1000, 'st_size': 6905, 'st_atime': 1403002695, 'st_mtime': 1402520784, 'st_ctime': 1402520784} elif self.file_cache[path] == CacheStatus.Folder: return { 'st_ctime': 1402489488.4108176, 'st_mtime': 1402489488.4108176, 'st_nlink': 4, 'st_mode': 16893, 'st_size': 4096, 'st_gid': 1000, 'st_uid': 1000, 'st_atime': 1402383556.9949517} elif self.file_cache[path] == CacheStatus.NotFound: raise FuseOSError(errno.ENOENT) else: raise Exception('Cache is dirty with: {dirty}'.format( self.file_cache[path])) if filename: entity = Entity.Files title = filename elif project: entity = Entity.Projects title = project elif space: entity = Entity.Spaces title = space else: print space, project, filename, path raise Exception('Failed figuring out entity type') # TODO: Cache this stuff. entities = self.client.get(entity, search_terms={'title': title}) if not entities: # Raise a FUSE error if we cannot find the requested path, this # gets caught in the super class and properly handled. self.file_cache[path] = CacheStatus.NotFound raise FuseOSError(errno.ENOENT) if entity == Entity.Files: self.file_cache[path] = CacheStatus.File return { 'st_mode': 33204, 'st_ino': 4852076, 'st_dev': 36L, 'st_nlink': 1, 'st_uid': 1000, 'st_gid': 1000, 'st_size': 6905, 'st_atime': 1403002695, 'st_mtime': 1402520784, 'st_ctime': 1402520784} self.file_cache[path] = CacheStatus.Folder return { 'st_ctime': 1402489488.4108176, 'st_mtime': 1402489488.4108176, 'st_nlink': 4, 'st_mode': 16893, 'st_size': 4096, 'st_gid': 1000, 'st_uid': 1000, 'st_atime': 1402383556.9949517} def readdir(self, path, fh): """Read directory""" print 'Reading directory {path}'.format(path=path.encode('utf8')) space, project, filename = Utils.split_path(path) if path in self.cache: return ['.', '..'] + self.cache[path] if not space: docs = self.client.get(Entity.Spaces) titles = map(lambda x: x['title'], docs) elif filename: raise NotImplementedError() elif project: project = self.client.get(Entity.Projects, limit=1, search_terms={ 'title': project}) project_id = project[0]['id'] docs = self.client.get( Entity.Projects, project_id, Entity.Files, limit=200) titles = map(lambda x: x['filename'], docs) elif space: space = self.client.get( Entity.Spaces, limit=1, search_terms={'title': space}) space_id = space[0]['id'] docs = self.client.get( Entity.Spaces, space_id, Entity.Projects, limit=200) titles = map(lambda x: x['title'], docs) self.cache[path] = titles return ['.', '..'] + titles def readlink(self, path): pass def mknod(self, path, mode, dev): """ Create a file node This is called for creation of all non-directory, non-symlink nodes. If the filesystem defines a create() method, then for regular files that will be called instead. """ pass def rmdir(self, path): pass def mkdir(self, path, mode): """ Create a directory """ title = os.path.basename(os.path.normpath(path)) space_name = filter(lambda x: x != '', path.split('/'))[0] space = self.client.find_one(Entity.Spaces, {'title': space_name}) space_id = space['id'] print 'Trying to make {title} in space {space}. Path is {path}'.format( title=title, space=space_id, path=path) self.client.create(Entity.Projects, {'space': space_id, 'title': title}) def statfs(self, path): pass def unlink(self, path): pass def symlink(self, target, name): pass def rename(self, old, new): pass def link(self, target, name): """ Create a hard link to a file """ pass def utimens(self, path, times=None): """ Change the access and modification times of a file with nanosecond resolution. This supersedes the old utime() interface. New applications should use this. """ pass def open(self, path, flags): """ File open operation """ space, project, filename = Utils.split_path(path) # Get the file from the API, saving to temp file # Remove extension again title, _ = filename.split('.') # TODO: Make sure we only get one file back. f = self.client.get(Entity.Files, limit=1, search_terms={'title': title})[0] file_id = f['id'] # TODO: Add content in file endpoint and fetch it here. content = self.client.get(Entity.Files, file_id, Entity.Content) tmp_file = NamedTemporaryFile() tmp_file.write(content) # Open file descripton and pass the file descriptor print 'Returning tmp file!' return os.open(tmp_file.name, flags) def create(self, path, mode, fi=None): """ Create and open a file If the file does not exist, first create it with the specified mode, and then open it. """ print 'Trying to creating file: ' + path pass def read(self, path, length, offset, fh): """ Read data from an open file Read should return exactly the number of bytes requested except on EOF or error, otherwise the rest of the data will be substituted with zeroes. An exception to this is when the 'direct_io' mount option is specified, in which case the return value of the read system call will reflect the return value of this operation. """ print 'Trying to read file: ' + path os.lseek(fh, offset, os.SEEK_SET) return os.read(fh, length) def write(self, path, buf, offset, fh): pass def truncate(self, path, length, fh=None): pass def flush(self, path, fh): """ Possibly flush cached data BIG NOTE: This is not equivalent to fsync(). It's not a request to sync dirty data. Flush is called on each close() of a file descriptor. So if a filesystem wants to return write errors in close() and the file has cached dirty data, this is a good place to write back data and return any errors. Since many applications ignore close() errors this is not always useful. """ pass def release(self, path, fh): pass def fsync(self, path, fdatasync, fh): """ Synchronize file contents If the datasync parameter is non-zero, then only the user data should be flushed, not the meta data. """ pass