| /* |
| * 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 <sys/stat.h> |
| #include <sys/ioctl.h> |
| #include <sys/types.h> |
| #include <sys/xattr.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| |
| #include <btrfsutil.h> |
| |
| #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: %m", object); |
| 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: %m", |
| value ? "set" : "get", object); |
| 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: %m", object); |
| 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} |
| }; |