summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Cross2012-05-20 15:28:05 -0500
committerColin Cross2012-07-10 00:09:36 -0500
commit28fa5bc347390480fe190294c6c385b6a9f0d68b (patch)
tree59189cf41baf263befeba392fc5bab814740eab1 /libsparse
parent2177c79bddc66e295599d87007d4cbec549e1cac (diff)
downloadplatform-system-core-28fa5bc347390480fe190294c6c385b6a9f0d68b.tar.gz
platform-system-core-28fa5bc347390480fe190294c6c385b6a9f0d68b.tar.xz
platform-system-core-28fa5bc347390480fe190294c6c385b6a9f0d68b.zip
system/core: move libsparse into system/core
This moves an exact copy of libsparse from system/extras/ext4_utils/libsparse to system/core/libsparse in preparation for linking tools in system/core against it. Change-Id: If664e4fcfd6612844ac745589beb1517e7f9fe58
Diffstat (limited to 'libsparse')
-rw-r--r--libsparse/Android.mk86
-rw-r--r--libsparse/backed_block.c179
-rw-r--r--libsparse/backed_block.h39
-rw-r--r--libsparse/img2simg.c327
-rw-r--r--libsparse/include/sparse/sparse.h134
-rw-r--r--libsparse/output_file.c613
-rw-r--r--libsparse/output_file.h36
-rw-r--r--libsparse/simg2img.c321
-rwxr-xr-xlibsparse/simg_dump.py169
-rw-r--r--libsparse/sparse.c154
-rw-r--r--libsparse/sparse_crc32.c111
-rw-r--r--libsparse/sparse_crc32.h18
-rw-r--r--libsparse/sparse_defs.h48
-rw-r--r--libsparse/sparse_file.h30
-rw-r--r--libsparse/sparse_format.h55
15 files changed, 2320 insertions, 0 deletions
diff --git a/libsparse/Android.mk b/libsparse/Android.mk
new file mode 100644
index 000000000..dbe4d1842
--- /dev/null
+++ b/libsparse/Android.mk
@@ -0,0 +1,86 @@
1# Copyright 2010 The Android Open Source Project
2
3LOCAL_PATH:= $(call my-dir)
4
5libsparse_src_files := \
6 backed_block.c \
7 output_file.c \
8 sparse.c \
9 sparse_crc32.c
10
11include $(CLEAR_VARS)
12
13LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
14LOCAL_SRC_FILES := $(libsparse_src_files)
15LOCAL_MODULE := libsparse
16LOCAL_MODULE_TAGS := optional
17LOCAL_STATIC_LIBRARIES := libz
18LOCAL_C_INCLUDES += $(LOCAL_PATH)/include external/zlib
19
20include $(BUILD_HOST_STATIC_LIBRARY)
21
22include $(CLEAR_VARS)
23
24LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
25LOCAL_SRC_FILES := $(libsparse_src_files)
26LOCAL_MODULE := libsparse
27LOCAL_MODULE_TAGS := optional
28LOCAL_C_INCLUDES += $(LOCAL_PATH)/include external/zlib
29LOCAL_SHARED_LIBRARIES := libz
30
31include $(BUILD_SHARED_LIBRARY)
32
33include $(CLEAR_VARS)
34
35LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
36LOCAL_SRC_FILES := $(libsparse_src_files)
37LOCAL_MODULE := libsparse
38LOCAL_MODULE_TAGS := optional
39LOCAL_C_INCLUDES += $(LOCAL_PATH)/include external/zlib
40LOCAL_STATIC_LIBRARIES := libz
41
42include $(BUILD_STATIC_LIBRARY)
43
44include $(CLEAR_VARS)
45
46LOCAL_SRC_FILES := simg2img.c \
47 sparse_crc32.c
48LOCAL_MODULE := simg2img
49LOCAL_MODULE_TAGS := debug
50
51include $(BUILD_HOST_EXECUTABLE)
52
53include $(CLEAR_VARS)
54
55LOCAL_SRC_FILES := simg2img.c \
56 sparse_crc32.c
57LOCAL_MODULE := simg2img
58LOCAL_MODULE_TAGS := optional
59
60include $(BUILD_EXECUTABLE)
61
62include $(CLEAR_VARS)
63
64LOCAL_SRC_FILES := img2simg.c
65LOCAL_MODULE := img2simg
66LOCAL_MODULE_TAGS := debug
67
68include $(BUILD_HOST_EXECUTABLE)
69
70include $(CLEAR_VARS)
71
72LOCAL_SRC_FILES := img2simg.c
73LOCAL_MODULE := img2simg
74LOCAL_MODULE_TAGS := optional
75
76include $(BUILD_EXECUTABLE)
77
78include $(CLEAR_VARS)
79
80LOCAL_MODULE := simg_dump.py
81LOCAL_MODULE_TAGS := debug
82LOCAL_SRC_FILES := simg_dump.py
83LOCAL_MODULE_CLASS := EXECUTABLES
84LOCAL_IS_HOST_MODULE := true
85
86include $(BUILD_PREBUILT)
diff --git a/libsparse/backed_block.c b/libsparse/backed_block.c
new file mode 100644
index 000000000..254813809
--- /dev/null
+++ b/libsparse/backed_block.c
@@ -0,0 +1,179 @@
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18#include <string.h>
19
20#include "backed_block.h"
21#include "sparse_defs.h"
22
23struct data_block {
24 u32 block;
25 u32 len;
26 void *data;
27 const char *filename;
28 int64_t offset;
29 struct data_block *next;
30 u32 fill_val;
31 u8 fill;
32 u8 pad1;
33 u16 pad2;
34};
35
36static struct data_block *data_blocks = NULL;
37static struct data_block *last_used = NULL;
38
39static void queue_db(struct data_block *new_db)
40{
41 struct data_block *db;
42
43 if (data_blocks == NULL) {
44 data_blocks = new_db;
45 return;
46 }
47
48 if (data_blocks->block > new_db->block) {
49 new_db->next = data_blocks;
50 data_blocks = new_db;
51 return;
52 }
53
54 /* Optimization: blocks are mostly queued in sequence, so save the
55 pointer to the last db that was added, and start searching from
56 there if the next block number is higher */
57 if (last_used && new_db->block > last_used->block)
58 db = last_used;
59 else
60 db = data_blocks;
61 last_used = new_db;
62
63 for (; db->next && db->next->block < new_db->block; db = db->next)
64 ;
65
66 if (db->next == NULL) {
67 db->next = new_db;
68 } else {
69 new_db->next = db->next;
70 db->next = new_db;
71 }
72}
73
74/* Queues a fill block of memory to be written to the specified data blocks */
75void queue_fill_block(unsigned int fill_val, unsigned int len, unsigned int block)
76{
77 struct data_block *db = malloc(sizeof(struct data_block));
78 if (db == NULL) {
79 error_errno("malloc");
80 return;
81 }
82
83 db->block = block;
84 db->len = len;
85 db->fill = 1;
86 db->fill_val = fill_val;
87 db->data = NULL;
88 db->filename = NULL;
89 db->next = NULL;
90
91 queue_db(db);
92}
93
94/* Queues a block of memory to be written to the specified data blocks */
95void queue_data_block(void *data, unsigned int len, unsigned int block)
96{
97 struct data_block *db = malloc(sizeof(struct data_block));
98 if (db == NULL) {
99 error_errno("malloc");
100 return;
101 }
102
103 db->block = block;
104 db->len = len;
105 db->data = data;
106 db->filename = NULL;
107 db->fill = 0;
108 db->next = NULL;
109
110 queue_db(db);
111}
112
113/* Queues a chunk of a file on disk to be written to the specified data blocks */
114void queue_data_file(const char *filename, int64_t offset, unsigned int len,
115 unsigned int block)
116{
117 struct data_block *db = malloc(sizeof(struct data_block));
118 if (db == NULL) {
119 error_errno("malloc");
120 return;
121 }
122
123 db->block = block;
124 db->len = len;
125 db->filename = strdup(filename);
126 db->offset = offset;
127 db->data = NULL;
128 db->fill = 0;
129 db->next = NULL;
130
131 queue_db(db);
132}
133
134/* Iterates over the queued data blocks, calling data_func for each contiguous
135 data block, and file_func for each contiguous file block */
136void for_each_data_block(data_block_callback_t data_func,
137 data_block_file_callback_t file_func,
138 data_block_fill_callback_t fill_func, void *priv, unsigned int block_size)
139{
140 struct data_block *db;
141 u32 last_block = 0;
142
143 for (db = data_blocks; db; db = db->next) {
144 if (db->block < last_block)
145 error("data blocks out of order: %u < %u", db->block, last_block);
146 last_block = db->block + DIV_ROUND_UP(db->len, block_size) - 1;
147
148 if (db->filename)
149 file_func(priv, (u64)db->block * block_size, db->filename, db->offset, db->len);
150 else if (db->fill)
151 fill_func(priv, (u64)db->block * block_size, db->fill_val, db->len);
152 else
153 data_func(priv, (u64)db->block * block_size, db->data, db->len);
154 }
155}
156
157/* Frees the memory used by the linked list of data blocks */
158void free_data_blocks()
159{
160 if (!data_blocks) return;
161 struct data_block *db = data_blocks;
162 while (db) {
163 struct data_block *next = db->next;
164 free((void*)db->filename);
165
166 // There used to be a free() of db->data here, but it
167 // made the function crash since queue_data_block() is
168 // sometimes passed pointers it can't take ownership of
169 // (like a pointer into the middle of an allocated
170 // block). It's not clear what the queue_data_block
171 // contract is supposed to be, but we'd rather leak
172 // memory than crash.
173
174 free(db);
175 db = next;
176 }
177 data_blocks = NULL;
178 last_used = NULL;
179}
diff --git a/libsparse/backed_block.h b/libsparse/backed_block.h
new file mode 100644
index 000000000..7b7c90aad
--- /dev/null
+++ b/libsparse/backed_block.h
@@ -0,0 +1,39 @@
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _BACKED_BLOCK_H_
18#define _BACKED_BLOCK_H_
19
20#include <sparse/sparse.h>
21
22typedef void (*data_block_callback_t)(void *priv, int64_t off, void *data, int len);
23typedef void (*data_block_fill_callback_t)(void *priv, int64_t off, unsigned int fill_val, int len);
24typedef void (*data_block_file_callback_t)(void *priv, int64_t off,
25 const char *file, int64_t offset,
26 int len);
27
28void for_each_data_block(data_block_callback_t data_func,
29 data_block_file_callback_t file_func,
30 data_block_fill_callback_t fill_func, void *priv, unsigned int);
31
32void queue_data_block(void *data, unsigned int len, unsigned int block);
33void queue_fill_block(unsigned int fill_val, unsigned int len, unsigned int block);
34void queue_data_file(const char *filename, int64_t offset, unsigned int len,
35 unsigned int block);
36
37void free_data_blocks();
38
39#endif
diff --git a/libsparse/img2simg.c b/libsparse/img2simg.c
new file mode 100644
index 000000000..a1594df63
--- /dev/null
+++ b/libsparse/img2simg.c
@@ -0,0 +1,327 @@
1/*
2 * Copyright (C) 2010-2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define DEFAULT_BLOCK_SIZE "4K"
18#define DEFAULT_CHUNK_SIZE "64M"
19#define DEFAULT_SUFFIX "%03d"
20
21#include "sparse_format.h"
22#if 0 /* endian.h is not on all platforms */
23# include <endian.h>
24#else
25 /* For now, just assume we're going to run on little-endian. */
26# define my_htole32(h) (h)
27# define my_htole16(h) (h)
28#endif
29#include <errno.h>
30#include <fcntl.h>
31#include <limits.h>
32#include <stdarg.h>
33#include <stddef.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <unistd.h>
38#include <sys/stat.h>
39#include <sys/types.h>
40
41#define COPY_BUF_SIZE (1024*1024)
42static char *copy_buf;
43
44static const char *progname(const char *argv0)
45{
46 const char *prog_name;
47 if ((prog_name = strrchr(argv0, '/')))
48 return(prog_name + 1); /* Advance beyond '/'. */
49 return(argv0); /* No '/' in argv0, use it as is. */
50}
51
52static void error_exit(const char *fmt, ...)
53{
54 va_list ap;
55 va_start(ap, fmt);
56 vfprintf(stderr, fmt, ap);
57 fputc('\n', stderr);
58 va_end(ap);
59
60 exit(EXIT_FAILURE);
61}
62
63static void usage(const char *argv0, const char *error_fmt, ...)
64{
65 fprintf(stderr,
66 "Usage: %s [OPTIONS] <raw_image_file>\n",
67 progname(argv0));
68 fprintf(stderr, "The <raw_image_file> will be split into as many sparse\n");
69 fprintf(stderr, "files as needed. Each sparse file will contain a single\n");
70 fprintf(stderr, "DONT CARE chunk to offset to the correct block and then\n");
71 fprintf(stderr, "a single RAW chunk containing a portion of the data from\n");
72 fprintf(stderr, "the raw image file. The sparse files will be named by\n");
73 fprintf(stderr, "appending a number to the name of the raw image file.\n");
74 fprintf(stderr, "\n");
75 fprintf(stderr, "OPTIONS (Defaults are enclosed by square brackets):\n");
76 fprintf(stderr, " -s SUFFIX Format appended number with SUFFIX [%s]\n",
77 DEFAULT_SUFFIX);
78 fprintf(stderr, " -B SIZE Use a block size of SIZE [%s]\n",
79 DEFAULT_BLOCK_SIZE);
80 fprintf(stderr, " -C SIZE Use a chunk size of SIZE [%s]\n",
81 DEFAULT_CHUNK_SIZE);
82 fprintf(stderr, "SIZE is a decimal integer that may optionally be\n");
83 fprintf(stderr, "followed by a suffix that specifies a multiplier for\n");
84 fprintf(stderr, "the integer:\n");
85 fprintf(stderr, " c 1 byte (the default when omitted)\n");
86 fprintf(stderr, " w 2 bytes\n");
87 fprintf(stderr, " b 512 bytes\n");
88 fprintf(stderr, " kB 1000 bytes\n");
89 fprintf(stderr, " K 1024 bytes\n");
90 fprintf(stderr, " MB 1000*1000 bytes\n");
91 fprintf(stderr, " M 1024*1024 bytes\n");
92 fprintf(stderr, " GB 1000*1000*1000 bytes\n");
93 fprintf(stderr, " G 1024*1024*1024 bytes\n");
94
95 if (error_fmt && *error_fmt)
96 {
97 fprintf(stderr, "\n");
98 va_list ap;
99 va_start(ap, error_fmt);
100 vfprintf(stderr, error_fmt, ap);
101 va_end(ap);
102 fprintf(stderr, "\n");
103 }
104
105 exit(EXIT_FAILURE);
106}
107
108static void cpy_file(int out_fd, char *out_path, int in_fd, char *in_path,
109 size_t len)
110{
111 ssize_t s, cpy_len = COPY_BUF_SIZE;
112
113 while (len) {
114 if (len < COPY_BUF_SIZE)
115 cpy_len = len;
116
117 s = read(in_fd, copy_buf, cpy_len);
118 if (s < 0)
119 error_exit("\"%s\": %s", in_path, strerror(errno));
120 if (!s)
121 error_exit("\"%s\": Unexpected EOF", in_path);
122
123 cpy_len = s;
124
125 s = write(out_fd, copy_buf, cpy_len);
126 if (s < 0)
127 error_exit("\"%s\": %s", out_path, strerror(errno));
128 if (s != cpy_len)
129 error_exit("\"%s\": Short data write (%lu)", out_path,
130 (unsigned long)s);
131
132 len -= cpy_len;
133 }
134}
135
136static int parse_size(const char *size_str, size_t *size)
137{
138 static const size_t MAX_SIZE_T = ~(size_t)0;
139 size_t mult;
140 unsigned long long int value;
141 const char *end;
142 errno = 0;
143 value = strtoull(size_str, (char **)&end, 10);
144 if (errno != 0 || end == size_str || value > MAX_SIZE_T)
145 return -1;
146 if (*end == '\0') {
147 *size = value;
148 return 0;
149 }
150 if (!strcmp(end, "c"))
151 mult = 1;
152 else if (!strcmp(end, "w"))
153 mult = 2;
154 else if (!strcmp(end, "b"))
155 mult = 512;
156 else if (!strcmp(end, "kB"))
157 mult = 1000;
158 else if (!strcmp(end, "K"))
159 mult = 1024;
160 else if (!strcmp(end, "MB"))
161 mult = (size_t)1000*1000;
162 else if (!strcmp(end, "M"))
163 mult = (size_t)1024*1024;
164 else if (!strcmp(end, "GB"))
165 mult = (size_t)1000*1000*1000;
166 else if (!strcmp(end, "G"))
167 mult = (size_t)1024*1024*1024;
168 else
169 return -1;
170
171 if (value > MAX_SIZE_T / mult)
172 return -1;
173 *size = value * mult;
174 return 0;
175}
176
177int main(int argc, char *argv[])
178{
179 char *suffix = DEFAULT_SUFFIX;
180 char *block_size_str = DEFAULT_BLOCK_SIZE;
181 char *chunk_size_str = DEFAULT_CHUNK_SIZE;
182 size_t block_size, chunk_size, blocks_per_chunk, to_write;
183 char *in_path, *out_path, *out_fmt;
184 int in_fd, out_fd;
185 struct stat in_st;
186 off_t left_to_write;
187 struct {
188 sparse_header_t sparse_hdr;
189 chunk_header_t dont_care_hdr;
190 chunk_header_t raw_hdr;
191 } file_hdr;
192 unsigned int file_count;
193 ssize_t s;
194 int i;
195
196 /* Parse the command line. */
197 while ((i = getopt(argc, argv, "s:B:C:")) != -1)
198 {
199 switch (i) {
200 case 's':
201 suffix = optarg;
202 break;
203 case 'B':
204 block_size_str = optarg;
205 break;
206 case 'C':
207 chunk_size_str = optarg;
208 break;
209 default:
210 usage(argv[0], NULL);
211 break;
212 }
213 }
214
215 if (parse_size(block_size_str, &block_size))
216 usage(argv[0], "Can not parse \"%s\" as a block size.",
217 block_size_str);
218 if (block_size % 4096)
219 usage(argv[0], "Block size is not a multiple of 4096.");
220
221 if (parse_size(chunk_size_str, &chunk_size))
222 usage(argv[0], "Can not parse \"%s\" as a chunk size.",
223 chunk_size_str);
224 if (chunk_size % block_size)
225 usage(argv[0], "Chunk size is not a multiple of the block size.");
226 blocks_per_chunk = chunk_size / block_size;
227
228 if ((argc - optind) != 1)
229 usage(argv[0], "Missing or extra arguments.");
230 in_path = argv[optind];
231
232 /* Open the input file and validate it. */
233 if ((in_fd = open(in_path, O_RDONLY)) < 0)
234 error_exit("open \"%s\": %s", in_path, strerror(errno));
235 if (fstat(in_fd, &in_st))
236 error_exit("fstat \"%s\": %s", in_path, strerror(errno));
237 left_to_write = in_st.st_size;
238 if (left_to_write % block_size)
239 error_exit(
240 "\"%s\" size (%llu) is not a multiple of the block size (%llu).\n",
241 in_path,
242 (unsigned long long)left_to_write, (unsigned long long)block_size);
243
244 /* Get a buffer for copying the chunks. */
245 if ((copy_buf = malloc(COPY_BUF_SIZE)) == 0)
246 error_exit("malloc copy buffer: %s", strerror(errno));
247
248 /* Get a buffer for a sprintf format to form output paths. */
249 if ((out_fmt = malloc(sizeof("%s") + strlen(suffix))) == 0)
250 error_exit("malloc format buffer: %s", strerror(errno));
251 out_fmt[0] = '%';
252 out_fmt[1] = 's';
253 strcpy(out_fmt + 2, suffix);
254
255 /* Get a buffer for an output path. */
256 i = snprintf(copy_buf, COPY_BUF_SIZE, out_fmt, in_path, UINT_MAX);
257 if (i >= COPY_BUF_SIZE)
258 error_exit("Ridulously long suffix: %s", suffix);
259 if ((out_path = malloc(i + 1)) == 0)
260 error_exit("malloc output path buffer: %s", strerror(errno));
261
262 /*
263 * Each file gets a sparse_header, a Don't Care chunk to offset to
264 * where the data belongs and then a Raw chunk with the actual data.
265 */
266 memset((void *)&file_hdr.sparse_hdr, 0, sizeof(file_hdr.sparse_hdr));
267 file_hdr.sparse_hdr.magic = my_htole32(SPARSE_HEADER_MAGIC);
268 file_hdr.sparse_hdr.major_version = my_htole16(1);
269 file_hdr.sparse_hdr.minor_version = my_htole16(0);
270 file_hdr.sparse_hdr.file_hdr_sz = my_htole16(sizeof(sparse_header_t));
271 file_hdr.sparse_hdr.chunk_hdr_sz = my_htole16(sizeof(chunk_header_t));
272 file_hdr.sparse_hdr.blk_sz = my_htole32(block_size);
273 /* The total_blks will be set in the file loop below. */
274 file_hdr.sparse_hdr.total_chunks = my_htole32(2);
275 file_hdr.sparse_hdr.image_checksum = my_htole32(0); /* Typically unused. */
276
277 memset((void *)&file_hdr.dont_care_hdr, 0, sizeof(file_hdr.dont_care_hdr));
278 file_hdr.dont_care_hdr.chunk_type = my_htole16(CHUNK_TYPE_DONT_CARE);
279 /* The Don't Care's chunk_sz will be set in the file loop below. */
280 file_hdr.dont_care_hdr.total_sz = my_htole32(sizeof(chunk_header_t));
281
282 memset((void *)&file_hdr.raw_hdr, 0, sizeof(file_hdr.raw_hdr));
283 file_hdr.raw_hdr.chunk_type = my_htole16(CHUNK_TYPE_RAW);
284 file_hdr.raw_hdr.chunk_sz = my_htole32(blocks_per_chunk);
285 file_hdr.raw_hdr.total_sz = my_htole32(chunk_size + sizeof(chunk_header_t));
286
287 /* Loop through writing chunk_size to each of the output files. */
288 to_write = chunk_size;
289 for (file_count = 1; left_to_write ; file_count++) {
290 /* Fix up the headers on the last block. */
291 if (left_to_write < (off_t)chunk_size) {
292 to_write = left_to_write;
293 file_hdr.raw_hdr.chunk_sz = my_htole32(left_to_write / block_size);
294 file_hdr.raw_hdr.total_sz = my_htole32(left_to_write
295 + sizeof(chunk_header_t));
296 }
297
298 /* Form the pathname for this output file and open it. */
299 sprintf(out_path, out_fmt, in_path, file_count);
300 if ((out_fd = creat(out_path, 0666)) < 0)
301 error_exit("\"%s\": %s", out_path, strerror(errno));
302
303 /* Update and write the headers to this output file. */
304 s = (file_count-1) * blocks_per_chunk;
305 file_hdr.dont_care_hdr.chunk_sz = my_htole32(s);
306 file_hdr.sparse_hdr.total_blks = my_htole32(s
307 + (to_write / block_size));
308 s = write(out_fd, (void *)&file_hdr, sizeof(file_hdr));
309 if (s < 0)
310 error_exit("\"%s\": %s", out_path, strerror(errno));
311 if (s != sizeof(file_hdr))
312 error_exit("\"%s\": Short write (%lu)", out_path, (unsigned long)s);
313
314 /* Copy this chunk from the input file to the output file. */
315 cpy_file(out_fd, out_path, in_fd, in_path, to_write);
316
317 /* Close this output file and update the amount left to write. */
318 if (close(out_fd))
319 error_exit("close \"%s\": %s", out_path, strerror(errno));
320 left_to_write -= to_write;
321 }
322
323 if (close(in_fd))
324 error_exit("close \"%s\": %s", in_path, strerror(errno));
325
326 exit(EXIT_SUCCESS);
327}
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
new file mode 100644
index 000000000..db0688471
--- /dev/null
+++ b/libsparse/include/sparse/sparse.h
@@ -0,0 +1,134 @@
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _LIBSPARSE_SPARSE_H_
18#define _LIBSPARSE_SPARSE_H_
19
20#include <stdbool.h>
21#include <stdint.h>
22
23struct sparse_file;
24
25/**
26 * sparse_file_new - create a new sparse file cookie
27 *
28 * @block_size - minimum size of a chunk
29 * @len - size of the expanded sparse file.
30 *
31 * Creates a new sparse_file cookie that can be used to associate data
32 * blocks. Can later be written to a file with a variety of options.
33 * block_size specifies the minimum size of a chunk in the file. The maximum
34 * size of the file is 2**32 * block_size (16TB for 4k block size).
35 *
36 * Returns the sparse file cookie, or NULL on error.
37 */
38struct sparse_file *sparse_file_new(unsigned int block_size, int64_t len);
39
40/**
41 * sparse_file_destroy - destroy a sparse file cookie
42 *
43 * @s - sparse file cookie
44 *
45 * Destroys a sparse file cookie. After destroy, all memory passed in to
46 * sparse_file_add_data can be freed by the caller
47 */
48void sparse_file_destroy(struct sparse_file *s);
49
50/**
51 * sparse_file_add_data - associate a data chunk with a sparse file
52 *
53 * @s - sparse file cookie
54 * @data - pointer to data block
55 * @len - length of the data block
56 * @block - offset in blocks into the sparse file to place the data chunk
57 *
58 * Associates a data chunk with a sparse file cookie. The region
59 * [block * block_size : block * block_size + len) must not already be used in
60 * the sparse file. If len is not a multiple of the block size the data
61 * will be padded with zeros.
62 *
63 * The data pointer must remain valid until the sparse file is closed or the
64 * data block is removed from the sparse file.
65 *
66 * Returns 0 on success, negative errno on error.
67 */
68int sparse_file_add_data(struct sparse_file *s,
69 void *data, unsigned int len, unsigned int block);
70
71/**
72 * sparse_file_add_fill - associate a fill chunk with a sparse file
73 *
74 * @s - sparse file cookie
75 * @fill_val - 32 bit fill data
76 * @len - length of the fill block
77 * @block - offset in blocks into the sparse file to place the fill chunk
78 *
79 * Associates a chunk filled with fill_val with a sparse file cookie.
80 * The region [block * block_size : block * block_size + len) must not already
81 * be used in the sparse file. If len is not a multiple of the block size the
82 * data will be padded with zeros.
83 *
84 * Returns 0 on success, negative errno on error.
85 */
86int sparse_file_add_fill(struct sparse_file *s,
87 uint32_t fill_val, unsigned int len, unsigned int block);
88
89/**
90 * sparse_file_add_file - associate a chunk of a file with a sparse file
91 *
92 * @s - sparse file cookie
93 * @filename - filename of the file to be copied
94 * @file_offset - offset into the copied file
95 * @len - length of the copied block
96 * @block - offset in blocks into the sparse file to place the file chunk
97 *
98 * Associates a chunk of an existing file with a sparse file cookie.
99 * The region [block * block_size : block * block_size + len) must not already
100 * be used in the sparse file. If len is not a multiple of the block size the
101 * data will be padded with zeros.
102 *
103 * Allows adding large amounts of data to a sparse file without needing to keep
104 * it all mapped. File size is limited by available virtual address space,
105 * exceptionally large files may need to be added in multiple chunks.
106 *
107 * Returns 0 on success, negative errno on error.
108 */
109int sparse_file_add_file(struct sparse_file *s,
110 const char *filename, int64_t file_offset, unsigned int len,
111 unsigned int block);
112
113/**
114 * sparse_file_write - write a sparse file to a file
115 *
116 * @s - sparse file cookie
117 * @fd - file descriptor to write to
118 * @gz - write a gzipped file
119 * @sparse - write in the Android sparse file format
120 * @crc - append a crc chunk
121 *
122 * Writes a sparse file to a file. If gz is true, the data will be passed
123 * through zlib. If sparse is true, the file will be written in the Android
124 * sparse file format. If sparse is false, the file will be written by seeking
125 * over unused chunks, producing a smaller file if the filesystem supports
126 * sparse files. If crc is true, the crc of the expanded data will be
127 * calculated and appended in a crc chunk.
128 *
129 * Returns 0 on success, negative errno on error.
130 */
131int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse,
132 bool crc);
133
134#endif
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
new file mode 100644
index 000000000..2c4b5573e
--- /dev/null
+++ b/libsparse/output_file.c
@@ -0,0 +1,613 @@
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define _FILE_OFFSET_BITS 64
18#define _LARGEFILE64_SOURCE 1
19
20#include <fcntl.h>
21#include <stdbool.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <unistd.h>
27#include <zlib.h>
28
29#include "output_file.h"
30#include "sparse_format.h"
31#include "sparse_crc32.h"
32
33#ifndef USE_MINGW
34#include <sys/mman.h>
35#define O_BINARY 0
36#endif
37
38#if defined(__APPLE__) && defined(__MACH__)
39#define lseek64 lseek
40#define ftruncate64 ftruncate
41#define mmap64 mmap
42#define off64_t off_t
43#endif
44
45#ifdef __BIONIC__
46extern void* __mmap2(void *, size_t, int, int, int, off_t);
47static inline void *mmap64(void *addr, size_t length, int prot, int flags,
48 int fd, off64_t offset)
49{
50 return __mmap2(addr, length, prot, flags, fd, offset >> 12);
51}
52#endif
53
54#define SPARSE_HEADER_MAJOR_VER 1
55#define SPARSE_HEADER_MINOR_VER 0
56#define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
57#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
58
59struct output_file_ops {
60 int (*seek)(struct output_file *, int64_t);
61 int (*write)(struct output_file *, u8 *, int);
62 void (*close)(struct output_file *);
63};
64
65struct output_file {
66 int fd;
67 gzFile gz_fd;
68 bool close_fd;
69 int sparse;
70 int64_t cur_out_ptr;
71 u32 chunk_cnt;
72 u32 crc32;
73 struct output_file_ops *ops;
74 int use_crc;
75 unsigned int block_size;
76 int64_t len;
77};
78
79static int file_seek(struct output_file *out, int64_t off)
80{
81 off64_t ret;
82
83 ret = lseek64(out->fd, off, SEEK_SET);
84 if (ret < 0) {
85 error_errno("lseek64");
86 return -1;
87 }
88 return 0;
89}
90
91static int file_write(struct output_file *out, u8 *data, int len)
92{
93 int ret;
94 ret = write(out->fd, data, len);
95 if (ret < 0) {
96 error_errno("write");
97 return -1;
98 } else if (ret < len) {
99 error("incomplete write");
100 return -1;
101 }
102
103 return 0;
104}
105
106static void file_close(struct output_file *out)
107{
108 if (out->close_fd) {
109 close(out->fd);
110 }
111}
112
113
114static struct output_file_ops file_ops = {
115 .seek = file_seek,
116 .write = file_write,
117 .close = file_close,
118};
119
120static int gz_file_seek(struct output_file *out, int64_t off)
121{
122 off64_t ret;
123
124 ret = gzseek(out->gz_fd, off, SEEK_SET);
125 if (ret < 0) {
126 error_errno("gzseek");
127 return -1;
128 }
129 return 0;
130}
131
132static int gz_file_write(struct output_file *out, u8 *data, int len)
133{
134 int ret;
135 ret = gzwrite(out->gz_fd, data, len);
136 if (ret < 0) {
137 error_errno("gzwrite");
138 return -1;
139 } else if (ret < len) {
140 error("incomplete gzwrite");
141 return -1;
142 }
143
144 return 0;
145}
146
147static void gz_file_close(struct output_file *out)
148{
149 gzclose(out->gz_fd);
150}
151
152static struct output_file_ops gz_file_ops = {
153 .seek = gz_file_seek,
154 .write = gz_file_write,
155 .close = gz_file_close,
156};
157
158static sparse_header_t sparse_header = {
159 .magic = SPARSE_HEADER_MAGIC,
160 .major_version = SPARSE_HEADER_MAJOR_VER,
161 .minor_version = SPARSE_HEADER_MINOR_VER,
162 .file_hdr_sz = SPARSE_HEADER_LEN,
163 .chunk_hdr_sz = CHUNK_HEADER_LEN,
164 .blk_sz = 0,
165 .total_blks = 0,
166 .total_chunks = 0,
167 .image_checksum = 0
168};
169
170static u8 *zero_buf;
171
172static int emit_skip_chunk(struct output_file *out, u64 skip_len)
173{
174 chunk_header_t chunk_header;
175 int ret, chunk;
176
177 //DBG printf("skip chunk: 0x%llx bytes\n", skip_len);
178
179 if (skip_len % out->block_size) {
180 error("don't care size %llu is not a multiple of the block size %u",
181 skip_len, out->block_size);
182 return -1;
183 }
184
185 /* We are skipping data, so emit a don't care chunk. */
186 chunk_header.chunk_type = CHUNK_TYPE_DONT_CARE;
187 chunk_header.reserved1 = 0;
188 chunk_header.chunk_sz = skip_len / out->block_size;
189 chunk_header.total_sz = CHUNK_HEADER_LEN;
190 ret = out->ops->write(out, (u8 *)&chunk_header, sizeof(chunk_header));
191 if (ret < 0)
192 return -1;
193
194 out->cur_out_ptr += skip_len;
195 out->chunk_cnt++;
196
197 return 0;
198}
199
200static int write_chunk_fill(struct output_file *out, int64_t off, u32 fill_val, int len)
201{
202 chunk_header_t chunk_header;
203 int rnd_up_len, zero_len, count;
204 int ret;
205 unsigned int i;
206 u32 fill_buf[4096/sizeof(u32)]; /* Maximum size of a block */
207
208 /* We can assume that all the chunks to be written are in
209 * ascending order, block-size aligned, and non-overlapping.
210 * So, if the offset is less than the current output pointer,
211 * throw an error, and if there is a gap, emit a "don't care"
212 * chunk. The first write (of the super block) may not be
213 * blocksize aligned, so we need to deal with that too.
214 */
215 //DBG printf("write chunk: offset 0x%llx, length 0x%x bytes\n", off, len);
216
217 if (off < out->cur_out_ptr) {
218 error("offset %llu is less than the current output offset %llu",
219 off, out->cur_out_ptr);
220 return -1;
221 }
222
223 if (off > out->cur_out_ptr) {
224 emit_skip_chunk(out, off - out->cur_out_ptr);
225 }
226
227 if (off % out->block_size) {
228 error("write chunk offset %llu is not a multiple of the block size %u",
229 off, out->block_size);
230 return -1;
231 }
232
233 if (off != out->cur_out_ptr) {
234 error("internal error, offset accounting screwy in write_chunk_raw()");
235 return -1;
236 }
237
238 /* Round up the file length to a multiple of the block size */
239 rnd_up_len = (len + (out->block_size - 1)) & (~(out->block_size -1));
240
241 /* Finally we can safely emit a chunk of data */
242 chunk_header.chunk_type = CHUNK_TYPE_FILL;
243 chunk_header.reserved1 = 0;
244 chunk_header.chunk_sz = rnd_up_len / out->block_size;
245 chunk_header.total_sz = CHUNK_HEADER_LEN + sizeof(fill_val);
246 ret = out->ops->write(out, (u8 *)&chunk_header, sizeof(chunk_header));
247
248 if (ret < 0)
249 return -1;
250 ret = out->ops->write(out, (u8 *)&fill_val, sizeof(fill_val));
251 if (ret < 0)
252 return -1;
253
254 if (out->use_crc) {
255 /* Initialize fill_buf with the fill_val */
256 for (i = 0; i < (out->block_size / sizeof(u32)); i++) {
257 fill_buf[i] = fill_val;
258 }
259
260 count = chunk_header.chunk_sz;
261 while (count) {
262 out->crc32 = sparse_crc32(out->crc32, fill_buf, out->block_size);
263 count--;
264 }
265 }
266
267 out->cur_out_ptr += rnd_up_len;
268 out->chunk_cnt++;
269
270 return 0;
271}
272
273static int write_chunk_raw(struct output_file *out, int64_t off, u8 *data, int len)
274{
275 chunk_header_t chunk_header;
276 int rnd_up_len, zero_len;
277 int ret;
278
279 /* We can assume that all the chunks to be written are in
280 * ascending order, block-size aligned, and non-overlapping.
281 * So, if the offset is less than the current output pointer,
282 * throw an error, and if there is a gap, emit a "don't care"
283 * chunk. The first write (of the super block) may not be
284 * blocksize aligned, so we need to deal with that too.
285 */
286 //DBG printf("write chunk: offset 0x%llx, length 0x%x bytes\n", off, len);
287
288 if (off < out->cur_out_ptr) {
289 error("offset %llu is less than the current output offset %llu",
290 off, out->cur_out_ptr);
291 return -1;
292 }
293
294 if (off > out->cur_out_ptr) {
295 emit_skip_chunk(out, off - out->cur_out_ptr);
296 }
297
298 if (off % out->block_size) {
299 error("write chunk offset %llu is not a multiple of the block size %u",
300 off, out->block_size);
301 return -1;
302 }
303
304 if (off != out->cur_out_ptr) {
305 error("internal error, offset accounting screwy in write_chunk_raw()");
306 return -1;
307 }
308
309 /* Round up the file length to a multiple of the block size */
310 rnd_up_len = (len + (out->block_size - 1)) & (~(out->block_size -1));
311 zero_len = rnd_up_len - len;
312
313 /* Finally we can safely emit a chunk of data */
314 chunk_header.chunk_type = CHUNK_TYPE_RAW;
315 chunk_header.reserved1 = 0;
316 chunk_header.chunk_sz = rnd_up_len / out->block_size;
317 chunk_header.total_sz = CHUNK_HEADER_LEN + rnd_up_len;
318 ret = out->ops->write(out, (u8 *)&chunk_header, sizeof(chunk_header));
319
320 if (ret < 0)
321 return -1;
322 ret = out->ops->write(out, data, len);
323 if (ret < 0)
324 return -1;
325 if (zero_len) {
326 ret = out->ops->write(out, zero_buf, zero_len);
327 if (ret < 0)
328 return -1;
329 }
330
331 if (out->use_crc) {
332 out->crc32 = sparse_crc32(out->crc32, data, len);
333 if (zero_len)
334 out->crc32 = sparse_crc32(out->crc32, zero_buf, zero_len);
335 }
336
337 out->cur_out_ptr += rnd_up_len;
338 out->chunk_cnt++;
339
340 return 0;
341}
342
343void close_output_file(struct output_file *out)
344{
345 int ret;
346 chunk_header_t chunk_header;
347
348 if (out->sparse) {
349 if (out->use_crc) {
350 chunk_header.chunk_type = CHUNK_TYPE_CRC32;
351 chunk_header.reserved1 = 0;
352 chunk_header.chunk_sz = 0;
353 chunk_header.total_sz = CHUNK_HEADER_LEN + 4;
354
355 out->ops->write(out, (u8 *)&chunk_header, sizeof(chunk_header));
356 out->ops->write(out, (u8 *)&out->crc32, 4);
357
358 out->chunk_cnt++;
359 }
360
361 if (out->chunk_cnt != sparse_header.total_chunks)
362 error("sparse chunk count did not match: %d %d", out->chunk_cnt,
363 sparse_header.total_chunks);
364 }
365 out->ops->close(out);
366}
367
368struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len,
369 int gz, int sparse, int chunks, int crc)
370{
371 int ret;
372 struct output_file *out = malloc(sizeof(struct output_file));
373 if (!out) {
374 error_errno("malloc struct out");
375 return NULL;
376 }
377 zero_buf = malloc(out->block_size);
378 if (!zero_buf) {
379 error_errno("malloc zero_buf");
380 free(out);
381 return NULL;
382 }
383 memset(zero_buf, '\0', out->block_size);
384
385 if (gz) {
386 out->ops = &gz_file_ops;
387 out->gz_fd = gzdopen(fd, "wb9");
388 if (!out->gz_fd) {
389 error_errno("gzopen");
390 free(out);
391 return NULL;
392 }
393 } else {
394 out->fd = fd;
395 out->ops = &file_ops;
396 }
397 out->close_fd = false;
398 out->sparse = sparse;
399 out->cur_out_ptr = 0ll;
400 out->chunk_cnt = 0;
401
402 /* Initialize the crc32 value */
403 out->crc32 = 0;
404 out->use_crc = crc;
405
406 out->len = len;
407 out->block_size = block_size;
408
409 if (out->sparse) {
410 sparse_header.blk_sz = out->block_size,
411 sparse_header.total_blks = out->len / out->block_size,
412 sparse_header.total_chunks = chunks;
413 if (out->use_crc)
414 sparse_header.total_chunks++;
415
416 ret = out->ops->write(out, (u8 *)&sparse_header, sizeof(sparse_header));
417 if (ret < 0)
418 return NULL;
419 }
420
421 return out;
422}
423
424struct output_file *open_output_file(const char *filename,
425 unsigned int block_size, int64_t len,
426 int gz, int sparse, int chunks, int crc)
427{
428 int fd;
429 struct output_file *file;
430
431 if (strcmp(filename, "-")) {
432 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
433 if (fd < 0) {
434 error_errno("open");
435 return NULL;
436 }
437 } else {
438 fd = STDOUT_FILENO;
439 }
440
441 file = open_output_fd(fd, block_size, len, gz, sparse, chunks, crc);
442 if (!file) {
443 close(fd);
444 return NULL;
445 }
446
447 file->close_fd = true; // we opened descriptor thus we responsible for closing it
448
449 return file;
450}
451
452void pad_output_file(struct output_file *out, int64_t len)
453{
454 int ret;
455
456 if (len > out->len) {
457 error("attempted to pad file %llu bytes past end of filesystem",
458 len - out->len);
459 return;
460 }
461 if (out->sparse) {
462 /* We need to emit a DONT_CARE chunk to pad out the file if the
463 * cur_out_ptr is not already at the end of the filesystem.
464 */
465 if (len < out->cur_out_ptr) {
466 error("attempted to pad file %llu bytes less than the current output pointer",
467 out->cur_out_ptr - len);
468 return;
469 }
470 if (len > out->cur_out_ptr) {
471 emit_skip_chunk(out, len - out->cur_out_ptr);
472 }
473 } else {
474 //KEN TODO: Fixme. If the filesystem image needs no padding,
475 // this will overwrite the last byte in the file with 0
476 // The answer is to do accounting like the sparse image
477 // code does and know if there is already data there.
478 ret = out->ops->seek(out, len - 1);
479 if (ret < 0)
480 return;
481
482 ret = out->ops->write(out, (u8*)"", 1);
483 if (ret < 0)
484 return;
485 }
486}
487
488/* Write a contiguous region of data blocks from a memory buffer */
489void write_data_block(struct output_file *out, int64_t off, void *data, int len)
490{
491 int ret;
492
493 if (off + len > out->len) {
494 error("attempted to write block %llu past end of filesystem",
495 off + len - out->len);
496 return;
497 }
498
499 if (out->sparse) {
500 write_chunk_raw(out, off, data, len);
501 } else {
502 ret = out->ops->seek(out, off);
503 if (ret < 0)
504 return;
505
506 ret = out->ops->write(out, data, len);
507 if (ret < 0)
508 return;
509 }
510}
511
512/* Write a contiguous region of data blocks with a fill value */
513void write_fill_block(struct output_file *out, int64_t off, unsigned int fill_val, int len)
514{
515 int ret;
516 unsigned int i;
517 int write_len;
518 u32 fill_buf[4096/sizeof(u32)]; /* Maximum size of a block */
519
520 if (off + len > out->len) {
521 error("attempted to write block %llu past end of filesystem",
522 off + len - out->len);
523 return;
524 }
525
526 if (out->sparse) {
527 write_chunk_fill(out, off, fill_val, len);
528 } else {
529 /* Initialize fill_buf with the fill_val */
530 for (i = 0; i < sizeof(fill_buf)/sizeof(u32); i++) {
531 fill_buf[i] = fill_val;
532 }
533
534 ret = out->ops->seek(out, off);
535 if (ret < 0)
536 return;
537
538 while (len) {
539 write_len = (len > (int)sizeof(fill_buf) ? (int)sizeof(fill_buf) : len);
540 ret = out->ops->write(out, (u8 *)fill_buf, write_len);
541 if (ret < 0) {
542 return;
543 } else {
544 len -= write_len;
545 }
546 }
547 }
548}
549
550/* Write a contiguous region of data blocks from a file */
551void write_data_file(struct output_file *out, int64_t off, const char *file,
552 int64_t offset, int len)
553{
554 int ret;
555 int64_t aligned_offset;
556 int aligned_diff;
557 int buffer_size;
558
559 if (off + len >= out->len) {
560 error("attempted to write block %llu past end of filesystem",
561 off + len - out->len);
562 return;
563 }
564
565 int file_fd = open(file, O_RDONLY | O_BINARY);
566 if (file_fd < 0) {
567 error_errno("open");
568 return;
569 }
570
571 aligned_offset = offset & ~(4096 - 1);
572 aligned_diff = offset - aligned_offset;
573 buffer_size = len + aligned_diff;
574
575#ifndef USE_MINGW
576 u8 *data = mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, file_fd,
577 aligned_offset);
578 if (data == MAP_FAILED) {
579 error_errno("mmap64");
580 close(file_fd);
581 return;
582 }
583#else
584 u8 *data = malloc(buffer_size);
585 if (!data) {
586 error_errno("malloc");
587 close(file_fd);
588 return;
589 }
590 memset(data, 0, buffer_size);
591#endif
592
593 if (out->sparse) {
594 write_chunk_raw(out, off, data + aligned_diff, len);
595 } else {
596 ret = out->ops->seek(out, off);
597 if (ret < 0)
598 goto err;
599
600 ret = out->ops->write(out, data + aligned_diff, len);
601 if (ret < 0)
602 goto err;
603 }
604
605err:
606#ifndef USE_MINGW
607 munmap(data, buffer_size);
608#else
609 write(file_fd, data, buffer_size);
610 free(data);
611#endif
612 close(file_fd);
613}
diff --git a/libsparse/output_file.h b/libsparse/output_file.h
new file mode 100644
index 000000000..b12194fc7
--- /dev/null
+++ b/libsparse/output_file.h
@@ -0,0 +1,36 @@
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _OUTPUT_FILE_H_
18#define _OUTPUT_FILE_H_
19
20#include <sparse/sparse.h>
21
22struct output_file;
23
24struct output_file *open_output_file(const char *filename,
25 unsigned int block_size, int64_t len,
26 int gz, int sparse, int chunks, int crc);
27struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len,
28 int gz, int sparse, int chunks, int crc);
29void write_data_block(struct output_file *out, int64_t off, void *data, int len);
30void write_fill_block(struct output_file *out, int64_t off, unsigned int fill_val, int len);
31void write_data_file(struct output_file *out, int64_t off, const char *file,
32 int64_t offset, int len);
33void pad_output_file(struct output_file *out, int64_t len);
34void close_output_file(struct output_file *out);
35
36#endif
diff --git a/libsparse/simg2img.c b/libsparse/simg2img.c
new file mode 100644
index 000000000..486b8054f
--- /dev/null
+++ b/libsparse/simg2img.c
@@ -0,0 +1,321 @@
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define _FILE_OFFSET_BITS 64
18#define _LARGEFILE64_SOURCE 1
19#include <sys/types.h>
20#include <unistd.h>
21
22#include "sparse_defs.h"
23#include "sparse_format.h"
24#include "sparse_crc32.h"
25
26#include <fcntl.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33#include <sys/mman.h>
34#include <unistd.h>
35
36#define COPY_BUF_SIZE (1024*1024)
37u8 *copybuf;
38
39/* This will be malloc'ed with the size of blk_sz from the sparse file header */
40u8* zerobuf;
41
42#define SPARSE_HEADER_MAJOR_VER 1
43#define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
44#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
45
46void usage()
47{
48 fprintf(stderr, "Usage: simg2img <sparse_image_file> <raw_image_file>\n");
49}
50
51static int read_all(int fd, void *buf, size_t len)
52{
53 size_t total = 0;
54 int ret;
55 char *ptr = buf;
56
57 while (total < len) {
58 ret = read(fd, ptr, len - total);
59
60 if (ret < 0)
61 return ret;
62
63 if (ret == 0)
64 return total;
65
66 ptr += ret;
67 total += ret;
68 }
69
70 return total;
71}
72
73static int write_all(int fd, void *buf, size_t len)
74{
75 size_t total = 0;
76 int ret;
77 char *ptr = buf;
78
79 while (total < len) {
80 ret = write(fd, ptr, len - total);
81
82 if (ret < 0)
83 return ret;
84
85 if (ret == 0)
86 return total;
87
88 ptr += ret;
89 total += ret;
90 }
91
92 return total;
93}
94
95int process_raw_chunk(int in, int out, u32 blocks, u32 blk_sz, u32 *crc32)
96{
97 u64 len = (u64)blocks * blk_sz;
98 int ret;
99 int chunk;
100
101 while (len) {
102 chunk = (len > COPY_BUF_SIZE) ? COPY_BUF_SIZE : len;
103 ret = read_all(in, copybuf, chunk);
104 if (ret != chunk) {
105 fprintf(stderr, "read returned an error copying a raw chunk: %d %d\n",
106 ret, chunk);
107 exit(-1);
108 }
109 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
110 ret = write_all(out, copybuf, chunk);
111 if (ret != chunk) {
112 fprintf(stderr, "write returned an error copying a raw chunk\n");
113 exit(-1);
114 }
115 len -= chunk;
116 }
117
118 return blocks;
119}
120
121
122int process_fill_chunk(int in, int out, u32 blocks, u32 blk_sz, u32 *crc32)
123{
124 u64 len = (u64)blocks * blk_sz;
125 int ret;
126 int chunk;
127 u32 fill_val;
128 u32 *fillbuf;
129 unsigned int i;
130
131 /* Fill copy_buf with the fill value */
132 ret = read_all(in, &fill_val, sizeof(fill_val));
133 fillbuf = (u32 *)copybuf;
134 for (i = 0; i < (COPY_BUF_SIZE / sizeof(fill_val)); i++) {
135 fillbuf[i] = fill_val;
136 }
137
138 while (len) {
139 chunk = (len > COPY_BUF_SIZE) ? COPY_BUF_SIZE : len;
140 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
141 ret = write_all(out, copybuf, chunk);
142 if (ret != chunk) {
143 fprintf(stderr, "write returned an error copying a raw chunk\n");
144 exit(-1);
145 }
146 len -= chunk;
147 }
148
149 return blocks;
150}
151
152int process_skip_chunk(int out, u32 blocks, u32 blk_sz, u32 *crc32)
153{
154 /* len needs to be 64 bits, as the sparse file specifies the skip amount
155 * as a 32 bit value of blocks.
156 */
157 u64 len = (u64)blocks * blk_sz;
158
159 lseek64(out, len, SEEK_CUR);
160
161 return blocks;
162}
163
164int process_crc32_chunk(int in, u32 crc32)
165{
166 u32 file_crc32;
167 int ret;
168
169 ret = read_all(in, &file_crc32, 4);
170 if (ret != 4) {
171 fprintf(stderr, "read returned an error copying a crc32 chunk\n");
172 exit(-1);
173 }
174
175 if (file_crc32 != crc32) {
176 fprintf(stderr, "computed crc32 of 0x%8.8x, expected 0x%8.8x\n",
177 crc32, file_crc32);
178 exit(-1);
179 }
180
181 return 0;
182}
183
184int main(int argc, char *argv[])
185{
186 int in;
187 int out;
188 unsigned int i;
189 sparse_header_t sparse_header;
190 chunk_header_t chunk_header;
191 u32 crc32 = 0;
192 u32 total_blocks = 0;
193 int ret;
194
195 if (argc != 3) {
196 usage();
197 exit(-1);
198 }
199
200 if ( (copybuf = malloc(COPY_BUF_SIZE)) == 0) {
201 fprintf(stderr, "Cannot malloc copy buf\n");
202 exit(-1);
203 }
204
205 if (strcmp(argv[1], "-") == 0) {
206 in = STDIN_FILENO;
207 } else {
208 if ((in = open(argv[1], O_RDONLY)) == 0) {
209 fprintf(stderr, "Cannot open input file %s\n", argv[1]);
210 exit(-1);
211 }
212 }
213
214 if (strcmp(argv[2], "-") == 0) {
215 out = STDOUT_FILENO;
216 } else {
217 if ((out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666)) == 0) {
218 fprintf(stderr, "Cannot open output file %s\n", argv[2]);
219 exit(-1);
220 }
221 }
222
223 ret = read_all(in, &sparse_header, sizeof(sparse_header));
224 if (ret != sizeof(sparse_header)) {
225 fprintf(stderr, "Error reading sparse file header\n");
226 exit(-1);
227 }
228
229 if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
230 fprintf(stderr, "Bad magic\n");
231 exit(-1);
232 }
233
234 if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
235 fprintf(stderr, "Unknown major version number\n");
236 exit(-1);
237 }
238
239 if (sparse_header.file_hdr_sz > SPARSE_HEADER_LEN) {
240 /* Skip the remaining bytes in a header that is longer than
241 * we expected.
242 */
243 lseek64(in, sparse_header.file_hdr_sz - SPARSE_HEADER_LEN, SEEK_CUR);
244 }
245
246 if ( (zerobuf = malloc(sparse_header.blk_sz)) == 0) {
247 fprintf(stderr, "Cannot malloc zero buf\n");
248 exit(-1);
249 }
250
251 for (i=0; i<sparse_header.total_chunks; i++) {
252 ret = read_all(in, &chunk_header, sizeof(chunk_header));
253 if (ret != sizeof(chunk_header)) {
254 fprintf(stderr, "Error reading chunk header\n");
255 exit(-1);
256 }
257
258 if (sparse_header.chunk_hdr_sz > CHUNK_HEADER_LEN) {
259 /* Skip the remaining bytes in a header that is longer than
260 * we expected.
261 */
262 lseek64(in, sparse_header.chunk_hdr_sz - CHUNK_HEADER_LEN, SEEK_CUR);
263 }
264
265 switch (chunk_header.chunk_type) {
266 case CHUNK_TYPE_RAW:
267 if (chunk_header.total_sz != (sparse_header.chunk_hdr_sz +
268 (chunk_header.chunk_sz * sparse_header.blk_sz)) ) {
269 fprintf(stderr, "Bogus chunk size for chunk %d, type Raw\n", i);
270 exit(-1);
271 }
272 total_blocks += process_raw_chunk(in, out,
273 chunk_header.chunk_sz, sparse_header.blk_sz, &crc32);
274 break;
275 case CHUNK_TYPE_FILL:
276 if (chunk_header.total_sz != (sparse_header.chunk_hdr_sz + sizeof(u32)) ) {
277 fprintf(stderr, "Bogus chunk size for chunk %d, type Fill\n", i);
278 exit(-1);
279 }
280 total_blocks += process_fill_chunk(in, out,
281 chunk_header.chunk_sz, sparse_header.blk_sz, &crc32);
282 break;
283 case CHUNK_TYPE_DONT_CARE:
284 if (chunk_header.total_sz != sparse_header.chunk_hdr_sz) {
285 fprintf(stderr, "Bogus chunk size for chunk %d, type Dont Care\n", i);
286 exit(-1);
287 }
288 total_blocks += process_skip_chunk(out,
289 chunk_header.chunk_sz, sparse_header.blk_sz, &crc32);
290 break;
291 case CHUNK_TYPE_CRC32:
292 process_crc32_chunk(in, crc32);
293 break;
294 default:
295 fprintf(stderr, "Unknown chunk type 0x%4.4x\n", chunk_header.chunk_type);
296 }
297
298 }
299
300 /* If the last chunk was a skip, then the code just did a seek, but
301 * no write, and the file won't actually be the correct size. This
302 * will make the file the correct size. Make sure the offset is
303 * computed in 64 bits, and the function called can handle 64 bits.
304 */
305 if (ftruncate64(out, (u64)total_blocks * sparse_header.blk_sz)) {
306 fprintf(stderr, "Error calling ftruncate() to set the image size\n");
307 exit(-1);
308 }
309
310 close(in);
311 close(out);
312
313 if (sparse_header.total_blks != total_blocks) {
314 fprintf(stderr, "Wrote %d blocks, expected to write %d blocks\n",
315 total_blocks, sparse_header.total_blks);
316 exit(-1);
317 }
318
319 exit(0);
320}
321
diff --git a/libsparse/simg_dump.py b/libsparse/simg_dump.py
new file mode 100755
index 000000000..6ece31d0c
--- /dev/null
+++ b/libsparse/simg_dump.py
@@ -0,0 +1,169 @@
1#! /usr/bin/env python
2
3# Copyright (C) 2012 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17from __future__ import print_function
18import getopt, posixpath, signal, struct, sys
19
20def usage(argv0):
21 print("""
22Usage: %s [-v] sparse_image_file ...
23 -v verbose output
24""" % ( argv0 ))
25 sys.exit(2)
26
27def main():
28
29 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
30
31 me = posixpath.basename(sys.argv[0])
32
33 # Parse the command line
34 verbose = 0 # -v
35 try:
36 opts, args = getopt.getopt(sys.argv[1:],
37 "v",
38 ["verbose"])
39 except getopt.GetoptError, e:
40 print(e)
41 usage(me)
42 for o, a in opts:
43 if o in ("-v", "--verbose"):
44 verbose += 1
45 else:
46 print("Unrecognized option \"%s\"" % (o))
47 usage(me)
48
49 if len(args) == 0:
50 print("No sparse_image_file specified")
51 usage(me)
52
53 for path in args:
54 FH = open(path, 'rb')
55 header_bin = FH.read(28)
56 header = struct.unpack("<I4H4I", header_bin)
57
58 magic = header[0]
59 major_version = header[1]
60 minor_version = header[2]
61 file_hdr_sz = header[3]
62 chunk_hdr_sz = header[4]
63 blk_sz = header[5]
64 total_blks = header[6]
65 total_chunks = header[7]
66 image_checksum = header[8]
67
68 if magic != 0xED26FF3A:
69 print("%s: %s: Magic should be 0xED26FF3A but is 0x%08X"
70 % (me, path, magic))
71 continue
72 if major_version != 1 or minor_version != 0:
73 print("%s: %s: I only know about version 1.0, but this is version %u.%u"
74 % (me, path, major_version, minor_version))
75 continue
76 if file_hdr_sz != 28:
77 print("%s: %s: The file header size was expected to be 28, but is %u."
78 % (me, path, file_hdr_sz))
79 continue
80 if chunk_hdr_sz != 12:
81 print("%s: %s: The chunk header size was expected to be 12, but is %u."
82 % (me, path, chunk_hdr_sz))
83 continue
84
85 print("%s: Total of %u %u-byte output blocks in %u input chunks."
86 % (path, total_blks, blk_sz, total_chunks))
87
88 if image_checksum != 0:
89 print("checksum=0x%08X" % (image_checksum))
90
91 if not verbose:
92 continue
93 print(" input_bytes output_blocks")
94 print("chunk offset number offset number")
95 offset = 0
96 for i in xrange(1,total_chunks+1):
97 header_bin = FH.read(12)
98 header = struct.unpack("<2H2I", header_bin)
99 chunk_type = header[0]
100 reserved1 = header[1]
101 chunk_sz = header[2]
102 total_sz = header[3]
103 data_sz = total_sz - 12
104
105 print("%4u %10u %10u %7u %7u" % (i, FH.tell(), data_sz, offset, chunk_sz),
106 end=" ")
107
108 if chunk_type == 0xCAC1:
109 if data_sz != (chunk_sz * blk_sz):
110 print("Raw chunk input size (%u) does not match output size (%u)"
111 % (data_sz, chunk_sz * blk_sz))
112 break;
113 else:
114 print("Raw data", end="")
115 FH.read(data_sz)
116 elif chunk_type == 0xCAC2:
117 if data_sz != 4:
118 print("Fill chunk should have 4 bytes of fill, but this has %u"
119 % (data_sz), end="")
120 break;
121 else:
122 fill_bin = FH.read(4)
123 fill = struct.unpack("<I", fill_bin)
124 print("Fill with 0x%08X" % (fill))
125 elif chunk_type == 0xCAC3:
126 if data_sz != 0:
127 print("Don't care chunk input size is non-zero (%u)" % (data_sz))
128 break;
129 else:
130 print("Don't care", end="")
131 elif chunk_type == 0xCAC4:
132 if data_sz != 4:
133 print("CRC32 chunk should have 4 bytes of CRC, but this has %u"
134 % (data_sz), end="")
135 break;
136 else:
137 crc_bin = FH.read(4)
138 crc = struct.unpack("<I", crc)
139 print("Unverified CRC32 0x%08X" % (crc))
140 else:
141 print("Unknown chunk type 0x%04X" % (chunk_type), end="")
142 break;
143
144 if verbose > 1:
145 header = struct.unpack("<12B", header_bin)
146 print(" (%02X%02X %02X%02X %02X%02X%02X%02X %02X%02X%02X%02X)"
147 % (header[0], header[1], header[2], header[3],
148 header[4], header[5], header[6], header[7],
149 header[8], header[9], header[10], header[11]))
150 else:
151 print()
152
153 offset += chunk_sz
154
155 print(" %10u %7u End" % (FH.tell(), offset))
156
157 if total_blks != offset:
158 print("The header said we should have %u output blocks, but we saw %u"
159 % (total_blks, offset))
160
161 junk_len = len(FH.read())
162 if junk_len:
163 print("There were %u bytes of extra data at the end of the file."
164 % (junk_len))
165
166 sys.exit(0)
167
168if __name__ == "__main__":
169 main()
diff --git a/libsparse/sparse.c b/libsparse/sparse.c
new file mode 100644
index 000000000..d6f556114
--- /dev/null
+++ b/libsparse/sparse.c
@@ -0,0 +1,154 @@
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18
19#include <sparse/sparse.h>
20
21#include "sparse_file.h"
22
23#include "output_file.h"
24#include "backed_block.h"
25#include "sparse_defs.h"
26
27
28struct sparse_file *sparse_file_new(unsigned int block_size, int64_t len)
29{
30 struct sparse_file *s = calloc(sizeof(struct sparse_file), 1);
31 if (!s) {
32 return NULL;
33 }
34
35 /* TODO: allocate backed block list */
36
37 s->block_size = block_size;
38 s->len = len;
39
40 return s;
41}
42
43void sparse_file_destroy(struct sparse_file *s)
44{
45 free_data_blocks();
46 free(s);
47}
48
49int sparse_file_add_data(struct sparse_file *s,
50 void *data, unsigned int len, unsigned int block)
51{
52 queue_data_block(data, len, block);
53
54 return 0;
55}
56
57int sparse_file_add_fill(struct sparse_file *s,
58 uint32_t fill_val, unsigned int len, unsigned int block)
59{
60 queue_fill_block(fill_val, len, block);
61
62 return 0;
63}
64
65int sparse_file_add_file(struct sparse_file *s,
66 const char *filename, int64_t file_offset, unsigned int len,
67 unsigned int block)
68{
69 queue_data_file(filename, file_offset, len, block);
70
71 return 0;
72}
73
74struct count_chunks {
75 unsigned int chunks;
76 int64_t cur_ptr;
77 unsigned int block_size;
78};
79
80static void count_data_block(void *priv, int64_t off, void *data, int len)
81{
82 struct count_chunks *count_chunks = priv;
83 if (off > count_chunks->cur_ptr)
84 count_chunks->chunks++;
85 count_chunks->cur_ptr = off + ALIGN(len, count_chunks->block_size);
86 count_chunks->chunks++;
87}
88
89static void count_fill_block(void *priv, int64_t off, unsigned int fill_val, int len)
90{
91 struct count_chunks *count_chunks = priv;
92 if (off > count_chunks->cur_ptr)
93 count_chunks->chunks++;
94 count_chunks->cur_ptr = off + ALIGN(len, count_chunks->block_size);
95 count_chunks->chunks++;
96}
97
98static void count_file_block(void *priv, int64_t off, const char *file,
99 int64_t offset, int len)
100{
101 struct count_chunks *count_chunks = priv;
102 if (off > count_chunks->cur_ptr)
103 count_chunks->chunks++;
104 count_chunks->cur_ptr = off + ALIGN(len, count_chunks->block_size);
105 count_chunks->chunks++;
106}
107
108static int count_sparse_chunks(unsigned int block_size, int64_t len)
109{
110 struct count_chunks count_chunks = {0, 0, block_size};
111
112 for_each_data_block(count_data_block, count_file_block, count_fill_block, &count_chunks, block_size);
113
114 if (count_chunks.cur_ptr != len)
115 count_chunks.chunks++;
116
117 return count_chunks.chunks;
118}
119
120static void ext4_write_data_block(void *priv, int64_t off, void *data, int len)
121{
122 write_data_block(priv, off, data, len);
123}
124
125static void ext4_write_fill_block(void *priv, int64_t off, unsigned int fill_val, int len)
126{
127 write_fill_block(priv, off, fill_val, len);
128}
129
130static void ext4_write_data_file(void *priv, int64_t off, const char *file,
131 int64_t offset, int len)
132{
133 write_data_file(priv, off, file, offset, len);
134}
135
136int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse,
137 bool crc)
138{
139 int chunks = count_sparse_chunks(s->block_size, s->len);
140 struct output_file *out = open_output_fd(fd, s->block_size, s->len,
141 gz, sparse, chunks, crc);
142
143 if (!out)
144 return -ENOMEM;
145
146 for_each_data_block(ext4_write_data_block, ext4_write_data_file, ext4_write_fill_block, out, s->block_size);
147
148 if (s->len)
149 pad_output_file(out, s->len);
150
151 close_output_file(out);
152
153 return 0;
154}
diff --git a/libsparse/sparse_crc32.c b/libsparse/sparse_crc32.c
new file mode 100644
index 000000000..38bfe4aa0
--- /dev/null
+++ b/libsparse/sparse_crc32.c
@@ -0,0 +1,111 @@
1/*-
2 * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
3 * code or tables extracted from it, as desired without restriction.
4 */
5
6/*
7 * First, the polynomial itself and its table of feedback terms. The
8 * polynomial is
9 * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
10 *
11 * Note that we take it "backwards" and put the highest-order term in
12 * the lowest-order bit. The X^32 term is "implied"; the LSB is the
13 * X^31 term, etc. The X^0 term (usually shown as "+1") results in
14 * the MSB being 1
15 *
16 * Note that the usual hardware shift register implementation, which
17 * is what we're using (we're merely optimizing it by doing eight-bit
18 * chunks at a time) shifts bits into the lowest-order term. In our
19 * implementation, that means shifting towards the right. Why do we
20 * do it this way? Because the calculated CRC must be transmitted in
21 * order from highest-order term to lowest-order term. UARTs transmit
22 * characters in order from LSB to MSB. By storing the CRC this way
23 * we hand it to the UART in the order low-byte to high-byte; the UART
24 * sends each low-bit to hight-bit; and the result is transmission bit
25 * by bit from highest- to lowest-order term without requiring any bit
26 * shuffling on our part. Reception works similarly
27 *
28 * The feedback terms table consists of 256, 32-bit entries. Notes
29 *
30 * The table can be generated at runtime if desired; code to do so
31 * is shown later. It might not be obvious, but the feedback
32 * terms simply represent the results of eight shift/xor opera
33 * tions for all combinations of data and CRC register values
34 *
35 * The values must be right-shifted by eight bits by the "updcrc
36 * logic; the shift must be unsigned (bring in zeroes). On some
37 * hardware you could probably optimize the shift in assembler by
38 * using byte-swap instructions
39 * polynomial $edb88320
40 *
41 *
42 * CRC32 code derived from work by Gary S. Brown.
43 */
44
45/* Code taken from FreeBSD 8 */
46#include <stdint.h>
47
48static uint32_t crc32_tab[] = {
49 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
50 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
51 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
52 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
53 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
54 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
55 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
56 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
57 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
58 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
59 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
60 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
61 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
62 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
63 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
64 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
65 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
66 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
67 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
68 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
69 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
70 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
71 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
72 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
73 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
74 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
75 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
76 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
77 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
78 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
79 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
80 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
81 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
82 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
83 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
84 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
85 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
86 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
87 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
88 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
89 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
90 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
91 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
92};
93
94/*
95 * A function that calculates the CRC-32 based on the table above is
96 * given below for documentation purposes. An equivalent implementation
97 * of this function that's actually used in the kernel can be found
98 * in sys/libkern.h, where it can be inlined.
99 */
100
101uint32_t sparse_crc32(uint32_t crc_in, const void *buf, int size)
102{
103 const uint8_t *p = buf;
104 uint32_t crc;
105
106 crc = crc_in ^ ~0U;
107 while (size--)
108 crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
109 return crc ^ ~0U;
110}
111
diff --git a/libsparse/sparse_crc32.h b/libsparse/sparse_crc32.h
new file mode 100644
index 000000000..21625bac9
--- /dev/null
+++ b/libsparse/sparse_crc32.h
@@ -0,0 +1,18 @@
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17u32 sparse_crc32(u32 crc, const void *buf, size_t size);
18
diff --git a/libsparse/sparse_defs.h b/libsparse/sparse_defs.h
new file mode 100644
index 000000000..9f32d592e
--- /dev/null
+++ b/libsparse/sparse_defs.h
@@ -0,0 +1,48 @@
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _LIBSPARSE_SPARSE_DEFS_
18#define _LIBSPARSE_SPARSE_DEFS_
19
20#include <errno.h>
21#include <stdio.h>
22
23#define __le64 u64
24#define __le32 u32
25#define __le16 u16
26
27#define __be64 u64
28#define __be32 u32
29#define __be16 u16
30
31#define __u64 u64
32#define __u32 u32
33#define __u16 u16
34#define __u8 u8
35
36typedef unsigned long long u64;
37typedef signed long long s64;
38typedef unsigned int u32;
39typedef unsigned short int u16;
40typedef unsigned char u8;
41
42#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y))
43#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
44
45#define error(fmt, args...) do { fprintf(stderr, "error: %s: " fmt "\n", __func__, ## args); } while (0)
46#define error_errno(s, args...) error(s ": %s", ##args, strerror(errno))
47
48#endif
diff --git a/libsparse/sparse_file.h b/libsparse/sparse_file.h
new file mode 100644
index 000000000..05a78d96e
--- /dev/null
+++ b/libsparse/sparse_file.h
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _LIBSPARSE_SPARSE_FILE_H_
18#define _LIBSPARSE_SPARSE_FILE_H_
19
20#include <sparse/sparse.h>
21
22struct sparse_file {
23 unsigned int block_size;
24 int64_t len;
25
26 struct output_file *out;
27};
28
29
30#endif /* _LIBSPARSE_SPARSE_FILE_H_ */
diff --git a/libsparse/sparse_format.h b/libsparse/sparse_format.h
new file mode 100644
index 000000000..c41f12a54
--- /dev/null
+++ b/libsparse/sparse_format.h
@@ -0,0 +1,55 @@
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _LIBSPARSE_SPARSE_FORMAT_H_
18#define _LIBSPARSE_SPARSE_FORMAT_H_
19#include "sparse_defs.h"
20
21typedef struct sparse_header {
22 __le32 magic; /* 0xed26ff3a */
23 __le16 major_version; /* (0x1) - reject images with higher major versions */
24 __le16 minor_version; /* (0x0) - allow images with higer minor versions */
25 __le16 file_hdr_sz; /* 28 bytes for first revision of the file format */
26 __le16 chunk_hdr_sz; /* 12 bytes for first revision of the file format */
27 __le32 blk_sz; /* block size in bytes, must be a multiple of 4 (4096) */
28 __le32 total_blks; /* total blocks in the non-sparse output image */
29 __le32 total_chunks; /* total chunks in the sparse input image */
30 __le32 image_checksum; /* CRC32 checksum of the original data, counting "don't care" */
31 /* as 0. Standard 802.3 polynomial, use a Public Domain */
32 /* table implementation */
33} sparse_header_t;
34
35#define SPARSE_HEADER_MAGIC 0xed26ff3a
36
37#define CHUNK_TYPE_RAW 0xCAC1
38#define CHUNK_TYPE_FILL 0xCAC2
39#define CHUNK_TYPE_DONT_CARE 0xCAC3
40#define CHUNK_TYPE_CRC32 0xCAC4
41
42typedef struct chunk_header {
43 __le16 chunk_type; /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
44 __le16 reserved1;
45 __le32 chunk_sz; /* in blocks in output image */
46 __le32 total_sz; /* in bytes of chunk input file including chunk header and data */
47} chunk_header_t;
48
49/* Following a Raw or Fill or CRC32 chunk is data.
50 * For a Raw chunk, it's the data in chunk_sz * blk_sz.
51 * For a Fill chunk, it's 4 bytes of the fill data.
52 * For a CRC32 chunk, it's 4 bytes of CRC32
53 */
54
55#endif