Skip to content

Commit bb5a3dc

Browse files
committed
add support sparse attribute
1 parent 1906e7d commit bb5a3dc

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
@@ -5,7 +5,7 @@ CFLAGS += -O2 -Wall -g `pkg-config --cflags libxml-2.0 libusb-1.0`
55
LDFLAGS += `pkg-config --libs libxml-2.0 libusb-1.0`
66
prefix := /usr/local
77

8-
QDL_SRCS := firehose.c qdl.c sahara.c util.c patch.c program.c read.c ufs.c usb.c
8+
QDL_SRCS := firehose.c qdl.c sahara.c util.c patch.c program.c read.c ufs.c usb.c sparse.c
99
QDL_OBJS := $(QDL_SRCS:.c=.o)
1010

1111
RAMDUMP_SRCS := ramdump.c sahara.c usb.c util.c

firehose.c

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

357-
num_sectors = (sb.st_size + program->sector_size - 1) / program->sector_size;
358-
359-
if (program->num_sectors && num_sectors > program->num_sectors) {
360-
fprintf(stderr, "[PROGRAM] %s truncated to %d\n",
361-
program->label,
362-
program->num_sectors * program->sector_size);
363-
num_sectors = program->num_sectors;
357+
if (!program->sparse) {
358+
num_sectors = (sb.st_size + program->sector_size - 1) / program->sector_size;
359+
360+
if (program->num_sectors && num_sectors > program->num_sectors) {
361+
fprintf(stderr, "[PROGRAM] %s truncated to %d\n",
362+
program->label,
363+
program->num_sectors * program->sector_size);
364+
num_sectors = program->num_sectors;
365+
}
364366
}
365367

366368
buf = malloc(max_payload_size);
@@ -398,7 +400,10 @@ static int firehose_program(struct qdl_device *qdl, struct program *program, int
398400

399401
t0 = time(NULL);
400402

401-
lseek(fd, (off_t) program->file_offset * program->sector_size, SEEK_SET);
403+
if (program->sparse)
404+
lseek(fd, (off_t) program->sparse_file_offset, SEEK_SET);
405+
else
406+
lseek(fd, (off_t) program->file_offset * program->sector_size, SEEK_SET);
402407
left = num_sectors;
403408
while (left > 0) {
404409
chunk_size = MIN(max_payload_size / program->sector_size, left);

program.c

+85-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
#include "program.h"
4040
#include "qdl.h"
41+
#include "sparse.h"
4142

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

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

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

192276
close(fd);
193277
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)