#include <fcntl.h>
#include <sys/ioctl.h>
#include <uuid/uuid.h>
+#include <limits.h>
+#include <errno.h>
#include "ctree.h"
#include "send-utils.h"
off += sizeof(*sh);
item = (struct btrfs_root_item *)(args.buf + off);
- off += sh->len;
+ off += btrfs_search_header_len(sh);
- sk->min_objectid = sh->objectid;
- sk->min_type = sh->type;
- sk->min_offset = sh->offset;
+ sk->min_objectid = btrfs_search_header_objectid(sh);
+ sk->min_type = btrfs_search_header_type(sh);
+ sk->min_offset = btrfs_search_header_offset(sh);
- if (sh->objectid > root_id)
+ if (btrfs_search_header_objectid(sh) > root_id)
break;
- if (sh->objectid == root_id &&
- sh->type == BTRFS_ROOT_ITEM_KEY) {
- if (sh->len > buf_len) {
+ if (btrfs_search_header_objectid(sh) == root_id &&
+ btrfs_search_header_type(sh) == BTRFS_ROOT_ITEM_KEY) {
+ if (btrfs_search_header_len(sh) > buf_len) {
/* btrfs-progs is too old for kernel */
fprintf(stderr,
"ERROR: buf for read_root_item_raw() is too small, get newer btrfs tools!\n");
return -EOVERFLOW;
}
- memcpy(buf, item, sh->len);
- *read_len = sh->len;
+ memcpy(buf, item, btrfs_search_header_len(sh));
+ *read_len = btrfs_search_header_len(sh);
found = 1;
}
}
return 0;
}
+#ifdef BTRFS_COMPAT_SEND_NO_UUID_TREE
static struct rb_node *tree_insert(struct rb_root *root,
struct subvol_info *si,
enum subvol_search_type type)
}
return NULL;
}
+#endif
int btrfs_subvolid_resolve(int fd, char *path, size_t path_len, u64 subvol_id)
{
search_arg.key.max_transid = (u64)-1;
search_arg.key.nr_items = 1;
ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &search_arg);
- if (ret) {
+ if (ret < 0) {
fprintf(stderr,
"ioctl(BTRFS_IOC_TREE_SEARCH, subvol_id %llu) ret=%d, error: %s\n",
(unsigned long long)subvol_id, ret, strerror(errno));
}
search_header = (struct btrfs_ioctl_search_header *)search_arg.buf;
backref_item = (struct btrfs_root_ref *)(search_header + 1);
- if (search_header->offset != BTRFS_FS_TREE_OBJECTID) {
+ if (btrfs_search_header_offset(search_header)
+ != BTRFS_FS_TREE_OBJECTID) {
int sub_ret;
sub_ret = btrfs_subvolid_resolve_sub(fd, path, path_len,
- search_header->offset);
+ btrfs_search_header_offset(search_header));
if (sub_ret)
return sub_ret;
if (*path_len < 1)
int len;
memset(&ino_lookup_arg, 0, sizeof(ino_lookup_arg));
- ino_lookup_arg.treeid = search_header->offset;
+ ino_lookup_arg.treeid =
+ btrfs_search_header_offset(search_header);
ino_lookup_arg.objectid =
btrfs_stack_root_ref_dirid(backref_item);
ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_lookup_arg);
- if (ret) {
+ if (ret < 0) {
fprintf(stderr,
"ioctl(BTRFS_IOC_INO_LOOKUP) ret=%d, error: %s\n",
ret, strerror(errno));
return 0;
}
+#ifdef BTRFS_COMPAT_SEND_NO_UUID_TREE
static int count_bytes(void *buf, int len, char b)
{
int cnt = 0;
}
/*
- * this function will be only called if kernel dosen't support uuid tree.
+ * this function will be only called if kernel doesn't support uuid tree.
*/
static struct subvol_info *subvol_uuid_search_old(struct subvol_uuid_search *s,
u64 root_id, const u8 *uuid, u64 transid,
return NULL;
return tree_search(root, root_id, uuid, transid, path, type);
}
+#else
+void subvol_uuid_search_add(struct subvol_uuid_search *s,
+ struct subvol_info *si)
+{
+ if (si) {
+ free(si->path);
+ free(si);
+ }
+}
+#endif
struct subvol_info *subvol_uuid_search(struct subvol_uuid_search *s,
u64 root_id, const u8 *uuid, u64 transid,
const char *path,
enum subvol_search_type type)
{
+ struct subvol_info *si;
+
+ si = subvol_uuid_search2(s, root_id, uuid, transid, path, type);
+ if (IS_ERR(si))
+ return NULL;
+ return si;
+}
+
+struct subvol_info *subvol_uuid_search2(struct subvol_uuid_search *s,
+ u64 root_id, const u8 *uuid, u64 transid,
+ const char *path,
+ enum subvol_search_type type)
+{
int ret = 0;
struct btrfs_root_item root_item;
struct subvol_info *info = NULL;
+#ifdef BTRFS_COMPAT_SEND_NO_UUID_TREE
if (!s->uuid_tree_existed)
return subvol_uuid_search_old(s, root_id, uuid, transid,
path, type);
+#endif
switch (type) {
case subvol_search_by_received_uuid:
ret = btrfs_lookup_uuid_received_subvol_item(s->mnt_fd, uuid,
goto out;
info = calloc(1, sizeof(*info));
+ if (!info) {
+ ret = -ENOMEM;
+ goto out;
+ }
info->root_id = root_id;
memcpy(info->uuid, root_item.uuid, BTRFS_UUID_SIZE);
memcpy(info->received_uuid, root_item.received_uuid, BTRFS_UUID_SIZE);
info->rtransid = btrfs_root_rtransid(&root_item);
if (type == subvol_search_by_path) {
info->path = strdup(path);
+ if (!info->path) {
+ ret = -ENOMEM;
+ goto out;
+ }
} else {
- info->path = malloc(BTRFS_PATH_NAME_MAX);
+ info->path = malloc(PATH_MAX);
+ if (!info->path) {
+ ret = -ENOMEM;
+ goto out;
+ }
ret = btrfs_subvolid_resolve(s->mnt_fd, info->path,
- BTRFS_PATH_NAME_MAX, root_id);
+ PATH_MAX, root_id);
}
out:
- if (ret && info) {
- free(info->path);
- free(info);
- info = NULL;
+ if (ret) {
+ if (info) {
+ free(info->path);
+ free(info);
+ }
+ return ERR_PTR(ret);
}
return info;
}
+#ifdef BTRFS_COMPAT_SEND_NO_UUID_TREE
static int is_uuid_tree_supported(int fd)
{
int ret;
struct btrfs_ioctl_search_key *sk = &args.key;
struct btrfs_ioctl_search_header *sh;
struct btrfs_root_item *root_item_ptr;
- struct btrfs_root_item root_item;
+ struct btrfs_root_item root_item = {};
struct subvol_info *si = NULL;
int root_item_valid = 0;
unsigned long off = 0;
int i;
- int e;
char *path;
s->mnt_fd = mnt_fd;
ret = is_uuid_tree_supported(mnt_fd);
if (ret < 0) {
fprintf(stderr,
- "ERROR: check if we support uuid tree fails- %s\n",
+ "ERROR: check if we support uuid tree fails - %s\n",
strerror(errno));
return ret;
} else if (ret) {
while (1) {
ret = ioctl(mnt_fd, BTRFS_IOC_TREE_SEARCH, &args);
- e = errno;
if (ret < 0) {
- fprintf(stderr, "ERROR: can't perform the search- %s\n",
- strerror(e));
+ fprintf(stderr, "ERROR: can't perform the search - %s\n",
+ strerror(errno));
return ret;
}
if (sk->nr_items == 0)
off);
off += sizeof(*sh);
- if ((sh->objectid != 5 &&
- sh->objectid < BTRFS_FIRST_FREE_OBJECTID) ||
- sh->objectid > BTRFS_LAST_FREE_OBJECTID)
+ if ((btrfs_search_header_objectid(sh) != 5 &&
+ btrfs_search_header_objectid(sh)
+ < BTRFS_FIRST_FREE_OBJECTID) ||
+ btrfs_search_header_objectid(sh)
+ > BTRFS_LAST_FREE_OBJECTID) {
goto skip;
+ }
- if (sh->type == BTRFS_ROOT_ITEM_KEY) {
+ if (btrfs_search_header_type(sh)
+ == BTRFS_ROOT_ITEM_KEY) {
/* older kernels don't have uuids+times */
- if (sh->len < sizeof(root_item)) {
+ if (btrfs_search_header_len(sh)
+ < sizeof(root_item)) {
root_item_valid = 0;
goto skip;
}
memcpy(&root_item, root_item_ptr,
sizeof(root_item));
root_item_valid = 1;
- } else if (sh->type == BTRFS_ROOT_BACKREF_KEY ||
+ } else if (btrfs_search_header_type(sh)
+ == BTRFS_ROOT_BACKREF_KEY ||
root_item_valid) {
if (!root_item_valid)
goto skip;
path = btrfs_list_path_for_root(mnt_fd,
- sh->objectid);
+ btrfs_search_header_objectid(sh));
if (!path)
path = strdup("");
if (IS_ERR(path)) {
fprintf(stderr, "ERROR: unable to "
"resolve path "
"for root %llu\n",
- sh->objectid);
+ btrfs_search_header_objectid(sh));
goto out;
}
si = calloc(1, sizeof(*si));
- si->root_id = sh->objectid;
+ si->root_id = btrfs_search_header_objectid(sh);
memcpy(si->uuid, root_item.uuid,
BTRFS_UUID_SIZE);
memcpy(si->parent_uuid, root_item.parent_uuid,
}
skip:
- off += sh->len;
+ off += btrfs_search_header_len(sh);
/*
* record the mins in sk so we can make sure the
* next search doesn't repeat this root
*/
- sk->min_objectid = sh->objectid;
- sk->min_offset = sh->offset;
- sk->min_type = sh->type;
+ sk->min_objectid = btrfs_search_header_objectid(sh);
+ sk->min_offset = btrfs_search_header_offset(sh);
+ sk->min_type = btrfs_search_header_type(sh);
}
sk->nr_items = 4096;
if (sk->min_offset < (u64)-1)
s->received_subvols = RB_ROOT;
s->path_subvols = RB_ROOT;
}
+#else
+int subvol_uuid_search_init(int mnt_fd, struct subvol_uuid_search *s)
+{
+ s->mnt_fd = mnt_fd;
+
+ return 0;
+}
-char *path_cat(const char *p1, const char *p2)
+void subvol_uuid_search_finit(struct subvol_uuid_search *s)
+{
+}
+#endif
+
+int path_cat_out(char *out, const char *p1, const char *p2)
{
int p1_len = strlen(p1);
int p2_len = strlen(p2);
- char *new = malloc(p1_len + p2_len + 2);
+
+ if (p1_len + p2_len + 2 >= PATH_MAX)
+ return -ENAMETOOLONG;
if (p1_len && p1[p1_len - 1] == '/')
p1_len--;
if (p2_len && p2[p2_len - 1] == '/')
p2_len--;
- sprintf(new, "%.*s/%.*s", p1_len, p1, p2_len, p2);
+ sprintf(out, "%.*s/%.*s", p1_len, p1, p2_len, p2);
+
+ return 0;
+}
+
+__attribute__((deprecated))
+char *path_cat(const char *p1, const char *p2)
+{
+ int p1_len = strlen(p1);
+ int p2_len = strlen(p2);
+ char *new = malloc(p1_len + p2_len + 2);
+
+ path_cat_out(new, p1, p2);
+
return new;
}
-char *path_cat3(const char *p1, const char *p2, const char *p3)
+int path_cat3_out(char *out, const char *p1, const char *p2, const char *p3)
{
int p1_len = strlen(p1);
int p2_len = strlen(p2);
int p3_len = strlen(p3);
- char *new = malloc(p1_len + p2_len + p3_len + 3);
+
+ if (p1_len + p2_len + p3_len + 3 >= PATH_MAX)
+ return -ENAMETOOLONG;
if (p1_len && p1[p1_len - 1] == '/')
p1_len--;
p2_len--;
if (p3_len && p3[p3_len - 1] == '/')
p3_len--;
- sprintf(new, "%.*s/%.*s/%.*s", p1_len, p1, p2_len, p2, p3_len, p3);
+ sprintf(out, "%.*s/%.*s/%.*s", p1_len, p1, p2_len, p2, p3_len, p3);
+
+ return 0;
+}
+
+__attribute__((deprecated))
+char *path_cat3(const char *p1, const char *p2, const char *p3)
+{
+ int p1_len = strlen(p1);
+ int p2_len = strlen(p2);
+ int p3_len = strlen(p3);
+ char *new = malloc(p1_len + p2_len + p3_len + 3);
+
+ path_cat3_out(new, p1, p2, p3);
+
return new;
}