From cc6baf5e39fbfba24bff9aa1cdf9d0f83b4eb648 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 27 Feb 2015 16:26:36 +0800 Subject: btrfs-progs: Allow parse_qgroupid() to resolve subvolume path into qgroupid Now parse_qgroupid() can resolve subvolume path into qgroupid. This is quite handy for handling level 0 qgroupid, and user don't need to resolve rootid by hand now. Signed-off-by: Qu Wenruo [constify string in __is_subvol] Signed-off-by: David Sterba --- utils.c | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) (limited to 'utils.c') diff --git a/utils.c b/utils.c index ca8efca2..7b977ee1 100644 --- a/utils.c +++ b/utils.c @@ -1707,6 +1707,25 @@ scan_again: return 0; } +/* + * Unsafe subvolume check. + * + * This only checks ino == BTRFS_FIRST_FREE_OBJECTID, even it is not in a + * btrfs mount point. + * Must use together with other reliable method like btrfs ioctl. + */ +static int __is_subvol(const char *path) +{ + struct stat st; + int ret; + + ret = lstat(path, &st); + if (ret < 0) + return ret; + + return st.st_ino == BTRFS_FIRST_FREE_OBJECTID; +} + /* * A not-so-good version fls64. No fascinating optimization since * no one except parse_size use it @@ -1802,24 +1821,45 @@ u64 parse_qgroupid(const char *p) char *ptr_parse_end = NULL; u64 level; u64 id; + int fd; + int ret = 0; + + if (p[0] == '/') + goto path; + /* Numeric format like '0/257' is the primary case */ if (!s) { id = strtoull(p, &ptr_parse_end, 10); if (ptr_parse_end != ptr_src_end) - goto err; + goto path; return id; } level = strtoull(p, &ptr_parse_end, 10); if (ptr_parse_end != s) - goto err; + goto path; id = strtoull(s + 1, &ptr_parse_end, 10); if (ptr_parse_end != ptr_src_end) - goto err; + goto path; return (level << BTRFS_QGROUP_LEVEL_SHIFT) | id; + +path: + /* Path format like subv at 'my_subvol' is the fallback case */ + ret = __is_subvol(p); + if (ret < 0 || !ret) + goto err; + fd = open(p, O_RDONLY); + if (fd < 0) + goto err; + ret = lookup_ino_rootid(fd, &id); + close(fd); + if (ret < 0) + goto err; + return id; + err: - fprintf(stderr, "ERROR: invalid qgroupid %s\n", p); + fprintf(stderr, "ERROR: invalid qgroupid or subvolume path: %s\n", p); exit(-1); } -- cgit v1.2.3