Esempio n. 1
0
    async def setattr(self, id_, attr, fields, fh, ctx):
        """Handles FUSE setattr() requests"""
        inode = self.inodes[id_]
        if fh is not None:
            assert fh == id_
        now_ns = time_ns()

        if self.failsafe or inode.locked:
            raise FUSEError(errno.EPERM)

        if fields.update_mode:
            inode.mode = attr.st_mode

        if fields.update_uid:
            inode.uid = attr.st_uid

        if fields.update_gid:
            inode.gid = attr.st_gid

        if fields.update_atime:
            inode.atime_ns = attr.st_atime_ns

        if fields.update_mtime:
            inode.mtime_ns = attr.st_mtime_ns

        inode.ctime_ns = now_ns

        # This needs to go last, because the call to cache.remove and cache.get
        # are asynchronous and may thus evict the *inode* object from the cache.
        if fields.update_size:
            len_ = attr.st_size

            # Determine blocks to delete
            last_block = len_ // self.max_obj_size
            cutoff = len_ % self.max_obj_size
            total_blocks = int(math.ceil(inode.size / self.max_obj_size))

            # Adjust file size
            inode.size = len_

            # Delete blocks and truncate last one if required
            if cutoff == 0:
                await self.cache.remove(id_, last_block, total_blocks)
            else:
                await self.cache.remove(id_, last_block + 1, total_blocks)
                try:
                    async with self.cache.get(id_, last_block) as fh:
                        fh.truncate(cutoff)
                except NoSuchObject as exc:
                    log.warning('Backend lost block %d of inode %d (id %s)!',
                                last_block, id_, exc.key)
                    raise

                except CorruptedObjectError as exc:
                    log.warning(
                        'Backend returned malformed data for block %d of inode %d (%s)',
                        last_block, id_, exc)
                    self.failsafe = True
                    self.broken_blocks[id_].add(last_block)
                    raise FUSEError(errno.EIO)

        return inode.entry_attributes()
Esempio n. 2
0
    async def remove_tree(self, id_p0, name0):
        '''Remove directory tree'''

        if self.failsafe:
            raise FUSEError(errno.EPERM)

        log.debug('started with %d, %s', id_p0, name0)

        if self.inodes[id_p0].locked:
            raise FUSEError(errno.EPERM)

        id0 = self._lookup(id_p0, name0, ctx=None).id
        queue = [id0]  # Directories that we still need to delete
        batch_size = 200  # Entries to process before checkpointing
        stamp = time.time()  # Time of last checkpoint
        while queue:  # For every directory
            id_p = queue.pop()
            is_open = id_p in self.open_inodes

            # Per https://sqlite.org/isolation.html, results of removing rows
            # during select are undefined. Therefore, process data in chunks.
            # This is also a nice opportunity to release the GIL...
            query_chunk = self.db.get_list(
                'SELECT name, name_id, inode FROM contents_v WHERE '
                'parent_inode=? LIMIT %d' % batch_size, (id_p, ))
            reinserted = False
            for (name, name_id, id_) in query_chunk:
                if self.db.has_val(
                        'SELECT 1 FROM contents WHERE parent_inode=?',
                    (id_, )):
                    # First delete subdirectories
                    if not reinserted:
                        queue.append(id_p)
                        reinserted = True
                    queue.append(id_)
                else:
                    if is_open:
                        pyfuse3.invalidate_entry_async(id_p, name)
                    await self._remove(id_p, name, id_, force=True)

            if query_chunk and not reinserted:
                # Make sure to re-insert the directory to process the remaining
                # contents and delete the directory itself.
                queue.append(id_p)

            dt = time.time() - stamp
            batch_size = int(batch_size * CHECKPOINT_INTERVAL / dt)
            batch_size = min(batch_size, 200)  # somewhat arbitrary...
            batch_size = max(batch_size, 20000)
            log.debug('Adjusting batch_size to %d and yielding', batch_size)
            await trio.lowlevel.checkpoint()
            log.debug('re-acquired lock')
            stamp = time.time()

        if id_p0 in self.open_inodes:
            log.debug('invalidate_entry(%d, %r)', id_p0, name0)
            pyfuse3.invalidate_entry_async(id_p0, name0)
        await self._remove(id_p0, name0, id0, force=True)

        await self.forget([(id0, 1)])
        log.debug('finished')
