-
Notifications
You must be signed in to change notification settings - Fork 19
/
cpio.c
103 lines (94 loc) · 2.13 KB
/
cpio.c
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
#include "inc.h"
static u32
cpio_hex(byte *p)
{
u32 x = 0;
int i;
for (i = 0; i < 8; i++, p++)
{
int c = *p;
x <<= 4;
if (c >= '0' && c <= '9')
x += (c - '0');
else if (c >= 'a' && c <= 'f')
x += (c - 'a') + 10;
else if (c >= 'A' && c <= 'F')
x += (c - 'A') + 10;
else
dodie("invalid cpio data");
}
return x;
}
static void
cpio_tohex(byte *p, u32 x)
{
static const char hexstr[] = "0123456789ABCDEF";
int i;
p += 7;
for (i = 0; i < 8; i++, p--)
{
int c = (x & 15);
x >>= 4;
*p = (byte)hexstr[c];
}
}
byte *
cpio_read(int fd, int *typep, int reserve)
{
byte hdr[110]; /* cpio header */
byte *cpio;
u32 mode, size, namesize, namepad;
doread(fd, hdr, 110);
if (memcmp(hdr, "070701", 6))
dodie("bad/unsupported cpio file");
mode = cpio_hex(hdr + 14);
size = cpio_hex(hdr + 54);
namesize = cpio_hex(hdr + 94);
if (namesize > 8192)
dodie("illegal name size");
if (size > 0x40000000)
dodie("illegal file size");
namepad = (6 - (namesize & 3)) & 3;
cpio = doalloc(110 + namesize + namepad + 1 + (reserve ? reserve + 4 : 0));
memcpy(cpio, hdr, 110);
doread(fd, cpio + 110, namesize + namepad);
cpio[110 + namesize] = 0;
if (!size && !strcmp((char *)cpio + 110, "TRAILER!!!"))
*typep = CPIO_TYPE_TRAILER;
else if (((mode >> 12) & 15) == 8)
*typep = CPIO_TYPE_FILE;
else
*typep = CPIO_TYPE_OTHER;
return cpio;
}
u32
cpio_name_append(byte *cpio, char *suf)
{
u32 namepad, namesize = strlen((char *)cpio + 110);
strcpy((char *)cpio + 110 + namesize, suf);
namesize += strlen(suf) + 1;
namepad = (6 - (namesize & 3)) & 3;
memset(cpio + 110 + namesize, 0, namepad);
cpio_tohex(cpio + 94, namesize);
return namepad;
}
u32
cpio_size_set(byte *cpio, u32 size)
{
cpio_tohex(cpio + 54, size);
return (4 - (size & 3)) & 3;
}
u32
cpio_size_get(byte *cpio, u32 *padp)
{
u32 size = cpio_hex(cpio + 54);
if (padp)
*padp = ((4 - (size & 3)) & 3);
return size;
}
u32
cpio_headnamesize(byte *cpio)
{
u32 namesize = cpio_hex(cpio + 94);
return 110 + namesize + ((6 - (namesize & 3)) & 3);
}