Skip to content

Commit 92fd16d

Browse files
committed
add support sparse attribute
1 parent da722fe commit 92fd16d

File tree

6 files changed

+331
-17
lines changed

6 files changed

+331
-17
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ CFLAGS += -O2 -Wall -g `pkg-config --cflags libxml-2.0 libusb-1.0`
66
LDFLAGS += `pkg-config --libs libxml-2.0 libusb-1.0`
77
prefix := /usr/local
88

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

1212
RAMDUMP_SRCS := ramdump.c sahara.c usb.c util.c ux.c

firehose.c

+38-15
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include <unistd.h>
5151
#include <libxml/parser.h>
5252
#include <libxml/tree.h>
53+
#include "sparse.h"
5354
#include "qdl.h"
5455
#include "ufs.h"
5556

@@ -359,21 +360,24 @@ static int firehose_program(struct qdl_device *qdl, struct program *program, int
359360
int left;
360361
int ret;
361362
int n;
363+
uint32_t fill_value;
362364

363365
num_sectors = program->num_sectors;
364366

365367
ret = fstat(fd, &sb);
366368
if (ret < 0)
367369
err(1, "failed to stat \"%s\"\n", program->filename);
368370

369-
num_sectors = (sb.st_size + program->sector_size - 1) / program->sector_size;
371+
if (!program->sparse) {
372+
num_sectors = (sb.st_size + program->sector_size - 1) / program->sector_size;
370373

371-
if (program->num_sectors && num_sectors > program->num_sectors) {
372-
ux_err("%s to big for %s truncated to %d\n",
373-
program->filename,
374-
program->label,
375-
program->num_sectors * program->sector_size);
376-
num_sectors = program->num_sectors;
374+
if (program->num_sectors && num_sectors > program->num_sectors) {
375+
ux_err("%s to big for %s truncated to %d\n",
376+
program->filename,
377+
program->label,
378+
program->num_sectors * program->sector_size);
379+
num_sectors = program->num_sectors;
380+
}
377381
}
378382

379383
buf = malloc(max_payload_size);
@@ -411,19 +415,38 @@ static int firehose_program(struct qdl_device *qdl, struct program *program, int
411415

412416
t0 = time(NULL);
413417

414-
lseek(fd, (off_t) program->file_offset * program->sector_size, SEEK_SET);
418+
if (!program->sparse)
419+
lseek(fd, (off_t) program->file_offset * program->sector_size, SEEK_SET);
420+
else {
421+
switch (program->sparse_chunk_type) {
422+
case CHUNK_TYPE_RAW:
423+
lseek(fd, (off_t) program->sparse_chunk_data, SEEK_SET);
424+
break;
425+
case CHUNK_TYPE_FILL:
426+
fill_value = (uint32_t) program->sparse_chunk_data;
427+
for (n = 0; n < max_payload_size; n += sizeof(fill_value))
428+
memcpy(buf + n, &fill_value, sizeof(fill_value));
429+
break;
430+
default:
431+
fprintf(stderr, "[SPARSE] invalid chunk type\n");
432+
goto out;
433+
}
434+
}
435+
415436
left = num_sectors;
416437
while (left > 0) {
417438
chunk_size = MIN(max_payload_size / program->sector_size, left);
418439

419-
n = read(fd, buf, chunk_size * program->sector_size);
420-
if (n < 0) {
421-
ux_err("failed to read %s\n", program->filename);
422-
goto out;
423-
}
440+
if (!program->sparse || program->sparse_chunk_type != CHUNK_TYPE_FILL) {
441+
n = read(fd, buf, chunk_size * program->sector_size);
442+
if (n < 0) {
443+
ux_err("failed to read %s\n", program->filename);
444+
goto out;
445+
}
424446

425-
if (n < max_payload_size)
426-
memset(buf + n, 0, max_payload_size - n);
447+
if (n < max_payload_size)
448+
memset(buf + n, 0, max_payload_size - n);
449+
}
427450

428451
n = qdl_write(qdl, buf, chunk_size * program->sector_size);
429452
if (n < 0) {

program.c

+101-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,90 @@ 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, chunk_type, chunk_data;
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+
chunk_type = sparse_chunk_header_parse(fd, &sparse_header, &chunk_size, &chunk_data);
112+
113+
switch (chunk_type) {
114+
case CHUNK_TYPE_RAW:
115+
case CHUNK_TYPE_FILL:
116+
case CHUNK_TYPE_DONT_CARE:
117+
break;
118+
default:
119+
fprintf(stderr, "[PROGRAM] Unable to parse sparse chunk %i at %s...failed\n",
120+
i, program->filename);
121+
return NULL;
122+
}
123+
124+
if (chunk_size == 0)
125+
continue;
126+
127+
if (chunk_size % program->sector_size != 0) {
128+
fprintf(stderr, "[SPARSE] File chunk #%u size %u is not a sector-multiple\n",
129+
i, chunk_size);
130+
return NULL;
131+
}
132+
133+
switch (chunk_type) {
134+
case CHUNK_TYPE_RAW:
135+
case CHUNK_TYPE_FILL:
136+
137+
program_sparse = calloc(1, sizeof(struct program));
138+
memcpy(program_sparse, program, sizeof(struct program));
139+
140+
program_sparse->next = NULL;
141+
program_sparse->num_sectors = chunk_size / program->sector_size;
142+
143+
program_sparse->sparse_chunk_type = chunk_type;
144+
program_sparse->sparse_chunk_data = chunk_data;
145+
146+
if (programes_sparse) {
147+
programes_sparse_last->next = program_sparse;
148+
programes_sparse_last = program_sparse;
149+
} else {
150+
programes_sparse = program_sparse;
151+
programes_sparse_last = program_sparse;
152+
}
153+
154+
break;
155+
default:
156+
break;
157+
}
158+
159+
start_sector = (unsigned int) strtoul(program->start_sector, NULL, 0);
160+
start_sector += chunk_size / program->sector_size;
161+
sprintf(tmp, "%u", start_sector);
162+
program->start_sector = strdup(tmp);
163+
}
164+
165+
return programes_sparse;
166+
}
167+
83168
static int load_program_tag(xmlNode *node, bool is_nand)
84169
{
85170
struct program *program;
@@ -164,6 +249,7 @@ int program_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl,
164249
const char *incdir, bool allow_missing)
165250
{
166251
struct program *program;
252+
struct program *program_sparse;
167253
const char *filename;
168254
char tmp[PATH_MAX];
169255
int ret;
@@ -192,7 +278,21 @@ int program_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl,
192278
continue;
193279
}
194280

195-
ret = apply(qdl, program, fd);
281+
if (!program->sparse) {
282+
ret = apply(qdl, program, fd);
283+
} else {
284+
program_sparse = program_load_sparse(program, fd);
285+
if (!program_sparse) {
286+
fprintf(stderr, "[PROGRAM] load sparse failed\n");
287+
return -EINVAL;
288+
}
289+
290+
for (; program_sparse; program_sparse = program_sparse->next) {
291+
ret = apply(qdl, program_sparse, fd);
292+
if (ret)
293+
break;
294+
}
295+
}
196296

197297
close(fd);
198298
if (ret)

program.h

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

22+
unsigned sparse_chunk_type;
23+
unsigned sparse_chunk_data;
24+
2225
struct program *next;
2326
};
2427

sparse.c

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
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 <arpa/inet.h>
33+
#include <ctype.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 (ntohl(sparse_header->magic) != ntohl(SPARSE_HEADER_MAGIC)) {
54+
fprintf(stderr, "[SPARSE] Invalid magic in sparse header\n");
55+
return -EINVAL;
56+
}
57+
58+
if (ntohs(sparse_header->major_version) != ntohs(SPARSE_HEADER_MAJOR_VER)) {
59+
fprintf(stderr, "[SPARSE] Invalid major version in sparse header\n");
60+
return -EINVAL;
61+
}
62+
63+
if (ntohs(sparse_header->minor_version) != ntohs(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 *value)
75+
{
76+
chunk_header_t chunk_header;
77+
uint32_t fill_value = 0;
78+
79+
*chunk_size = 0;
80+
*value = 0;
81+
82+
if (read(fd, &chunk_header, sizeof(chunk_header_t)) != sizeof(chunk_header_t)) {
83+
fprintf(stderr, "[SPARSE] Unable to read sparse chunk header\n");
84+
return -EINVAL;
85+
}
86+
87+
if (sparse_header->chunk_hdr_sz > sizeof(chunk_header_t))
88+
lseek(fd, sparse_header->chunk_hdr_sz - sizeof(chunk_header_t), SEEK_CUR);
89+
90+
if (ntohs(chunk_header.chunk_type) == ntohs(CHUNK_TYPE_RAW)) {
91+
92+
*chunk_size = chunk_header.chunk_sz * sparse_header->blk_sz;
93+
94+
if (chunk_header.total_sz != (sparse_header->chunk_hdr_sz + *chunk_size)) {
95+
fprintf(stderr, "[SPARSE] Bogus chunk size, type Raw\n");
96+
return -EINVAL;
97+
}
98+
99+
/* Save the current file offset in the 'value' variable */
100+
*value = lseek(fd, 0, SEEK_CUR);
101+
102+
/* Move the file cursor forward by the size of the chunk */
103+
lseek(fd, *chunk_size, SEEK_CUR);
104+
105+
return CHUNK_TYPE_RAW;
106+
}
107+
else if (ntohs(chunk_header.chunk_type) == ntohs(CHUNK_TYPE_DONT_CARE)) {
108+
109+
*chunk_size = chunk_header.chunk_sz * sparse_header->blk_sz;
110+
111+
if (chunk_header.total_sz != sparse_header->chunk_hdr_sz) {
112+
fprintf(stderr, "[SPARSE] Bogus chunk size, type Don't Care\n");
113+
return -EINVAL;
114+
}
115+
116+
return CHUNK_TYPE_DONT_CARE;
117+
}
118+
else if (ntohs(chunk_header.chunk_type) == ntohs(CHUNK_TYPE_FILL)) {
119+
120+
*chunk_size = chunk_header.chunk_sz * sparse_header->blk_sz;
121+
122+
if (chunk_header.total_sz != (sparse_header->chunk_hdr_sz + sizeof(fill_value))) {
123+
fprintf(stderr, "[SPARSE] Bogus chunk size, type Fill\n");
124+
return -EINVAL;
125+
}
126+
127+
if (read(fd, &fill_value, sizeof(fill_value)) != sizeof(fill_value)) {
128+
fprintf(stderr, "[SPARSE] Unable to read fill value\n");
129+
return -EINVAL;
130+
}
131+
132+
/* Save the current fill value in the 'value' variable */
133+
*value = ntohl(fill_value);
134+
135+
return CHUNK_TYPE_FILL;
136+
}
137+
138+
fprintf(stderr, "[SPARSE] Unknown chunk\n");
139+
return -EINVAL;
140+
}

0 commit comments

Comments
 (0)