예제 #1
0
def test_notify_store(testfs):
    (mnt_dir, fs_state) = testfs
    with open(os.path.join(mnt_dir, 'message'), 'r') as fh:
        pyfuse3.setxattr(mnt_dir, 'command', b'store')
        fs_state.read_called = False
        assert fh.read() == 'hello world\n'
        assert not fs_state.read_called
예제 #2
0
def main(args=None):
    '''Control a mounted S3QL File System.'''

    if args is None:
        args = sys.argv[1:]

    options = parse_args(args)
    setup_logging(options)

    path = options.mountpoint

    ctrlfile = assert_fs_owner(path, mountpoint=True)

    if options.action == 'flushcache':
        pyfuse3.setxattr(ctrlfile, 's3ql_flushcache!', b'dummy')

    elif options.action == 'dropcache':
        pyfuse3.setxattr(ctrlfile, 's3ql_dropcache!', b'dummy')

    elif options.action == 'upload-meta':
        pyfuse3.setxattr(ctrlfile, 'upload-meta', b'dummy')

    elif options.action == 'log':
        level = getattr(logging, options.level.upper())
        cmd = ('(%r, %r)' % (level, ','.join(options.modules))).encode()
        pyfuse3.setxattr(ctrlfile, 'logging', cmd)

    elif options.action == 'cachesize':
        pyfuse3.setxattr(ctrlfile, 'cachesize',
                         ('%d' % (options.cachesize * 1024, )).encode())
예제 #3
0
 async def setxattr(self, inode: INode, name: bytes, value: bytes,
                    ctx: RequestContext) -> None:
     try:
         pyfuse3.setxattr(path=self.paths[inode],
                          name=_bytes2str(name),
                          value=value)
     except OSError as exc:
         raise FUSEError(exc.errno) from None
예제 #4
0
def main(args=None):
    '''Efficiently copy a directory tree'''

    if args is None:
        args = sys.argv[1:]

    options = parse_args(args)
    setup_logging(options)

    if not os.path.exists(options.source):
        raise QuietError('Source directory %r does not exist' % options.source)

    if os.path.exists(options.target):
        raise QuietError('Target directory %r must not yet exist.' %
                         options.target)

    parent = os.path.dirname(os.path.abspath(options.target))
    if not os.path.exists(parent):
        raise QuietError('Target parent %r does not exist' % parent)

    fstat_s = os.stat(options.source)
    fstat_p = os.stat(parent)
    if not stat.S_ISDIR(fstat_s.st_mode):
        raise QuietError('Source %r is not a directory' % options.source)

    if not stat.S_ISDIR(fstat_p.st_mode):
        raise QuietError('Target parent %r is not a directory' % parent)

    if fstat_p.st_dev != fstat_s.st_dev:
        raise QuietError('Source and target are not on the same file system.')

    if os.path.ismount(options.source):
        raise QuietError('%s is a mount point.' % options.source)

    ctrlfile = assert_fs_owner(options.source)
    try:
        os.mkdir(options.target)
    except PermissionError:
        raise QuietError('No permission to create target directory')

    # Make sure that write cache is flushed
    pyfuse3.syncfs(options.target)

    # Ensure the inode of the target folder stays in the kernel dentry cache
    # (We invalidate it during the copy)
    with os.scandir(options.target) as it:

        fstat_t = os.stat(options.target)
        pyfuse3.setxattr(ctrlfile, 'copy',
                         ('(%d, %d)' %
                          (fstat_s.st_ino, fstat_t.st_ino)).encode())
예제 #5
0
def test_invalidate_inode(testfs):
    (mnt_dir, fs_state) = testfs
    with open(os.path.join(mnt_dir, 'message'), 'r') as fh:
        assert fh.read() == 'hello world\n'
        assert fs_state.read_called
        fs_state.read_called = False
        fh.seek(0)
        assert fh.read() == 'hello world\n'
        assert not fs_state.read_called

        pyfuse3.setxattr(mnt_dir, 'command', b'forget_inode')
        fh.seek(0)
        assert fh.read() == 'hello world\n'
        assert fs_state.read_called
예제 #6
0
 def tst_bug382(self):
     dirname = self.newname()
     fullname = self.mnt_dir + "/" + dirname
     os.mkdir(fullname)
     assert stat.S_ISDIR(os.stat(fullname).st_mode)
     assert dirname in pyfuse3.listdir(self.mnt_dir)
     cmd = ('(%d, %r)' % (pyfuse3.ROOT_INODE, path2bytes(dirname))).encode()
     pyfuse3.setxattr('%s/%s' % (self.mnt_dir, CTRL_NAME), 'rmtree', cmd)
     # Invalidation is asynchronous...
     try:
         retry(5, lambda: not os.path.exists(fullname))
     except RetryTimeoutError:
         pass  # assert_raises should fail
     assert_raises(FileNotFoundError, os.stat, fullname)
     assert dirname not in pyfuse3.listdir(self.mnt_dir)
