mirror of
https://github.com/clearlinux/systemd-stable.git
synced 2026-10-03 15:30:38 +00:00
import-raw: when downloading raw images, generate sparse files if we can
This commit is contained in:
@@ -332,6 +332,14 @@ 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;
|
||||
@@ -427,7 +435,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;
|
||||
|
||||
@@ -7931,3 +7931,65 @@ void release_lock_file(LockFile *f) {
|
||||
f->fd = safe_close(f->fd);
|
||||
f->operation = 0;
|
||||
}
|
||||
|
||||
static size_t nul_length(const uint8_t *p, size_t sz) {
|
||||
size_t n = 0;
|
||||
|
||||
while (sz > 0) {
|
||||
if (*p != 0)
|
||||
break;
|
||||
|
||||
n++;
|
||||
p++;
|
||||
sz--;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
|
||||
const uint8_t *q, *w, *e;
|
||||
ssize_t l;
|
||||
|
||||
q = w = p;
|
||||
e = q + sz;
|
||||
while (q < e) {
|
||||
size_t n;
|
||||
|
||||
n = nul_length(q, e - q);
|
||||
|
||||
/* If there are more than the specified run length of
|
||||
* NUL bytes, or if this is the beginning or the end
|
||||
* of the buffer, then seek instead of write */
|
||||
if ((n > run_length) ||
|
||||
(n > 0 && q == p) ||
|
||||
(n > 0 && q + n >= e)) {
|
||||
if (q > w) {
|
||||
l = write(fd, w, q - w);
|
||||
if (l < 0)
|
||||
return -errno;
|
||||
if (l != q -w)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
|
||||
return -errno;
|
||||
|
||||
q += n;
|
||||
w = q;
|
||||
} else if (n > 0)
|
||||
q += n;
|
||||
else
|
||||
q ++;
|
||||
}
|
||||
|
||||
if (q > w) {
|
||||
l = write(fd, w, q - w);
|
||||
if (l < 0)
|
||||
return -errno;
|
||||
if (l != q - w)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return q - (const uint8_t*) p;
|
||||
}
|
||||
|
||||
@@ -1062,3 +1062,5 @@ void release_lock_file(LockFile *f);
|
||||
#define LOCK_FILE_INIT { .fd = -1, .path = NULL }
|
||||
|
||||
#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim })
|
||||
|
||||
ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
|
||||
|
||||
@@ -1464,6 +1464,42 @@ static void test_uid_ptr(void) {
|
||||
assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000);
|
||||
}
|
||||
|
||||
static void test_sparse_write_one(int fd, const char *buffer, size_t n) {
|
||||
char check[n];
|
||||
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(ftruncate(fd, 0) >= 0);
|
||||
assert_se(sparse_write(fd, buffer, n, 4) == (ssize_t) n);
|
||||
|
||||
assert_se(lseek(fd, 0, SEEK_CUR) == (off_t) n);
|
||||
assert_se(ftruncate(fd, n) >= 0);
|
||||
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(read(fd, check, n) == (ssize_t) n);
|
||||
|
||||
assert_se(memcmp(buffer, check, n) == 0);
|
||||
}
|
||||
|
||||
static void test_sparse_write(void) {
|
||||
const char test_a[] = "test";
|
||||
const char test_b[] = "\0\0\0\0test\0\0\0\0";
|
||||
const char test_c[] = "\0\0test\0\0\0\0";
|
||||
const char test_d[] = "\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0\0\0\0";
|
||||
const char test_e[] = "test\0\0\0\0test";
|
||||
_cleanup_close_ int fd = -1;
|
||||
char fn[] = "/tmp/sparseXXXXXX";
|
||||
|
||||
fd = mkostemp(fn, O_CLOEXEC);
|
||||
assert_se(fd >= 0);
|
||||
unlink(fn);
|
||||
|
||||
test_sparse_write_one(fd, test_a, sizeof(test_a));
|
||||
test_sparse_write_one(fd, test_b, sizeof(test_b));
|
||||
test_sparse_write_one(fd, test_c, sizeof(test_c));
|
||||
test_sparse_write_one(fd, test_d, sizeof(test_d));
|
||||
test_sparse_write_one(fd, test_e, sizeof(test_e));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
@@ -1540,6 +1576,7 @@ int main(int argc, char *argv[]) {
|
||||
test_raw_clone();
|
||||
test_same_fd();
|
||||
test_uid_ptr();
|
||||
test_sparse_write();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user