diff options
author | Omar Sandoval <osandov@fb.com> | 2018-02-14 22:16:33 -0800 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2018-03-06 11:28:36 +0100 |
commit | 8b87811f945bec2a0681334030ed51af1e4828f6 (patch) | |
tree | 217417d7eeddb7eb5704908ae8991c4b5158187d /libbtrfsutil/python | |
parent | f676a8ad118ecba7fbf4edc77b91f788c6fa7e7c (diff) |
libbtrfsutil: add btrfs_util_subvolume_path()
We can just walk up root backrefs with BTRFS_IOC_TREE_SEARCH and inode
paths with BTRFS_IOC_INO_LOOKUP.
Signed-off-by: Omar Sandoval <osandov@fb.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'libbtrfsutil/python')
-rw-r--r-- | libbtrfsutil/python/btrfsutilpy.h | 1 | ||||
-rw-r--r-- | libbtrfsutil/python/module.c | 8 | ||||
-rw-r--r-- | libbtrfsutil/python/subvolume.c | 30 | ||||
-rw-r--r-- | libbtrfsutil/python/tests/test_subvolume.py | 31 |
4 files changed, 70 insertions, 0 deletions
diff --git a/libbtrfsutil/python/btrfsutilpy.h b/libbtrfsutil/python/btrfsutilpy.h index 19ba71f3..1fd475b4 100644 --- a/libbtrfsutil/python/btrfsutilpy.h +++ b/libbtrfsutil/python/btrfsutilpy.h @@ -63,6 +63,7 @@ PyObject *start_sync(PyObject *self, PyObject *args, PyObject *kwds); PyObject *wait_sync(PyObject *self, PyObject *args, PyObject *kwds); 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 *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 deb26875..455e909a 100644 --- a/libbtrfsutil/python/module.c +++ b/libbtrfsutil/python/module.c @@ -165,6 +165,14 @@ static PyMethodDef btrfsutil_methods[] = { "Get the ID of the subvolume containing a file.\n\n" "Arguments:\n" "path -- string, bytes, path-like object, or open file descriptor"}, + {"subvolume_path", (PyCFunction)subvolume_path, + METH_VARARGS | METH_KEYWORDS, + "subvolume_path(path, id=0) -> int\n\n" + "Get the path of a subvolume relative to the filesystem root.\n\n" + "Arguments:\n" + "path -- string, bytes, path-like object, or open file descriptor\n" + "id -- if not zero, instead of returning the subvolume path of the\n" + "given path, return the path of the subvolume with this ID"}, {"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 6f2080ee..6382d290 100644 --- a/libbtrfsutil/python/subvolume.c +++ b/libbtrfsutil/python/subvolume.c @@ -72,6 +72,36 @@ PyObject *subvolume_id(PyObject *self, PyObject *args, PyObject *kwds) return PyLong_FromUnsignedLongLong(id); } +PyObject *subvolume_path(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *keywords[] = {"path", "id", NULL}; + struct path_arg path = {.allow_fd = true}; + enum btrfs_util_error err; + uint64_t id = 0; + char *subvol_path; + PyObject *ret; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|K:subvolume_path", + keywords, &path_converter, &path, &id)) + return NULL; + + if (path.path) + err = btrfs_util_subvolume_path(path.path, id, &subvol_path); + else + err = btrfs_util_subvolume_path_fd(path.fd, id, &subvol_path); + if (err) { + SetFromBtrfsUtilErrorWithPath(err, &path); + path_cleanup(&path); + return NULL; + } + + path_cleanup(&path); + + ret = PyUnicode_DecodeFSDefault(subvol_path); + free(subvol_path); + return ret; +} + 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 f6c5958d..57ba27bf 100644 --- a/libbtrfsutil/python/tests/test_subvolume.py +++ b/libbtrfsutil/python/tests/test_subvolume.py @@ -56,6 +56,37 @@ class TestSubvolume(BtrfsTestCase): with self.subTest(type=type(arg)): self.assertEqual(btrfsutil.subvolume_id(arg), 5) + def test_subvolume_path(self): + btrfsutil.create_subvolume(os.path.join(self.mountpoint, 'subvol1')) + os.mkdir(os.path.join(self.mountpoint, 'dir1')) + os.mkdir(os.path.join(self.mountpoint, 'dir1/dir2')) + btrfsutil.create_subvolume(os.path.join(self.mountpoint, 'dir1/dir2/subvol2')) + btrfsutil.create_subvolume(os.path.join(self.mountpoint, 'dir1/dir2/subvol2/subvol3')) + os.mkdir(os.path.join(self.mountpoint, 'subvol1/dir3')) + btrfsutil.create_subvolume(os.path.join(self.mountpoint, 'subvol1/dir3/subvol4')) + + for arg in self.path_or_fd(self.mountpoint): + with self.subTest(type=type(arg)): + self.assertEqual(btrfsutil.subvolume_path(arg), '') + self.assertEqual(btrfsutil.subvolume_path(arg, 5), '') + self.assertEqual(btrfsutil.subvolume_path(arg, 256), 'subvol1') + self.assertEqual(btrfsutil.subvolume_path(arg, 257), 'dir1/dir2/subvol2') + self.assertEqual(btrfsutil.subvolume_path(arg, 258), 'dir1/dir2/subvol2/subvol3') + self.assertEqual(btrfsutil.subvolume_path(arg, 259), 'subvol1/dir3/subvol4') + + pwd = os.getcwd() + try: + os.chdir(self.mountpoint) + path = '' + for i in range(26): + name = chr(ord('a') + i) * 255 + path = os.path.join(path, name) + btrfsutil.create_subvolume(name) + os.chdir(name) + self.assertEqual(btrfsutil.subvolume_path('.'), path) + finally: + os.chdir(pwd) + def test_create_subvolume(self): subvol = os.path.join(self.mountpoint, 'subvol') |