예제 #7
0
def test_invalidate_entry(testfs):
    (mnt_dir, fs_state) = testfs
    path = os.path.join(mnt_dir, 'message')
    os.stat(path)
    assert fs_state.lookup_called
    fs_state.lookup_called = False
    os.stat(path)
    assert not fs_state.lookup_called

    # Hardcoded sleeptimes - sorry! Needed because of the special semantics of
    # invalidate_entry()
    pyfuse3.setxattr(mnt_dir, 'command', b'forget_entry')
    time.sleep(1.1)
    os.stat(path)
    assert fs_state.lookup_called
예제 #8
0
def main(args=None):
    '''Make directory tree immutable'''

    if args is None:
        args = sys.argv[1:]

    options = parse_args(args)
    setup_logging(options)

    for name in options.path:
        if os.path.ismount(name):
            raise QuietError('%s is a mount point.' % name)
        ctrlfile = assert_fs_owner(name)
        fstat = os.stat(name)
        pyfuse3.setxattr(ctrlfile, 'lock', ('%d' % fstat.st_ino).encode())
예제 #9
0
def test_terminate(tmpdir):
    mnt_dir = str(tmpdir)
    mp = get_mp()
    with mp.Manager() as mgr:
        fs_state = mgr.Namespace()
        mount_process = mp.Process(target=run_fs, args=(mnt_dir, fs_state))

        mount_process.start()
        try:
            wait_for_mount(mount_process, mnt_dir)
            pyfuse3.setxattr(mnt_dir, 'command', b'terminate')
            mount_process.join(5)
            assert mount_process.exitcode is not None
        except:
            cleanup(mount_process, mnt_dir)
            raise
예제 #10
0
def main(args=None):
    '''Recursively delete files and directories in an S3QL file system'''

    if args is None:
        args = sys.argv[1:]

    options = parse_args(args)
    setup_logging(options)

    for name in options.path:
        if os.path.ismount(name):
            raise QuietError('%s is a mount point.' % name)

        ctrlfile = assert_fs_owner(name)
        fstat_p = os.stat(os.path.dirname(os.path.abspath(name)))

        # Make sure that write cache is flushed
        pyfuse3.syncfs(name)

        cmd = ('(%d, %r)' % (fstat_p.st_ino,
                             path2bytes(os.path.basename(name)))).encode()
        pyfuse3.setxattr(ctrlfile, 'rmtree', cmd)
예제 #11
0
def test_xattr():
    with tempfile.NamedTemporaryFile() as fh:
        key = 'user.new_attribute'
        assert _getxattr_helper(fh.name, key) is None
        value = b'a nice little bytestring'

        try:
            pyfuse3.setxattr(fh.name, key, value)
        except OSError as exc:
            if exc.errno == errno.ENOTSUP:
                pytest.skip('ACLs not supported for %s' % fh.name)
            raise
        assert _getxattr_helper(fh.name, key) == value

        if not hasattr(os, 'setxattr'):
            return

        key = 'user.another_new_attribute'
        assert _getxattr_helper(fh.name, key) is None
        value = b'a nice little bytestring, but slightly modified'
        os.setxattr(fh.name, key, value)
        assert _getxattr_helper(fh.name, key) == value
예제 #12
0
def blocking_umount(mountpoint):
    '''Invoke fusermount and wait for daemon to terminate.'''

    with open('/dev/null', 'wb') as devnull:
        if subprocess.call(['fuser', '-m', mountpoint],
                           stdout=devnull,
                           stderr=devnull) == 0:
            raise MountInUseError(mountpoint)

    ctrlfile = os.path.join(mountpoint, CTRL_NAME)

    log.debug('Flushing cache...')
    pyfuse3.setxattr(ctrlfile, 's3ql_flushcache!', b'dummy')

    # Get pid
    log.debug('Trying to get pid')
    pid = parse_literal(pyfuse3.getxattr(ctrlfile, 's3ql_pid?'), int)
    log.debug('PID is %d', pid)

    # Get command line to make race conditions less-likely
    cmdline = get_cmdline(pid)

    # Unmount
    log.debug('Unmounting...')

    if os.getuid() == 0 or platform.system() == 'Darwin':
        # MacOS X always uses umount rather than fusermount
        umount_cmd = ['umount', mountpoint]
    else:
        umount_cmd = ['fusermount', '-u', mountpoint]

    if subprocess.call(umount_cmd) != 0:
        raise UmountSubError(mountpoint)

    # Wait for daemon
    log.debug('Uploading metadata...')
    step = 0.1
    while True:
        try:
            os.kill(pid, 0)
        except OSError:
            log.debug('Kill failed, assuming daemon has quit.')
            break

        # Check that the process did not terminate and the PID
        # was reused by a different process
        cmdline2 = get_cmdline(pid)
        if cmdline2 is None:
            log.debug('Reading cmdline failed, assuming daemon has quit.')
            break
        elif cmdline2 == cmdline:
            log.debug('PID still alive and commandline unchanged.')
        else:
            log.debug('PID still alive, but cmdline changed')
            break

        # Process still exists, we wait
        log.debug('Daemon seems to be alive, waiting...')
        time.sleep(step)
        if step < 1:
            step += 0.1