Beispiel #1
0
    async def rename(self, parent_inode_old: INode, name_old: bytes,
                     parent_inode_new: INode, name_new: bytes,
                     flags: RenameFlags, ctx: RequestContext) -> None:
        if flags:
            raise FUSEError(errno.EINVAL)

        old_path = self.paths.join(parent_inode_old, name_old)
        new_path = self.paths.join(parent_inode_new, name_new)
        try:
            os.rename(src=old_path, dst=new_path)
            inode = cast(INode, os.lstat(new_path).st_ino)
        except OSError as exc:
            raise FUSEError(exc.errno)

        try:
            self.paths.replace_path(inode=inode,
                                    old_path=old_path,
                                    new_path=new_path)
        except KeyError:
            self.runtime_errors.unknown_path(inode=inode, path=old_path)
Beispiel #2
0
 async def rmdir(self, inode_p, name, ctx):
     name = fsdecode(name)
     parent = self._inode_to_path(inode_p)
     path = os.path.join(parent, name)
     try:
         inode = os.lstat(path).st_ino
         os.rmdir(path)
     except OSError as exc:
         raise FUSEError(exc.errno)
     if inode in self._lookup_cnt:
         self._forget_path(inode, path)
Beispiel #3
0
 async def mknod(self, parent_inode: INode, name: bytes, mode: FileMode,
                 rdev: int, ctx: RequestContext) -> EntryAttributes:
     path = self.paths.join(parent_inode, name)
     try:
         os.mknod(path=path, mode=(mode & ~ctx.umask), device=rdev)
         os.chown(path=path, uid=ctx.uid, gid=ctx.gid)
     except OSError as exc:
         raise FUSEError(exc.errno)
     entry_attrs = self._get_entry_attrs(path)
     self.paths[entry_attrs.st_ino] = path
     return entry_attrs
Beispiel #4
0
 async def release(self, fd):
     LOG.info('release fd %s', fd)
     # Since we opened all files with its own fd,
     # we only need to close the fd, and not care about lookup count
     try:
         del self._fd2cryptors[fd]
     except KeyError as exc:
         LOG.error('Already closed: %s', exc)
     except Exception as exc:
         LOG.error('Error closing %d: %s', fd, exc)
         raise FUSEError(errno.EBADF)
Beispiel #5
0
    async def readlink(
        self,
        inode: InodeT,
        ctx: "RequestContext"
    ) -> FileNameT:
        '''Return target of symbolic link *inode*.

        *ctx* will be a `RequestContext` instance.
        '''

        raise FUSEError(errno.ENOSYS)
Beispiel #6
0
 async def statfs(self, ctx):
     LOG.info('Getting statfs')
     s = pyfuse3.StatvfsData()
     try:
         statfs = os.statvfs(self.rootdir)
     except OSError as exc:
         raise FUSEError(exc.errno)
     for attr in ('f_bsize', 'f_frsize', 'f_blocks', 'f_bfree', 'f_bavail',
                  'f_files', 'f_ffree', 'f_favail'):
         setattr(s, attr, getattr(statfs, attr))
     #s.f_namemax = statfs.f_namemax - (len(self.rootdir)+1)
     return s
Beispiel #7
0
    async def link(self, inode, new_inode_p, new_name, ctx):
        entry_p = await self.getattr(new_inode_p)
        if entry_p.st_nlink == 0:
            log.warn('Attempted to create entry %s with unlinked parent %d',
                     new_name, new_inode_p)
            raise FUSEError(errno.EINVAL)

        self.cursor.execute(
            "INSERT INTO contents (name, inode, parent_inode) VALUES(?,?,?)",
            (new_name, inode, new_inode_p))

        return await self.getattr(inode)
