From patchwork Fri Jan 26 18:40:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Omar Sandoval X-Patchwork-Id: 10186743 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id D4A77601D5 for ; Fri, 26 Jan 2018 18:41:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C3F5E29EC8 for ; Fri, 26 Jan 2018 18:41:43 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B759529EE1; Fri, 26 Jan 2018 18:41:43 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0434D29EC8 for ; Fri, 26 Jan 2018 18:41:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751849AbeAZSlg (ORCPT ); Fri, 26 Jan 2018 13:41:36 -0500 Received: from mail-pg0-f66.google.com ([74.125.83.66]:41631 "EHLO mail-pg0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751632AbeAZSlb (ORCPT ); Fri, 26 Jan 2018 13:41:31 -0500 Received: by mail-pg0-f66.google.com with SMTP id 136so781698pgd.8 for ; Fri, 26 Jan 2018 10:41:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=osandov-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=APXCCJZ0sC7WQfkKvmr4T+aDRc7qCvu6/OorEAd4P8Q=; b=gv6DyIJfCNNUxXwen7zcC0PNhuw6ULsn6Md1XlPXxBKKLcpaN4dpICX0yHXsDi5BJd jEuw+yeXep0++aVwjfsNk5xZi0Z3UIf5pWph/KwjmW7zu7t3XKq8XEnEJU+Nws8Fh2y2 GXV/oBxlyYu8jbQwAwYlkZzWPZScB0Aia38vNMl6iuxBAMZVeA1ifs1kLS+lQyJq4WWB uNf6bqQ+MfSfAt3y46GJtTVDVLw48tOYe+XmAwGWf3qL8rc60PzssNLOzFopN0QB+A1B F+rXY3HLCVVWp+sqkcnQjiAqBSiztLYeqbHBlwezcYFos03hQy81VcaObKJjq4LF3ASB UaJg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=APXCCJZ0sC7WQfkKvmr4T+aDRc7qCvu6/OorEAd4P8Q=; b=XmpE9YRmmtBadd/zkeEp7MrJs3cNZo3XBIDpuETpQG5SEStF6bTVd6QrDgduaCd/nj MlYMJDFPhRNVlnJi1OEOBDcOysBnNyKnbV+MRgCyvCLotyUEJH5pBaw93RZQrLexf/Qk tgXMNTNklj7PoUGnOfdm00ErBxlCqghDE7uvJ/PUCwSqzKejHh1zKpxCYwA1pq39O1ww u6VPfYXIEDhlOQXBuEOvGFhwstY+v1gQFj1sMUwbE8Y1oEOoU+UGCH4hoBvjC32gl1CO 0GlGY3rwdQkuTlps8tyIIARcj6Tngog4WKbqk1tTAXvHiucnjm4rnCzsCno4F6y27df0 sJPQ== X-Gm-Message-State: AKwxytchYl4bCxCJb20fd/y2s6pHp0Jx+X2DJejAul12PrK4gwQKJuEQ +3MPGGabx7Fehkv7pmKT30+JmM63zcQ= X-Google-Smtp-Source: AH8x2276oxffLYH4eNCN7dDtRC2VFnngEKvxbEFrMERLaO5a7GbjOYozaCHPBiJGRmz8DZ54ynDPWw== X-Received: by 10.98.100.139 with SMTP id y133mr19906827pfb.68.1516992090460; Fri, 26 Jan 2018 10:41:30 -0800 (PST) Received: from vader.thefacebook.com ([2620:10d:c090:200::6:7f96]) by smtp.gmail.com with ESMTPSA id y29sm19627400pff.24.2018.01.26.10.41.29 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 26 Jan 2018 10:41:29 -0800 (PST) From: Omar Sandoval To: linux-btrfs@vger.kernel.org Cc: kernel-team@fb.com Subject: [PATCH 08/26] libbtrfsutil: add btrfs_util_[gs]et_read_only() Date: Fri, 26 Jan 2018 10:40:56 -0800 Message-Id: <5a7095592d94a9fdb4c5c99c411a492ecf35c3c0.1516991902.git.osandov@fb.com> X-Mailer: git-send-email 2.16.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Omar Sandoval 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 --- libbtrfsutil/btrfsutil.h | 33 ++++++++++++++ libbtrfsutil/python/btrfsutilpy.h | 2 + libbtrfsutil/python/module.c | 13 ++++++ libbtrfsutil/python/subvolume.c | 53 ++++++++++++++++++++++ libbtrfsutil/python/tests/test_subvolume.py | 17 +++++++ libbtrfsutil/subvolume.c | 69 +++++++++++++++++++++++++++++ 6 files changed, 187 insertions(+) diff --git a/libbtrfsutil/btrfsutil.h b/libbtrfsutil/btrfsutil.h index 41d5c1e7..d187d3a7 100644 --- a/libbtrfsutil/btrfsutil.h +++ b/libbtrfsutil/btrfsutil.h @@ -227,6 +227,39 @@ enum btrfs_util_error btrfs_util_subvolume_info(const char *path, uint64_t id, enum btrfs_util_error btrfs_util_f_subvolume_info(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_f_get_subvolume_read_only() - See + * btrfs_util_get_subvolume_read_only(). + */ +enum btrfs_util_error btrfs_util_f_get_subvolume_read_only(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_f_set_subvolume_read_only() - See + * btrfs_util_set_subvolume_read_only(). + */ +enum btrfs_util_error btrfs_util_f_set_subvolume_read_only(int fd, + bool read_only); + struct btrfs_util_qgroup_inherit; /** diff --git a/libbtrfsutil/python/btrfsutilpy.h b/libbtrfsutil/python/btrfsutilpy.h index e601cb8b..21253e51 100644 --- a/libbtrfsutil/python/btrfsutilpy.h +++ b/libbtrfsutil/python/btrfsutilpy.h @@ -64,6 +64,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 b1469fc9..3395fb14 100644 --- a/libbtrfsutil/python/module.c +++ b/libbtrfsutil/python/module.c @@ -160,6 +160,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 9c323995..9ae7729f 100644 --- a/libbtrfsutil/python/subvolume.c +++ b/libbtrfsutil/python/subvolume.c @@ -215,6 +215,59 @@ 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_f_get_subvolume_read_only(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_f_set_subvolume_read_only(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 ecb0d7ae..23871de9 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 3e94c050..394c7cbd 100644 --- a/libbtrfsutil/subvolume.c +++ b/libbtrfsutil/subvolume.c @@ -414,6 +414,75 @@ enum btrfs_util_error btrfs_util_f_subvolume_info(int fd, uint64_t id, return BTRFS_UTIL_OK; } +enum btrfs_util_error btrfs_util_f_get_subvolume_read_only(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; +} + +__attribute__((visibility("default"))) +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_f_get_subvolume_read_only(fd, ret); + SAVE_ERRNO_AND_CLOSE(fd); + return err; +} + +__attribute__((visibility("default"))) +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_f_set_subvolume_read_only(fd, read_only); + SAVE_ERRNO_AND_CLOSE(fd); + return err; +} + +__attribute__((visibility("default"))) +enum btrfs_util_error btrfs_util_f_set_subvolume_read_only(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)