199767f8919635c4928607450d9e0abb932109ceToomas Soome/*-
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Copyright (c) 2007-2014, Juniper Networks, Inc.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * All rights reserved.
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Redistribution and use in source and binary forms, with or without
199767f8919635c4928607450d9e0abb932109ceToomas Soome * modification, are permitted provided that the following conditions
199767f8919635c4928607450d9e0abb932109ceToomas Soome * are met:
199767f8919635c4928607450d9e0abb932109ceToomas Soome * 1. Redistributions of source code must retain the above copyright
199767f8919635c4928607450d9e0abb932109ceToomas Soome * notice, this list of conditions and the following disclaimer.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
199767f8919635c4928607450d9e0abb932109ceToomas Soome * notice, this list of conditions and the following disclaimer in the
199767f8919635c4928607450d9e0abb932109ceToomas Soome * documentation and/or other materials provided with the distribution.
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
199767f8919635c4928607450d9e0abb932109ceToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
199767f8919635c4928607450d9e0abb932109ceToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
199767f8919635c4928607450d9e0abb932109ceToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
199767f8919635c4928607450d9e0abb932109ceToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
199767f8919635c4928607450d9e0abb932109ceToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
199767f8919635c4928607450d9e0abb932109ceToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
199767f8919635c4928607450d9e0abb932109ceToomas Soome * SUCH DAMAGE.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/cdefs.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome__FBSDID("$FreeBSD$");
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include "stand.h"
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/stat.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/stdint.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <string.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <zlib.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#ifdef PKGFS_DEBUG
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define DBG(x) printf x
199767f8919635c4928607450d9e0abb932109ceToomas Soome#else
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define DBG(x)
199767f8919635c4928607450d9e0abb932109ceToomas Soome#endif
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int pkg_open(const char *, struct open_file *);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int pkg_close(struct open_file *);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int pkg_read(struct open_file *, void *, size_t, size_t *);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic off_t pkg_seek(struct open_file *, off_t, int);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int pkg_stat(struct open_file *, struct stat *);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int pkg_readdir(struct open_file *, struct dirent *);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct fs_ops pkgfs_fsops = {
199767f8919635c4928607450d9e0abb932109ceToomas Soome "pkg",
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg_open,
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg_close,
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg_read,
199767f8919635c4928607450d9e0abb932109ceToomas Soome null_write,
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg_seek,
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg_stat,
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg_readdir
199767f8919635c4928607450d9e0abb932109ceToomas Soome};
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define PKG_BUFSIZE 512
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define PKG_MAXCACHESZ 4096
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define PKG_FILEEXT ".tgz"
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Layout of POSIX 'ustar' header.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct ustar_hdr {
199767f8919635c4928607450d9e0abb932109ceToomas Soome char ut_name[100];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char ut_mode[8];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char ut_uid[8];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char ut_gid[8];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char ut_size[12];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char ut_mtime[12];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char ut_checksum[8];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char ut_typeflag[1];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char ut_linkname[100];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char ut_magic[6]; /* For POSIX: "ustar\0" */
199767f8919635c4928607450d9e0abb932109ceToomas Soome char ut_version[2]; /* For POSIX: "00" */
199767f8919635c4928607450d9e0abb932109ceToomas Soome char ut_uname[32];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char ut_gname[32];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char ut_rdevmajor[8];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char ut_rdevminor[8];
199767f8919635c4928607450d9e0abb932109ceToomas Soome union {
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct {
199767f8919635c4928607450d9e0abb932109ceToomas Soome char prefix[155];
199767f8919635c4928607450d9e0abb932109ceToomas Soome } posix;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct {
199767f8919635c4928607450d9e0abb932109ceToomas Soome char atime[12];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char ctime[12];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char offset[12];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char longnames[4];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char unused[1];
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct gnu_sparse {
199767f8919635c4928607450d9e0abb932109ceToomas Soome char offset[12];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char numbytes[12];
199767f8919635c4928607450d9e0abb932109ceToomas Soome } sparse[4];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char isextended[1];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char realsize[12];
199767f8919635c4928607450d9e0abb932109ceToomas Soome } gnu;
199767f8919635c4928607450d9e0abb932109ceToomas Soome } u;
199767f8919635c4928607450d9e0abb932109ceToomas Soome u_char __padding[12];
199767f8919635c4928607450d9e0abb932109ceToomas Soome};
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct package;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct tarfile
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct package *tf_pkg;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct tarfile *tf_next;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct ustar_hdr tf_hdr;
199767f8919635c4928607450d9e0abb932109ceToomas Soome off_t tf_ofs;
199767f8919635c4928607450d9e0abb932109ceToomas Soome off_t tf_size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome off_t tf_fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome size_t tf_cachesz;
199767f8919635c4928607450d9e0abb932109ceToomas Soome void *tf_cache;
199767f8919635c4928607450d9e0abb932109ceToomas Soome};
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct package
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct package *pkg_chain;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int pkg_fd;
199767f8919635c4928607450d9e0abb932109ceToomas Soome off_t pkg_ofs;
199767f8919635c4928607450d9e0abb932109ceToomas Soome z_stream pkg_zs;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct tarfile *pkg_first;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct tarfile *pkg_last;
199767f8919635c4928607450d9e0abb932109ceToomas Soome u_char pkg_buf[PKG_BUFSIZE];
199767f8919635c4928607450d9e0abb932109ceToomas Soome};
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic struct package *package = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int new_package(int, struct package **);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomevoid
199767f8919635c4928607450d9e0abb932109ceToomas Soomepkgfs_cleanup(void)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct package *chain;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct tarfile *tf, *tfn;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (package != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome inflateEnd(&package->pkg_zs);
199767f8919635c4928607450d9e0abb932109ceToomas Soome close(package->pkg_fd);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf = package->pkg_first;
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (tf != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome tfn = tf->tf_next;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tf->tf_cachesz > 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(tf->tf_cache);
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(tf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf = tfn;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome chain = package->pkg_chain;
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(package);
199767f8919635c4928607450d9e0abb932109ceToomas Soome package = chain;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomeint
199767f8919635c4928607450d9e0abb932109ceToomas Soomepkgfs_init(const char *pkgname, struct fs_ops *proto)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct package *pkg;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int error, fd;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (proto != &pkgfs_fsops)
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkgfs_cleanup();
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome exclusive_file_system = proto;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome fd = open(pkgname, O_RDONLY);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome exclusive_file_system = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fd == -1)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (errno);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = new_package(fd, &pkg);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (error) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome close(fd);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (error);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (pkg == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EDOOFUS);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg->pkg_chain = package;
199767f8919635c4928607450d9e0abb932109ceToomas Soome package = pkg;
199767f8919635c4928607450d9e0abb932109ceToomas Soome exclusive_file_system = &pkgfs_fsops;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int get_mode(struct tarfile *);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int get_zipped(struct package *, void *, size_t);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int new_package(int, struct package **);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic struct tarfile *scan_tarfile(struct package *, struct tarfile *);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomepkg_open(const char *fn, struct open_file *f)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct tarfile *tf;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fn == NULL || f == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EINVAL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (package == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ENXIO);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * We can only read from a package, so reject request to open
199767f8919635c4928607450d9e0abb932109ceToomas Soome * for write-only or read-write.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (f->f_flags != F_READ)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EPERM);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Scan the file headers for the named file. We stop scanning
199767f8919635c4928607450d9e0abb932109ceToomas Soome * at the first filename that has the .pkg extension. This is
199767f8919635c4928607450d9e0abb932109ceToomas Soome * a package within a package. We assume we have all the files
199767f8919635c4928607450d9e0abb932109ceToomas Soome * we need up-front and without having to dig within nested
199767f8919635c4928607450d9e0abb932109ceToomas Soome * packages.
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Note that we preserve streaming properties as much as possible.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (*fn == '/')
199767f8919635c4928607450d9e0abb932109ceToomas Soome fn++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Allow opening of the root directory for use by readdir()
199767f8919635c4928607450d9e0abb932109ceToomas Soome * to support listing files in the package.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (*fn == '\0') {
199767f8919635c4928607450d9e0abb932109ceToomas Soome f->f_fsdata = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf = scan_tarfile(package, NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (tf != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (strcmp(fn, tf->tf_hdr.ut_name) == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome f->f_fsdata = tf;
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf->tf_fp = 0; /* Reset the file pointer. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf = scan_tarfile(package, tf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (errno);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomepkg_close(struct open_file *f)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct tarfile *tf;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf = (struct tarfile *)f->f_fsdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tf == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Free up the cache if we read all of the file.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tf->tf_fp == tf->tf_size && tf->tf_cachesz > 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(tf->tf_cache);
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf->tf_cachesz = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomepkg_read(struct open_file *f, void *buf, size_t size, size_t *res)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct tarfile *tf;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *p;
199767f8919635c4928607450d9e0abb932109ceToomas Soome off_t fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome size_t sz;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf = (struct tarfile *)f->f_fsdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tf == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (res != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome *res = size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EBADF);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp = tf->tf_fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome p = buf;
199767f8919635c4928607450d9e0abb932109ceToomas Soome sz = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (size > 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome sz = tf->tf_size - fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp < tf->tf_cachesz && tf->tf_cachesz < tf->tf_size)
199767f8919635c4928607450d9e0abb932109ceToomas Soome sz = tf->tf_cachesz - fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (size < sz)
199767f8919635c4928607450d9e0abb932109ceToomas Soome sz = size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (sz == 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp < tf->tf_cachesz) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Satisfy the request from cache. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome memcpy(p, tf->tf_cache + fp, sz);
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp += sz;
199767f8919635c4928607450d9e0abb932109ceToomas Soome p += sz;
199767f8919635c4928607450d9e0abb932109ceToomas Soome size -= sz;
199767f8919635c4928607450d9e0abb932109ceToomas Soome continue;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (get_zipped(tf->tf_pkg, p, sz) == -1) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome sz = -1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp += sz;
199767f8919635c4928607450d9e0abb932109ceToomas Soome p += sz;
199767f8919635c4928607450d9e0abb932109ceToomas Soome size -= sz;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tf->tf_cachesz != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome continue;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf->tf_cachesz = (sz <= PKG_MAXCACHESZ) ? sz : PKG_MAXCACHESZ;
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf->tf_cache = malloc(tf->tf_cachesz);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tf->tf_cache != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome memcpy(tf->tf_cache, buf, tf->tf_cachesz);
199767f8919635c4928607450d9e0abb932109ceToomas Soome else
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf->tf_cachesz = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf->tf_fp = fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (res != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome *res = size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return ((sz == -1) ? errno : 0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic off_t
199767f8919635c4928607450d9e0abb932109ceToomas Soomepkg_seek(struct open_file *f, off_t ofs, int whence)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome char buf[512];
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct tarfile *tf;
199767f8919635c4928607450d9e0abb932109ceToomas Soome off_t delta;
199767f8919635c4928607450d9e0abb932109ceToomas Soome size_t sz, res;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf = (struct tarfile *)f->f_fsdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tf == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome errno = EBADF;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome switch (whence) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome case SEEK_SET:
199767f8919635c4928607450d9e0abb932109ceToomas Soome delta = ofs - tf->tf_fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome case SEEK_CUR:
199767f8919635c4928607450d9e0abb932109ceToomas Soome delta = ofs;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome case SEEK_END:
199767f8919635c4928607450d9e0abb932109ceToomas Soome delta = tf->tf_size - tf->tf_fp + ofs;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome default:
199767f8919635c4928607450d9e0abb932109ceToomas Soome errno = EINVAL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (delta < 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome DBG(("%s: negative file seek (%jd)\n", __func__,
199767f8919635c4928607450d9e0abb932109ceToomas Soome (intmax_t)delta));
199767f8919635c4928607450d9e0abb932109ceToomas Soome errno = ESPIPE;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (delta > 0 && tf->tf_fp < tf->tf_size) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome sz = (delta > sizeof(buf)) ? sizeof(buf) : delta;
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = pkg_read(f, buf, sz, &res);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (error != 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome errno = error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome delta -= sz - res;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (tf->tf_fp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomepkg_stat(struct open_file *f, struct stat *sb)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct tarfile *tf;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf = (struct tarfile *)f->f_fsdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tf == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EBADF);
199767f8919635c4928607450d9e0abb932109ceToomas Soome memset(sb, 0, sizeof(*sb));
199767f8919635c4928607450d9e0abb932109ceToomas Soome sb->st_mode = get_mode(tf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome sb->st_size = tf->tf_size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome sb->st_blocks = (tf->tf_size + 511) / 512;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomepkg_readdir(struct open_file *f, struct dirent *d)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct tarfile *tf;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf = (struct tarfile *)f->f_fsdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tf != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EBADF);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf = scan_tarfile(package, NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tf == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ENOENT);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome d->d_fileno = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome d->d_reclen = sizeof(*d);
199767f8919635c4928607450d9e0abb932109ceToomas Soome d->d_type = DT_REG;
199767f8919635c4928607450d9e0abb932109ceToomas Soome memcpy(d->d_name, tf->tf_hdr.ut_name, sizeof(d->d_name));
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Low-level support functions.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomeget_byte(struct package *pkg, off_t *op)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome int c;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (pkg->pkg_zs.avail_in == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome c = read(pkg->pkg_fd, pkg->pkg_buf, PKG_BUFSIZE);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (c <= 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg->pkg_zs.avail_in = c;
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg->pkg_zs.next_in = pkg->pkg_buf;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome c = *pkg->pkg_zs.next_in;
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg->pkg_zs.next_in++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg->pkg_zs.avail_in--;
199767f8919635c4928607450d9e0abb932109ceToomas Soome (*op)++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (c);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomeget_zipped(struct package *pkg, void *buf, size_t bufsz)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome int c;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg->pkg_zs.next_out = buf;
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg->pkg_zs.avail_out = bufsz;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (pkg->pkg_zs.avail_out) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (pkg->pkg_zs.avail_in == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome c = read(pkg->pkg_fd, pkg->pkg_buf, PKG_BUFSIZE);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (c <= 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome errno = EIO;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg->pkg_zs.avail_in = c;
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg->pkg_zs.next_in = pkg->pkg_buf;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome c = inflate(&pkg->pkg_zs, Z_SYNC_FLUSH);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (c != Z_OK && c != Z_STREAM_END) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome errno = EIO;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg->pkg_ofs += bufsz;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomecache_data(struct tarfile *tf)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct package *pkg;
199767f8919635c4928607450d9e0abb932109ceToomas Soome size_t sz;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tf == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome DBG(("%s: no file to cache data for?\n", __func__));
199767f8919635c4928607450d9e0abb932109ceToomas Soome errno = EINVAL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg = tf->tf_pkg;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (pkg == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome DBG(("%s: no package associated with file?\n", __func__));
199767f8919635c4928607450d9e0abb932109ceToomas Soome errno = EINVAL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tf->tf_ofs != pkg->pkg_ofs) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome DBG(("%s: caching after partial read of file %s?\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome __func__, tf->tf_hdr.ut_name));
199767f8919635c4928607450d9e0abb932109ceToomas Soome errno = EINVAL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* We don't cache everything... */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tf->tf_size > PKG_MAXCACHESZ) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome errno = ENOMEM;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* All files are padded to a multiple of 512 bytes. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome sz = (tf->tf_size + 0x1ff) & ~0x1ff;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf->tf_cache = malloc(sz);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tf->tf_cache == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome DBG(("%s: could not allocate %d bytes\n", __func__, (int)sz));
199767f8919635c4928607450d9e0abb932109ceToomas Soome errno = ENOMEM;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome tf->tf_cachesz = sz;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (get_zipped(pkg, tf->tf_cache, sz));
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Note that this implementation does not (and should not!) obey
199767f8919635c4928607450d9e0abb932109ceToomas Soome * locale settings; you cannot simply substitute strtol here, since
199767f8919635c4928607450d9e0abb932109ceToomas Soome * it does obey locale.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic off_t
199767f8919635c4928607450d9e0abb932109ceToomas Soomepkg_atol8(const char *p, unsigned char_cnt)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome int64_t l, limit, last_digit_limit;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int digit, sign, base;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome base = 8;
199767f8919635c4928607450d9e0abb932109ceToomas Soome limit = INT64_MAX / base;
199767f8919635c4928607450d9e0abb932109ceToomas Soome last_digit_limit = INT64_MAX % base;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (*p == ' ' || *p == '\t')
199767f8919635c4928607450d9e0abb932109ceToomas Soome p++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (*p == '-') {
199767f8919635c4928607450d9e0abb932109ceToomas Soome sign = -1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome p++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else
199767f8919635c4928607450d9e0abb932109ceToomas Soome sign = 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome l = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome digit = *p - '0';
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (digit >= 0 && digit < base && char_cnt-- > 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (l>limit || (l == limit && digit > last_digit_limit)) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome l = UINT64_MAX; /* Truncate on overflow. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome l = (l * base) + digit;
199767f8919635c4928607450d9e0abb932109ceToomas Soome digit = *++p - '0';
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (sign < 0) ? -l : l;
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Parse a base-256 integer. This is just a straight signed binary
199767f8919635c4928607450d9e0abb932109ceToomas Soome * value in big-endian order, except that the high-order bit is
199767f8919635c4928607450d9e0abb932109ceToomas Soome * ignored. Remember that "int64_t" may or may not be exactly 64
199767f8919635c4928607450d9e0abb932109ceToomas Soome * bits; the implementation here tries to avoid making any assumptions
199767f8919635c4928607450d9e0abb932109ceToomas Soome * about the actual size of an int64_t. It does assume we're using
199767f8919635c4928607450d9e0abb932109ceToomas Soome * twos-complement arithmetic, though.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int64_t
199767f8919635c4928607450d9e0abb932109ceToomas Soomepkg_atol256(const char *_p, unsigned char_cnt)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome int64_t l, upper_limit, lower_limit;
199767f8919635c4928607450d9e0abb932109ceToomas Soome const unsigned char *p = (const unsigned char *)_p;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome upper_limit = INT64_MAX / 256;
199767f8919635c4928607450d9e0abb932109ceToomas Soome lower_limit = INT64_MIN / 256;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Pad with 1 or 0 bits, depending on sign. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((0x40 & *p) == 0x40)
199767f8919635c4928607450d9e0abb932109ceToomas Soome l = (int64_t)-1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome else
199767f8919635c4928607450d9e0abb932109ceToomas Soome l = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome l = (l << 6) | (0x3f & *p++);
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (--char_cnt > 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (l > upper_limit) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome l = INT64_MAX; /* Truncate on overflow */
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else if (l < lower_limit) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome l = INT64_MIN;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome l = (l << 8) | (0xff & (int64_t)*p++);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (l);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic off_t
199767f8919635c4928607450d9e0abb932109ceToomas Soomepkg_atol(const char *p, unsigned char_cnt)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Technically, GNU pkg considers a field to be in base-256
199767f8919635c4928607450d9e0abb932109ceToomas Soome * only if the first byte is 0xff or 0x80.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (*p & 0x80)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (pkg_atol256(p, char_cnt));
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (pkg_atol8(p, char_cnt));
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomeget_mode(struct tarfile *tf)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (pkg_atol(tf->tf_hdr.ut_mode, sizeof(tf->tf_hdr.ut_mode)));
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* GZip flag byte */
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define COMMENT 0x10 /* bit 4 set: file comment present */
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define RESERVED 0xE0 /* bits 5..7: reserved */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomenew_package(int fd, struct package **pp)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct package *pkg;
199767f8919635c4928607450d9e0abb932109ceToomas Soome off_t ofs;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int flags, i, error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg = malloc(sizeof(*pkg));
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (pkg == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ENOMEM);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzero(pkg, sizeof(*pkg));
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg->pkg_fd = fd;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Parse the header.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = EFTYPE;
199767f8919635c4928607450d9e0abb932109ceToomas Soome ofs = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Check megic. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (get_byte(pkg, &ofs) != 0x1f || get_byte(pkg, &ofs) != 0x8b)
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto fail;
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Check method. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (get_byte(pkg, &ofs) != Z_DEFLATED)
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto fail;
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Check flags. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome flags = get_byte(pkg, &ofs);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (flags & RESERVED)
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto fail;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Skip time, xflags and OS code. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < 6; i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (get_byte(pkg, &ofs) == -1)
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto fail;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Skip extra field. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (flags & EXTRA_FIELD) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome i = (get_byte(pkg, &ofs) & 0xff) |
199767f8919635c4928607450d9e0abb932109ceToomas Soome ((get_byte(pkg, &ofs) << 8) & 0xff);
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (i-- > 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (get_byte(pkg, &ofs) == -1)
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto fail;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Skip original file name. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (flags & ORIG_NAME) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome do {
199767f8919635c4928607450d9e0abb932109ceToomas Soome i = get_byte(pkg, &ofs);
199767f8919635c4928607450d9e0abb932109ceToomas Soome } while (i != 0 && i != -1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (i == -1)
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto fail;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Print the comment if it's there. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (flags & COMMENT) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (1) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome i = get_byte(pkg, &ofs);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (i == -1)
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto fail;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (i == 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome putchar(i);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Skip the CRC. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (flags & HEAD_CRC) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (get_byte(pkg, &ofs) == -1)
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto fail;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (get_byte(pkg, &ofs) == -1)
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto fail;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Done parsing the ZIP header. Spkgt the inflation engine.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = inflateInit2(&pkg->pkg_zs, -15);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (error != Z_OK)
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto fail;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome *pp = pkg;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome fail:
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(pkg);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (error);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic struct tarfile *
199767f8919635c4928607450d9e0abb932109ceToomas Soomescan_tarfile(struct package *pkg, struct tarfile *last)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome char buf[512];
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct tarfile *cur;
199767f8919635c4928607450d9e0abb932109ceToomas Soome off_t ofs;
199767f8919635c4928607450d9e0abb932109ceToomas Soome size_t sz;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome cur = (last != NULL) ? last->tf_next : pkg->pkg_first;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (cur == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome ofs = (last != NULL) ? last->tf_ofs + last->tf_size :
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg->pkg_ofs;
199767f8919635c4928607450d9e0abb932109ceToomas Soome ofs = (ofs + 0x1ff) & ~0x1ff;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Check if we've reached EOF. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (ofs < pkg->pkg_ofs) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome errno = ENOSPC;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (ofs != pkg->pkg_ofs) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (last != NULL && pkg->pkg_ofs == last->tf_ofs) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (cache_data(last) == -1)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else {
199767f8919635c4928607450d9e0abb932109ceToomas Soome sz = ofs - pkg->pkg_ofs;
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (sz != 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (sz > sizeof(buf))
199767f8919635c4928607450d9e0abb932109ceToomas Soome sz = sizeof(buf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (get_zipped(pkg, buf, sz) == -1)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome sz = ofs - pkg->pkg_ofs;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome cur = malloc(sizeof(*cur));
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (cur == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome memset(cur, 0, sizeof(*cur));
199767f8919635c4928607450d9e0abb932109ceToomas Soome cur->tf_pkg = pkg;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (1) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (get_zipped(pkg, &cur->tf_hdr,
199767f8919635c4928607450d9e0abb932109ceToomas Soome sizeof(cur->tf_hdr)) == -1) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(cur);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * There are always 2 empty blocks appended to
199767f8919635c4928607450d9e0abb932109ceToomas Soome * a PKG. It marks the end of the archive.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (strncmp(cur->tf_hdr.ut_magic, "ustar", 5) != 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(cur);
199767f8919635c4928607450d9e0abb932109ceToomas Soome errno = ENOSPC;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome cur->tf_ofs = pkg->pkg_ofs;
199767f8919635c4928607450d9e0abb932109ceToomas Soome cur->tf_size = pkg_atol(cur->tf_hdr.ut_size,
199767f8919635c4928607450d9e0abb932109ceToomas Soome sizeof(cur->tf_hdr.ut_size));
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (cur->tf_hdr.ut_name[0] != '+')
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Skip package meta-files.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome ofs = cur->tf_ofs + cur->tf_size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome ofs = (ofs + 0x1ff) & ~0x1ff;
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (pkg->pkg_ofs < ofs) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (get_zipped(pkg, buf, sizeof(buf)) == -1) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(cur);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (last != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome last->tf_next = cur;
199767f8919635c4928607450d9e0abb932109ceToomas Soome else
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg->pkg_first = cur;
199767f8919635c4928607450d9e0abb932109ceToomas Soome pkg->pkg_last = cur;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (cur);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}