Beispiel #8
0
 async def unlink(self, parent_inode: INode, name: bytes,
                  ctx: RequestContext) -> None:
     path = self.paths.join(parent_inode, name)
     try:
         inode = cast(INode, os.lstat(path).st_ino)
         os.unlink(path)
     except OSError as exc:
         raise FUSEError(exc.errno) from None
     try:
         self.paths.forget_path(inode=inode, path=path)
     except KeyError:
         self.runtime_errors.unknown_path(inode=inode, path=path)
Beispiel #9
0
 async def statfs(self, ctx):
     root = self._inode_path_map[pyfuse3.ROOT_INODE]
     stat_ = pyfuse3.StatvfsData()
     try:
         statfs = os.statvfs(root)
     except OSError as exc:
         raise FUSEError(exc.errno)
     for attr in ('f_bsize', 'f_frsize', 'f_blocks', 'f_bfree', 'f_bavail',
                  'f_files', 'f_ffree', 'f_favail'):
         setattr(stat_, attr, getattr(statfs, attr))
     stat_.f_namemax = statfs.f_namemax - (len(root) + 1)
     return stat_
Beispiel #10
0
 async def create(self, inode_p, name, mode, flags, ctx):
     path = os.path.join(self._inode_to_path(inode_p), fsdecode(name))
     try:
         fd = os.open(path, flags | os.O_CREAT | os.O_TRUNC)
     except OSError as exc:
         raise FUSEError(exc.errno)
     attr = self._getattr(fd=fd)
     self._add_path(attr.st_ino, path)
     self._inode_fd_map[attr.st_ino] = fd
     self._fd_inode_map[fd] = attr.st_ino
     self._fd_open_count[fd] = 1
     return (pyfuse3.FileInfo(fh=fd), attr)
Beispiel #11
0
    async def statfs(
        self,
        ctx: "RequestContext"
    ) -> "StatvfsData":
        '''Get file system statistics.

        *ctx* will be a `RequestContext` instance.

        The method must return an appropriately filled `StatvfsData` instance.
        '''

        raise FUSEError(errno.ENOSYS)
Beispiel #12
0
    async def fsyncdir(
        self,
        fh: FileHandleT,
        datasync: bool
    ) -> None:
        '''Flush buffers for open directory *fh*.

        If *datasync* is true, only the directory contents should be
        flushed (in contrast to metadata about the directory itself).
        '''

        raise FUSEError(errno.ENOSYS)
Beispiel #13
0
 async def readlink(self, id_, ctx):
     log.debug('started with %d', id_)
     now_ns = time_ns()
     inode = self.inodes[id_]
     if inode.atime_ns < inode.ctime_ns or inode.atime_ns < inode.mtime_ns:
         inode.atime_ns = now_ns
     try:
         return self.db.get_val(
             "SELECT target FROM symlink_targets WHERE inode=?", (id_, ))
     except NoSuchRowError:
         log.warning('Inode does not have symlink target: %d', id_)
         raise FUSEError(errno.EINVAL)
 async def lookup(self, inode_p, name, ctx=None):
     self.autenticado(ctx)
     self.lastContextt = ctx
     
     if not self.autenticadoB:
         raise FUSEError(1)
     name = fsdecode(name)
     path = os.path.join(self._inode_to_path(inode_p), name)
     attr = self._getattr(path=path)
     if name != '.' and name != '..':
         self._add_path(attr.st_ino, path)
     return attr
Beispiel #15
0
    async def releasedir(
        self,
        fh: FileHandleT
    ) -> None:
        '''Release open directory.

        This method will be called exactly once for each `opendir` call. After
        *fh* has been released, no further `readdir` requests will be received
        for it (until it is opened again with `opendir`).
        '''

        raise FUSEError(errno.ENOSYS)
