libbtrfsutil: add get and set filesystem label

Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
David Sterba 2021-04-30 02:19:04 +02:00
parent 9f48d1b72f
commit 3d5c0c203c
9 changed files with 175 additions and 1 deletions

View File

@ -50,3 +50,11 @@ LIBBTRFSUTIL_1.2 {
global:
btrfs_util_delete_subvolume_by_id_fd;
} LIBBTRFSUTIL_1.1;
LIBBTRFSUTIL_1.3 {
global:
btrfs_util_filesystem_get_label;
btrfs_util_filesystem_get_label_fd;
btrfs_util_filesystem_set_label;
btrfs_util_filesystem_set_label_fd;
} LIBBTRFSUTIL_1.2;

View File

@ -67,6 +67,8 @@ enum btrfs_util_error {
BTRFS_UTIL_ERROR_GET_SUBVOL_ROOTREF_FAILED,
BTRFS_UTIL_ERROR_INO_LOOKUP_USER_FAILED,
BTRFS_UTIL_ERROR_FS_INFO_FAILED,
BTRFS_UTIL_ERROR_GET_LABEL_FAILED,
BTRFS_UTIL_ERROR_SET_LABEL_FAILED,
};
/**
@ -122,6 +124,39 @@ enum btrfs_util_error btrfs_util_wait_sync(const char *path, uint64_t transid);
*/
enum btrfs_util_error btrfs_util_wait_sync_fd(int fd, uint64_t transid);
#define BTRFS_UTIL_LABEL_SIZE 256
/**
* btrfs_util_filesystem_set_label() - Set label of the filesystem under path
* @path: Path on a Btrfs filesystem.
* @label: New label as string, maximum length must be less than %BTRFS_LABEL_SIZE.
*
* Return: %BTRFS_UTIL_OK on success, non-zero error code on failure.
*/
enum btrfs_util_error btrfs_util_filesystem_set_label(const char *path,
const char *label);
/**
* btrfs_util_filesystem_get_label_fd() - See btrfs_util_filesystem_get_label().
*/
enum btrfs_util_error btrfs_util_filesystem_set_label_fd(int fd,
const char *label);
/**
* btrfs_util_filesystem_get_label - Get labelf of the filesystem under path
* @path: Path on a Btrfs filesystem.
* @label: Buffer where to store the label, must be at least %BTRFS_LABEL_SIZE.
*
* Return: %BTRFS_UTIL_OK on success, non-zero error code on failure.
*/
enum btrfs_util_error btrfs_util_filesystem_get_label(const char *path,
char *label);
/**
* btrfs_util_filesystem_get_label_fd() - See btrfs_util_filesystem_get_label().
*/
enum btrfs_util_error btrfs_util_filesystem_get_label_fd(int fd,
char *label);
/**
* btrfs_util_is_subvolume() - Return whether a given path is a Btrfs subvolume.
* @path: Path to check.

View File

@ -53,6 +53,10 @@ static const char * const error_messages[] = {
"Could not resolve subvolume path with BTRFS_IOC_INO_LOOKUP_USER",
[BTRFS_UTIL_ERROR_FS_INFO_FAILED] =
"Could not get filesystem information",
[BTRFS_UTIL_ERROR_GET_LABEL_FAILED] =
"Could not get filesystem label",
[BTRFS_UTIL_ERROR_SET_LABEL_FAILED] =
"Could not set filesystem label",
};
PUBLIC const char *btrfs_util_strerror(enum btrfs_util_error err)

View File

@ -100,3 +100,66 @@ PUBLIC enum btrfs_util_error btrfs_util_wait_sync_fd(int fd, uint64_t transid)
return BTRFS_UTIL_OK;
}
PUBLIC enum btrfs_util_error btrfs_util_filesystem_set_label_fd(int fd,
const char *label)
{
int ret;
char buf[BTRFS_UTIL_LABEL_SIZE];
if (strlen(label) >= BTRFS_UTIL_LABEL_SIZE) {
errno = EINVAL;
return BTRFS_UTIL_ERROR_INVALID_ARGUMENT;
}
memset(buf, 0, sizeof(buf));
strncpy(buf, label, BTRFS_UTIL_LABEL_SIZE - 1);
ret = ioctl(fd, BTRFS_IOC_SET_FSLABEL, buf);
if (ret == -1)
return BTRFS_UTIL_ERROR_GET_LABEL_FAILED;
return BTRFS_UTIL_OK;
}
PUBLIC enum btrfs_util_error btrfs_util_filesystem_set_label(const char *path,
const char *label)
{
enum btrfs_util_error err;
int fd;
fd = open(path, O_RDONLY);
if (fd == -1)
return BTRFS_UTIL_ERROR_OPEN_FAILED;
err = btrfs_util_filesystem_set_label_fd(fd, label);
SAVE_ERRNO_AND_CLOSE(fd);
return err;
}
PUBLIC enum btrfs_util_error btrfs_util_filesystem_get_label_fd(int fd,
char *label)
{
int ret;
/* Kernel does not return more than BTRFS_LABEL_SIZE/BTRFS_UTIL_LABEL_SIZE */
ret = ioctl(fd, BTRFS_IOC_GET_FSLABEL, label);
if (ret == -1)
return BTRFS_UTIL_ERROR_GET_LABEL_FAILED;
return BTRFS_UTIL_OK;
}
PUBLIC enum btrfs_util_error btrfs_util_filesystem_get_label(const char *path,
char *label)
{
enum btrfs_util_error err;
int fd;
fd = open(path, O_RDONLY);
if (fd == -1)
return BTRFS_UTIL_ERROR_OPEN_FAILED;
err = btrfs_util_filesystem_get_label_fd(fd, label);
SAVE_ERRNO_AND_CLOSE(fd);
return err;
}

