#include #include #include #include #include #include "zipfs.h" #define LFH_SIG (0x04034b50) #define LFH_SIZEOF (30) #define LFH_CSIZE (18) #define LFH_NAMELEN (26) #define LFH_EXTLEN (28) #define FH_SIG (0x02014b50) #define FH_SIZEOF (46) #define FH_NAMELEN (28) #define FH_EXTLEN (30) #define FH_COMMENTLEN (32) #define DS_SIG (0x05054b50) #define DS_SIZEOF (6) #define DS_SIZE (4) #define ECD_SIG (0x06054b50) #define ECD_SIZEOF (22) #define ECD_COMMENTLEN (20) #define ZF_OPEN (0x1) #define min(x, y) ((x) < (y) ? (x) : (y)) #define TS(x) (sizeof(x) / sizeof(x[0])) typedef int zip_callback_t(char *p, size_t len, off_t off, void *arg); struct zip_file { off_t zf_fileoff; off_t zf_curoff; size_t zf_size; int zf_flags; }; struct zip_open_args { const char *zoa_name; struct zip_file *zoa_zf; }; static void zip_scan(zip_callback_t *callback, void *arg); static void *zip_pullup(off_t off, size_t len); static zip_callback_t zip_open_callback; static int zip_fd; static off_t zip_block; static off_t zip_offset; static char zip_buf[1024]; static struct zip_file zip_file; static int zip_sig_search[] = { 0, 8192 }; int zip_mount(const char *name) { void *p; int i; if ((zip_fd = open(name, O_RDONLY)) < 0) return (1); for (i = 0; i < TS(zip_sig_search); i++) { zip_block = -1; zip_offset = zip_sig_search[i]; p = zip_pullup(0, 4); if (le32toh(*(uint32_t *)p) == LFH_SIG) return (0); } return (1); } void * zip_open(const char *name) { struct zip_open_args zoa; struct zip_file *zf; zf = &zip_file; if ((zf->zf_flags & ZF_OPEN) != 0) return (NULL); bzero(zf, sizeof(*zf)); zoa.zoa_name = name; zoa.zoa_zf = zf; zip_scan(zip_open_callback, &zoa); return ((zf->zf_flags & ZF_OPEN) != 0 ? zf : NULL); } size_t zip_read(void *handle, void *buf, size_t len) { struct zip_file *zf; const char *p; size_t nread; size_t resid; zf = handle; nread = 0; while (len != 0) { resid = min(min(len, 512), zf->zf_size - zf->zf_curoff); if (resid == 0) break; p = zip_pullup(zf->zf_fileoff + zf->zf_curoff, resid); zf->zf_curoff += resid; bcopy(p, buf + nread, resid); nread += resid; len -= resid; } return (nread); } off_t zip_seek(void *handle, off_t off) { struct zip_file *zf; zf = handle; if (off < zf->zf_size) { zf->zf_curoff = off; return (0); } return (-1); } static int zip_open_callback(char *p, size_t len, off_t off, void *arg) { struct zip_open_args *zoa; struct zip_file *zf; const char *name; zoa = arg; zf = zoa->zoa_zf; switch (le32toh(*(uint32_t *)p)) { case LFH_SIG: if (bcmp(zoa->zoa_name, p + LFH_SIZEOF, le16toh(*(uint16_t *)(p + LFH_NAMELEN))) == 0) { zf->zf_curoff = 0; zf->zf_fileoff = LFH_SIZEOF + le16toh(*(uint16_t *)(p + LFH_NAMELEN)) + le16toh(*(uint16_t *)(p + LFH_EXTLEN)); zf->zf_size = le32toh(*(uint32_t *)(p + LFH_CSIZE)); zf->zf_flags = ZF_OPEN; return (0); } return (1); case ECD_SIG: return (0); default: return (1); } } static void * zip_pullup(off_t off, size_t len) { if ((off / 512) != zip_block) { zip_block = off / 512; if (lseek(zip_fd, (zip_offset + zip_block) * 512, SEEK_SET) < 0) err(1, "lseek"); if (read(zip_fd, zip_buf, 512) < 0) err(1, "read"); } if (((off + len) / 512) != zip_block) { if (lseek(zip_fd, (zip_offset + zip_block + 1) * 512, SEEK_SET) < 0) err(1, "lseek"); if (read(zip_fd, zip_buf + 512, 512) < 0) err(1, "read"); } return &zip_buf[off % 512]; } static void zip_scan(zip_callback_t *callback, void *arg) { size_t len; off_t off; char *p; off = 0; for (;;) { p = zip_pullup(off, 4); switch (le32toh(*(uint32_t *)p)) { case LFH_SIG: p = zip_pullup(off, LFH_SIZEOF); len = LFH_SIZEOF + le16toh(*(uint16_t *)(p + LFH_NAMELEN)) + le16toh(*(uint16_t *)(p + LFH_EXTLEN)) + le32toh(*(uint32_t *)(p + LFH_CSIZE)); break; case FH_SIG: p = zip_pullup(off, FH_SIZEOF); len = FH_SIZEOF + le16toh(*(uint16_t *)(p + FH_NAMELEN)) + le16toh(*(uint16_t *)(p + FH_EXTLEN)) + le16toh(*(uint16_t *)(p + FH_COMMENTLEN)); break; case DS_SIG: p = zip_pullup(off, DS_SIZEOF); len = DS_SIZEOF + le16toh(*(uint16_t *)(p + DS_SIZE)); break; case ECD_SIG: p = zip_pullup(off, ECD_SIZEOF); len = ECD_SIZEOF + le16toh(*(uint16_t *)(p + ECD_COMMENTLEN)); break; default: printf("invalid header signature: %#x\n", le32toh(*(uint32_t *)p)); break; } p = zip_pullup(off, len); if (callback(p, len, off, arg) == 0) return; off += len; } }