#include <lzo/lzoconf.h>
#include <lzo/lzo1x.h>
#include <zlib.h>
+#if BTRFSRESTORE_ZSTD
+#include <zstd.h>
+#endif
#include <regex.h>
#include <getopt.h>
#include <sys/types.h>
#include "volumes.h"
#include "utils.h"
#include "commands.h"
+#include "help.h"
static char fs_name[PATH_MAX];
static char path_name[PATH_MAX];
inbuf += LZO_LEN;
tot_in += LZO_LEN;
- new_len = lzo1x_worst_compress(root->sectorsize);
+ new_len = lzo1x_worst_compress(root->fs_info->sectorsize);
ret = lzo1x_decompress_safe((const unsigned char *)inbuf, in_len,
(unsigned char *)outbuf,
(void *)&new_len, NULL);
* If the 4 byte header does not fit to the rest of the page we
* have to move to the next one, unless we read some garbage
*/
- mod_page = tot_in % root->sectorsize;
- rem_page = root->sectorsize - mod_page;
+ mod_page = tot_in % root->fs_info->sectorsize;
+ rem_page = root->fs_info->sectorsize - mod_page;
if (rem_page < LZO_LEN) {
inbuf += rem_page;
tot_in += rem_page;
return 0;
}
+static int decompress_zstd(const char *inbuf, char *outbuf, u64 compress_len,
+ u64 decompress_len)
+{
+#if !BTRFSRESTORE_ZSTD
+ error("btrfs not compiled with zstd support");
+ return -1;
+#else
+ ZSTD_DStream *strm;
+ size_t zret;
+ int ret = 0;
+ ZSTD_inBuffer in = {inbuf, compress_len, 0};
+ ZSTD_outBuffer out = {outbuf, decompress_len, 0};
+
+ strm = ZSTD_createDStream();
+ if (!strm) {
+ error("zstd create failed");
+ return -1;
+ }
+
+ zret = ZSTD_initDStream(strm);
+ if (ZSTD_isError(zret)) {
+ error("zstd init failed: %s", ZSTD_getErrorName(zret));
+ ret = -1;
+ goto out;
+ }
+
+ zret = ZSTD_decompressStream(strm, &out, &in);
+ if (ZSTD_isError(zret)) {
+ error("zstd decompress failed %s\n", ZSTD_getErrorName(zret));
+ ret = -1;
+ goto out;
+ }
+ if (zret != 0) {
+ error("zstd frame incomplete");
+ ret = -1;
+ goto out;
+ }
+
+out:
+ ZSTD_freeDStream(strm);
+ return ret;
+#endif
+}
+
static int decompress(struct btrfs_root *root, char *inbuf, char *outbuf,
u64 compress_len, u64 *decompress_len, int compress)
{
case BTRFS_COMPRESS_LZO:
return decompress_lzo(root, (unsigned char *)inbuf, outbuf,
compress_len, decompress_len);
+ case BTRFS_COMPRESS_ZSTD:
+ return decompress_zstd(inbuf, outbuf, compress_len,
+ *decompress_len);
default:
break;
}
int offset = 1;
struct extent_buffer *c;
struct extent_buffer *next = NULL;
+ struct btrfs_fs_info *fs_info = root->fs_info;
again:
for (; level < BTRFS_MAX_LEVEL; level++) {
if (path->reada)
reada_for_search(root, path, level, slot, 0);
- next = read_node_slot(root, c, slot);
+ next = read_node_slot(fs_info, c, slot);
if (extent_buffer_uptodate(next))
break;
offset++;
break;
if (path->reada)
reada_for_search(root, path, level, 0, 0);
- next = read_node_slot(root, next, 0);
+ next = read_node_slot(fs_info, next, 0);
if (!extent_buffer_uptodate(next))
goto again;
}
inbuf = malloc(size_left);
if (!inbuf) {
- error("not enough memory\n");
+ error("not enough memory");
return -ENOMEM;
}
}
again:
length = size_left;
- ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
- bytenr, &length, &multi, mirror_num, NULL);
+ ret = btrfs_map_block(root->fs_info, READ, bytenr, &length, &multi,
+ mirror_num, NULL);
if (ret) {
error("cannot map block logical %llu length %llu: %d",
(unsigned long long)bytenr,
done = pread(dev_fd, inbuf+count, length, dev_bytenr);
/* Need both checks, or we miss negative values due to u64 conversion */
if (done < 0 || done < length) {
- num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
- bytenr, length);
+ num_copies = btrfs_num_copies(root->fs_info, bytenr, length);
mirror_num++;
/* mirror_num is 1-indexed, so num_copies is a valid mirror. */
if (mirror_num > num_copies) {
pos+total);
if (done < 0) {
ret = -1;
- error("cannot write data: %d %s", errno, strerror(errno));
+ error("cannot write data: %d %m", errno);
goto out;
}
total += done;
ret = decompress(root, inbuf, outbuf, disk_size, &ram_size, compress);
if (ret) {
- num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
- bytenr, length);
+ num_copies = btrfs_num_copies(root->fs_info, bytenr, length);
mirror_num++;
if (mirror_num >= num_copies) {
ret = -1;
do {
ret = next_leaf(root, &path);
if (ret < 0) {
- error("searching for extended attributes: %d\n",
+ error("searching for extended attributes: %d",
ret);
goto out;
} else if (ret) {
data_len = len;
if (fsetxattr(fd, name, data, data_len, 0))
- error("setting extended attribute %s on file %s: %s",
- name, file_name, strerror(errno));
+ error("setting extended attribute %s on file %s: %m",
+ name, file_name);
len = sizeof(*di) + name_len + data_len;
cur += len;
ret = fchown(fd, btrfs_inode_uid(path.nodes[0], inode_item),
btrfs_inode_gid(path.nodes[0], inode_item));
if (ret) {
- error("failed to change owner: %s", strerror(errno));
+ error("failed to change owner: %m");
goto out;
}
ret = fchmod(fd, btrfs_inode_mode(path.nodes[0], inode_item));
if (ret) {
- error("failed to change mode: %s", strerror(errno));
+ error("failed to change mode: %m");
goto out;
}
ret = futimens(fd, times);
if (ret) {
- error("failed to set times: %s", strerror(errno));
+ error("failed to set times: %m");
goto out;
}
}
if (!dry_run) {
ret = symlink(symlink_target, path_name);
if (ret < 0) {
- fprintf(stderr, "Failed to restore symlink '%s': %s\n",
- path_name, strerror(errno));
+ fprintf(stderr, "Failed to restore symlink '%s': %m\n",
+ path_name);
goto out;
}
}
btrfs_inode_gid(path.nodes[0], inode_item),
AT_SYMLINK_NOFOLLOW);
if (ret) {
- fprintf(stderr, "Failed to change owner: %s\n",
- strerror(errno));
+ fprintf(stderr, "Failed to change owner: %m\n");
goto out;
}
ret = utimensat(-1, file, times, AT_SYMLINK_NOFOLLOW);
if (ret)
- fprintf(stderr, "Failed to set times: %s\n", strerror(errno));
+ fprintf(stderr, "Failed to set times: %m\n");
out:
btrfs_release_path(&path);
return ret;
const char *output_rootdir, const char *in_dir,
const regex_t *mreg)
{
- struct btrfs_path *path;
+ struct btrfs_path path;
struct extent_buffer *leaf;
struct btrfs_dir_item *dir_item;
struct btrfs_key found_key, location;
int loops = 0;
u8 type;
- path = btrfs_alloc_path();
- if (!path) {
- fprintf(stderr, "Ran out of memory\n");
- return -ENOMEM;
- }
-
+ btrfs_init_path(&path);
key->offset = 0;
key->type = BTRFS_DIR_INDEX_KEY;
-
- ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
+ ret = btrfs_search_slot(NULL, root, key, &path, 0, 0);
if (ret < 0) {
fprintf(stderr, "Error searching %d\n", ret);
goto out;
ret = 0;
- leaf = path->nodes[0];
+ leaf = path.nodes[0];
while (!leaf) {
if (verbose > 1)
printf("No leaf after search, looking for the next "
"leaf\n");
- ret = next_leaf(root, path);
+ ret = next_leaf(root, &path);
if (ret < 0) {
fprintf(stderr, "Error getting next leaf %d\n",
ret);
ret = 0;
goto out;
}
- leaf = path->nodes[0];
+ leaf = path.nodes[0];
}
while (leaf) {
break;
}
- if (path->slots[0] >= btrfs_header_nritems(leaf)) {
+ if (path.slots[0] >= btrfs_header_nritems(leaf)) {
do {
- ret = next_leaf(root, path);
+ ret = next_leaf(root, &path);
if (ret < 0) {
fprintf(stderr, "Error searching %d\n",
ret);
ret = 0;
goto out;
}
- leaf = path->nodes[0];
+ leaf = path.nodes[0];
} while (!leaf);
continue;
}
- btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
+ btrfs_item_key_to_cpu(leaf, &found_key, path.slots[0]);
if (found_key.objectid != key->objectid) {
if (verbose > 1)
printf("Found objectid=%Lu, key=%Lu\n",
found_key.type, key->type);
break;
}
- dir_item = btrfs_item_ptr(leaf, path->slots[0],
+ dir_item = btrfs_item_ptr(leaf, path.slots[0],
struct btrfs_dir_item);
name_ptr = (unsigned long)(dir_item + 1);
name_len = btrfs_dir_name_len(leaf, dir_item);
if (ret < 0) {
if (ignore_errors)
goto next;
- btrfs_free_path(path);
+ btrfs_release_path(&path);
return ret;
}
}
next:
- path->slots[0]++;
+ path.slots[0]++;
}
if (restore_metadata) {
if (verbose)
printf("Done searching %s\n", in_dir);
out:
- btrfs_free_path(path);
+ btrfs_release_path(&path);
return ret;
}
struct btrfs_key key;
struct btrfs_key found_key;
struct btrfs_disk_key disk_key;
- struct btrfs_path *path;
+ struct btrfs_path path;
struct extent_buffer *leaf;
struct btrfs_root_item ri;
unsigned long offset;
int ret;
root = root->fs_info->tree_root;
- path = btrfs_alloc_path();
- if (!path) {
- fprintf(stderr, "Failed to alloc path\n");
- return -ENOMEM;
- }
+ btrfs_init_path(&path);
key.offset = 0;
key.objectid = 0;
key.type = BTRFS_ROOT_ITEM_KEY;
-
- ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (ret < 0) {
fprintf(stderr, "Failed to do search %d\n", ret);
- btrfs_free_path(path);
+ btrfs_release_path(&path);
return -1;
}
- leaf = path->nodes[0];
+ leaf = path.nodes[0];
while (1) {
- slot = path->slots[0];
+ slot = path.slots[0];
if (slot >= btrfs_header_nritems(leaf)) {
- ret = btrfs_next_leaf(root, path);
+ ret = btrfs_next_leaf(root, &path);
if (ret)
break;
- leaf = path->nodes[0];
- slot = path->slots[0];
+ leaf = path.nodes[0];
+ slot = path.slots[0];
}
btrfs_item_key(leaf, &disk_key, slot);
btrfs_disk_key_to_cpu(&found_key, &disk_key);
if (found_key.type != BTRFS_ROOT_ITEM_KEY) {
- path->slots[0]++;
+ path.slots[0]++;
continue;
}
btrfs_print_key(&disk_key);
printf(" %Lu level %d\n", btrfs_root_bytenr(&ri),
btrfs_root_level(&ri));
- path->slots[0]++;
+ path.slots[0]++;
}
- btrfs_free_path(path);
+ btrfs_release_path(&path);
return 0;
}
if (!root_location)
root_location = btrfs_super_root(fs_info->super_copy);
generation = btrfs_super_generation(fs_info->super_copy);
- root->node = read_tree_block(root, root_location,
- root->nodesize, generation);
+ root->node = read_tree_block(fs_info, root_location,
+ generation);
if (!extent_buffer_uptodate(root->node)) {
fprintf(stderr, "Error opening tree root\n");
close_ctree(root);
static int find_first_dir(struct btrfs_root *root, u64 *objectid)
{
- struct btrfs_path *path;
+ struct btrfs_path path;
struct btrfs_key found_key;
struct btrfs_key key;
int ret = -1;
int i;
+ btrfs_init_path(&path);
key.objectid = 0;
key.type = BTRFS_DIR_INDEX_KEY;
key.offset = 0;
-
- path = btrfs_alloc_path();
- if (!path) {
- fprintf(stderr, "Ran out of memory\n");
- return ret;
- }
-
- ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (ret < 0) {
fprintf(stderr, "Error searching %d\n", ret);
goto out;
}
- if (!path->nodes[0]) {
+ if (!path.nodes[0]) {
fprintf(stderr, "No leaf!\n");
goto out;
}
again:
- for (i = path->slots[0];
- i < btrfs_header_nritems(path->nodes[0]); i++) {
- btrfs_item_key_to_cpu(path->nodes[0], &found_key, i);
+ for (i = path.slots[0];
+ i < btrfs_header_nritems(path.nodes[0]); i++) {
+ btrfs_item_key_to_cpu(path.nodes[0], &found_key, i);
if (found_key.type != key.type)
continue;
goto out;
}
do {
- ret = next_leaf(root, path);
+ ret = next_leaf(root, &path);
if (ret < 0) {
fprintf(stderr, "Error getting next leaf %d\n",
ret);
fprintf(stderr, "No more leaves\n");
goto out;
}
- } while (!path->nodes[0]);
- if (path->nodes[0])
+ } while (!path.nodes[0]);
+ if (path.nodes[0])
goto again;
printf("Couldn't find a dir index item\n");
out:
- btrfs_free_path(path);
+ btrfs_release_path(&path);
return ret;
}
if (fs_location != 0) {
free_extent_buffer(root->node);
- root->node = read_tree_block(root, fs_location, root->nodesize, 0);
+ root->node = read_tree_block(root->fs_info, fs_location, 0);
if (!extent_buffer_uptodate(root->node)) {
fprintf(stderr, "Failed to read fs location\n");
ret = 1;