diff options
author | sjg <sjg@FreeBSD.org> | 2014-11-19 01:07:58 +0000 |
---|---|---|
committer | sjg <sjg@FreeBSD.org> | 2014-11-19 01:07:58 +0000 |
commit | b137080f19736ee33fede2e88bb54438604cf86b (patch) | |
tree | 377ac0ac449528621eb192cd245adadb5fd53668 /lib/libstand | |
parent | ab21a29eb607d4dfe389b965fbdee27558e791aa (diff) | |
parent | 4a8d07956d121238d006d34ffe7d6269744e8b1a (diff) | |
download | FreeBSD-src-b137080f19736ee33fede2e88bb54438604cf86b.zip FreeBSD-src-b137080f19736ee33fede2e88bb54438604cf86b.tar.gz |
Merge from head@274682
Diffstat (limited to 'lib/libstand')
-rw-r--r-- | lib/libstand/Makefile | 5 | ||||
-rw-r--r-- | lib/libstand/open.c | 32 | ||||
-rw-r--r-- | lib/libstand/pkgfs.c | 791 | ||||
-rw-r--r-- | lib/libstand/stand.h | 2 |
4 files changed, 817 insertions, 13 deletions
diff --git a/lib/libstand/Makefile b/lib/libstand/Makefile index 72b201e..e57407f 100644 --- a/lib/libstand/Makefile +++ b/lib/libstand/Makefile @@ -64,9 +64,6 @@ SRCS+= bcmp.c bcopy.c bzero.c ffs.c memccpy.c memchr.c memcmp.c memcpy.c \ .if ${MACHINE_CPUARCH} == "arm" .PATH: ${.CURDIR}/../libc/arm/gen -.if ${MK_ARM_EABI} == "no" -SRCS+= divsi3.S -.else # Compiler support functions .PATH: ${.CURDIR}/../../contrib/compiler-rt/lib/ # __clzsi2 and ctzsi2 for various builtin functions @@ -78,7 +75,6 @@ SRCS+= udivmoddi4.c udivmodsi4.c udivdi3.c udivsi3.c umoddi3.c umodsi3.c .PATH: ${.CURDIR}/../../contrib/compiler-rt/lib/arm/ SRCS+= aeabi_idivmod.S aeabi_ldivmod.S aeabi_uidivmod.S aeabi_uldivmod.S SRCS+= aeabi_memcmp.S aeabi_memcpy.S aeabi_memmove.S aeabi_memset.S -.endif .endif .if ${MACHINE_CPUARCH} == "powerpc" @@ -161,6 +157,7 @@ SRCS+= bootp.c rarp.c bootparam.c SRCS+= ufs.c nfs.c cd9660.c tftp.c gzipfs.c bzipfs.c SRCS+= dosfs.c ext2fs.c SRCS+= splitfs.c +SRCS+= pkgfs.c .if ${MK_NAND} != "no" SRCS+= nandfs.c .endif diff --git a/lib/libstand/open.c b/lib/libstand/open.c index 49dc660..0d90433 100644 --- a/lib/libstand/open.c +++ b/lib/libstand/open.c @@ -65,6 +65,8 @@ __FBSDID("$FreeBSD$"); #include "stand.h" +struct fs_ops *exclusive_file_system; + struct open_file files[SOPEN_MAX]; static int @@ -89,6 +91,7 @@ o_rainit(struct open_file *f) int open(const char *fname, int mode) { + struct fs_ops *fs; struct open_file *f; int fd, i, error, besterror; const char *file; @@ -105,6 +108,15 @@ open(const char *fname, int mode) f->f_offset = 0; f->f_devdata = NULL; file = (char *)0; + + if (exclusive_file_system != NULL) { + fs = exclusive_file_system; + error = (fs->fo_open)(fname, f); + if (error == 0) + goto ok; + goto fail; + } + error = devopen(f, fname, &file); if (error || (((f->f_flags & F_NODEV) == 0) && f->f_dev == (struct devsw *)0)) @@ -120,20 +132,17 @@ open(const char *fname, int mode) /* pass file name to the different filesystem open routines */ besterror = ENOENT; for (i = 0; file_system[i] != NULL; i++) { - - error = ((*file_system[i]).fo_open)(file, f); - if (error == 0) { - - f->f_ops = file_system[i]; - o_rainit(f); - return (fd); - } + fs = file_system[i]; + error = (fs->fo_open)(file, f); + if (error == 0) + goto ok; if (error != EINVAL) besterror = error; } error = besterror; - if ((f->f_flags & F_NODEV) == 0) + fail: + if ((f->f_flags & F_NODEV) == 0 && f->f_dev != NULL) f->f_dev->dv_close(f); if (error) devclose(f); @@ -142,4 +151,9 @@ open(const char *fname, int mode) f->f_flags = 0; errno = error; return (-1); + + ok: + f->f_ops = fs; + o_rainit(f); + return (fd); } diff --git a/lib/libstand/pkgfs.c b/lib/libstand/pkgfs.c new file mode 100644 index 0000000..fda7f60 --- /dev/null +++ b/lib/libstand/pkgfs.c @@ -0,0 +1,791 @@ +/*- + * Copyright (c) 2007-2014, Juniper Networks, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +#include <sys/stat.h> +#include <sys/stdint.h> +#include <string.h> +#include <zlib.h> + +#ifdef PKGFS_DEBUG +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +static int pkg_open(const char *, struct open_file *); +static int pkg_close(struct open_file *); +static int pkg_read(struct open_file *, void *, size_t, size_t *); +static off_t pkg_seek(struct open_file *, off_t, int); +static int pkg_stat(struct open_file *, struct stat *); +static int pkg_readdir(struct open_file *, struct dirent *); + +struct fs_ops pkgfs_fsops = { + "pkg", + pkg_open, + pkg_close, + pkg_read, + null_write, + pkg_seek, + pkg_stat, + pkg_readdir +}; + +#define PKG_BUFSIZE 512 +#define PKG_MAXCACHESZ 4096 + +#define PKG_FILEEXT ".tgz" + +/* + * Layout of POSIX 'ustar' header. + */ +struct ustar_hdr { + char ut_name[100]; + char ut_mode[8]; + char ut_uid[8]; + char ut_gid[8]; + char ut_size[12]; + char ut_mtime[12]; + char ut_checksum[8]; + char ut_typeflag[1]; + char ut_linkname[100]; + char ut_magic[6]; /* For POSIX: "ustar\0" */ + char ut_version[2]; /* For POSIX: "00" */ + char ut_uname[32]; + char ut_gname[32]; + char ut_rdevmajor[8]; + char ut_rdevminor[8]; + union { + struct { + char prefix[155]; + } posix; + struct { + char atime[12]; + char ctime[12]; + char offset[12]; + char longnames[4]; + char unused[1]; + struct gnu_sparse { + char offset[12]; + char numbytes[12]; + } sparse[4]; + char isextended[1]; + char realsize[12]; + } gnu; + } u; + u_char __padding[12]; +}; + +struct package; + +struct tarfile +{ + struct package *tf_pkg; + struct tarfile *tf_next; + struct ustar_hdr tf_hdr; + off_t tf_ofs; + off_t tf_size; + off_t tf_fp; + size_t tf_cachesz; + void *tf_cache; +}; + +struct package +{ + struct package *pkg_chain; + int pkg_fd; + off_t pkg_ofs; + z_stream pkg_zs; + struct tarfile *pkg_first; + struct tarfile *pkg_last; + u_char pkg_buf[PKG_BUFSIZE]; +}; + +static struct package *package = NULL; + +static int new_package(int, struct package **); + +void +pkgfs_cleanup(void) +{ + struct package *chain; + struct tarfile *tf, *tfn; + + while (package != NULL) { + inflateEnd(&package->pkg_zs); + close(package->pkg_fd); + + tf = package->pkg_first; + while (tf != NULL) { + tfn = tf->tf_next; + if (tf->tf_cachesz > 0) + free(tf->tf_cache); + free(tf); + tf = tfn; + } + + chain = package->pkg_chain; + free(package); + package = chain; + } +} + +int +pkgfs_init(const char *pkgname, struct fs_ops *proto) +{ + struct package *pkg; + int error, fd; + + if (proto != &pkgfs_fsops) + pkgfs_cleanup(); + + exclusive_file_system = proto; + + fd = open(pkgname, O_RDONLY); + + exclusive_file_system = NULL; + + if (fd == -1) + return (errno); + + error = new_package(fd, &pkg); + if (error) { + close(fd); + return (error); + } + + if (pkg == NULL) + return (EDOOFUS); + + pkg->pkg_chain = package; + package = pkg; + exclusive_file_system = &pkgfs_fsops; + return (0); +} + +static int get_mode(struct tarfile *); +static int get_zipped(struct package *, void *, size_t); +static int new_package(int, struct package **); +static struct tarfile *scan_tarfile(struct package *, struct tarfile *); + +static int +pkg_open(const char *fn, struct open_file *f) +{ + struct tarfile *tf; + + if (fn == NULL || f == NULL) + return (EINVAL); + + if (package == NULL) + return (ENXIO); + + /* + * We can only read from a package, so reject request to open + * for write-only or read-write. + */ + if (f->f_flags != F_READ) + return (EPERM); + + /* + * Scan the file headers for the named file. We stop scanning + * at the first filename that has the .pkg extension. This is + * a package within a package. We assume we have all the files + * we need up-front and without having to dig within nested + * packages. + * + * Note that we preserve streaming properties as much as possible. + */ + while (*fn == '/') + fn++; + + /* + * Allow opening of the root directory for use by readdir() + * to support listing files in the package. + */ + if (*fn == '\0') { + f->f_fsdata = NULL; + return (0); + } + + tf = scan_tarfile(package, NULL); + while (tf != NULL) { + if (strcmp(fn, tf->tf_hdr.ut_name) == 0) { + f->f_fsdata = tf; + tf->tf_fp = 0; /* Reset the file pointer. */ + return (0); + } + tf = scan_tarfile(package, tf); + } + return (errno); +} + +static int +pkg_close(struct open_file *f) +{ + struct tarfile *tf; + + tf = (struct tarfile *)f->f_fsdata; + if (tf == NULL) + return (0); + + /* + * Free up the cache if we read all of the file. + */ + if (tf->tf_fp == tf->tf_size && tf->tf_cachesz > 0) { + free(tf->tf_cache); + tf->tf_cachesz = 0; + } + return (0); +} + +static int +pkg_read(struct open_file *f, void *buf, size_t size, size_t *res) +{ + struct tarfile *tf; + char *p; + off_t fp; + size_t sz; + + tf = (struct tarfile *)f->f_fsdata; + if (tf == NULL) { + if (res != NULL) + *res = size; + return (EBADF); + } + + fp = tf->tf_fp; + p = buf; + sz = 0; + while (size > 0) { + sz = tf->tf_size - fp; + if (fp < tf->tf_cachesz && tf->tf_cachesz < tf->tf_size) + sz = tf->tf_cachesz - fp; + if (size < sz) + sz = size; + if (sz == 0) + break; + + if (fp < tf->tf_cachesz) { + /* Satisfy the request from cache. */ + memcpy(p, tf->tf_cache + fp, sz); + fp += sz; + p += sz; + size -= sz; + continue; + } + + if (get_zipped(tf->tf_pkg, p, sz) == -1) { + sz = -1; + break; + } + + fp += sz; + p += sz; + size -= sz; + + if (tf->tf_cachesz != 0) + continue; + + tf->tf_cachesz = (sz <= PKG_MAXCACHESZ) ? sz : PKG_MAXCACHESZ; + tf->tf_cache = malloc(tf->tf_cachesz); + if (tf->tf_cache != NULL) + memcpy(tf->tf_cache, buf, tf->tf_cachesz); + else + tf->tf_cachesz = 0; + } + + tf->tf_fp = fp; + if (res != NULL) + *res = size; + return ((sz == -1) ? errno : 0); +} + +static off_t +pkg_seek(struct open_file *f, off_t ofs, int whence) +{ + char buf[512]; + struct tarfile *tf; + off_t delta; + size_t sz, res; + int error; + + tf = (struct tarfile *)f->f_fsdata; + if (tf == NULL) { + errno = EBADF; + return (-1); + } + + switch (whence) { + case SEEK_SET: + delta = ofs - tf->tf_fp; + break; + case SEEK_CUR: + delta = ofs; + break; + case SEEK_END: + delta = tf->tf_size - tf->tf_fp + ofs; + break; + default: + errno = EINVAL; + return (-1); + } + + if (delta < 0) { + DBG(("%s: negative file seek (%jd)\n", __func__, + (intmax_t)delta)); + errno = ESPIPE; + return (-1); + } + + while (delta > 0 && tf->tf_fp < tf->tf_size) { + sz = (delta > sizeof(buf)) ? sizeof(buf) : delta; + error = pkg_read(f, buf, sz, &res); + if (error != 0) { + errno = error; + return (-1); + } + delta -= sz - res; + } + + return (tf->tf_fp); +} + +static int +pkg_stat(struct open_file *f, struct stat *sb) +{ + struct tarfile *tf; + + tf = (struct tarfile *)f->f_fsdata; + if (tf == NULL) + return (EBADF); + memset(sb, 0, sizeof(*sb)); + sb->st_mode = get_mode(tf); + sb->st_size = tf->tf_size; + sb->st_blocks = (tf->tf_size + 511) / 512; + return (0); +} + +static int +pkg_readdir(struct open_file *f, struct dirent *d) +{ + struct tarfile *tf; + + tf = (struct tarfile *)f->f_fsdata; + if (tf != NULL) + return (EBADF); + + tf = scan_tarfile(package, NULL); + if (tf == NULL) + return (ENOENT); + + d->d_fileno = 0; + d->d_reclen = sizeof(*d); + d->d_type = DT_REG; + memcpy(d->d_name, tf->tf_hdr.ut_name, sizeof(d->d_name)); + return (0); +} + +/* + * Low-level support functions. + */ + +static int +get_byte(struct package *pkg, off_t *op) +{ + int c; + + if (pkg->pkg_zs.avail_in == 0) { + c = read(pkg->pkg_fd, pkg->pkg_buf, PKG_BUFSIZE); + if (c <= 0) + return (-1); + pkg->pkg_zs.avail_in = c; + pkg->pkg_zs.next_in = pkg->pkg_buf; + } + + c = *pkg->pkg_zs.next_in; + pkg->pkg_zs.next_in++; + pkg->pkg_zs.avail_in--; + (*op)++; + return (c); +} + +static int +get_zipped(struct package *pkg, void *buf, size_t bufsz) +{ + int c; + + pkg->pkg_zs.next_out = buf; + pkg->pkg_zs.avail_out = bufsz; + + while (pkg->pkg_zs.avail_out) { + if (pkg->pkg_zs.avail_in == 0) { + c = read(pkg->pkg_fd, pkg->pkg_buf, PKG_BUFSIZE); + if (c <= 0) { + errno = EIO; + return (-1); + } + pkg->pkg_zs.avail_in = c; + pkg->pkg_zs.next_in = pkg->pkg_buf; + } + + c = inflate(&pkg->pkg_zs, Z_SYNC_FLUSH); + if (c != Z_OK && c != Z_STREAM_END) { + errno = EIO; + return (-1); + } + } + + pkg->pkg_ofs += bufsz; + return (0); +} + +static int +cache_data(struct tarfile *tf) +{ + struct package *pkg; + size_t sz; + + if (tf == NULL) { + DBG(("%s: no file to cache data for?\n", __func__)); + errno = EINVAL; + return (-1); + } + + pkg = tf->tf_pkg; + if (pkg == NULL) { + DBG(("%s: no package associated with file?\n", __func__)); + errno = EINVAL; + return (-1); + } + + if (tf->tf_ofs != pkg->pkg_ofs) { + DBG(("%s: caching after partial read of file %s?\n", + __func__, tf->tf_hdr.ut_name)); + errno = EINVAL; + return (-1); + } + + /* We don't cache everything... */ + if (tf->tf_size > PKG_MAXCACHESZ) { + errno = ENOMEM; + return (-1); + } + + /* All files are padded to a multiple of 512 bytes. */ + sz = (tf->tf_size + 0x1ff) & ~0x1ff; + + tf->tf_cache = malloc(sz); + if (tf->tf_cache == NULL) { + DBG(("%s: could not allocate %d bytes\n", __func__, (int)sz)); + errno = ENOMEM; + return (-1); + } + + tf->tf_cachesz = sz; + return (get_zipped(pkg, tf->tf_cache, sz)); +} + +/* + * Note that this implementation does not (and should not!) obey + * locale settings; you cannot simply substitute strtol here, since + * it does obey locale. + */ +static off_t +pkg_atol8(const char *p, unsigned char_cnt) +{ + int64_t l, limit, last_digit_limit; + int digit, sign, base; + + base = 8; + limit = INT64_MAX / base; + last_digit_limit = INT64_MAX % base; + + while (*p == ' ' || *p == '\t') + p++; + if (*p == '-') { + sign = -1; + p++; + } else + sign = 1; + + l = 0; + digit = *p - '0'; + while (digit >= 0 && digit < base && char_cnt-- > 0) { + if (l>limit || (l == limit && digit > last_digit_limit)) { + l = UINT64_MAX; /* Truncate on overflow. */ + break; + } + l = (l * base) + digit; + digit = *++p - '0'; + } + return (sign < 0) ? -l : l; +} + +/* + * Parse a base-256 integer. This is just a straight signed binary + * value in big-endian order, except that the high-order bit is + * ignored. Remember that "int64_t" may or may not be exactly 64 + * bits; the implementation here tries to avoid making any assumptions + * about the actual size of an int64_t. It does assume we're using + * twos-complement arithmetic, though. + */ +static int64_t +pkg_atol256(const char *_p, unsigned char_cnt) +{ + int64_t l, upper_limit, lower_limit; + const unsigned char *p = (const unsigned char *)_p; + + upper_limit = INT64_MAX / 256; + lower_limit = INT64_MIN / 256; + + /* Pad with 1 or 0 bits, depending on sign. */ + if ((0x40 & *p) == 0x40) + l = (int64_t)-1; + else + l = 0; + l = (l << 6) | (0x3f & *p++); + while (--char_cnt > 0) { + if (l > upper_limit) { + l = INT64_MAX; /* Truncate on overflow */ + break; + } else if (l < lower_limit) { + l = INT64_MIN; + break; + } + l = (l << 8) | (0xff & (int64_t)*p++); + } + return (l); +} + +static off_t +pkg_atol(const char *p, unsigned char_cnt) +{ + /* + * Technically, GNU pkg considers a field to be in base-256 + * only if the first byte is 0xff or 0x80. + */ + if (*p & 0x80) + return (pkg_atol256(p, char_cnt)); + return (pkg_atol8(p, char_cnt)); +} + +static int +get_mode(struct tarfile *tf) +{ + return (pkg_atol(tf->tf_hdr.ut_mode, sizeof(tf->tf_hdr.ut_mode))); +} + +/* GZip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +static int +new_package(int fd, struct package **pp) +{ + struct package *pkg; + off_t ofs; + int flags, i, error; + + pkg = malloc(sizeof(*pkg)); + if (pkg == NULL) + return (ENOMEM); + + bzero(pkg, sizeof(*pkg)); + pkg->pkg_fd = fd; + + /* + * Parse the header. + */ + error = EFTYPE; + ofs = 0; + + /* Check megic. */ + if (get_byte(pkg, &ofs) != 0x1f || get_byte(pkg, &ofs) != 0x8b) + goto fail; + /* Check method. */ + if (get_byte(pkg, &ofs) != Z_DEFLATED) + goto fail; + /* Check flags. */ + flags = get_byte(pkg, &ofs); + if (flags & RESERVED) + goto fail; + + /* Skip time, xflags and OS code. */ + for (i = 0; i < 6; i++) { + if (get_byte(pkg, &ofs) == -1) + goto fail; + } + + /* Skip extra field. */ + if (flags & EXTRA_FIELD) { + i = (get_byte(pkg, &ofs) & 0xff) | + ((get_byte(pkg, &ofs) << 8) & 0xff); + while (i-- > 0) { + if (get_byte(pkg, &ofs) == -1) + goto fail; + } + } + + /* Skip original file name. */ + if (flags & ORIG_NAME) { + do { + i = get_byte(pkg, &ofs); + } while (i != 0 && i != -1); + if (i == -1) + goto fail; + } + + /* Print the comment if it's there. */ + if (flags & COMMENT) { + while (1) { + i = get_byte(pkg, &ofs); + if (i == -1) + goto fail; + if (i == 0) + break; + putchar(i); + } + } + + /* Skip the CRC. */ + if (flags & HEAD_CRC) { + if (get_byte(pkg, &ofs) == -1) + goto fail; + if (get_byte(pkg, &ofs) == -1) + goto fail; + } + + /* + * Done parsing the ZIP header. Spkgt the inflation engine. + */ + error = inflateInit2(&pkg->pkg_zs, -15); + if (error != Z_OK) + goto fail; + + *pp = pkg; + return (0); + + fail: + free(pkg); + return (error); +} + +static struct tarfile * +scan_tarfile(struct package *pkg, struct tarfile *last) +{ + char buf[512]; + struct tarfile *cur; + off_t ofs; + size_t sz; + + cur = (last != NULL) ? last->tf_next : pkg->pkg_first; + if (cur == NULL) { + ofs = (last != NULL) ? last->tf_ofs + last->tf_size : + pkg->pkg_ofs; + ofs = (ofs + 0x1ff) & ~0x1ff; + + /* Check if we've reached EOF. */ + if (ofs < pkg->pkg_ofs) { + errno = ENOSPC; + return (NULL); + } + + if (ofs != pkg->pkg_ofs) { + if (last != NULL && pkg->pkg_ofs == last->tf_ofs) { + if (cache_data(last) == -1) + return (NULL); + } else { + sz = ofs - pkg->pkg_ofs; + while (sz != 0) { + if (sz > sizeof(buf)) + sz = sizeof(buf); + if (get_zipped(pkg, buf, sz) == -1) + return (NULL); + sz = ofs - pkg->pkg_ofs; + } + } + } + + cur = malloc(sizeof(*cur)); + if (cur == NULL) + return (NULL); + memset(cur, 0, sizeof(*cur)); + cur->tf_pkg = pkg; + + while (1) { + if (get_zipped(pkg, &cur->tf_hdr, + sizeof(cur->tf_hdr)) == -1) { + free(cur); + return (NULL); + } + + /* + * There are always 2 empty blocks appended to + * a PKG. It marks the end of the archive. + */ + if (strncmp(cur->tf_hdr.ut_magic, "ustar", 5) != 0) { + free(cur); + errno = ENOSPC; + return (NULL); + } + + cur->tf_ofs = pkg->pkg_ofs; + cur->tf_size = pkg_atol(cur->tf_hdr.ut_size, + sizeof(cur->tf_hdr.ut_size)); + + if (cur->tf_hdr.ut_name[0] != '+') + break; + + /* + * Skip package meta-files. + */ + ofs = cur->tf_ofs + cur->tf_size; + ofs = (ofs + 0x1ff) & ~0x1ff; + while (pkg->pkg_ofs < ofs) { + if (get_zipped(pkg, buf, sizeof(buf)) == -1) { + free(cur); + return (NULL); + } + } + } + + if (last != NULL) + last->tf_next = cur; + else + pkg->pkg_first = cur; + pkg->pkg_last = cur; + } + + return (cur); +} diff --git a/lib/libstand/stand.h b/lib/libstand/stand.h index 2808722..bcd146a 100644 --- a/lib/libstand/stand.h +++ b/lib/libstand/stand.h @@ -124,6 +124,7 @@ extern struct fs_ops bzipfs_fsops; extern struct fs_ops dosfs_fsops; extern struct fs_ops ext2fs_fsops; extern struct fs_ops splitfs_fsops; +extern struct fs_ops pkgfs_fsops; /* where values for lseek(2) */ #define SEEK_SET 0 /* set file offset to offset */ @@ -364,6 +365,7 @@ extern int devopen(struct open_file *, const char *, const char **); extern int devclose(struct open_file *f); extern void panic(const char *, ...) __dead2 __printflike(1, 2); extern struct fs_ops *file_system[]; +extern struct fs_ops *exclusive_file_system; extern struct devsw *devsw[]; /* |