pkgfs.c revision 329145
1/*-
2 * Copyright (c) 2007-2014, Juniper Networks, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: stable/11/stand/libsa/pkgfs.c 329132 2018-02-11 19:51:29Z kevans $");
29
30#include "stand.h"
31
32#include <sys/stat.h>
33#include <sys/stdint.h>
34#include <string.h>
35#include <zlib.h>
36
37#ifdef PKGFS_DEBUG
38#define	DBG(x)	printf x
39#else
40#define	DBG(x)
41#endif
42
43static int   pkg_open(const char *, struct open_file *);
44static int   pkg_close(struct open_file *);
45static int   pkg_read(struct open_file *, void *, size_t, size_t *);
46static off_t pkg_seek(struct open_file *, off_t, int);
47static int   pkg_stat(struct open_file *, struct stat *);
48static int   pkg_readdir(struct open_file *, struct dirent *);
49
50struct fs_ops pkgfs_fsops = {
51	"pkg",
52	pkg_open,
53	pkg_close,
54	pkg_read,
55	null_write,
56	pkg_seek,
57	pkg_stat,
58	pkg_readdir
59};
60
61#define PKG_BUFSIZE	512
62#define	PKG_MAXCACHESZ	4096
63
64#define	PKG_FILEEXT	".tgz"
65
66/*
67 * Layout of POSIX 'ustar' header.
68 */
69struct ustar_hdr {
70	char	ut_name[100];
71	char	ut_mode[8];
72	char	ut_uid[8];
73	char	ut_gid[8];
74	char	ut_size[12];
75	char	ut_mtime[12];
76	char	ut_checksum[8];
77	char	ut_typeflag[1];
78	char	ut_linkname[100];
79	char	ut_magic[6];		/* For POSIX: "ustar\0" */
80	char	ut_version[2];		/* For POSIX: "00" */
81	char	ut_uname[32];
82	char	ut_gname[32];
83	char	ut_rdevmajor[8];
84	char	ut_rdevminor[8];
85	union {
86		struct {
87			char	prefix[155];
88		} posix;
89		struct {
90			char	atime[12];
91			char	ctime[12];
92			char	offset[12];
93			char	longnames[4];
94			char	unused[1];
95			struct gnu_sparse {
96				char	offset[12];
97				char	numbytes[12];
98			} sparse[4];
99			char	isextended[1];
100			char	realsize[12];
101		} gnu;
102	} u;
103	u_char __padding[12];
104};
105
106struct package;
107
108struct tarfile
109{
110	struct package *tf_pkg;
111	struct tarfile *tf_next;
112	struct ustar_hdr tf_hdr;
113	off_t	tf_ofs;
114	off_t	tf_size;
115	off_t	tf_fp;
116	size_t	tf_cachesz;
117	void	*tf_cache;
118};
119
120struct package
121{
122	struct package *pkg_chain;
123	int	pkg_fd;
124	off_t	pkg_ofs;
125	z_stream pkg_zs;
126	struct tarfile *pkg_first;
127	struct tarfile *pkg_last;
128	u_char	pkg_buf[PKG_BUFSIZE];
129};
130
131static struct package *package = NULL;
132
133static int new_package(int, struct package **);
134
135void
136pkgfs_cleanup(void)
137{
138	struct package *chain;
139	struct tarfile *tf, *tfn;
140
141	while (package != NULL) {
142		inflateEnd(&package->pkg_zs);
143		close(package->pkg_fd);
144
145		tf = package->pkg_first;
146		while (tf != NULL) {
147			tfn = tf->tf_next;
148			if (tf->tf_cachesz > 0)
149				free(tf->tf_cache);
150			free(tf);
151			tf = tfn;
152		}
153
154		chain = package->pkg_chain;
155		free(package);
156		package = chain;
157	}
158}
159
160int
161pkgfs_init(const char *pkgname, struct fs_ops *proto)
162{
163	struct package *pkg;
164	int error, fd;
165
166	if (proto != &pkgfs_fsops)
167		pkgfs_cleanup();
168
169	exclusive_file_system = proto;
170
171	fd = open(pkgname, O_RDONLY);
172
173	exclusive_file_system = NULL;
174
175	if (fd == -1)
176		return (errno);
177
178	error = new_package(fd, &pkg);
179	if (error) {
180		close(fd);
181		return (error);
182	}
183
184	if (pkg == NULL)
185		return (EDOOFUS);
186
187	pkg->pkg_chain = package;
188	package = pkg;
189	exclusive_file_system = &pkgfs_fsops;
190	return (0);
191}
192
193static int get_mode(struct tarfile *);
194static int get_zipped(struct package *, void *, size_t);
195static int new_package(int, struct package **);
196static struct tarfile *scan_tarfile(struct package *, struct tarfile *);
197
198static int
199pkg_open(const char *fn, struct open_file *f)
200{
201	struct tarfile *tf;
202
203	if (fn == NULL || f == NULL)
204		return (EINVAL);
205
206	if (package == NULL)
207		return (ENXIO);
208
209	/*
210	 * We can only read from a package, so reject request to open
211	 * for write-only or read-write.
212	 */
213	if (f->f_flags != F_READ)
214		return (EPERM);
215
216	/*
217	 * Scan the file headers for the named file. We stop scanning
218	 * at the first filename that has the .pkg extension. This is
219	 * a package within a package. We assume we have all the files
220	 * we need up-front and without having to dig within nested
221	 * packages.
222	 *
223	 * Note that we preserve streaming properties as much as possible.
224	 */
225	while (*fn == '/')
226		fn++;
227
228	/*
229	 * Allow opening of the root directory for use by readdir()
230	 * to support listing files in the package.
231	 */
232	if (*fn == '\0') {
233		f->f_fsdata = NULL;
234		return (0);
235	}
236
237	tf = scan_tarfile(package, NULL);
238	while (tf != NULL) {
239		if (strcmp(fn, tf->tf_hdr.ut_name) == 0) {
240			f->f_fsdata = tf;
241			tf->tf_fp = 0;	/* Reset the file pointer. */
242			return (0);
243		}
244		tf = scan_tarfile(package, tf);
245	}
246	return (errno);
247}
248
249static int
250pkg_close(struct open_file *f)
251{
252	struct tarfile *tf;
253
254	tf = (struct tarfile *)f->f_fsdata;
255	if (tf == NULL)
256		return (0);
257
258	/*
259	 * Free up the cache if we read all of the file.
260	 */
261	if (tf->tf_fp == tf->tf_size && tf->tf_cachesz > 0) {
262		free(tf->tf_cache);
263		tf->tf_cachesz = 0;
264	}
265	return (0);
266}
267
268static int
269pkg_read(struct open_file *f, void *buf, size_t size, size_t *res)
270{
271	struct tarfile *tf;
272	char *p;
273	off_t fp;
274	size_t sz;
275
276	tf = (struct tarfile *)f->f_fsdata;
277	if (tf == NULL) {
278		if (res != NULL)
279			*res = size;
280		return (EBADF);
281	}
282
283	fp = tf->tf_fp;
284	p = buf;
285	sz = 0;
286	while (size > 0) {
287		sz = tf->tf_size - fp;
288		if (fp < tf->tf_cachesz && tf->tf_cachesz < tf->tf_size)
289			sz = tf->tf_cachesz - fp;
290		if (size < sz)
291			sz = size;
292		if (sz == 0)
293			break;
294
295		if (fp < tf->tf_cachesz) {
296			/* Satisfy the request from cache. */
297			memcpy(p, tf->tf_cache + fp, sz);
298			fp += sz;
299			p += sz;
300			size -= sz;
301			continue;
302		}
303
304		if (get_zipped(tf->tf_pkg, p, sz) == -1) {
305			sz = -1;
306			break;
307		}
308
309		fp += sz;
310		p += sz;
311		size -= sz;
312
313		if (tf->tf_cachesz != 0)
314			continue;
315
316		tf->tf_cachesz = (sz <= PKG_MAXCACHESZ) ? sz : PKG_MAXCACHESZ;
317		tf->tf_cache = malloc(tf->tf_cachesz);
318		if (tf->tf_cache != NULL)
319			memcpy(tf->tf_cache, buf, tf->tf_cachesz);
320		else
321			tf->tf_cachesz = 0;
322	}
323
324	tf->tf_fp = fp;
325	if (res != NULL)
326		*res = size;
327	return ((sz == -1) ? errno : 0);
328}
329
330static off_t
331pkg_seek(struct open_file *f, off_t ofs, int whence)
332{
333	char buf[512];
334	struct tarfile *tf;
335	off_t delta;
336	size_t sz, res;
337	int error;
338
339	tf = (struct tarfile *)f->f_fsdata;
340	if (tf == NULL) {
341		errno = EBADF;
342		return (-1);
343	}
344
345	switch (whence) {
346	case SEEK_SET:
347		delta = ofs - tf->tf_fp;
348		break;
349	case SEEK_CUR:
350		delta = ofs;
351		break;
352	case SEEK_END:
353		delta = tf->tf_size - tf->tf_fp + ofs;
354		break;
355	default:
356		errno = EINVAL;
357		return (-1);
358	}
359
360	if (delta < 0) {
361		DBG(("%s: negative file seek (%jd)\n", __func__,
362		    (intmax_t)delta));
363		errno = ESPIPE;
364		return (-1);
365	}
366
367	while (delta > 0 && tf->tf_fp < tf->tf_size) {
368		sz = (delta > sizeof(buf)) ? sizeof(buf) : delta;
369		error = pkg_read(f, buf, sz, &res);
370		if (error != 0) {
371			errno = error;
372			return (-1);
373		}
374		delta -= sz - res;
375	}
376
377	return (tf->tf_fp);
378}
379
380static int
381pkg_stat(struct open_file *f, struct stat *sb)
382{
383	struct tarfile *tf;
384
385	tf = (struct tarfile *)f->f_fsdata;
386	if (tf == NULL)
387		return (EBADF);
388	memset(sb, 0, sizeof(*sb));
389	sb->st_mode = get_mode(tf);
390	sb->st_size = tf->tf_size;
391	sb->st_blocks = (tf->tf_size + 511) / 512;
392	return (0);
393}
394
395static int
396pkg_readdir(struct open_file *f, struct dirent *d)
397{
398	struct tarfile *tf;
399
400	tf = (struct tarfile *)f->f_fsdata;
401	if (tf != NULL)
402		return (EBADF);
403
404	tf = scan_tarfile(package, NULL);
405	if (tf == NULL)
406		return (ENOENT);
407
408	d->d_fileno = 0;
409	d->d_reclen = sizeof(*d);
410	d->d_type = DT_REG;
411	memcpy(d->d_name, tf->tf_hdr.ut_name, sizeof(d->d_name));
412	return (0);
413}
414
415/*
416 * Low-level support functions.
417 */
418
419static int
420get_byte(struct package *pkg, off_t *op)
421{
422	int c;
423
424	if (pkg->pkg_zs.avail_in == 0) {
425		c = read(pkg->pkg_fd, pkg->pkg_buf, PKG_BUFSIZE);
426		if (c <= 0)
427			return (-1);
428		pkg->pkg_zs.avail_in = c;
429		pkg->pkg_zs.next_in = pkg->pkg_buf;
430	}
431
432	c = *pkg->pkg_zs.next_in;
433	pkg->pkg_zs.next_in++;
434	pkg->pkg_zs.avail_in--;
435	(*op)++;
436	return (c);
437}
438
439static int
440get_zipped(struct package *pkg, void *buf, size_t bufsz)
441{
442	int c;
443
444	pkg->pkg_zs.next_out = buf;
445	pkg->pkg_zs.avail_out = bufsz;
446
447	while (pkg->pkg_zs.avail_out) {
448		if (pkg->pkg_zs.avail_in == 0) {
449			c = read(pkg->pkg_fd, pkg->pkg_buf, PKG_BUFSIZE);
450			if (c <= 0) {
451				errno = EIO;
452				return (-1);
453			}
454			pkg->pkg_zs.avail_in = c;
455			pkg->pkg_zs.next_in = pkg->pkg_buf;
456		}
457
458		c = inflate(&pkg->pkg_zs, Z_SYNC_FLUSH);
459		if (c != Z_OK && c != Z_STREAM_END) {
460			errno = EIO;
461			return (-1);
462		}
463	}
464
465	pkg->pkg_ofs += bufsz;
466	return (0);
467}
468
469static int
470cache_data(struct tarfile *tf)
471{
472	struct package *pkg;
473	size_t sz;
474
475	if (tf == NULL) {
476		DBG(("%s: no file to cache data for?\n", __func__));
477		errno = EINVAL;
478		return (-1);
479	}
480
481	pkg = tf->tf_pkg;
482	if (pkg == NULL) {
483		DBG(("%s: no package associated with file?\n", __func__));
484		errno = EINVAL;
485		return (-1);
486	}
487
488	if (tf->tf_ofs != pkg->pkg_ofs) {
489		DBG(("%s: caching after partial read of file %s?\n",
490		    __func__, tf->tf_hdr.ut_name));
491		errno = EINVAL;
492		return (-1);
493	}
494
495	/* We don't cache everything... */
496	if (tf->tf_size > PKG_MAXCACHESZ) {
497		errno = ENOMEM;
498		return (-1);
499	}
500
501	/* All files are padded to a multiple of 512 bytes. */
502	sz = (tf->tf_size + 0x1ff) & ~0x1ff;
503
504	tf->tf_cache = malloc(sz);
505	if (tf->tf_cache == NULL) {
506		DBG(("%s: could not allocate %d bytes\n", __func__, (int)sz));
507		errno = ENOMEM;
508		return (-1);
509	}
510
511	tf->tf_cachesz = sz;
512	return (get_zipped(pkg, tf->tf_cache, sz));
513}
514
515/*
516 * Note that this implementation does not (and should not!) obey
517 * locale settings; you cannot simply substitute strtol here, since
518 * it does obey locale.
519 */
520static off_t
521pkg_atol8(const char *p, unsigned char_cnt)
522{
523        int64_t l, limit, last_digit_limit;
524        int digit, sign, base;
525
526        base = 8;
527        limit = INT64_MAX / base;
528        last_digit_limit = INT64_MAX % base;
529
530        while (*p == ' ' || *p == '\t')
531                p++;
532        if (*p == '-') {
533                sign = -1;
534                p++;
535        } else
536                sign = 1;
537
538        l = 0;
539        digit = *p - '0';
540        while (digit >= 0 && digit < base  && char_cnt-- > 0) {
541                if (l>limit || (l == limit && digit > last_digit_limit)) {
542                        l = UINT64_MAX; /* Truncate on overflow. */
543                        break;
544                }
545                l = (l * base) + digit;
546                digit = *++p - '0';
547        }
548        return (sign < 0) ? -l : l;
549}
550
551/*
552 * Parse a base-256 integer.  This is just a straight signed binary
553 * value in big-endian order, except that the high-order bit is
554 * ignored.  Remember that "int64_t" may or may not be exactly 64
555 * bits; the implementation here tries to avoid making any assumptions
556 * about the actual size of an int64_t.  It does assume we're using
557 * twos-complement arithmetic, though.
558 */
559static int64_t
560pkg_atol256(const char *_p, unsigned char_cnt)
561{
562        int64_t l, upper_limit, lower_limit;
563        const unsigned char *p = (const unsigned char *)_p;
564
565        upper_limit = INT64_MAX / 256;
566        lower_limit = INT64_MIN / 256;
567
568        /* Pad with 1 or 0 bits, depending on sign. */
569        if ((0x40 & *p) == 0x40)
570                l = (int64_t)-1;
571        else
572                l = 0;
573        l = (l << 6) | (0x3f & *p++);
574        while (--char_cnt > 0) {
575                if (l > upper_limit) {
576                        l = INT64_MAX; /* Truncate on overflow */
577                        break;
578                } else if (l < lower_limit) {
579                        l = INT64_MIN;
580                        break;
581                }
582                l = (l << 8) | (0xff & (int64_t)*p++);
583        }
584        return (l);
585}
586
587static off_t
588pkg_atol(const char *p, unsigned char_cnt)
589{
590	/*
591	 * Technically, GNU pkg considers a field to be in base-256
592	 * only if the first byte is 0xff or 0x80.
593	 */
594	if (*p & 0x80)
595		return (pkg_atol256(p, char_cnt));
596	return (pkg_atol8(p, char_cnt));
597}
598
599static int
600get_mode(struct tarfile *tf)
601{
602	return (pkg_atol(tf->tf_hdr.ut_mode, sizeof(tf->tf_hdr.ut_mode)));
603}
604
605/* GZip flag byte */
606#define ASCII_FLAG	0x01 /* bit 0 set: file probably ascii text */
607#define HEAD_CRC	0x02 /* bit 1 set: header CRC present */
608#define EXTRA_FIELD	0x04 /* bit 2 set: extra field present */
609#define ORIG_NAME	0x08 /* bit 3 set: original file name present */
610#define COMMENT		0x10 /* bit 4 set: file comment present */
611#define RESERVED	0xE0 /* bits 5..7: reserved */
612
613static int
614new_package(int fd, struct package **pp)
615{
616	struct package *pkg;
617	off_t ofs;
618	int flags, i, error;
619
620	pkg = malloc(sizeof(*pkg));
621	if (pkg == NULL)
622		return (ENOMEM);
623
624	bzero(pkg, sizeof(*pkg));
625	pkg->pkg_fd = fd;
626
627	/*
628	 * Parse the header.
629	 */
630	error = EFTYPE;
631	ofs = 0;
632
633	/* Check megic. */
634	if (get_byte(pkg, &ofs) != 0x1f || get_byte(pkg, &ofs) != 0x8b)
635		goto fail;
636	/* Check method. */
637	if (get_byte(pkg, &ofs) != Z_DEFLATED)
638		goto fail;
639	/* Check flags. */
640	flags = get_byte(pkg, &ofs);
641	if (flags & RESERVED)
642		goto fail;
643
644	/* Skip time, xflags and OS code. */
645	for (i = 0; i < 6; i++) {
646		if (get_byte(pkg, &ofs) == -1)
647			goto fail;
648	}
649
650	/* Skip extra field. */
651	if (flags & EXTRA_FIELD) {
652		i = (get_byte(pkg, &ofs) & 0xff) |
653		    ((get_byte(pkg, &ofs) << 8) & 0xff);
654		while (i-- > 0) {
655			if (get_byte(pkg, &ofs) == -1)
656				goto fail;
657		}
658	}
659
660	/* Skip original file name. */
661	if (flags & ORIG_NAME) {
662		do {
663			i = get_byte(pkg, &ofs);
664		} while (i != 0 && i != -1);
665		if (i == -1)
666			goto fail;
667	}
668
669	/* Print the comment if it's there. */
670	if (flags & COMMENT) {
671		while (1) {
672			i = get_byte(pkg, &ofs);
673			if (i == -1)
674				goto fail;
675			if (i == 0)
676				break;
677			putchar(i);
678		}
679	}
680
681	/* Skip the CRC. */
682	if (flags & HEAD_CRC) {
683		if (get_byte(pkg, &ofs) == -1)
684			goto fail;
685		if (get_byte(pkg, &ofs) == -1)
686			goto fail;
687	}
688
689	/*
690	 * Done parsing the ZIP header. Spkgt the inflation engine.
691	 */
692	error = inflateInit2(&pkg->pkg_zs, -15);
693	if (error != Z_OK)
694		goto fail;
695
696	*pp = pkg;
697	return (0);
698
699 fail:
700	free(pkg);
701	return (error);
702}
703
704static struct tarfile *
705scan_tarfile(struct package *pkg, struct tarfile *last)
706{
707	char buf[512];
708	struct tarfile *cur;
709	off_t ofs;
710	size_t sz;
711
712	cur = (last != NULL) ? last->tf_next : pkg->pkg_first;
713	if (cur == NULL) {
714		ofs = (last != NULL) ? last->tf_ofs + last->tf_size :
715		    pkg->pkg_ofs;
716		ofs = (ofs + 0x1ff) & ~0x1ff;
717
718		/* Check if we've reached EOF. */
719		if (ofs < pkg->pkg_ofs) {
720			errno = ENOSPC;
721			return (NULL);
722		}
723
724		if (ofs != pkg->pkg_ofs) {
725			if (last != NULL && pkg->pkg_ofs == last->tf_ofs) {
726				if (cache_data(last) == -1)
727					return (NULL);
728			} else {
729				sz = ofs - pkg->pkg_ofs;
730				while (sz != 0) {
731					if (sz > sizeof(buf))
732						sz = sizeof(buf);
733					if (get_zipped(pkg, buf, sz) == -1)
734						return (NULL);
735					sz = ofs - pkg->pkg_ofs;
736				}
737			}
738		}
739
740		cur = malloc(sizeof(*cur));
741		if (cur == NULL)
742			return (NULL);
743		memset(cur, 0, sizeof(*cur));
744		cur->tf_pkg = pkg;
745
746		while (1) {
747			if (get_zipped(pkg, &cur->tf_hdr,
748			    sizeof(cur->tf_hdr)) == -1) {
749				free(cur);
750				return (NULL);
751			}
752
753			/*
754			 * There are always 2 empty blocks appended to
755			 * a PKG. It marks the end of the archive.
756			 */
757			if (strncmp(cur->tf_hdr.ut_magic, "ustar", 5) != 0) {
758				free(cur);
759				errno = ENOSPC;
760				return (NULL);
761			}
762
763			cur->tf_ofs = pkg->pkg_ofs;
764			cur->tf_size = pkg_atol(cur->tf_hdr.ut_size,
765			    sizeof(cur->tf_hdr.ut_size));
766
767			if (cur->tf_hdr.ut_name[0] != '+')
768				break;
769
770			/*
771			 * Skip package meta-files.
772			 */
773			ofs = cur->tf_ofs + cur->tf_size;
774			ofs = (ofs + 0x1ff) & ~0x1ff;
775			while (pkg->pkg_ofs < ofs) {
776				if (get_zipped(pkg, buf, sizeof(buf)) == -1) {
777					free(cur);
778					return (NULL);
779				}
780			}
781		}
782
783		if (last != NULL)
784			last->tf_next = cur;
785		else
786			pkg->pkg_first = cur;
787		pkg->pkg_last = cur;
788	}
789
790	return (cur);
791}
792