Beispiel #16
0
    def _create(self, id_p, name, mode, ctx, rdev=0, size=0):
        if name == CTRL_NAME:
            log.warning('Attempted to create s3ql control file at %s',
                        get_path(id_p, self.db, name))
            raise FUSEError(errno.EACCES)

        now_ns = time_ns()
        inode_p = self.inodes[id_p]

        if inode_p.locked:
            raise FUSEError(errno.EPERM)

        if inode_p.refcount == 0:
            log.warning('Attempted to create entry %s with unlinked parent %d',
                        name, id_p)
            raise FUSEError(errno.EINVAL)
        inode_p.mtime_ns = now_ns
        inode_p.ctime_ns = now_ns

        if inode_p.mode & stat.S_ISGID:
            gid = inode_p.gid
            if stat.S_ISDIR(mode):
                mode |= stat.S_ISGID
        else:
            gid = ctx.gid
        inode = self.inodes.create_inode(mtime_ns=now_ns,
                                         ctime_ns=now_ns,
                                         atime_ns=now_ns,
                                         uid=ctx.uid,
                                         gid=gid,
                                         mode=mode,
                                         refcount=1,
                                         rdev=rdev,
                                         size=size)

        self.db.execute(
            "INSERT INTO contents(name_id, inode, parent_inode) VALUES(?,?,?)",
            (self._add_name(name), inode.id, id_p))

        return inode
Beispiel #17
0
    async def readlink(self, inode, ctx):
        """Return target of symbolic link *inode*.
        *ctx* will be a `RequestContext` instance.

        Currently, this function only works in this FUSE filesystem.
        """
        entry = self.data.get_link_entry(inode, LinkTypes.SYMBOLIC)
        self.log.debug("Read link of {}".format(entry))
        if entry is None:
            raise FUSEError(errno.ENOENT)

        self.log.debug("Real path: %s", entry.link_path)
        return os.fsencode(entry.link_path)
Beispiel #18
0
    async def setxattr(self, inode, name, value, ctx):
        if inode != pyfuse3.ROOT_INODE or name != b'command':
            raise FUSEError(errno.ENOTSUP)

        if value == b'forget_entry':
            pyfuse3.invalidate_entry_async(pyfuse3.ROOT_INODE, self.hello_name)

            # Make sure that the request is pending before we return
            await trio.sleep(0.1)

        elif value == b'forget_inode':
            pyfuse3.invalidate_inode(self.hello_inode)

        elif value == b'store':
            pyfuse3.notify_store(self.hello_inode,
                                 offset=0,
                                 data=self.hello_data)

        elif value == b'terminate':
            pyfuse3.terminate()
        else:
            raise FUSEError(errno.EINVAL)
Beispiel #19
0
	async def mknod(self, inode_p, name, mode, rdev, ctx):
		# create special or ordinary file
		# mostly used for fifo / pipes but nowadays mkfifo would be better suited for that
		# mostly rare use cases
		path = os.path.join(self._inode_to_path(inode_p), fsdecode(name))
		try:
			os.mknod(path, mode=(mode & ~ctx.umask), device=rdev)
			os.chown(path, ctx.uid, ctx.gid)
		except OSError as exc:
			raise FUSEError(exc.errno)
		attr = FileInfo.getattr(path=path)
		self._add_path(attr.st_ino, path)
		return attr
Beispiel #20
0
 async def create(self, parent_inode: INode, name: bytes, mode: FileMode,
                  flags: int,
                  ctx: RequestContext) -> Tuple[FileInfo, EntryAttributes]:
     path = self.paths.join(parent_inode, name)
     try:
         fd = os.open(path, flags | os.O_CREAT | os.O_TRUNC)
     except OSError as exc:
         raise FUSEError(exc.errno)
     entry_attrs = self._get_entry_attrs(fd)
     inode = entry_attrs.st_ino
     self.paths[inode] = path
     self.descriptors[inode] = fd
     return FileInfo(fh=fd), entry_attrs
Beispiel #21
0
    async def release(self, fd):
        if self._fd_open_count[fd] > 1:
            self._fd_open_count[fd] -= 1
            return

        del self._fd_open_count[fd]
        inode = self._fd_inode_map[fd]
        del self._inode_fd_map[inode]
        del self._fd_inode_map[fd]
        try:
            os.close(fd)
        except OSError as exc:
            raise FUSEError(exc.errno)
