1228753Smm/*-
2228753Smm * Copyright (c) 2003-2007 Tim Kientzle
3228753Smm * Copyright (c) 2008 Joerg Sonnenberger
4248616Smm * Copyright (c) 2011-2012 Michihiro NAKAJIMA
5228753Smm * All rights reserved.
6228753Smm *
7228753Smm * Redistribution and use in source and binary forms, with or without
8228753Smm * modification, are permitted provided that the following conditions
9228753Smm * are met:
10228753Smm * 1. Redistributions of source code must retain the above copyright
11228753Smm *    notice, this list of conditions and the following disclaimer.
12228753Smm * 2. Redistributions in binary form must reproduce the above copyright
13228753Smm *    notice, this list of conditions and the following disclaimer in the
14228753Smm *    documentation and/or other materials provided with the distribution.
15228753Smm *
16228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
17228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
20228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26228753Smm */
27228753Smm
28228753Smm#include "archive_platform.h"
29228763Smm__FBSDID("$FreeBSD: stable/10/contrib/libarchive/libarchive/archive_read_support_format_mtree.c 368708 2020-12-16 22:25:40Z mm $");
30228753Smm
31228753Smm#ifdef HAVE_SYS_STAT_H
32228753Smm#include <sys/stat.h>
33228753Smm#endif
34228753Smm#ifdef HAVE_ERRNO_H
35228753Smm#include <errno.h>
36228753Smm#endif
37228753Smm#ifdef HAVE_FCNTL_H
38228753Smm#include <fcntl.h>
39228753Smm#endif
40228753Smm#include <stddef.h>
41228753Smm/* #include <stdint.h> */ /* See archive_platform.h */
42228753Smm#ifdef HAVE_STDLIB_H
43228753Smm#include <stdlib.h>
44228753Smm#endif
45228753Smm#ifdef HAVE_STRING_H
46228753Smm#include <string.h>
47228753Smm#endif
48348608Smm#ifdef HAVE_CTYPE_H
49348608Smm#include <ctype.h>
50348608Smm#endif
51228753Smm
52228753Smm#include "archive.h"
53228753Smm#include "archive_entry.h"
54368708Smm#include "archive_entry_private.h"
55228753Smm#include "archive_private.h"
56337352Smm#include "archive_rb.h"
57228753Smm#include "archive_read_private.h"
58228753Smm#include "archive_string.h"
59302001Smm#include "archive_pack_dev.h"
60228753Smm
61228753Smm#ifndef O_BINARY
62228753Smm#define	O_BINARY 0
63228753Smm#endif
64248616Smm#ifndef O_CLOEXEC
65248616Smm#define O_CLOEXEC	0
66248616Smm#endif
67228753Smm
68228753Smm#define	MTREE_HAS_DEVICE	0x0001
69228753Smm#define	MTREE_HAS_FFLAGS	0x0002
70228753Smm#define	MTREE_HAS_GID		0x0004
71228753Smm#define	MTREE_HAS_GNAME		0x0008
72228753Smm#define	MTREE_HAS_MTIME		0x0010
73228753Smm#define	MTREE_HAS_NLINK		0x0020
74228753Smm#define	MTREE_HAS_PERM		0x0040
75228753Smm#define	MTREE_HAS_SIZE		0x0080
76228753Smm#define	MTREE_HAS_TYPE		0x0100
77228753Smm#define	MTREE_HAS_UID		0x0200
78228753Smm#define	MTREE_HAS_UNAME		0x0400
79228753Smm
80228753Smm#define	MTREE_HAS_OPTIONAL	0x0800
81248616Smm#define	MTREE_HAS_NOCHANGE	0x1000 /* FreeBSD specific */
82228753Smm
83324418Smm#define	MAX_LINE_LEN		(1024 * 1024)
84324418Smm
85228753Smmstruct mtree_option {
86228753Smm	struct mtree_option *next;
87228753Smm	char *value;
88228753Smm};
89228753Smm
90228753Smmstruct mtree_entry {
91337352Smm	struct archive_rb_node rbnode;
92337352Smm	struct mtree_entry *next_dup;
93228753Smm	struct mtree_entry *next;
94228753Smm	struct mtree_option *options;
95228753Smm	char *name;
96228753Smm	char full;
97228753Smm	char used;
98228753Smm};
99228753Smm
100228753Smmstruct mtree {
101228753Smm	struct archive_string	 line;
102228753Smm	size_t			 buffsize;
103228753Smm	char			*buff;
104232153Smm	int64_t			 offset;
105228753Smm	int			 fd;
106228753Smm	int			 archive_format;
107228753Smm	const char		*archive_format_name;
108228753Smm	struct mtree_entry	*entries;
109228753Smm	struct mtree_entry	*this_entry;
110337352Smm	struct archive_rb_tree	 entry_rbtree;
111228753Smm	struct archive_string	 current_dir;
112228753Smm	struct archive_string	 contents_name;
113228753Smm
114228753Smm	struct archive_entry_linkresolver *resolver;
115337352Smm	struct archive_rb_tree rbtree;
116228753Smm
117232153Smm	int64_t			 cur_size;
118302001Smm	char checkfs;
119228753Smm};
120228753Smm
121232153Smmstatic int	bid_keycmp(const char *, const char *, ssize_t);
122228753Smmstatic int	cleanup(struct archive_read *);
123248616Smmstatic int	detect_form(struct archive_read *, int *);
124232153Smmstatic int	mtree_bid(struct archive_read *, int);
125228753Smmstatic int	parse_file(struct archive_read *, struct archive_entry *,
126228753Smm		    struct mtree *, struct mtree_entry *, int *);
127228753Smmstatic void	parse_escapes(char *, struct mtree_entry *);
128228753Smmstatic int	parse_line(struct archive_read *, struct archive_entry *,
129228753Smm		    struct mtree *, struct mtree_entry *, int *);
130228753Smmstatic int	parse_keyword(struct archive_read *, struct mtree *,
131228753Smm		    struct archive_entry *, struct mtree_option *, int *);
132228753Smmstatic int	read_data(struct archive_read *a,
133232153Smm		    const void **buff, size_t *size, int64_t *offset);
134228753Smmstatic ssize_t	readline(struct archive_read *, struct mtree *, char **, ssize_t);
135228753Smmstatic int	skip(struct archive_read *a);
136228753Smmstatic int	read_header(struct archive_read *,
137228753Smm		    struct archive_entry *);
138318483Smmstatic int64_t	mtree_atol(char **, int base);
139228753Smm
140232153Smm/*
141232153Smm * There's no standard for TIME_T_MAX/TIME_T_MIN.  So we compute them
142232153Smm * here.  TODO: Move this to configure time, but be careful
143232153Smm * about cross-compile environments.
144232153Smm */
145232153Smmstatic int64_t
146232153Smmget_time_t_max(void)
147232153Smm{
148232153Smm#if defined(TIME_T_MAX)
149232153Smm	return TIME_T_MAX;
150232153Smm#else
151302001Smm	/* ISO C allows time_t to be a floating-point type,
152302001Smm	   but POSIX requires an integer type.  The following
153302001Smm	   should work on any system that follows the POSIX
154302001Smm	   conventions. */
155302001Smm	if (((time_t)0) < ((time_t)-1)) {
156302001Smm		/* Time_t is unsigned */
157302001Smm		return (~(time_t)0);
158302001Smm	} else {
159302001Smm		/* Time_t is signed. */
160302001Smm		/* Assume it's the same as int64_t or int32_t */
161302001Smm		if (sizeof(time_t) == sizeof(int64_t)) {
162302001Smm			return (time_t)INT64_MAX;
163302001Smm		} else {
164302001Smm			return (time_t)INT32_MAX;
165232153Smm		}
166232153Smm	}
167232153Smm#endif
168232153Smm}
169232153Smm
170232153Smmstatic int64_t
171232153Smmget_time_t_min(void)
172232153Smm{
173232153Smm#if defined(TIME_T_MIN)
174232153Smm	return TIME_T_MIN;
175232153Smm#else
176302001Smm	if (((time_t)0) < ((time_t)-1)) {
177302001Smm		/* Time_t is unsigned */
178302001Smm		return (time_t)0;
179302001Smm	} else {
180302001Smm		/* Time_t is signed. */
181302001Smm		if (sizeof(time_t) == sizeof(int64_t)) {
182302001Smm			return (time_t)INT64_MIN;
183302001Smm		} else {
184302001Smm			return (time_t)INT32_MIN;
185302001Smm		}
186232153Smm	}
187232153Smm#endif
188232153Smm}
189232153Smm
190302001Smmstatic int
191302001Smmarchive_read_format_mtree_options(struct archive_read *a,
192302001Smm    const char *key, const char *val)
193302001Smm{
194302001Smm	struct mtree *mtree;
195302001Smm
196302001Smm	mtree = (struct mtree *)(a->format->data);
197302001Smm	if (strcmp(key, "checkfs")  == 0) {
198302001Smm		/* Allows to read information missing from the mtree from the file system */
199302001Smm		if (val == NULL || val[0] == 0) {
200302001Smm			mtree->checkfs = 0;
201302001Smm		} else {
202302001Smm			mtree->checkfs = 1;
203302001Smm		}
204302001Smm		return (ARCHIVE_OK);
205302001Smm	}
206302001Smm
207302001Smm	/* Note: The "warn" return is just to inform the options
208302001Smm	 * supervisor that we didn't handle it.  It will generate
209302001Smm	 * a suitable error if no one used this option. */
210302001Smm	return (ARCHIVE_WARN);
211302001Smm}
212302001Smm
213228753Smmstatic void
214228753Smmfree_options(struct mtree_option *head)
215228753Smm{
216228753Smm	struct mtree_option *next;
217228753Smm
218228753Smm	for (; head != NULL; head = next) {
219228753Smm		next = head->next;
220228753Smm		free(head->value);
221228753Smm		free(head);
222228753Smm	}
223228753Smm}
224228753Smm
225337352Smmstatic int
226337352Smmmtree_cmp_node(const struct archive_rb_node *n1,
227337352Smm    const struct archive_rb_node *n2)
228337352Smm{
229337352Smm	const struct mtree_entry *e1 = (const struct mtree_entry *)n1;
230337352Smm	const struct mtree_entry *e2 = (const struct mtree_entry *)n2;
231337352Smm
232337352Smm	return (strcmp(e1->name, e2->name));
233337352Smm}
234337352Smm
235337352Smmstatic int
236337352Smmmtree_cmp_key(const struct archive_rb_node *n, const void *key)
237337352Smm{
238337352Smm	const struct mtree_entry *e = (const struct mtree_entry *)n;
239337352Smm
240337352Smm	return (strcmp(e->name, key));
241337352Smm}
242337352Smm
243228753Smmint
244228753Smmarchive_read_support_format_mtree(struct archive *_a)
245228753Smm{
246337352Smm	static const struct archive_rb_tree_ops rb_ops = {
247337352Smm		mtree_cmp_node, mtree_cmp_key,
248337352Smm	};
249228753Smm	struct archive_read *a = (struct archive_read *)_a;
250228753Smm	struct mtree *mtree;
251228753Smm	int r;
252228753Smm
253232153Smm	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
254232153Smm	    ARCHIVE_STATE_NEW, "archive_read_support_format_mtree");
255232153Smm
256311042Smm	mtree = (struct mtree *)calloc(1, sizeof(*mtree));
257228753Smm	if (mtree == NULL) {
258228753Smm		archive_set_error(&a->archive, ENOMEM,
259228753Smm		    "Can't allocate mtree data");
260228753Smm		return (ARCHIVE_FATAL);
261228753Smm	}
262358090Smm	mtree->checkfs = 0;
263228753Smm	mtree->fd = -1;
264228753Smm
265337352Smm	__archive_rb_tree_init(&mtree->rbtree, &rb_ops);
266337352Smm
267228753Smm	r = __archive_read_register_format(a, mtree, "mtree",
268302001Smm           mtree_bid, archive_read_format_mtree_options, read_header, read_data, skip, NULL, cleanup, NULL, NULL);
269228753Smm
270228753Smm	if (r != ARCHIVE_OK)
271228753Smm		free(mtree);
272228753Smm	return (ARCHIVE_OK);
273228753Smm}
274228753Smm
275228753Smmstatic int
276228753Smmcleanup(struct archive_read *a)
277228753Smm{
278228753Smm	struct mtree *mtree;
279228753Smm	struct mtree_entry *p, *q;
280228753Smm
281228753Smm	mtree = (struct mtree *)(a->format->data);
282228753Smm
283228753Smm	p = mtree->entries;
284228753Smm	while (p != NULL) {
285228753Smm		q = p->next;
286228753Smm		free(p->name);
287228753Smm		free_options(p->options);
288228753Smm		free(p);
289228753Smm		p = q;
290228753Smm	}
291228753Smm	archive_string_free(&mtree->line);
292228753Smm	archive_string_free(&mtree->current_dir);
293228753Smm	archive_string_free(&mtree->contents_name);
294228753Smm	archive_entry_linkresolver_free(mtree->resolver);
295228753Smm
296228753Smm	free(mtree->buff);
297228753Smm	free(mtree);
298228753Smm	(a->format->data) = NULL;
299228753Smm	return (ARCHIVE_OK);
300228753Smm}
301228753Smm
302232153Smmstatic ssize_t
303232153Smmget_line_size(const char *b, ssize_t avail, ssize_t *nlsize)
304232153Smm{
305232153Smm	ssize_t len;
306228753Smm
307232153Smm	len = 0;
308232153Smm	while (len < avail) {
309232153Smm		switch (*b) {
310232153Smm		case '\0':/* Non-ascii character or control character. */
311232153Smm			if (nlsize != NULL)
312232153Smm				*nlsize = 0;
313232153Smm			return (-1);
314232153Smm		case '\r':
315232153Smm			if (avail-len > 1 && b[1] == '\n') {
316232153Smm				if (nlsize != NULL)
317232153Smm					*nlsize = 2;
318232153Smm				return (len+2);
319232153Smm			}
320232153Smm			/* FALL THROUGH */
321232153Smm		case '\n':
322232153Smm			if (nlsize != NULL)
323232153Smm				*nlsize = 1;
324232153Smm			return (len+1);
325232153Smm		default:
326232153Smm			b++;
327232153Smm			len++;
328232153Smm			break;
329232153Smm		}
330232153Smm	}
331232153Smm	if (nlsize != NULL)
332232153Smm		*nlsize = 0;
333232153Smm	return (avail);
334232153Smm}
335232153Smm
336307139Smm/*
337307139Smm *  <---------------- ravail --------------------->
338307139Smm *  <-- diff ------> <---  avail ----------------->
339307139Smm *                   <---- len ----------->
340307139Smm * | Previous lines | line being parsed  nl extra |
341307139Smm *                  ^
342307139Smm *                  b
343307139Smm *
344307139Smm */
345232153Smmstatic ssize_t
346232153Smmnext_line(struct archive_read *a,
347232153Smm    const char **b, ssize_t *avail, ssize_t *ravail, ssize_t *nl)
348232153Smm{
349232153Smm	ssize_t len;
350232153Smm	int quit;
351232153Smm
352232153Smm	quit = 0;
353232153Smm	if (*avail == 0) {
354232153Smm		*nl = 0;
355232153Smm		len = 0;
356232153Smm	} else
357232153Smm		len = get_line_size(*b, *avail, nl);
358232153Smm	/*
359232153Smm	 * Read bytes more while it does not reach the end of line.
360232153Smm	 */
361232153Smm	while (*nl == 0 && len == *avail && !quit) {
362232153Smm		ssize_t diff = *ravail - *avail;
363232153Smm		size_t nbytes_req = (*ravail+1023) & ~1023U;
364232153Smm		ssize_t tested;
365232153Smm
366324418Smm		/*
367324418Smm		 * Place an arbitrary limit on the line length.
368324418Smm		 * mtree is almost free-form input and without line length limits,
369324418Smm		 * it can consume a lot of memory.
370324418Smm		 */
371324418Smm		if (len >= MAX_LINE_LEN)
372324418Smm			return (-1);
373324418Smm
374232153Smm		/* Increase reading bytes if it is not enough to at least
375232153Smm		 * new two lines. */
376232153Smm		if (nbytes_req < (size_t)*ravail + 160)
377232153Smm			nbytes_req <<= 1;
378232153Smm
379232153Smm		*b = __archive_read_ahead(a, nbytes_req, avail);
380232153Smm		if (*b == NULL) {
381232153Smm			if (*ravail >= *avail)
382232153Smm				return (0);
383232153Smm			/* Reading bytes reaches the end of file. */
384232153Smm			*b = __archive_read_ahead(a, *avail, avail);
385232153Smm			quit = 1;
386232153Smm		}
387232153Smm		*ravail = *avail;
388232153Smm		*b += diff;
389232153Smm		*avail -= diff;
390232153Smm		tested = len;/* Skip some bytes we already determinated. */
391307139Smm		len = get_line_size(*b + len, *avail - len, nl);
392232153Smm		if (len >= 0)
393232153Smm			len += tested;
394232153Smm	}
395232153Smm	return (len);
396232153Smm}
397232153Smm
398232153Smm/*
399232153Smm * Compare characters with a mtree keyword.
400232153Smm * Returns the length of a mtree keyword if matched.
401232153Smm * Returns 0 if not matched.
402232153Smm */
403228753Smmstatic int
404232153Smmbid_keycmp(const char *p, const char *key, ssize_t len)
405228753Smm{
406232153Smm	int match_len = 0;
407232153Smm
408232153Smm	while (len > 0 && *p && *key) {
409232153Smm		if (*p == *key) {
410232153Smm			--len;
411232153Smm			++p;
412232153Smm			++key;
413232153Smm			++match_len;
414232153Smm			continue;
415232153Smm		}
416232153Smm		return (0);/* Not match */
417232153Smm	}
418232153Smm	if (*key != '\0')
419232153Smm		return (0);/* Not match */
420232153Smm
421232153Smm	/* A following character should be specified characters */
422232153Smm	if (p[0] == '=' || p[0] == ' ' || p[0] == '\t' ||
423232153Smm	    p[0] == '\n' || p[0] == '\r' ||
424232153Smm	   (p[0] == '\\' && (p[1] == '\n' || p[1] == '\r')))
425232153Smm		return (match_len);
426232153Smm	return (0);/* Not match */
427232153Smm}
428232153Smm
429232153Smm/*
430232153Smm * Test whether the characters 'p' has is mtree keyword.
431232153Smm * Returns the length of a detected keyword.
432232153Smm * Returns 0 if any keywords were not found.
433232153Smm */
434248616Smmstatic int
435232153Smmbid_keyword(const char *p,  ssize_t len)
436232153Smm{
437316338Smm	static const char * const keys_c[] = {
438232153Smm		"content", "contents", "cksum", NULL
439232153Smm	};
440316338Smm	static const char * const keys_df[] = {
441232153Smm		"device", "flags", NULL
442232153Smm	};
443316338Smm	static const char * const keys_g[] = {
444232153Smm		"gid", "gname", NULL
445232153Smm	};
446316338Smm	static const char * const keys_il[] = {
447302001Smm		"ignore", "inode", "link", NULL
448232153Smm	};
449316338Smm	static const char * const keys_m[] = {
450232153Smm		"md5", "md5digest", "mode", NULL
451232153Smm	};
452316338Smm	static const char * const keys_no[] = {
453248616Smm		"nlink", "nochange", "optional", NULL
454232153Smm	};
455316338Smm	static const char * const keys_r[] = {
456302001Smm		"resdevice", "rmd160", "rmd160digest", NULL
457232153Smm	};
458316338Smm	static const char * const keys_s[] = {
459232153Smm		"sha1", "sha1digest",
460232153Smm		"sha256", "sha256digest",
461232153Smm		"sha384", "sha384digest",
462232153Smm		"sha512", "sha512digest",
463232153Smm		"size", NULL
464232153Smm	};
465316338Smm	static const char * const keys_t[] = {
466232153Smm		"tags", "time", "type", NULL
467232153Smm	};
468316338Smm	static const char * const keys_u[] = {
469232153Smm		"uid", "uname",	NULL
470232153Smm	};
471316338Smm	const char * const *keys;
472232153Smm	int i;
473232153Smm
474232153Smm	switch (*p) {
475232153Smm	case 'c': keys = keys_c; break;
476232153Smm	case 'd': case 'f': keys = keys_df; break;
477232153Smm	case 'g': keys = keys_g; break;
478232153Smm	case 'i': case 'l': keys = keys_il; break;
479232153Smm	case 'm': keys = keys_m; break;
480232153Smm	case 'n': case 'o': keys = keys_no; break;
481232153Smm	case 'r': keys = keys_r; break;
482232153Smm	case 's': keys = keys_s; break;
483232153Smm	case 't': keys = keys_t; break;
484232153Smm	case 'u': keys = keys_u; break;
485232153Smm	default: return (0);/* Unknown key */
486232153Smm	}
487232153Smm
488232153Smm	for (i = 0; keys[i] != NULL; i++) {
489232153Smm		int l = bid_keycmp(p, keys[i], len);
490232153Smm		if (l > 0)
491232153Smm			return (l);
492232153Smm	}
493232153Smm	return (0);/* Unknown key */
494232153Smm}
495232153Smm
496232153Smm/*
497232153Smm * Test whether there is a set of mtree keywords.
498232153Smm * Returns the number of keyword.
499232153Smm * Returns -1 if we got incorrect sequence.
500232153Smm * This function expects a set of "<space characters>keyword=value".
501232153Smm * When "unset" is specified, expects a set of "<space characters>keyword".
502232153Smm */
503232153Smmstatic int
504248616Smmbid_keyword_list(const char *p,  ssize_t len, int unset, int last_is_path)
505232153Smm{
506232153Smm	int l;
507232153Smm	int keycnt = 0;
508232153Smm
509232153Smm	while (len > 0 && *p) {
510232153Smm		int blank = 0;
511232153Smm
512232153Smm		/* Test whether there are blank characters in the line. */
513232153Smm		while (len >0 && (*p == ' ' || *p == '\t')) {
514232153Smm			++p;
515232153Smm			--len;
516232153Smm			blank = 1;
517232153Smm		}
518232153Smm		if (*p == '\n' || *p == '\r')
519232153Smm			break;
520232153Smm		if (p[0] == '\\' && (p[1] == '\n' || p[1] == '\r'))
521232153Smm			break;
522248616Smm		if (!blank && !last_is_path) /* No blank character. */
523232153Smm			return (-1);
524248616Smm		if (last_is_path && len == 0)
525248616Smm				return (keycnt);
526232153Smm
527232153Smm		if (unset) {
528232153Smm			l = bid_keycmp(p, "all", len);
529232153Smm			if (l > 0)
530232153Smm				return (1);
531232153Smm		}
532232153Smm		/* Test whether there is a correct key in the line. */
533232153Smm		l = bid_keyword(p, len);
534232153Smm		if (l == 0)
535232153Smm			return (-1);/* Unknown keyword was found. */
536232153Smm		p += l;
537232153Smm		len -= l;
538232153Smm		keycnt++;
539232153Smm
540232153Smm		/* Skip value */
541232153Smm		if (*p == '=') {
542232153Smm			int value = 0;
543232153Smm			++p;
544232153Smm			--len;
545232153Smm			while (len > 0 && *p != ' ' && *p != '\t') {
546232153Smm				++p;
547232153Smm				--len;
548232153Smm				value = 1;
549232153Smm			}
550232153Smm			/* A keyword should have a its value unless
551232153Smm			 * "/unset" operation. */
552232153Smm			if (!unset && value == 0)
553232153Smm				return (-1);
554232153Smm		}
555232153Smm	}
556232153Smm	return (keycnt);
557232153Smm}
558232153Smm
559232153Smmstatic int
560248616Smmbid_entry(const char *p, ssize_t len, ssize_t nl, int *last_is_path)
561232153Smm{
562232153Smm	int f = 0;
563232153Smm	static const unsigned char safe_char[256] = {
564232153Smm		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
565232153Smm		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
566232153Smm		/* !"$%&'()*+,-./  EXCLUSION:( )(#) */
567232153Smm		0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
568232153Smm		/* 0123456789:;<>?  EXCLUSION:(=) */
569232153Smm		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, /* 30 - 3F */
570232153Smm		/* @ABCDEFGHIJKLMNO */
571232153Smm		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
572232153Smm		/* PQRSTUVWXYZ[\]^_  */
573232153Smm		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
574232153Smm		/* `abcdefghijklmno */
575232153Smm		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
576232153Smm		/* pqrstuvwxyz{|}~ */
577232153Smm		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */
578232153Smm		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
579232153Smm		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
580232153Smm		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
581232153Smm		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
582232153Smm		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
583232153Smm		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
584232153Smm		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
585232153Smm		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
586232153Smm	};
587302001Smm	ssize_t ll;
588248616Smm	const char *pp = p;
589302001Smm	const char * const pp_end = pp + len;
590232153Smm
591248616Smm	*last_is_path = 0;
592232153Smm	/*
593232153Smm	 * Skip the path-name which is quoted.
594232153Smm	 */
595302001Smm	for (;pp < pp_end; ++pp) {
596248616Smm		if (!safe_char[*(const unsigned char *)pp]) {
597302001Smm			if (*pp != ' ' && *pp != '\t' && *pp != '\r'
598302001Smm			    && *pp != '\n')
599302001Smm				f = 0;
600248616Smm			break;
601248616Smm		}
602302001Smm		f = 1;
603232153Smm	}
604302001Smm	ll = pp_end - pp;
605302001Smm
606248616Smm	/* If a path-name was not found at the first, try to check
607302001Smm	 * a mtree format(a.k.a form D) ``NetBSD's mtree -D'' creates,
608302001Smm	 * which places the path-name at the last. */
609248616Smm	if (f == 0) {
610248616Smm		const char *pb = p + len - nl;
611248616Smm		int name_len = 0;
612248616Smm		int slash;
613232153Smm
614302001Smm		/* The form D accepts only a single line for an entry. */
615248616Smm		if (pb-2 >= p &&
616248616Smm		    pb[-1] == '\\' && (pb[-2] == ' ' || pb[-2] == '\t'))
617248616Smm			return (-1);
618248616Smm		if (pb-1 >= p && pb[-1] == '\\')
619248616Smm			return (-1);
620248616Smm
621248616Smm		slash = 0;
622248616Smm		while (p <= --pb && *pb != ' ' && *pb != '\t') {
623248616Smm			if (!safe_char[*(const unsigned char *)pb])
624248616Smm				return (-1);
625248616Smm			name_len++;
626248616Smm			/* The pathname should have a slash in this
627248616Smm			 * format. */
628248616Smm			if (*pb == '/')
629248616Smm				slash = 1;
630248616Smm		}
631248616Smm		if (name_len == 0 || slash == 0)
632248616Smm			return (-1);
633248616Smm		/* If '/' is placed at the first in this field, this is not
634248616Smm		 * a valid filename. */
635248616Smm		if (pb[1] == '/')
636248616Smm			return (-1);
637248616Smm		ll = len - nl - name_len;
638248616Smm		pp = p;
639248616Smm		*last_is_path = 1;
640248616Smm	}
641248616Smm
642248616Smm	return (bid_keyword_list(pp, ll, 0, *last_is_path));
643232153Smm}
644232153Smm
645232153Smm#define MAX_BID_ENTRY	3
646232153Smm
647232153Smmstatic int
648232153Smmmtree_bid(struct archive_read *a, int best_bid)
649232153Smm{
650228753Smm	const char *signature = "#mtree";
651228753Smm	const char *p;
652228753Smm
653232153Smm	(void)best_bid; /* UNUSED */
654232153Smm
655228753Smm	/* Now let's look at the actual header and see if it matches. */
656248616Smm	p = __archive_read_ahead(a, strlen(signature), NULL);
657228753Smm	if (p == NULL)
658228753Smm		return (-1);
659228753Smm
660232153Smm	if (memcmp(p, signature, strlen(signature)) == 0)
661228753Smm		return (8 * (int)strlen(signature));
662232153Smm
663232153Smm	/*
664232153Smm	 * There is not a mtree signature. Let's try to detect mtree format.
665232153Smm	 */
666248616Smm	return (detect_form(a, NULL));
667248616Smm}
668248616Smm
669248616Smmstatic int
670248616Smmdetect_form(struct archive_read *a, int *is_form_d)
671248616Smm{
672248616Smm	const char *p;
673248616Smm	ssize_t avail, ravail;
674248616Smm	ssize_t detected_bytes = 0, len, nl;
675248616Smm	int entry_cnt = 0, multiline = 0;
676248616Smm	int form_D = 0;/* The archive is generated by `NetBSD mtree -D'
677248616Smm			* (In this source we call it `form D') . */
678248616Smm
679248616Smm	if (is_form_d != NULL)
680248616Smm		*is_form_d = 0;
681248616Smm	p = __archive_read_ahead(a, 1, &avail);
682248616Smm	if (p == NULL)
683248616Smm		return (-1);
684232153Smm	ravail = avail;
685232153Smm	for (;;) {
686232153Smm		len = next_line(a, &p, &avail, &ravail, &nl);
687232153Smm		/* The terminal character of the line should be
688232153Smm		 * a new line character, '\r\n' or '\n'. */
689232153Smm		if (len <= 0 || nl == 0)
690232153Smm			break;
691232153Smm		if (!multiline) {
692232153Smm			/* Leading whitespace is never significant,
693232153Smm			 * ignore it. */
694232153Smm			while (len > 0 && (*p == ' ' || *p == '\t')) {
695232153Smm				++p;
696232153Smm				--avail;
697232153Smm				--len;
698232153Smm			}
699232153Smm			/* Skip comment or empty line. */
700232153Smm			if (p[0] == '#' || p[0] == '\n' || p[0] == '\r') {
701232153Smm				p += len;
702232153Smm				avail -= len;
703232153Smm				continue;
704232153Smm			}
705232153Smm		} else {
706232153Smm			/* A continuance line; the terminal
707232153Smm			 * character of previous line was '\' character. */
708248616Smm			if (bid_keyword_list(p, len, 0, 0) <= 0)
709232153Smm				break;
710232153Smm			if (multiline == 1)
711232153Smm				detected_bytes += len;
712232153Smm			if (p[len-nl-1] != '\\') {
713232153Smm				if (multiline == 1 &&
714232153Smm				    ++entry_cnt >= MAX_BID_ENTRY)
715232153Smm					break;
716232153Smm				multiline = 0;
717232153Smm			}
718232153Smm			p += len;
719232153Smm			avail -= len;
720232153Smm			continue;
721232153Smm		}
722232153Smm		if (p[0] != '/') {
723248616Smm			int last_is_path, keywords;
724248616Smm
725248616Smm			keywords = bid_entry(p, len, nl, &last_is_path);
726248616Smm			if (keywords >= 0) {
727232153Smm				detected_bytes += len;
728248616Smm				if (form_D == 0) {
729248616Smm					if (last_is_path)
730248616Smm						form_D = 1;
731248616Smm					else if (keywords > 0)
732248616Smm						/* This line is not `form D'. */
733248616Smm						form_D = -1;
734248616Smm				} else if (form_D == 1) {
735248616Smm					if (!last_is_path && keywords > 0)
736248616Smm						/* This this is not `form D'
737248616Smm						 * and We cannot accept mixed
738248616Smm						 * format. */
739248616Smm						break;
740248616Smm				}
741248616Smm				if (!last_is_path && p[len-nl-1] == '\\')
742232153Smm					/* This line continues. */
743232153Smm					multiline = 1;
744232153Smm				else {
745232153Smm					/* We've got plenty of correct lines
746232153Smm					 * to assume that this file is a mtree
747232153Smm					 * format. */
748232153Smm					if (++entry_cnt >= MAX_BID_ENTRY)
749232153Smm						break;
750232153Smm				}
751232153Smm			} else
752232153Smm				break;
753313571Smm		} else if (len > 4 && strncmp(p, "/set", 4) == 0) {
754248616Smm			if (bid_keyword_list(p+4, len-4, 0, 0) <= 0)
755232153Smm				break;
756232153Smm			/* This line continues. */
757232153Smm			if (p[len-nl-1] == '\\')
758232153Smm				multiline = 2;
759313571Smm		} else if (len > 6 && strncmp(p, "/unset", 6) == 0) {
760248616Smm			if (bid_keyword_list(p+6, len-6, 1, 0) <= 0)
761232153Smm				break;
762232153Smm			/* This line continues. */
763232153Smm			if (p[len-nl-1] == '\\')
764232153Smm				multiline = 2;
765232153Smm		} else
766232153Smm			break;
767232153Smm
768232153Smm		/* Test next line. */
769232153Smm		p += len;
770232153Smm		avail -= len;
771232153Smm	}
772248616Smm	if (entry_cnt >= MAX_BID_ENTRY || (entry_cnt > 0 && len == 0)) {
773248616Smm		if (is_form_d != NULL) {
774248616Smm			if (form_D == 1)
775248616Smm				*is_form_d = 1;
776248616Smm		}
777232153Smm		return (32);
778248616Smm	}
779232153Smm
780228753Smm	return (0);
781228753Smm}
782228753Smm
783228753Smm/*
784228753Smm * The extended mtree format permits multiple lines specifying
785228753Smm * attributes for each file.  For those entries, only the last line
786228753Smm * is actually used.  Practically speaking, that means we have
787228753Smm * to read the entire mtree file into memory up front.
788228753Smm *
789228753Smm * The parsing is done in two steps.  First, it is decided if a line
790228753Smm * changes the global defaults and if it is, processed accordingly.
791228753Smm * Otherwise, the options of the line are merged with the current
792228753Smm * global options.
793228753Smm */
794228753Smmstatic int
795228753Smmadd_option(struct archive_read *a, struct mtree_option **global,
796228753Smm    const char *value, size_t len)
797228753Smm{
798232153Smm	struct mtree_option *opt;
799228753Smm
800232153Smm	if ((opt = malloc(sizeof(*opt))) == NULL) {
801228753Smm		archive_set_error(&a->archive, errno, "Can't allocate memory");
802228753Smm		return (ARCHIVE_FATAL);
803228753Smm	}
804232153Smm	if ((opt->value = malloc(len + 1)) == NULL) {
805232153Smm		free(opt);
806228753Smm		archive_set_error(&a->archive, errno, "Can't allocate memory");
807228753Smm		return (ARCHIVE_FATAL);
808228753Smm	}
809232153Smm	memcpy(opt->value, value, len);
810232153Smm	opt->value[len] = '\0';
811232153Smm	opt->next = *global;
812232153Smm	*global = opt;
813228753Smm	return (ARCHIVE_OK);
814228753Smm}
815228753Smm
816228753Smmstatic void
817228753Smmremove_option(struct mtree_option **global, const char *value, size_t len)
818228753Smm{
819228753Smm	struct mtree_option *iter, *last;
820228753Smm
821228753Smm	last = NULL;
822228753Smm	for (iter = *global; iter != NULL; last = iter, iter = iter->next) {
823228753Smm		if (strncmp(iter->value, value, len) == 0 &&
824228753Smm		    (iter->value[len] == '\0' ||
825228753Smm		     iter->value[len] == '='))
826228753Smm			break;
827228753Smm	}
828228753Smm	if (iter == NULL)
829228753Smm		return;
830228753Smm	if (last == NULL)
831228753Smm		*global = iter->next;
832228753Smm	else
833228753Smm		last->next = iter->next;
834228753Smm
835228753Smm	free(iter->value);
836228753Smm	free(iter);
837228753Smm}
838228753Smm
839228753Smmstatic int
840228753Smmprocess_global_set(struct archive_read *a,
841228753Smm    struct mtree_option **global, const char *line)
842228753Smm{
843228753Smm	const char *next, *eq;
844228753Smm	size_t len;
845228753Smm	int r;
846228753Smm
847228753Smm	line += 4;
848228753Smm	for (;;) {
849228753Smm		next = line + strspn(line, " \t\r\n");
850228753Smm		if (*next == '\0')
851228753Smm			return (ARCHIVE_OK);
852228753Smm		line = next;
853228753Smm		next = line + strcspn(line, " \t\r\n");
854228753Smm		eq = strchr(line, '=');
855228753Smm		if (eq > next)
856228753Smm			len = next - line;
857228753Smm		else
858228753Smm			len = eq - line;
859228753Smm
860228753Smm		remove_option(global, line, len);
861228753Smm		r = add_option(a, global, line, next - line);
862228753Smm		if (r != ARCHIVE_OK)
863228753Smm			return (r);
864228753Smm		line = next;
865228753Smm	}
866228753Smm}
867228753Smm
868228753Smmstatic int
869228753Smmprocess_global_unset(struct archive_read *a,
870228753Smm    struct mtree_option **global, const char *line)
871228753Smm{
872228753Smm	const char *next;
873228753Smm	size_t len;
874228753Smm
875228753Smm	line += 6;
876228753Smm	if (strchr(line, '=') != NULL) {
877228753Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
878228753Smm		    "/unset shall not contain `='");
879228753Smm		return ARCHIVE_FATAL;
880228753Smm	}
881228753Smm
882228753Smm	for (;;) {
883228753Smm		next = line + strspn(line, " \t\r\n");
884228753Smm		if (*next == '\0')
885228753Smm			return (ARCHIVE_OK);
886228753Smm		line = next;
887228753Smm		len = strcspn(line, " \t\r\n");
888228753Smm
889228753Smm		if (len == 3 && strncmp(line, "all", 3) == 0) {
890228753Smm			free_options(*global);
891228753Smm			*global = NULL;
892228753Smm		} else {
893228753Smm			remove_option(global, line, len);
894228753Smm		}
895228753Smm
896228753Smm		line += len;
897228753Smm	}
898228753Smm}
899228753Smm
900228753Smmstatic int
901228753Smmprocess_add_entry(struct archive_read *a, struct mtree *mtree,
902248616Smm    struct mtree_option **global, const char *line, ssize_t line_len,
903248616Smm    struct mtree_entry **last_entry, int is_form_d)
904228753Smm{
905337352Smm	struct mtree_entry *entry;
906228753Smm	struct mtree_option *iter;
907248616Smm	const char *next, *eq, *name, *end;
908302001Smm	size_t name_len, len;
909302001Smm	int r, i;
910228753Smm
911228753Smm	if ((entry = malloc(sizeof(*entry))) == NULL) {
912228753Smm		archive_set_error(&a->archive, errno, "Can't allocate memory");
913228753Smm		return (ARCHIVE_FATAL);
914228753Smm	}
915228753Smm	entry->next = NULL;
916228753Smm	entry->options = NULL;
917228753Smm	entry->name = NULL;
918228753Smm	entry->used = 0;
919228753Smm	entry->full = 0;
920228753Smm
921228753Smm	/* Add this entry to list. */
922228753Smm	if (*last_entry == NULL)
923228753Smm		mtree->entries = entry;
924228753Smm	else
925228753Smm		(*last_entry)->next = entry;
926228753Smm	*last_entry = entry;
927228753Smm
928248616Smm	if (is_form_d) {
929302001Smm		/* Filename is last item on line. */
930302001Smm		/* Adjust line_len to trim trailing whitespace */
931248616Smm		while (line_len > 0) {
932302001Smm			char last_character = line[line_len - 1];
933302001Smm			if (last_character == '\r'
934302001Smm			    || last_character == '\n'
935302001Smm			    || last_character == '\t'
936302001Smm			    || last_character == ' ') {
937302001Smm				line_len--;
938302001Smm			} else {
939248616Smm				break;
940302001Smm			}
941248616Smm		}
942302001Smm		/* Name starts after the last whitespace separator */
943302001Smm		name = line;
944302001Smm		for (i = 0; i < line_len; i++) {
945302001Smm			if (line[i] == '\r'
946302001Smm			    || line[i] == '\n'
947302001Smm			    || line[i] == '\t'
948302001Smm			    || line[i] == ' ') {
949302001Smm				name = line + i + 1;
950248616Smm			}
951248616Smm		}
952302001Smm		name_len = line + line_len - name;
953248616Smm		end = name;
954248616Smm	} else {
955302001Smm		/* Filename is first item on line */
956302001Smm		name_len = strcspn(line, " \t\r\n");
957248616Smm		name = line;
958302001Smm		line += name_len;
959248616Smm		end = line + line_len;
960248616Smm	}
961302001Smm	/* name/name_len is the name within the line. */
962302001Smm	/* line..end brackets the entire line except the name */
963248616Smm
964302001Smm	if ((entry->name = malloc(name_len + 1)) == NULL) {
965228753Smm		archive_set_error(&a->archive, errno, "Can't allocate memory");
966228753Smm		return (ARCHIVE_FATAL);
967228753Smm	}
968228753Smm
969302001Smm	memcpy(entry->name, name, name_len);
970302001Smm	entry->name[name_len] = '\0';
971228753Smm	parse_escapes(entry->name, entry);
972228753Smm
973337352Smm	entry->next_dup = NULL;
974337352Smm	if (entry->full) {
975337352Smm		if (!__archive_rb_tree_insert_node(&mtree->rbtree, &entry->rbnode)) {
976337352Smm			struct mtree_entry *alt;
977337352Smm			alt = (struct mtree_entry *)__archive_rb_tree_find_node(
978337352Smm			    &mtree->rbtree, entry->name);
979337352Smm			while (alt->next_dup)
980337352Smm				alt = alt->next_dup;
981337352Smm			alt->next_dup = entry;
982337352Smm		}
983311042Smm	}
984311042Smm
985228753Smm	for (iter = *global; iter != NULL; iter = iter->next) {
986228753Smm		r = add_option(a, &entry->options, iter->value,
987228753Smm		    strlen(iter->value));
988228753Smm		if (r != ARCHIVE_OK)
989228753Smm			return (r);
990228753Smm	}
991228753Smm
992228753Smm	for (;;) {
993228753Smm		next = line + strspn(line, " \t\r\n");
994228753Smm		if (*next == '\0')
995228753Smm			return (ARCHIVE_OK);
996248616Smm		if (next >= end)
997248616Smm			return (ARCHIVE_OK);
998228753Smm		line = next;
999228753Smm		next = line + strcspn(line, " \t\r\n");
1000228753Smm		eq = strchr(line, '=');
1001228753Smm		if (eq == NULL || eq > next)
1002228753Smm			len = next - line;
1003228753Smm		else
1004228753Smm			len = eq - line;
1005228753Smm
1006228753Smm		remove_option(&entry->options, line, len);
1007228753Smm		r = add_option(a, &entry->options, line, next - line);
1008228753Smm		if (r != ARCHIVE_OK)
1009228753Smm			return (r);
1010228753Smm		line = next;
1011228753Smm	}
1012228753Smm}
1013228753Smm
1014228753Smmstatic int
1015228753Smmread_mtree(struct archive_read *a, struct mtree *mtree)
1016228753Smm{
1017228753Smm	ssize_t len;
1018228753Smm	uintmax_t counter;
1019348608Smm	char *p, *s;
1020228753Smm	struct mtree_option *global;
1021228753Smm	struct mtree_entry *last_entry;
1022248616Smm	int r, is_form_d;
1023228753Smm
1024228753Smm	mtree->archive_format = ARCHIVE_FORMAT_MTREE;
1025228753Smm	mtree->archive_format_name = "mtree";
1026228753Smm
1027228753Smm	global = NULL;
1028228753Smm	last_entry = NULL;
1029228753Smm
1030248616Smm	(void)detect_form(a, &is_form_d);
1031248616Smm
1032228753Smm	for (counter = 1; ; ++counter) {
1033348608Smm		r = ARCHIVE_OK;
1034232153Smm		len = readline(a, mtree, &p, 65536);
1035228753Smm		if (len == 0) {
1036228753Smm			mtree->this_entry = mtree->entries;
1037228753Smm			free_options(global);
1038228753Smm			return (ARCHIVE_OK);
1039228753Smm		}
1040228753Smm		if (len < 0) {
1041228753Smm			free_options(global);
1042248616Smm			return ((int)len);
1043228753Smm		}
1044228753Smm		/* Leading whitespace is never significant, ignore it. */
1045228753Smm		while (*p == ' ' || *p == '\t') {
1046228753Smm			++p;
1047228753Smm			--len;
1048228753Smm		}
1049228753Smm		/* Skip content lines and blank lines. */
1050228753Smm		if (*p == '#')
1051228753Smm			continue;
1052228753Smm		if (*p == '\r' || *p == '\n' || *p == '\0')
1053228753Smm			continue;
1054348608Smm		/* Non-printable characters are not allowed */
1055348608Smm		for (s = p;s < p + len - 1; s++) {
1056348608Smm			if (!isprint(*s)) {
1057348608Smm				r = ARCHIVE_FATAL;
1058348608Smm				break;
1059348608Smm			}
1060348608Smm		}
1061348608Smm		if (r != ARCHIVE_OK)
1062348608Smm			break;
1063228753Smm		if (*p != '/') {
1064248616Smm			r = process_add_entry(a, mtree, &global, p, len,
1065248616Smm			    &last_entry, is_form_d);
1066313571Smm		} else if (len > 4 && strncmp(p, "/set", 4) == 0) {
1067228753Smm			if (p[4] != ' ' && p[4] != '\t')
1068228753Smm				break;
1069228753Smm			r = process_global_set(a, &global, p);
1070313571Smm		} else if (len > 6 && strncmp(p, "/unset", 6) == 0) {
1071228753Smm			if (p[6] != ' ' && p[6] != '\t')
1072228753Smm				break;
1073228753Smm			r = process_global_unset(a, &global, p);
1074228753Smm		} else
1075228753Smm			break;
1076228753Smm
1077228753Smm		if (r != ARCHIVE_OK) {
1078228753Smm			free_options(global);
1079228753Smm			return r;
1080228753Smm		}
1081228753Smm	}
1082228753Smm
1083228753Smm	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
1084228753Smm	    "Can't parse line %ju", counter);
1085228753Smm	free_options(global);
1086228753Smm	return (ARCHIVE_FATAL);
1087228753Smm}
1088228753Smm
1089228753Smm/*
1090228753Smm * Read in the entire mtree file into memory on the first request.
1091228753Smm * Then use the next unused file to satisfy each header request.
1092228753Smm */
1093228753Smmstatic int
1094228753Smmread_header(struct archive_read *a, struct archive_entry *entry)
1095228753Smm{
1096228753Smm	struct mtree *mtree;
1097228753Smm	char *p;
1098228753Smm	int r, use_next;
1099228753Smm
1100228753Smm	mtree = (struct mtree *)(a->format->data);
1101228753Smm
1102228753Smm	if (mtree->fd >= 0) {
1103228753Smm		close(mtree->fd);
1104228753Smm		mtree->fd = -1;
1105228753Smm	}
1106228753Smm
1107228753Smm	if (mtree->entries == NULL) {
1108228753Smm		mtree->resolver = archive_entry_linkresolver_new();
1109228753Smm		if (mtree->resolver == NULL)
1110228753Smm			return ARCHIVE_FATAL;
1111228753Smm		archive_entry_linkresolver_set_strategy(mtree->resolver,
1112228753Smm		    ARCHIVE_FORMAT_MTREE);
1113228753Smm		r = read_mtree(a, mtree);
1114228753Smm		if (r != ARCHIVE_OK)
1115228753Smm			return (r);
1116228753Smm	}
1117228753Smm
1118228753Smm	a->archive.archive_format = mtree->archive_format;
1119228753Smm	a->archive.archive_format_name = mtree->archive_format_name;
1120228753Smm
1121228753Smm	for (;;) {
1122228753Smm		if (mtree->this_entry == NULL)
1123228753Smm			return (ARCHIVE_EOF);
1124228753Smm		if (strcmp(mtree->this_entry->name, "..") == 0) {
1125228753Smm			mtree->this_entry->used = 1;
1126228753Smm			if (archive_strlen(&mtree->current_dir) > 0) {
1127228753Smm				/* Roll back current path. */
1128228753Smm				p = mtree->current_dir.s
1129228753Smm				    + mtree->current_dir.length - 1;
1130228753Smm				while (p >= mtree->current_dir.s && *p != '/')
1131228753Smm					--p;
1132228753Smm				if (p >= mtree->current_dir.s)
1133228753Smm					--p;
1134228753Smm				mtree->current_dir.length
1135228753Smm				    = p - mtree->current_dir.s + 1;
1136228753Smm			}
1137228753Smm		}
1138228753Smm		if (!mtree->this_entry->used) {
1139228753Smm			use_next = 0;
1140302001Smm			r = parse_file(a, entry, mtree, mtree->this_entry,
1141302001Smm				&use_next);
1142228753Smm			if (use_next == 0)
1143228753Smm				return (r);
1144228753Smm		}
1145228753Smm		mtree->this_entry = mtree->this_entry->next;
1146228753Smm	}
1147228753Smm}
1148228753Smm
1149228753Smm/*
1150228753Smm * A single file can have multiple lines contribute specifications.
1151228753Smm * Parse as many lines as necessary, then pull additional information
1152228753Smm * from a backing file on disk as necessary.
1153228753Smm */
1154228753Smmstatic int
1155228753Smmparse_file(struct archive_read *a, struct archive_entry *entry,
1156228753Smm    struct mtree *mtree, struct mtree_entry *mentry, int *use_next)
1157228753Smm{
1158228753Smm	const char *path;
1159228753Smm	struct stat st_storage, *st;
1160228753Smm	struct mtree_entry *mp;
1161228753Smm	struct archive_entry *sparse_entry;
1162232153Smm	int r = ARCHIVE_OK, r1, parsed_kws;
1163228753Smm
1164228753Smm	mentry->used = 1;
1165228753Smm
1166228753Smm	/* Initialize reasonable defaults. */
1167232153Smm	archive_entry_set_filetype(entry, AE_IFREG);
1168228753Smm	archive_entry_set_size(entry, 0);
1169228753Smm	archive_string_empty(&mtree->contents_name);
1170228753Smm
1171228753Smm	/* Parse options from this line. */
1172228753Smm	parsed_kws = 0;
1173228753Smm	r = parse_line(a, entry, mtree, mentry, &parsed_kws);
1174228753Smm
1175228753Smm	if (mentry->full) {
1176228753Smm		archive_entry_copy_pathname(entry, mentry->name);
1177228753Smm		/*
1178228753Smm		 * "Full" entries are allowed to have multiple lines
1179228753Smm		 * and those lines aren't required to be adjacent.  We
1180228753Smm		 * don't support multiple lines for "relative" entries
1181228753Smm		 * nor do we make any attempt to merge data from
1182228753Smm		 * separate "relative" and "full" entries.  (Merging
1183228753Smm		 * "relative" and "full" entries would require dealing
1184228753Smm		 * with pathname canonicalization, which is a very
1185228753Smm		 * tricky subject.)
1186228753Smm		 */
1187337352Smm		mp = (struct mtree_entry *)__archive_rb_tree_find_node(
1188337352Smm		    &mtree->rbtree, mentry->name);
1189337352Smm		for (; mp; mp = mp->next_dup) {
1190337352Smm			if (mp->full && !mp->used) {
1191228753Smm				/* Later lines override earlier ones. */
1192228753Smm				mp->used = 1;
1193337352Smm				r1 = parse_line(a, entry, mtree, mp, &parsed_kws);
1194228753Smm				if (r1 < r)
1195228753Smm					r = r1;
1196228753Smm			}
1197228753Smm		}
1198228753Smm	} else {
1199228753Smm		/*
1200228753Smm		 * Relative entries require us to construct
1201228753Smm		 * the full path and possibly update the
1202228753Smm		 * current directory.
1203228753Smm		 */
1204228753Smm		size_t n = archive_strlen(&mtree->current_dir);
1205228753Smm		if (n > 0)
1206228753Smm			archive_strcat(&mtree->current_dir, "/");
1207228753Smm		archive_strcat(&mtree->current_dir, mentry->name);
1208228753Smm		archive_entry_copy_pathname(entry, mtree->current_dir.s);
1209228753Smm		if (archive_entry_filetype(entry) != AE_IFDIR)
1210228753Smm			mtree->current_dir.length = n;
1211228753Smm	}
1212228753Smm
1213302001Smm	if (mtree->checkfs) {
1214302001Smm		/*
1215302001Smm		 * Try to open and stat the file to get the real size
1216302001Smm		 * and other file info.  It would be nice to avoid
1217302001Smm		 * this here so that getting a listing of an mtree
1218302001Smm		 * wouldn't require opening every referenced contents
1219302001Smm		 * file.  But then we wouldn't know the actual
1220302001Smm		 * contents size, so I don't see a really viable way
1221302001Smm		 * around this.  (Also, we may want to someday pull
1222302001Smm		 * other unspecified info from the contents file on
1223302001Smm		 * disk.)
1224302001Smm		 */
1225302001Smm		mtree->fd = -1;
1226302001Smm		if (archive_strlen(&mtree->contents_name) > 0)
1227302001Smm			path = mtree->contents_name.s;
1228302001Smm		else
1229302001Smm			path = archive_entry_pathname(entry);
1230228753Smm
1231302001Smm		if (archive_entry_filetype(entry) == AE_IFREG ||
1232302001Smm				archive_entry_filetype(entry) == AE_IFDIR) {
1233302001Smm			mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC);
1234302001Smm			__archive_ensure_cloexec_flag(mtree->fd);
1235302001Smm			if (mtree->fd == -1 &&
1236302001Smm				(errno != ENOENT ||
1237302001Smm				 archive_strlen(&mtree->contents_name) > 0)) {
1238302001Smm				archive_set_error(&a->archive, errno,
1239302001Smm						"Can't open %s", path);
1240302001Smm				r = ARCHIVE_WARN;
1241302001Smm			}
1242228753Smm		}
1243228753Smm
1244302001Smm		st = &st_storage;
1245302001Smm		if (mtree->fd >= 0) {
1246302001Smm			if (fstat(mtree->fd, st) == -1) {
1247302001Smm				archive_set_error(&a->archive, errno,
1248302001Smm						"Could not fstat %s", path);
1249302001Smm				r = ARCHIVE_WARN;
1250302001Smm				/* If we can't stat it, don't keep it open. */
1251302001Smm				close(mtree->fd);
1252302001Smm				mtree->fd = -1;
1253302001Smm				st = NULL;
1254302001Smm			}
1255302001Smm		} else if (lstat(path, st) == -1) {
1256228753Smm			st = NULL;
1257228753Smm		}
1258228753Smm
1259302001Smm		/*
1260302001Smm		 * Check for a mismatch between the type in the specification
1261302001Smm		 * and the type of the contents object on disk.
1262302001Smm		 */
1263302001Smm		if (st != NULL) {
1264302001Smm			if (((st->st_mode & S_IFMT) == S_IFREG &&
1265302001Smm			      archive_entry_filetype(entry) == AE_IFREG)
1266232153Smm#ifdef S_IFLNK
1267302001Smm			  ||((st->st_mode & S_IFMT) == S_IFLNK &&
1268302001Smm			      archive_entry_filetype(entry) == AE_IFLNK)
1269232153Smm#endif
1270232153Smm#ifdef S_IFSOCK
1271302001Smm			  ||((st->st_mode & S_IFSOCK) == S_IFSOCK &&
1272302001Smm			      archive_entry_filetype(entry) == AE_IFSOCK)
1273232153Smm#endif
1274232153Smm#ifdef S_IFCHR
1275302001Smm			  ||((st->st_mode & S_IFMT) == S_IFCHR &&
1276302001Smm			      archive_entry_filetype(entry) == AE_IFCHR)
1277232153Smm#endif
1278232153Smm#ifdef S_IFBLK
1279302001Smm			  ||((st->st_mode & S_IFMT) == S_IFBLK &&
1280302001Smm			      archive_entry_filetype(entry) == AE_IFBLK)
1281232153Smm#endif
1282302001Smm			  ||((st->st_mode & S_IFMT) == S_IFDIR &&
1283302001Smm			      archive_entry_filetype(entry) == AE_IFDIR)
1284232153Smm#ifdef S_IFIFO
1285302001Smm			  ||((st->st_mode & S_IFMT) == S_IFIFO &&
1286302001Smm			      archive_entry_filetype(entry) == AE_IFIFO)
1287232153Smm#endif
1288302001Smm			) {
1289302001Smm				/* Types match. */
1290302001Smm			} else {
1291302001Smm				/* Types don't match; bail out gracefully. */
1292302001Smm				if (mtree->fd >= 0)
1293302001Smm					close(mtree->fd);
1294302001Smm				mtree->fd = -1;
1295302001Smm				if (parsed_kws & MTREE_HAS_OPTIONAL) {
1296302001Smm					/* It's not an error for an optional
1297302001Smm					 * entry to not match disk. */
1298302001Smm					*use_next = 1;
1299302001Smm				} else if (r == ARCHIVE_OK) {
1300302001Smm					archive_set_error(&a->archive,
1301302001Smm					    ARCHIVE_ERRNO_MISC,
1302302001Smm					    "mtree specification has different"
1303302001Smm					    " type for %s",
1304302001Smm					    archive_entry_pathname(entry));
1305302001Smm					r = ARCHIVE_WARN;
1306302001Smm				}
1307302001Smm				return (r);
1308228753Smm			}
1309228753Smm		}
1310228753Smm
1311302001Smm		/*
1312302001Smm		 * If there is a contents file on disk, pick some of the
1313302001Smm		 * metadata from that file.  For most of these, we only
1314302001Smm		 * set it from the contents if it wasn't already parsed
1315302001Smm		 * from the specification.
1316302001Smm		 */
1317302001Smm		if (st != NULL) {
1318302001Smm			if (((parsed_kws & MTREE_HAS_DEVICE) == 0 ||
1319302001Smm				(parsed_kws & MTREE_HAS_NOCHANGE) != 0) &&
1320302001Smm				(archive_entry_filetype(entry) == AE_IFCHR ||
1321302001Smm				 archive_entry_filetype(entry) == AE_IFBLK))
1322302001Smm				archive_entry_set_rdev(entry, st->st_rdev);
1323302001Smm			if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME))
1324302001Smm				== 0 ||
1325302001Smm			    (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
1326302001Smm				archive_entry_set_gid(entry, st->st_gid);
1327302001Smm			if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME))
1328302001Smm				== 0 ||
1329302001Smm			    (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
1330302001Smm				archive_entry_set_uid(entry, st->st_uid);
1331302001Smm			if ((parsed_kws & MTREE_HAS_MTIME) == 0 ||
1332302001Smm			    (parsed_kws & MTREE_HAS_NOCHANGE) != 0) {
1333228753Smm#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
1334302001Smm				archive_entry_set_mtime(entry, st->st_mtime,
1335302001Smm						st->st_mtimespec.tv_nsec);
1336228753Smm#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1337302001Smm				archive_entry_set_mtime(entry, st->st_mtime,
1338302001Smm						st->st_mtim.tv_nsec);
1339228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_N
1340302001Smm				archive_entry_set_mtime(entry, st->st_mtime,
1341302001Smm						st->st_mtime_n);
1342228753Smm#elif HAVE_STRUCT_STAT_ST_UMTIME
1343302001Smm				archive_entry_set_mtime(entry, st->st_mtime,
1344302001Smm						st->st_umtime*1000);
1345228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_USEC
1346302001Smm				archive_entry_set_mtime(entry, st->st_mtime,
1347302001Smm						st->st_mtime_usec*1000);
1348228753Smm#else
1349302001Smm				archive_entry_set_mtime(entry, st->st_mtime, 0);
1350228753Smm#endif
1351302001Smm			}
1352302001Smm			if ((parsed_kws & MTREE_HAS_NLINK) == 0 ||
1353302001Smm			    (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
1354302001Smm				archive_entry_set_nlink(entry, st->st_nlink);
1355302001Smm			if ((parsed_kws & MTREE_HAS_PERM) == 0 ||
1356302001Smm			    (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
1357302001Smm				archive_entry_set_perm(entry, st->st_mode);
1358302001Smm			if ((parsed_kws & MTREE_HAS_SIZE) == 0 ||
1359302001Smm			    (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
1360302001Smm				archive_entry_set_size(entry, st->st_size);
1361302001Smm			archive_entry_set_ino(entry, st->st_ino);
1362302001Smm			archive_entry_set_dev(entry, st->st_dev);
1363302001Smm
1364302001Smm			archive_entry_linkify(mtree->resolver, &entry,
1365302001Smm				&sparse_entry);
1366302001Smm		} else if (parsed_kws & MTREE_HAS_OPTIONAL) {
1367302001Smm			/*
1368302001Smm			 * Couldn't open the entry, stat it or the on-disk type
1369302001Smm			 * didn't match.  If this entry is optional, just
1370302001Smm			 * ignore it and read the next header entry.
1371302001Smm			 */
1372302001Smm			*use_next = 1;
1373302001Smm			return ARCHIVE_OK;
1374228753Smm		}
1375228753Smm	}
1376228753Smm
1377228753Smm	mtree->cur_size = archive_entry_size(entry);
1378228753Smm	mtree->offset = 0;
1379228753Smm
1380228753Smm	return r;
1381228753Smm}
1382228753Smm
1383228753Smm/*
1384228753Smm * Each line contains a sequence of keywords.
1385228753Smm */
1386228753Smmstatic int
1387228753Smmparse_line(struct archive_read *a, struct archive_entry *entry,
1388228753Smm    struct mtree *mtree, struct mtree_entry *mp, int *parsed_kws)
1389228753Smm{
1390228753Smm	struct mtree_option *iter;
1391228753Smm	int r = ARCHIVE_OK, r1;
1392228753Smm
1393228753Smm	for (iter = mp->options; iter != NULL; iter = iter->next) {
1394228753Smm		r1 = parse_keyword(a, mtree, entry, iter, parsed_kws);
1395228753Smm		if (r1 < r)
1396228753Smm			r = r1;
1397228753Smm	}
1398232153Smm	if (r == ARCHIVE_OK && (*parsed_kws & MTREE_HAS_TYPE) == 0) {
1399228753Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
1400228753Smm		    "Missing type keyword in mtree specification");
1401228753Smm		return (ARCHIVE_WARN);
1402228753Smm	}
1403228753Smm	return (r);
1404228753Smm}
1405228753Smm
1406228753Smm/*
1407228753Smm * Device entries have one of the following forms:
1408302001Smm *  - raw dev_t
1409302001Smm *  - format,major,minor[,subdevice]
1410302001Smm * When parsing succeeded, `pdev' will contain the appropriate dev_t value.
1411228753Smm */
1412302001Smm
1413302001Smm/* strsep() is not in C90, but strcspn() is. */
1414302001Smm/* Taken from http://unixpapa.com/incnote/string.html */
1415302001Smmstatic char *
1416302001Smmla_strsep(char **sp, const char *sep)
1417302001Smm{
1418302001Smm	char *p, *s;
1419302001Smm	if (sp == NULL || *sp == NULL || **sp == '\0')
1420302001Smm		return(NULL);
1421302001Smm	s = *sp;
1422302001Smm	p = s + strcspn(s, sep);
1423302001Smm	if (*p != '\0')
1424302001Smm		*p++ = '\0';
1425302001Smm	*sp = p;
1426302001Smm	return(s);
1427302001Smm}
1428302001Smm
1429228753Smmstatic int
1430302001Smmparse_device(dev_t *pdev, struct archive *a, char *val)
1431228753Smm{
1432302001Smm#define MAX_PACK_ARGS 3
1433302001Smm	unsigned long numbers[MAX_PACK_ARGS];
1434302001Smm	char *p, *dev;
1435302001Smm	int argc;
1436302001Smm	pack_t *pack;
1437302001Smm	dev_t result;
1438302001Smm	const char *error = NULL;
1439228753Smm
1440302001Smm	memset(pdev, 0, sizeof(*pdev));
1441302001Smm	if ((dev = strchr(val, ',')) != NULL) {
1442302001Smm		/*
1443302001Smm		 * Device's major/minor are given in a specified format.
1444302001Smm		 * Decode and pack it accordingly.
1445302001Smm		 */
1446302001Smm		*dev++ = '\0';
1447302001Smm		if ((pack = pack_find(val)) == NULL) {
1448302001Smm			archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
1449302001Smm			    "Unknown format `%s'", val);
1450302001Smm			return ARCHIVE_WARN;
1451302001Smm		}
1452302001Smm		argc = 0;
1453302001Smm		while ((p = la_strsep(&dev, ",")) != NULL) {
1454302001Smm			if (*p == '\0') {
1455302001Smm				archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
1456302001Smm				    "Missing number");
1457302001Smm				return ARCHIVE_WARN;
1458302001Smm			}
1459302295Smm			if (argc >= MAX_PACK_ARGS) {
1460302001Smm				archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
1461302001Smm				    "Too many arguments");
1462302001Smm				return ARCHIVE_WARN;
1463302001Smm			}
1464318483Smm			numbers[argc++] = (unsigned long)mtree_atol(&p, 0);
1465302001Smm		}
1466302001Smm		if (argc < 2) {
1467302001Smm			archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
1468302001Smm			    "Not enough arguments");
1469302001Smm			return ARCHIVE_WARN;
1470302001Smm		}
1471302001Smm		result = (*pack)(argc, numbers, &error);
1472302001Smm		if (error != NULL) {
1473302001Smm			archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
1474302001Smm			    "%s", error);
1475302001Smm			return ARCHIVE_WARN;
1476302001Smm		}
1477302001Smm	} else {
1478302001Smm		/* file system raw value. */
1479318483Smm		result = (dev_t)mtree_atol(&val, 0);
1480228753Smm	}
1481302001Smm	*pdev = result;
1482302001Smm	return ARCHIVE_OK;
1483302001Smm#undef MAX_PACK_ARGS
1484228753Smm}
1485228753Smm
1486368708Smmstatic int
1487368708Smmparse_hex_nibble(char c)
1488368708Smm{
1489368708Smm	if (c >= '0' && c <= '9')
1490368708Smm		return c - '0';
1491368708Smm	if (c >= 'a' && c <= 'f')
1492368708Smm		return 10 + c - 'a';
1493368708Smm#if 0
1494368708Smm	/* XXX: Is uppercase something we should support? */
1495368708Smm	if (c >= 'A' && c <= 'F')
1496368708Smm		return 10 + c - 'A';
1497368708Smm#endif
1498368708Smm
1499368708Smm	return -1;
1500368708Smm}
1501368708Smm
1502368708Smmstatic int
1503368708Smmparse_digest(struct archive_read *a, struct archive_entry *entry,
1504368708Smm    const char *digest, int type)
1505368708Smm{
1506368708Smm	unsigned char digest_buf[64];
1507368708Smm	int high, low;
1508368708Smm	size_t i, j, len;
1509368708Smm
1510368708Smm	switch (type) {
1511368708Smm	case ARCHIVE_ENTRY_DIGEST_MD5:
1512368708Smm		len = sizeof(entry->digest.md5);
1513368708Smm		break;
1514368708Smm	case ARCHIVE_ENTRY_DIGEST_RMD160:
1515368708Smm		len = sizeof(entry->digest.rmd160);
1516368708Smm		break;
1517368708Smm	case ARCHIVE_ENTRY_DIGEST_SHA1:
1518368708Smm		len = sizeof(entry->digest.sha1);
1519368708Smm		break;
1520368708Smm	case ARCHIVE_ENTRY_DIGEST_SHA256:
1521368708Smm		len = sizeof(entry->digest.sha256);
1522368708Smm		break;
1523368708Smm	case ARCHIVE_ENTRY_DIGEST_SHA384:
1524368708Smm		len = sizeof(entry->digest.sha384);
1525368708Smm		break;
1526368708Smm	case ARCHIVE_ENTRY_DIGEST_SHA512:
1527368708Smm		len = sizeof(entry->digest.sha512);
1528368708Smm		break;
1529368708Smm	default:
1530368708Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
1531368708Smm			"Internal error: Unknown digest type");
1532368708Smm		return ARCHIVE_FATAL;
1533368708Smm	}
1534368708Smm
1535368708Smm	if (len > sizeof(digest_buf)) {
1536368708Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
1537368708Smm			"Internal error: Digest storage too large");
1538368708Smm		return ARCHIVE_FATAL;
1539368708Smm	}
1540368708Smm
1541368708Smm	len *= 2;
1542368708Smm
1543368708Smm	if (strnlen(digest, len+1) != len) {
1544368708Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
1545368708Smm				  "incorrect digest length, ignoring");
1546368708Smm		return ARCHIVE_WARN;
1547368708Smm	}
1548368708Smm
1549368708Smm	for (i = 0, j = 0; i < len; i += 2, j++) {
1550368708Smm		high = parse_hex_nibble(digest[i]);
1551368708Smm		low = parse_hex_nibble(digest[i+1]);
1552368708Smm		if (high == -1 || low == -1) {
1553368708Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
1554368708Smm					  "invalid digest data, ignoring");
1555368708Smm			return ARCHIVE_WARN;
1556368708Smm		}
1557368708Smm
1558368708Smm		digest_buf[j] = high << 4 | low;
1559368708Smm	}
1560368708Smm
1561368708Smm	return archive_entry_set_digest(entry, type, digest_buf);
1562368708Smm}
1563368708Smm
1564228753Smm/*
1565228753Smm * Parse a single keyword and its value.
1566228753Smm */
1567228753Smmstatic int
1568228753Smmparse_keyword(struct archive_read *a, struct mtree *mtree,
1569232153Smm    struct archive_entry *entry, struct mtree_option *opt, int *parsed_kws)
1570228753Smm{
1571228753Smm	char *val, *key;
1572228753Smm
1573232153Smm	key = opt->value;
1574228753Smm
1575228753Smm	if (*key == '\0')
1576228753Smm		return (ARCHIVE_OK);
1577228753Smm
1578248616Smm	if (strcmp(key, "nochange") == 0) {
1579248616Smm		*parsed_kws |= MTREE_HAS_NOCHANGE;
1580248616Smm		return (ARCHIVE_OK);
1581248616Smm	}
1582228753Smm	if (strcmp(key, "optional") == 0) {
1583228753Smm		*parsed_kws |= MTREE_HAS_OPTIONAL;
1584228753Smm		return (ARCHIVE_OK);
1585228753Smm	}
1586228753Smm	if (strcmp(key, "ignore") == 0) {
1587228753Smm		/*
1588228753Smm		 * The mtree processing is not recursive, so
1589228753Smm		 * recursion will only happen for explicitly listed
1590228753Smm		 * entries.
1591228753Smm		 */
1592228753Smm		return (ARCHIVE_OK);
1593228753Smm	}
1594228753Smm
1595228753Smm	val = strchr(key, '=');
1596228753Smm	if (val == NULL) {
1597228753Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
1598228753Smm		    "Malformed attribute \"%s\" (%d)", key, key[0]);
1599228753Smm		return (ARCHIVE_WARN);
1600228753Smm	}
1601228753Smm
1602228753Smm	*val = '\0';
1603228753Smm	++val;
1604228753Smm
1605228753Smm	switch (key[0]) {
1606228753Smm	case 'c':
1607228753Smm		if (strcmp(key, "content") == 0
1608228753Smm		    || strcmp(key, "contents") == 0) {
1609228753Smm			parse_escapes(val, NULL);
1610228753Smm			archive_strcpy(&mtree->contents_name, val);
1611228753Smm			break;
1612228753Smm		}
1613228753Smm		if (strcmp(key, "cksum") == 0)
1614228753Smm			break;
1615328828Smm		__LA_FALLTHROUGH;
1616228753Smm	case 'd':
1617228753Smm		if (strcmp(key, "device") == 0) {
1618302001Smm			/* stat(2) st_rdev field, e.g. the major/minor IDs
1619302001Smm			 * of a char/block special file */
1620302001Smm			int r;
1621302001Smm			dev_t dev;
1622302001Smm
1623228753Smm			*parsed_kws |= MTREE_HAS_DEVICE;
1624302001Smm			r = parse_device(&dev, &a->archive, val);
1625302001Smm			if (r == ARCHIVE_OK)
1626302001Smm				archive_entry_set_rdev(entry, dev);
1627302001Smm			return r;
1628228753Smm		}
1629328828Smm		__LA_FALLTHROUGH;
1630228753Smm	case 'f':
1631228753Smm		if (strcmp(key, "flags") == 0) {
1632228753Smm			*parsed_kws |= MTREE_HAS_FFLAGS;
1633228753Smm			archive_entry_copy_fflags_text(entry, val);
1634228753Smm			break;
1635228753Smm		}
1636328828Smm		__LA_FALLTHROUGH;
1637228753Smm	case 'g':
1638228753Smm		if (strcmp(key, "gid") == 0) {
1639228753Smm			*parsed_kws |= MTREE_HAS_GID;
1640318483Smm			archive_entry_set_gid(entry, mtree_atol(&val, 10));
1641228753Smm			break;
1642228753Smm		}
1643228753Smm		if (strcmp(key, "gname") == 0) {
1644228753Smm			*parsed_kws |= MTREE_HAS_GNAME;
1645228753Smm			archive_entry_copy_gname(entry, val);
1646228753Smm			break;
1647228753Smm		}
1648328828Smm		__LA_FALLTHROUGH;
1649302001Smm	case 'i':
1650302001Smm		if (strcmp(key, "inode") == 0) {
1651318483Smm			archive_entry_set_ino(entry, mtree_atol(&val, 10));
1652302001Smm			break;
1653302001Smm		}
1654328828Smm		__LA_FALLTHROUGH;
1655228753Smm	case 'l':
1656228753Smm		if (strcmp(key, "link") == 0) {
1657228753Smm			archive_entry_copy_symlink(entry, val);
1658228753Smm			break;
1659228753Smm		}
1660328828Smm		__LA_FALLTHROUGH;
1661228753Smm	case 'm':
1662368708Smm		if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0) {
1663368708Smm			return parse_digest(a, entry, val,
1664368708Smm			    ARCHIVE_ENTRY_DIGEST_MD5);
1665368708Smm		}
1666228753Smm		if (strcmp(key, "mode") == 0) {
1667318483Smm			if (val[0] >= '0' && val[0] <= '7') {
1668228753Smm				*parsed_kws |= MTREE_HAS_PERM;
1669228753Smm				archive_entry_set_perm(entry,
1670318483Smm				    (mode_t)mtree_atol(&val, 8));
1671228753Smm			} else {
1672228753Smm				archive_set_error(&a->archive,
1673228753Smm				    ARCHIVE_ERRNO_FILE_FORMAT,
1674318483Smm				    "Symbolic or non-octal mode \"%s\" unsupported", val);
1675228753Smm				return ARCHIVE_WARN;
1676228753Smm			}
1677228753Smm			break;
1678228753Smm		}
1679328828Smm		__LA_FALLTHROUGH;
1680228753Smm	case 'n':
1681228753Smm		if (strcmp(key, "nlink") == 0) {
1682228753Smm			*parsed_kws |= MTREE_HAS_NLINK;
1683238856Smm			archive_entry_set_nlink(entry,
1684318483Smm				(unsigned int)mtree_atol(&val, 10));
1685228753Smm			break;
1686228753Smm		}
1687328828Smm		__LA_FALLTHROUGH;
1688228753Smm	case 'r':
1689302001Smm		if (strcmp(key, "resdevice") == 0) {
1690302001Smm			/* stat(2) st_dev field, e.g. the device ID where the
1691302001Smm			 * inode resides */
1692302001Smm			int r;
1693302001Smm			dev_t dev;
1694302001Smm
1695302001Smm			r = parse_device(&dev, &a->archive, val);
1696302001Smm			if (r == ARCHIVE_OK)
1697302001Smm				archive_entry_set_dev(entry, dev);
1698302001Smm			return r;
1699302001Smm		}
1700228753Smm		if (strcmp(key, "rmd160") == 0 ||
1701368708Smm		    strcmp(key, "rmd160digest") == 0) {
1702368708Smm			return parse_digest(a, entry, val,
1703368708Smm			    ARCHIVE_ENTRY_DIGEST_RMD160);
1704368708Smm		}
1705328828Smm		__LA_FALLTHROUGH;
1706228753Smm	case 's':
1707368708Smm		if (strcmp(key, "sha1") == 0 ||
1708368708Smm		    strcmp(key, "sha1digest") == 0) {
1709368708Smm			return parse_digest(a, entry, val,
1710368708Smm			    ARCHIVE_ENTRY_DIGEST_SHA1);
1711368708Smm		}
1712228753Smm		if (strcmp(key, "sha256") == 0 ||
1713368708Smm		    strcmp(key, "sha256digest") == 0) {
1714368708Smm			return parse_digest(a, entry, val,
1715368708Smm			    ARCHIVE_ENTRY_DIGEST_SHA256);
1716368708Smm		}
1717228753Smm		if (strcmp(key, "sha384") == 0 ||
1718368708Smm		    strcmp(key, "sha384digest") == 0) {
1719368708Smm			return parse_digest(a, entry, val,
1720368708Smm			    ARCHIVE_ENTRY_DIGEST_SHA384);
1721368708Smm		}
1722228753Smm		if (strcmp(key, "sha512") == 0 ||
1723368708Smm		    strcmp(key, "sha512digest") == 0) {
1724368708Smm			return parse_digest(a, entry, val,
1725368708Smm			    ARCHIVE_ENTRY_DIGEST_SHA512);
1726368708Smm		}
1727228753Smm		if (strcmp(key, "size") == 0) {
1728318483Smm			archive_entry_set_size(entry, mtree_atol(&val, 10));
1729228753Smm			break;
1730228753Smm		}
1731328828Smm		__LA_FALLTHROUGH;
1732228753Smm	case 't':
1733228753Smm		if (strcmp(key, "tags") == 0) {
1734228753Smm			/*
1735228753Smm			 * Comma delimited list of tags.
1736228753Smm			 * Ignore the tags for now, but the interface
1737228753Smm			 * should be extended to allow inclusion/exclusion.
1738228753Smm			 */
1739228753Smm			break;
1740228753Smm		}
1741228753Smm		if (strcmp(key, "time") == 0) {
1742232153Smm			int64_t m;
1743232153Smm			int64_t my_time_t_max = get_time_t_max();
1744232153Smm			int64_t my_time_t_min = get_time_t_min();
1745302001Smm			long ns = 0;
1746228753Smm
1747228753Smm			*parsed_kws |= MTREE_HAS_MTIME;
1748318483Smm			m = mtree_atol(&val, 10);
1749232153Smm			/* Replicate an old mtree bug:
1750232153Smm			 * 123456789.1 represents 123456789
1751232153Smm			 * seconds and 1 nanosecond. */
1752228753Smm			if (*val == '.') {
1753228753Smm				++val;
1754318483Smm				ns = (long)mtree_atol(&val, 10);
1755313929Smm				if (ns < 0)
1756313929Smm					ns = 0;
1757313929Smm				else if (ns > 999999999)
1758313929Smm					ns = 999999999;
1759313929Smm			}
1760232153Smm			if (m > my_time_t_max)
1761232153Smm				m = my_time_t_max;
1762232153Smm			else if (m < my_time_t_min)
1763232153Smm				m = my_time_t_min;
1764232153Smm			archive_entry_set_mtime(entry, (time_t)m, ns);
1765228753Smm			break;
1766228753Smm		}
1767228753Smm		if (strcmp(key, "type") == 0) {
1768228753Smm			switch (val[0]) {
1769228753Smm			case 'b':
1770228753Smm				if (strcmp(val, "block") == 0) {
1771232153Smm					archive_entry_set_filetype(entry, AE_IFBLK);
1772228753Smm					break;
1773228753Smm				}
1774328828Smm				__LA_FALLTHROUGH;
1775228753Smm			case 'c':
1776228753Smm				if (strcmp(val, "char") == 0) {
1777302001Smm					archive_entry_set_filetype(entry,
1778302001Smm						AE_IFCHR);
1779228753Smm					break;
1780228753Smm				}
1781328828Smm				__LA_FALLTHROUGH;
1782228753Smm			case 'd':
1783228753Smm				if (strcmp(val, "dir") == 0) {
1784302001Smm					archive_entry_set_filetype(entry,
1785302001Smm						AE_IFDIR);
1786228753Smm					break;
1787228753Smm				}
1788328828Smm				__LA_FALLTHROUGH;
1789228753Smm			case 'f':
1790228753Smm				if (strcmp(val, "fifo") == 0) {
1791302001Smm					archive_entry_set_filetype(entry,
1792302001Smm						AE_IFIFO);
1793228753Smm					break;
1794228753Smm				}
1795228753Smm				if (strcmp(val, "file") == 0) {
1796302001Smm					archive_entry_set_filetype(entry,
1797302001Smm						AE_IFREG);
1798228753Smm					break;
1799228753Smm				}
1800328828Smm				__LA_FALLTHROUGH;
1801228753Smm			case 'l':
1802228753Smm				if (strcmp(val, "link") == 0) {
1803302001Smm					archive_entry_set_filetype(entry,
1804302001Smm						AE_IFLNK);
1805228753Smm					break;
1806228753Smm				}
1807328828Smm				__LA_FALLTHROUGH;
1808228753Smm			default:
1809228753Smm				archive_set_error(&a->archive,
1810228753Smm				    ARCHIVE_ERRNO_FILE_FORMAT,
1811302001Smm				    "Unrecognized file type \"%s\"; "
1812302001Smm				    "assuming \"file\"", val);
1813232153Smm				archive_entry_set_filetype(entry, AE_IFREG);
1814228753Smm				return (ARCHIVE_WARN);
1815228753Smm			}
1816232153Smm			*parsed_kws |= MTREE_HAS_TYPE;
1817228753Smm			break;
1818228753Smm		}
1819328828Smm		__LA_FALLTHROUGH;
1820228753Smm	case 'u':
1821228753Smm		if (strcmp(key, "uid") == 0) {
1822228753Smm			*parsed_kws |= MTREE_HAS_UID;
1823318483Smm			archive_entry_set_uid(entry, mtree_atol(&val, 10));
1824228753Smm			break;
1825228753Smm		}
1826228753Smm		if (strcmp(key, "uname") == 0) {
1827228753Smm			*parsed_kws |= MTREE_HAS_UNAME;
1828228753Smm			archive_entry_copy_uname(entry, val);
1829228753Smm			break;
1830228753Smm		}
1831328828Smm		__LA_FALLTHROUGH;
1832228753Smm	default:
1833228753Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
1834228753Smm		    "Unrecognized key %s=%s", key, val);
1835228753Smm		return (ARCHIVE_WARN);
1836228753Smm	}
1837228753Smm	return (ARCHIVE_OK);
1838228753Smm}
1839228753Smm
1840228753Smmstatic int
1841302001Smmread_data(struct archive_read *a, const void **buff, size_t *size,
1842302001Smm    int64_t *offset)
1843228753Smm{
1844228753Smm	size_t bytes_to_read;
1845228753Smm	ssize_t bytes_read;
1846228753Smm	struct mtree *mtree;
1847228753Smm
1848228753Smm	mtree = (struct mtree *)(a->format->data);
1849228753Smm	if (mtree->fd < 0) {
1850228753Smm		*buff = NULL;
1851228753Smm		*offset = 0;
1852228753Smm		*size = 0;
1853228753Smm		return (ARCHIVE_EOF);
1854228753Smm	}
1855228753Smm	if (mtree->buff == NULL) {
1856228753Smm		mtree->buffsize = 64 * 1024;
1857228753Smm		mtree->buff = malloc(mtree->buffsize);
1858228753Smm		if (mtree->buff == NULL) {
1859228753Smm			archive_set_error(&a->archive, ENOMEM,
1860228753Smm			    "Can't allocate memory");
1861228753Smm			return (ARCHIVE_FATAL);
1862228753Smm		}
1863228753Smm	}
1864228753Smm
1865228753Smm	*buff = mtree->buff;
1866228753Smm	*offset = mtree->offset;
1867232153Smm	if ((int64_t)mtree->buffsize > mtree->cur_size - mtree->offset)
1868238856Smm		bytes_to_read = (size_t)(mtree->cur_size - mtree->offset);
1869228753Smm	else
1870228753Smm		bytes_to_read = mtree->buffsize;
1871228753Smm	bytes_read = read(mtree->fd, mtree->buff, bytes_to_read);
1872228753Smm	if (bytes_read < 0) {
1873228753Smm		archive_set_error(&a->archive, errno, "Can't read");
1874228753Smm		return (ARCHIVE_WARN);
1875228753Smm	}
1876228753Smm	if (bytes_read == 0) {
1877228753Smm		*size = 0;
1878228753Smm		return (ARCHIVE_EOF);
1879228753Smm	}
1880228753Smm	mtree->offset += bytes_read;
1881228753Smm	*size = bytes_read;
1882228753Smm	return (ARCHIVE_OK);
1883228753Smm}
1884228753Smm
1885228753Smm/* Skip does nothing except possibly close the contents file. */
1886228753Smmstatic int
1887228753Smmskip(struct archive_read *a)
1888228753Smm{
1889228753Smm	struct mtree *mtree;
1890228753Smm
1891228753Smm	mtree = (struct mtree *)(a->format->data);
1892228753Smm	if (mtree->fd >= 0) {
1893228753Smm		close(mtree->fd);
1894228753Smm		mtree->fd = -1;
1895228753Smm	}
1896228753Smm	return (ARCHIVE_OK);
1897228753Smm}
1898228753Smm
1899228753Smm/*
1900228753Smm * Since parsing backslash sequences always makes strings shorter,
1901228753Smm * we can always do this conversion in-place.
1902228753Smm */
1903228753Smmstatic void
1904228753Smmparse_escapes(char *src, struct mtree_entry *mentry)
1905228753Smm{
1906228753Smm	char *dest = src;
1907228753Smm	char c;
1908228753Smm
1909228753Smm	if (mentry != NULL && strcmp(src, ".") == 0)
1910228753Smm		mentry->full = 1;
1911228753Smm
1912228753Smm	while (*src != '\0') {
1913228753Smm		c = *src++;
1914228753Smm		if (c == '/' && mentry != NULL)
1915228753Smm			mentry->full = 1;
1916228753Smm		if (c == '\\') {
1917228753Smm			switch (src[0]) {
1918228753Smm			case '0':
1919228753Smm				if (src[1] < '0' || src[1] > '7') {
1920228753Smm					c = 0;
1921228753Smm					++src;
1922228753Smm					break;
1923228753Smm				}
1924228753Smm				/* FALLTHROUGH */
1925228753Smm			case '1':
1926228753Smm			case '2':
1927228753Smm			case '3':
1928228753Smm				if (src[1] >= '0' && src[1] <= '7' &&
1929228753Smm				    src[2] >= '0' && src[2] <= '7') {
1930228753Smm					c = (src[0] - '0') << 6;
1931228753Smm					c |= (src[1] - '0') << 3;
1932228753Smm					c |= (src[2] - '0');
1933228753Smm					src += 3;
1934228753Smm				}
1935228753Smm				break;
1936228753Smm			case 'a':
1937228753Smm				c = '\a';
1938228753Smm				++src;
1939228753Smm				break;
1940228753Smm			case 'b':
1941228753Smm				c = '\b';
1942228753Smm				++src;
1943228753Smm				break;
1944228753Smm			case 'f':
1945228753Smm				c = '\f';
1946228753Smm				++src;
1947228753Smm				break;
1948228753Smm			case 'n':
1949228753Smm				c = '\n';
1950228753Smm				++src;
1951228753Smm				break;
1952228753Smm			case 'r':
1953228753Smm				c = '\r';
1954228753Smm				++src;
1955228753Smm				break;
1956228753Smm			case 's':
1957228753Smm				c = ' ';
1958228753Smm				++src;
1959228753Smm				break;
1960228753Smm			case 't':
1961228753Smm				c = '\t';
1962228753Smm				++src;
1963228753Smm				break;
1964228753Smm			case 'v':
1965228753Smm				c = '\v';
1966228753Smm				++src;
1967228753Smm				break;
1968302001Smm			case '\\':
1969302001Smm				c = '\\';
1970302001Smm				++src;
1971302001Smm				break;
1972228753Smm			}
1973228753Smm		}
1974228753Smm		*dest++ = c;
1975228753Smm	}
1976228753Smm	*dest = '\0';
1977228753Smm}
1978228753Smm
1979232153Smm/* Parse a hex digit. */
1980232153Smmstatic int
1981318483Smmparsedigit(char c)
1982232153Smm{
1983232153Smm	if (c >= '0' && c <= '9')
1984232153Smm		return c - '0';
1985232153Smm	else if (c >= 'a' && c <= 'f')
1986232153Smm		return c - 'a';
1987232153Smm	else if (c >= 'A' && c <= 'F')
1988232153Smm		return c - 'A';
1989232153Smm	else
1990232153Smm		return -1;
1991232153Smm}
1992232153Smm
1993228753Smm/*
1994228753Smm * Note that this implementation does not (and should not!) obey
1995228753Smm * locale settings; you cannot simply substitute strtol here, since
1996228753Smm * it does obey locale.
1997228753Smm */
1998228753Smmstatic int64_t
1999318483Smmmtree_atol(char **p, int base)
2000228753Smm{
2001318483Smm	int64_t l, limit;
2002318483Smm	int digit, last_digit_limit;
2003228753Smm
2004318483Smm	if (base == 0) {
2005318483Smm		if (**p != '0')
2006318483Smm			base = 10;
2007318483Smm		else if ((*p)[1] == 'x' || (*p)[1] == 'X') {
2008318483Smm			*p += 2;
2009318483Smm			base = 16;
2010318483Smm		} else {
2011318483Smm			base = 8;
2012318483Smm		}
2013318483Smm	}
2014228753Smm
2015228753Smm	if (**p == '-') {
2016318483Smm		limit = INT64_MIN / base;
2017318483Smm		last_digit_limit = INT64_MIN % base;
2018228753Smm		++(*p);
2019318483Smm
2020318483Smm		l = 0;
2021318483Smm		digit = parsedigit(**p);
2022318483Smm		while (digit >= 0 && digit < base) {
2023318483Smm			if (l < limit || (l == limit && digit > last_digit_limit))
2024318483Smm				return INT64_MIN;
2025318483Smm			l = (l * base) - digit;
2026318483Smm			digit = parsedigit(*++(*p));
2027318483Smm		}
2028318483Smm		return l;
2029232153Smm	} else {
2030232153Smm		limit = INT64_MAX / base;
2031232153Smm		last_digit_limit = INT64_MAX % base;
2032228753Smm
2033318483Smm		l = 0;
2034318483Smm		digit = parsedigit(**p);
2035318483Smm		while (digit >= 0 && digit < base) {
2036318483Smm			if (l > limit || (l == limit && digit > last_digit_limit))
2037318483Smm				return INT64_MAX;
2038318483Smm			l = (l * base) + digit;
2039318483Smm			digit = parsedigit(*++(*p));
2040318483Smm		}
2041318483Smm		return l;
2042228753Smm	}
2043228753Smm}
2044228753Smm
2045228753Smm/*
2046228753Smm * Returns length of line (including trailing newline)
2047228753Smm * or negative on error.  'start' argument is updated to
2048228753Smm * point to first character of line.
2049228753Smm */
2050228753Smmstatic ssize_t
2051302001Smmreadline(struct archive_read *a, struct mtree *mtree, char **start,
2052302001Smm    ssize_t limit)
2053228753Smm{
2054228753Smm	ssize_t bytes_read;
2055228753Smm	ssize_t total_size = 0;
2056228753Smm	ssize_t find_off = 0;
2057228753Smm	const void *t;
2058302001Smm	void *nl;
2059228753Smm	char *u;
2060228753Smm
2061228753Smm	/* Accumulate line in a line buffer. */
2062228753Smm	for (;;) {
2063228753Smm		/* Read some more. */
2064228753Smm		t = __archive_read_ahead(a, 1, &bytes_read);
2065228753Smm		if (t == NULL)
2066228753Smm			return (0);
2067228753Smm		if (bytes_read < 0)
2068228753Smm			return (ARCHIVE_FATAL);
2069302001Smm		nl = memchr(t, '\n', bytes_read);
2070302001Smm		/* If we found '\n', trim the read to end exactly there. */
2071302001Smm		if (nl != NULL) {
2072302001Smm			bytes_read = ((const char *)nl) - ((const char *)t) + 1;
2073228753Smm		}
2074228753Smm		if (total_size + bytes_read + 1 > limit) {
2075228753Smm			archive_set_error(&a->archive,
2076228753Smm			    ARCHIVE_ERRNO_FILE_FORMAT,
2077228753Smm			    "Line too long");
2078228753Smm			return (ARCHIVE_FATAL);
2079228753Smm		}
2080228753Smm		if (archive_string_ensure(&mtree->line,
2081228753Smm			total_size + bytes_read + 1) == NULL) {
2082228753Smm			archive_set_error(&a->archive, ENOMEM,
2083228753Smm			    "Can't allocate working buffer");
2084228753Smm			return (ARCHIVE_FATAL);
2085228753Smm		}
2086302001Smm		/* Append new bytes to string. */
2087228753Smm		memcpy(mtree->line.s + total_size, t, bytes_read);
2088228753Smm		__archive_read_consume(a, bytes_read);
2089228753Smm		total_size += bytes_read;
2090228753Smm		mtree->line.s[total_size] = '\0';
2091302001Smm
2092228753Smm		for (u = mtree->line.s + find_off; *u; ++u) {
2093228753Smm			if (u[0] == '\n') {
2094302001Smm				/* Ends with unescaped newline. */
2095228753Smm				*start = mtree->line.s;
2096228753Smm				return total_size;
2097302001Smm			} else if (u[0] == '#') {
2098302001Smm				/* Ends with comment sequence #...\n */
2099302001Smm				if (nl == NULL) {
2100302001Smm					/* But we've not found the \n yet */
2101228753Smm					break;
2102302001Smm				}
2103302001Smm			} else if (u[0] == '\\') {
2104302001Smm				if (u[1] == '\n') {
2105302001Smm					/* Trim escaped newline. */
2106302001Smm					total_size -= 2;
2107302001Smm					mtree->line.s[total_size] = '\0';
2108302001Smm					break;
2109302001Smm				} else if (u[1] != '\0') {
2110302001Smm					/* Skip the two-char escape sequence */
2111302001Smm					++u;
2112302001Smm				}
2113228753Smm			}
2114228753Smm		}
2115228753Smm		find_off = u - mtree->line.s;
2116228753Smm	}
2117228753Smm}
2118