summaryrefslogtreecommitdiffstats
path: root/libsparse
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2012-05-18 14:49:50 -0700
committerColin Cross <ccross@android.com>2012-07-09 22:09:37 -0700
commitb4cd267db30c152245e6308598e0066d87c5c55d (patch)
treee888dfa52c033e91247daa5ad33c77696bfe6ff4 /libsparse
parent0c4c47f88dfc15cada154a1cf9b4db88b49890f0 (diff)
downloadsystem_core-b4cd267db30c152245e6308598e0066d87c5c55d.zip
system_core-b4cd267db30c152245e6308598e0066d87c5c55d.tar.gz
system_core-b4cd267db30c152245e6308598e0066d87c5c55d.tar.bz2
libsparse: pseudo-subclass output_file for normal and gz files
Create two subclasses of output_file that can handle normal and gzipped files, and refactor open_output_fd. Will allow adding support for an output_file type that is not file backed. Change-Id: I26744c74d13f205cf17df1ea9caac1eea9c57357
Diffstat (limited to 'libsparse')
-rw-r--r--libsparse/output_file.c236
-rw-r--r--libsparse/output_file.h3
2 files changed, 158 insertions, 81 deletions
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index 5e8a68c..14b057a 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -19,6 +19,7 @@
#include <fcntl.h>
#include <stdbool.h>
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
@@ -33,6 +34,8 @@
#ifndef USE_MINGW
#include <sys/mman.h>
#define O_BINARY 0
+#else
+#define ftruncate64 ftruncate
#endif
#if defined(__APPLE__) && defined(__MACH__)
@@ -59,8 +62,13 @@ static inline void *mmap64(void *addr, size_t length, int prot, int flags,
#define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
+#define container_of(inner, outer_t, elem) \
+ ((outer_t *)((char *)inner - offsetof(outer_t, elem)))
+
struct output_file_ops {
+ int (*open)(struct output_file *, int fd);
int (*skip)(struct output_file *, int64_t);
+ int (*pad)(struct output_file *, int64_t);
int (*write)(struct output_file *, void *, int);
void (*close)(struct output_file *);
};
@@ -75,9 +83,6 @@ struct sparse_file_ops {
};
struct output_file {
- int fd;
- gzFile gz_fd;
- bool close_fd;
int64_t cur_out_ptr;
unsigned int chunk_cnt;
uint32_t crc32;
@@ -88,13 +93,39 @@ struct output_file {
int64_t len;
char *zero_buf;
uint32_t *fill_buf;
+ char *buf;
+};
+
+struct output_file_gz {
+ struct output_file out;
+ gzFile gz_fd;
};
+#define to_output_file_gz(_o) \
+ container_of((_o), struct output_file_gz, out)
+
+struct output_file_normal {
+ struct output_file out;
+ int fd;
+};
+
+#define to_output_file_normal(_o) \
+ container_of((_o), struct output_file_normal, out)
+
+static int file_open(struct output_file *out, int fd)
+{
+ struct output_file_normal *outn = to_output_file_normal(out);
+
+ outn->fd = fd;
+ return 0;
+}
+
static int file_skip(struct output_file *out, int64_t cnt)
{
off64_t ret;
+ struct output_file_normal *outn = to_output_file_normal(out);
- ret = lseek64(out->fd, cnt, SEEK_CUR);
+ ret = lseek64(outn->fd, cnt, SEEK_CUR);
if (ret < 0) {
error_errno("lseek64");
return -1;
@@ -102,10 +133,25 @@ static int file_skip(struct output_file *out, int64_t cnt)
return 0;
}
+static int file_pad(struct output_file *out, int64_t len)
+{
+ int ret;
+ struct output_file_normal *outn = to_output_file_normal(out);
+
+ ret = ftruncate64(outn->fd, len);
+ if (ret < 0) {
+ return -errno;
+ }
+
+ return 0;
+}
+
static int file_write(struct output_file *out, void *data, int len)
{
int ret;
- ret = write(out->fd, data, len);
+ struct output_file_normal *outn = to_output_file_normal(out);
+
+ ret = write(outn->fd, data, len);
if (ret < 0) {
error_errno("write");
return -1;
@@ -119,22 +165,39 @@ static int file_write(struct output_file *out, void *data, int len)
static void file_close(struct output_file *out)
{
- if (out->close_fd) {
- close(out->fd);
- }
+ struct output_file_normal *outn = to_output_file_normal(out);
+
+ free(outn);
}
static struct output_file_ops file_ops = {
+ .open = file_open,
.skip = file_skip,
+ .pad = file_pad,
.write = file_write,
.close = file_close,
};
+static int gz_file_open(struct output_file *out, int fd)
+{
+ struct output_file_gz *outgz = to_output_file_gz(out);
+
+ outgz->gz_fd = gzdopen(fd, "wb9");
+ if (!outgz->gz_fd) {
+ error_errno("gzopen");
+ return -errno;
+ }
+
+ return 0;
+}
+
+
static int gz_file_skip(struct output_file *out, int64_t cnt)
{
off64_t ret;
+ struct output_file_gz *outgz = to_output_file_gz(out);
- ret = gzseek(out->gz_fd, cnt, SEEK_CUR);
+ ret = gzseek(outgz->gz_fd, cnt, SEEK_CUR);
if (ret < 0) {
error_errno("gzseek");
return -1;
@@ -142,10 +205,36 @@ static int gz_file_skip(struct output_file *out, int64_t cnt)
return 0;
}
+static int gz_file_pad(struct output_file *out, int64_t len)
+{
+ off64_t ret;
+ struct output_file_gz *outgz = to_output_file_gz(out);
+
+ ret = gztell(outgz->gz_fd);
+ if (ret < 0) {
+ return -1;
+ }
+
+ if (ret >= len) {
+ return 0;
+ }
+
+ ret = gzseek(outgz->gz_fd, len - 1, SEEK_SET);
+ if (ret < 0) {
+ return -1;
+ }
+
+ gzwrite(outgz->gz_fd, "", 1);
+
+ return 0;
+}
+
static int gz_file_write(struct output_file *out, void *data, int len)
{
int ret;
- ret = gzwrite(out->gz_fd, data, len);
+ struct output_file_gz *outgz = to_output_file_gz(out);
+
+ ret = gzwrite(outgz->gz_fd, data, len);
if (ret < 0) {
error_errno("gzwrite");
return -1;
@@ -159,11 +248,16 @@ static int gz_file_write(struct output_file *out, void *data, int len)
static void gz_file_close(struct output_file *out)
{
- gzclose(out->gz_fd);
+ struct output_file_gz *outgz = to_output_file_gz(out);
+
+ gzclose(outgz->gz_fd);
+ free(outgz);
}
static struct output_file_ops gz_file_ops = {
+ .open = gz_file_open,
.skip = gz_file_skip,
+ .pad = gz_file_pad,
.write = gz_file_write,
.close = gz_file_close,
};
@@ -371,21 +465,12 @@ static int write_normal_fill_chunk(struct output_file *out, unsigned int len,
static int write_normal_skip_chunk(struct output_file *out, int64_t len)
{
- int ret;
-
return out->ops->skip(out, len);
}
int write_normal_end_chunk(struct output_file *out)
{
- int ret;
-
- ret = ftruncate64(out->fd, out->len);
- if (ret < 0) {
- return -errno;
- }
-
- return 0;
+ return out->ops->pad(out, out->len);
}
static struct sparse_file_ops normal_file_ops = {
@@ -401,59 +486,39 @@ void close_output_file(struct output_file *out)
out->sparse_ops->write_end_chunk(out);
out->ops->close(out);
- free(out);
}
-struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len,
- int gz, int sparse, int chunks, int crc)
+static int output_file_init(struct output_file *out, int block_size,
+ int64_t len, bool sparse, int chunks, bool crc)
{
int ret;
- struct output_file *out = malloc(sizeof(struct output_file));
- if (!out) {
- error_errno("malloc struct out");
- return NULL;
- }
+
+ out->len = len;
+ out->block_size = block_size;
+ out->cur_out_ptr = 0ll;
+ out->chunk_cnt = 0;
+ out->crc32 = 0;
+ out->use_crc = crc;
+
out->zero_buf = calloc(block_size, 1);
if (!out->zero_buf) {
error_errno("malloc zero_buf");
- goto err_zero_buf;
+ return -ENOMEM;
}
out->fill_buf = calloc(block_size, 1);
if (!out->fill_buf) {
error_errno("malloc fill_buf");
+ ret = -ENOMEM;
goto err_fill_buf;
}
- if (gz) {
- out->ops = &gz_file_ops;
- out->gz_fd = gzdopen(fd, "wb9");
- if (!out->gz_fd) {
- error_errno("gzopen");
- goto err_gzopen;
- }
- } else {
- out->fd = fd;
- out->ops = &file_ops;
- }
-
if (sparse) {
out->sparse_ops = &sparse_file_ops;
} else {
out->sparse_ops = &normal_file_ops;
}
- out->close_fd = false;
- out->cur_out_ptr = 0ll;
- out->chunk_cnt = 0;
-
- /* Initialize the crc32 value */
- out->crc32 = 0;
- out->use_crc = crc;
-
- out->len = len;
- out->block_size = block_size;
-
if (sparse) {
sparse_header_t sparse_header = {
.magic = SPARSE_HEADER_MAGIC,
@@ -477,47 +542,62 @@ struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len,
}
}
- return out;
+ return 0;
err_write:
- if (gz) {
- gzclose(out->gz_fd);
- }
-err_gzopen:
free(out->fill_buf);
err_fill_buf:
free(out->zero_buf);
-err_zero_buf:
- free(out);
- return NULL;
+ return ret;
+}
+
+static struct output_file *output_file_new_gz(void)
+{
+ struct output_file_gz *outgz = calloc(1, sizeof(struct output_file_gz));
+ if (!outgz) {
+ error_errno("malloc struct outgz");
+ return NULL;
+ }
+
+ outgz->out.ops = &gz_file_ops;
+
+ return &outgz->out;
+}
+
+static struct output_file *output_file_new_normal(void)
+{
+ struct output_file_normal *outn = calloc(1, sizeof(struct output_file_normal));
+ if (!outn) {
+ error_errno("malloc struct outn");
+ return NULL;
+ }
+
+ outn->out.ops = &file_ops;
+
+ return &outn->out;
}
-struct output_file *open_output_file(const char *filename,
- unsigned int block_size, int64_t len,
+struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len,
int gz, int sparse, int chunks, int crc)
{
- int fd;
- struct output_file *file;
+ int ret;
+ struct output_file *out;
- if (strcmp(filename, "-")) {
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
- if (fd < 0) {
- error_errno("open");
- return NULL;
- }
+ if (gz) {
+ out = output_file_new_gz();
} else {
- fd = STDOUT_FILENO;
+ out = output_file_new_normal();
}
- file = open_output_fd(fd, block_size, len, gz, sparse, chunks, crc);
- if (!file) {
- close(fd);
+ out->ops->open(out, fd);
+
+ ret = output_file_init(out, block_size, len, sparse, chunks, crc);
+ if (ret < 0) {
+ free(out);
return NULL;
}
- file->close_fd = true; // we opened descriptor thus we responsible for closing it
-
- return file;
+ return out;
}
/* Write a contiguous region of data blocks from a memory buffer */
diff --git a/libsparse/output_file.h b/libsparse/output_file.h
index b86528b..24496f7 100644
--- a/libsparse/output_file.h
+++ b/libsparse/output_file.h
@@ -21,9 +21,6 @@
struct output_file;
-struct output_file *open_output_file(const char *filename,
- unsigned int block_size, int64_t len,
- int gz, int sparse, int chunks, int crc);
struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len,
int gz, int sparse, int chunks, int crc);
int write_data_chunk(struct output_file *out, unsigned int len, void *data);