diff --git a/utils/src/find_xattrs.c b/utils/src/find_xattrs.c new file mode 100644 index 00000000..ab9da445 --- /dev/null +++ b/utils/src/find_xattrs.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sparse.h" +#include "util.h" +#include "format.h" +#include "ioctl.h" +#include "cmd.h" + +static struct option long_ops[] = { + { "name", 1, NULL, 'n' }, + { "file", 1, NULL, 'f' }, + { NULL, 0, NULL, 0} +}; + +static int find_xattrs_cmd(int argc, char **argv) +{ + struct scoutfs_ioctl_find_xattrs fx; + char *path = NULL; + char *name = NULL; + u64 inos[32]; + int fd = -1; + int ret; + int c; + int i; + + memset(&fx, 0, sizeof(fx)); + + while ((c = getopt_long(argc, argv, "f:n:", long_ops, NULL)) != -1) { + switch (c) { + case 'f': + path = strdup(optarg); + if (!path) { + fprintf(stderr, "path mem alloc failed\n"); + ret = -ENOMEM; + goto out; + } + break; + case 'n': + name = strdup(optarg); + if (!name) { + fprintf(stderr, "name mem alloc failed\n"); + ret = -ENOMEM; + goto out; + } + break; + case '?': + default: + ret = -EINVAL; + goto out; + } + } + + if (path == NULL) { + fprintf(stderr, "must specify -f path to file\n"); + ret = -EINVAL; + goto out; + } + + fd = open(path, O_RDONLY); + if (fd < 0) { + ret = -errno; + fprintf(stderr, "failed to open '%s': %s (%d)\n", + path, strerror(errno), errno); + goto out; + } + + fx.next_ino = 0; + fx.name_ptr = (unsigned long)name; + fx.inodes_ptr = (unsigned long)inos; + fx.name_bytes = strlen(name); + fx.nr_inodes = array_size(inos); + + for (;;) { + + ret = ioctl(fd, SCOUTFS_IOC_FIND_XATTRS, &fx); + if (ret == 0) + break; + if (ret < 0) { + ret = -errno; + fprintf(stderr, "find_xattrs ioctl failed: " + "%s (%d)\n", strerror(errno), errno); + goto out; + } + + for (i = 0; i < ret; i++) + printf("%llu\n", inos[i]); + + fx.next_ino = inos[ret - 1] + 1; + if (fx.next_ino == 0) + break; + } + + ret = 0; +out: + if (fd >= 0) + close(fd); + free(path); + free(name); + + return ret; +}; + +static void __attribute__((constructor)) find_xattrs_ctor(void) +{ + cmd_register("find-xattrs", "-n name -f ", + "print inode numbers of inodes which may have given xattr", + find_xattrs_cmd); +} diff --git a/utils/src/format.h b/utils/src/format.h index 79317691..19990161 100644 --- a/utils/src/format.h +++ b/utils/src/format.h @@ -108,6 +108,11 @@ struct scoutfs_key { #define skii_major _sk_second #define skii_ino _sk_third +/* xattr index */ +#define skxi_hash _sk_first +#define skxi_ino _sk_second +#define skxi_id _sk_third + /* node free extent */ #define sknf_node_id _sk_first #define sknf_major _sk_second @@ -351,9 +356,10 @@ struct scoutfs_segment_block { * Keys are first sorted by major key zones. */ #define SCOUTFS_INODE_INDEX_ZONE 1 -#define SCOUTFS_NODE_ZONE 2 -#define SCOUTFS_FS_ZONE 3 -#define SCOUTFS_LOCK_ZONE 4 +#define SCOUTFS_XATTR_INDEX_ZONE 2 +#define SCOUTFS_NODE_ZONE 3 +#define SCOUTFS_FS_ZONE 4 +#define SCOUTFS_LOCK_ZONE 5 #define SCOUTFS_MAX_ZONE 8 /* power of 2 is efficient */ /* inode index zone */ @@ -361,6 +367,9 @@ struct scoutfs_segment_block { #define SCOUTFS_INODE_INDEX_DATA_SEQ_TYPE 2 #define SCOUTFS_INODE_INDEX_NR 3 /* don't forget to update */ +/* xattr index zone */ +#define SCOUTFS_XATTR_INDEX_NAME_TYPE 1 + /* node zone (also used in server alloc btree) */ #define SCOUTFS_FREE_EXTENT_BLKNO_TYPE 1 #define SCOUTFS_FREE_EXTENT_BLOCKS_TYPE 2 diff --git a/utils/src/ioctl.h b/utils/src/ioctl.h index e49116b4..b9966c68 100644 --- a/utils/src/ioctl.h +++ b/utils/src/ioctl.h @@ -271,4 +271,44 @@ struct scoutfs_ioctl_setattr_more { #define SCOUTFS_IOC_SETATTR_MORE _IOW(SCOUTFS_IOCTL_MAGIC, 10, \ struct scoutfs_ioctl_setattr_more) +struct scoutfs_ioctl_listxattr_raw { + __u64 id_pos; + __u64 buf_ptr; + __u32 buf_bytes; + __u32 hash_pos; +} __packed; + +#define SCOUTFS_IOC_LISTXATTR_RAW _IOW(SCOUTFS_IOCTL_MAGIC, 11, \ + struct scoutfs_ioctl_listxattr_raw) + +/* + * Return the inode numbers of inodes which might contain the given + * named xattr. The inode may not have a set xattr with that name, the + * caller must check the returned inodes to see if they match. + * + * @next_ino: The next inode number that could be returned. Initialized + * to 0 when first searching and set to one past the last inode number + * returned to continue searching. + * @name_ptr: The address of the name of the xattr to search for. It does + * not need to be null terminated. + * @inodes_ptr: The address of the array of uint64_t inode numbers in which + * to store inode numbers that may contain the xattr. EFAULT may be returned + * if this address is not naturally aligned. + * @name_bytes: The number of non-null bytes found in the name at name_ptr. + * @nr_inodes: The number of elements in the array found at inodes_ptr. + * + * This requires the CAP_SYS_ADMIN capability and will return -EPERM if + * it's not granted. + */ +struct scoutfs_ioctl_find_xattrs { + __u64 next_ino; + __u64 name_ptr; + __u64 inodes_ptr; + __u16 name_bytes; + __u16 nr_inodes; +} __packed; + +#define SCOUTFS_IOC_FIND_XATTRS _IOW(SCOUTFS_IOCTL_MAGIC, 12, \ + struct scoutfs_ioctl_find_xattrs) + #endif diff --git a/utils/src/key.c b/utils/src/key.c index 2afc855f..32be964c 100644 --- a/utils/src/key.c +++ b/utils/src/key.c @@ -21,6 +21,7 @@ char *scoutfs_zone_strings[SCOUTFS_MAX_ZONE] = { [SCOUTFS_INODE_INDEX_ZONE] = "ind", + [SCOUTFS_XATTR_INDEX_ZONE] = "xnd", [SCOUTFS_NODE_ZONE] = "nod", [SCOUTFS_FS_ZONE] = "fs", }; @@ -28,6 +29,7 @@ char *scoutfs_zone_strings[SCOUTFS_MAX_ZONE] = { char *scoutfs_type_strings[SCOUTFS_MAX_ZONE][SCOUTFS_MAX_TYPE] = { [SCOUTFS_INODE_INDEX_ZONE][SCOUTFS_INODE_INDEX_META_SEQ_TYPE] = "msq", [SCOUTFS_INODE_INDEX_ZONE][SCOUTFS_INODE_INDEX_DATA_SEQ_TYPE] = "dsq", + [SCOUTFS_XATTR_INDEX_ZONE][SCOUTFS_XATTR_INDEX_NAME_TYPE] = "nam", [SCOUTFS_NODE_ZONE][SCOUTFS_FREE_EXTENT_BLKNO_TYPE] = "fbn", [SCOUTFS_NODE_ZONE][SCOUTFS_FREE_EXTENT_BLOCKS_TYPE] = "fbs", [SCOUTFS_NODE_ZONE][SCOUTFS_ORPHAN_TYPE] = "orp", diff --git a/utils/src/listxattr_raw.c b/utils/src/listxattr_raw.c new file mode 100644 index 00000000..f7b69c0d --- /dev/null +++ b/utils/src/listxattr_raw.c @@ -0,0 +1,147 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sparse.h" +#include "util.h" +#include "format.h" +#include "ioctl.h" +#include "cmd.h" + +static struct option long_ops[] = { + { "file", 1, NULL, 'f' }, + { NULL, 0, NULL, 0} +}; + +static int listxattr_raw_cmd(int argc, char **argv) +{ + struct scoutfs_ioctl_listxattr_raw lxr; + char *path = NULL; + char *buf = NULL; + char *name; + int fd = -1; + int bytes; + int len; + int ret; + int c; + int i; + + while ((c = getopt_long(argc, argv, "f:", long_ops, NULL)) != -1) { + switch (c) { + case 'f': + path = strdup(optarg); + if (!path) { + fprintf(stderr, "path mem alloc failed\n"); + ret = -ENOMEM; + goto out; + } + break; + case '?': + default: + ret = -EINVAL; + goto out; + } + } + + if (path == NULL) { + fprintf(stderr, "must specify -f path to file\n"); + ret = -EINVAL; + goto out; + } + + memset(&lxr, 0, sizeof(lxr)); + lxr.id_pos = 0; + lxr.hash_pos = 0; + lxr.buf_bytes = 256 * 1024; + + buf = malloc(lxr.buf_bytes); + if (!buf) { + fprintf(stderr, "xattr name buf alloc failed\n"); + return -ENOMEM; + } + lxr.buf_ptr = (unsigned long)buf; + + fd = open(path, O_RDONLY); + if (fd < 0) { + ret = -errno; + fprintf(stderr, "failed to open '%s': %s (%d)\n", + path, strerror(errno), errno); + goto out; + } + + for (;;) { + + ret = ioctl(fd, SCOUTFS_IOC_LISTXATTR_RAW, &lxr); + if (ret == 0) + break; + if (ret < 0) { + ret = -errno; + fprintf(stderr, "listxattr_raw ioctl failed: " + "%s (%d)\n", strerror(errno), errno); + goto out; + } + + bytes = ret; + + if (bytes > lxr.buf_bytes) { + fprintf(stderr, "listxattr_raw overflowed\n"); + ret = -EFAULT; + goto out; + } + if (buf[bytes - 1] != '\0') { + fprintf(stderr, "listxattr_raw didn't term\n"); + ret = -EINVAL; + goto out; + } + + name = buf; + + do { + len = strlen(name); + if (len == 0) { + fprintf(stderr, "listxattr_raw empty name\n"); + ret = -EINVAL; + goto out; + } + + if (len > SCOUTFS_XATTR_MAX_NAME_LEN) { + fprintf(stderr, "listxattr_raw long name\n"); + ret = -EINVAL; + goto out; + } + + for (i = 0; i < len; i++) { + if (!isprint(name[i])) + name[i] = '?'; + } + + printf("%s\n", name); + name += len + 1; + bytes -= len + 1; + + } while (bytes > 0); + } + + ret = 0; +out: + if (fd >= 0) + close(fd); + free(buf); + + return ret; +}; + +static void __attribute__((constructor)) listxattr_raw_ctor(void) +{ + cmd_register("listxattr-raw", "-f ", + "print only the names of all xattrs on the file", + listxattr_raw_cmd); +} diff --git a/utils/src/print.c b/utils/src/print.c index 161c7f33..dd9f7308 100644 --- a/utils/src/print.c +++ b/utils/src/print.c @@ -197,6 +197,13 @@ static void print_inode_index(struct scoutfs_key *key, void *val, int val_len) le64_to_cpu(key->skii_major), le64_to_cpu(key->skii_ino)); } +static void print_xattr_index(struct scoutfs_key *key, void *val, int val_len) +{ + printf(" xattr index: hash 0x%016llx ino %llu id %llu\n", + le64_to_cpu(key->skxi_hash), le64_to_cpu(key->skxi_ino), + le64_to_cpu(key->skxi_id)); +} + typedef void (*print_func_t)(struct scoutfs_key *key, void *val, int val_len); static print_func_t find_printer(u8 zone, u8 type) @@ -206,6 +213,10 @@ static print_func_t find_printer(u8 zone, u8 type) type <= SCOUTFS_INODE_INDEX_DATA_SEQ_TYPE) return print_inode_index; + if (zone == SCOUTFS_XATTR_INDEX_ZONE && + type >= SCOUTFS_XATTR_INDEX_NAME_TYPE) + return print_xattr_index; + if (zone == SCOUTFS_NODE_ZONE) { if (type == SCOUTFS_FREE_EXTENT_BLKNO_TYPE || type == SCOUTFS_FREE_EXTENT_BLOCKS_TYPE)