Blob


1 /*
2 * This is free and unencumbered software released into the public domain.
3 */
5 #include <sys/mman.h>
7 #include <endian.h>
8 #include <err.h>
9 #include <fcntl.h>
10 #include <limits.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <zlib.h>
17 #define MIN(a, b) ((a) < (b) ? (a) : (b))
19 void *
20 find_central_directory(uint8_t *addr, size_t len)
21 {
22 uint32_t offset;
23 uint16_t clen;
24 uint8_t *p, *end;
26 /*
27 * At -22 bytes from the end there is the end of the central
28 * directory assuming an empty comment. It's a sensible place
29 * from which start.
30 */
31 if (len < 22)
32 return NULL;
33 end = addr + len;
34 p = end - 22;
36 again:
37 for (; p > addr; --p)
38 if (memcmp(p, "\x50\x4b\x05\x06", 4) == 0)
39 break;
41 if (p == addr)
42 return NULL;
44 /* read comment length */
45 memcpy(&clen, p + 20, sizeof(clen));
46 clen = le16toh(clen);
48 /* false signature inside a comment? */
49 if (clen + 22 != end - p) {
50 p--;
51 goto again;
52 }
54 /* read the offset for the central directory */
55 memcpy(&offset, p + 16, sizeof(offset));
56 offset = le32toh(offset);
58 if (addr + offset > p)
59 return NULL;
61 return addr + offset;
62 }
64 void
65 ls(uint8_t *zip, size_t len, uint8_t *cd)
66 {
67 uint16_t flen, xlen, clen;
68 uint8_t *end;
69 char filename[PATH_MAX];
71 end = zip + len;
72 while (cd < end - 46 && memcmp(cd, "\x50\x4b\x01\x02", 4) == 0) {
73 memcpy(&flen, cd + 28, sizeof(flen));
74 memcpy(&xlen, cd + 28 + 2, sizeof(xlen));
75 memcpy(&clen, cd + 28 + 2 + 2, sizeof(clen));
77 flen = le16toh(flen);
78 xlen = le16toh(xlen);
79 clen = le16toh(clen);
81 memset(filename, 0, sizeof(filename));
82 memcpy(filename, cd + 46, MIN(sizeof(filename)-1, flen));
84 printf("%s\n", filename);
86 cd += 46 + flen + xlen + clen;
87 }
88 }
90 void *
91 map_file(int fd, size_t *len)
92 {
93 off_t jump;
94 void *addr;
96 if ((jump = lseek(fd, 0, SEEK_END)) == -1)
97 err(1, "lseek");
99 if (lseek(fd, 0, SEEK_SET) == -1)
100 err(1, "lseek");
102 if ((addr = mmap(NULL, jump, PROT_READ, MAP_PRIVATE, fd, 0))
103 == MAP_FAILED)
104 err(1, "mmap");
106 *len = jump;
107 return addr;
110 int
111 main(int argc, char **argv)
113 int fd;
114 void *zip, *cd;
115 size_t len;
117 if (argc != 2)
118 errx(1, "missing file to inspect");
120 if ((fd = open(argv[1], O_RDONLY)) == -1)
121 err(1, "can't open %s", argv[1]);
123 zip = map_file(fd, &len);
124 if ((cd = find_central_directory(zip, len)) == NULL)
125 errx(1, "can't find the central directory");
127 ls(zip, len, cd);
129 munmap(zip, len);
130 close(fd);
132 return 0;