import-tar.c revision 3ffd4af22052963e7a29431721ee204e634bea75
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2015 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "sd-daemon.h"
#include "sd-event.h"
#include "btrfs-util.h"
#include "copy.h"
#include "fd-util.h"
#include "hostname-util.h"
#include "import-common.h"
#include "import-compress.h"
#include "import-tar.h"
#include "machine-pool.h"
#include "mkdir.h"
#include "path-util.h"
#include "process-util.h"
#include "qcow2-util.h"
#include "ratelimit.h"
#include "rm-rf.h"
#include "string-util.h"
#include "util.h"
struct TarImport {
char *image_root;
void *userdata;
char *local;
bool force_local;
bool read_only;
bool grow_machine_directory;
char *temp_path;
char *final_path;
int input_fd;
int tar_fd;
unsigned last_percent;
};
if (!i)
return NULL;
if (i->tar_pid > 1) {
}
if (i->temp_path) {
}
import_compress_free(&i->compress);
sd_event_unref(i->event);
safe_close(i->tar_fd);
free(i->final_path);
free(i->image_root);
free(i);
return NULL;
}
int tar_import_new(
const char *image_root,
void *userdata) {
int r;
if (!i)
return -ENOMEM;
i->on_finished = on_finished;
i->last_percent = (unsigned) -1;
if (!i->image_root)
return -ENOMEM;
if (event)
else {
r = sd_event_default(&i->event);
if (r < 0)
return r;
}
*ret = i;
i = NULL;
return 0;
}
static void tar_import_report_progress(TarImport *i) {
unsigned percent;
assert(i);
/* We have no size information, unless the source is a regular file */
return;
percent = 100;
else
if (percent == i->last_percent)
return;
if (!ratelimit_test(&i->progress_rate_limit))
return;
i->last_percent = percent;
}
static int tar_import_finish(TarImport *i) {
int r;
assert(i);
assert(i->final_path);
if (i->tar_pid > 0) {
i->tar_pid = 0;
if (r < 0)
return r;
}
if (i->read_only) {
r = import_make_read_only(i->temp_path);
if (r < 0)
return r;
}
if (i->force_local)
if (r < 0)
return log_error_errno(r, "Failed to move image into place: %m");
return 0;
}
static int tar_import_fork_tar(TarImport *i) {
int r;
assert(i);
assert(!i->final_path);
if (!i->final_path)
return log_oom();
if (r < 0)
return log_oom();
r = btrfs_subvol_make(i->temp_path);
if (r == -ENOTTY) {
} else if (r < 0)
else
(void) import_assign_pool_quota_and_warn(i->temp_path);
if (i->tar_fd < 0)
return i->tar_fd;
return 0;
}
int r;
i->written_since_last_grow = 0;
}
if (r < 0)
return r;
i->written_uncompressed += sz;
i->written_since_last_grow += sz;
return 0;
}
static int tar_import_process(TarImport *i) {
ssize_t l;
int r;
assert(i);
if (l < 0) {
return 0;
goto finish;
}
if (l == 0) {
log_error("Premature end of file: %m");
r = -EIO;
goto finish;
}
r = tar_import_finish(i);
goto finish;
}
i->buffer_size += l;
if (r < 0) {
log_error("Failed to detect file compression: %m");
goto finish;
}
if (r == 0) /* Need more data */
return 0;
r = tar_import_fork_tar(i);
if (r < 0)
goto finish;
}
if (r < 0) {
log_error_errno(r, "Failed to decode and write: %m");
goto finish;
}
i->written_compressed += i->buffer_size;
i->buffer_size = 0;
return 0;
if (i->on_finished)
i->on_finished(i, r, i->userdata);
else
sd_event_exit(i->event, r);
return 0;
}
return tar_import_process(i);
}
return tar_import_process(i);
}
int r;
assert(i);
if (!machine_name_is_valid(local))
return -EINVAL;
if (i->input_fd >= 0)
return -EBUSY;
r = fd_nonblock(fd, true);
if (r < 0)
return r;
if (r < 0)
return r;
i->force_local = force_local;
return -errno;
if (r == -EPERM) {
/* This fd does not support epoll, for example because it is a regular file. Busy read in that case */
if (r < 0)
return r;
}
if (r < 0)
return r;
return r;
}