Esempio n. 3
0
    async def copy_tree(self, src_id, target_id):
        '''Efficiently copy directory tree'''

        if self.failsafe:
            raise FUSEError(errno.EPERM)

        log.debug('started with %d, %d', src_id, target_id)

        # To avoid lookups and make code tidier
        make_inode = self.inodes.create_inode
        db = self.db

        # Copy target attributes
        # These come from setxattr, so they may have been deleted
        # without being in open_inodes
        try:
            src_inode = self.inodes[src_id]
            target_inode = self.inodes[target_id]
        except KeyError:
            raise FUSEError(errno.ENOENT)
        for attr in ('atime_ns', 'ctime_ns', 'mtime_ns', 'mode', 'uid', 'gid'):
            setattr(target_inode, attr, getattr(src_inode, attr))

        # We first replicate into a dummy inode, so that we
        # need to invalidate only once.
        now_ns = time_ns()
        tmp = make_inode(mtime_ns=now_ns,
                         ctime_ns=now_ns,
                         atime_ns=now_ns,
                         uid=0,
                         gid=0,
                         mode=0,
                         refcount=0)

        queue = [(src_id, tmp.id, -1)]
        id_cache = dict()
        while queue:
            (src_id, target_id, off) = queue.pop()
            log.debug('Processing directory (%d, %d, %d)', src_id, target_id,
                      off)
            processed = 0
            with db.query(
                    'SELECT name_id, inode FROM contents WHERE parent_inode=? '
                    'AND name_id > ? ORDER BY name_id', (src_id, off)) as res:
                for (name_id, id_) in res:

                    # Make sure that all blocks are in the database
                    if id_ in self.open_inodes:
                        await self.cache.start_flush(id_)

                    if id_ not in id_cache:
                        inode = self.inodes[id_]
                        inode_new = make_inode(refcount=1,
                                               mode=inode.mode,
                                               size=inode.size,
                                               uid=inode.uid,
                                               gid=inode.gid,
                                               mtime_ns=inode.mtime_ns,
                                               atime_ns=inode.atime_ns,
                                               ctime_ns=inode.ctime_ns,
                                               rdev=inode.rdev)

                        id_new = inode_new.id

                        if inode.refcount != 1:
                            id_cache[id_] = id_new

                        db.execute(
                            'INSERT INTO symlink_targets (inode, target) '
                            'SELECT ?, target FROM symlink_targets WHERE inode=?',
                            (id_new, id_))

                        db.execute(
                            'INSERT INTO ext_attributes (inode, name_id, value) '
                            'SELECT ?, name_id, value FROM ext_attributes WHERE inode=?',
                            (id_new, id_))
                        db.execute(
                            'UPDATE names SET refcount = refcount + 1 WHERE '
                            'id IN (SELECT name_id FROM ext_attributes WHERE inode=?)',
                            (id_, ))

                        processed += db.execute(
                            'INSERT INTO inode_blocks (inode, blockno, block_id) '
                            'SELECT ?, blockno, block_id FROM inode_blocks '
                            'WHERE inode=?', (id_new, id_))
                        db.execute(
                            'REPLACE INTO blocks (id, hash, refcount, size, obj_id) '
                            'SELECT id, hash, refcount+COUNT(id), size, obj_id '
                            'FROM inode_blocks JOIN blocks ON block_id = id '
                            'WHERE inode = ? GROUP BY id', (id_new, ))

                        if db.has_val(
                                'SELECT 1 FROM contents WHERE parent_inode=?',
                            (id_, )):
                            queue.append((id_, id_new, -1))
                    else:
                        id_new = id_cache[id_]
                        self.inodes[id_new].refcount += 1

                    db.execute(
                        'INSERT INTO contents (name_id, inode, parent_inode) VALUES(?, ?, ?)',
                        (name_id, id_new, target_id))
                    db.execute(
                        'UPDATE names SET refcount=refcount+1 WHERE id=?',
                        (name_id, ))

                    # Break every once in a while - note that we can't yield
                    # right here because there's an active DB query.
                    processed += 1
                    if processed > 200:
                        queue.append((src_id, target_id, name_id))
                        break

            await trio.lowlevel.checkpoint()

        # Make replication visible
        self.db.execute(
            'UPDATE contents SET parent_inode=? WHERE parent_inode=?',
            (target_inode.id, tmp.id))
        del self.inodes[tmp.id]
        pyfuse3.invalidate_inode(target_inode.id)

        log.debug('finished')
