X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fimport%2Fimport-raw.c;h=94b936b43983ccdd2bf975361243fc7eeec39ff9;hb=2f64ba0e6ea4fe8bac69215290d16321ab820f54;hp=f1b36cbfcc242d91d0142e0f56f19146639a03b6;hpb=49bb233bb734536b9617d838f09a7bf9b8336003;p=elogind.git diff --git a/src/import/import-raw.c b/src/import/import-raw.c index f1b36cbfc..94b936b43 100644 --- a/src/import/import-raw.c +++ b/src/import/import-raw.c @@ -27,6 +27,7 @@ #include "hashmap.h" #include "utf8.h" #include "curl-util.h" +#include "qcow2-util.h" #include "import-raw.h" #include "strv.h" #include "copy.h" @@ -151,82 +152,81 @@ static int raw_import_file_make_final_path(RawImportFile *f) { return 0; } -static void raw_import_file_success(RawImportFile *f) { +static int raw_import_file_make_local_copy(RawImportFile *f) { + _cleanup_free_ char *tp = NULL; + _cleanup_close_ int dfd = -1; + const char *p; int r; assert(f); - f->done = true; + if (!f->local) + return 0; - if (f->local) { - _cleanup_free_ char *tp = NULL; - _cleanup_close_ int dfd = -1; - const char *p; + if (f->disk_fd >= 0) { + if (lseek(f->disk_fd, SEEK_SET, 0) == (off_t) -1) + return log_error_errno(errno, "Failed to seek to beginning of vendor image: %m"); + } else { + r = raw_import_file_make_final_path(f); + if (r < 0) + return log_oom(); - if (f->disk_fd >= 0) { - if (lseek(f->disk_fd, SEEK_SET, 0) == (off_t) -1) { - r = log_error_errno(errno, "Failed to seek to beginning of vendor image: %m"); - goto finish; - } - } else { - r = raw_import_file_make_final_path(f); - if (r < 0) { - log_oom(); - goto finish; - } + f->disk_fd = open(f->final_path, O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (f->disk_fd < 0) + return log_error_errno(errno, "Failed to open vendor image: %m"); + } - f->disk_fd = open(f->final_path, O_RDONLY|O_NOCTTY|O_CLOEXEC); - if (f->disk_fd < 0) { - r = log_error_errno(errno, "Failed to open vendor image: %m"); - goto finish; - } - } + p = strappenda(f->import->image_root, "/", f->local, ".raw"); + if (f->force_local) + (void) rm_rf_dangerous(p, false, true, false); - p = strappenda(f->import->image_root, "/", f->local, ".raw"); - if (f->force_local) - (void) rm_rf_dangerous(p, false, true, false); + r = tempfn_random(p, &tp); + if (r < 0) + return log_oom(); - r = tempfn_random(p, &tp); - if (r < 0) { - log_oom(); - goto finish; - } + dfd = open(tp, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664); + if (dfd < 0) + return log_error_errno(errno, "Failed to create writable copy of image: %m"); - dfd = open(tp, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664); - if (dfd < 0) { - r = log_error_errno(errno, "Failed to create writable copy of image: %m"); - goto finish; - } + /* Turn off COW writing. This should greatly improve + * performance on COW file systems like btrfs, since it + * reduces fragmentation caused by not allowing in-place + * writes. */ + r = chattr_fd(dfd, true, FS_NOCOW_FL); + if (r < 0) + log_warning_errno(errno, "Failed to set file attributes on %s: %m", tp); - /* Turn off COW writing. This should greatly improve - * performance on COW file systems like btrfs, since it - * reduces fragmentation caused by not allowing in-place - * writes. */ - r = chattr_fd(dfd, true, FS_NOCOW_FL); - if (r < 0) - log_warning_errno(errno, "Failed to set file attributes on %s: %m", f->temp_path); + r = copy_bytes(f->disk_fd, dfd, (off_t) -1, true); + if (r < 0) { + unlink(tp); + return log_error_errno(r, "Failed to make writable copy of image: %m"); + } - r = copy_bytes(f->disk_fd, dfd, (off_t) -1, true); - if (r < 0) { - log_error_errno(r, "Failed to make writable copy of image: %m"); - unlink(tp); - goto finish; - } + (void) copy_times(f->disk_fd, dfd); + (void) copy_xattr(f->disk_fd, dfd); - (void) copy_times(f->disk_fd, dfd); - (void) copy_xattr(f->disk_fd, dfd); + dfd = safe_close(dfd); - dfd = safe_close(dfd); + r = rename(tp, p); + if (r < 0) { + unlink(tp); + return log_error_errno(errno, "Failed to move writable image into place: %m"); + } - r = rename(tp, p); - if (r < 0) { - r = log_error_errno(errno, "Failed to move writable image into place: %m"); - unlink(tp); - goto finish; - } + log_info("Created new local image %s.", p); + return 0; +} - log_info("Created new local image %s.", p); - } +static void raw_import_file_success(RawImportFile *f) { + int r; + + assert(f); + + f->done = true; + + r = raw_import_file_make_local_copy(f); + if (r < 0) + goto finish; f->disk_fd = safe_close(f->disk_fd); r = 0; @@ -235,6 +235,49 @@ finish: raw_import_finish(f->import, r); } +static int raw_import_maybe_convert_qcow2(RawImportFile *f) { + _cleanup_close_ int converted_fd = -1; + _cleanup_free_ char *t = NULL; + int r; + + assert(f); + assert(f->disk_fd); + assert(f->temp_path); + + r = qcow2_detect(f->disk_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(f->final_path, &t); + if (r < 0) + return log_oom(); + + converted_fd = open(t, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0644); + if (converted_fd < 0) + return log_error_errno(errno, "Failed to create %s: %m", t); + + r = qcow2_convert(f->disk_fd, converted_fd); + if (r < 0) { + unlink(t); + return log_error_errno(r, "Failed to convert qcow2 image: %m"); + } + + unlink(f->temp_path); + free(f->temp_path); + + f->temp_path = t; + t = NULL; + + safe_close(f->disk_fd); + f->disk_fd = converted_fd; + converted_fd = -1; + + return 1; +} + static void raw_import_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) { RawImportFile *f = NULL; struct stat st; @@ -288,6 +331,18 @@ static void raw_import_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result goto fail; } + /* Make sure the file size is right, in case the file was + * sparse and we just seeked for the last part */ + if (ftruncate(f->disk_fd, f->written_uncompressed) < 0) { + log_error_errno(errno, "Failed to truncate file: %m"); + r = -errno; + goto fail; + } + + r = raw_import_maybe_convert_qcow2(f); + if (r < 0) + goto fail; + if (f->etag) (void) fsetxattr(f->disk_fd, "user.source_etag", f->etag, strlen(f->etag), 0); if (f->url) @@ -354,6 +409,10 @@ static int raw_import_file_open_disk_for_write(RawImportFile *f) { if (f->disk_fd < 0) return log_error_errno(errno, "Failed to create %s: %m", f->temp_path); + r = chattr_fd(f->disk_fd, true, FS_NOCOW_FL); + if (r < 0) + log_warning_errno(errno, "Failed to set file attributes on %s: %m", f->temp_path); + return 0; } @@ -375,7 +434,7 @@ static int raw_import_file_write_uncompressed(RawImportFile *f, void *p, size_t return -EFBIG; } - n = write(f->disk_fd, p, sz); + n = sparse_write(f->disk_fd, p, sz, 64); if (n < 0) { log_error_errno(errno, "Failed to write file: %m"); return -errno;