def test_notify_store(testfs): (mnt_dir, fs_state) = testfs with open(os.path.join(mnt_dir, 'message'), 'r') as fh: llfuse.setxattr(mnt_dir, 'command', b'store') fs_state.read_called = False assert fh.read() == 'hello world\n' assert not fs_state.read_called
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': llfuse.setxattr(ctrlfile, 's3ql_flushcache!', b'dummy') elif options.action == 'dropcache': llfuse.setxattr(ctrlfile, 's3ql_dropcache!', b'dummy') elif options.action == 'upload-meta': llfuse.setxattr(ctrlfile, 'upload-meta', b'dummy') elif options.action == 'log': level = getattr(logging, options.level.upper()) cmd = ('(%r, %r)' % (level, ','.join(options.modules))).encode() llfuse.setxattr(ctrlfile, 'logging', cmd) elif options.action == 'cachesize': llfuse.setxattr(ctrlfile, 'cachesize', ('%d' % (options.cachesize * 1024,)).encode())
def check(_wait_time=[0.01]): llfuse.setxattr(mnt_dir, 'command', b'forget_entry') time.sleep(_wait_time[0]) fs_state.lookup_called = False os.stat(path) _wait_time[0] += max(1, _wait_time[0]) return fs_state.lookup_called
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 not os.path.exists(name): raise QuietError('%r does not exist' % name) parent = os.path.dirname(os.path.abspath(name)) fstat_p = os.stat(parent) fstat = os.stat(name) if fstat_p.st_dev != fstat.st_dev: raise QuietError('%s is a mount point itself.' % name) ctrlfile = os.path.join(parent, CTRL_NAME) if not (CTRL_NAME not in llfuse.listdir(parent) and os.path.exists(ctrlfile)): raise QuietError('%s is not on an S3QL file system' % name) if os.stat(ctrlfile).st_uid != os.geteuid(): raise QuietError('Only root and the mounting user may run s3qlrm.') llfuse.setxattr(ctrlfile, 'rmtree', pickle.dumps((fstat_p.st_ino, os.path.basename(name)), pickle.HIGHEST_PROTOCOL))
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...') llfuse.setxattr(ctrlfile, 's3ql_flushcache!', b'dummy') # Get pid log.debug('Trying to get pid') pid = parse_literal(llfuse.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
def check(_wait_time=[0.01]): llfuse.setxattr(mnt_dir, 'command', b'forget_inode') time.sleep(_wait_time[0]) fs_state.read_called = False fh.seek(0) assert fh.read() == 'hello world\n' _wait_time[0] += max(1, _wait_time[0]) return fs_state.read_called
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 llfuse.listdir(self.mnt_dir) cmd = ('(%d, %r)' % (llfuse.ROOT_INODE, path2bytes(dirname))).encode() llfuse.setxattr('%s/%s' % (self.mnt_dir, CTRL_NAME), 'rmtree', cmd) assert_raises(FileNotFoundError, os.stat, fullname) assert dirname not in llfuse.listdir(self.mnt_dir)
def tst_bug382(self): dirname = self.newname() fullname = self.mnt_dir + "/" + dirname os.mkdir(fullname) self.assertTrue(stat.S_ISDIR(os.stat(fullname).st_mode)) self.assertTrue(dirname in llfuse.listdir(self.mnt_dir)) llfuse.setxattr('%s/%s' % (self.mnt_dir, CTRL_NAME), 'rmtree', pickle.dumps((llfuse.ROOT_INODE, path2bytes(dirname)), PICKLE_PROTOCOL)) self.assertRaises(FileNotFoundError, os.stat, fullname) self.assertTrue(dirname not in llfuse.listdir(self.mnt_dir))
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 llfuse.listdir(self.mnt_dir) llfuse.setxattr('%s/%s' % (self.mnt_dir, CTRL_NAME), 'rmtree', pickle.dumps((llfuse.ROOT_INODE, path2bytes(dirname)), PICKLE_PROTOCOL)) assert_raises(FileNotFoundError, os.stat, fullname) assert dirname not in llfuse.listdir(self.mnt_dir)
def tst_bug382(self): dirname = self.newname() fullname = self.mnt_dir + "/" + dirname os.mkdir(fullname) self.assertTrue(stat.S_ISDIR(os.stat(fullname).st_mode)) self.assertTrue(dirname in llfuse.listdir(self.mnt_dir)) llfuse.setxattr('%s/%s' % (self.mnt_dir, CTRL_NAME), 'rmtree', pickle.dumps((llfuse.ROOT_INODE, dirname), pickle.HIGHEST_PROTOCOL)) self.assertRaises(OSError, os.stat, fullname) self.assertTrue(dirname not in llfuse.listdir(self.mnt_dir))
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': llfuse.setxattr(ctrlfile, 's3ql_flushcache!', b'dummy') if options.action == 'upload-meta': llfuse.setxattr(ctrlfile, 'upload-meta', b'dummy') elif options.action == 'log': llfuse.setxattr( ctrlfile, 'logging', pickle.dumps((options.level, options.modules), PICKLE_PROTOCOL)) elif options.action == 'cachesize': llfuse.setxattr( ctrlfile, 'cachesize', pickle.dumps(options.cachesize * 1024, PICKLE_PROTOCOL))
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': llfuse.setxattr(ctrlfile, 's3ql_flushcache!', b'dummy') if options.action == 'upload-meta': llfuse.setxattr(ctrlfile, 'upload-meta', b'dummy') elif options.action == 'log': cmd = ('(%r, %r)' % (options.level, ','.join(options.modules))).encode() llfuse.setxattr(ctrlfile, 'logging', cmd) elif options.action == 'cachesize': llfuse.setxattr(ctrlfile, 'cachesize', ('%d' % options.cachesize * 1024).encode())
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 if not os.path.exists(path): raise QuietError('Mountpoint %r does not exist' % path) ctrlfile = os.path.join(path, CTRL_NAME) if not (CTRL_NAME not in llfuse.listdir(path) and os.path.exists(ctrlfile)): raise QuietError('Mountpoint is not an S3QL file system') if os.stat(ctrlfile).st_uid != os.geteuid() and os.geteuid() != 0: raise QuietError('Only root and the mounting user may run s3qlctrl.') if options.action == 'flushcache': llfuse.setxattr(ctrlfile, 's3ql_flushcache!', 'dummy') if options.action == 'upload-meta': llfuse.setxattr(ctrlfile, 'upload-meta', 'dummy') elif options.action == 'log': llfuse.setxattr(ctrlfile, 'logging', pickle.dumps((options.level, options.modules), pickle.HIGHEST_PROTOCOL)) elif options.action == 'cachesize': llfuse.setxattr(ctrlfile, 'cachesize', pickle.dumps(options.cachesize*1024))
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': llfuse.setxattr(ctrlfile, 's3ql_flushcache!', b'dummy') if options.action == 'upload-meta': llfuse.setxattr(ctrlfile, 'upload-meta', b'dummy') elif options.action == 'log': llfuse.setxattr(ctrlfile, 'logging', pickle.dumps((options.level, options.modules), PICKLE_PROTOCOL)) elif options.action == 'cachesize': llfuse.setxattr(ctrlfile, 'cachesize', pickle.dumps(options.cachesize * 1024, PICKLE_PROTOCOL))
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) llfuse.setxattr(ctrlfile, 'lock', pickle.dumps((fstat.st_ino,), PICKLE_PROTOCOL))
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) llfuse.setxattr(ctrlfile, 'lock', ('%d' % fstat.st_ino).encode())
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.') ctrlfile = os.path.join(parent, CTRL_NAME) if not (CTRL_NAME not in llfuse.listdir(parent) and os.path.exists(ctrlfile)): raise QuietError('Source and target are not on an S3QL file system') if os.stat(ctrlfile).st_uid != os.geteuid() and os.geteuid() != 0: raise QuietError('Only root and the mounting user may run s3qlcp.') try: os.mkdir(options.target) except OSError as exc: if exc.errno == errno.EACCES: raise QuietError('No permission to create target directory') else: raise fstat_t = os.stat(options.target) llfuse.setxattr(ctrlfile, 'copy', pickle.dumps((fstat_s.st_ino, fstat_t.st_ino), pickle.HIGHEST_PROTOCOL))
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))) cmd = ("(%d, %r)" % (fstat_p.st_ino, path2bytes(os.path.basename(name)))).encode() llfuse.setxattr(ctrlfile, "rmtree", cmd)
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))) llfuse.setxattr(ctrlfile, 'rmtree', pickle.dumps((fstat_p.st_ino, path2bytes(os.path.basename(name))), PICKLE_PROTOCOL))
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))) cmd = ('(%d, %r)' % (fstat_p.st_ino, path2bytes(os.path.basename(name)))).encode() llfuse.setxattr(ctrlfile, 'rmtree', cmd)
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') fstat_t = os.stat(options.target) llfuse.setxattr( ctrlfile, 'copy', pickle.dumps((fstat_s.st_ino, fstat_t.st_ino), PICKLE_PROTOCOL))
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') fstat_t = os.stat(options.target) llfuse.setxattr(ctrlfile, 'copy', ('(%d, %d)' % (fstat_s.st_ino, fstat_t.st_ino)).encode())
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") fstat_t = os.stat(options.target) llfuse.setxattr(ctrlfile, "copy", pickle.dumps((fstat_s.st_ino, fstat_t.st_ino), PICKLE_PROTOCOL))
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: llfuse.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
def blocking_umount(mountpoint): '''Invoke fusermount and wait for daemon to terminate.''' devnull = open('/dev/null', 'wb') 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...') llfuse.setxattr(ctrlfile, b's3ql_flushcache!', b'dummy') # Get pid log.debug('Trying to get pid') pid = int(llfuse.getxattr(ctrlfile, b's3ql_pid?')) log.debug('PID is %d', pid) # Get command line to make race conditions less-likely with open('/proc/%d/cmdline' % pid, 'r') as fh: cmdline = fh.readline() log.debug('cmdline is %r', cmdline) # Unmount log.debug('Unmounting...') # This seems to be necessary to prevent weird busy errors time.sleep(3) if os.getuid() == 0: umount_cmd = ['umount', mountpoint] else: umount_cmd = ['fusermount', '-u', mountpoint] if subprocess.call(umount_cmd) != 0: raise UmountError(mountpoint) # Wait for daemon log.debug('Uploading metadata...') step = 0.5 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 try: with open('/proc/%d/cmdline' % pid, 'r') as fh: if fh.readline() != cmdline: log.debug('PID still alive, but cmdline changed') # PID must have been reused, original process terminated break else: log.debug('PID still alive and commandline unchanged.') except OSError: # Process must have exited by now log.debug('Reading cmdline failed, assuming daemon has quit.') break # Process still exists, we wait log.debug('Daemon seems to be alive, waiting...') time.sleep(step) if step < 10: step *= 2