Esempio n. 4
0
 async def read(self, fh: FileHandle, off: int, size: int) -> bytes:
     try:
         os.lseek(fh, off, os.SEEK_SET)
         return os.read(fh, size)
     except OSError as exc:
         raise FUSEError(exc.errno) from None
Esempio n. 5
0
    async def setxattr(self, id_, name, value, ctx):
        log.debug('started with %d, %r, %r', id_, name, value)

        # Handle S3QL commands
        if id_ == CTRL_INODE:
            if name == b's3ql_flushcache!':
                self.inodes.flush()
                await self.cache.flush()

            elif name == b's3ql_dropcache!':
                self.inodes.drop()
                await self.cache.drop()

            elif name == b'copy':
                try:
                    tup = parse_literal(value, (int, int))
                except ValueError:
                    log.warning('Received malformed command via control inode')
                    raise FUSEError.EINVAL()
                await self.copy_tree(*tup)

            elif name == b'upload-meta':
                if self.upload_task is not None:
                    self.inodes.flush()
                    self.upload_task.event.set()
                else:
                    raise FUSEError(errno.ENOTTY)

            elif name == b'lock':
                try:
                    id_ = parse_literal(value, int)
                except ValueError:
                    log.warning('Received malformed command via control inode')
                    raise FUSEError.EINVAL()
                await self.lock_tree(id_)

            elif name == b'rmtree':
                try:
                    tup = parse_literal(value, (int, bytes))
                except ValueError:
                    log.warning('Received malformed command via control inode')
                    raise FUSEError.EINVAL()
                await self.remove_tree(*tup)

            elif name == b'logging':
                try:
                    (lvl, modules) = parse_literal(value, (int, str))
                except (ValueError, KeyError):
                    log.warning('Received malformed command via control inode')
                    raise FUSEError.EINVAL()
                update_logging(lvl, modules.split(',') if modules else None)

            elif name == b'cachesize':
                try:
                    self.cache.cache.max_size = parse_literal(value, int)
                except ValueError:
                    log.warning('Received malformed command via control inode')
                    raise FUSEError.EINVAL()
                log.debug('updated cache size to %d bytes',
                          self.cache.cache.max_size)

            else:
                log.warning('Received unknown command via control inode')
                raise FUSEError(errno.EINVAL)

        # http://code.google.com/p/s3ql/issues/detail?id=385
        elif name in (b'system.posix_acl_access', b'system.posix_acl_default'):
            raise FUSEError(ACL_ERRNO)

        else:
            if self.failsafe or self.inodes[id_].locked:
                raise FUSEError(errno.EPERM)

            if len(value) > deltadump.MAX_BLOB_SIZE:
                raise FUSEError(errno.EINVAL)

            self.db.execute(
                'INSERT OR REPLACE INTO ext_attributes (inode, name_id, value) '
                'VALUES(?, ?, ?)', (id_, self._add_name(name), value))
            self.inodes[id_].ctime_ns = time_ns()
Esempio n. 6
0
 async def link(self, inode, new_inode_p, new_name, ctx):
     raise (FUSEError(errno.ENOTSUP))