Beispiel #22
0
 async def symlink(self, inode_p, name, target, ctx):
     name = fsdecode(name)
     target = fsdecode(target)
     parent = self._inode_to_path(inode_p)
     path = os.path.join(parent, name)
     try:
         os.symlink(target, path)
         os.chown(path, ctx.uid, ctx.gid, follow_symlinks=False)
     except OSError as exc:
         raise FUSEError(exc.errno)
     stat = os.lstat(path)
     self._add_path(stat.st_ino, path)
     return await self.getattr(stat.st_ino)
Beispiel #23
0
    async def open(self, id_, flags, ctx):
        log.debug('started with %d', id_)
        if ((flags & os.O_RDWR or flags & os.O_WRONLY)
                and (self.failsafe or self.inodes[id_].locked)):
            raise FUSEError(errno.EPERM)

        if flags & os.O_TRUNC:
            if not (flags & os.O_RDWR or flags & os.O_WRONLY):
                #  behaviour is not defined in POSIX, we opt for an error
                raise FUSEError(errno.EINVAL)
            attr = await self.getattr(id_, ctx)
            if stat.S_ISREG(attr.st_mode):
                attr.st_mtime_ns = time_ns()
                attr.st_size = 0
                await self.setattr(id_, attr, _TruncSetattrFields, None, ctx)
            elif stat.S_ISFIFO(attr.st_mode) or stat.S_ISBLK(attr.st_mode):
                #  silently ignore O_TRUNC when FIFO or terminal block device
                pass
            else:
                #  behaviour is not defined in POSIX, we opt for an error
                raise FUSEError(errno.EINVAL)

        return pyfuse3.FileInfo(fh=id_, keep_cache=True)
Beispiel #24
0
 def _get_entry_attrs(
         target: Union[str, FileDescriptor]) -> EntryAttributes:
     try:
         stat_result = os.lstat(target) if isinstance(
             target, str) else os.fstat(target)
     except OSError as exc:
         raise FUSEError(exc.errno)
     entry_attrs = EntryAttributes()
     for attr in dir(entry_attrs):
         if attr.startswith("st_") and hasattr(stat_result, attr):
             setattr(entry_attrs, attr, getattr(stat_result, attr))
     entry_attrs.attr_timeout = 0
     entry_attrs.entry_timeout = 0
     return entry_attrs
Beispiel #25
0
 async def open(self, inode, flags, ctx):
     if inode in self._inode_fd_map:
         fd = self._inode_fd_map[inode]
         self._fd_open_count[fd] += 1
         return pyfuse3.FileInfo(fh=fd)
     assert flags & os.O_CREAT == 0
     try:
         fd = os.open(self._inode_to_path(inode), flags)
     except OSError as exc:
         raise FUSEError(exc.errno)
     self._inode_fd_map[inode] = fd
     self._fd_inode_map[fd] = inode
     self._fd_open_count[fd] = 1
     return pyfuse3.FileInfo(fh=fd)
Beispiel #26
0
 async def symlink(self, parent_inode: INode, name: bytes, target: bytes,
                   ctx: RequestContext) -> EntryAttributes:
     path = self.paths.join(parent_inode, name)
     try:
         os.symlink(src=os.fsdecode(target), dst=path)
         os.chown(path=path,
                  uid=ctx.uid,
                  gid=ctx.gid,
                  follow_symlinks=False)
     except OSError as exc:
         raise FUSEError(exc.errno) from None
     symlink_inode = cast(INode, os.lstat(path).st_ino)
     self.paths[symlink_inode] = path
     return await self.getattr(inode=symlink_inode, ctx=ctx)
