Skip to content

Commit ff11c13

Browse files
committed
add support sparse attribute
1 parent e36b236 commit ff11c13

File tree

6 files changed

+258
-10
lines changed

6 files changed

+258
-10
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ CFLAGS := -O2 -Wall -g `pkg-config --cflags libxml-2.0`
44
LDFLAGS := `pkg-config --libs libxml-2.0 libudev`
55
prefix := /usr/local
66

7-
SRCS := firehose.c qdl.c sahara.c util.c patch.c program.c ufs.c
7+
SRCS := firehose.c qdl.c sahara.c util.c patch.c program.c ufs.c sparse.c
88
OBJS := $(SRCS:.c=.o)
99

1010
KS_OUT := ks

firehose.c

+13-8
Original file line numberDiff line numberDiff line change
@@ -344,13 +344,15 @@ static int firehose_program(struct qdl_device *qdl, struct program *program, int
344344
if (ret < 0)
345345
err(1, "failed to stat \"%s\"\n", program->filename);
346346

347-
num_sectors = (sb.st_size + program->sector_size - 1) / program->sector_size;
348-
349-
if (program->num_sectors && num_sectors > program->num_sectors) {
350-
fprintf(stderr, "[PROGRAM] %s truncated to %d\n",
351-
program->label,
352-
program->num_sectors * program->sector_size);
353-
num_sectors = program->num_sectors;
347+
if (!program->sparse) {
348+
num_sectors = (sb.st_size + program->sector_size - 1) / program->sector_size;
349+
350+
if (program->num_sectors && num_sectors > program->num_sectors) {
351+
fprintf(stderr, "[PROGRAM] %s truncated to %d\n",
352+
program->label,
353+
program->num_sectors * program->sector_size);
354+
num_sectors = program->num_sectors;
355+
}
354356
}
355357

356358
buf = malloc(max_payload_size);
@@ -388,7 +390,10 @@ static int firehose_program(struct qdl_device *qdl, struct program *program, int
388390

389391
t0 = time(NULL);
390392

391-
lseek(fd, (off_t) program->file_offset * program->sector_size, SEEK_SET);
393+
if (program->sparse)
394+
lseek(fd, (off_t) program->sparse_file_offset, SEEK_SET);
395+
else
396+
lseek(fd, (off_t) program->file_offset * program->sector_size, SEEK_SET);
392397
left = num_sectors;
393398
while (left > 0) {
394399
chunk_size = MIN(max_payload_size / program->sector_size, left);

program.c

+85-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
#include "program.h"
3939
#include "qdl.h"
40+
#include "sparse.h"
4041

4142
static struct program *programes;
4243
static struct program *programes_last;
@@ -79,6 +80,74 @@ static int load_erase_tag(xmlNode *node, bool is_nand)
7980
return 0;
8081
}
8182

83+
static struct program *program_load_sparse(struct program *program, int fd)
84+
{
85+
struct program *program_sparse = NULL;
86+
struct program *programes_sparse = NULL;
87+
struct program *programes_sparse_last = NULL;
88+
char tmp[PATH_MAX];
89+
90+
sparse_header_t sparse_header;
91+
unsigned start_sector, chunk_size, sparse_file_offset;
92+
93+
if (sparse_header_parse(fd, &sparse_header)) {
94+
/* ignore false sparse images */
95+
if (program->sector_size * program->num_sectors == lseek(fd, 0, SEEK_END)) {
96+
program_sparse = calloc(1, sizeof(struct program));
97+
memcpy(program_sparse, program, sizeof(struct program));
98+
program_sparse->sparse = false;
99+
program_sparse->next = NULL;
100+
return program_sparse;
101+
}
102+
103+
fprintf(stderr, "[PROGRAM] Unable to parse sparse header at %s...failed\n",
104+
program->filename);
105+
return NULL;
106+
}
107+
108+
for (uint32_t i = 0; i < sparse_header.total_chunks; ++i) {
109+
110+
if (sparse_chunk_header_parse(fd, &sparse_header, &chunk_size, &sparse_file_offset)) {
111+
fprintf(stderr, "[PROGRAM] Unable to parse sparse chunk %i at %s...failed\n",
112+
i, program->filename);
113+
return NULL;
114+
}
115+
116+
if (chunk_size == 0)
117+
continue;
118+
119+
if (chunk_size % program->sector_size != 0) {
120+
fprintf(stderr, "[SPARSE] File chunk #%u size %u is not a sector-multiple\n",
121+
i, chunk_size);
122+
return NULL;
123+
}
124+
125+
if (sparse_file_offset) {
126+
program_sparse = calloc(1, sizeof(struct program));
127+
memcpy(program_sparse, program, sizeof(struct program));
128+
129+
program_sparse->next = NULL;
130+
program_sparse->num_sectors = chunk_size / program->sector_size;
131+
program_sparse->sparse_file_offset = sparse_file_offset;
132+
133+
if (programes_sparse) {
134+
programes_sparse_last->next = program_sparse;
135+
programes_sparse_last = program_sparse;
136+
} else {
137+
programes_sparse = program_sparse;
138+
programes_sparse_last = program_sparse;
139+
}
140+
}
141+
142+
start_sector = (unsigned int) strtoul(program->start_sector, NULL, 0);
143+
start_sector += chunk_size / program->sector_size;
144+
sprintf(tmp, "%u", start_sector);
145+
program->start_sector = strdup(tmp);
146+
}
147+
148+
return programes_sparse;
149+
}
150+
82151
static int load_program_tag(xmlNode *node, bool is_nand)
83152
{
84153
struct program *program;
@@ -162,6 +231,7 @@ int program_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl,
162231
const char *incdir)
163232
{
164233
struct program *program;
234+
struct program *program_sparse;
165235
const char *filename;
166236
char tmp[PATH_MAX];
167237
int ret;
@@ -185,7 +255,21 @@ int program_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl,
185255
continue;
186256
}
187257

188-
ret = apply(qdl, program, fd);
258+
if (!program->sparse) {
259+
ret = apply(qdl, program, fd);
260+
} else {
261+
program_sparse = program_load_sparse(program, fd);
262+
if (!program_sparse) {
263+
fprintf(stderr, "[PROGRAM] load sparse failed\n");
264+
return -EINVAL;
265+
}
266+
267+
for (; program_sparse; program_sparse = program_sparse->next) {
268+
ret = apply(qdl, program_sparse, fd);
269+
if (ret)
270+
break;
271+
}
272+
}
189273

190274
close(fd);
191275
if (ret)

program.h

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ struct program {
1919
bool is_nand;
2020
bool is_erase;
2121

22+
unsigned sparse_file_offset;
23+
2224
struct program *next;
2325
};
2426

sparse.c

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright (c) 2016, Bjorn Andersson <[email protected]>
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
*
8+
* 1. Redistributions of source code must retain the above copyright notice,
9+
* this list of conditions and the following disclaimer.
10+
*
11+
* 2. Redistributions in binary form must reproduce the above copyright notice,
12+
* this list of conditions and the following disclaimer in the documentation
13+
* and/or other materials provided with the distribution.
14+
*
15+
* 3. Neither the name of the copyright holder nor the names of its contributors
16+
* may be used to endorse or promote products derived from this software without
17+
* specific prior written permission.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+
* POSSIBILITY OF SUCH DAMAGE.
30+
*/
31+
#define _FILE_OFFSET_BITS 64
32+
#include <ctype.h>
33+
#include <endian.h>
34+
#include <errno.h>
35+
#include <inttypes.h>
36+
#include <stdbool.h>
37+
#include <stdint.h>
38+
#include <stdio.h>
39+
#include <string.h>
40+
#include <unistd.h>
41+
42+
#include "sparse.h"
43+
44+
int sparse_header_parse(int fd, sparse_header_t* sparse_header)
45+
{
46+
lseek(fd, 0, SEEK_SET);
47+
48+
if (read(fd, sparse_header, sizeof(sparse_header_t)) != sizeof(sparse_header_t)) {
49+
fprintf(stderr, "[SPARSE] Unable to read sparse header\n");
50+
return -EINVAL;
51+
}
52+
53+
if (htole32(sparse_header->magic) != htole32(SPARSE_HEADER_MAGIC)) {
54+
fprintf(stderr, "[SPARSE] Invalid magic in sparse header\n");
55+
return -EINVAL;
56+
}
57+
58+
if (htole16(sparse_header->major_version) != htole16(SPARSE_HEADER_MAJOR_VER)) {
59+
fprintf(stderr, "[SPARSE] Invalid major version in sparse header\n");
60+
return -EINVAL;
61+
}
62+
63+
if (htole16(sparse_header->minor_version) != htole16(SPARSE_HEADER_MINOR_VER)) {
64+
fprintf(stderr, "[SPARSE] Invalid minor version in sparse header\n");
65+
return -EINVAL;
66+
}
67+
68+
if (sparse_header->file_hdr_sz > sizeof(sparse_header_t))
69+
lseek(fd, sparse_header->file_hdr_sz - sizeof(sparse_header_t), SEEK_CUR);
70+
71+
return 0;
72+
}
73+
74+
int sparse_chunk_header_parse(int fd, sparse_header_t* sparse_header, unsigned *chunk_size, unsigned *sparse_file_offset)
75+
{
76+
chunk_header_t chunk_header;
77+
78+
*chunk_size = 0;
79+
*sparse_file_offset = 0;
80+
81+
if (read(fd, &chunk_header, sizeof(chunk_header_t)) != sizeof(chunk_header_t)) {
82+
fprintf(stderr, "[SPARSE] Unable to read sparse chunk header\n");
83+
return -EINVAL;
84+
}
85+
86+
if (sparse_header->chunk_hdr_sz > sizeof(chunk_header_t))
87+
lseek(fd, sparse_header->chunk_hdr_sz - sizeof(chunk_header_t), SEEK_CUR);
88+
89+
if (htole16(chunk_header.chunk_type) == htole16(CHUNK_TYPE_RAW)) {
90+
91+
*chunk_size = chunk_header.chunk_sz * sparse_header->blk_sz;
92+
93+
if (chunk_header.total_sz != (sparse_header->chunk_hdr_sz + *chunk_size)) {
94+
fprintf(stderr, "[SPARSE] Bogus chunk size, type Raw\n");
95+
return -EINVAL;
96+
}
97+
98+
*sparse_file_offset = lseek(fd, 0, SEEK_CUR);
99+
lseek(fd, *chunk_size, SEEK_CUR);
100+
}
101+
else if (htole16(chunk_header.chunk_type) == htole16(CHUNK_TYPE_DONT_CARE)) {
102+
103+
*chunk_size = chunk_header.chunk_sz * sparse_header->blk_sz;
104+
if (chunk_header.total_sz != sparse_header->chunk_hdr_sz) {
105+
fprintf(stderr, "[SPARSE] Bogus chunk size, type Don't Care\n");
106+
return -EINVAL;
107+
}
108+
}
109+
else if (htole16(chunk_header.chunk_type) == htole16(CHUNK_TYPE_FILL)) {
110+
fprintf(stderr, "[SPARSE] Fill chunk size doesn't support\n");
111+
return -EINVAL;
112+
}
113+
else {
114+
fprintf(stderr, "[SPARSE] Unknown chunk\n");
115+
return -EINVAL;
116+
}
117+
118+
return 0;
119+
}

sparse.h

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#ifndef __SPARSE_H__
2+
#define __SPARSE_H__
3+
4+
#include <stdint.h>
5+
6+
typedef struct __attribute__((__packed__)) sparse_header {
7+
uint32_t magic; /* 0xed26ff3a */
8+
uint16_t major_version; /* (0x1) - reject images with higher major versions */
9+
uint16_t minor_version; /* (0x0) - allow images with higer minor versions */
10+
uint16_t file_hdr_sz; /* 28 bytes for first revision of the file format */
11+
uint16_t chunk_hdr_sz; /* 12 bytes for first revision of the file format */
12+
uint32_t blk_sz; /* block size in bytes, must be a multiple of 4 (4096) */
13+
uint32_t total_blks; /* total blocks in the non-sparse output image */
14+
uint32_t total_chunks; /* total chunks in the sparse input image */
15+
uint32_t image_checksum; /* CRC32 checksum of the original data, counting "don't care" */
16+
/* as 0. Standard 802.3 polynomial, use a Public Domain */
17+
/* table implementation */
18+
} sparse_header_t;
19+
20+
#define SPARSE_HEADER_MAGIC 0xed26ff3a
21+
#define SPARSE_HEADER_MAJOR_VER 0x0001
22+
#define SPARSE_HEADER_MINOR_VER 0x0000
23+
24+
typedef struct __attribute__((__packed__)) chunk_header {
25+
uint16_t chunk_type; /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
26+
uint16_t reserved1;
27+
uint32_t chunk_sz; /* in blocks in output image */
28+
uint32_t total_sz; /* in bytes of chunk input file including chunk header and data */
29+
} chunk_header_t;
30+
31+
#define CHUNK_TYPE_RAW 0xCAC1
32+
#define CHUNK_TYPE_FILL 0xCAC2
33+
#define CHUNK_TYPE_DONT_CARE 0xCAC3
34+
35+
int sparse_header_parse(int fd, sparse_header_t* sparse_header);
36+
int sparse_chunk_header_parse(int fd, sparse_header_t* sparse_header, unsigned *chunk_size, unsigned *sparse_file_offset);
37+
38+
#endif

0 commit comments

Comments
 (0)