Esempio n. 7
0
    async def mkdir(self, inode_p, name, mode, ctx):
        path = os.path.join(self._inode_to_path(inode_p), fsdecode(name))
        print("path mkdir: ", path)

        start = "/sys/class/gpio/"
        print("start: ", start)
        relative_path = os.path.relpath(path, start)
        print("relative path ", relative_path)

        print("\n")
        print("listagpio2 utilizzabile per test2: ", listgpio)

        if path.startswith('/sys/class/gpio/'):
            start = '/sys/class/gpio/'
            relative_path = os.path.relpath(path, start)
            print("relative path ", relative_path)
            if relative_path in listgpio:
                print(relative_path, "trovato\n")
                try:
                    os.mkdir(path, mode=(mode & ~ctx.umask))
                    os.chown(path, ctx.uid, ctx.gid)
                except OSError as exc:
                    raise FUSEError(exc.errno)

            else:
                print("questo gpio non puoi usarlo2, puoi utilizzare dall'8 al 15!")

            attr = self._getattr(path=path)
            self._add_path(attr.st_ino, path)
            return attr

        elif path.startswith('/sys/devices/platform/soc/3f200000.gpio/gpiochip0/gpio/'):
            start = '/sys/devices/platform/soc/3f200000.gpio/gpiochip0/gpio/'
            relative_path = os.path.relpath(path, start)
            print("relative path ", relative_path)
            if relative_path in listgpio:
                print(relative_path, "trovato\n")
                try:
                    os.mkdir(path, mode=(mode & ~ctx.umask))
                    os.chown(path, ctx.uid, ctx.gid)
                except OSError as exc:
                    raise FUSEError(exc.errno)

            else:
                print("questo gpio non puoi usarlo2, puoi utilizzare dall'8 al 15!")

            attr = self._getattr(path=path)
            self._add_path(attr.st_ino, path)
            return attr

        else:
            print("caso non analizzato\n\n\n")

            try:
                os.mkdir(path, mode=(mode & ~ctx.umask))
                os.chown(path, ctx.uid, ctx.gid)
            except OSError as exc:
                raise FUSEError(exc.errno)

            attr = self._getattr(path=path)
            self._add_path(attr.st_ino, path)
            return attr
Esempio n. 8
0
 def _fd_to_cryptors(self, fd):
     v = self._fd2cryptors.get(fd)
     if v is None:
         LOG.error('Error finding cryptor for %d: %r', fd, exc)
         raise FUSEError(errno.EBADF)
     return v
Esempio n. 9
0
	async def access(self, inode, mode, ctx):
		# for permissions but eh
		raise FUSEError(errno.ENOSYS)
Esempio n. 10
0
async def _not_permitted_func(name, *args, **kwargs):
    LOG.debug('Function %s not permitted', name)
    raise FUSEError(errno.EPERM)  # not permitted
Esempio n. 11
0
 def _inode_to_path(self, inode):
     v = self._inode2path.get(inode)
     if v is None:
         raise FUSEError(errno.ENOENT)
     return v
Esempio n. 12
0
 async def write(self, fh: FileHandle, off: int, buf: bytes) -> int:
     try:
         os.lseek(fh, off, os.SEEK_SET)
         return os.write(fh, buf)
     except OSError as exc:
         raise FUSEError(exc.errno) from None
Esempio n. 13
0
 async def release(self, fh: FileHandle) -> None:
     if self.descriptors.release(cast(FileDescriptor, fh)):
         try:
             os.close(fh)
         except OSError as exc:
             raise FUSEError(exc.errno)
Esempio n. 14
0
 async def readlink(self, inode: INode, ctx: RequestContext) -> bytes:
     try:
         return os.fsencode(os.readlink(self.paths[inode]))
     except OSError as exc:
         raise FUSEError(exc.errno) from None
Esempio n. 15
0
 async def readlink(self, inode: int, ctx: pyfuse3.RequestContext):
     raise (FUSEError(errno.ENOTSUP))  # Error: not supported
Esempio n. 16
0
	async def setxattr(self, inode, name, value, ctx):
		raise FUSEError(errno.ENOSYS)
Esempio n. 17
0
 async def symlink(self, inode_p: int, name: bytes, target: bytes,
                   ctx: pyfuse3.RequestContext):
     raise (FUSEError(errno.ENOTSUP))  # Error: not supported
Esempio n. 18
0
	async def listxattr(self, inode, ctx):
		raise FUSEError(errno.ENOSYS)
