xref: /aosp_15_r20/external/erofs-utils/lib/tar.c (revision 33b1fccf6a0fada2c2875d400ed01119b7676ee5)
1*33b1fccfSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
2*33b1fccfSAndroid Build Coastguard Worker #include <unistd.h>
3*33b1fccfSAndroid Build Coastguard Worker #include <stdlib.h>
4*33b1fccfSAndroid Build Coastguard Worker #include <string.h>
5*33b1fccfSAndroid Build Coastguard Worker #include <sys/stat.h>
6*33b1fccfSAndroid Build Coastguard Worker #if defined(HAVE_ZLIB)
7*33b1fccfSAndroid Build Coastguard Worker #include <zlib.h>
8*33b1fccfSAndroid Build Coastguard Worker #endif
9*33b1fccfSAndroid Build Coastguard Worker #include "erofs/print.h"
10*33b1fccfSAndroid Build Coastguard Worker #include "erofs/cache.h"
11*33b1fccfSAndroid Build Coastguard Worker #include "erofs/diskbuf.h"
12*33b1fccfSAndroid Build Coastguard Worker #include "erofs/inode.h"
13*33b1fccfSAndroid Build Coastguard Worker #include "erofs/list.h"
14*33b1fccfSAndroid Build Coastguard Worker #include "erofs/tar.h"
15*33b1fccfSAndroid Build Coastguard Worker #include "erofs/xattr.h"
16*33b1fccfSAndroid Build Coastguard Worker #include "erofs/blobchunk.h"
17*33b1fccfSAndroid Build Coastguard Worker #include "erofs/rebuild.h"
18*33b1fccfSAndroid Build Coastguard Worker 
19*33b1fccfSAndroid Build Coastguard Worker /* This file is a tape/volume header.  Ignore it on extraction.  */
20*33b1fccfSAndroid Build Coastguard Worker #define GNUTYPE_VOLHDR 'V'
21*33b1fccfSAndroid Build Coastguard Worker 
22*33b1fccfSAndroid Build Coastguard Worker struct tar_header {
23*33b1fccfSAndroid Build Coastguard Worker 	char name[100];		/*   0-99 */
24*33b1fccfSAndroid Build Coastguard Worker 	char mode[8];		/* 100-107 */
25*33b1fccfSAndroid Build Coastguard Worker 	char uid[8];		/* 108-115 */
26*33b1fccfSAndroid Build Coastguard Worker 	char gid[8];		/* 116-123 */
27*33b1fccfSAndroid Build Coastguard Worker 	char size[12];		/* 124-135 */
28*33b1fccfSAndroid Build Coastguard Worker 	char mtime[12];		/* 136-147 */
29*33b1fccfSAndroid Build Coastguard Worker 	char chksum[8];		/* 148-155 */
30*33b1fccfSAndroid Build Coastguard Worker 	char typeflag;		/* 156-156 */
31*33b1fccfSAndroid Build Coastguard Worker 	char linkname[100];	/* 157-256 */
32*33b1fccfSAndroid Build Coastguard Worker 	char magic[6];		/* 257-262 */
33*33b1fccfSAndroid Build Coastguard Worker 	char version[2];	/* 263-264 */
34*33b1fccfSAndroid Build Coastguard Worker 	char uname[32];		/* 265-296 */
35*33b1fccfSAndroid Build Coastguard Worker 	char gname[32];		/* 297-328 */
36*33b1fccfSAndroid Build Coastguard Worker 	char devmajor[8];	/* 329-336 */
37*33b1fccfSAndroid Build Coastguard Worker 	char devminor[8];	/* 337-344 */
38*33b1fccfSAndroid Build Coastguard Worker 	char prefix[155];	/* 345-499 */
39*33b1fccfSAndroid Build Coastguard Worker 	char padding[12];	/* 500-512 (pad to exactly the 512 byte) */
40*33b1fccfSAndroid Build Coastguard Worker };
41*33b1fccfSAndroid Build Coastguard Worker 
erofs_iostream_close(struct erofs_iostream * ios)42*33b1fccfSAndroid Build Coastguard Worker void erofs_iostream_close(struct erofs_iostream *ios)
43*33b1fccfSAndroid Build Coastguard Worker {
44*33b1fccfSAndroid Build Coastguard Worker 	free(ios->buffer);
45*33b1fccfSAndroid Build Coastguard Worker 	if (ios->decoder == EROFS_IOS_DECODER_GZIP) {
46*33b1fccfSAndroid Build Coastguard Worker #if defined(HAVE_ZLIB)
47*33b1fccfSAndroid Build Coastguard Worker 		gzclose(ios->handler);
48*33b1fccfSAndroid Build Coastguard Worker #endif
49*33b1fccfSAndroid Build Coastguard Worker 		return;
50*33b1fccfSAndroid Build Coastguard Worker 	} else if (ios->decoder == EROFS_IOS_DECODER_LIBLZMA) {
51*33b1fccfSAndroid Build Coastguard Worker #if defined(HAVE_LIBLZMA)
52*33b1fccfSAndroid Build Coastguard Worker 		lzma_end(&ios->lzma->strm);
53*33b1fccfSAndroid Build Coastguard Worker 		close(ios->lzma->fd);
54*33b1fccfSAndroid Build Coastguard Worker 		free(ios->lzma);
55*33b1fccfSAndroid Build Coastguard Worker #endif
56*33b1fccfSAndroid Build Coastguard Worker 		return;
57*33b1fccfSAndroid Build Coastguard Worker 	}
58*33b1fccfSAndroid Build Coastguard Worker 	close(ios->vf.fd);
59*33b1fccfSAndroid Build Coastguard Worker }
60*33b1fccfSAndroid Build Coastguard Worker 
erofs_iostream_open(struct erofs_iostream * ios,int fd,int decoder)61*33b1fccfSAndroid Build Coastguard Worker int erofs_iostream_open(struct erofs_iostream *ios, int fd, int decoder)
62*33b1fccfSAndroid Build Coastguard Worker {
63*33b1fccfSAndroid Build Coastguard Worker 	s64 fsz;
64*33b1fccfSAndroid Build Coastguard Worker 
65*33b1fccfSAndroid Build Coastguard Worker 	ios->feof = false;
66*33b1fccfSAndroid Build Coastguard Worker 	ios->tail = ios->head = 0;
67*33b1fccfSAndroid Build Coastguard Worker 	ios->decoder = decoder;
68*33b1fccfSAndroid Build Coastguard Worker 	ios->dumpfd = -1;
69*33b1fccfSAndroid Build Coastguard Worker 	if (decoder == EROFS_IOS_DECODER_GZIP) {
70*33b1fccfSAndroid Build Coastguard Worker #if defined(HAVE_ZLIB)
71*33b1fccfSAndroid Build Coastguard Worker 		ios->handler = gzdopen(fd, "r");
72*33b1fccfSAndroid Build Coastguard Worker 		if (!ios->handler)
73*33b1fccfSAndroid Build Coastguard Worker 			return -ENOMEM;
74*33b1fccfSAndroid Build Coastguard Worker 		ios->sz = fsz = 0;
75*33b1fccfSAndroid Build Coastguard Worker 		ios->bufsize = 32768;
76*33b1fccfSAndroid Build Coastguard Worker #else
77*33b1fccfSAndroid Build Coastguard Worker 		return -EOPNOTSUPP;
78*33b1fccfSAndroid Build Coastguard Worker #endif
79*33b1fccfSAndroid Build Coastguard Worker 	} else if (decoder == EROFS_IOS_DECODER_LIBLZMA) {
80*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LIBLZMA
81*33b1fccfSAndroid Build Coastguard Worker 		lzma_ret ret;
82*33b1fccfSAndroid Build Coastguard Worker 
83*33b1fccfSAndroid Build Coastguard Worker 		ios->lzma = malloc(sizeof(*ios->lzma));
84*33b1fccfSAndroid Build Coastguard Worker 		if (!ios->lzma)
85*33b1fccfSAndroid Build Coastguard Worker 			return -ENOMEM;
86*33b1fccfSAndroid Build Coastguard Worker 		ios->lzma->fd = fd;
87*33b1fccfSAndroid Build Coastguard Worker 		ios->lzma->strm = (lzma_stream)LZMA_STREAM_INIT;
88*33b1fccfSAndroid Build Coastguard Worker 		ret = lzma_auto_decoder(&ios->lzma->strm,
89*33b1fccfSAndroid Build Coastguard Worker 					UINT64_MAX, LZMA_CONCATENATED);
90*33b1fccfSAndroid Build Coastguard Worker 		if (ret != LZMA_OK)
91*33b1fccfSAndroid Build Coastguard Worker 			return -EFAULT;
92*33b1fccfSAndroid Build Coastguard Worker 		ios->sz = fsz = 0;
93*33b1fccfSAndroid Build Coastguard Worker 		ios->bufsize = 32768;
94*33b1fccfSAndroid Build Coastguard Worker #else
95*33b1fccfSAndroid Build Coastguard Worker 		return -EOPNOTSUPP;
96*33b1fccfSAndroid Build Coastguard Worker #endif
97*33b1fccfSAndroid Build Coastguard Worker 	} else {
98*33b1fccfSAndroid Build Coastguard Worker 		ios->vf.fd = fd;
99*33b1fccfSAndroid Build Coastguard Worker 		fsz = lseek(fd, 0, SEEK_END);
100*33b1fccfSAndroid Build Coastguard Worker 		if (fsz <= 0) {
101*33b1fccfSAndroid Build Coastguard Worker 			ios->feof = !fsz;
102*33b1fccfSAndroid Build Coastguard Worker 			ios->sz = 0;
103*33b1fccfSAndroid Build Coastguard Worker 		} else {
104*33b1fccfSAndroid Build Coastguard Worker 			ios->sz = fsz;
105*33b1fccfSAndroid Build Coastguard Worker 			if (lseek(fd, 0, SEEK_SET))
106*33b1fccfSAndroid Build Coastguard Worker 				return -EIO;
107*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_POSIX_FADVISE
108*33b1fccfSAndroid Build Coastguard Worker 			if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL))
109*33b1fccfSAndroid Build Coastguard Worker 				erofs_warn("failed to fadvise: %s, ignored.",
110*33b1fccfSAndroid Build Coastguard Worker 					   erofs_strerror(-errno));
111*33b1fccfSAndroid Build Coastguard Worker #endif
112*33b1fccfSAndroid Build Coastguard Worker 		}
113*33b1fccfSAndroid Build Coastguard Worker 		ios->bufsize = 16384;
114*33b1fccfSAndroid Build Coastguard Worker 	}
115*33b1fccfSAndroid Build Coastguard Worker 
116*33b1fccfSAndroid Build Coastguard Worker 	do {
117*33b1fccfSAndroid Build Coastguard Worker 		ios->buffer = malloc(ios->bufsize);
118*33b1fccfSAndroid Build Coastguard Worker 		if (ios->buffer)
119*33b1fccfSAndroid Build Coastguard Worker 			break;
120*33b1fccfSAndroid Build Coastguard Worker 		ios->bufsize >>= 1;
121*33b1fccfSAndroid Build Coastguard Worker 	} while (ios->bufsize >= 1024);
122*33b1fccfSAndroid Build Coastguard Worker 
123*33b1fccfSAndroid Build Coastguard Worker 	if (!ios->buffer)
124*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
125*33b1fccfSAndroid Build Coastguard Worker 	return 0;
126*33b1fccfSAndroid Build Coastguard Worker }
127*33b1fccfSAndroid Build Coastguard Worker 
erofs_iostream_read(struct erofs_iostream * ios,void ** buf,u64 bytes)128*33b1fccfSAndroid Build Coastguard Worker int erofs_iostream_read(struct erofs_iostream *ios, void **buf, u64 bytes)
129*33b1fccfSAndroid Build Coastguard Worker {
130*33b1fccfSAndroid Build Coastguard Worker 	unsigned int rabytes = ios->tail - ios->head;
131*33b1fccfSAndroid Build Coastguard Worker 	int ret;
132*33b1fccfSAndroid Build Coastguard Worker 
133*33b1fccfSAndroid Build Coastguard Worker 	if (rabytes >= bytes) {
134*33b1fccfSAndroid Build Coastguard Worker 		*buf = ios->buffer + ios->head;
135*33b1fccfSAndroid Build Coastguard Worker 		ios->head += bytes;
136*33b1fccfSAndroid Build Coastguard Worker 		return bytes;
137*33b1fccfSAndroid Build Coastguard Worker 	}
138*33b1fccfSAndroid Build Coastguard Worker 
139*33b1fccfSAndroid Build Coastguard Worker 	if (ios->head) {
140*33b1fccfSAndroid Build Coastguard Worker 		memmove(ios->buffer, ios->buffer + ios->head, rabytes);
141*33b1fccfSAndroid Build Coastguard Worker 		ios->head = 0;
142*33b1fccfSAndroid Build Coastguard Worker 		ios->tail = rabytes;
143*33b1fccfSAndroid Build Coastguard Worker 	}
144*33b1fccfSAndroid Build Coastguard Worker 
145*33b1fccfSAndroid Build Coastguard Worker 	if (!ios->feof) {
146*33b1fccfSAndroid Build Coastguard Worker 		if (ios->decoder == EROFS_IOS_DECODER_GZIP) {
147*33b1fccfSAndroid Build Coastguard Worker #if defined(HAVE_ZLIB)
148*33b1fccfSAndroid Build Coastguard Worker 			ret = gzread(ios->handler, ios->buffer + rabytes,
149*33b1fccfSAndroid Build Coastguard Worker 				     ios->bufsize - rabytes);
150*33b1fccfSAndroid Build Coastguard Worker 			if (!ret) {
151*33b1fccfSAndroid Build Coastguard Worker 				int errnum;
152*33b1fccfSAndroid Build Coastguard Worker 				const char *errstr;
153*33b1fccfSAndroid Build Coastguard Worker 
154*33b1fccfSAndroid Build Coastguard Worker 				errstr = gzerror(ios->handler, &errnum);
155*33b1fccfSAndroid Build Coastguard Worker 				if (errnum != Z_STREAM_END) {
156*33b1fccfSAndroid Build Coastguard Worker 					erofs_err("failed to gzread: %s", errstr);
157*33b1fccfSAndroid Build Coastguard Worker 					return -EIO;
158*33b1fccfSAndroid Build Coastguard Worker 				}
159*33b1fccfSAndroid Build Coastguard Worker 				ios->feof = true;
160*33b1fccfSAndroid Build Coastguard Worker 			}
161*33b1fccfSAndroid Build Coastguard Worker 			ios->tail += ret;
162*33b1fccfSAndroid Build Coastguard Worker #else
163*33b1fccfSAndroid Build Coastguard Worker 			return -EOPNOTSUPP;
164*33b1fccfSAndroid Build Coastguard Worker #endif
165*33b1fccfSAndroid Build Coastguard Worker 		} else if (ios->decoder == EROFS_IOS_DECODER_LIBLZMA) {
166*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LIBLZMA
167*33b1fccfSAndroid Build Coastguard Worker 			struct erofs_iostream_liblzma *lzma = ios->lzma;
168*33b1fccfSAndroid Build Coastguard Worker 			lzma_action action = LZMA_RUN;
169*33b1fccfSAndroid Build Coastguard Worker 			lzma_ret ret2;
170*33b1fccfSAndroid Build Coastguard Worker 
171*33b1fccfSAndroid Build Coastguard Worker 			if (!lzma->strm.avail_in) {
172*33b1fccfSAndroid Build Coastguard Worker 				lzma->strm.next_in = lzma->inbuf;
173*33b1fccfSAndroid Build Coastguard Worker 				ret = read(lzma->fd, lzma->inbuf,
174*33b1fccfSAndroid Build Coastguard Worker 					   sizeof(lzma->inbuf));
175*33b1fccfSAndroid Build Coastguard Worker 				if (ret < 0)
176*33b1fccfSAndroid Build Coastguard Worker 					return -errno;
177*33b1fccfSAndroid Build Coastguard Worker 				lzma->strm.avail_in = ret;
178*33b1fccfSAndroid Build Coastguard Worker 				if (ret < sizeof(lzma->inbuf))
179*33b1fccfSAndroid Build Coastguard Worker 					action = LZMA_FINISH;
180*33b1fccfSAndroid Build Coastguard Worker 			}
181*33b1fccfSAndroid Build Coastguard Worker 			lzma->strm.next_out = (u8 *)ios->buffer + rabytes;
182*33b1fccfSAndroid Build Coastguard Worker 			lzma->strm.avail_out = ios->bufsize - rabytes;
183*33b1fccfSAndroid Build Coastguard Worker 
184*33b1fccfSAndroid Build Coastguard Worker 			ret2 = lzma_code(&lzma->strm, action);
185*33b1fccfSAndroid Build Coastguard Worker 			if (ret2 != LZMA_OK) {
186*33b1fccfSAndroid Build Coastguard Worker 				if (ret2 == LZMA_STREAM_END)
187*33b1fccfSAndroid Build Coastguard Worker 					ios->feof = true;
188*33b1fccfSAndroid Build Coastguard Worker 				else
189*33b1fccfSAndroid Build Coastguard Worker 					return -EIO;
190*33b1fccfSAndroid Build Coastguard Worker 			}
191*33b1fccfSAndroid Build Coastguard Worker 			ret = ios->bufsize - rabytes - lzma->strm.avail_out;
192*33b1fccfSAndroid Build Coastguard Worker 			ios->tail += ret;
193*33b1fccfSAndroid Build Coastguard Worker #else
194*33b1fccfSAndroid Build Coastguard Worker 			return -EOPNOTSUPP;
195*33b1fccfSAndroid Build Coastguard Worker #endif
196*33b1fccfSAndroid Build Coastguard Worker 		} else {
197*33b1fccfSAndroid Build Coastguard Worker 			ret = erofs_io_read(&ios->vf, ios->buffer + rabytes,
198*33b1fccfSAndroid Build Coastguard Worker 					    ios->bufsize - rabytes);
199*33b1fccfSAndroid Build Coastguard Worker 			if (ret < 0)
200*33b1fccfSAndroid Build Coastguard Worker 				return ret;
201*33b1fccfSAndroid Build Coastguard Worker 			ios->tail += ret;
202*33b1fccfSAndroid Build Coastguard Worker 			if (ret < ios->bufsize - rabytes)
203*33b1fccfSAndroid Build Coastguard Worker 				ios->feof = true;
204*33b1fccfSAndroid Build Coastguard Worker 		}
205*33b1fccfSAndroid Build Coastguard Worker 		if (__erofs_unlikely(ios->dumpfd >= 0))
206*33b1fccfSAndroid Build Coastguard Worker 			if (write(ios->dumpfd, ios->buffer + rabytes, ret) < ret)
207*33b1fccfSAndroid Build Coastguard Worker 				erofs_err("failed to dump %d bytes of the raw stream: %s",
208*33b1fccfSAndroid Build Coastguard Worker 					  ret, erofs_strerror(-errno));
209*33b1fccfSAndroid Build Coastguard Worker 	}
210*33b1fccfSAndroid Build Coastguard Worker 	*buf = ios->buffer;
211*33b1fccfSAndroid Build Coastguard Worker 	ret = min_t(int, ios->tail, min_t(u64, bytes, INT_MAX));
212*33b1fccfSAndroid Build Coastguard Worker 	ios->head = ret;
213*33b1fccfSAndroid Build Coastguard Worker 	return ret;
214*33b1fccfSAndroid Build Coastguard Worker }
215*33b1fccfSAndroid Build Coastguard Worker 
erofs_iostream_bread(struct erofs_iostream * ios,void * buf,u64 bytes)216*33b1fccfSAndroid Build Coastguard Worker int erofs_iostream_bread(struct erofs_iostream *ios, void *buf, u64 bytes)
217*33b1fccfSAndroid Build Coastguard Worker {
218*33b1fccfSAndroid Build Coastguard Worker 	u64 rem = bytes;
219*33b1fccfSAndroid Build Coastguard Worker 	void *src;
220*33b1fccfSAndroid Build Coastguard Worker 	int ret;
221*33b1fccfSAndroid Build Coastguard Worker 
222*33b1fccfSAndroid Build Coastguard Worker 	do {
223*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_iostream_read(ios, &src, rem);
224*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 0)
225*33b1fccfSAndroid Build Coastguard Worker 			return ret;
226*33b1fccfSAndroid Build Coastguard Worker 		memcpy(buf, src, ret);
227*33b1fccfSAndroid Build Coastguard Worker 		rem -= ret;
228*33b1fccfSAndroid Build Coastguard Worker 	} while (rem && ret);
229*33b1fccfSAndroid Build Coastguard Worker 
230*33b1fccfSAndroid Build Coastguard Worker 	return bytes - rem;
231*33b1fccfSAndroid Build Coastguard Worker }
232*33b1fccfSAndroid Build Coastguard Worker 
erofs_iostream_lskip(struct erofs_iostream * ios,u64 sz)233*33b1fccfSAndroid Build Coastguard Worker int erofs_iostream_lskip(struct erofs_iostream *ios, u64 sz)
234*33b1fccfSAndroid Build Coastguard Worker {
235*33b1fccfSAndroid Build Coastguard Worker 	unsigned int rabytes = ios->tail - ios->head;
236*33b1fccfSAndroid Build Coastguard Worker 	int ret;
237*33b1fccfSAndroid Build Coastguard Worker 	void *dummy;
238*33b1fccfSAndroid Build Coastguard Worker 
239*33b1fccfSAndroid Build Coastguard Worker 	if (rabytes >= sz) {
240*33b1fccfSAndroid Build Coastguard Worker 		ios->head += sz;
241*33b1fccfSAndroid Build Coastguard Worker 		return 0;
242*33b1fccfSAndroid Build Coastguard Worker 	}
243*33b1fccfSAndroid Build Coastguard Worker 
244*33b1fccfSAndroid Build Coastguard Worker 	sz -= rabytes;
245*33b1fccfSAndroid Build Coastguard Worker 	ios->head = ios->tail = 0;
246*33b1fccfSAndroid Build Coastguard Worker 	if (ios->feof)
247*33b1fccfSAndroid Build Coastguard Worker 		return sz;
248*33b1fccfSAndroid Build Coastguard Worker 
249*33b1fccfSAndroid Build Coastguard Worker 	if (ios->sz && __erofs_likely(ios->dumpfd < 0)) {
250*33b1fccfSAndroid Build Coastguard Worker 		s64 cur = erofs_io_lseek(&ios->vf, sz, SEEK_CUR);
251*33b1fccfSAndroid Build Coastguard Worker 
252*33b1fccfSAndroid Build Coastguard Worker 		if (cur > ios->sz)
253*33b1fccfSAndroid Build Coastguard Worker 			return cur - ios->sz;
254*33b1fccfSAndroid Build Coastguard Worker 		return 0;
255*33b1fccfSAndroid Build Coastguard Worker 	}
256*33b1fccfSAndroid Build Coastguard Worker 
257*33b1fccfSAndroid Build Coastguard Worker 	do {
258*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_iostream_read(ios, &dummy, sz);
259*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 0)
260*33b1fccfSAndroid Build Coastguard Worker 			return ret;
261*33b1fccfSAndroid Build Coastguard Worker 		sz -= ret;
262*33b1fccfSAndroid Build Coastguard Worker 	} while (!(ios->feof || !ret || !sz));
263*33b1fccfSAndroid Build Coastguard Worker 
264*33b1fccfSAndroid Build Coastguard Worker 	return sz;
265*33b1fccfSAndroid Build Coastguard Worker }
266*33b1fccfSAndroid Build Coastguard Worker 
tarerofs_otoi(const char * ptr,int len)267*33b1fccfSAndroid Build Coastguard Worker static long long tarerofs_otoi(const char *ptr, int len)
268*33b1fccfSAndroid Build Coastguard Worker {
269*33b1fccfSAndroid Build Coastguard Worker 	char inp[32];
270*33b1fccfSAndroid Build Coastguard Worker 	char *endp = inp;
271*33b1fccfSAndroid Build Coastguard Worker 	long long val;
272*33b1fccfSAndroid Build Coastguard Worker 
273*33b1fccfSAndroid Build Coastguard Worker 	memcpy(inp, ptr, len);
274*33b1fccfSAndroid Build Coastguard Worker 	inp[len] = '\0';
275*33b1fccfSAndroid Build Coastguard Worker 
276*33b1fccfSAndroid Build Coastguard Worker 	errno = 0;
277*33b1fccfSAndroid Build Coastguard Worker 	val = strtol(ptr, &endp, 8);
278*33b1fccfSAndroid Build Coastguard Worker 	if ((!val && endp == inp) |
279*33b1fccfSAndroid Build Coastguard Worker 	     (*endp && *endp != ' '))
280*33b1fccfSAndroid Build Coastguard Worker 		errno = EINVAL;
281*33b1fccfSAndroid Build Coastguard Worker 	return val;
282*33b1fccfSAndroid Build Coastguard Worker }
283*33b1fccfSAndroid Build Coastguard Worker 
tarerofs_parsenum(const char * ptr,int len)284*33b1fccfSAndroid Build Coastguard Worker static long long tarerofs_parsenum(const char *ptr, int len)
285*33b1fccfSAndroid Build Coastguard Worker {
286*33b1fccfSAndroid Build Coastguard Worker 	/*
287*33b1fccfSAndroid Build Coastguard Worker 	 * For fields containing numbers or timestamps that are out of range
288*33b1fccfSAndroid Build Coastguard Worker 	 * for the basic format, the GNU format uses a base-256 representation
289*33b1fccfSAndroid Build Coastguard Worker 	 * instead of an ASCII octal number.
290*33b1fccfSAndroid Build Coastguard Worker 	 */
291*33b1fccfSAndroid Build Coastguard Worker 	if (*(char *)ptr == '\200') {
292*33b1fccfSAndroid Build Coastguard Worker 		long long res = 0;
293*33b1fccfSAndroid Build Coastguard Worker 
294*33b1fccfSAndroid Build Coastguard Worker 		while (--len)
295*33b1fccfSAndroid Build Coastguard Worker 			res = (res << 8) + (u8)*(++ptr);
296*33b1fccfSAndroid Build Coastguard Worker 		return res;
297*33b1fccfSAndroid Build Coastguard Worker 	}
298*33b1fccfSAndroid Build Coastguard Worker 	return tarerofs_otoi(ptr, len);
299*33b1fccfSAndroid Build Coastguard Worker }
300*33b1fccfSAndroid Build Coastguard Worker 
301*33b1fccfSAndroid Build Coastguard Worker struct tarerofs_xattr_item {
302*33b1fccfSAndroid Build Coastguard Worker 	struct list_head list;
303*33b1fccfSAndroid Build Coastguard Worker 	char *kv;
304*33b1fccfSAndroid Build Coastguard Worker 	unsigned int len, namelen;
305*33b1fccfSAndroid Build Coastguard Worker };
306*33b1fccfSAndroid Build Coastguard Worker 
tarerofs_insert_xattr(struct list_head * xattrs,char * kv,int namelen,int len,bool skip)307*33b1fccfSAndroid Build Coastguard Worker int tarerofs_insert_xattr(struct list_head *xattrs,
308*33b1fccfSAndroid Build Coastguard Worker 			  char *kv, int namelen, int len, bool skip)
309*33b1fccfSAndroid Build Coastguard Worker {
310*33b1fccfSAndroid Build Coastguard Worker 	struct tarerofs_xattr_item *item;
311*33b1fccfSAndroid Build Coastguard Worker 	char *nv;
312*33b1fccfSAndroid Build Coastguard Worker 
313*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(namelen >= len);
314*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry(item, xattrs, list) {
315*33b1fccfSAndroid Build Coastguard Worker 		if (!strncmp(item->kv, kv, namelen + 1)) {
316*33b1fccfSAndroid Build Coastguard Worker 			if (skip)
317*33b1fccfSAndroid Build Coastguard Worker 				return 0;
318*33b1fccfSAndroid Build Coastguard Worker 			goto found;
319*33b1fccfSAndroid Build Coastguard Worker 		}
320*33b1fccfSAndroid Build Coastguard Worker 	}
321*33b1fccfSAndroid Build Coastguard Worker 
322*33b1fccfSAndroid Build Coastguard Worker 	item = malloc(sizeof(*item));
323*33b1fccfSAndroid Build Coastguard Worker 	if (!item)
324*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
325*33b1fccfSAndroid Build Coastguard Worker 	item->kv = NULL;
326*33b1fccfSAndroid Build Coastguard Worker 	item->namelen = namelen;
327*33b1fccfSAndroid Build Coastguard Worker 	namelen = 0;
328*33b1fccfSAndroid Build Coastguard Worker 	list_add_tail(&item->list, xattrs);
329*33b1fccfSAndroid Build Coastguard Worker found:
330*33b1fccfSAndroid Build Coastguard Worker 	nv = realloc(item->kv, len);
331*33b1fccfSAndroid Build Coastguard Worker 	if (!nv)
332*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
333*33b1fccfSAndroid Build Coastguard Worker 	item->kv = nv;
334*33b1fccfSAndroid Build Coastguard Worker 	item->len = len;
335*33b1fccfSAndroid Build Coastguard Worker 	memcpy(nv + namelen, kv + namelen, len - namelen);
336*33b1fccfSAndroid Build Coastguard Worker 	return 0;
337*33b1fccfSAndroid Build Coastguard Worker }
338*33b1fccfSAndroid Build Coastguard Worker 
tarerofs_merge_xattrs(struct list_head * dst,struct list_head * src)339*33b1fccfSAndroid Build Coastguard Worker int tarerofs_merge_xattrs(struct list_head *dst, struct list_head *src)
340*33b1fccfSAndroid Build Coastguard Worker {
341*33b1fccfSAndroid Build Coastguard Worker 	struct tarerofs_xattr_item *item;
342*33b1fccfSAndroid Build Coastguard Worker 
343*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry(item, src, list) {
344*33b1fccfSAndroid Build Coastguard Worker 		int ret;
345*33b1fccfSAndroid Build Coastguard Worker 
346*33b1fccfSAndroid Build Coastguard Worker 		ret = tarerofs_insert_xattr(dst, item->kv, item->namelen,
347*33b1fccfSAndroid Build Coastguard Worker 					    item->len, true);
348*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
349*33b1fccfSAndroid Build Coastguard Worker 			return ret;
350*33b1fccfSAndroid Build Coastguard Worker 	}
351*33b1fccfSAndroid Build Coastguard Worker 	return 0;
352*33b1fccfSAndroid Build Coastguard Worker }
353*33b1fccfSAndroid Build Coastguard Worker 
tarerofs_remove_xattrs(struct list_head * xattrs)354*33b1fccfSAndroid Build Coastguard Worker void tarerofs_remove_xattrs(struct list_head *xattrs)
355*33b1fccfSAndroid Build Coastguard Worker {
356*33b1fccfSAndroid Build Coastguard Worker 	struct tarerofs_xattr_item *item, *n;
357*33b1fccfSAndroid Build Coastguard Worker 
358*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry_safe(item, n, xattrs, list) {
359*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(!item->kv);
360*33b1fccfSAndroid Build Coastguard Worker 		free(item->kv);
361*33b1fccfSAndroid Build Coastguard Worker 		list_del(&item->list);
362*33b1fccfSAndroid Build Coastguard Worker 		free(item);
363*33b1fccfSAndroid Build Coastguard Worker 	}
364*33b1fccfSAndroid Build Coastguard Worker }
365*33b1fccfSAndroid Build Coastguard Worker 
tarerofs_apply_xattrs(struct erofs_inode * inode,struct list_head * xattrs)366*33b1fccfSAndroid Build Coastguard Worker int tarerofs_apply_xattrs(struct erofs_inode *inode, struct list_head *xattrs)
367*33b1fccfSAndroid Build Coastguard Worker {
368*33b1fccfSAndroid Build Coastguard Worker 	struct tarerofs_xattr_item *item;
369*33b1fccfSAndroid Build Coastguard Worker 	int ret;
370*33b1fccfSAndroid Build Coastguard Worker 
371*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry(item, xattrs, list) {
372*33b1fccfSAndroid Build Coastguard Worker 		const char *v = item->kv + item->namelen + 1;
373*33b1fccfSAndroid Build Coastguard Worker 		unsigned int vsz = item->len - item->namelen - 1;
374*33b1fccfSAndroid Build Coastguard Worker 
375*33b1fccfSAndroid Build Coastguard Worker 		if (item->len <= item->namelen - 1) {
376*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(item->len < item->namelen - 1);
377*33b1fccfSAndroid Build Coastguard Worker 			continue;
378*33b1fccfSAndroid Build Coastguard Worker 		}
379*33b1fccfSAndroid Build Coastguard Worker 		item->kv[item->namelen] = '\0';
380*33b1fccfSAndroid Build Coastguard Worker 		erofs_dbg("Recording xattr(%s)=\"%s\" (of %u bytes) to file %s",
381*33b1fccfSAndroid Build Coastguard Worker 			  item->kv, v, vsz, inode->i_srcpath);
382*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_setxattr(inode, item->kv, v, vsz);
383*33b1fccfSAndroid Build Coastguard Worker 		if (ret == -ENODATA)
384*33b1fccfSAndroid Build Coastguard Worker 			erofs_err("Failed to set xattr(%s)=%s to file %s",
385*33b1fccfSAndroid Build Coastguard Worker 				  item->kv, v, inode->i_srcpath);
386*33b1fccfSAndroid Build Coastguard Worker 		else if (ret)
387*33b1fccfSAndroid Build Coastguard Worker 			return ret;
388*33b1fccfSAndroid Build Coastguard Worker 	}
389*33b1fccfSAndroid Build Coastguard Worker 	return 0;
390*33b1fccfSAndroid Build Coastguard Worker }
391*33b1fccfSAndroid Build Coastguard Worker 
392*33b1fccfSAndroid Build Coastguard Worker static const char lookup_table[65] =
393*33b1fccfSAndroid Build Coastguard Worker 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
394*33b1fccfSAndroid Build Coastguard Worker 
base64_decode(const char * src,int len,u8 * dst)395*33b1fccfSAndroid Build Coastguard Worker static int base64_decode(const char *src, int len, u8 *dst)
396*33b1fccfSAndroid Build Coastguard Worker {
397*33b1fccfSAndroid Build Coastguard Worker 	int i, bits = 0, ac = 0;
398*33b1fccfSAndroid Build Coastguard Worker 	const char *p;
399*33b1fccfSAndroid Build Coastguard Worker 	u8 *cp = dst;
400*33b1fccfSAndroid Build Coastguard Worker 
401*33b1fccfSAndroid Build Coastguard Worker 	if(!(len % 4)) {
402*33b1fccfSAndroid Build Coastguard Worker 		/* Check for and ignore any end padding */
403*33b1fccfSAndroid Build Coastguard Worker 		if (src[len - 2] == '=' && src[len - 1] == '=')
404*33b1fccfSAndroid Build Coastguard Worker 			len -= 2;
405*33b1fccfSAndroid Build Coastguard Worker 		else if (src[len - 1] == '=')
406*33b1fccfSAndroid Build Coastguard Worker 			--len;
407*33b1fccfSAndroid Build Coastguard Worker 	}
408*33b1fccfSAndroid Build Coastguard Worker 
409*33b1fccfSAndroid Build Coastguard Worker 	for (i = 0; i < len; i++) {
410*33b1fccfSAndroid Build Coastguard Worker 		p = strchr(lookup_table, src[i]);
411*33b1fccfSAndroid Build Coastguard Worker 		if (p == NULL || src[i] == 0)
412*33b1fccfSAndroid Build Coastguard Worker 			return -2;
413*33b1fccfSAndroid Build Coastguard Worker 		ac += (p - lookup_table) << bits;
414*33b1fccfSAndroid Build Coastguard Worker 		bits += 6;
415*33b1fccfSAndroid Build Coastguard Worker 		if (bits >= 8) {
416*33b1fccfSAndroid Build Coastguard Worker 			*cp++ = ac & 0xff;
417*33b1fccfSAndroid Build Coastguard Worker 			ac >>= 8;
418*33b1fccfSAndroid Build Coastguard Worker 			bits -= 8;
419*33b1fccfSAndroid Build Coastguard Worker 		}
420*33b1fccfSAndroid Build Coastguard Worker 	}
421*33b1fccfSAndroid Build Coastguard Worker 	if (ac)
422*33b1fccfSAndroid Build Coastguard Worker 		return -1;
423*33b1fccfSAndroid Build Coastguard Worker 	return cp - dst;
424*33b1fccfSAndroid Build Coastguard Worker }
425*33b1fccfSAndroid Build Coastguard Worker 
tarerofs_parse_pax_header(struct erofs_iostream * ios,struct erofs_pax_header * eh,u32 size)426*33b1fccfSAndroid Build Coastguard Worker int tarerofs_parse_pax_header(struct erofs_iostream *ios,
427*33b1fccfSAndroid Build Coastguard Worker 			      struct erofs_pax_header *eh, u32 size)
428*33b1fccfSAndroid Build Coastguard Worker {
429*33b1fccfSAndroid Build Coastguard Worker 	char *buf, *p;
430*33b1fccfSAndroid Build Coastguard Worker 	int ret;
431*33b1fccfSAndroid Build Coastguard Worker 
432*33b1fccfSAndroid Build Coastguard Worker 	buf = malloc(size);
433*33b1fccfSAndroid Build Coastguard Worker 	if (!buf)
434*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
435*33b1fccfSAndroid Build Coastguard Worker 	p = buf;
436*33b1fccfSAndroid Build Coastguard Worker 
437*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_iostream_bread(ios, buf, size);
438*33b1fccfSAndroid Build Coastguard Worker 	if (ret != size)
439*33b1fccfSAndroid Build Coastguard Worker 		goto out;
440*33b1fccfSAndroid Build Coastguard Worker 
441*33b1fccfSAndroid Build Coastguard Worker 	while (p < buf + size) {
442*33b1fccfSAndroid Build Coastguard Worker 		char *kv, *value;
443*33b1fccfSAndroid Build Coastguard Worker 		int len, n;
444*33b1fccfSAndroid Build Coastguard Worker 		/* extended records are of the format: "LEN NAME=VALUE\n" */
445*33b1fccfSAndroid Build Coastguard Worker 		ret = sscanf(p, "%d %n", &len, &n);
446*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 1 || len <= n || len > buf + size - p) {
447*33b1fccfSAndroid Build Coastguard Worker 			ret = -EIO;
448*33b1fccfSAndroid Build Coastguard Worker 			goto out;
449*33b1fccfSAndroid Build Coastguard Worker 		}
450*33b1fccfSAndroid Build Coastguard Worker 		kv = p + n;
451*33b1fccfSAndroid Build Coastguard Worker 		p += len;
452*33b1fccfSAndroid Build Coastguard Worker 		len -= n;
453*33b1fccfSAndroid Build Coastguard Worker 
454*33b1fccfSAndroid Build Coastguard Worker 		if (p[-1] != '\n') {
455*33b1fccfSAndroid Build Coastguard Worker 			ret = -EIO;
456*33b1fccfSAndroid Build Coastguard Worker 			goto out;
457*33b1fccfSAndroid Build Coastguard Worker 		}
458*33b1fccfSAndroid Build Coastguard Worker 		p[-1] = '\0';
459*33b1fccfSAndroid Build Coastguard Worker 
460*33b1fccfSAndroid Build Coastguard Worker 		value = memchr(kv, '=', p - kv);
461*33b1fccfSAndroid Build Coastguard Worker 		if (!value) {
462*33b1fccfSAndroid Build Coastguard Worker 			ret = -EIO;
463*33b1fccfSAndroid Build Coastguard Worker 			goto out;
464*33b1fccfSAndroid Build Coastguard Worker 		} else {
465*33b1fccfSAndroid Build Coastguard Worker 			long long lln;
466*33b1fccfSAndroid Build Coastguard Worker 
467*33b1fccfSAndroid Build Coastguard Worker 			value++;
468*33b1fccfSAndroid Build Coastguard Worker 
469*33b1fccfSAndroid Build Coastguard Worker 			if (!strncmp(kv, "path=", sizeof("path=") - 1)) {
470*33b1fccfSAndroid Build Coastguard Worker 				int j = p - 1 - value;
471*33b1fccfSAndroid Build Coastguard Worker 				free(eh->path);
472*33b1fccfSAndroid Build Coastguard Worker 				eh->path = strdup(value);
473*33b1fccfSAndroid Build Coastguard Worker 				while (eh->path[j - 1] == '/')
474*33b1fccfSAndroid Build Coastguard Worker 					eh->path[--j] = '\0';
475*33b1fccfSAndroid Build Coastguard Worker 			} else if (!strncmp(kv, "linkpath=",
476*33b1fccfSAndroid Build Coastguard Worker 					sizeof("linkpath=") - 1)) {
477*33b1fccfSAndroid Build Coastguard Worker 				free(eh->link);
478*33b1fccfSAndroid Build Coastguard Worker 				eh->link = strdup(value);
479*33b1fccfSAndroid Build Coastguard Worker 			} else if (!strncmp(kv, "mtime=",
480*33b1fccfSAndroid Build Coastguard Worker 					sizeof("mtime=") - 1)) {
481*33b1fccfSAndroid Build Coastguard Worker 				ret = sscanf(value, "%lld %n", &lln, &n);
482*33b1fccfSAndroid Build Coastguard Worker 				if(ret < 1) {
483*33b1fccfSAndroid Build Coastguard Worker 					ret = -EIO;
484*33b1fccfSAndroid Build Coastguard Worker 					goto out;
485*33b1fccfSAndroid Build Coastguard Worker 				}
486*33b1fccfSAndroid Build Coastguard Worker 				eh->st.st_mtime = lln;
487*33b1fccfSAndroid Build Coastguard Worker 				if (value[n] == '.') {
488*33b1fccfSAndroid Build Coastguard Worker 					ret = sscanf(value + n + 1, "%d", &n);
489*33b1fccfSAndroid Build Coastguard Worker 					if (ret < 1) {
490*33b1fccfSAndroid Build Coastguard Worker 						ret = -EIO;
491*33b1fccfSAndroid Build Coastguard Worker 						goto out;
492*33b1fccfSAndroid Build Coastguard Worker 					}
493*33b1fccfSAndroid Build Coastguard Worker 					ST_MTIM_NSEC_SET(&eh->st, n);
494*33b1fccfSAndroid Build Coastguard Worker 				} else {
495*33b1fccfSAndroid Build Coastguard Worker 					ST_MTIM_NSEC_SET(&eh->st, 0);
496*33b1fccfSAndroid Build Coastguard Worker 				}
497*33b1fccfSAndroid Build Coastguard Worker 				eh->use_mtime = true;
498*33b1fccfSAndroid Build Coastguard Worker 			} else if (!strncmp(kv, "size=",
499*33b1fccfSAndroid Build Coastguard Worker 					sizeof("size=") - 1)) {
500*33b1fccfSAndroid Build Coastguard Worker 				ret = sscanf(value, "%lld %n", &lln, &n);
501*33b1fccfSAndroid Build Coastguard Worker 				if(ret < 1 || value[n] != '\0') {
502*33b1fccfSAndroid Build Coastguard Worker 					ret = -EIO;
503*33b1fccfSAndroid Build Coastguard Worker 					goto out;
504*33b1fccfSAndroid Build Coastguard Worker 				}
505*33b1fccfSAndroid Build Coastguard Worker 				eh->st.st_size = lln;
506*33b1fccfSAndroid Build Coastguard Worker 				eh->use_size = true;
507*33b1fccfSAndroid Build Coastguard Worker 			} else if (!strncmp(kv, "uid=", sizeof("uid=") - 1)) {
508*33b1fccfSAndroid Build Coastguard Worker 				ret = sscanf(value, "%lld %n", &lln, &n);
509*33b1fccfSAndroid Build Coastguard Worker 				if(ret < 1 || value[n] != '\0') {
510*33b1fccfSAndroid Build Coastguard Worker 					ret = -EIO;
511*33b1fccfSAndroid Build Coastguard Worker 					goto out;
512*33b1fccfSAndroid Build Coastguard Worker 				}
513*33b1fccfSAndroid Build Coastguard Worker 				eh->st.st_uid = lln;
514*33b1fccfSAndroid Build Coastguard Worker 				eh->use_uid = true;
515*33b1fccfSAndroid Build Coastguard Worker 			} else if (!strncmp(kv, "gid=", sizeof("gid=") - 1)) {
516*33b1fccfSAndroid Build Coastguard Worker 				ret = sscanf(value, "%lld %n", &lln, &n);
517*33b1fccfSAndroid Build Coastguard Worker 				if(ret < 1 || value[n] != '\0') {
518*33b1fccfSAndroid Build Coastguard Worker 					ret = -EIO;
519*33b1fccfSAndroid Build Coastguard Worker 					goto out;
520*33b1fccfSAndroid Build Coastguard Worker 				}
521*33b1fccfSAndroid Build Coastguard Worker 				eh->st.st_gid = lln;
522*33b1fccfSAndroid Build Coastguard Worker 				eh->use_gid = true;
523*33b1fccfSAndroid Build Coastguard Worker 			} else if (!strncmp(kv, "SCHILY.xattr.",
524*33b1fccfSAndroid Build Coastguard Worker 				   sizeof("SCHILY.xattr.") - 1)) {
525*33b1fccfSAndroid Build Coastguard Worker 				char *key = kv + sizeof("SCHILY.xattr.") - 1;
526*33b1fccfSAndroid Build Coastguard Worker 
527*33b1fccfSAndroid Build Coastguard Worker 				--len; /* p[-1] == '\0' */
528*33b1fccfSAndroid Build Coastguard Worker 				ret = tarerofs_insert_xattr(&eh->xattrs, key,
529*33b1fccfSAndroid Build Coastguard Worker 						value - key - 1,
530*33b1fccfSAndroid Build Coastguard Worker 						len - (key - kv), false);
531*33b1fccfSAndroid Build Coastguard Worker 				if (ret)
532*33b1fccfSAndroid Build Coastguard Worker 					goto out;
533*33b1fccfSAndroid Build Coastguard Worker 			} else if (!strncmp(kv, "LIBARCHIVE.xattr.",
534*33b1fccfSAndroid Build Coastguard Worker 				   sizeof("LIBARCHIVE.xattr.") - 1)) {
535*33b1fccfSAndroid Build Coastguard Worker 				char *key;
536*33b1fccfSAndroid Build Coastguard Worker 				key = kv + sizeof("LIBARCHIVE.xattr.") - 1;
537*33b1fccfSAndroid Build Coastguard Worker 
538*33b1fccfSAndroid Build Coastguard Worker 				--len; /* p[-1] == '\0' */
539*33b1fccfSAndroid Build Coastguard Worker 				ret = base64_decode(value, len - (value - kv),
540*33b1fccfSAndroid Build Coastguard Worker 						    (u8 *)value);
541*33b1fccfSAndroid Build Coastguard Worker 				if (ret < 0) {
542*33b1fccfSAndroid Build Coastguard Worker 					ret = -EFSCORRUPTED;
543*33b1fccfSAndroid Build Coastguard Worker 					goto out;
544*33b1fccfSAndroid Build Coastguard Worker 				}
545*33b1fccfSAndroid Build Coastguard Worker 
546*33b1fccfSAndroid Build Coastguard Worker 				ret = tarerofs_insert_xattr(&eh->xattrs, key,
547*33b1fccfSAndroid Build Coastguard Worker 						value - key - 1,
548*33b1fccfSAndroid Build Coastguard Worker 						value - key + ret, false);
549*33b1fccfSAndroid Build Coastguard Worker 				if (ret)
550*33b1fccfSAndroid Build Coastguard Worker 					goto out;
551*33b1fccfSAndroid Build Coastguard Worker 			} else {
552*33b1fccfSAndroid Build Coastguard Worker 				erofs_info("unrecognized pax keyword \"%s\", ignoring", kv);
553*33b1fccfSAndroid Build Coastguard Worker 			}
554*33b1fccfSAndroid Build Coastguard Worker 		}
555*33b1fccfSAndroid Build Coastguard Worker 	}
556*33b1fccfSAndroid Build Coastguard Worker 	ret = 0;
557*33b1fccfSAndroid Build Coastguard Worker out:
558*33b1fccfSAndroid Build Coastguard Worker 	free(buf);
559*33b1fccfSAndroid Build Coastguard Worker 	return ret;
560*33b1fccfSAndroid Build Coastguard Worker }
561*33b1fccfSAndroid Build Coastguard Worker 
tarerofs_remove_inode(struct erofs_inode * inode)562*33b1fccfSAndroid Build Coastguard Worker void tarerofs_remove_inode(struct erofs_inode *inode)
563*33b1fccfSAndroid Build Coastguard Worker {
564*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_dentry *d;
565*33b1fccfSAndroid Build Coastguard Worker 
566*33b1fccfSAndroid Build Coastguard Worker 	--inode->i_nlink;
567*33b1fccfSAndroid Build Coastguard Worker 	if (!S_ISDIR(inode->i_mode))
568*33b1fccfSAndroid Build Coastguard Worker 		return;
569*33b1fccfSAndroid Build Coastguard Worker 
570*33b1fccfSAndroid Build Coastguard Worker 	/* remove all subdirss */
571*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry(d, &inode->i_subdirs, d_child) {
572*33b1fccfSAndroid Build Coastguard Worker 		if (!is_dot_dotdot(d->name))
573*33b1fccfSAndroid Build Coastguard Worker 			tarerofs_remove_inode(d->inode);
574*33b1fccfSAndroid Build Coastguard Worker 		erofs_iput(d->inode);
575*33b1fccfSAndroid Build Coastguard Worker 		d->inode = NULL;
576*33b1fccfSAndroid Build Coastguard Worker 	}
577*33b1fccfSAndroid Build Coastguard Worker 	--inode->i_parent->i_nlink;
578*33b1fccfSAndroid Build Coastguard Worker }
579*33b1fccfSAndroid Build Coastguard Worker 
tarerofs_write_file_data(struct erofs_inode * inode,struct erofs_tarfile * tar)580*33b1fccfSAndroid Build Coastguard Worker static int tarerofs_write_file_data(struct erofs_inode *inode,
581*33b1fccfSAndroid Build Coastguard Worker 				    struct erofs_tarfile *tar)
582*33b1fccfSAndroid Build Coastguard Worker {
583*33b1fccfSAndroid Build Coastguard Worker 	void *buf;
584*33b1fccfSAndroid Build Coastguard Worker 	int fd, nread;
585*33b1fccfSAndroid Build Coastguard Worker 	u64 off, j;
586*33b1fccfSAndroid Build Coastguard Worker 
587*33b1fccfSAndroid Build Coastguard Worker 	if (!inode->i_diskbuf) {
588*33b1fccfSAndroid Build Coastguard Worker 		inode->i_diskbuf = calloc(1, sizeof(*inode->i_diskbuf));
589*33b1fccfSAndroid Build Coastguard Worker 		if (!inode->i_diskbuf)
590*33b1fccfSAndroid Build Coastguard Worker 			return -ENOSPC;
591*33b1fccfSAndroid Build Coastguard Worker 	} else {
592*33b1fccfSAndroid Build Coastguard Worker 		erofs_diskbuf_close(inode->i_diskbuf);
593*33b1fccfSAndroid Build Coastguard Worker 	}
594*33b1fccfSAndroid Build Coastguard Worker 
595*33b1fccfSAndroid Build Coastguard Worker 	fd = erofs_diskbuf_reserve(inode->i_diskbuf, 0, &off);
596*33b1fccfSAndroid Build Coastguard Worker 	if (fd < 0)
597*33b1fccfSAndroid Build Coastguard Worker 		return -EBADF;
598*33b1fccfSAndroid Build Coastguard Worker 
599*33b1fccfSAndroid Build Coastguard Worker 	for (j = inode->i_size; j; ) {
600*33b1fccfSAndroid Build Coastguard Worker 		nread = erofs_iostream_read(&tar->ios, &buf, j);
601*33b1fccfSAndroid Build Coastguard Worker 		if (nread < 0)
602*33b1fccfSAndroid Build Coastguard Worker 			break;
603*33b1fccfSAndroid Build Coastguard Worker 		if (write(fd, buf, nread) != nread) {
604*33b1fccfSAndroid Build Coastguard Worker 			nread = -EIO;
605*33b1fccfSAndroid Build Coastguard Worker 			break;
606*33b1fccfSAndroid Build Coastguard Worker 		}
607*33b1fccfSAndroid Build Coastguard Worker 		j -= nread;
608*33b1fccfSAndroid Build Coastguard Worker 	}
609*33b1fccfSAndroid Build Coastguard Worker 	erofs_diskbuf_commit(inode->i_diskbuf, inode->i_size);
610*33b1fccfSAndroid Build Coastguard Worker 	inode->datasource = EROFS_INODE_DATA_SOURCE_DISKBUF;
611*33b1fccfSAndroid Build Coastguard Worker 	return 0;
612*33b1fccfSAndroid Build Coastguard Worker }
613*33b1fccfSAndroid Build Coastguard Worker 
tarerofs_parse_tar(struct erofs_inode * root,struct erofs_tarfile * tar)614*33b1fccfSAndroid Build Coastguard Worker int tarerofs_parse_tar(struct erofs_inode *root, struct erofs_tarfile *tar)
615*33b1fccfSAndroid Build Coastguard Worker {
616*33b1fccfSAndroid Build Coastguard Worker 	char path[PATH_MAX];
617*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_pax_header eh = tar->global;
618*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = root->sbi;
619*33b1fccfSAndroid Build Coastguard Worker 	bool whout, opq, e = false;
620*33b1fccfSAndroid Build Coastguard Worker 	struct stat st;
621*33b1fccfSAndroid Build Coastguard Worker 	erofs_off_t tar_offset, dataoff;
622*33b1fccfSAndroid Build Coastguard Worker 
623*33b1fccfSAndroid Build Coastguard Worker 	struct tar_header *th;
624*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_dentry *d;
625*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *inode;
626*33b1fccfSAndroid Build Coastguard Worker 	unsigned int j, csum, cksum;
627*33b1fccfSAndroid Build Coastguard Worker 	int ckksum, ret, rem;
628*33b1fccfSAndroid Build Coastguard Worker 
629*33b1fccfSAndroid Build Coastguard Worker 	if (eh.path)
630*33b1fccfSAndroid Build Coastguard Worker 		eh.path = strdup(eh.path);
631*33b1fccfSAndroid Build Coastguard Worker 	if (eh.link)
632*33b1fccfSAndroid Build Coastguard Worker 		eh.link = strdup(eh.link);
633*33b1fccfSAndroid Build Coastguard Worker 	init_list_head(&eh.xattrs);
634*33b1fccfSAndroid Build Coastguard Worker 
635*33b1fccfSAndroid Build Coastguard Worker restart:
636*33b1fccfSAndroid Build Coastguard Worker 	rem = tar->offset & 511;
637*33b1fccfSAndroid Build Coastguard Worker 	if (rem) {
638*33b1fccfSAndroid Build Coastguard Worker 		if (erofs_iostream_lskip(&tar->ios, 512 - rem)) {
639*33b1fccfSAndroid Build Coastguard Worker 			ret = -EIO;
640*33b1fccfSAndroid Build Coastguard Worker 			goto out;
641*33b1fccfSAndroid Build Coastguard Worker 		}
642*33b1fccfSAndroid Build Coastguard Worker 		tar->offset += 512 - rem;
643*33b1fccfSAndroid Build Coastguard Worker 	}
644*33b1fccfSAndroid Build Coastguard Worker 
645*33b1fccfSAndroid Build Coastguard Worker 	tar_offset = tar->offset;
646*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_iostream_read(&tar->ios, (void **)&th, sizeof(*th));
647*33b1fccfSAndroid Build Coastguard Worker 	if (ret != sizeof(*th)) {
648*33b1fccfSAndroid Build Coastguard Worker 		if (tar->headeronly_mode || tar->ddtaridx_mode) {
649*33b1fccfSAndroid Build Coastguard Worker 			ret = 1;
650*33b1fccfSAndroid Build Coastguard Worker 			goto out;
651*33b1fccfSAndroid Build Coastguard Worker 		}
652*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("failed to read header block @ %llu", tar_offset);
653*33b1fccfSAndroid Build Coastguard Worker 		ret = -EIO;
654*33b1fccfSAndroid Build Coastguard Worker 		goto out;
655*33b1fccfSAndroid Build Coastguard Worker 	}
656*33b1fccfSAndroid Build Coastguard Worker 	tar->offset += sizeof(*th);
657*33b1fccfSAndroid Build Coastguard Worker 	if (*th->name == '\0') {
658*33b1fccfSAndroid Build Coastguard Worker 		if (e) {	/* end of tar 2 empty blocks */
659*33b1fccfSAndroid Build Coastguard Worker 			ret = 1;
660*33b1fccfSAndroid Build Coastguard Worker 			goto out;
661*33b1fccfSAndroid Build Coastguard Worker 		}
662*33b1fccfSAndroid Build Coastguard Worker 		e = true;	/* empty jump to next block */
663*33b1fccfSAndroid Build Coastguard Worker 		goto restart;
664*33b1fccfSAndroid Build Coastguard Worker 	}
665*33b1fccfSAndroid Build Coastguard Worker 
666*33b1fccfSAndroid Build Coastguard Worker 	/* chksum field itself treated as ' ' */
667*33b1fccfSAndroid Build Coastguard Worker 	csum = tarerofs_otoi(th->chksum, sizeof(th->chksum));
668*33b1fccfSAndroid Build Coastguard Worker 	if (errno) {
669*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("invalid chksum @ %llu", tar_offset);
670*33b1fccfSAndroid Build Coastguard Worker 		ret = -EBADMSG;
671*33b1fccfSAndroid Build Coastguard Worker 		goto out;
672*33b1fccfSAndroid Build Coastguard Worker 	}
673*33b1fccfSAndroid Build Coastguard Worker 	cksum = 0;
674*33b1fccfSAndroid Build Coastguard Worker 	for (j = 0; j < 8; ++j)
675*33b1fccfSAndroid Build Coastguard Worker 		cksum += (unsigned int)' ';
676*33b1fccfSAndroid Build Coastguard Worker 	ckksum = cksum;
677*33b1fccfSAndroid Build Coastguard Worker 	for (j = 0; j < 148; ++j) {
678*33b1fccfSAndroid Build Coastguard Worker 		cksum += (unsigned int)((u8*)th)[j];
679*33b1fccfSAndroid Build Coastguard Worker 		ckksum += (int)((char*)th)[j];
680*33b1fccfSAndroid Build Coastguard Worker 	}
681*33b1fccfSAndroid Build Coastguard Worker 	for (j = 156; j < 500; ++j) {
682*33b1fccfSAndroid Build Coastguard Worker 		cksum += (unsigned int)((u8*)th)[j];
683*33b1fccfSAndroid Build Coastguard Worker 		ckksum += (int)((char*)th)[j];
684*33b1fccfSAndroid Build Coastguard Worker 	}
685*33b1fccfSAndroid Build Coastguard Worker 	if (!tar->ddtaridx_mode && csum != cksum && csum != ckksum) {
686*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("chksum mismatch @ %llu", tar_offset);
687*33b1fccfSAndroid Build Coastguard Worker 		ret = -EBADMSG;
688*33b1fccfSAndroid Build Coastguard Worker 		goto out;
689*33b1fccfSAndroid Build Coastguard Worker 	}
690*33b1fccfSAndroid Build Coastguard Worker 
691*33b1fccfSAndroid Build Coastguard Worker 	if (th->typeflag == GNUTYPE_VOLHDR) {
692*33b1fccfSAndroid Build Coastguard Worker 		if (th->size[0])
693*33b1fccfSAndroid Build Coastguard Worker 			erofs_warn("GNUTYPE_VOLHDR with non-zeroed size @ %llu",
694*33b1fccfSAndroid Build Coastguard Worker 				   tar_offset);
695*33b1fccfSAndroid Build Coastguard Worker 		/* anyway, strncpy could cause some GCC warning here */
696*33b1fccfSAndroid Build Coastguard Worker 		memcpy(sbi->volume_name, th->name, sizeof(sbi->volume_name));
697*33b1fccfSAndroid Build Coastguard Worker 		goto restart;
698*33b1fccfSAndroid Build Coastguard Worker 	}
699*33b1fccfSAndroid Build Coastguard Worker 
700*33b1fccfSAndroid Build Coastguard Worker 	if (memcmp(th->magic, "ustar", 5)) {
701*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("invalid tar magic @ %llu", tar_offset);
702*33b1fccfSAndroid Build Coastguard Worker 		ret = -EIO;
703*33b1fccfSAndroid Build Coastguard Worker 		goto out;
704*33b1fccfSAndroid Build Coastguard Worker 	}
705*33b1fccfSAndroid Build Coastguard Worker 
706*33b1fccfSAndroid Build Coastguard Worker 	st.st_mode = tarerofs_otoi(th->mode, sizeof(th->mode));
707*33b1fccfSAndroid Build Coastguard Worker 	if (errno)
708*33b1fccfSAndroid Build Coastguard Worker 		goto invalid_tar;
709*33b1fccfSAndroid Build Coastguard Worker 
710*33b1fccfSAndroid Build Coastguard Worker 	if (eh.use_uid) {
711*33b1fccfSAndroid Build Coastguard Worker 		st.st_uid = eh.st.st_uid;
712*33b1fccfSAndroid Build Coastguard Worker 	} else {
713*33b1fccfSAndroid Build Coastguard Worker 		st.st_uid = tarerofs_parsenum(th->uid, sizeof(th->uid));
714*33b1fccfSAndroid Build Coastguard Worker 		if (errno)
715*33b1fccfSAndroid Build Coastguard Worker 			goto invalid_tar;
716*33b1fccfSAndroid Build Coastguard Worker 	}
717*33b1fccfSAndroid Build Coastguard Worker 
718*33b1fccfSAndroid Build Coastguard Worker 	if (eh.use_gid) {
719*33b1fccfSAndroid Build Coastguard Worker 		st.st_gid = eh.st.st_gid;
720*33b1fccfSAndroid Build Coastguard Worker 	} else {
721*33b1fccfSAndroid Build Coastguard Worker 		st.st_gid = tarerofs_parsenum(th->gid, sizeof(th->gid));
722*33b1fccfSAndroid Build Coastguard Worker 		if (errno)
723*33b1fccfSAndroid Build Coastguard Worker 			goto invalid_tar;
724*33b1fccfSAndroid Build Coastguard Worker 	}
725*33b1fccfSAndroid Build Coastguard Worker 
726*33b1fccfSAndroid Build Coastguard Worker 	if (eh.use_size) {
727*33b1fccfSAndroid Build Coastguard Worker 		st.st_size = eh.st.st_size;
728*33b1fccfSAndroid Build Coastguard Worker 	} else {
729*33b1fccfSAndroid Build Coastguard Worker 		st.st_size = tarerofs_parsenum(th->size, sizeof(th->size));
730*33b1fccfSAndroid Build Coastguard Worker 		if (errno)
731*33b1fccfSAndroid Build Coastguard Worker 			goto invalid_tar;
732*33b1fccfSAndroid Build Coastguard Worker 	}
733*33b1fccfSAndroid Build Coastguard Worker 
734*33b1fccfSAndroid Build Coastguard Worker 	if (eh.use_mtime) {
735*33b1fccfSAndroid Build Coastguard Worker 		st.st_mtime = eh.st.st_mtime;
736*33b1fccfSAndroid Build Coastguard Worker 		ST_MTIM_NSEC_SET(&st, ST_MTIM_NSEC(&eh.st));
737*33b1fccfSAndroid Build Coastguard Worker 	} else {
738*33b1fccfSAndroid Build Coastguard Worker 		st.st_mtime = tarerofs_parsenum(th->mtime, sizeof(th->mtime));
739*33b1fccfSAndroid Build Coastguard Worker 		if (errno)
740*33b1fccfSAndroid Build Coastguard Worker 			goto invalid_tar;
741*33b1fccfSAndroid Build Coastguard Worker 		ST_MTIM_NSEC_SET(&st, 0);
742*33b1fccfSAndroid Build Coastguard Worker 	}
743*33b1fccfSAndroid Build Coastguard Worker 
744*33b1fccfSAndroid Build Coastguard Worker 	if (th->typeflag <= '7' && !eh.path) {
745*33b1fccfSAndroid Build Coastguard Worker 		eh.path = path;
746*33b1fccfSAndroid Build Coastguard Worker 		j = 0;
747*33b1fccfSAndroid Build Coastguard Worker 		if (*th->prefix) {
748*33b1fccfSAndroid Build Coastguard Worker 			memcpy(path, th->prefix, sizeof(th->prefix));
749*33b1fccfSAndroid Build Coastguard Worker 			path[sizeof(th->prefix)] = '\0';
750*33b1fccfSAndroid Build Coastguard Worker 			j = strlen(path);
751*33b1fccfSAndroid Build Coastguard Worker 			if (path[j - 1] != '/') {
752*33b1fccfSAndroid Build Coastguard Worker 				path[j] = '/';
753*33b1fccfSAndroid Build Coastguard Worker 				path[++j] = '\0';
754*33b1fccfSAndroid Build Coastguard Worker 			}
755*33b1fccfSAndroid Build Coastguard Worker 		}
756*33b1fccfSAndroid Build Coastguard Worker 		memcpy(path + j, th->name, sizeof(th->name));
757*33b1fccfSAndroid Build Coastguard Worker 		path[j + sizeof(th->name)] = '\0';
758*33b1fccfSAndroid Build Coastguard Worker 		j = strlen(path);
759*33b1fccfSAndroid Build Coastguard Worker 		while (path[j - 1] == '/')
760*33b1fccfSAndroid Build Coastguard Worker 			path[--j] = '\0';
761*33b1fccfSAndroid Build Coastguard Worker 	}
762*33b1fccfSAndroid Build Coastguard Worker 
763*33b1fccfSAndroid Build Coastguard Worker 	dataoff = tar->offset;
764*33b1fccfSAndroid Build Coastguard Worker 	if (!(tar->headeronly_mode || tar->ddtaridx_mode))
765*33b1fccfSAndroid Build Coastguard Worker 		tar->offset += st.st_size;
766*33b1fccfSAndroid Build Coastguard Worker 	switch(th->typeflag) {
767*33b1fccfSAndroid Build Coastguard Worker 	case '0':
768*33b1fccfSAndroid Build Coastguard Worker 	case '7':
769*33b1fccfSAndroid Build Coastguard Worker 	case '1':
770*33b1fccfSAndroid Build Coastguard Worker 		st.st_mode |= S_IFREG;
771*33b1fccfSAndroid Build Coastguard Worker 		break;
772*33b1fccfSAndroid Build Coastguard Worker 	case '2':
773*33b1fccfSAndroid Build Coastguard Worker 		st.st_mode |= S_IFLNK;
774*33b1fccfSAndroid Build Coastguard Worker 		break;
775*33b1fccfSAndroid Build Coastguard Worker 	case '3':
776*33b1fccfSAndroid Build Coastguard Worker 		st.st_mode |= S_IFCHR;
777*33b1fccfSAndroid Build Coastguard Worker 		break;
778*33b1fccfSAndroid Build Coastguard Worker 	case '4':
779*33b1fccfSAndroid Build Coastguard Worker 		st.st_mode |= S_IFBLK;
780*33b1fccfSAndroid Build Coastguard Worker 		break;
781*33b1fccfSAndroid Build Coastguard Worker 	case '5':
782*33b1fccfSAndroid Build Coastguard Worker 		st.st_mode |= S_IFDIR;
783*33b1fccfSAndroid Build Coastguard Worker 		break;
784*33b1fccfSAndroid Build Coastguard Worker 	case '6':
785*33b1fccfSAndroid Build Coastguard Worker 		st.st_mode |= S_IFIFO;
786*33b1fccfSAndroid Build Coastguard Worker 		break;
787*33b1fccfSAndroid Build Coastguard Worker 	case 'g':
788*33b1fccfSAndroid Build Coastguard Worker 		ret = tarerofs_parse_pax_header(&tar->ios, &tar->global,
789*33b1fccfSAndroid Build Coastguard Worker 						st.st_size);
790*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
791*33b1fccfSAndroid Build Coastguard Worker 			goto out;
792*33b1fccfSAndroid Build Coastguard Worker 		if (tar->global.path) {
793*33b1fccfSAndroid Build Coastguard Worker 			free(eh.path);
794*33b1fccfSAndroid Build Coastguard Worker 			eh.path = strdup(tar->global.path);
795*33b1fccfSAndroid Build Coastguard Worker 		}
796*33b1fccfSAndroid Build Coastguard Worker 		if (tar->global.link) {
797*33b1fccfSAndroid Build Coastguard Worker 			free(eh.link);
798*33b1fccfSAndroid Build Coastguard Worker 			eh.link = strdup(tar->global.link);
799*33b1fccfSAndroid Build Coastguard Worker 		}
800*33b1fccfSAndroid Build Coastguard Worker 		goto restart;
801*33b1fccfSAndroid Build Coastguard Worker 	case 'x':
802*33b1fccfSAndroid Build Coastguard Worker 		ret = tarerofs_parse_pax_header(&tar->ios, &eh, st.st_size);
803*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
804*33b1fccfSAndroid Build Coastguard Worker 			goto out;
805*33b1fccfSAndroid Build Coastguard Worker 		goto restart;
806*33b1fccfSAndroid Build Coastguard Worker 	case 'L':
807*33b1fccfSAndroid Build Coastguard Worker 		free(eh.path);
808*33b1fccfSAndroid Build Coastguard Worker 		eh.path = malloc(st.st_size + 1);
809*33b1fccfSAndroid Build Coastguard Worker 		if (st.st_size != erofs_iostream_bread(&tar->ios, eh.path,
810*33b1fccfSAndroid Build Coastguard Worker 						       st.st_size))
811*33b1fccfSAndroid Build Coastguard Worker 			goto invalid_tar;
812*33b1fccfSAndroid Build Coastguard Worker 		eh.path[st.st_size] = '\0';
813*33b1fccfSAndroid Build Coastguard Worker 		goto restart;
814*33b1fccfSAndroid Build Coastguard Worker 	case 'K':
815*33b1fccfSAndroid Build Coastguard Worker 		free(eh.link);
816*33b1fccfSAndroid Build Coastguard Worker 		eh.link = malloc(st.st_size + 1);
817*33b1fccfSAndroid Build Coastguard Worker 		if (st.st_size > PATH_MAX || st.st_size !=
818*33b1fccfSAndroid Build Coastguard Worker 		    erofs_iostream_bread(&tar->ios, eh.link, st.st_size))
819*33b1fccfSAndroid Build Coastguard Worker 			goto invalid_tar;
820*33b1fccfSAndroid Build Coastguard Worker 		eh.link[st.st_size] = '\0';
821*33b1fccfSAndroid Build Coastguard Worker 		goto restart;
822*33b1fccfSAndroid Build Coastguard Worker 	default:
823*33b1fccfSAndroid Build Coastguard Worker 		erofs_info("unrecognized typeflag %xh @ %llu - ignoring",
824*33b1fccfSAndroid Build Coastguard Worker 			   th->typeflag, tar_offset);
825*33b1fccfSAndroid Build Coastguard Worker 		(void)erofs_iostream_lskip(&tar->ios, st.st_size);
826*33b1fccfSAndroid Build Coastguard Worker 		ret = 0;
827*33b1fccfSAndroid Build Coastguard Worker 		goto out;
828*33b1fccfSAndroid Build Coastguard Worker 	}
829*33b1fccfSAndroid Build Coastguard Worker 
830*33b1fccfSAndroid Build Coastguard Worker 	st.st_rdev = 0;
831*33b1fccfSAndroid Build Coastguard Worker 	if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) {
832*33b1fccfSAndroid Build Coastguard Worker 		int major, minor;
833*33b1fccfSAndroid Build Coastguard Worker 
834*33b1fccfSAndroid Build Coastguard Worker 		major = tarerofs_parsenum(th->devmajor, sizeof(th->devmajor));
835*33b1fccfSAndroid Build Coastguard Worker 		if (errno) {
836*33b1fccfSAndroid Build Coastguard Worker 			erofs_err("invalid device major @ %llu", tar_offset);
837*33b1fccfSAndroid Build Coastguard Worker 			goto out;
838*33b1fccfSAndroid Build Coastguard Worker 		}
839*33b1fccfSAndroid Build Coastguard Worker 
840*33b1fccfSAndroid Build Coastguard Worker 		minor = tarerofs_parsenum(th->devminor, sizeof(th->devminor));
841*33b1fccfSAndroid Build Coastguard Worker 		if (errno) {
842*33b1fccfSAndroid Build Coastguard Worker 			erofs_err("invalid device minor @ %llu", tar_offset);
843*33b1fccfSAndroid Build Coastguard Worker 			goto out;
844*33b1fccfSAndroid Build Coastguard Worker 		}
845*33b1fccfSAndroid Build Coastguard Worker 
846*33b1fccfSAndroid Build Coastguard Worker 		st.st_rdev = (major << 8) | (minor & 0xff) | ((minor & ~0xff) << 12);
847*33b1fccfSAndroid Build Coastguard Worker 	} else if (th->typeflag == '1' || th->typeflag == '2') {
848*33b1fccfSAndroid Build Coastguard Worker 		if (!eh.link)
849*33b1fccfSAndroid Build Coastguard Worker 			eh.link = strndup(th->linkname, sizeof(th->linkname));
850*33b1fccfSAndroid Build Coastguard Worker 	}
851*33b1fccfSAndroid Build Coastguard Worker 
852*33b1fccfSAndroid Build Coastguard Worker 	/* EROFS metadata index referring to the original tar data */
853*33b1fccfSAndroid Build Coastguard Worker 	if (tar->index_mode && sbi->extra_devices &&
854*33b1fccfSAndroid Build Coastguard Worker 	    erofs_blkoff(sbi, dataoff)) {
855*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("invalid tar data alignment @ %llu", tar_offset);
856*33b1fccfSAndroid Build Coastguard Worker 		ret = -EIO;
857*33b1fccfSAndroid Build Coastguard Worker 		goto out;
858*33b1fccfSAndroid Build Coastguard Worker 	}
859*33b1fccfSAndroid Build Coastguard Worker 
860*33b1fccfSAndroid Build Coastguard Worker 	erofs_dbg("parsing %s (mode %05o)", eh.path, st.st_mode);
861*33b1fccfSAndroid Build Coastguard Worker 
862*33b1fccfSAndroid Build Coastguard Worker 	d = erofs_rebuild_get_dentry(root, eh.path, tar->aufs, &whout, &opq, true);
863*33b1fccfSAndroid Build Coastguard Worker 	if (IS_ERR(d)) {
864*33b1fccfSAndroid Build Coastguard Worker 		ret = PTR_ERR(d);
865*33b1fccfSAndroid Build Coastguard Worker 		goto out;
866*33b1fccfSAndroid Build Coastguard Worker 	}
867*33b1fccfSAndroid Build Coastguard Worker 
868*33b1fccfSAndroid Build Coastguard Worker 	if (!d) {
869*33b1fccfSAndroid Build Coastguard Worker 		/* some tarballs include '.' which indicates the root directory */
870*33b1fccfSAndroid Build Coastguard Worker 		if (!S_ISDIR(st.st_mode)) {
871*33b1fccfSAndroid Build Coastguard Worker 			ret = -ENOTDIR;
872*33b1fccfSAndroid Build Coastguard Worker 			goto out;
873*33b1fccfSAndroid Build Coastguard Worker 		}
874*33b1fccfSAndroid Build Coastguard Worker 		inode = root;
875*33b1fccfSAndroid Build Coastguard Worker 	} else if (opq) {
876*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(d->type == EROFS_FT_UNKNOWN);
877*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(!d->inode);
878*33b1fccfSAndroid Build Coastguard Worker 		/*
879*33b1fccfSAndroid Build Coastguard Worker 		 * needed if the tar tree is used soon, thus we have no chance
880*33b1fccfSAndroid Build Coastguard Worker 		 * to generate it from xattrs.  No impact to mergefs.
881*33b1fccfSAndroid Build Coastguard Worker 		 */
882*33b1fccfSAndroid Build Coastguard Worker 		d->inode->opaque = true;
883*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_set_opaque_xattr(d->inode);
884*33b1fccfSAndroid Build Coastguard Worker 		goto out;
885*33b1fccfSAndroid Build Coastguard Worker 	} else if (th->typeflag == '1') {	/* hard link cases */
886*33b1fccfSAndroid Build Coastguard Worker 		struct erofs_dentry *d2;
887*33b1fccfSAndroid Build Coastguard Worker 		bool dumb;
888*33b1fccfSAndroid Build Coastguard Worker 
889*33b1fccfSAndroid Build Coastguard Worker 		if (S_ISDIR(st.st_mode)) {
890*33b1fccfSAndroid Build Coastguard Worker 			ret = -EISDIR;
891*33b1fccfSAndroid Build Coastguard Worker 			goto out;
892*33b1fccfSAndroid Build Coastguard Worker 		}
893*33b1fccfSAndroid Build Coastguard Worker 
894*33b1fccfSAndroid Build Coastguard Worker 		if (d->type != EROFS_FT_UNKNOWN) {
895*33b1fccfSAndroid Build Coastguard Worker 			tarerofs_remove_inode(d->inode);
896*33b1fccfSAndroid Build Coastguard Worker 			erofs_iput(d->inode);
897*33b1fccfSAndroid Build Coastguard Worker 		}
898*33b1fccfSAndroid Build Coastguard Worker 		d->inode = NULL;
899*33b1fccfSAndroid Build Coastguard Worker 
900*33b1fccfSAndroid Build Coastguard Worker 		d2 = erofs_rebuild_get_dentry(root, eh.link, tar->aufs,
901*33b1fccfSAndroid Build Coastguard Worker 					      &dumb, &dumb, false);
902*33b1fccfSAndroid Build Coastguard Worker 		if (IS_ERR(d2)) {
903*33b1fccfSAndroid Build Coastguard Worker 			ret = PTR_ERR(d2);
904*33b1fccfSAndroid Build Coastguard Worker 			goto out;
905*33b1fccfSAndroid Build Coastguard Worker 		}
906*33b1fccfSAndroid Build Coastguard Worker 		if (d2->type == EROFS_FT_UNKNOWN) {
907*33b1fccfSAndroid Build Coastguard Worker 			ret = -ENOENT;
908*33b1fccfSAndroid Build Coastguard Worker 			goto out;
909*33b1fccfSAndroid Build Coastguard Worker 		}
910*33b1fccfSAndroid Build Coastguard Worker 		if (S_ISDIR(d2->inode->i_mode)) {
911*33b1fccfSAndroid Build Coastguard Worker 			ret = -EISDIR;
912*33b1fccfSAndroid Build Coastguard Worker 			goto out;
913*33b1fccfSAndroid Build Coastguard Worker 		}
914*33b1fccfSAndroid Build Coastguard Worker 		inode = erofs_igrab(d2->inode);
915*33b1fccfSAndroid Build Coastguard Worker 		d->inode = inode;
916*33b1fccfSAndroid Build Coastguard Worker 		d->type = d2->type;
917*33b1fccfSAndroid Build Coastguard Worker 		++inode->i_nlink;
918*33b1fccfSAndroid Build Coastguard Worker 		ret = 0;
919*33b1fccfSAndroid Build Coastguard Worker 		goto out;
920*33b1fccfSAndroid Build Coastguard Worker 	} else if (d->type != EROFS_FT_UNKNOWN) {
921*33b1fccfSAndroid Build Coastguard Worker 		if (d->type != EROFS_FT_DIR || !S_ISDIR(st.st_mode)) {
922*33b1fccfSAndroid Build Coastguard Worker 			struct erofs_inode *parent = d->inode->i_parent;
923*33b1fccfSAndroid Build Coastguard Worker 
924*33b1fccfSAndroid Build Coastguard Worker 			tarerofs_remove_inode(d->inode);
925*33b1fccfSAndroid Build Coastguard Worker 			erofs_iput(d->inode);
926*33b1fccfSAndroid Build Coastguard Worker 			d->inode = parent;
927*33b1fccfSAndroid Build Coastguard Worker 			goto new_inode;
928*33b1fccfSAndroid Build Coastguard Worker 		}
929*33b1fccfSAndroid Build Coastguard Worker 		inode = d->inode;
930*33b1fccfSAndroid Build Coastguard Worker 	} else {
931*33b1fccfSAndroid Build Coastguard Worker new_inode:
932*33b1fccfSAndroid Build Coastguard Worker 		inode = erofs_new_inode(sbi);
933*33b1fccfSAndroid Build Coastguard Worker 		if (IS_ERR(inode)) {
934*33b1fccfSAndroid Build Coastguard Worker 			ret = PTR_ERR(inode);
935*33b1fccfSAndroid Build Coastguard Worker 			goto out;
936*33b1fccfSAndroid Build Coastguard Worker 		}
937*33b1fccfSAndroid Build Coastguard Worker 		inode->dev = tar->dev;
938*33b1fccfSAndroid Build Coastguard Worker 		inode->i_parent = d->inode;
939*33b1fccfSAndroid Build Coastguard Worker 		d->inode = inode;
940*33b1fccfSAndroid Build Coastguard Worker 		d->type = erofs_mode_to_ftype(st.st_mode);
941*33b1fccfSAndroid Build Coastguard Worker 	}
942*33b1fccfSAndroid Build Coastguard Worker 
943*33b1fccfSAndroid Build Coastguard Worker 	if (whout) {
944*33b1fccfSAndroid Build Coastguard Worker 		inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFCHR;
945*33b1fccfSAndroid Build Coastguard Worker 		inode->u.i_rdev = EROFS_WHITEOUT_DEV;
946*33b1fccfSAndroid Build Coastguard Worker 		d->type = EROFS_FT_CHRDEV;
947*33b1fccfSAndroid Build Coastguard Worker 
948*33b1fccfSAndroid Build Coastguard Worker 		/*
949*33b1fccfSAndroid Build Coastguard Worker 		 * Mark the parent directory as copied-up to avoid exposing
950*33b1fccfSAndroid Build Coastguard Worker 		 * whiteouts if mounted.  See kernel commit b79e05aaa166
951*33b1fccfSAndroid Build Coastguard Worker 		 * ("ovl: no direct iteration for dir with origin xattr")
952*33b1fccfSAndroid Build Coastguard Worker 		 */
953*33b1fccfSAndroid Build Coastguard Worker 		inode->i_parent->whiteouts = true;
954*33b1fccfSAndroid Build Coastguard Worker 	} else {
955*33b1fccfSAndroid Build Coastguard Worker 		inode->i_mode = st.st_mode;
956*33b1fccfSAndroid Build Coastguard Worker 		if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
957*33b1fccfSAndroid Build Coastguard Worker 			inode->u.i_rdev = erofs_new_encode_dev(st.st_rdev);
958*33b1fccfSAndroid Build Coastguard Worker 	}
959*33b1fccfSAndroid Build Coastguard Worker 
960*33b1fccfSAndroid Build Coastguard Worker 	inode->i_srcpath = strdup(eh.path);
961*33b1fccfSAndroid Build Coastguard Worker 	if (!inode->i_srcpath) {
962*33b1fccfSAndroid Build Coastguard Worker 		ret = -ENOMEM;
963*33b1fccfSAndroid Build Coastguard Worker 		goto out;
964*33b1fccfSAndroid Build Coastguard Worker 	}
965*33b1fccfSAndroid Build Coastguard Worker 
966*33b1fccfSAndroid Build Coastguard Worker 	ret = __erofs_fill_inode(inode, &st, eh.path);
967*33b1fccfSAndroid Build Coastguard Worker 	if (ret)
968*33b1fccfSAndroid Build Coastguard Worker 		goto out;
969*33b1fccfSAndroid Build Coastguard Worker 	inode->i_size = st.st_size;
970*33b1fccfSAndroid Build Coastguard Worker 
971*33b1fccfSAndroid Build Coastguard Worker 	if (!S_ISDIR(inode->i_mode)) {
972*33b1fccfSAndroid Build Coastguard Worker 		if (S_ISLNK(inode->i_mode)) {
973*33b1fccfSAndroid Build Coastguard Worker 			inode->i_size = strlen(eh.link);
974*33b1fccfSAndroid Build Coastguard Worker 			inode->i_link = malloc(inode->i_size + 1);
975*33b1fccfSAndroid Build Coastguard Worker 			memcpy(inode->i_link, eh.link, inode->i_size + 1);
976*33b1fccfSAndroid Build Coastguard Worker 		} else if (inode->i_size) {
977*33b1fccfSAndroid Build Coastguard Worker 			if (tar->headeronly_mode) {
978*33b1fccfSAndroid Build Coastguard Worker 				ret = erofs_write_zero_inode(inode);
979*33b1fccfSAndroid Build Coastguard Worker 			} else if (tar->ddtaridx_mode) {
980*33b1fccfSAndroid Build Coastguard Worker 				dataoff = le64_to_cpu(*(__le64 *)(th->devmajor));
981*33b1fccfSAndroid Build Coastguard Worker 				if (tar->rvsp_mode) {
982*33b1fccfSAndroid Build Coastguard Worker 					inode->datasource = EROFS_INODE_DATA_SOURCE_RESVSP;
983*33b1fccfSAndroid Build Coastguard Worker 					inode->i_ino[1] = dataoff;
984*33b1fccfSAndroid Build Coastguard Worker 					ret = 0;
985*33b1fccfSAndroid Build Coastguard Worker 				} else {
986*33b1fccfSAndroid Build Coastguard Worker 					ret = tarerofs_write_chunkes(inode, dataoff);
987*33b1fccfSAndroid Build Coastguard Worker 				}
988*33b1fccfSAndroid Build Coastguard Worker 			} else if (tar->rvsp_mode) {
989*33b1fccfSAndroid Build Coastguard Worker 				inode->datasource = EROFS_INODE_DATA_SOURCE_RESVSP;
990*33b1fccfSAndroid Build Coastguard Worker 				inode->i_ino[1] = dataoff;
991*33b1fccfSAndroid Build Coastguard Worker 				if (erofs_iostream_lskip(&tar->ios, inode->i_size))
992*33b1fccfSAndroid Build Coastguard Worker 					ret = -EIO;
993*33b1fccfSAndroid Build Coastguard Worker 				else
994*33b1fccfSAndroid Build Coastguard Worker 					ret = 0;
995*33b1fccfSAndroid Build Coastguard Worker 			} else if (tar->index_mode) {
996*33b1fccfSAndroid Build Coastguard Worker 				ret = tarerofs_write_chunkes(inode, dataoff);
997*33b1fccfSAndroid Build Coastguard Worker 				if (!ret && erofs_iostream_lskip(&tar->ios,
998*33b1fccfSAndroid Build Coastguard Worker 								 inode->i_size))
999*33b1fccfSAndroid Build Coastguard Worker 					ret = -EIO;
1000*33b1fccfSAndroid Build Coastguard Worker 			} else {
1001*33b1fccfSAndroid Build Coastguard Worker 				ret = tarerofs_write_file_data(inode, tar);
1002*33b1fccfSAndroid Build Coastguard Worker 			}
1003*33b1fccfSAndroid Build Coastguard Worker 			if (ret)
1004*33b1fccfSAndroid Build Coastguard Worker 				goto out;
1005*33b1fccfSAndroid Build Coastguard Worker 		}
1006*33b1fccfSAndroid Build Coastguard Worker 		inode->i_nlink++;
1007*33b1fccfSAndroid Build Coastguard Worker 	} else if (!inode->i_nlink) {
1008*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_init_empty_dir(inode);
1009*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
1010*33b1fccfSAndroid Build Coastguard Worker 			goto out;
1011*33b1fccfSAndroid Build Coastguard Worker 	}
1012*33b1fccfSAndroid Build Coastguard Worker 
1013*33b1fccfSAndroid Build Coastguard Worker 	ret = tarerofs_merge_xattrs(&eh.xattrs, &tar->global.xattrs);
1014*33b1fccfSAndroid Build Coastguard Worker 	if (ret)
1015*33b1fccfSAndroid Build Coastguard Worker 		goto out;
1016*33b1fccfSAndroid Build Coastguard Worker 
1017*33b1fccfSAndroid Build Coastguard Worker 	ret = tarerofs_apply_xattrs(inode, &eh.xattrs);
1018*33b1fccfSAndroid Build Coastguard Worker 
1019*33b1fccfSAndroid Build Coastguard Worker out:
1020*33b1fccfSAndroid Build Coastguard Worker 	if (eh.path != path)
1021*33b1fccfSAndroid Build Coastguard Worker 		free(eh.path);
1022*33b1fccfSAndroid Build Coastguard Worker 	free(eh.link);
1023*33b1fccfSAndroid Build Coastguard Worker 	tarerofs_remove_xattrs(&eh.xattrs);
1024*33b1fccfSAndroid Build Coastguard Worker 	return ret;
1025*33b1fccfSAndroid Build Coastguard Worker 
1026*33b1fccfSAndroid Build Coastguard Worker invalid_tar:
1027*33b1fccfSAndroid Build Coastguard Worker 	erofs_err("invalid tar @ %llu", tar_offset);
1028*33b1fccfSAndroid Build Coastguard Worker 	ret = -EIO;
1029*33b1fccfSAndroid Build Coastguard Worker 	goto out;
1030*33b1fccfSAndroid Build Coastguard Worker }
1031