summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/sqfs/data_writer.c98
1 files changed, 57 insertions, 41 deletions
diff --git a/lib/sqfs/data_writer.c b/lib/sqfs/data_writer.c
index 4324f06..301c944 100644
--- a/lib/sqfs/data_writer.c
+++ b/lib/sqfs/data_writer.c
@@ -22,6 +22,7 @@ struct data_writer_t {
size_t frag_offset;
size_t devblksz;
+ off_t start;
int block_idx;
@@ -126,7 +127,33 @@ int data_writer_flush_fragments(data_writer_t *data)
return 0;
}
-static int flush_data_block(data_writer_t *data, size_t size,
+static int deduplicate_data(data_writer_t *data, file_info_t *fi,
+ file_info_t *list)
+{
+ uint64_t ref = find_equal_blocks(fi, list, data->super->block_size);
+
+ if (ref > 0) {
+ data->super->bytes_used = fi->startblock;
+
+ fi->startblock = ref;
+ fi->flags |= FILE_FLAG_BLOCKS_ARE_DUPLICATE;
+
+ if (lseek(data->outfd, data->start, SEEK_SET) == (off_t)-1)
+ goto fail_seek;
+
+ if (ftruncate(data->outfd, data->start))
+ goto fail_truncate;
+ }
+ return 0;
+fail_seek:
+ perror("seeking on squashfs image after file deduplication");
+ return -1;
+fail_truncate:
+ perror("truncating squashfs image after file deduplication");
+ return -1;
+}
+
+static int flush_data_block(data_writer_t *data, size_t size, bool is_last,
file_info_t *fi, int flags, file_info_t *list)
{
uint32_t out, chksum;
@@ -137,7 +164,7 @@ static int flush_data_block(data_writer_t *data, size_t size,
fi->blocks[data->block_idx].chksum = 0;
fi->sparse += size;
data->block_idx++;
- return 0;
+ return is_last ? deduplicate_data(data, fi, list) : 0;
}
chksum = update_crc32(0, data->block, size);
@@ -145,6 +172,9 @@ static int flush_data_block(data_writer_t *data, size_t size,
if (size < data->super->block_size && !(flags & DW_DONT_FRAGMENT)) {
fi->flags |= FILE_FLAG_HAS_FRAGMENT;
+ if (deduplicate_data(data, fi, list))
+ return -1;
+
ref = fragment_by_chksum(fi, chksum, size, list,
data->super->block_size);
@@ -175,16 +205,18 @@ static int flush_data_block(data_writer_t *data, size_t size,
fi->blocks[data->block_idx].chksum = chksum;
fi->blocks[data->block_idx].size = out;
data->block_idx++;
+
+ if (is_last && deduplicate_data(data, fi, list) != 0)
+ return -1;
}
return 0;
}
-static int begin_file(data_writer_t *data, file_info_t *fi,
- int flags, off_t *start)
+static int begin_file(data_writer_t *data, file_info_t *fi, int flags)
{
- *start = lseek(data->outfd, 0, SEEK_CUR);
- if (*start == (off_t)-1)
+ data->start = lseek(data->outfd, 0, SEEK_CUR);
+ if (data->start == (off_t)-1)
goto fail_seek;
if ((flags & DW_ALLIGN_DEVBLK) && allign_file(data) != 0)
@@ -199,59 +231,41 @@ fail_seek:
return -1;
}
-static int end_file(data_writer_t *data, file_info_t *fi,
- off_t start, int flags, file_info_t *list)
+static int end_file(data_writer_t *data, int flags)
{
- uint64_t ref;
-
if ((flags & DW_ALLIGN_DEVBLK) && allign_file(data) != 0)
return -1;
- ref = find_equal_blocks(fi, list, data->super->block_size);
-
- if (ref > 0) {
- data->super->bytes_used = fi->startblock;
-
- fi->startblock = ref;
- fi->flags |= FILE_FLAG_BLOCKS_ARE_DUPLICATE;
-
- if (lseek(data->outfd, start, SEEK_SET) == (off_t)-1)
- goto fail_seek;
-
- if (ftruncate(data->outfd, start))
- goto fail_truncate;
- }
return 0;
-fail_seek:
- perror("seeking on squashfs image after file deduplication");
- return -1;
-fail_truncate:
- perror("truncating squashfs image after file deduplication");
- return -1;
}
int write_data_from_fd(data_writer_t *data, file_info_t *fi,
int infd, int flags, file_info_t *list)
{
uint64_t count;
+ bool is_last;
size_t diff;
- off_t start;
- if (begin_file(data, fi, flags, &start))
+ if (begin_file(data, fi, flags))
return -1;
for (count = fi->size; count != 0; count -= diff) {
- diff = count > (uint64_t)data->super->block_size ?
- data->super->block_size : count;
+ if (count > (uint64_t)data->super->block_size) {
+ diff = data->super->block_size;
+ is_last = false;
+ } else {
+ diff = count;
+ is_last = true;
+ }
if (read_data(fi->input_file, infd, data->block, diff))
return -1;
- if (flush_data_block(data, diff, fi, flags, list))
+ if (flush_data_block(data, diff, is_last, fi, flags, list))
return -1;
}
- return end_file(data, fi, start, flags, list);
+ return end_file(data, flags);
}
int write_data_from_fd_condensed(data_writer_t *data, file_info_t *fi,
@@ -261,9 +275,9 @@ int write_data_from_fd_condensed(data_writer_t *data, file_info_t *fi,
size_t start, count, diff;
sparse_map_t *m;
uint64_t offset;
- off_t location;
+ bool is_last;
- if (begin_file(data, fi, flags, &location))
+ if (begin_file(data, fi, flags))
return -1;
if (map != NULL) {
@@ -280,10 +294,12 @@ int write_data_from_fd_condensed(data_writer_t *data, file_info_t *fi,
}
for (offset = 0; offset < fi->size; offset += diff) {
- if (fi->size - offset >= (uint64_t)data->super->block_size) {
+ if (fi->size - offset > (uint64_t)data->super->block_size) {
diff = data->super->block_size;
+ is_last = false;
} else {
diff = fi->size - offset;
+ is_last = true;
}
memset(data->block, 0, diff);
@@ -309,11 +325,11 @@ int write_data_from_fd_condensed(data_writer_t *data, file_info_t *fi,
map = map->next;
}
- if (flush_data_block(data, diff, fi, flags, list))
+ if (flush_data_block(data, diff, is_last, fi, flags, list))
return -1;
}
- return end_file(data, fi, location, flags, list);
+ return end_file(data, flags);
fail_map_size:
fprintf(stderr, "%s: sparse file map spans beyond file size\n",
fi->input_file);