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 <quwenruo@cn.fujitsu.com>
[constify string in __is_subvol]
Signed-off-by: David Sterba <dsterba@suse.cz>
This commit is contained in:
Qu Wenruo 2015-02-27 16:26:36 +08:00 committed by David Sterba
parent a3b048b306
commit cc6baf5e39
1 changed files with 44 additions and 4 deletions

48
utils.c
View File

@ -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);
}