pkgfs.c revision 199767f8919635c4928607450d9e0abb932109ce
/*-
* 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
*
* 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.
*/
__FBSDID("$FreeBSD$");
#include "stand.h"
#include <string.h>
#include <zlib.h>
#ifdef PKGFS_DEBUG
#else
#define DBG(x)
#endif
struct fs_ops pkgfs_fsops = {
"pkg",
};
#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_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;
};
struct package;
struct tarfile
{
void *tf_cache;
};
struct package
{
int pkg_fd;
};
static int new_package(int, struct package **);
void
pkgfs_cleanup(void)
{
if (tf->tf_cachesz > 0)
}
}
}
int
{
if (proto != &pkgfs_fsops)
if (fd == -1)
return (errno);
if (error) {
return (error);
}
return (EDOOFUS);
return (0);
}
static int new_package(int, struct package **);
static int
{
return (EINVAL);
return (ENXIO);
/*
* We can only read from a package, so reject request to open
* for write-only or read-write.
*/
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') {
return (0);
}
return (0);
}
}
return (errno);
}
static int
{
return (0);
/*
* Free up the cache if we read all of the file.
*/
tf->tf_cachesz = 0;
}
return (0);
}
static int
{
char *p;
return (EBADF);
}
p = buf;
sz = 0;
while (size > 0) {
if (sz == 0)
break;
/* Satisfy the request from cache. */
p += sz;
continue;
}
sz = -1;
break;
}
p += sz;
if (tf->tf_cachesz != 0)
continue;
else
tf->tf_cachesz = 0;
}
}
static off_t
{
char buf[512];
int error;
return (-1);
}
switch (whence) {
case SEEK_SET:
break;
case SEEK_CUR:
break;
case SEEK_END:
break;
default:
return (-1);
}
if (delta < 0) {
return (-1);
}
if (error != 0) {
return (-1);
}
}
}
static int
{
return (EBADF);
return (0);
}
static int
{
return (EBADF);
return (ENOENT);
d->d_fileno = 0;
d->d_reclen = sizeof(*d);
return (0);
}
/*
* Low-level support functions.
*/
static int
{
int c;
if (c <= 0)
return (-1);
}
(*op)++;
return (c);
}
static int
{
int c;
if (c <= 0) {
return (-1);
}
}
if (c != Z_OK && c != Z_STREAM_END) {
return (-1);
}
}
return (0);
}
static int
{
return (-1);
}
return (-1);
}
DBG(("%s: caching after partial read of file %s?\n",
return (-1);
}
/* We don't cache everything... */
return (-1);
}
/* All files are padded to a multiple of 512 bytes. */
return (-1);
}
}
/*
* 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
{
base = 8;
while (*p == ' ' || *p == '\t')
p++;
if (*p == '-') {
sign = -1;
p++;
} else
sign = 1;
l = 0;
digit = *p - '0';
l = UINT64_MAX; /* Truncate on overflow. */
break;
}
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
{
const unsigned char *p = (const unsigned char *)_p;
/* 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;
}
}
return (l);
}
static off_t
{
/*
* 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));
}
static int
{
}
/* GZip flag byte */
static int
{
return (ENOMEM);
/*
* Parse the header.
*/
ofs = 0;
/* Check megic. */
goto fail;
/* Check method. */
goto fail;
/* Check flags. */
goto fail;
/* Skip time, xflags and OS code. */
for (i = 0; i < 6; i++) {
goto fail;
}
/* Skip extra field. */
if (flags & EXTRA_FIELD) {
while (i-- > 0) {
goto fail;
}
}
/* Skip original file name. */
do {
} while (i != 0 && i != -1);
if (i == -1)
goto fail;
}
/* Print the comment if it's there. */
while (1) {
if (i == -1)
goto fail;
if (i == 0)
break;
putchar(i);
}
}
/* Skip the CRC. */
goto fail;
goto fail;
}
/*
* Done parsing the ZIP header. Spkgt the inflation engine.
*/
goto fail;
return (0);
fail:
return (error);
}
static struct tarfile *
{
char buf[512];
/* Check if we've reached EOF. */
return (NULL);
}
return (NULL);
} else {
while (sz != 0) {
return (NULL);
}
}
}
return (NULL);
while (1) {
return (NULL);
}
/*
* There are always 2 empty blocks appended to
* a PKG. It marks the end of the archive.
*/
return (NULL);
}
break;
/*
* Skip package meta-files.
*/
return (NULL);
}
}
}
else
}
return (cur);
}