OSDN Git Service

ext4_utils: Fix OSX build
[android-x86/system-extras.git] / ext4_utils / simg2img.c
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 "ext4_utils.h"
18 #include "sparse_format.h"
19 #include "sparse_crc32.h"
20
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <sys/mman.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28
29 #define COPY_BUF_SIZE (1024*1024)
30 u8 *copybuf;
31
32 /* This will be malloc'ed with the size of blk_sz from the sparse file header */
33 u8* zerobuf;
34
35 #define SPARSE_HEADER_MAJOR_VER 1
36 #define SPARSE_HEADER_LEN       (sizeof(sparse_header_t))
37 #define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
38
39 void usage()
40 {
41   fprintf(stderr, "Usage: simg2img <sparse_image_file> <raw_image_file>\n");
42 }
43
44 static int read_all(int fd, void *buf, size_t len)
45 {
46         size_t total = 0;
47         int ret;
48         char *ptr = buf;
49
50         while (total < len) {
51                 ret = read(fd, ptr, len - total);
52
53                 if (ret < 0)
54                         return ret;
55
56                 if (ret == 0)
57                         return total;
58
59                 ptr += ret;
60                 total += ret;
61         }
62
63         return total;
64 }
65
66 static int write_all(int fd, void *buf, size_t len)
67 {
68         size_t total = 0;
69         int ret;
70         char *ptr = buf;
71
72         while (total < len) {
73                 ret = write(fd, ptr, len - total);
74
75                 if (ret < 0)
76                         return ret;
77
78                 if (ret == 0)
79                         return total;
80
81                 ptr += ret;
82                 total += ret;
83         }
84
85         return total;
86 }
87
88 int process_raw_chunk(int in, int out, u32 blocks, u32 blk_sz, u32 *crc32)
89 {
90         u64 len = (u64)blocks * blk_sz;
91         int ret;
92         int chunk;
93
94         while (len) {
95                 chunk = (len > COPY_BUF_SIZE) ? COPY_BUF_SIZE : len;
96                 ret = read_all(in, copybuf, chunk);
97                 if (ret != chunk) {
98                         fprintf(stderr, "read returned an error copying a raw chunk: %d %d\n",
99                                         ret, chunk);
100                         exit(-1);
101                 }
102                 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
103                 ret = write_all(out, copybuf, chunk);
104                 if (ret != chunk) {
105                         fprintf(stderr, "write returned an error copying a raw chunk\n");
106                         exit(-1);
107                 }
108                 len -= chunk;
109         }
110
111         return blocks;
112 }
113
114
115 int process_skip_chunk(int out, u32 blocks, u32 blk_sz, u32 *crc32)
116 {
117         /* len needs to be 64 bits, as the sparse file specifies the skip amount
118          * as a 32 bit value of blocks.
119          */
120         u64 len = (u64)blocks * blk_sz;
121
122         lseek64(out, len, SEEK_CUR);
123
124         return blocks;
125 }
126
127 int process_crc32_chunk(int in, u32 crc32)
128 {
129         u32 file_crc32;
130         int ret;
131
132         ret = read_all(in, &file_crc32, 4);
133         if (ret != 4) {
134                 fprintf(stderr, "read returned an error copying a crc32 chunk\n");
135                 exit(-1);
136         }
137
138         if (file_crc32 != crc32) {
139                 fprintf(stderr, "computed crc32 of 0x%8.8x, expected 0x%8.8x\n",
140                          crc32, file_crc32);
141                 exit(-1);
142         }
143
144         return 0;
145 }
146
147 int main(int argc, char *argv[])
148 {
149         int in;
150         int out;
151         unsigned int i;
152         sparse_header_t sparse_header;
153         chunk_header_t chunk_header;
154         u32 crc32 = 0;
155         u32 total_blocks = 0;
156         int ret;
157
158         if (argc != 3) {
159                 usage();
160                 exit(-1);
161         }
162
163         if ( (copybuf = malloc(COPY_BUF_SIZE)) == 0) {
164                 fprintf(stderr, "Cannot malloc copy buf\n");
165                 exit(-1);
166         }
167
168         if (strcmp(argv[1], "-") == 0) {
169                 in = STDIN_FILENO;
170         } else {
171                 if ((in = open(argv[1], O_RDONLY)) == 0) {
172                         fprintf(stderr, "Cannot open input file %s\n", argv[1]);
173                         exit(-1);
174                 }
175         }
176
177         if (strcmp(argv[2], "-") == 0) {
178                 out = STDOUT_FILENO;
179         } else {
180                 if ((out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC)) == 0) {
181                         fprintf(stderr, "Cannot open output file %s\n", argv[2]);
182                         exit(-1);
183                 }
184         }
185
186         ret = read_all(in, &sparse_header, sizeof(sparse_header));
187         if (ret != sizeof(sparse_header)) {
188                 fprintf(stderr, "Error reading sparse file header\n");
189                 exit(-1);
190         }
191
192         if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
193                 fprintf(stderr, "Bad magic\n");
194                 exit(-1);
195         }
196
197         if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
198                 fprintf(stderr, "Unknown major version number\n");
199                 exit(-1);
200         }
201
202         if (sparse_header.file_hdr_sz > SPARSE_HEADER_LEN) {
203                 /* Skip the remaining bytes in a header that is longer than
204                  * we expected.
205                  */
206                 lseek64(in, sparse_header.file_hdr_sz - SPARSE_HEADER_LEN, SEEK_CUR);
207         }
208
209         if ( (zerobuf = malloc(sparse_header.blk_sz)) == 0) {
210                 fprintf(stderr, "Cannot malloc zero buf\n");
211                 exit(-1);
212         }
213
214         for (i=0; i<sparse_header.total_chunks; i++) {
215                 ret = read_all(in, &chunk_header, sizeof(chunk_header));
216                 if (ret != sizeof(chunk_header)) {
217                         fprintf(stderr, "Error reading chunk header\n");
218                         exit(-1);
219                 }
220  
221                 if (sparse_header.chunk_hdr_sz > CHUNK_HEADER_LEN) {
222                         /* Skip the remaining bytes in a header that is longer than
223                          * we expected.
224                          */
225                         lseek64(in, sparse_header.chunk_hdr_sz - CHUNK_HEADER_LEN, SEEK_CUR);
226                 }
227
228                 switch (chunk_header.chunk_type) {
229                     case CHUNK_TYPE_RAW:
230                         if (chunk_header.total_sz != (sparse_header.chunk_hdr_sz +
231                                  (chunk_header.chunk_sz * sparse_header.blk_sz)) ) {
232                                 fprintf(stderr, "Bogus chunk size for chunk %d, type Raw\n", i);
233                                 exit(-1);
234                         }
235                         total_blocks += process_raw_chunk(in, out,
236                                          chunk_header.chunk_sz, sparse_header.blk_sz, &crc32);
237                         break;
238                     case CHUNK_TYPE_DONT_CARE:
239                         if (chunk_header.total_sz != sparse_header.chunk_hdr_sz) {
240                                 fprintf(stderr, "Bogus chunk size for chunk %d, type Dont Care\n", i);
241                                 exit(-1);
242                         }
243                         total_blocks += process_skip_chunk(out,
244                                          chunk_header.chunk_sz, sparse_header.blk_sz, &crc32);
245                         break;
246                     case CHUNK_TYPE_CRC32:
247                         process_crc32_chunk(in, crc32);
248                         break;
249                     default:
250                         fprintf(stderr, "Unknown chunk type 0x%4.4x\n", chunk_header.chunk_type);
251                 }
252
253         }
254
255         /* If the last chunk was a skip, then the code just did a seek, but
256          * no write, and the file won't actually be the correct size.  This
257          * will make the file the correct size.  Make sure the offset is
258          * computed in 64 bits, and the function called can handle 64 bits.
259          */
260         if (ftruncate64(out, (u64)total_blocks * sparse_header.blk_sz)) {
261                 fprintf(stderr, "Error calling ftruncate() to set the image size\n");
262                 exit(-1);
263         }
264
265         close(in);
266         close(out);
267
268         if (sparse_header.total_blks != total_blocks) {
269                 fprintf(stderr, "Wrote %d blocks, expected to write %d blocks\n",
270                          total_blocks, sparse_header.total_blks);
271                 exit(-1);
272         }
273
274         exit(0);
275 }
276