Esempio n. 19
0
    async def mkdir(self, inode_p, name, mode, ctx):
        path = os.path.join(self._inode_to_path(inode_p), fsdecode(name))
        print("path mkdir: ", path)

        start = "/sys/class/gpio/"
        print("start: ", start)
        relative_path = os.path.relpath(path, start)
        print("relative path ", relative_path)

        config = configparser.ConfigParser()
        config.sections()
        config.read('example.ini')
        config.sections()

        listgpio = ['gpiochip0', 'gpiochip504']

        print("\n\n\n")

        for count in range(1, 27):
            print(count, "-gpio" + str(count))
            print(config['gpiotest3']['gpio' + str(count)])
            if config['gpiotest3']['gpio' + str(count)] == 'yes':
                print("ok2")
                listgpio.append("gpio" + str(count))
            print("\n")

        print("\n")
        print("listagpio2 utilizzabile per test3: ", listgpio)

        if path.startswith('/sys/class/gpio/'):
            start = '/sys/class/gpio/'
            relative_path = os.path.relpath(path, start)
            print("relative path ", relative_path)
            if relative_path in listgpio:
                print(relative_path, "trovato\n")
                try:
                    os.mkdir(path, mode=(mode & ~ctx.umask))
                    os.chown(path, ctx.uid, ctx.gid)
                except OSError as exc:
                    raise FUSEError(exc.errno)

            else:
                print(
                    "questo gpio non puoi usarlo2, puoi utilizzare dall'8 al 15!"
                )

            attr = self._getattr(path=path)
            self._add_path(attr.st_ino, path)
            return attr

        elif path.startswith(
                '/sys/devices/platform/soc/3f200000.gpio/gpiochip0/gpio/'):
            start = '/sys/devices/platform/soc/3f200000.gpio/gpiochip0/gpio/'
            relative_path = os.path.relpath(path, start)
            print("relative path ", relative_path)
            if relative_path in listgpio:
                print(relative_path, "trovato\n")
                try:
                    os.mkdir(path, mode=(mode & ~ctx.umask))
                    os.chown(path, ctx.uid, ctx.gid)
                except OSError as exc:
                    raise FUSEError(exc.errno)

            else:
                print(
                    "questo gpio non puoi usarlo2, puoi utilizzare dall'8 al 15!"
                )

            attr = self._getattr(path=path)
            self._add_path(attr.st_ino, path)
            return attr

        else:
            print("caso non analizzato\n\n\n")

            try:
                os.mkdir(path, mode=(mode & ~ctx.umask))
                os.chown(path, ctx.uid, ctx.gid)
            except OSError as exc:
                raise FUSEError(exc.errno)

            attr = self._getattr(path=path)
            self._add_path(attr.st_ino, path)
            return attr
Esempio n. 20
0
	async def removexattr(self, inode, name, ctx):
		raise FUSEError(errno.ENOSYS)
Esempio n. 21
0
    async def setattr(self, inode, attr, fields, fh, ctx):
        # We use the f* functions if possible so that we can handle
        # a setattr() call for an inode without associated directory
        # handle.
        if fh is None:
            path_or_fh = self._inode_to_path(inode)
            truncate = os.truncate
            chmod = os.chmod
            chown = os.chown
            stat = os.lstat
        else:
            path_or_fh = fh
            truncate = os.ftruncate
            chmod = os.fchmod
            chown = os.fchown
            stat = os.fstat

        try:
            if fields.update_size:
                truncate(path_or_fh, attr.st_size)

            if fields.update_mode:
                # Under Linux, chmod always resolves symlinks so we should
                # actually never get a setattr() request for a symbolic
                # link.
                assert not stat_m.S_ISLNK(attr.st_mode)
                chmod(path_or_fh, stat_m.S_IMODE(attr.st_mode))

            if fields.update_uid:
                chown(path_or_fh, attr.st_uid, -1, follow_symlinks=False)

            if fields.update_gid:
                chown(path_or_fh, -1, attr.st_gid, follow_symlinks=False)

            if fields.update_atime and fields.update_mtime:
                if fh is None:
                    os.utime(path_or_fh,
                             None,
                             follow_symlinks=False,
                             ns=(attr.st_atime_ns, attr.st_mtime_ns))
                else:
                    os.utime(path_or_fh,
                             None,
                             ns=(attr.st_atime_ns, attr.st_mtime_ns))
            elif fields.update_atime or fields.update_mtime:
                # We can only set both values, so we first need to retrieve the
                # one that we shouldn't be changing.
                oldstat = stat(path_or_fh)
                if not fields.update_atime:
                    attr.st_atime_ns = oldstat.st_atime_ns
                else:
                    attr.st_mtime_ns = oldstat.st_mtime_ns
                if fh is None:
                    os.utime(path_or_fh,
                             None,
                             follow_symlinks=False,
                             ns=(attr.st_atime_ns, attr.st_mtime_ns))
                else:
                    os.utime(path_or_fh,
                             None,
                             ns=(attr.st_atime_ns, attr.st_mtime_ns))

        except OSError as exc:
            raise FUSEError(exc.errno)

        return await self.getattr(inode)