Beispiel #27
0
    def _replace(self, id_p_old, name_old, id_p_new, name_new, id_old, id_new):

        now_ns = time_ns()

        if self.db.has_val("SELECT 1 FROM contents WHERE parent_inode=?",
                           (id_new, )):
            log.info("Attempted to overwrite entry with children: %s",
                     get_path(id_p_new, self.db, name_new))
            raise FUSEError(errno.EINVAL)

        # Replace target
        name_id_new = self.db.get_val('SELECT id FROM names WHERE name=?',
                                      (name_new, ))
        self.db.execute(
            "UPDATE contents SET inode=? WHERE name_id=? AND parent_inode=?",
            (id_old, name_id_new, id_p_new))

        # Delete old name
        name_id_old = self._del_name(name_old)
        self.db.execute(
            'DELETE FROM contents WHERE name_id=? AND parent_inode=?',
            (name_id_old, id_p_old))

        inode_new = self.inodes[id_new]
        inode_new.refcount -= 1
        inode_new.ctime_ns = now_ns

        inode_p_old = self.inodes[id_p_old]
        inode_p_old.ctime_ns = now_ns
        inode_p_old.mtime_ns = now_ns

        inode_p_new = self.inodes[id_p_new]
        inode_p_new.ctime_ns = now_ns
        inode_p_new.mtime_ns = now_ns

        if inode_new.refcount == 0 and id_new not in self.open_inodes:
            self.cache.remove(
                id_new, 0, int(math.ceil(inode_new.size / self.max_obj_size)))
            # Since the inode is not open, it's not possible that new blocks
            # get created at this point and we can safely delete the inode
            self.db.execute(
                'UPDATE names SET refcount = refcount - 1 WHERE '
                'id IN (SELECT name_id FROM ext_attributes WHERE inode=?)',
                (id_new, ))
            self.db.execute('DELETE FROM names WHERE refcount=0')
            self.db.execute('DELETE FROM ext_attributes WHERE inode=?',
                            (id_new, ))
            self.db.execute('DELETE FROM symlink_targets WHERE inode=?',
                            (id_new, ))
            del self.inodes[id_new]
Beispiel #28
0
    def __init__(self, response):
        (success, response) = response

        if not success:
            if response == 2:
                raise (FUSEError(errno.ENOENT))
            elif response == 6:
                raise (FUSEError(errno.ENOENT))
            elif response == 9:
                raise (FUSEError(errno.EACCES))
            elif response == 22:
                raise (FUSEError(errno.ENOENT))
            elif response == 25:
                raise (FUSEError(errno.ENOENT))
            else:
                raise (Exception(response))

        if 'directory' in response:
            response = response['directory']
        if 'file' in response:
            response = response['file']

        self.response = response
Beispiel #29
0
    async def getxattr(self, inode, name, ctx):
        """Return extended attribute *name* of *inode*
        *ctx* will be a `RequestContext` instance.
        If the attribute does not exist, the method must raise `FUSEError` with
        an error code of `ENOATTR`. *name* will be of type `bytes`, but is
        guaranteed not to contain zero-bytes (``\\0``).
        """

        xattr = self.data.nodes[inode].xattr

        if name not in xattr:
            # https://github.com/libfuse/pyfuse3/blob/master/src/xattr.h ENOATTR = ENODATA
            raise FUSEError(errno.ENODATA)
        return xattr[name]
Beispiel #30
0
    async def open(self, inode, flags, ctx):
        logger.debug(f'open() called for inode {inode}')

        if inode in self._inode_to_fd:
            fd = self._inode_to_fd[inode]
            self._fd_to_open_count[fd] += 1
            return pyfuse3.FileInfo(fh=fd)
        else:
            asset = self._inode_to_asset[inode]
            if not asset:
                raise FUSEError(errno.ENOENT)

            try:
                fd = os.open(asset.original_path(self.photo_library.path),
                             flags)
            except OSError as err:
                raise FUSEError(err.errno)

            self._inode_to_fd[inode] = fd
            self._fd_to_inode[fd] = inode
            self._fd_to_open_count[fd] = 1

            return pyfuse3.FileInfo(fh=fd)