#include <wait.h>
#include <assert.h>
#include <getopt.h>
+#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
int dest_dir_fd;
int write_fd;
- char *write_path;
+ char write_path[PATH_MAX];
char *root_path;
char *dest_dir_path; /* relative to root_path */
- char *full_subvol_path;
+ char full_subvol_path[PATH_MAX];
+ char *full_root_path;
int dest_dir_chroot;
- struct subvol_info *cur_subvol;
+ struct subvol_info cur_subvol;
+ /*
+ * Substitute for cur_subvol::path which is a pointer and we cannot
+ * change it to an array as it's a public API.
+ */
+ char cur_subvol_path[PATH_MAX];
struct subvol_uuid_search sus;
char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
u64 flags;
- if (r->cur_subvol == NULL)
+ if (r->cur_subvol_path[0] == 0)
return 0;
- subvol_fd = openat(r->mnt_fd, r->cur_subvol->path,
+ subvol_fd = openat(r->mnt_fd, r->cur_subvol_path,
O_RDONLY | O_NOATIME);
if (subvol_fd < 0) {
ret = -errno;
fprintf(stderr, "ERROR: open %s failed. %s\n",
- r->cur_subvol->path, strerror(-ret));
+ r->cur_subvol_path, strerror(-ret));
goto out;
}
memset(&rs_args, 0, sizeof(rs_args));
- memcpy(rs_args.uuid, r->cur_subvol->received_uuid, BTRFS_UUID_SIZE);
- rs_args.stransid = r->cur_subvol->stransid;
+ memcpy(rs_args.uuid, r->cur_subvol.received_uuid, BTRFS_UUID_SIZE);
+ rs_args.stransid = r->cur_subvol.stransid;
if (g_verbose >= 1) {
uuid_unparse((u8*)rs_args.uuid, uuid_str);
strerror(-ret));
goto out;
}
- r->cur_subvol->rtransid = rs_args.rtransid;
+ r->cur_subvol.rtransid = rs_args.rtransid;
ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
if (ret < 0) {
ret = 0;
out:
- if (r->cur_subvol) {
- free(r->cur_subvol->path);
- free(r->cur_subvol);
- r->cur_subvol = NULL;
+ if (r->cur_subvol_path[0]) {
+ r->cur_subvol_path[0] = 0;
}
if (subvol_fd != -1)
close(subvol_fd);
if (ret < 0)
goto out;
- r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
+ BUG_ON(r->cur_subvol.path);
+ BUG_ON(r->cur_subvol_path[0]);
- if (strlen(r->dest_dir_path) == 0)
- r->cur_subvol->path = strdup(path);
- else
- r->cur_subvol->path = path_cat(r->dest_dir_path, path);
- free(r->full_subvol_path);
- r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
+ if (strlen(r->dest_dir_path) == 0) {
+ strncpy_null(r->cur_subvol_path, path);
+ } else {
+ ret = path_cat_out(r->cur_subvol_path, r->dest_dir_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: subvol: path invalid: %s\n",
+ path);
+ goto out;
+ }
+ }
+ ret = path_cat3_out(r->full_subvol_path, r->root_path,
+ r->dest_dir_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: subvol: path invalid: %s\n", path);
+ goto out;
+ }
fprintf(stderr, "At subvol %s\n", path);
- memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
- r->cur_subvol->stransid = ctransid;
+ memcpy(r->cur_subvol.received_uuid, uuid, BTRFS_UUID_SIZE);
+ r->cur_subvol.stransid = ctransid;
if (g_verbose) {
- uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
+ uuid_unparse((u8*)r->cur_subvol.received_uuid, uuid_str);
fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
path, uuid_str,
- r->cur_subvol->stransid);
+ r->cur_subvol.stransid);
}
memset(&args_v1, 0, sizeof(args_v1));
if (ret < 0)
goto out;
- r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
+ BUG_ON(r->cur_subvol.path);
+ BUG_ON(r->cur_subvol_path[0]);
- if (strlen(r->dest_dir_path) == 0)
- r->cur_subvol->path = strdup(path);
- else
- r->cur_subvol->path = path_cat(r->dest_dir_path, path);
- free(r->full_subvol_path);
- r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
+ if (strlen(r->dest_dir_path) == 0) {
+ strncpy_null(r->cur_subvol_path, path);
+ } else {
+ ret = path_cat_out(r->cur_subvol_path, r->dest_dir_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: snapshot: path invalid: %s\n",
+ path);
+ goto out;
+ }
+ }
+ ret = path_cat3_out(r->full_subvol_path, r->root_path,
+ r->dest_dir_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: snapshot: path invalid: %s\n", path);
+ goto out;
+ }
fprintf(stdout, "At snapshot %s\n", path);
- memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
- r->cur_subvol->stransid = ctransid;
+ memcpy(r->cur_subvol.received_uuid, uuid, BTRFS_UUID_SIZE);
+ r->cur_subvol.stransid = ctransid;
if (g_verbose) {
- uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
+ uuid_unparse((u8*)r->cur_subvol.received_uuid, uuid_str);
fprintf(stderr, "receiving snapshot %s uuid=%s, "
"ctransid=%llu ", path, uuid_str,
- r->cur_subvol->stransid);
+ r->cur_subvol.stransid);
uuid_unparse(parent_uuid, uuid_str);
fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
uuid_str, parent_ctransid);
goto out;
}
+ /*
+ * The path is resolved from the root subvol, but we could be in some
+ * subvolume under the root subvolume, so try and adjust the path to be
+ * relative to our root path.
+ */
+ if (r->full_root_path) {
+ size_t root_len;
+ size_t sub_len;
+
+ root_len = strlen(r->full_root_path);
+ sub_len = strlen(parent_subvol->path);
+
+ /* First make sure the parent subvol is actually in our path */
+ if (sub_len < root_len ||
+ strstr(parent_subvol->path, r->full_root_path) == NULL) {
+ fprintf(stderr, "ERROR: parent subvol is not reachable"
+ " from inside the root subvol.\n");
+ ret = -ENOENT;
+ goto out;
+ }
+
+ if (sub_len == root_len) {
+ parent_subvol->path[0] = '/';
+ parent_subvol->path[1] = '\0';
+ } else {
+ /*
+ * root path is foo/bar
+ * subvol path is foo/bar/baz
+ *
+ * we need to have baz be the path, so we need to move
+ * the bit after foo/bar/, so path + root_len + 1, and
+ * move the part we care about, so sub_len - root_len -
+ * 1.
+ */
+ memmove(parent_subvol->path,
+ parent_subvol->path + root_len + 1,
+ sub_len - root_len - 1);
+ parent_subvol->path[sub_len - root_len - 1] = '\0';
+ }
+ }
/*if (rs_args.ctransid > rs_args.rtransid) {
if (!r->force) {
ret = -EINVAL;
}
}*/
- args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
- O_RDONLY | O_NOATIME);
+ if (strlen(parent_subvol->path) == 0)
+ args_v2.fd = dup(r->mnt_fd);
+ else
+ args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
+ O_RDONLY | O_NOATIME);
if (args_v2.fd < 0) {
ret = -errno;
if (errno != ENOENT)
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: mkfile: path invalid: %s\n", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "mkfile %s\n", path);
ret = 0;
out:
- free(full_path);
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: mkdir: path invalid: %s\n", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "mkdir %s\n", path);
strerror(-ret));
}
- free(full_path);
+out:
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: mknod: path invalid: %s\n", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
strerror(-ret));
}
- free(full_path);
+out:
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: mkfifo: path invalid: %s\n", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "mkfifo %s\n", path);
strerror(-ret));
}
- free(full_path);
+out:
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: mksock: path invalid: %s\n", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "mksock %s\n", path);
strerror(-ret));
}
- free(full_path);
+out:
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: symlink: path invalid: %s\n", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "symlink %s -> %s\n", path, lnk);
lnk, strerror(-ret));
}
- free(full_path);
+out:
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_from = path_cat(r->full_subvol_path, from);
- char *full_to = path_cat(r->full_subvol_path, to);
+ char full_from[PATH_MAX];
+ char full_to[PATH_MAX];
+
+ ret = path_cat_out(full_from, r->full_subvol_path, from);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: rename: source path invalid: %s\n",
+ from);
+ goto out;
+ }
+
+ ret = path_cat_out(full_to, r->full_subvol_path, to);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: rename: target path invalid: %s\n",
+ to);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "rename %s -> %s\n", from, to);
to, strerror(-ret));
}
- free(full_from);
- free(full_to);
+out:
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
- char *full_link_path = path_cat(r->full_subvol_path, lnk);
+ char full_path[PATH_MAX];
+ char full_link_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: link: source path invalid: %s\n",
+ full_path);
+ goto out;
+ }
+
+ ret = path_cat_out(full_link_path, r->full_subvol_path, lnk);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: link: target path invalid: %s\n",
+ full_link_path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "link %s -> %s\n", path, lnk);
lnk, strerror(-ret));
}
- free(full_path);
- free(full_link_path);
+out:
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: unlink: path invalid: %s\n", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "unlink %s\n", path);
strerror(-ret));
}
- free(full_path);
+out:
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: rmdir: path invalid: %s\n", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "rmdir %s\n", path);
strerror(-ret));
}
- free(full_path);
+out:
return ret;
}
-
static int open_inode_for_write(struct btrfs_receive *r, const char *path)
{
int ret = 0;
strerror(-ret));
goto out;
}
- free(r->write_path);
- r->write_path = strdup(path);
+ strncpy_null(r->write_path, path);
out:
return ret;
{
int ret = 0;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
u64 pos = 0;
int w;
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: write: path invalid: %s\n", path);
+ goto out;
+ }
+
ret = open_inode_for_write(r, full_path);
if (ret < 0)
goto out;
}
out:
- free(full_path);
return ret;
}
struct btrfs_receive *r = user;
struct btrfs_ioctl_clone_range_args clone_args;
struct subvol_info *si = NULL;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
char *subvol_path = NULL;
- char *full_clone_path = NULL;
+ char full_clone_path[PATH_MAX];
int clone_fd = -1;
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: clone: source path invalid: %s\n",
+ path);
+ goto out;
+ }
+
ret = open_inode_for_write(r, full_path);
if (ret < 0)
goto out;
si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
subvol_search_by_received_uuid);
if (!si) {
- if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
+ if (memcmp(clone_uuid, r->cur_subvol.received_uuid,
BTRFS_UUID_SIZE) == 0) {
/* TODO check generation of extent */
- subvol_path = strdup(r->cur_subvol->path);
+ subvol_path = strdup(r->cur_subvol_path);
} else {
ret = -ENOENT;
fprintf(stderr, "ERROR: did not find source subvol.\n");
subvol_path = strdup(si->path);
}
- full_clone_path = path_cat(subvol_path, clone_path);
+ ret = path_cat_out(full_clone_path, subvol_path, clone_path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: clone: target path invalid: %s\n",
+ clone_path);
+ goto out;
+ }
clone_fd = openat(r->mnt_fd, full_clone_path, O_RDONLY | O_NOATIME);
if (clone_fd < 0) {
free(si->path);
free(si);
}
- free(full_path);
- free(full_clone_path);
free(subvol_path);
if (clone_fd != -1)
close(clone_fd);
{
int ret = 0;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: set_xattr: path invalid: %s\n", path);
+ goto out;
+ }
if (strcmp("security.capability", name) == 0) {
if (g_verbose >= 3)
}
out:
- free(full_path);
return ret;
}
{
int ret = 0;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: remove_xattr: path invalid: %s\n",
+ path);
+ goto out;
+ }
if (g_verbose >= 2) {
fprintf(stderr, "remove_xattr %s - name=%s\n",
}
out:
- free(full_path);
return ret;
}
{
int ret = 0;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: truncate: path invalid: %s\n", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "truncate %s size=%llu\n", path, size);
}
out:
- free(full_path);
return ret;
}
{
int ret = 0;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: chmod: path invalid: %s\n", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
}
out:
- free(full_path);
return ret;
}
{
int ret = 0;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: chown: path invalid: %s\n", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
}
out:
- free(full_path);
return ret;
}
{
int ret = 0;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
struct timespec tv[2];
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: utimes: path invalid: %s\n", path);
+ goto out;
+ }
+
if (g_verbose >= 2)
fprintf(stderr, "utimes %s\n", path);
}
out:
- free(full_path);
return ret;
}
+static int process_update_extent(const char *path, u64 offset, u64 len,
+ void *user)
+{
+ if (g_verbose >= 2)
+ fprintf(stderr, "update_extent %s: offset=%llu, len=%llu\n",
+ path, (unsigned long long)offset,
+ (unsigned long long)len);
+
+ /*
+ * Sent with BTRFS_SEND_FLAG_NO_FILE_DATA, nothing to do.
+ */
+
+ return 0;
+}
static struct btrfs_send_ops send_ops = {
.subvol = process_subvol,
.chmod = process_chmod,
.chown = process_chown,
.utimes = process_utimes,
+ .update_extent = process_update_extent,
};
static int do_receive(struct btrfs_receive *r, const char *tomnt,
char *realmnt, int r_fd, u64 max_errors)
{
+ u64 subvol_id;
int ret;
char *dest_dir_full_path;
+ char root_subvol_path[PATH_MAX];
int end = 0;
dest_dir_full_path = realpath(tomnt, NULL);
goto out;
}
- if (realmnt) {
+ if (realmnt[0]) {
r->root_path = realmnt;
} else {
ret = find_mount_root(dest_dir_full_path, &r->root_path);
goto out;
}
+ /*
+ * If we use -m or a default subvol we want to resolve the path to the
+ * subvolume we're sitting in so that we can adjust the paths of any
+ * subvols we want to receive in.
+ */
+ ret = btrfs_list_get_path_rootid(r->mnt_fd, &subvol_id);
+ if (ret) {
+ fprintf(stderr, "ERROR: couldn't resolve our subvolid %d\n",
+ ret);
+ goto out;
+ }
+
+ root_subvol_path[0] = 0;
+ ret = btrfs_subvolid_resolve(r->mnt_fd, root_subvol_path,
+ PATH_MAX, subvol_id);
+ if (ret) {
+ fprintf(stderr, "ERROR: couldn't resolve our subvol path\n");
+ goto out;
+ }
+
+ /*
+ * Ok we're inside of a subvol off of the root subvol, we need to
+ * actually set full_root_path.
+ */
+ if (strlen(root_subvol_path))
+ r->full_root_path = root_subvol_path;
+
if (r->dest_dir_chroot) {
if (chroot(dest_dir_full_path)) {
ret = -errno;
}
free(r->root_path);
r->root_path = NULL;
- free(r->write_path);
- r->write_path = NULL;
- free(r->full_subvol_path);
- r->full_subvol_path = NULL;
r->dest_dir_path = NULL;
free(dest_dir_full_path);
- if (r->cur_subvol) {
- free(r->cur_subvol->path);
- free(r->cur_subvol);
- r->cur_subvol = NULL;
- }
subvol_uuid_search_finit(&r->sus);
if (r->mnt_fd != -1) {
close(r->mnt_fd);
close(r->dest_dir_fd);
r->dest_dir_fd = -1;
}
+
return ret;
}
int cmd_receive(int argc, char **argv)
{
char *tomnt = NULL;
- char *fromfile = NULL;
- char *realmnt = NULL;
+ char fromfile[PATH_MAX];
+ char realmnt[PATH_MAX];
struct btrfs_receive r;
int receive_fd = fileno(stdin);
u64 max_errors = 1;
- int ret;
+ int ret = 0;
memset(&r, 0, sizeof(r));
r.mnt_fd = -1;
r.write_fd = -1;
r.dest_dir_fd = -1;
r.dest_dir_chroot = 0;
+ realmnt[0] = 0;
+ fromfile[0] = 0;
while (1) {
int c;
g_verbose++;
break;
case 'f':
- fromfile = optarg;
+ if (arg_copy_path(fromfile, optarg, sizeof(fromfile))) {
+ fprintf(stderr,
+ "ERROR: input file path too long (%zu)\n",
+ strlen(optarg));
+ ret = 1;
+ goto out;
+ }
break;
case 'e':
r.honor_end_cmd = 1;
max_errors = arg_strtou64(optarg);
break;
case 'm':
- realmnt = strdup(optarg);
- if (!realmnt) {
- fprintf(stderr, "ERROR: couldn't allocate realmnt.\n");
- return 1;
+ if (arg_copy_path(realmnt, optarg, sizeof(realmnt))) {
+ fprintf(stderr,
+ "ERROR: mount point path too long (%zu)\n",
+ strlen(optarg));
+ ret = 1;
+ goto out;
}
break;
case '?':
tomnt = argv[optind];
- if (fromfile) {
+ if (fromfile[0]) {
receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
if (receive_fd < 0) {
fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
- return 1;
+ goto out;
}
}
ret = do_receive(&r, tomnt, realmnt, receive_fd, max_errors);
+out:
+
return !!ret;
}