Esempio n. 22
0
    async def mkdir(self, inode_p, name, mode, ctx):
        path = os.path.join(self._inode_to_path(inode_p), fsdecode(name))
        print("path mkdir: ", path)

        start = "/sys/class/gpio/"
        print("start: ", start)
        relative_path = os.path.relpath(path, start)
        print("relative path ", relative_path)

        if path.startswith('/sys/class/gpio/'):
            print("si tratta di gpio")
            start = "/sys/class/gpio/"
            print("start: ", start)
            relative_path = os.path.relpath(path, start)
            print("relative path ", relative_path, "\n\n")

            config = configparser.ConfigParser()
            config.sections()
            config.read('example.ini')
            config.sections()

            listgpio = ["gpiochip0", "gpiochip504", "export", "unexport"]

            for count in range(1, 27):
                # print(count, "gpio" + str(count))
                # print(config['gpiotest2']['gpio' + str(count)])
                if config['gpiotest2']['gpio' + str(count)] == 'yes':
                    print(count, "gpio" + str(count), "ok")
                    # print("ok")
                    listgpio.append("gpio" + str(count))
                print("\n")

            print("la lista di gpio disponibili per test2 è: ", listgpio, "\n")

            if any(i in relative_path for i in listgpio):
                print(relative_path, "trovato\n")
                try:
                    os.mkdir(path, mode=(mode & ~ctx.umask))
                    os.chown(path, ctx.uid, ctx.gid)
                except OSError as exc:
                    raise FUSEError(exc.errno)

            else:
                print(
                    "questo gpio non puoi usarlo2, puoi utilizzare dall'8 al 15!"
                )
            attr = self._getattr(path=path)
            self._add_path(attr.st_ino, path)
            return attr

        elif path.startswith(
                '/sys/devices/platform/soc/3f200000.gpio/gpiochip0/gpio/'):
            print("si tratta di gpio indirettamente")
            start = "/sys/devices/platform/soc/3f200000.gpio/gpiochip0/"
            print("start: ", start)
            relative_path = os.path.relpath(path, start)
            print("relative path ", relative_path, "\n\n")

            config = configparser.ConfigParser()
            config.sections()
            config.read('example.ini')
            config.sections()

            listgpio = ["gpiochip0", "gpiochip504", "export", "unexport"]

            for count in range(1, 27):
                # print(count, "gpio" + str(count))
                # print(config['gpiotest2']['gpio' + str(count)])
                if config['gpiotest2']['gpio' + str(count)] == 'yes':
                    print(count, "gpio" + str(count), "ok")
                    # print("ok")
                    listgpio.append("gpio" + str(count))
                print("\n")

            print("la lista di gpio disponibili per test2 è: ", listgpio, "\n")

            if any(i in relative_path for i in listgpio):
                print(relative_path, "trovato\n")
                try:
                    os.mkdir(path, mode=(mode & ~ctx.umask))
                    os.chown(path, ctx.uid, ctx.gid)
                except OSError as exc:
                    raise FUSEError(exc.errno)

            else:
                print(
                    "questo gpio non puoi usarlo2, puoi utilizzare dall'8 al 15!"
                )
            attr = self._getattr(path=path)
            self._add_path(attr.st_ino, path)
            return attr

        else:
            print("caso non analizzato\n\n")
            path = os.path.join(self._inode_to_path(inode_p), fsdecode(name))
            try:
                os.mkdir(path, mode=(mode & ~ctx.umask))
                os.chown(path, ctx.uid, ctx.gid)
            except OSError as exc:
                raise FUSEError(exc.errno)
            attr = self._getattr(path=path)
            self._add_path(attr.st_ino, path)
            return attr