def release(self, path, fuse_file_info): """ Save file to database and launch replication to remote Cozy. path {string}: file path fuse_file_info {struct}: information about open file Release is called when there are no more references to an open file: all file descriptors are closed and all memory mappings are unmapped. """ try: path = _normalize_path(path) logger.info('release file %s' % path) file_doc = dbutils.get_file(self.db, path) binary_id = file_doc["binary"]["file"]["id"] if path in self.writeBuffers: data = self.writeBuffers[path] self.db.put_attachment(self.db[binary_id], data, filename="file") file_doc['size'] = len(data) file_doc['lastModification'] = get_current_date() self.writeBuffers.pop(path, None) binary = self.db[binary_id] file_doc['binary']['file']['rev'] = binary['_rev'] self.db.save(file_doc) logger.info("release is done") return 0 except Exception as e: logger.exception(e) return -errno.ENOENT
def unlink(self, path): """ Remove file from database. """ try: path = _normalize_path(path) logger.info('unlink %s' % path) parts = path.rsplit(u'/', 1) if len(parts) == 1: dirname, filename = u'', parts[0] else: dirname, filename = parts file_doc = dbutils.get_file(self.db, path) if file_doc is not None: binary_id = file_doc["binary"]["file"]["id"] logger.info(self.db[file_doc["_id"]]) try: self.db.delete(self.db[binary_id]) except ResourceNotFound: pass self.db.delete(self.db[file_doc["_id"]]) logger.info('file %s removed' % path) self._update_parent_folder(file_doc['path']) return 0 else: logger.warn('Cannot delete file, no entry found') return -errno.ENOENT except Exception as e: logger.exception(e) return -errno.ENOENT
def _is_found(self, path): ''' Returns true if the path exists in the database, false either. ''' path = fusepath.normalize_path(path) file_doc = dbutils.get_file(self.db, path) return file_doc is not None
def _create_new_file(self, path): ''' Create empty binary cache and load file metadata from database. ''' file_doc = dbutils.get_file(self.db, path) file_doc['size'] = 0 file_doc['lastModification'] = fusepath.get_current_date() dbutils.update_file(self.db, file_doc)
def get_st(self, path): self.receive() if path in self.cache['st']: logger.info('st : cache') return self.cache['st'][path] else: try: st = CouchStat() # Path is root if path is "/": st.st_mode = stat.S_IFDIR | 0o775 st.st_nlink = 2 self.cache['st'][path] = st return st else: # Or path is a folder folder = dbutils.get_folder(self.db, path) if folder is not None: st.st_mode = stat.S_IFDIR | 0o775 st.st_nlink = 2 if 'lastModification' in folder: st.st_atime = get_date(folder['lastModification']) st.st_ctime = st.st_atime st.st_mtime = st.st_atime self.cache['st'][path] = st return st else: # Or path is a file file_doc = dbutils.get_file(self.db, path) if file_doc is not None: st.st_mode = stat.S_IFREG | 0o664 st.st_nlink = 1 # TODO: if size is not set, get the binary # and save the information. st.st_size = file_doc.get('size', 4096) if 'lastModification' in file_doc: st.st_atime = \ get_date(file_doc['lastModification']) st.st_ctime = st.st_atime st.st_mtime = st.st_atime self.cache['st'][path] = st return st else: print 'File does not exist: %s' % path logger.info('file_not_fount') return st self.send() except Exception as e: logger.exception(e) return e
def getattr(self, path): """ Return file descriptor for given_path. Useful for 'ls -la' command like. """ try: logger.debug('getattr %s' % path) st = CouchStat() # Path is root if path is "/": st.st_mode = stat.S_IFDIR | 0o775 st.st_nlink = 2 return st else: # Or path is a folder folder = dbutils.get_folder(self.db, path) if folder is not None: st.st_mode = stat.S_IFDIR | 0o775 st.st_nlink = 2 if 'lastModification' in folder: st.st_atime = get_date(folder['lastModification']) st.st_ctime = st.st_atime st.st_mtime = st.st_atime return st else: # Or path is a file file_doc = dbutils.get_file(self.db, path) if file_doc is not None: st.st_mode = stat.S_IFREG | 0o664 st.st_nlink = 1 # TODO: if size is not set, get the binary # and save the information. st.st_size = file_doc.get('size', 4096) if 'lastModification' in file_doc: st.st_atime = \ get_date(file_doc['lastModification']) st.st_ctime = st.st_atime st.st_mtime = st.st_atime return st else: print 'File does not exist: %s' % path return -errno.ENOENT return st except Exception as e: logger.exception(e) return -errno.ENOENT
def get_binary(self, path): self.receive() if path in self.cache['binaries']: return self.cache['binaries'][path] else: file_doc = dbutils.get_file(self.db, path) if file_doc is not None: binary_id = file_doc["binary"]["file"]["id"] self.cache['binaries'][path] = binary_id return binary_id else: return False
def _remove_file_from_db(self, path): ''' Remove binary document if it exists, then remove file document. ''' file_doc = dbutils.get_file(self.db, path) if file_doc["binary"] is not None and 'file' in file_doc["binary"]: binary_id = file_doc["binary"]["file"]["id"] try: self.db.delete(self.db[binary_id]) except ResourceNotFound: pass dbutils.delete_file(self.db, file_doc)
def _get_attr_from_db(self, path, isfile=None): ''' Build fuse file attribute from data located in database. Check if path corresponds to a folder first. ''' st = CouchStat() path = fusepath.normalize_path(path) if isfile is None: folder = dbutils.get_folder(self.db, path) if folder is not None: st.set_folder(folder) self.attr_cache.add(path, st) return st else: file_doc = dbutils.get_file(self.db, path) if file_doc is not None: st.set_file(file_doc) self.attr_cache.add(path, st) return st else: return None elif isfile: file_doc = dbutils.get_file(self.db, path) if file_doc is not None: st.set_file(file_doc) self.attr_cache.add(path, st) return st else: return None else: folder = dbutils.get_folder(self.db, path) if folder is not None: st.set_folder(folder) self.attr_cache.add(path, st) return st else: return None
def get_file_metadata(self, path): ''' Return file metadata based on given path. The corresponding file doc is returned with the linked binary ID and the cached file path. ''' res = self.metadata_cache.get(path) if res is None: file_doc = dbutils.get_file(self.db, path) binary_id = file_doc["binary"]["file"]["id"] cache_file_folder = os.path.join(self.cache_path, binary_id) cache_file_name = os.path.join(cache_file_folder, 'file') res = (file_doc, binary_id, cache_file_name) self.metadata_cache.add(path, res) return res
def unlink(self, path): """ Remove file from current FS. Update cache accordingly. """ try: logger.info('unlink %s' % path) path = fusepath.normalize_path(path) if dbutils.get_file(self.db, path) is not None: self.binary_cache.remove(path) self._clean_cache(path, True) self._remove_file_from_db(path) self._update_parent_folder(path) return 0 else: logger.info('Cannot delete file, no entry found') return -errno.ENOENT except Exception as e: logger.exception(e) return -errno.ENOENT
def read(self, path, size, offset): """ Return content of file located at given path. path {string}: file path size {integer}: size of file part to read offset {integer}: beginning of file part to read """ # TODO: do not load the file for each chunk. # Save it in a cache file maybe?. try: path = _normalize_path(path) logger.info('read %s' % path) file_doc = dbutils.get_file(self.db, path) binary_id = file_doc["binary"]["file"]["id"] binary_attachment = self.db.get_attachment(binary_id, "file") if binary_attachment is None: logger.info('No attachment for this binary') return '' else: content = binary_attachment.read() content_length = len(content) logger.info('Return file content') if offset < content_length: if offset + size > content_length: size = content_length - offset buf = content[offset:offset+size] else: buf = '' logger.info('Empty file content') return buf except Exception, e: logger.exception(e) return -errno.ENOENT
def rename(self, pathfrom, pathto, root=True): """ Rename file and subfiles (if it's a folder) in device. """ logger.info("rename %s -> %s: " % (pathfrom, pathto)) try: pathfrom = fusepath.normalize_path(pathfrom) pathto = fusepath.normalize_path(pathto) file_doc = dbutils.get_file(self.db, pathfrom) if file_doc is not None: file_path, name = fusepath.split(pathto) file_doc.update({ "name": name, "path": file_path, "lastModification": fusepath.get_current_date() }) dbutils.update_file(self.db, file_doc) folder_doc = dbutils.get_folder(self.db, pathfrom) if folder_doc is not None: folder_path, name = fusepath.split(pathto) folder_doc.update({ "name": name, "path": folder_path, "lastModification": fusepath.get_current_date() }) # Rename all subfiles for res in self.db.view("file/byFolder", key=pathfrom): child_pathfrom = os.path.join( res.value['path'], res.value['name'] ) child_pathto = os.path.join(folder_path, name, res.value['name']) self.rename(child_pathfrom, child_pathto, False) for res in self.db.view("folder/byFolder", key=pathfrom): child_pathfrom = os.path.join( res.value['path'], res.value['name']) child_pathto = os.path.join(folder_path, name, res.value['name']) self.rename(child_pathfrom, child_pathto, False) dbutils.update_folder(self.db, folder_doc) parent_path_from, namefrom = fusepath.split(pathfrom) parent_path_to, nameto = fusepath.split(pathto) if root: self._update_parent_folder(parent_path_from) self._update_parent_folder(parent_path_to) names = dbutils.name_cache.get(parent_path_from) if names is not None and namefrom in names: names.remove(namefrom) names.add(parent_path_from, names) names = dbutils.name_cache.get(parent_path_to) if names is not None: names.append(nameto) names.add(parent_path_to, names) self._clean_cache(pathfrom) self._add_to_cache(pathto) if folder_doc is None and file_doc is None: return -errno.ENOENT else: return 0 except Exception as e: logger.exception(e) return -errno.ENOENT