xref: /illumos-gate/usr/src/cmd/cpio/utils.c (revision 5fbb8099)
1*5fbb8099SNobutomo Nakano /*
2*5fbb8099SNobutomo Nakano  * CDDL HEADER START
3*5fbb8099SNobutomo Nakano  *
4*5fbb8099SNobutomo Nakano  * The contents of this file are subject to the terms of the
5*5fbb8099SNobutomo Nakano  * Common Development and Distribution License (the "License").
6*5fbb8099SNobutomo Nakano  * You may not use this file except in compliance with the License.
7*5fbb8099SNobutomo Nakano  *
8*5fbb8099SNobutomo Nakano  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5fbb8099SNobutomo Nakano  * or http://www.opensolaris.org/os/licensing.
10*5fbb8099SNobutomo Nakano  * See the License for the specific language governing permissions
11*5fbb8099SNobutomo Nakano  * and limitations under the License.
12*5fbb8099SNobutomo Nakano  *
13*5fbb8099SNobutomo Nakano  * When distributing Covered Code, include this CDDL HEADER in each
14*5fbb8099SNobutomo Nakano  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5fbb8099SNobutomo Nakano  * If applicable, add the following below this CDDL HEADER, with the
16*5fbb8099SNobutomo Nakano  * fields enclosed by brackets "[]" replaced with your own identifying
17*5fbb8099SNobutomo Nakano  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5fbb8099SNobutomo Nakano  *
19*5fbb8099SNobutomo Nakano  * CDDL HEADER END
20*5fbb8099SNobutomo Nakano  */
21*5fbb8099SNobutomo Nakano /*
22*5fbb8099SNobutomo Nakano  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*5fbb8099SNobutomo Nakano  * Use is subject to license terms.
24*5fbb8099SNobutomo Nakano  */
25*5fbb8099SNobutomo Nakano 
26*5fbb8099SNobutomo Nakano /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
27*5fbb8099SNobutomo Nakano /*	All Rights Reserved					*/
28*5fbb8099SNobutomo Nakano 
29*5fbb8099SNobutomo Nakano /*
30*5fbb8099SNobutomo Nakano  * Portions of this source code were derived from Berkeley 4.3 BSD
31*5fbb8099SNobutomo Nakano  * under license from the Regents of the University of California.
32*5fbb8099SNobutomo Nakano  */
33*5fbb8099SNobutomo Nakano 
34*5fbb8099SNobutomo Nakano #include <stdio.h>
35*5fbb8099SNobutomo Nakano #include <stdlib.h>
36*5fbb8099SNobutomo Nakano #include <stdarg.h>
37*5fbb8099SNobutomo Nakano #include <string.h>
38*5fbb8099SNobutomo Nakano #include <sys/stat.h>
39*5fbb8099SNobutomo Nakano #include <unistd.h>
40*5fbb8099SNobutomo Nakano #include <ctype.h>
41*5fbb8099SNobutomo Nakano #include <limits.h>
42*5fbb8099SNobutomo Nakano #include <errno.h>
43*5fbb8099SNobutomo Nakano #include <fcntl.h>
44*5fbb8099SNobutomo Nakano 
45*5fbb8099SNobutomo Nakano #include "cpio.h"
46*5fbb8099SNobutomo Nakano 
47*5fbb8099SNobutomo Nakano /*
48*5fbb8099SNobutomo Nakano  * Allocation wrappers.  Used to centralize error handling for
49*5fbb8099SNobutomo Nakano  * failed allocations.
50*5fbb8099SNobutomo Nakano  */
51*5fbb8099SNobutomo Nakano static void *
e_alloc_fail(int flag)52*5fbb8099SNobutomo Nakano e_alloc_fail(int flag)
53*5fbb8099SNobutomo Nakano {
54*5fbb8099SNobutomo Nakano 	if (flag == E_EXIT)
55*5fbb8099SNobutomo Nakano 		msg(EXTN, "Out of memory");
56*5fbb8099SNobutomo Nakano 
57*5fbb8099SNobutomo Nakano 	return (NULL);
58*5fbb8099SNobutomo Nakano }
59*5fbb8099SNobutomo Nakano 
60*5fbb8099SNobutomo Nakano /*
61*5fbb8099SNobutomo Nakano  *  Note: unlike the other e_*lloc functions, e_realloc does not zero out the
62*5fbb8099SNobutomo Nakano  *  additional memory it returns.  Ensure that you do not trust its contents
63*5fbb8099SNobutomo Nakano  *  when you call it.
64*5fbb8099SNobutomo Nakano  */
65*5fbb8099SNobutomo Nakano void *
e_realloc(int flag,void * old,size_t newsize)66*5fbb8099SNobutomo Nakano e_realloc(int flag, void *old, size_t newsize)
67*5fbb8099SNobutomo Nakano {
68*5fbb8099SNobutomo Nakano 	void *ret = realloc(old, newsize);
69*5fbb8099SNobutomo Nakano 
70*5fbb8099SNobutomo Nakano 	if (ret == NULL) {
71*5fbb8099SNobutomo Nakano 		return (e_alloc_fail(flag));
72*5fbb8099SNobutomo Nakano 	}
73*5fbb8099SNobutomo Nakano 
74*5fbb8099SNobutomo Nakano 	return (ret);
75*5fbb8099SNobutomo Nakano }
76*5fbb8099SNobutomo Nakano 
77*5fbb8099SNobutomo Nakano char *
e_strdup(int flag,const char * arg)78*5fbb8099SNobutomo Nakano e_strdup(int flag, const char *arg)
79*5fbb8099SNobutomo Nakano {
80*5fbb8099SNobutomo Nakano 	char *ret = strdup(arg);
81*5fbb8099SNobutomo Nakano 
82*5fbb8099SNobutomo Nakano 	if (ret == NULL) {
83*5fbb8099SNobutomo Nakano 		return (e_alloc_fail(flag));
84*5fbb8099SNobutomo Nakano 	}
85*5fbb8099SNobutomo Nakano 
86*5fbb8099SNobutomo Nakano 	return (ret);
87*5fbb8099SNobutomo Nakano }
88*5fbb8099SNobutomo Nakano 
89*5fbb8099SNobutomo Nakano void *
e_valloc(int flag,size_t size)90*5fbb8099SNobutomo Nakano e_valloc(int flag, size_t size)
91*5fbb8099SNobutomo Nakano {
92*5fbb8099SNobutomo Nakano 	void *ret = valloc(size);
93*5fbb8099SNobutomo Nakano 
94*5fbb8099SNobutomo Nakano 	if (ret == NULL) {
95*5fbb8099SNobutomo Nakano 		return (e_alloc_fail(flag));
96*5fbb8099SNobutomo Nakano 	}
97*5fbb8099SNobutomo Nakano 
98*5fbb8099SNobutomo Nakano 	return (ret);
99*5fbb8099SNobutomo Nakano }
100*5fbb8099SNobutomo Nakano 
101*5fbb8099SNobutomo Nakano void *
e_zalloc(int flag,size_t size)102*5fbb8099SNobutomo Nakano e_zalloc(int flag, size_t size)
103*5fbb8099SNobutomo Nakano {
104*5fbb8099SNobutomo Nakano 	void *ret = malloc(size);
105*5fbb8099SNobutomo Nakano 
106*5fbb8099SNobutomo Nakano 	if (ret == NULL) {
107*5fbb8099SNobutomo Nakano 		return (e_alloc_fail(flag));
108*5fbb8099SNobutomo Nakano 	}
109*5fbb8099SNobutomo Nakano 
110*5fbb8099SNobutomo Nakano 	(void) memset(ret, 0, size);
111*5fbb8099SNobutomo Nakano 	return (ret);
112*5fbb8099SNobutomo Nakano }
113*5fbb8099SNobutomo Nakano 
114*5fbb8099SNobutomo Nakano /*
115*5fbb8099SNobutomo Nakano  * Simple printf() which only support "%s" conversion.
116*5fbb8099SNobutomo Nakano  * We need secure version of printf since format string can be supplied
117*5fbb8099SNobutomo Nakano  * from gettext().
118*5fbb8099SNobutomo Nakano  */
119*5fbb8099SNobutomo Nakano void
str_fprintf(FILE * fp,const char * fmt,...)120*5fbb8099SNobutomo Nakano str_fprintf(FILE *fp, const char *fmt, ...)
121*5fbb8099SNobutomo Nakano {
122*5fbb8099SNobutomo Nakano 	const char *s = fmt;
123*5fbb8099SNobutomo Nakano 	va_list	ap;
124*5fbb8099SNobutomo Nakano 
125*5fbb8099SNobutomo Nakano 	va_start(ap, fmt);
126*5fbb8099SNobutomo Nakano 	while (*s != '\0') {
127*5fbb8099SNobutomo Nakano 		if (*s != '%') {
128*5fbb8099SNobutomo Nakano 			(void) fputc(*s++, fp);
129*5fbb8099SNobutomo Nakano 			continue;
130*5fbb8099SNobutomo Nakano 		}
131*5fbb8099SNobutomo Nakano 		s++;
132*5fbb8099SNobutomo Nakano 		if (*s != 's') {
133*5fbb8099SNobutomo Nakano 			(void) fputc(*(s - 1), fp);
134*5fbb8099SNobutomo Nakano 			(void) fputc(*s++, fp);
135*5fbb8099SNobutomo Nakano 			continue;
136*5fbb8099SNobutomo Nakano 		}
137*5fbb8099SNobutomo Nakano 		(void) fputs(va_arg(ap, char *), fp);
138*5fbb8099SNobutomo Nakano 		s++;
139*5fbb8099SNobutomo Nakano 	}
140*5fbb8099SNobutomo Nakano 	va_end(ap);
141*5fbb8099SNobutomo Nakano }
142*5fbb8099SNobutomo Nakano 
143*5fbb8099SNobutomo Nakano /*
144*5fbb8099SNobutomo Nakano  * Step through a file discovering and recording pairs of data and hole
145*5fbb8099SNobutomo Nakano  * offsets. Returns a linked list of data/hole offset pairs of a file.
146*5fbb8099SNobutomo Nakano  * If there is no holes found, NULL is returned.
147*5fbb8099SNobutomo Nakano  *
148*5fbb8099SNobutomo Nakano  * Note: According to lseek(2), only filesystems which support
149*5fbb8099SNobutomo Nakano  * fpathconf(_PC_MIN_HOLE_SIZE) support SEEK_HOLE.  For filesystems
150*5fbb8099SNobutomo Nakano  * that do not supply information about holes, the file will be
151*5fbb8099SNobutomo Nakano  * represented as one entire data region.
152*5fbb8099SNobutomo Nakano  */
153*5fbb8099SNobutomo Nakano static holes_list_t *
get_holes_list(int fd,off_t filesz,size_t * countp)154*5fbb8099SNobutomo Nakano get_holes_list(int fd, off_t filesz, size_t *countp)
155*5fbb8099SNobutomo Nakano {
156*5fbb8099SNobutomo Nakano 	off_t	data, hole;
157*5fbb8099SNobutomo Nakano 	holes_list_t *hlh, *hl, **hlp;
158*5fbb8099SNobutomo Nakano 	size_t	cnt;
159*5fbb8099SNobutomo Nakano 
160*5fbb8099SNobutomo Nakano 	if (filesz == 0 || fpathconf(fd, _PC_MIN_HOLE_SIZE) < 0)
161*5fbb8099SNobutomo Nakano 		return (NULL);
162*5fbb8099SNobutomo Nakano 
163*5fbb8099SNobutomo Nakano 	cnt = 0;
164*5fbb8099SNobutomo Nakano 	hole = 0;
165*5fbb8099SNobutomo Nakano 	hlh = NULL;
166*5fbb8099SNobutomo Nakano 	hlp = &hlh;
167*5fbb8099SNobutomo Nakano 
168*5fbb8099SNobutomo Nakano 	while (hole < filesz) {
169*5fbb8099SNobutomo Nakano 		if ((data = lseek(fd, hole, SEEK_DATA)) == -1) {
170*5fbb8099SNobutomo Nakano 			/* no more data till the end of file */
171*5fbb8099SNobutomo Nakano 			if (errno == ENXIO) {
172*5fbb8099SNobutomo Nakano 				data = filesz;
173*5fbb8099SNobutomo Nakano 			} else {
174*5fbb8099SNobutomo Nakano 				/* assume data starts from the * beginning */
175*5fbb8099SNobutomo Nakano 				data = 0;
176*5fbb8099SNobutomo Nakano 			}
177*5fbb8099SNobutomo Nakano 		}
178*5fbb8099SNobutomo Nakano 		if ((hole = lseek(fd, data, SEEK_HOLE)) == -1) {
179*5fbb8099SNobutomo Nakano 			/* assume that data ends at the end of file */
180*5fbb8099SNobutomo Nakano 			hole = filesz;
181*5fbb8099SNobutomo Nakano 		}
182*5fbb8099SNobutomo Nakano 		if (data == 0 && hole == filesz) {
183*5fbb8099SNobutomo Nakano 			/* no holes */
184*5fbb8099SNobutomo Nakano 			break;
185*5fbb8099SNobutomo Nakano 		}
186*5fbb8099SNobutomo Nakano 		hl = e_zalloc(E_EXIT, sizeof (holes_list_t));
187*5fbb8099SNobutomo Nakano 		hl->hl_next = NULL;
188*5fbb8099SNobutomo Nakano 
189*5fbb8099SNobutomo Nakano 		/* set data and hole */
190*5fbb8099SNobutomo Nakano 		hl->hl_data = data;
191*5fbb8099SNobutomo Nakano 		hl->hl_hole = hole;
192*5fbb8099SNobutomo Nakano 
193*5fbb8099SNobutomo Nakano 		*hlp = hl;
194*5fbb8099SNobutomo Nakano 		hlp = &hl->hl_next;
195*5fbb8099SNobutomo Nakano 		cnt++;
196*5fbb8099SNobutomo Nakano 	}
197*5fbb8099SNobutomo Nakano 	if (countp != NULL)
198*5fbb8099SNobutomo Nakano 		*countp = cnt;
199*5fbb8099SNobutomo Nakano 
200*5fbb8099SNobutomo Nakano 	/*
201*5fbb8099SNobutomo Nakano 	 * reset to the beginning, otherwise subsequent read calls would
202*5fbb8099SNobutomo Nakano 	 * get EOF
203*5fbb8099SNobutomo Nakano 	 */
204*5fbb8099SNobutomo Nakano 	(void) lseek(fd, 0, SEEK_SET);
205*5fbb8099SNobutomo Nakano 
206*5fbb8099SNobutomo Nakano 	return (hlh);
207*5fbb8099SNobutomo Nakano }
208*5fbb8099SNobutomo Nakano 
209*5fbb8099SNobutomo Nakano /*
210*5fbb8099SNobutomo Nakano  * Calculate the real data size in the sparse file.
211*5fbb8099SNobutomo Nakano  */
212*5fbb8099SNobutomo Nakano static off_t
get_compressed_filesz(holes_list_t * hlh)213*5fbb8099SNobutomo Nakano get_compressed_filesz(holes_list_t *hlh)
214*5fbb8099SNobutomo Nakano {
215*5fbb8099SNobutomo Nakano 	holes_list_t *hl;
216*5fbb8099SNobutomo Nakano 	off_t	size;
217*5fbb8099SNobutomo Nakano 
218*5fbb8099SNobutomo Nakano 	size = 0;
219*5fbb8099SNobutomo Nakano 	for (hl = hlh; hl != NULL; hl = hl->hl_next) {
220*5fbb8099SNobutomo Nakano 		size += (hl->hl_hole - hl->hl_data);
221*5fbb8099SNobutomo Nakano 	}
222*5fbb8099SNobutomo Nakano 	return (size);
223*5fbb8099SNobutomo Nakano }
224*5fbb8099SNobutomo Nakano 
225*5fbb8099SNobutomo Nakano /*
226*5fbb8099SNobutomo Nakano  * Convert val to digit string and put it in str. The next address
227*5fbb8099SNobutomo Nakano  * of the last digit is returned.
228*5fbb8099SNobutomo Nakano  */
229*5fbb8099SNobutomo Nakano static char *
put_value(off_t val,char * str)230*5fbb8099SNobutomo Nakano put_value(off_t val, char *str)
231*5fbb8099SNobutomo Nakano {
232*5fbb8099SNobutomo Nakano 	size_t	len;
233*5fbb8099SNobutomo Nakano 	char	*digp, dbuf[ULL_MAX_SIZE + 1];
234*5fbb8099SNobutomo Nakano 
235*5fbb8099SNobutomo Nakano 	dbuf[ULL_MAX_SIZE] = '\0';
236*5fbb8099SNobutomo Nakano 	digp = ulltostr((u_longlong_t)val, &dbuf[ULL_MAX_SIZE]);
237*5fbb8099SNobutomo Nakano 	len = &dbuf[ULL_MAX_SIZE] - digp;
238*5fbb8099SNobutomo Nakano 	(void) memcpy(str, digp, len);
239*5fbb8099SNobutomo Nakano 
240*5fbb8099SNobutomo Nakano 	return (str + len);
241*5fbb8099SNobutomo Nakano }
242*5fbb8099SNobutomo Nakano 
243*5fbb8099SNobutomo Nakano /*
244*5fbb8099SNobutomo Nakano  * Put data/hole offset pair into string in the following
245*5fbb8099SNobutomo Nakano  * sequence.
246*5fbb8099SNobutomo Nakano  * <data> <sp> <hole> <sp>
247*5fbb8099SNobutomo Nakano  */
248*5fbb8099SNobutomo Nakano static void
store_sparse_string(holes_list_t * hlh,char * str,size_t * szp)249*5fbb8099SNobutomo Nakano store_sparse_string(holes_list_t *hlh, char *str, size_t *szp)
250*5fbb8099SNobutomo Nakano {
251*5fbb8099SNobutomo Nakano 	holes_list_t *hl;
252*5fbb8099SNobutomo Nakano 	char	*p;
253*5fbb8099SNobutomo Nakano 
254*5fbb8099SNobutomo Nakano 	p = str;
255*5fbb8099SNobutomo Nakano 	for (hl = hlh; hl != NULL; hl = hl->hl_next) {
256*5fbb8099SNobutomo Nakano 		p = put_value(hl->hl_data, p);
257*5fbb8099SNobutomo Nakano 		*p++ = ' ';
258*5fbb8099SNobutomo Nakano 		p = put_value(hl->hl_hole, p);
259*5fbb8099SNobutomo Nakano 		*p++ = ' ';
260*5fbb8099SNobutomo Nakano 	}
261*5fbb8099SNobutomo Nakano 	*--p = '\0';
262*5fbb8099SNobutomo Nakano 	if (szp != NULL)
263*5fbb8099SNobutomo Nakano 		*szp = p - str;
264*5fbb8099SNobutomo Nakano }
265*5fbb8099SNobutomo Nakano 
266*5fbb8099SNobutomo Nakano /*
267*5fbb8099SNobutomo Nakano  * Convert decimal str into unsigned long long value. The end pointer
268*5fbb8099SNobutomo Nakano  * is returned.
269*5fbb8099SNobutomo Nakano  */
270*5fbb8099SNobutomo Nakano static const char *
get_ull_tok(const char * str,uint64_t * ulp)271*5fbb8099SNobutomo Nakano get_ull_tok(const char *str, uint64_t *ulp)
272*5fbb8099SNobutomo Nakano {
273*5fbb8099SNobutomo Nakano 	uint64_t ul;
274*5fbb8099SNobutomo Nakano 	char	*np;
275*5fbb8099SNobutomo Nakano 
276*5fbb8099SNobutomo Nakano 	while (isspace(*str))
277*5fbb8099SNobutomo Nakano 		str++;
278*5fbb8099SNobutomo Nakano 	if (!isdigit(*str))
279*5fbb8099SNobutomo Nakano 		return (NULL);
280*5fbb8099SNobutomo Nakano 
281*5fbb8099SNobutomo Nakano 	errno = 0;
282*5fbb8099SNobutomo Nakano 	ul = strtoull(str, &np, 10);
283*5fbb8099SNobutomo Nakano 	if (ul == ULLONG_MAX && errno == ERANGE)
284*5fbb8099SNobutomo Nakano 		return (NULL);		/* invalid value */
285*5fbb8099SNobutomo Nakano 	if (*np != ' ' && *np != '\0')
286*5fbb8099SNobutomo Nakano 		return (NULL);		/* invalid input */
287*5fbb8099SNobutomo Nakano 
288*5fbb8099SNobutomo Nakano 	*ulp = ul;
289*5fbb8099SNobutomo Nakano 	return (np);
290*5fbb8099SNobutomo Nakano }
291*5fbb8099SNobutomo Nakano 
292*5fbb8099SNobutomo Nakano static void
free_holesdata(holes_info_t * hi)293*5fbb8099SNobutomo Nakano free_holesdata(holes_info_t *hi)
294*5fbb8099SNobutomo Nakano {
295*5fbb8099SNobutomo Nakano 	holes_list_t	*hl, *nhl;
296*5fbb8099SNobutomo Nakano 
297*5fbb8099SNobutomo Nakano 	for (hl = hi->holes_list; hl != NULL; hl = nhl) {
298*5fbb8099SNobutomo Nakano 		nhl = hl->hl_next;
299*5fbb8099SNobutomo Nakano 		free(hl);
300*5fbb8099SNobutomo Nakano 	}
301*5fbb8099SNobutomo Nakano 	hi->holes_list = NULL;
302*5fbb8099SNobutomo Nakano 
303*5fbb8099SNobutomo Nakano 	if (hi->holesdata != NULL)
304*5fbb8099SNobutomo Nakano 		free(hi->holesdata);
305*5fbb8099SNobutomo Nakano 	hi->holesdata = NULL;
306*5fbb8099SNobutomo Nakano }
307*5fbb8099SNobutomo Nakano 
308*5fbb8099SNobutomo Nakano /*
309*5fbb8099SNobutomo Nakano  * When a hole is detected, non NULL holes_info pointer is returned.
310*5fbb8099SNobutomo Nakano  * If we are in copy-out mode, holes_list is converted to string (holesdata)
311*5fbb8099SNobutomo Nakano  * which will be prepended to file contents. The holesdata is a character
312*5fbb8099SNobutomo Nakano  * string and in the format of:
313*5fbb8099SNobutomo Nakano  *
314*5fbb8099SNobutomo Nakano  * <data size(%10u)><SP><file size(%llu)><SP>
315*5fbb8099SNobutomo Nakano  *   <SP><data off><SP><hole off><SP><data off><SP><hole off> ...
316*5fbb8099SNobutomo Nakano  *
317*5fbb8099SNobutomo Nakano  * This string is parsed by parse_holesholes() in copy-in mode to restore
318*5fbb8099SNobutomo Nakano  * the sparse info.
319*5fbb8099SNobutomo Nakano  */
320*5fbb8099SNobutomo Nakano holes_info_t *
get_holes_info(int fd,off_t filesz,boolean_t pass_mode)321*5fbb8099SNobutomo Nakano get_holes_info(int fd, off_t filesz, boolean_t pass_mode)
322*5fbb8099SNobutomo Nakano {
323*5fbb8099SNobutomo Nakano 	holes_info_t *hi;
324*5fbb8099SNobutomo Nakano 	holes_list_t *hl;
325*5fbb8099SNobutomo Nakano 	char	*str, hstr[MIN_HOLES_HDRSIZE + 1];
326*5fbb8099SNobutomo Nakano 	size_t	ninfo, len;
327*5fbb8099SNobutomo Nakano 
328*5fbb8099SNobutomo Nakano 	if ((hl = get_holes_list(fd, filesz, &ninfo)) == NULL)
329*5fbb8099SNobutomo Nakano 		return (NULL);
330*5fbb8099SNobutomo Nakano 
331*5fbb8099SNobutomo Nakano 	hi = e_zalloc(E_EXIT, sizeof (holes_info_t));
332*5fbb8099SNobutomo Nakano 	hi->holes_list = hl;
333*5fbb8099SNobutomo Nakano 
334*5fbb8099SNobutomo Nakano 	if (!pass_mode) {
335*5fbb8099SNobutomo Nakano 		str = e_zalloc(E_EXIT,
336*5fbb8099SNobutomo Nakano 		    MIN_HOLES_HDRSIZE + ninfo * (ULL_MAX_SIZE * 2));
337*5fbb8099SNobutomo Nakano 		/*
338*5fbb8099SNobutomo Nakano 		 * Convert into string data, and place it to after
339*5fbb8099SNobutomo Nakano 		 * the first 2 fixed entries.
340*5fbb8099SNobutomo Nakano 		 */
341*5fbb8099SNobutomo Nakano 		store_sparse_string(hl, str + MIN_HOLES_HDRSIZE, &len);
342*5fbb8099SNobutomo Nakano 
343*5fbb8099SNobutomo Nakano 		/*
344*5fbb8099SNobutomo Nakano 		 * Add the first two fixed entries. The size of holesdata
345*5fbb8099SNobutomo Nakano 		 * includes '\0' at the end of data
346*5fbb8099SNobutomo Nakano 		 */
347*5fbb8099SNobutomo Nakano 		(void) sprintf(hstr, "%10lu %20llu ",
348*5fbb8099SNobutomo Nakano 		    (ulong_t)MIN_HOLES_HDRSIZE + len + 1, filesz);
349*5fbb8099SNobutomo Nakano 		(void) memcpy(str, hstr, MIN_HOLES_HDRSIZE);
350*5fbb8099SNobutomo Nakano 
351*5fbb8099SNobutomo Nakano 		/* calc real file size without holes */
352*5fbb8099SNobutomo Nakano 		hi->data_size = get_compressed_filesz(hl);
353*5fbb8099SNobutomo Nakano 		hi->holesdata = str;
354*5fbb8099SNobutomo Nakano 		hi->holesdata_sz = MIN_HOLES_HDRSIZE + len + 1;
355*5fbb8099SNobutomo Nakano 	}
356*5fbb8099SNobutomo Nakano 	return (hi);
357*5fbb8099SNobutomo Nakano }
358*5fbb8099SNobutomo Nakano 
359*5fbb8099SNobutomo Nakano /*
360*5fbb8099SNobutomo Nakano  * The holesdata information is in the following format:
361*5fbb8099SNobutomo Nakano  * <data size(%10u)><SP><file size(%llu)><SP>
362*5fbb8099SNobutomo Nakano  *   <SP><data off><SP><hole off><SP><data off><SP><hole off> ...
363*5fbb8099SNobutomo Nakano  * read_holes_header() allocates holes_info_t, and read the first 2
364*5fbb8099SNobutomo Nakano  * entries (data size and file size). The rest of holesdata is
365*5fbb8099SNobutomo Nakano  * read by parse_holesdata().
366*5fbb8099SNobutomo Nakano  */
367*5fbb8099SNobutomo Nakano holes_info_t *
read_holes_header(const char * str,off_t filesz)368*5fbb8099SNobutomo Nakano read_holes_header(const char *str, off_t filesz)
369*5fbb8099SNobutomo Nakano {
370*5fbb8099SNobutomo Nakano 	holes_info_t	*hi;
371*5fbb8099SNobutomo Nakano 	uint64_t	ull;
372*5fbb8099SNobutomo Nakano 
373*5fbb8099SNobutomo Nakano 	hi = e_zalloc(E_EXIT, sizeof (holes_info_t));
374*5fbb8099SNobutomo Nakano 
375*5fbb8099SNobutomo Nakano 	/* read prepended holes data size */
376*5fbb8099SNobutomo Nakano 	if ((str = get_ull_tok(str, &ull)) == NULL || *str != ' ') {
377*5fbb8099SNobutomo Nakano bad:
378*5fbb8099SNobutomo Nakano 		free(hi);
379*5fbb8099SNobutomo Nakano 		return (NULL);
380*5fbb8099SNobutomo Nakano 	}
381*5fbb8099SNobutomo Nakano 	hi->holesdata_sz = (size_t)ull;
382*5fbb8099SNobutomo Nakano 
383*5fbb8099SNobutomo Nakano 	/* read original(expanded) file size */
384*5fbb8099SNobutomo Nakano 	if (get_ull_tok(str, &ull) == NULL)
385*5fbb8099SNobutomo Nakano 		goto bad;
386*5fbb8099SNobutomo Nakano 	hi->orig_size = (off_t)ull;
387*5fbb8099SNobutomo Nakano 
388*5fbb8099SNobutomo Nakano 	/* sanity check */
389*5fbb8099SNobutomo Nakano 	if (hi->holesdata_sz > filesz ||
390*5fbb8099SNobutomo Nakano 	    hi->holesdata_sz <= MIN_HOLES_HDRSIZE) {
391*5fbb8099SNobutomo Nakano 		goto bad;
392*5fbb8099SNobutomo Nakano 	}
393*5fbb8099SNobutomo Nakano 	return (hi);
394*5fbb8099SNobutomo Nakano }
395*5fbb8099SNobutomo Nakano 
396*5fbb8099SNobutomo Nakano int
parse_holesdata(holes_info_t * hi,const char * str)397*5fbb8099SNobutomo Nakano parse_holesdata(holes_info_t *hi, const char *str)
398*5fbb8099SNobutomo Nakano {
399*5fbb8099SNobutomo Nakano 	holes_list_t	*hl, **hlp;
400*5fbb8099SNobutomo Nakano 	uint64_t	ull;
401*5fbb8099SNobutomo Nakano 	off_t		loff;
402*5fbb8099SNobutomo Nakano 
403*5fbb8099SNobutomo Nakano 	/* create hole list */
404*5fbb8099SNobutomo Nakano 	hlp = &hi->holes_list;
405*5fbb8099SNobutomo Nakano 	while (*str != '\0') {
406*5fbb8099SNobutomo Nakano 		hl = e_zalloc(E_EXIT, sizeof (holes_list_t));
407*5fbb8099SNobutomo Nakano 		/* link list */
408*5fbb8099SNobutomo Nakano 		hl->hl_next = NULL;
409*5fbb8099SNobutomo Nakano 		*hlp = hl;
410*5fbb8099SNobutomo Nakano 		hlp = &hl->hl_next;
411*5fbb8099SNobutomo Nakano 
412*5fbb8099SNobutomo Nakano 		/* read the string token for data */
413*5fbb8099SNobutomo Nakano 		if ((str = get_ull_tok(str, &ull)) == NULL)
414*5fbb8099SNobutomo Nakano 			goto bad;
415*5fbb8099SNobutomo Nakano 		hl->hl_data = (off_t)ull;
416*5fbb8099SNobutomo Nakano 
417*5fbb8099SNobutomo Nakano 		/* there must be single blank space in between */
418*5fbb8099SNobutomo Nakano 		if (*str != ' ')
419*5fbb8099SNobutomo Nakano 			goto bad;
420*5fbb8099SNobutomo Nakano 
421*5fbb8099SNobutomo Nakano 		/* read the string token for hole */
422*5fbb8099SNobutomo Nakano 		if ((str = get_ull_tok(str, &ull)) == NULL)
423*5fbb8099SNobutomo Nakano 			goto bad;
424*5fbb8099SNobutomo Nakano 		hl->hl_hole = (off_t)ull;
425*5fbb8099SNobutomo Nakano 	}
426*5fbb8099SNobutomo Nakano 
427*5fbb8099SNobutomo Nakano 	/* check to see if offset is in ascending order */
428*5fbb8099SNobutomo Nakano 	loff = -1;
429*5fbb8099SNobutomo Nakano 	for (hl = hi->holes_list; hl != NULL; hl = hl->hl_next) {
430*5fbb8099SNobutomo Nakano 		if (loff >= hl->hl_data)
431*5fbb8099SNobutomo Nakano 			goto bad;
432*5fbb8099SNobutomo Nakano 		loff = hl->hl_data;
433*5fbb8099SNobutomo Nakano 		/* data and hole can be equal */
434*5fbb8099SNobutomo Nakano 		if (loff > hl->hl_hole)
435*5fbb8099SNobutomo Nakano 			goto bad;
436*5fbb8099SNobutomo Nakano 		loff = hl->hl_hole;
437*5fbb8099SNobutomo Nakano 	}
438*5fbb8099SNobutomo Nakano 	/* The last hole offset should match original file size */
439*5fbb8099SNobutomo Nakano 	if (hi->orig_size != loff) {
440*5fbb8099SNobutomo Nakano bad:
441*5fbb8099SNobutomo Nakano 		free_holesdata(hi);
442*5fbb8099SNobutomo Nakano 		return (1);
443*5fbb8099SNobutomo Nakano 	}
444*5fbb8099SNobutomo Nakano 
445*5fbb8099SNobutomo Nakano 	hi->data_size = get_compressed_filesz(hi->holes_list);
446*5fbb8099SNobutomo Nakano 
447*5fbb8099SNobutomo Nakano 	return (0);
448*5fbb8099SNobutomo Nakano }
449*5fbb8099SNobutomo Nakano 
450*5fbb8099SNobutomo Nakano void
free_holes_info(holes_info_t * hi)451*5fbb8099SNobutomo Nakano free_holes_info(holes_info_t *hi)
452*5fbb8099SNobutomo Nakano {
453*5fbb8099SNobutomo Nakano 	free_holesdata(hi);
454*5fbb8099SNobutomo Nakano 	free(hi);
455*5fbb8099SNobutomo Nakano }
456