/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include #include #include #include #include #include #include #include "ctree.h" #include "commands.h" #include "utils.h" #include "props.h" #define XATTR_BTRFS_PREFIX "btrfs." #define XATTR_BTRFS_PREFIX_LEN (sizeof(XATTR_BTRFS_PREFIX) - 1) /* * Defined as synonyms in attr/xattr.h */ #ifndef ENOATTR #define ENOATTR ENODATA #endif static int prop_read_only(enum prop_object_type type, const char *object, const char *name, const char *value) { enum btrfs_util_error err; bool read_only; if (value) { if (!strcmp(value, "true")) { read_only = true; } else if (!strcmp(value, "false")) { read_only = false; } else { error("invalid value for property: %s", value); return -EINVAL; } err = btrfs_util_set_subvolume_read_only(object, read_only); if (err) { error_btrfs_util(err); return -errno; } } else { err = btrfs_util_get_subvolume_read_only(object, &read_only); if (err) { error_btrfs_util(err); return -errno; } printf("ro=%s\n", read_only ? "true" : "false"); } return 0; } static int prop_label(enum prop_object_type type, const char *object, const char *name, const char *value) { int ret; if (value) { ret = set_label((char *) object, (char *) value); } else { char label[BTRFS_LABEL_SIZE]; ret = get_label((char *) object, label); if (!ret) fprintf(stdout, "label=%s\n", label); } return ret; } static int prop_compression(enum prop_object_type type, const char *object, const char *name, const char *value) { int ret; ssize_t sret; int fd = -1; DIR *dirstream = NULL; char *buf = NULL; char *xattr_name = NULL; int open_flags = value ? O_RDWR : O_RDONLY; fd = open_file_or_dir3(object, &dirstream, open_flags); if (fd == -1) { ret = -errno; error("failed to open %s: %s", object, strerror(-ret)); goto out; } xattr_name = malloc(XATTR_BTRFS_PREFIX_LEN + strlen(name) + 1); if (!xattr_name) { ret = -ENOMEM; goto out; } memcpy(xattr_name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN); memcpy(xattr_name + XATTR_BTRFS_PREFIX_LEN, name, strlen(name)); xattr_name[XATTR_BTRFS_PREFIX_LEN + strlen(name)] = '\0'; if (value) { if (strcmp(value, "no") == 0 || strcmp(value, "none") == 0) value = ""; sret = fsetxattr(fd, xattr_name, value, strlen(value), 0); } else { sret = fgetxattr(fd, xattr_name, NULL, 0); } if (sret < 0) { ret = -errno; if (ret != -ENOATTR) error("failed to %s compression for %s: %s", value ? "set" : "get", object, strerror(-ret)); else ret = 0; goto out; } if (!value) { size_t len = sret; buf = malloc(len); if (!buf) { ret = -ENOMEM; goto out; } sret = fgetxattr(fd, xattr_name, buf, len); if (sret < 0) { ret = -errno; error("failed to get compression for %s: %s", object, strerror(-ret)); goto out; } fprintf(stdout, "compression=%.*s\n", (int)len, buf); } ret = 0; out: free(xattr_name); free(buf); if (fd >= 0) close_file_or_dir(fd, dirstream); return ret; } const struct prop_handler prop_handlers[] = { {"ro", "Set/get read-only flag of subvolume.", 0, prop_object_subvol, prop_read_only}, {"label", "Set/get label of device.", 0, prop_object_dev | prop_object_root, prop_label}, {"compression", "Set/get compression for a file or directory", 0, prop_object_inode, prop_compression}, {NULL, NULL, 0, 0, NULL} };