-
Notifications
You must be signed in to change notification settings - Fork 1
/
imoo.cc
128 lines (115 loc) · 3.54 KB
/
imoo.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "rawpod.h"
#include "vfs.h"
#include "device.h"
#include <getopt.h>
struct cow_hdr
{
#define COW_MAGIC 0x574F4372 /* 'rCOW' */
u32 magic;
u32 dummy;
u64 blocks;
} __attribute__ ((packed));
#define COW_HDR_SIZE 16
void usage (int exitcode)
{
fprintf (stderr,
"Usage: imoo [-i DEVICE] COWFILE\n"
" If no [device] is specified, searches for the iPod as usual.\n"
"\n"
"Writes a COW file back to a device it was used with.\n");
exit (exitcode);
}
int main (int argc, char **argv)
{
signed char ch;
while ((ch = getopt (argc, argv, "h" RAWPOD_OPTIONS_STR)) != EOF) switch (ch) {
case 'h':
usage (0);
break;
default:
if (rawpod_parse_option (ch, optarg))
break;
case '?':
usage (1);
break;
}
argc -= optind;
argv += optind;
if (argc < 1 || !argv[0])
usage (1);
const char *cowfile = argv[0];
int podloc = find_iPod();
LocalRawDevice *device = new LocalRawDevice (podloc);
LocalFile *cow = new LocalFile (cowfile, OPEN_READ);
if (device->error()) {
fprintf (stderr, "Error opening iPod (%d)\n", device->error());
exit (2);
}
if (cow->error()) {
fprintf (stderr, "Error opening COW file (%d)\n", cow->error());
exit (3);
}
struct cow_hdr hdr;
cow->read (&hdr, COW_HDR_SIZE);
if (hdr.magic != COW_MAGIC) {
fprintf (stderr, "%s is not a COW file\n", cowfile);
exit (4);
}
if (hdr.blocks != device->size()) {
fprintf (stderr, "%s is a COW file, but not for this device (size=%lld when it should be %lld)\n",
cowfile, hdr.blocks, device->size());
exit (5);
}
// Load the block bitmap.
int lastblk = 0;
int nblk = 0;
int blkmapsize = hdr.blocks >> 3;
int blkmapoff = 0;
int blkmapleft = 0;
char *blkmapsec = new char[device->blocksize()];
while (blkmapoff < blkmapsize) {
if (blkmapleft <= 0) {
cow->read (blkmapsec, device->blocksize());
blkmapleft = device->blocksize();
}
int x = blkmapsec[blkmapoff & (device->blocksize() - 1)];
if (x != 0) {
lastblk = (blkmapoff + 1) << 3;
for (int i = 0; i < 8; i++) {
if (x & (1 << i)) nblk++;
}
}
blkmapoff++;
blkmapleft--;
}
printf ("COW file has %d sectors.\n", nblk);
char *buf = new char[device->blocksize()];
char *blkmap = new char[lastblk >> 3];
cow->lseek (COW_HDR_SIZE, SEEK_SET);
cow->read (blkmap, hdr.blocks >> 3);
char *blkend = blkmap + (lastblk >> 3);
int bs = device->blocksizeBits();
int sector = 0;
int blksofar = 0;
while (blkmap != blkend) {
if (*blkmap != 0) {
int x = *blkmap;
for (int i = 0; i < 8; i++) {
if (x & (1 << i)) {
cow->lseek (COW_HDR_SIZE + (hdr.blocks >> 3) + (sector << bs), SEEK_SET);
cow->read (buf, device->blocksize());
device->lseek (sector << bs, SEEK_SET);
device->write (buf, device->blocksize());
blksofar++;
}
}
}
if (sector % 64 == 0 && *blkmap != 0)
printf ("Writing: %6d/%d %3d%%\r", blksofar, nblk, blksofar * 100 / nblk);
sector += 8;
blkmap++;
}
printf ("\rDone. \n");
delete cow; delete device;
return 0;
}