From 172c0d1a1218187f20460988a3c3d6212748f825 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Thu, 18 Jan 2018 13:39:57 -0800 Subject: [PATCH] libbtrfsutil: add btrfs_util_[gs]et_read_only() In the future, btrfs_util_[gs]et_subvolume_flags() might be useful, but since these are the only subvolume flags we've defined in all this time, this will do for now. Signed-off-by: Omar Sandoval Signed-off-by: David Sterba --- libbtrfsutil/btrfsutil.h | 33 +++++++++++++++ libbtrfsutil/python/btrfsutilpy.h | 2 + libbtrfsutil/python/module.c | 13 ++++++ libbtrfsutil/python/subvolume.c | 55 ++++++++++++++++++++++++ libbtrfsutil/python/tests/test_subvolume.py | 17 ++++++++ libbtrfsutil/subvolume.c | 66 +++++++++++++++++++++++++++++ 6 files changed, 186 insertions(+) diff --git a/libbtrfsutil/btrfsutil.h b/libbtrfsutil/btrfsutil.h index 2309fa4..ab96f44 100644 --- a/libbtrfsutil/btrfsutil.h +++ b/libbtrfsutil/btrfsutil.h @@ -279,6 +279,39 @@ enum btrfs_util_error btrfs_util_subvolume_info(const char *path, uint64_t id, enum btrfs_util_error btrfs_util_subvolume_info_fd(int fd, uint64_t id, struct btrfs_util_subvolume_info *subvol); +/** + * btrfs_util_get_subvolume_read_only() - Get whether a subvolume is read-only. + * @path: Subvolume path. + * @ret: Returned read-only flag. + * + * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. + */ +enum btrfs_util_error btrfs_util_get_subvolume_read_only(const char *path, + bool *ret); + +/** + * btrfs_util_get_subvolume_read_only_fd() - See + * btrfs_util_get_subvolume_read_only(). + */ +enum btrfs_util_error btrfs_util_get_subvolume_read_only_fd(int fd, bool *ret); + +/** + * btrfs_util_set_subvolume_read_only() - Set whether a subvolume is read-only. + * @path: Subvolume path. + * @read_only: New value of read-only flag. + * + * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. + */ +enum btrfs_util_error btrfs_util_set_subvolume_read_only(const char *path, + bool read_only); + +/** + * btrfs_util_set_subvolume_read_only_fd() - See + * btrfs_util_set_subvolume_read_only(). + */ +enum btrfs_util_error btrfs_util_set_subvolume_read_only_fd(int fd, + bool read_only); + struct btrfs_util_qgroup_inherit; /** diff --git a/libbtrfsutil/python/btrfsutilpy.h b/libbtrfsutil/python/btrfsutilpy.h index 2318621..aa17080 100644 --- a/libbtrfsutil/python/btrfsutilpy.h +++ b/libbtrfsutil/python/btrfsutilpy.h @@ -67,6 +67,8 @@ PyObject *is_subvolume(PyObject *self, PyObject *args, PyObject *kwds); PyObject *subvolume_id(PyObject *self, PyObject *args, PyObject *kwds); PyObject *subvolume_path(PyObject *self, PyObject *args, PyObject *kwds); PyObject *subvolume_info(PyObject *self, PyObject *args, PyObject *kwds); +PyObject *get_subvolume_read_only(PyObject *self, PyObject *args, PyObject *kwds); +PyObject *set_subvolume_read_only(PyObject *self, PyObject *args, PyObject *kwds); PyObject *create_subvolume(PyObject *self, PyObject *args, PyObject *kwds); void add_module_constants(PyObject *m); diff --git a/libbtrfsutil/python/module.c b/libbtrfsutil/python/module.c index 7b5d437..3173ff7 100644 --- a/libbtrfsutil/python/module.c +++ b/libbtrfsutil/python/module.c @@ -181,6 +181,19 @@ static PyMethodDef btrfsutil_methods[] = { "path -- string, bytes, path-like object, or open file descriptor\n" "id -- if not zero, instead of returning information about the\n" "given path, return information about the subvolume with this ID"}, + {"get_subvolume_read_only", (PyCFunction)get_subvolume_read_only, + METH_VARARGS | METH_KEYWORDS, + "get_subvolume_read_only(path) -> bool\n\n" + "Get whether a subvolume is read-only.\n\n" + "Arguments:\n" + "path -- string, bytes, path-like object, or open file descriptor"}, + {"set_subvolume_read_only", (PyCFunction)set_subvolume_read_only, + METH_VARARGS | METH_KEYWORDS, + "set_subvolume_read_only(path, read_only=True)\n\n" + "Set whether a subvolume is read-only.\n\n" + "Arguments:\n" + "path -- string, bytes, path-like object, or open file descriptor\n" + "read_only -- bool flag value"}, {"create_subvolume", (PyCFunction)create_subvolume, METH_VARARGS | METH_KEYWORDS, "create_subvolume(path, async=False)\n\n" diff --git a/libbtrfsutil/python/subvolume.c b/libbtrfsutil/python/subvolume.c index 31b6ca2..7648786 100644 --- a/libbtrfsutil/python/subvolume.c +++ b/libbtrfsutil/python/subvolume.c @@ -215,6 +215,61 @@ PyStructSequence_Desc SubvolumeInfo_desc = { PyTypeObject SubvolumeInfo_type; +PyObject *get_subvolume_read_only(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *keywords[] = {"path", NULL}; + struct path_arg path = {.allow_fd = true}; + enum btrfs_util_error err; + bool read_only; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "O&:get_subvolume_read_only", + keywords, &path_converter, &path)) + return NULL; + + if (path.path) { + err = btrfs_util_get_subvolume_read_only(path.path, &read_only); + } else { + err = btrfs_util_get_subvolume_read_only_fd(path.fd, + &read_only); + } + if (err) { + SetFromBtrfsUtilErrorWithPath(err, &path); + path_cleanup(&path); + return NULL; + } + + path_cleanup(&path); + return PyBool_FromLong(read_only); +} + +PyObject *set_subvolume_read_only(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *keywords[] = {"path", "read_only", NULL}; + struct path_arg path = {.allow_fd = true}; + enum btrfs_util_error err; + int read_only = 1; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "O&|p:set_subvolume_read_only", + keywords, &path_converter, &path, + &read_only)) + return NULL; + + if (path.path) + err = btrfs_util_set_subvolume_read_only(path.path, read_only); + else + err = btrfs_util_set_subvolume_read_only_fd(path.fd, read_only); + if (err) { + SetFromBtrfsUtilErrorWithPath(err, &path); + path_cleanup(&path); + return NULL; + } + + path_cleanup(&path); + Py_RETURN_NONE; +} + PyObject *create_subvolume(PyObject *self, PyObject *args, PyObject *kwds) { static char *keywords[] = {"path", "async", "qgroup_inherit", NULL}; diff --git a/libbtrfsutil/python/tests/test_subvolume.py b/libbtrfsutil/python/tests/test_subvolume.py index ecb0d7a..23871de 100644 --- a/libbtrfsutil/python/tests/test_subvolume.py +++ b/libbtrfsutil/python/tests/test_subvolume.py @@ -137,6 +137,23 @@ class TestSubvolume(BtrfsTestCase): # BTRFS_EXTENT_TREE_OBJECTID btrfsutil.subvolume_info(arg, 2) + def test_read_only(self): + for arg in self.path_or_fd(self.mountpoint): + with self.subTest(type=type(arg)): + btrfsutil.set_subvolume_read_only(arg) + self.assertTrue(btrfsutil.get_subvolume_read_only(arg)) + self.assertTrue(btrfsutil.subvolume_info(arg).flags & 1) + + btrfsutil.set_subvolume_read_only(arg, False) + self.assertFalse(btrfsutil.get_subvolume_read_only(arg)) + self.assertFalse(btrfsutil.subvolume_info(arg).flags & 1) + + btrfsutil.set_subvolume_read_only(arg, True) + self.assertTrue(btrfsutil.get_subvolume_read_only(arg)) + self.assertTrue(btrfsutil.subvolume_info(arg).flags & 1) + + btrfsutil.set_subvolume_read_only(arg, False) + def test_create_subvolume(self): subvol = os.path.join(self.mountpoint, 'subvol') diff --git a/libbtrfsutil/subvolume.c b/libbtrfsutil/subvolume.c index 07e124a..a8b8a76 100644 --- a/libbtrfsutil/subvolume.c +++ b/libbtrfsutil/subvolume.c @@ -399,6 +399,72 @@ PUBLIC enum btrfs_util_error btrfs_util_subvolume_info_fd(int fd, uint64_t id, return BTRFS_UTIL_OK; } +PUBLIC enum btrfs_util_error btrfs_util_get_subvolume_read_only_fd(int fd, + bool *read_only_ret) +{ + uint64_t flags; + int ret; + + ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags); + if (ret == -1) + return BTRFS_UTIL_ERROR_SUBVOL_GETFLAGS_FAILED; + + *read_only_ret = flags & BTRFS_SUBVOL_RDONLY; + return BTRFS_UTIL_OK; +} + +PUBLIC enum btrfs_util_error btrfs_util_get_subvolume_read_only(const char *path, + bool *ret) +{ + enum btrfs_util_error err; + int fd; + + fd = open(path, O_RDONLY); + if (fd == -1) + return BTRFS_UTIL_ERROR_OPEN_FAILED; + + err = btrfs_util_get_subvolume_read_only_fd(fd, ret); + SAVE_ERRNO_AND_CLOSE(fd); + return err; +} + +PUBLIC enum btrfs_util_error btrfs_util_set_subvolume_read_only(const char *path, + bool read_only) +{ + enum btrfs_util_error err; + int fd; + + fd = open(path, O_RDONLY); + if (fd == -1) + return BTRFS_UTIL_ERROR_OPEN_FAILED; + + err = btrfs_util_set_subvolume_read_only_fd(fd, read_only); + SAVE_ERRNO_AND_CLOSE(fd); + return err; +} + +PUBLIC enum btrfs_util_error btrfs_util_set_subvolume_read_only_fd(int fd, + bool read_only) +{ + uint64_t flags; + int ret; + + ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags); + if (ret == -1) + return BTRFS_UTIL_ERROR_SUBVOL_GETFLAGS_FAILED; + + if (read_only) + flags |= BTRFS_SUBVOL_RDONLY; + else + flags &= ~BTRFS_SUBVOL_RDONLY; + + ret = ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags); + if (ret == -1) + return BTRFS_UTIL_ERROR_SUBVOL_SETFLAGS_FAILED; + + return BTRFS_UTIL_OK; +} + static enum btrfs_util_error openat_parent_and_name(int dirfd, const char *path, char *name, size_t name_len, int *fd) -- 2.7.4