View File

@ -66,6 +66,8 @@ void SetFromBtrfsUtilErrorWithPaths(enum btrfs_util_error err,
PyObject *filesystem_sync(PyObject *self, PyObject *args, PyObject *kwds);
PyObject *start_sync(PyObject *self, PyObject *args, PyObject *kwds);
PyObject *wait_sync(PyObject *self, PyObject *args, PyObject *kwds);
PyObject *filesystem_get_label(PyObject *self, PyObject *args, PyObject *kwds);
PyObject *fielsystem_set_label(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);

View File

@ -92,3 +92,53 @@ PyObject *wait_sync(PyObject *self, PyObject *args, PyObject *kwds)
path_cleanup(&path);
Py_RETURN_NONE;
}
PyObject *filesystem_get_label(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *keywords[] = {"path", NULL};
struct path_arg path = {.allow_fd = true};
enum btrfs_util_error err;
char label[BTRFS_UTIL_LABEL_SIZE];
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:filesystem_get_label",
keywords, &path_converter, &path))
return NULL;
if (path.path)
err = btrfs_util_filesystem_get_label(path.path, label);
else
err = btrfs_util_filesystem_get_label_fd(path.fd, label);
if (err) {
SetFromBtrfsUtilErrorWithPath(err, &path);
path_cleanup(&path);
return NULL;
}
path_cleanup(&path);
return PyUnicode_DecodeFSDefault(label);
}
PyObject *filesystem_set_label(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *keywords[] = {"path", "label", NULL};
struct path_arg path = {.allow_fd = true};
enum btrfs_util_error err;
char *label;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&s:filesystem_set_label",
keywords, &path_converter, &path, &label))
return NULL;
if (path.path)
err = btrfs_util_filesystem_set_label(path.path, label);
else
err = btrfs_util_filesystem_set_label_fd(path.fd, label);
if (err) {
SetFromBtrfsUtilErrorWithPath(err, &path);
path_cleanup(&path);
return NULL;
}
path_cleanup(&path);
Py_RETURN_NONE;
}

View File

@ -176,6 +176,12 @@ static PyMethodDef btrfsutil_methods[] = {
"path -- string, bytes, path-like object, or open file descriptor\n"
"transid -- int transaction ID to wait for, or zero for the current\n"
"transaction"},
{"filesystem_get_label", (PyCFunction)filesystem_get_label,
METH_VARARGS | METH_KEYWORDS,
"filesystem_get_label(path) -> str\n\n"
"Get filesystem label.\n\n"
"Arguments:\n"
"path -- string, bytes, path-like object, or open file descriptor"},
{"is_subvolume", (PyCFunction)is_subvolume,
METH_VARARGS | METH_KEYWORDS,
"is_subvolume(path) -> bool\n\n"

View File

@ -76,7 +76,7 @@ class BtrfsTestCase(unittest.TestCase):
else:
mkfs = 'mkfs.btrfs'
try:
subprocess.check_call([mkfs, '-q', image])
subprocess.check_call([mkfs, '-q', '-L', 'BTRFS-PROGS-PYTEST', image])
subprocess.check_call(['mount', '-o', 'loop', '--', image, mountpoint])
except Exception as e:
os.rmdir(mountpoint)

View File

@ -71,3 +71,9 @@ class TestSubvolume(BtrfsTestCase):
new_generation = self.super_generation()
self.assertGreater(new_generation, old_generation)
old_generation = new_generation
def test_filesystem_get_label(self):
for arg in self.path_or_fd(self.mountpoint):
with self.subTest(type=type(arg)):
label = btrfsutil.filesystem_get_label(arg)
self.assertEqual(label, 'BTRFS-PROGS-PYTEST')