402d3171908122f926bd87dd41304efc53a3fb80
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
18 #if !defined(__BYTE_ORDER)
19 #error "Unknown byte order"
22 #if __BYTE_ORDER == __BIG_ENDIAN
23 #define cpu_to_le32(x) bswap_32(x)
24 #define le32_to_cpu(x) bswap_32(x)
25 #define cpu_to_be32(x) (x)
26 #define be32_to_cpu(x) (x)
27 #define cpu_to_le16(x) bswap_16(x)
28 #define le16_to_cpu(x) bswap_16(x)
29 #define cpu_to_be16(x) (x)
30 #define be16_to_cpu(x) (x)
31 #elif __BYTE_ORDER == __LITTLE_ENDIAN
32 #define cpu_to_le32(x) (x)
33 #define le32_to_cpu(x) (x)
34 #define cpu_to_be32(x) bswap_32(x)
35 #define be32_to_cpu(x) bswap_32(x)
36 #define cpu_to_le16(x) (x)
37 #define le16_to_cpu(x) (x)
38 #define cpu_to_be16(x) bswap_16(x)
39 #define be16_to_cpu(x) bswap_16(x)
41 #error "Unsupported endianness"
44 #define WFI_VERSION 0x00005732
45 #define WFI_VERSION_NAND_1MB_DATA 0x00005731
47 #define WFI_NOR_FLASH 1
48 #define WFI_NAND16_FLASH 2
49 #define WFI_NAND128_FLASH 3
50 #define WFI_NAND256_FLASH 4
51 #define WFI_NAND512_FLASH 5
52 #define WFI_NAND1024_FLASH 6
53 #define WFI_NAND2048_FLASH 7
55 #define WFI_FLAG_HAS_PMC 0x1
56 #define WFI_FLAG_SUPPORTS_BTRM 0x2
58 #define UBI_EC_HDR_MAGIC 0x55424923
62 struct bcm4908img_tail
{
71 * struct bcm4908img_info - info about BCM4908 image
73 * Standard BCM4908 image consists of:
74 * 1. (Optional) vedor header
75 * 2. (Optional) cferom
77 * 4. padding ├─ firmware
81 struct bcm4908img_info
{
85 size_t padding_offset
;
87 uint32_t crc32
; /* Calculated checksum */
88 struct bcm4908img_tail tail
;
93 static inline size_t bcm4908img_min(size_t x
, size_t y
) {
97 /**************************************************
99 **************************************************/
101 static const uint32_t crc32_tbl
[] = {
102 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
103 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
104 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
105 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
106 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
107 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
108 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
109 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
110 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
111 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
112 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
113 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
114 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
115 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
116 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
117 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
118 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
119 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
120 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
121 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
122 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
123 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
124 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
125 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
126 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
127 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
128 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
129 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
130 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
131 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
132 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
133 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
134 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
135 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
136 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
137 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
138 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
139 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
140 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
141 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
142 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
143 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
144 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
145 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
146 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
147 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
148 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
149 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
150 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
151 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
152 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
153 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
154 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
155 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
156 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
157 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
158 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
159 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
160 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
161 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
162 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
163 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
164 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
165 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
168 uint32_t bcm4908img_crc32(uint32_t crc
, const void *buf
, size_t len
) {
169 const uint8_t *in
= buf
;
172 crc
= crc32_tbl
[(crc
^ *in
) & 0xff] ^ (crc
>> 8);
180 /**************************************************
182 **************************************************/
184 static FILE *bcm4908img_open(const char *pathname
, const char *mode
) {
188 return fopen(pathname
, mode
);
190 if (isatty(fileno(stdin
))) {
191 fprintf(stderr
, "Reading from TTY stdin is unsupported\n");
195 if (fstat(fileno(stdin
), &st
)) {
196 fprintf(stderr
, "Failed to fstat stdin: %d\n", -errno
);
200 if (S_ISFIFO(st
.st_mode
)) {
201 fprintf(stderr
, "Reading from pipe stdin is unsupported\n");
208 static void bcm4908img_close(FILE *fp
) {
213 static int bcm4908img_calc_crc32(FILE *fp
, struct bcm4908img_info
*info
) {
218 /* Start with cferom (or bootfs) - skip vendor header */
219 fseek(fp
, info
->cferom_offset
, SEEK_SET
);
221 info
->crc32
= 0xffffffff;
222 length
= info
->file_size
- info
->cferom_offset
- sizeof(struct bcm4908img_tail
);
223 while (length
&& (bytes
= fread(buf
, 1, bcm4908img_min(sizeof(buf
), length
), fp
)) > 0) {
224 info
->crc32
= bcm4908img_crc32(info
->crc32
, buf
, bytes
);
228 fprintf(stderr
, "Failed to read last %zd B of data\n", length
);
235 /**************************************************
236 * Existing firmware parser
237 **************************************************/
243 uint32_t kernel_chksum
;
244 uint32_t rootfs_chksum
;
247 uint32_t image_chksum
;
248 uint32_t header_chksum
;
252 static bool bcm4908img_is_all_ff(const void *buf
, size_t length
)
254 const uint8_t *in
= buf
;
257 for (i
= 0; i
< length
; i
++) {
265 static int bcm4908img_parse(FILE *fp
, struct bcm4908img_info
*info
) {
266 struct bcm4908img_tail
*tail
= &info
->tail
;
267 struct chk_header
*chk
;
275 memset(info
, 0, sizeof(*info
));
279 if (fstat(fileno(fp
), &st
)) {
281 fprintf(stderr
, "Failed to fstat: %d\n", err
);
284 info
->file_size
= st
.st_size
;
289 if (fread(buf
, 1, sizeof(buf
), fp
) != sizeof(buf
)) {
290 fprintf(stderr
, "Failed to read file header\n");
294 if (be32_to_cpu(chk
->magic
) == 0x2a23245e)
295 info
->cferom_offset
= be32_to_cpu(chk
->header_len
);
299 for (info
->bootfs_offset
= info
->cferom_offset
;
300 info
->bootfs_offset
< info
->file_size
;
301 info
->bootfs_offset
+= 0x20000) {
302 if (fseek(fp
, info
->bootfs_offset
, SEEK_SET
)) {
304 fprintf(stderr
, "Failed to fseek to the 0x%zx\n", info
->bootfs_offset
);
307 if (fread(&tmp16
, 1, sizeof(tmp16
), fp
) != sizeof(tmp16
)) {
308 fprintf(stderr
, "Failed to read while looking for JFFS2\n");
311 if (be16_to_cpu(tmp16
) == 0x8519)
314 if (info
->bootfs_offset
>= info
->file_size
) {
315 fprintf(stderr
, "Failed to find bootfs offset\n");
319 for (info
->rootfs_offset
= info
->bootfs_offset
;
320 info
->rootfs_offset
< info
->file_size
;
321 info
->rootfs_offset
+= 0x20000) {
322 uint32_t *magic
= (uint32_t *)&buf
[0];
324 if (fseek(fp
, info
->rootfs_offset
, SEEK_SET
)) {
326 fprintf(stderr
, "Failed to fseek: %d\n", err
);
330 length
= info
->padding_offset
? sizeof(*magic
) : 256;
331 bytes
= fread(buf
, 1, length
, fp
);
332 if (bytes
!= length
) {
333 fprintf(stderr
, "Failed to read %zu bytes\n", length
);
337 if (!info
->padding_offset
&& bcm4908img_is_all_ff(buf
, length
))
338 info
->padding_offset
= info
->rootfs_offset
;
340 if (be32_to_cpu(*magic
) == UBI_EC_HDR_MAGIC
)
343 if (info
->rootfs_offset
>= info
->file_size
) {
344 fprintf(stderr
, "Failed to find rootfs offset\n");
350 /* Start with cferom (or bootfs) - skip vendor header */
351 fseek(fp
, info
->cferom_offset
, SEEK_SET
);
353 info
->crc32
= 0xffffffff;
354 length
= info
->file_size
- info
->cferom_offset
- sizeof(*tail
);
355 while (length
&& (bytes
= fread(buf
, 1, bcm4908img_min(sizeof(buf
), length
), fp
)) > 0) {
356 info
->crc32
= bcm4908img_crc32(info
->crc32
, buf
, bytes
);
360 fprintf(stderr
, "Failed to read last %zd B of data\n", length
);
366 if (fread(tail
, 1, sizeof(*tail
), fp
) != sizeof(*tail
)) {
367 fprintf(stderr
, "Failed to read BCM4908 image tail\n");
371 /* Standard validation */
373 if (info
->crc32
!= le32_to_cpu(tail
->crc32
)) {
374 fprintf(stderr
, "Invalid data crc32: 0x%08x instead of 0x%08x\n", info
->crc32
, le32_to_cpu(tail
->crc32
));
381 /**************************************************
383 **************************************************/
385 static int bcm4908img_info(int argc
, char **argv
) {
386 struct bcm4908img_info info
;
387 const char *pathname
= NULL
;
392 while ((c
= getopt(argc
, argv
, "i:")) != -1) {
400 fp
= bcm4908img_open(pathname
, "r");
402 fprintf(stderr
, "Failed to open BCM4908 image\n");
407 err
= bcm4908img_parse(fp
, &info
);
409 fprintf(stderr
, "Failed to parse BCM4908 image\n");
413 if (info
.bootfs_offset
!= info
.cferom_offset
)
414 printf("cferom offset:\t%zu\n", info
.cferom_offset
);
415 printf("bootfs offset:\t0x%zx\n", info
.bootfs_offset
);
416 if (info
.padding_offset
)
417 printf("padding offset:\t0x%zx\n", info
.padding_offset
);
418 printf("rootfs offset:\t0x%zx\n", info
.rootfs_offset
);
419 printf("Checksum:\t0x%08x\n", info
.crc32
);
422 bcm4908img_close(fp
);
427 /**************************************************
429 **************************************************/
431 static ssize_t
bcm4908img_create_append_file(FILE *trx
, const char *in_path
, uint32_t *crc32
) {
437 in
= fopen(in_path
, "r");
439 fprintf(stderr
, "Failed to open %s\n", in_path
);
443 while ((bytes
= fread(buf
, 1, sizeof(buf
), in
)) > 0) {
444 if (fwrite(buf
, 1, bytes
, trx
) != bytes
) {
445 fprintf(stderr
, "Failed to write %zu B to %s\n", bytes
, pathname
);
449 *crc32
= bcm4908img_crc32(*crc32
, buf
, bytes
);
458 static ssize_t
bcm4908img_create_append_zeros(FILE *trx
, size_t length
) {
461 buf
= malloc(length
);
464 memset(buf
, 0, length
);
466 if (fwrite(buf
, 1, length
, trx
) != length
) {
467 fprintf(stderr
, "Failed to write %zu B to %s\n", length
, pathname
);
477 static ssize_t
bcm4908img_create_align(FILE *trx
, size_t cur_offset
, size_t alignment
) {
478 if (cur_offset
& (alignment
- 1)) {
479 size_t length
= alignment
- (cur_offset
% alignment
);
480 return bcm4908img_create_append_zeros(trx
, length
);
486 static int bcm4908img_create(int argc
, char **argv
) {
487 struct bcm4908img_tail tail
= {
488 .version
= cpu_to_le32(WFI_VERSION
),
489 .chip_id
= cpu_to_le32(0x4908),
490 .flash_type
= cpu_to_le32(WFI_NAND128_FLASH
),
491 .flags
= cpu_to_le32(WFI_FLAG_SUPPORTS_BTRM
),
493 uint32_t crc32
= 0xffffffff;
494 size_t cur_offset
= 0;
501 fprintf(stderr
, "No BCM4908 image pathname passed\n");
507 fp
= fopen(pathname
, "w+");
509 fprintf(stderr
, "Failed to open %s\n", pathname
);
515 while ((c
= getopt(argc
, argv
, "f:a:A:")) != -1) {
518 bytes
= bcm4908img_create_append_file(fp
, optarg
, &crc32
);
520 fprintf(stderr
, "Failed to append file %s\n", optarg
);
526 bytes
= bcm4908img_create_align(fp
, cur_offset
, strtol(optarg
, NULL
, 0));
528 fprintf(stderr
, "Failed to append zeros\n");
533 bytes
= strtol(optarg
, NULL
, 0) - cur_offset
;
535 fprintf(stderr
, "Current BCM4908 image length is 0x%zx, can't pad it with zeros to 0x%lx\n", cur_offset
, strtol(optarg
, NULL
, 0));
537 bytes
= bcm4908img_create_append_zeros(fp
, bytes
);
539 fprintf(stderr
, "Failed to append zeros\n");
549 tail
.crc32
= cpu_to_le32(crc32
);
551 bytes
= fwrite(&tail
, 1, sizeof(tail
), fp
);
552 if (bytes
!= sizeof(tail
)) {
553 fprintf(stderr
, "Failed to write BCM4908 image tail to %s\n", pathname
);
563 /**************************************************
565 **************************************************/
567 static int bcm4908img_extract(int argc
, char **argv
) {
568 struct bcm4908img_info info
;
569 const char *pathname
= NULL
;
570 const char *type
= NULL
;
579 while ((c
= getopt(argc
, argv
, "i:t:")) != -1) {
590 fp
= bcm4908img_open(pathname
, "r");
592 fprintf(stderr
, "Failed to open BCM4908 image\n");
597 err
= bcm4908img_parse(fp
, &info
);
599 fprintf(stderr
, "Failed to parse BCM4908 image\n");
605 fprintf(stderr
, "No data to extract specified\n");
607 } else if (!strcmp(type
, "cferom")) {
608 offset
= info
.cferom_offset
;
609 length
= info
.bootfs_offset
- offset
;
612 fprintf(stderr
, "This BCM4908 image doesn't contain cferom\n");
615 } else if (!strcmp(type
, "bootfs")) {
616 offset
= info
.bootfs_offset
;
617 length
= (info
.padding_offset
? info
.padding_offset
: info
.rootfs_offset
) - offset
;
618 } else if (!strcmp(type
, "rootfs")) {
619 offset
= info
.rootfs_offset
;
620 length
= info
.file_size
- offset
- sizeof(struct bcm4908img_tail
);
621 } else if (!strcmp(type
, "firmware")) {
622 offset
= info
.bootfs_offset
;
623 length
= info
.file_size
- offset
- sizeof(struct bcm4908img_tail
);
626 fprintf(stderr
, "Unsupported extract type: %s\n", type
);
632 fprintf(stderr
, "Failed to find requested data in input image\n");
636 fseek(fp
, offset
, SEEK_SET
);
637 while (length
&& (bytes
= fread(buf
, 1, bcm4908img_min(sizeof(buf
), length
), fp
)) > 0) {
638 fwrite(buf
, bytes
, 1, stdout
);
643 fprintf(stderr
, "Failed to read last %zd B of data\n", length
);
648 bcm4908img_close(fp
);
653 /**************************************************
655 **************************************************/
657 #define JFFS2_MAGIC_BITMASK 0x1985
659 #define JFFS2_COMPR_NONE 0x00
660 #define JFFS2_COMPR_ZERO 0x01
661 #define JFFS2_COMPR_RTIME 0x02
662 #define JFFS2_COMPR_RUBINMIPS 0x03
663 #define JFFS2_COMPR_COPY 0x04
664 #define JFFS2_COMPR_DYNRUBIN 0x05
665 #define JFFS2_COMPR_ZLIB 0x06
666 #define JFFS2_COMPR_LZO 0x07
667 /* Compatibility flags. */
668 #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
669 #define JFFS2_NODE_ACCURATE 0x2000
670 /* INCOMPAT: Fail to mount the filesystem */
671 #define JFFS2_FEATURE_INCOMPAT 0xc000
672 /* ROCOMPAT: Mount read-only */
673 #define JFFS2_FEATURE_ROCOMPAT 0x8000
674 /* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */
675 #define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000
676 /* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */
677 #define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000
679 #define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
683 } __attribute__((packed
)) jint32_t
;
687 } __attribute__((packed
)) jint16_t
;
689 struct jffs2_unknown_node
691 /* All start like this */
694 jint32_t totlen
; /* So we can skip over nodes we don't grok */
698 struct jffs2_raw_dirent
701 jint16_t nodetype
; /* == JFFS2_NODETYPE_DIRENT */
706 jint32_t ino
; /* == zero for unlink */
716 #define je16_to_cpu(x) ((x).v16)
717 #define je32_to_cpu(x) ((x).v32)
719 static int bcm4908img_bootfs_ls(FILE *fp
, struct bcm4908img_info
*info
) {
720 struct jffs2_unknown_node node
;
721 struct jffs2_raw_dirent dirent
;
726 for (offset
= info
->bootfs_offset
; ; offset
+= (je32_to_cpu(node
.totlen
) + 0x03) & ~0x03) {
727 char name
[FILENAME_MAX
+ 1];
729 if (fseek(fp
, offset
, SEEK_SET
)) {
731 fprintf(stderr
, "Failed to fseek: %d\n", err
);
735 bytes
= fread(&node
, 1, sizeof(node
), fp
);
736 if (bytes
!= sizeof(node
)) {
737 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
741 if (je16_to_cpu(node
.magic
) != JFFS2_MAGIC_BITMASK
) {
745 if (je16_to_cpu(node
.nodetype
) != JFFS2_NODETYPE_DIRENT
) {
749 memcpy(&dirent
, &node
, sizeof(node
));
750 bytes
+= fread((uint8_t *)&dirent
+ sizeof(node
), 1, sizeof(dirent
) - sizeof(node
), fp
);
751 if (bytes
!= sizeof(dirent
)) {
752 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
756 if (dirent
.nsize
+ 1 > sizeof(name
)) {
757 /* Keep reading & printing BUT exit with error code */
758 fprintf(stderr
, "Too long filename\n");
763 bytes
= fread(name
, 1, dirent
.nsize
, fp
);
764 if (bytes
!= dirent
.nsize
) {
765 fprintf(stderr
, "Failed to read filename\n");
770 printf("%s\n", name
);
776 static int bcm4908img_bootfs_mv(FILE *fp
, struct bcm4908img_info
*info
, int argc
, char **argv
) {
777 struct jffs2_unknown_node node
;
778 struct jffs2_raw_dirent dirent
;
785 if (argc
- optind
< 2) {
786 fprintf(stderr
, "No enough arguments passed\n");
789 oldname
= argv
[optind
++];
790 newname
= argv
[optind
++];
792 if (strlen(newname
) != strlen(oldname
)) {
793 fprintf(stderr
, "New filename must have the same length as the old one\n");
797 for (offset
= info
->bootfs_offset
; ; offset
+= (je32_to_cpu(node
.totlen
) + 0x03) & ~0x03) {
798 char name
[FILENAME_MAX
];
801 if (fseek(fp
, offset
, SEEK_SET
)) {
803 fprintf(stderr
, "Failed to fseek: %d\n", err
);
807 bytes
= fread(&node
, 1, sizeof(node
), fp
);
808 if (bytes
!= sizeof(node
)) {
809 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
813 if (je16_to_cpu(node
.magic
) != JFFS2_MAGIC_BITMASK
) {
817 if (je16_to_cpu(node
.nodetype
) != JFFS2_NODETYPE_DIRENT
) {
821 bytes
+= fread((uint8_t *)&dirent
+ sizeof(node
), 1, sizeof(dirent
) - sizeof(node
), fp
);
822 if (bytes
!= sizeof(dirent
)) {
823 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
827 if (dirent
.nsize
+ 1 > sizeof(name
)) {
828 fprintf(stderr
, "Too long filename\n");
833 bytes
= fread(name
, 1, dirent
.nsize
, fp
);
834 if (bytes
!= dirent
.nsize
) {
835 fprintf(stderr
, "Failed to read filename\n");
841 printf("offset:%08zx name_crc:%04x filename:%s\n", offset
, je32_to_cpu(dirent
.name_crc
), name
);
843 if (strcmp(name
, oldname
)) {
847 if (fseek(fp
, offset
+ offsetof(struct jffs2_raw_dirent
, name_crc
), SEEK_SET
)) {
849 fprintf(stderr
, "Failed to fseek: %d\n", err
);
852 crc32
= bcm4908img_crc32(0, newname
, dirent
.nsize
);
853 bytes
= fwrite(&crc32
, 1, sizeof(crc32
), fp
);
854 if (bytes
!= sizeof(crc32
)) {
855 fprintf(stderr
, "Failed to write new CRC32\n");
859 if (fseek(fp
, offset
+ offsetof(struct jffs2_raw_dirent
, name
), SEEK_SET
)) {
861 fprintf(stderr
, "Failed to fseek: %d\n", err
);
864 bytes
= fwrite(newname
, 1, dirent
.nsize
, fp
);
865 if (bytes
!= dirent
.nsize
) {
866 fprintf(stderr
, "Failed to write new filename\n");
870 /* Calculate new BCM4908 image checksum */
872 err
= bcm4908img_calc_crc32(fp
, info
);
874 fprintf(stderr
, "Failed to write new filename\n");
878 info
->tail
.crc32
= cpu_to_le32(info
->crc32
);
879 if (fseek(fp
, -sizeof(struct bcm4908img_tail
), SEEK_END
)) {
881 fprintf(stderr
, "Failed to write new filename\n");
885 if (fwrite(&info
->tail
, 1, sizeof(struct bcm4908img_tail
), fp
) != sizeof(struct bcm4908img_tail
)) {
886 fprintf(stderr
, "Failed to write updated tail\n");
890 printf("Successfully renamed %s to the %s\n", oldname
, newname
);
895 fprintf(stderr
, "Failed to find %s\n", oldname
);
900 static int bcm4908img_bootfs(int argc
, char **argv
) {
901 struct bcm4908img_info info
;
902 const char *pathname
= NULL
;
909 while ((c
= getopt(argc
, argv
, "i:")) != -1) {
917 if (argc
- optind
< 1) {
918 fprintf(stderr
, "No bootfs command specified\n");
922 cmd
= argv
[optind
++];
924 mode
= strcmp(cmd
, "mv") ? "r" : "r+";
925 fp
= bcm4908img_open(pathname
, mode
);
927 fprintf(stderr
, "Failed to open BCM4908 image\n");
932 err
= bcm4908img_parse(fp
, &info
);
934 fprintf(stderr
, "Failed to parse BCM4908 image\n");
938 if (!strcmp(cmd
, "ls")) {
939 err
= bcm4908img_bootfs_ls(fp
, &info
);
940 } else if (!strcmp(cmd
, "mv")) {
941 err
= bcm4908img_bootfs_mv(fp
, &info
, argc
, argv
);
944 fprintf(stderr
, "Unsupported bootfs command: %s\n", cmd
);
948 bcm4908img_close(fp
);
953 /**************************************************
955 **************************************************/
957 static void usage() {
960 printf("Info about a BCM4908 image:\n");
961 printf("\tbcm4908img info <options>\n");
962 printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
964 printf("Creating a new BCM4908 image:\n");
965 printf("\tbcm4908img create <file> [options]\n");
966 printf("\t-f file\t\t\t\tadd data from specified file\n");
967 printf("\t-a alignment\t\t\tpad image with zeros to specified alignment\n");
968 printf("\t-A offset\t\t\t\tappend zeros until reaching specified offset\n");
970 printf("Extracting from a BCM4908 image:\n");
971 printf("\tbcm4908img extract <options>\n");
972 printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
973 printf("\t-t <type>\t\t\t\tone of: cferom, bootfs, rootfs, firmware\n");
975 printf("Access bootfs in a BCM4908 image:\n");
976 printf("\tbcm4908img bootfs <options> <command> <arguments>\n");
977 printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
978 printf("\tls\t\t\t\t\tlist bootfs files\n");
979 printf("\tmv <source> <dest>\t\t\trename bootfs file\n");
982 int main(int argc
, char **argv
) {
985 if (!strcmp(argv
[1], "info"))
986 return bcm4908img_info(argc
, argv
);
987 else if (!strcmp(argv
[1], "create"))
988 return bcm4908img_create(argc
, argv
);
989 else if (!strcmp(argv
[1], "extract"))
990 return bcm4908img_extract(argc
, argv
);
991 else if (!strcmp(argv
[1], "bootfs"))
992 return bcm4908img_bootfs(argc
, argv
);