twintig: Be less verbose by default
[svpe-tools.git] / zestig.c
blob85f1ea0c389bb0963ecf2ed59bf6ef5364a2fa2a
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <sys/mman.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <string.h>
7 #include <stdio.h>
9 #include "tools.h"
11 static const u8 *rom;
12 static const u8 *super;
13 static const u8 *fat;
14 static const u8 *fst;
16 static u8 key[16];
18 static const u8 *map_rom(const char *name)
20 int fd = open(name, O_RDONLY);
21 void *map = mmap(0, 0x20000000, PROT_READ, MAP_SHARED, fd, 0);
22 close(fd);
23 return map;
26 static const u8 *find_super(void)
28 u32 newest = 0;
29 const u8 *super = 0, *p;
31 for (p = rom + 0x1fc00000; p < rom + 0x20000000; p += 0x40000)
32 if (be32(p) == 0x53464653) {
33 u32 version = be32(p + 4);
34 if (super == 0 || version > newest) {
35 super = p;
36 newest = version;
40 return super;
43 static void print_mode(u8 mode)
45 int i;
46 const char dir[4] = "?-d?";
47 const char perm[3] = "-rw";
49 fprintf(stderr, "%c", dir[mode & 3]);
50 for (i = 0; i < 3; i++) {
51 fprintf(stderr, "%c", perm[(mode >> 6) & 1]);
52 fprintf(stderr, "%c", perm[(mode >> 6) & 2]);
53 mode <<= 2;
57 static void print_entry(const u8 *entry)
59 char name[13];
60 u8 mode, attr;
61 u16 sub, sib;
62 u32 size;
63 u16 x1, uid, gid;
64 u32 x3;
66 memcpy(name, entry, 12);
67 name[12] = 0;
68 mode = entry[0x0c];
69 attr = entry[0x0d];
70 sub = be16(entry + 0x0e);
71 sib = be16(entry + 0x10);
72 size = be32(entry + 0x12);
73 x1 = be16(entry + 0x16);
74 uid = be16(entry + 0x18);
75 gid = be16(entry + 0x1a);
76 x3 = be32(entry + 0x1c);
78 print_mode(mode);
79 fprintf(stderr, " %02x %04x %04x %08x (%04x %08x) %s\n",
80 attr, uid, gid, size, x1, x3, name);
83 static u8 block[0x4000];
85 static void do_file(const u8 *entry, const char *parent_path)
87 char name[13];
88 char path[256];
89 u8 iv[16];
90 u16 sub;
91 u32 size, this_size;
92 FILE *fp;
94 memcpy(name, entry, 12);
95 name[12] = 0;
96 sub = be16(entry + 0x0e);
97 size = be32(entry + 0x12);
99 if (parent_path[strlen(parent_path) - 1] == '/' || name[0] == '/')
100 sprintf(path, "%s%s", parent_path, name);
101 else
102 sprintf(path, "%s/%s", parent_path, name);
104 fp = fopen(path + 1, "wb");
106 while (size) {
107 this_size = size > 0x4000 ? 0x4000 : size;
109 memset(iv, 0, sizeof iv);
110 aes_cbc_dec(key, iv, (u8 *)rom + 0x4000*sub, 0x4000, block);
112 fwrite(block, 1, this_size, fp);
114 size -= this_size;
115 sub = be16(fat + 2*sub);
118 fclose(fp);
121 static void do_entry(const u8 *entry, const char *parent_path);
123 static void print_dir_entries(const u8 *entry)
125 u16 sib;
127 sib = be16(entry + 0x10);
129 if (sib != 0xffff)
130 print_dir_entries(fst + 0x20*sib);
132 print_entry(entry);
135 static void do_dir(const u8 *entry, const char *parent_path)
137 char name[13];
138 char path[256];
139 u16 sub, sib;
141 memcpy(name, entry, 12);
142 name[12] = 0;
143 sub = be16(entry + 0x0e);
144 sib = be16(entry + 0x10);
146 if (parent_path[strlen(parent_path) - 1] == '/' || name[0] == '/')
147 sprintf(path, "%s%s", parent_path, name);
148 else
149 sprintf(path, "%s/%s", parent_path, name);
150 fprintf(stderr, "%s:\n", path);
151 if (sub != 0xffff)
152 print_dir_entries(fst + 0x20*sub);
153 fprintf(stderr, "\n");
155 if (path[1])
156 mkdir(path + 1, 0777);
158 if (sub != 0xffff)
159 do_entry(fst + 0x20*sub, path);
162 static void do_entry(const u8 *entry, const char *parent_path)
164 u8 mode;
165 u16 sib;
167 mode = entry[0x0c];
168 sib = be16(entry + 0x10);
170 if (sib != 0xffff)
171 do_entry(fst + 0x20*sib, parent_path);
173 mode &= 3;
175 switch(mode) {
176 case 1:
177 do_file(entry, parent_path);
178 break;
179 case 2:
180 do_dir(entry, parent_path);
181 break;
182 default:
183 fprintf(stderr, "unknown mode! (%d)\n", mode);
187 int main(int argc, char **argv)
189 get_key("default/nand-key", key, 16);
191 rom = map_rom(argv[1]);
192 super = find_super();
193 fat = super + 0x0c;
194 fst = fat + 0x10000;
196 mkdir(argv[2], 0777);
197 chdir(argv[2]);
198 do_entry(fst, "");
199 chdir("..");
201 return 0;