def read(self, path, size, offset, fh=None): try: part_num = int(path[1:]) if part_num not in self.partitions: raise FuseOSError(errno.ENOENT) part = self.partitions[part_num] if offset >= (part['length'] * self.block_size): return '' start_block = (offset // self.block_size) + part['start'] start_offset_from_block = offset % self.block_size end_byte = offset + size if end_byte > (part['length'] * self.block_size): end_byte = part['length'] * self.block_size end_block = (end_byte // self.block_size) + part['start'] if end_byte % self.block_size > 0: end_block += 1 block_length = end_block - start_block byte_length = end_byte - offset block_data = self.get_mmc_blocks(start_block, block_length) block_data = block_data[start_offset_from_block:] block_data = block_data[:byte_length] return block_data except ValueError: raise FuseOSError(errno.ENOENT)
def access(self, path, mode): # Don't know whether file or dir yet dr = core.path2dir(Path(path)) fr = core.path2fr(Path(path)) if core.fileService.ValidateDirPath(dr): # we can always access directories, but possibly not the # files in them. (this is even true when directories are # locked) return 0 elif core.fileService.ValidateFilePath(dr): if mode & os.W_OK != 0 and not acquire_wlock(fr): # not only checks, but also acquires # if the user calls access, they likely intend to access raise FuseOSError(errno.EACCES) if mode & (os.R_OK | os.X_OK) != 0 and not acquire_rlock(fr): # For the purpose of this FS read implies execute raise FuseOSError(errno.EACCES) # this means we can access the file and have the appropriate (r or w) lock # Let's proactively download it, and mark it as being worked with file_sync.download(fr) return 0 else: raise FuseOSError(errno.ENOENT)
def getattr(self, path, fh=None): st = dict(st_mode=0, st_nlink=0, st_size=0, st_ctime=0, st_mtime=0, st_atime=0) if path == '/': st['st_mode'] = stat.S_IFDIR | 0o555 st['st_nlink'] = 2 else: try: part_num = int(path[1:]) if part_num not in self.partitions: raise FuseOSError(errno.ENOENT) st['st_mode'] = stat.S_IFREG | 0o444 st['st_nlink'] = 1 st['st_size'] = self.partitions[part_num][ 'length'] * self.block_size except ValueError: raise FuseOSError(errno.ENOENT) return st
def symlink(self, link, source): if link != "" and source != "" and path2tags(link).issubset( xattr2tags(real(link))): if base(link) in self.tags: raise FuseOSError(EEXIST) else: os.symlink(source, real(link)) set_tags_xattr(real(link), path2tags(link)) else: raise FuseOSError(ENOENT)
def getattr(self, path, fh=None): self.log("getattr " + path) if path != "/" and len(folder_cache) == 1: self.log("getattr " + path + " first read of root") self.populateFolderCache("/") if path in folder_cache: if 'st_size' in folder_cache[path]: return_val = folder_cache[path] self.log("getattr " + path + " " + pprint.saferepr(return_val)) return return_val else: self.log("getattr boxid: " + str(folder_cache[path]["boxid"])) file_query = client.file(folder_cache[path]["boxid"]).get() folder_cache[path]["st_size"] = file_query["size"] folder_cache[path]["st_ctime"] = time.mktime( time.strptime(file_query["created_at"], "%Y-%m-%dT%H:%M:%S-07:00")) folder_cache[path]["st_mtime"] = time.mktime( time.strptime(file_query["modified_at"], "%Y-%m-%dT%H:%M:%S-07:00")) folder_cache[path]["st_atime"] = time.time() return_val = folder_cache[path] self.log("getattr " + path + " " + pprint.saferepr(return_val)) return return_val else: # Not in cache, try populateFolderCache one direcory up oneback = path.split("/") oneback.pop() oneback.reverse() oneback.pop() oneback.reverse() self.log("getattr " + path + " oneback: " + pprint.saferepr(oneback)) if len(oneback) > 0: searchpath = "" for element in oneback: searchpath += "/" + element self.log("getattr " + path + " searchpath: " + searchpath) self.populateFolderCache(searchpath) if path in folder_cache: return_val = folder_cache[path] self.log("getattr " + path + " " + pprint.saferepr(return_val)) return return_val else: self.log("getattr " + path + " ENOENT (Not Found) - folder not found") raise FuseOSError(errno.ENOENT) return {} else: self.log("getattr " + path + " ENOENT (Not Found) - oneback empty") raise FuseOSError(errno.ENOENT) return {}
def create(self, path, mode, fi=None): fr = core.path2fr(Path(path)) if acquire_wlock(fr): real_path = core.fr2path(fr) result = os.open(real_path, os.O_WRONLY | os.O_CREAT, mode) if result > 0: upload(fr) return result else: raise FuseOSError(-result) else: raise FuseOSError(errno.ENOACCESS)
def chown(self, path, uid, gid): # see chmod fr = core.path2fr(Path(path)) dr = core.path2dir(Path(path)) if core.fileService.ValidateDirPath(dr): return 0 elif core.fileService.ValidateFilePath(fr): fr = core.path2fr(Path(path)) if acquire_wlock(fr): return 0 else: raise FuseOSError(errno.ENOACCESS) else: raise FuseOSError(errno.ENOENT)
def chmod(self, path, mode): fr = core.path2fr(Path(path)) dr = core.path2dir(Path(path)) if core.fileService.ValidateDirPath(dr): return 0 elif core.fileService.ValidateFilePath(fr): # if I am going to chmod something, I am probably going to # write to it. I'll proactively get a write lock. fr = core.path2fr(Path(path)) if acquire_wlock(fr): return 0 else: raise FuseOSError(errno.ENOACCESS) else: raise FuseOSError(errno.ENOENT)
def mkdir(self, path, mode): if not path2tags(path).issubset(self.tags): raise FuseOSError(ENOENT) os.mkdir(real(path), mode) # let the os generate a stat for us self.tags[base(path)] = stat(real(path)) os.rmdir(real(path)) self.update_fs_xattr()
def release(self, path, fd): result = os.close(fd) fr = core.path2fr(Path(path)) if acquire_wlock(fr): return result else: raise FuseOSError(errno.ENOACCESS)
def write(self, path, buf, offset, fd): fr = core.path2fr(Path(path)) if acquire_wlock(fr): os.lseek(fd, offset, os.SEEK_SET) return os.write(fd, buf) else: raise FuseOSError(errno.ENOACCESS)
def read(self, path, size, offset, fd): fr = core.path2fr(Path(path)) if acquire_rlock(fr): os.lseek(fd, offset, os.SEEK_SET) return os.read(fd, length) else: raise FuseOSError(errno.ENOACCESS)
def readdir(self, path, fh): if path != '/': raise FuseOSError(errno.ENOENT) yield '.' yield '..' for item in self.direntries: yield item
def _prep_write(self, path, trunclen): # We can't write in the virtual top level directory if len(path) < 4: raise FuseOSError(ENOENT) self._cancel_read() if self.writepath != path: self._flush_write() # If the file already exists, read its previous contents. # Check cache, since FUSE/VFS will have filled it. st = self.cache.getattr(path) if st != None and st['st_size'] > 0: if trunclen != None: if trunclen > 0: self.writebuf = self.read(path, trunclen, 0, None) else: self.writebuf = self.read(path, st['st_size'], 0, None) self._cancel_read() self.writepath = path self.writeattrs = 0 if self.writebuf == None: self.writebuf = b''
def readdir(self, path, fh): conf = self.get_conf() cert, filename, _ = conf.analyse_path(path) # Deal only with directories: if filename: raise FuseOSError(errno.ENOTDIR) # Extra attributes, just what it takes to support dirent->d_type: dir_attrs = {'st_mode': stat.S_IFDIR} reg_attrs = {'st_mode': stat.S_IFREG} # Yield common directory entries: yield '.', dir_attrs, 0 yield '..', dir_attrs, 0 if not cert: # Top-level directory flat_mode = conf.separator != '/' for cert in self.certificates(conf): if flat_mode: for filename in conf.files: yield cert + conf.separator + filename, reg_attrs, 0 else: yield cert, dir_attrs, 0 else: # Second-level directory for filename in conf.files: yield filename, reg_attrs, 0
def open(self, path, flags): accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR if (flags & accmode) != os.O_RDONLY: raise FuseOSError(errno.EACCES) self.next_fd += 1 return self.next_fd
def tags(): if any( base(path) in xattr2tags('./' + filename) for filename in os.listdir('.')): raise FuseOSError(ENOTEMPTY) else: del self.tags[base(path)] self.update_fs_xattr()
def read(self, path, length, offset, fh): self._l('read(%s, %s, %s, %s)' % (path, length, offset, fh)) try: fd = self.fhs[fh][1] fd.seek(offset) return fd.read(length) except KeyError: raise FuseOSError(errno.EBADFD)
def flush(self, path, fd): fr = core.path2fr(Path(path)) if acquire_wlock(fr): result = os.fsync(fd) upload(fr) return result else: raise FuseOSError(errno.ENOACCESS)
def utimens(self, path, times=None): fr = core.path2fr(Path(path)) if acquire_wlock(fr): # TODO: implement actual time-keeping, if we care. Right now, # this will just signify the users intent to continue working return else: raise FuseOSError(errno.ENOACCESS)
def readdir(self, path, fh=None): if path != '/': raise FuseOSError(errno.ENOENT) to_return = ['.', '..'] for part in self.partitions: to_return.append(str(part)) return to_return
def open(self, path, flags): full_path = self._fullpath(path) try: fh = os.open(full_path, flags) except OSError as e: raise FuseOSError(e.errno) self.keys[fh] = self._getkey(fh) return fh
def setxattr(self, path, name, value, options, position=0): full_path = self._full_path(path) print("getxattr "+str(self)+" path="+full_path+" name="+name+" value="+str(value)+" options="+str(options)) if name == "user.owncloud.virtual": (uid, gid, pid) = fuse_get_context() # CAUTION: Thread safe? be in self..., no? print("getxattr not impl. uid,gid,pid = ", uid, gid, pid) raise FuseOSError(errno.EREMOTE) # not impl. actually :-) return os.setxattr(full_path, name, value, flags=options)
def link(self, target, name): # hard target is always physical, to start with. # WARN: the link is likely to break into a copy as soon as the client is syncing... rpath, virt = self._oc_path(name) if virt: print("+ hard link virtual files cannot work.", file=sys.stderr) raise FuseOSError(errno.EREMOTE) return os.link(self._oc_path(target, virt=False)[0], rpath)
def rename(self, old, new): rpath, virt = self._oc_path(old) if virt: print( "+ rename virtual files is not supported by owncloud client.", file=sys.stderr) raise FuseOSError(errno.EREMOTE) return os.rename(rpath, self._oc_path(new, virt=False)[0])
def write(self, path, buf, offset, fh): print("+ write(%s, '%s', %s, %s, %s)" % (path, buf, offset, fh), file=sys.stderr) if fh in self.vfd: raise FuseOSError( errno.EREMOTE) # virtual files just cannot be written for now. else: os.lseek(fh, offset, os.SEEK_SET) return os.write(fh, buf)
def tags_operation(self, path, files_fn, tags_fn=notsup): tags = self.tags if (base(path) in self.tags) else xattr2tags( real(path)) if not path2tags(path).issubset(tags): raise FuseOSError(ENOENT) if base(path) in self.tags: return tags_fn() else: return files_fn()
def access(self, path, mode): """ libfuse documentation states: This will be called for the access() system call. If the 'default_permissions' mount option is given, this method is not called. Since this program enforces default_permissions, this method will never be called, which makes it dead simple to implement. """ raise FuseOSError(errno.ENOTSUP)
def write(self, path, buf, offset, fh): self._l('write(%s, %s, %s, %s)' % (path, buf, offset, fh)) try: fd = self.fhs[fh][1] fd.seek(offset) fd.write(buf) return len(buf) except KeyError: raise FuseOSError(errno.EBADFD)
def readdir(self, path, fh=None): full_path = self._fullpath(path) dirents = ['.', '..'] try: dirents.extend(os.listdir(full_path)) except OSError as e: raise FuseOSError(e.errno) for r in dirents: yield r