import-raw.c revision 920b52e4909d9dc812817fd8b82f83ca23a11c91
/*-*- 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 "util.h"
#include "path-util.h"
#include "btrfs-util.h"
#include "copy.h"
#include "mkdir.h"
#include "rm-rf.h"
#include "ratelimit.h"
#include "machine-pool.h"
#include "qcow2-util.h"
#include "import-compress.h"
#include "import-common.h"
#include "import-raw.h"
struct RawImport {
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 output_fd;
unsigned last_percent;
};
if (!i)
return NULL;
sd_event_unref(i->event);
if (i->temp_path) {
}
import_compress_free(&i->compress);
safe_close(i->output_fd);
free(i->final_path);
free(i->image_root);
free(i);
return NULL;
}
int raw_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 raw_import_report_progress(RawImport *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 raw_import_maybe_convert_qcow2(RawImport *i) {
_cleanup_free_ char *t = NULL;
int r;
assert(i);
r = qcow2_detect(i->output_fd);
if (r < 0)
return log_error_errno(r, "Failed to detect whether this is a QCOW2 image: %m");
if (r == 0)
return 0;
/* This is a QCOW2 image, let's convert it */
r = tempfn_random(i->final_path, &t);
if (r < 0)
return log_oom();
if (converted_fd < 0)
if (r < 0)
log_info("Unpacking QCOW2 file.");
if (r < 0) {
unlink(t);
return log_error_errno(r, "Failed to convert qcow2 image: %m");
}
i->temp_path = t;
t = NULL;
safe_close(i->output_fd);
i->output_fd = converted_fd;
converted_fd = -1;
return 1;
}
static int raw_import_finish(RawImport *i) {
int r;
assert(i);
assert(i->final_path);
/* In case this was a sparse file, make sure the file system is right */
if (i->written_uncompressed > 0) {
}
r = raw_import_maybe_convert_qcow2(i);
if (r < 0)
return r;
}
if (i->read_only) {
r = import_make_read_only_fd(i->output_fd);
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 raw_import_open_disk(RawImport *i) {
int r;
assert(i);
assert(!i->final_path);
if (!i->final_path)
return log_oom();
if (r < 0)
return log_oom();
if (i->output_fd < 0)
if (r < 0)
return 0;
}
static int raw_import_try_reflink(RawImport *i) {
off_t p;
int r;
assert(i);
return 0;
return 0;
if (p == (off_t) -1)
/* Let's only try a btrfs reflink, if we are reading from the beginning of the file */
return 0;
if (r >= 0)
return 1;
return 0;
}
ssize_t n;
i->written_since_last_grow = 0;
}
if (n < 0)
return -errno;
return -EIO;
i->written_uncompressed += sz;
i->written_since_last_grow += sz;
return 0;
}
static int raw_import_process(RawImport *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 = raw_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 = raw_import_open_disk(i);
if (r < 0)
goto finish;
r = raw_import_try_reflink(i);
if (r < 0)
goto finish;
if (r > 0) {
r = raw_import_finish(i);
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 raw_import_process(i);
}
return raw_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;
}