summaryrefslogtreecommitdiff
path: root/lib/sqfs/meta_writer.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqfs/meta_writer.c')
-rw-r--r--lib/sqfs/meta_writer.c122
1 files changed, 94 insertions, 28 deletions
diff --git a/lib/sqfs/meta_writer.c b/lib/sqfs/meta_writer.c
index 2dacaa0..ef869e7 100644
--- a/lib/sqfs/meta_writer.c
+++ b/lib/sqfs/meta_writer.c
@@ -8,6 +8,13 @@
#include <unistd.h>
#include <stdio.h>
+typedef struct meta_block_t {
+ struct meta_block_t *next;
+
+ /* possibly compressed data with 2 byte header */
+ uint8_t data[SQFS_META_BLOCK_SIZE + 2];
+} meta_block_t;
+
struct meta_writer_t {
/* A byte offset into the uncompressed data of the current block */
size_t offset;
@@ -22,13 +29,36 @@ struct meta_writer_t {
compressor_t *cmp;
/* The raw data chunk that data is appended to */
- uint8_t data[SQFS_META_BLOCK_SIZE + 2];
+ uint8_t data[SQFS_META_BLOCK_SIZE];
- /* Scratch buffer for compressing data */
- uint8_t scratch[SQFS_META_BLOCK_SIZE + 2];
+ bool keep_in_mem;
+ meta_block_t *list;
+ meta_block_t *list_end;
};
-meta_writer_t *meta_writer_create(int fd, compressor_t *cmp)
+static int write_block(int fd, meta_block_t *outblk)
+{
+ size_t count;
+ ssize_t ret;
+
+ count = le16toh(((uint16_t *)outblk->data)[0]) & 0x7FFF;
+
+ ret = write_retry(fd, outblk->data, count + 2);
+
+ if (ret < 0) {
+ perror("writing meta data block");
+ return -1;
+ }
+
+ if ((size_t)ret < count) {
+ fputs("meta data written to file was truncated\n", stderr);
+ return -1;
+ }
+
+ return 0;
+}
+
+meta_writer_t *meta_writer_create(int fd, compressor_t *cmp, bool keep_in_mem)
{
meta_writer_t *m = calloc(1, sizeof(*m));
@@ -39,53 +69,71 @@ meta_writer_t *meta_writer_create(int fd, compressor_t *cmp)
m->cmp = cmp;
m->outfd = fd;
+ m->keep_in_mem = keep_in_mem;
return m;
}
void meta_writer_destroy(meta_writer_t *m)
{
+ meta_block_t *blk;
+
+ while (m->list != NULL) {
+ blk = m->list;
+ m->list = blk->next;
+ free(blk);
+ }
+
free(m);
}
int meta_writer_flush(meta_writer_t *m)
{
- ssize_t ret, count;
- void *ptr;
+ meta_block_t *outblk;
+ size_t count;
+ ssize_t ret;
if (m->offset == 0)
return 0;
- ret = m->cmp->do_block(m->cmp, m->data + 2, m->offset,
- m->scratch + 2, sizeof(m->scratch) - 2);
- if (ret < 0)
+ outblk = calloc(1, sizeof(*outblk));
+ if (outblk == NULL) {
+ perror("generating meta data block");
+ return -1;
+ }
+
+ ret = m->cmp->do_block(m->cmp, m->data, m->offset,
+ outblk->data + 2, sizeof(outblk->data) - 2);
+ if (ret < 0) {
+ free(outblk);
return -1;
+ }
if (ret > 0) {
- ((uint16_t *)m->scratch)[0] = htole16(ret);
+ ((uint16_t *)outblk->data)[0] = htole16(ret);
count = ret + 2;
- ptr = m->scratch;
} else {
- ((uint16_t *)m->data)[0] = htole16(m->offset | 0x8000);
+ ((uint16_t *)outblk->data)[0] = htole16(m->offset | 0x8000);
+ memcpy(outblk->data + 2, m->data, m->offset);
count = m->offset + 2;
- ptr = m->data;
- }
-
- ret = write_retry(m->outfd, ptr, count);
-
- if (ret < 0) {
- perror("writing meta data");
- return -1;
}
- if (ret < count) {
- fputs("meta data written to file was truncated\n", stderr);
- return -1;
+ if (m->keep_in_mem) {
+ if (m->list == NULL) {
+ m->list = outblk;
+ } else {
+ m->list_end->next = outblk;
+ }
+ m->list_end = outblk;
+ ret = 0;
+ } else {
+ ret = write_block(m->outfd, outblk);
+ free(outblk);
}
memset(m->data, 0, sizeof(m->data));
m->offset = 0;
m->block_offset += count;
- return 0;
+ return ret;
}
int meta_writer_append(meta_writer_t *m, const void *data, size_t size)
@@ -93,24 +141,24 @@ int meta_writer_append(meta_writer_t *m, const void *data, size_t size)
size_t diff;
while (size != 0) {
- diff = sizeof(m->data) - 2 - m->offset;
+ diff = sizeof(m->data) - m->offset;
if (diff == 0) {
if (meta_writer_flush(m))
return -1;
- diff = sizeof(m->data) - 2;
+ diff = sizeof(m->data);
}
if (diff > size)
diff = size;
- memcpy(m->data + 2 + m->offset, data, diff);
+ memcpy(m->data + m->offset, data, diff);
m->offset += diff;
size -= diff;
data = (const char *)data + diff;
}
- if (m->offset == (sizeof(m->data) - 2))
+ if (m->offset == sizeof(m->data))
return meta_writer_flush(m);
return 0;
@@ -128,3 +176,21 @@ void meta_writer_reset(meta_writer_t *m)
m->block_offset = 0;
m->offset = 0;
}
+
+int meta_write_write_to_file(meta_writer_t *m)
+{
+ meta_block_t *blk;
+
+ while (m->list != NULL) {
+ blk = m->list;
+
+ if (write_block(m->outfd, blk))
+ return -1;
+
+ m->list = blk->next;
+ free(blk);
+ }
+
+ m->list_end = NULL;
+ return 0;
+}