xref: /aosp_15_r20/external/erofs-utils/lib/fragments.c (revision 33b1fccf6a0fada2c2875d400ed01119b7676ee5)
1*33b1fccfSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
2*33b1fccfSAndroid Build Coastguard Worker /*
3*33b1fccfSAndroid Build Coastguard Worker  * Copyright (C), 2022, Coolpad Group Limited.
4*33b1fccfSAndroid Build Coastguard Worker  * Created by Yue Hu <[email protected]>
5*33b1fccfSAndroid Build Coastguard Worker  */
6*33b1fccfSAndroid Build Coastguard Worker #ifndef _LARGEFILE_SOURCE
7*33b1fccfSAndroid Build Coastguard Worker #define _LARGEFILE_SOURCE
8*33b1fccfSAndroid Build Coastguard Worker #endif
9*33b1fccfSAndroid Build Coastguard Worker #ifndef _LARGEFILE64_SOURCE
10*33b1fccfSAndroid Build Coastguard Worker #define _LARGEFILE64_SOURCE
11*33b1fccfSAndroid Build Coastguard Worker #endif
12*33b1fccfSAndroid Build Coastguard Worker #ifndef _FILE_OFFSET_BITS
13*33b1fccfSAndroid Build Coastguard Worker #define _FILE_OFFSET_BITS 64
14*33b1fccfSAndroid Build Coastguard Worker #endif
15*33b1fccfSAndroid Build Coastguard Worker #ifndef _GNU_SOURCE
16*33b1fccfSAndroid Build Coastguard Worker #define _GNU_SOURCE
17*33b1fccfSAndroid Build Coastguard Worker #endif
18*33b1fccfSAndroid Build Coastguard Worker #include <stdlib.h>
19*33b1fccfSAndroid Build Coastguard Worker #include <unistd.h>
20*33b1fccfSAndroid Build Coastguard Worker #include <sys/mman.h>
21*33b1fccfSAndroid Build Coastguard Worker #include "erofs/err.h"
22*33b1fccfSAndroid Build Coastguard Worker #include "erofs/inode.h"
23*33b1fccfSAndroid Build Coastguard Worker #include "erofs/compress.h"
24*33b1fccfSAndroid Build Coastguard Worker #include "erofs/print.h"
25*33b1fccfSAndroid Build Coastguard Worker #include "erofs/internal.h"
26*33b1fccfSAndroid Build Coastguard Worker #include "erofs/fragments.h"
27*33b1fccfSAndroid Build Coastguard Worker 
28*33b1fccfSAndroid Build Coastguard Worker struct erofs_fragment_dedupe_item {
29*33b1fccfSAndroid Build Coastguard Worker 	struct list_head	list;
30*33b1fccfSAndroid Build Coastguard Worker 	unsigned int		length;
31*33b1fccfSAndroid Build Coastguard Worker 	erofs_off_t		pos;
32*33b1fccfSAndroid Build Coastguard Worker 	u8			data[];
33*33b1fccfSAndroid Build Coastguard Worker };
34*33b1fccfSAndroid Build Coastguard Worker 
35*33b1fccfSAndroid Build Coastguard Worker #define EROFS_TOF_HASHLEN		16
36*33b1fccfSAndroid Build Coastguard Worker 
37*33b1fccfSAndroid Build Coastguard Worker #define FRAGMENT_HASHSIZE		65536
38*33b1fccfSAndroid Build Coastguard Worker #define FRAGMENT_HASH(c)		((c) & (FRAGMENT_HASHSIZE - 1))
39*33b1fccfSAndroid Build Coastguard Worker 
40*33b1fccfSAndroid Build Coastguard Worker static struct list_head dupli_frags[FRAGMENT_HASHSIZE];
41*33b1fccfSAndroid Build Coastguard Worker static FILE *packedfile;
42*33b1fccfSAndroid Build Coastguard Worker const char *erofs_frags_packedname = "packed_file";
43*33b1fccfSAndroid Build Coastguard Worker 
44*33b1fccfSAndroid Build Coastguard Worker #ifndef HAVE_LSEEK64
45*33b1fccfSAndroid Build Coastguard Worker #define erofs_lseek64 lseek
46*33b1fccfSAndroid Build Coastguard Worker #else
47*33b1fccfSAndroid Build Coastguard Worker #define erofs_lseek64 lseek64
48*33b1fccfSAndroid Build Coastguard Worker #endif
49*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_fragments_dedupe_find(struct erofs_inode * inode,int fd,u32 crc)50*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_fragments_dedupe_find(struct erofs_inode *inode, int fd,
51*33b1fccfSAndroid Build Coastguard Worker 					 u32 crc)
52*33b1fccfSAndroid Build Coastguard Worker {
53*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_fragment_dedupe_item *cur, *di = NULL;
54*33b1fccfSAndroid Build Coastguard Worker 	struct list_head *head;
55*33b1fccfSAndroid Build Coastguard Worker 	u8 *data;
56*33b1fccfSAndroid Build Coastguard Worker 	unsigned int length, e2, deduped;
57*33b1fccfSAndroid Build Coastguard Worker 	erofs_off_t pos;
58*33b1fccfSAndroid Build Coastguard Worker 	int ret;
59*33b1fccfSAndroid Build Coastguard Worker 
60*33b1fccfSAndroid Build Coastguard Worker 	head = &dupli_frags[FRAGMENT_HASH(crc)];
61*33b1fccfSAndroid Build Coastguard Worker 	if (list_empty(head))
62*33b1fccfSAndroid Build Coastguard Worker 		return 0;
63*33b1fccfSAndroid Build Coastguard Worker 
64*33b1fccfSAndroid Build Coastguard Worker 	/* XXX: no need to read so much for smaller? */
65*33b1fccfSAndroid Build Coastguard Worker 	if (inode->i_size < EROFS_CONFIG_COMPR_MAX_SZ)
66*33b1fccfSAndroid Build Coastguard Worker 		length = inode->i_size;
67*33b1fccfSAndroid Build Coastguard Worker 	else
68*33b1fccfSAndroid Build Coastguard Worker 		length = EROFS_CONFIG_COMPR_MAX_SZ;
69*33b1fccfSAndroid Build Coastguard Worker 
70*33b1fccfSAndroid Build Coastguard Worker 	data = malloc(length);
71*33b1fccfSAndroid Build Coastguard Worker 	if (!data)
72*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
73*33b1fccfSAndroid Build Coastguard Worker 
74*33b1fccfSAndroid Build Coastguard Worker 	if (erofs_lseek64(fd, inode->i_size - length, SEEK_SET) < 0) {
75*33b1fccfSAndroid Build Coastguard Worker 		ret = -errno;
76*33b1fccfSAndroid Build Coastguard Worker 		goto out;
77*33b1fccfSAndroid Build Coastguard Worker 	}
78*33b1fccfSAndroid Build Coastguard Worker 
79*33b1fccfSAndroid Build Coastguard Worker 	ret = read(fd, data, length);
80*33b1fccfSAndroid Build Coastguard Worker 	if (ret != length) {
81*33b1fccfSAndroid Build Coastguard Worker 		ret = -errno;
82*33b1fccfSAndroid Build Coastguard Worker 		goto out;
83*33b1fccfSAndroid Build Coastguard Worker 	}
84*33b1fccfSAndroid Build Coastguard Worker 
85*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(length <= EROFS_TOF_HASHLEN);
86*33b1fccfSAndroid Build Coastguard Worker 	e2 = length - EROFS_TOF_HASHLEN;
87*33b1fccfSAndroid Build Coastguard Worker 	deduped = 0;
88*33b1fccfSAndroid Build Coastguard Worker 
89*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry(cur, head, list) {
90*33b1fccfSAndroid Build Coastguard Worker 		unsigned int e1, mn, i = 0;
91*33b1fccfSAndroid Build Coastguard Worker 
92*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(cur->length <= EROFS_TOF_HASHLEN);
93*33b1fccfSAndroid Build Coastguard Worker 		e1 = cur->length - EROFS_TOF_HASHLEN;
94*33b1fccfSAndroid Build Coastguard Worker 
95*33b1fccfSAndroid Build Coastguard Worker 		if (memcmp(cur->data + e1, data + e2, EROFS_TOF_HASHLEN))
96*33b1fccfSAndroid Build Coastguard Worker 			continue;
97*33b1fccfSAndroid Build Coastguard Worker 
98*33b1fccfSAndroid Build Coastguard Worker 		mn = min(e1, e2);
99*33b1fccfSAndroid Build Coastguard Worker 		while (i < mn && cur->data[e1 - i - 1] == data[e2 - i - 1])
100*33b1fccfSAndroid Build Coastguard Worker 			++i;
101*33b1fccfSAndroid Build Coastguard Worker 
102*33b1fccfSAndroid Build Coastguard Worker 		if (!di || i + EROFS_TOF_HASHLEN > deduped) {
103*33b1fccfSAndroid Build Coastguard Worker 			deduped = i + EROFS_TOF_HASHLEN;
104*33b1fccfSAndroid Build Coastguard Worker 			di = cur;
105*33b1fccfSAndroid Build Coastguard Worker 
106*33b1fccfSAndroid Build Coastguard Worker 			/* full match */
107*33b1fccfSAndroid Build Coastguard Worker 			if (i == e2)
108*33b1fccfSAndroid Build Coastguard Worker 				break;
109*33b1fccfSAndroid Build Coastguard Worker 		}
110*33b1fccfSAndroid Build Coastguard Worker 	}
111*33b1fccfSAndroid Build Coastguard Worker 	if (!di)
112*33b1fccfSAndroid Build Coastguard Worker 		goto out;
113*33b1fccfSAndroid Build Coastguard Worker 
114*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(di->length < deduped);
115*33b1fccfSAndroid Build Coastguard Worker 	pos = di->pos + di->length - deduped;
116*33b1fccfSAndroid Build Coastguard Worker 	/* let's read more to dedupe as long as we can */
117*33b1fccfSAndroid Build Coastguard Worker 	if (deduped == di->length) {
118*33b1fccfSAndroid Build Coastguard Worker 		fflush(packedfile);
119*33b1fccfSAndroid Build Coastguard Worker 
120*33b1fccfSAndroid Build Coastguard Worker 		while(deduped < inode->i_size && pos) {
121*33b1fccfSAndroid Build Coastguard Worker 			char buf[2][16384];
122*33b1fccfSAndroid Build Coastguard Worker 			unsigned int sz = min_t(unsigned int, pos,
123*33b1fccfSAndroid Build Coastguard Worker 						sizeof(buf[0]));
124*33b1fccfSAndroid Build Coastguard Worker 
125*33b1fccfSAndroid Build Coastguard Worker 			if (pread(fileno(packedfile), buf[0], sz,
126*33b1fccfSAndroid Build Coastguard Worker 				  pos - sz) != sz)
127*33b1fccfSAndroid Build Coastguard Worker 				break;
128*33b1fccfSAndroid Build Coastguard Worker 			if (pread(fd, buf[1], sz,
129*33b1fccfSAndroid Build Coastguard Worker 				  inode->i_size - deduped - sz) != sz)
130*33b1fccfSAndroid Build Coastguard Worker 				break;
131*33b1fccfSAndroid Build Coastguard Worker 
132*33b1fccfSAndroid Build Coastguard Worker 			if (memcmp(buf[0], buf[1], sz))
133*33b1fccfSAndroid Build Coastguard Worker 				break;
134*33b1fccfSAndroid Build Coastguard Worker 			pos -= sz;
135*33b1fccfSAndroid Build Coastguard Worker 			deduped += sz;
136*33b1fccfSAndroid Build Coastguard Worker 		}
137*33b1fccfSAndroid Build Coastguard Worker 	}
138*33b1fccfSAndroid Build Coastguard Worker 	inode->fragment_size = deduped;
139*33b1fccfSAndroid Build Coastguard Worker 	inode->fragmentoff = pos;
140*33b1fccfSAndroid Build Coastguard Worker 
141*33b1fccfSAndroid Build Coastguard Worker 	erofs_dbg("Dedupe %u tail data at %llu", inode->fragment_size,
142*33b1fccfSAndroid Build Coastguard Worker 		  inode->fragmentoff | 0ULL);
143*33b1fccfSAndroid Build Coastguard Worker out:
144*33b1fccfSAndroid Build Coastguard Worker 	free(data);
145*33b1fccfSAndroid Build Coastguard Worker 	return ret;
146*33b1fccfSAndroid Build Coastguard Worker }
147*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_fragments_dedupe(struct erofs_inode * inode,int fd,u32 * tofcrc)148*33b1fccfSAndroid Build Coastguard Worker int z_erofs_fragments_dedupe(struct erofs_inode *inode, int fd, u32 *tofcrc)
149*33b1fccfSAndroid Build Coastguard Worker {
150*33b1fccfSAndroid Build Coastguard Worker 	u8 data_to_hash[EROFS_TOF_HASHLEN];
151*33b1fccfSAndroid Build Coastguard Worker 	int ret;
152*33b1fccfSAndroid Build Coastguard Worker 
153*33b1fccfSAndroid Build Coastguard Worker 	if (inode->i_size <= EROFS_TOF_HASHLEN)
154*33b1fccfSAndroid Build Coastguard Worker 		return 0;
155*33b1fccfSAndroid Build Coastguard Worker 
156*33b1fccfSAndroid Build Coastguard Worker 	if (erofs_lseek64(fd, inode->i_size - EROFS_TOF_HASHLEN, SEEK_SET) < 0)
157*33b1fccfSAndroid Build Coastguard Worker 		return -errno;
158*33b1fccfSAndroid Build Coastguard Worker 
159*33b1fccfSAndroid Build Coastguard Worker 	ret = read(fd, data_to_hash, EROFS_TOF_HASHLEN);
160*33b1fccfSAndroid Build Coastguard Worker 	if (ret != EROFS_TOF_HASHLEN)
161*33b1fccfSAndroid Build Coastguard Worker 		return -errno;
162*33b1fccfSAndroid Build Coastguard Worker 
163*33b1fccfSAndroid Build Coastguard Worker 	*tofcrc = erofs_crc32c(~0, data_to_hash, EROFS_TOF_HASHLEN);
164*33b1fccfSAndroid Build Coastguard Worker 	ret = z_erofs_fragments_dedupe_find(inode, fd, *tofcrc);
165*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
166*33b1fccfSAndroid Build Coastguard Worker 		return ret;
167*33b1fccfSAndroid Build Coastguard Worker 	ret = lseek(fd, 0, SEEK_SET);
168*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
169*33b1fccfSAndroid Build Coastguard Worker 		return -errno;
170*33b1fccfSAndroid Build Coastguard Worker 	return 0;
171*33b1fccfSAndroid Build Coastguard Worker }
172*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_fragments_dedupe_insert(void * data,unsigned int len,erofs_off_t pos,u32 crc)173*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_fragments_dedupe_insert(void *data, unsigned int len,
174*33b1fccfSAndroid Build Coastguard Worker 					   erofs_off_t pos, u32 crc)
175*33b1fccfSAndroid Build Coastguard Worker {
176*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_fragment_dedupe_item *di;
177*33b1fccfSAndroid Build Coastguard Worker 
178*33b1fccfSAndroid Build Coastguard Worker 	if (len <= EROFS_TOF_HASHLEN)
179*33b1fccfSAndroid Build Coastguard Worker 		return 0;
180*33b1fccfSAndroid Build Coastguard Worker 	if (len > EROFS_CONFIG_COMPR_MAX_SZ) {
181*33b1fccfSAndroid Build Coastguard Worker 		data += len - EROFS_CONFIG_COMPR_MAX_SZ;
182*33b1fccfSAndroid Build Coastguard Worker 		pos += len - EROFS_CONFIG_COMPR_MAX_SZ;
183*33b1fccfSAndroid Build Coastguard Worker 		len = EROFS_CONFIG_COMPR_MAX_SZ;
184*33b1fccfSAndroid Build Coastguard Worker 	}
185*33b1fccfSAndroid Build Coastguard Worker 	di = malloc(sizeof(*di) + len);
186*33b1fccfSAndroid Build Coastguard Worker 	if (!di)
187*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
188*33b1fccfSAndroid Build Coastguard Worker 
189*33b1fccfSAndroid Build Coastguard Worker 	memcpy(di->data, data, len);
190*33b1fccfSAndroid Build Coastguard Worker 	di->length = len;
191*33b1fccfSAndroid Build Coastguard Worker 	di->pos = pos;
192*33b1fccfSAndroid Build Coastguard Worker 
193*33b1fccfSAndroid Build Coastguard Worker 	list_add_tail(&di->list, &dupli_frags[FRAGMENT_HASH(crc)]);
194*33b1fccfSAndroid Build Coastguard Worker 	return 0;
195*33b1fccfSAndroid Build Coastguard Worker }
196*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_fragments_init(void)197*33b1fccfSAndroid Build Coastguard Worker int z_erofs_fragments_init(void)
198*33b1fccfSAndroid Build Coastguard Worker {
199*33b1fccfSAndroid Build Coastguard Worker 	unsigned int i;
200*33b1fccfSAndroid Build Coastguard Worker 
201*33b1fccfSAndroid Build Coastguard Worker 	for (i = 0; i < FRAGMENT_HASHSIZE; ++i)
202*33b1fccfSAndroid Build Coastguard Worker 		init_list_head(&dupli_frags[i]);
203*33b1fccfSAndroid Build Coastguard Worker 	return 0;
204*33b1fccfSAndroid Build Coastguard Worker }
205*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_fragments_exit(void)206*33b1fccfSAndroid Build Coastguard Worker void z_erofs_fragments_exit(void)
207*33b1fccfSAndroid Build Coastguard Worker {
208*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_fragment_dedupe_item *di, *n;
209*33b1fccfSAndroid Build Coastguard Worker 	struct list_head *head;
210*33b1fccfSAndroid Build Coastguard Worker 	unsigned int i;
211*33b1fccfSAndroid Build Coastguard Worker 
212*33b1fccfSAndroid Build Coastguard Worker 	for (i = 0; i < FRAGMENT_HASHSIZE; ++i) {
213*33b1fccfSAndroid Build Coastguard Worker 		head = &dupli_frags[i];
214*33b1fccfSAndroid Build Coastguard Worker 
215*33b1fccfSAndroid Build Coastguard Worker 		list_for_each_entry_safe(di, n, head, list)
216*33b1fccfSAndroid Build Coastguard Worker 			free(di);
217*33b1fccfSAndroid Build Coastguard Worker 	}
218*33b1fccfSAndroid Build Coastguard Worker }
219*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_fragments_commit(struct erofs_inode * inode)220*33b1fccfSAndroid Build Coastguard Worker void z_erofs_fragments_commit(struct erofs_inode *inode)
221*33b1fccfSAndroid Build Coastguard Worker {
222*33b1fccfSAndroid Build Coastguard Worker 	if (!inode->fragment_size)
223*33b1fccfSAndroid Build Coastguard Worker 		return;
224*33b1fccfSAndroid Build Coastguard Worker 	/*
225*33b1fccfSAndroid Build Coastguard Worker 	 * If the packed inode is larger than 4GiB, the full fragmentoff
226*33b1fccfSAndroid Build Coastguard Worker 	 * will be recorded by switching to the noncompact layout anyway.
227*33b1fccfSAndroid Build Coastguard Worker 	 */
228*33b1fccfSAndroid Build Coastguard Worker 	if (inode->fragmentoff >> 32)
229*33b1fccfSAndroid Build Coastguard Worker 		inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
230*33b1fccfSAndroid Build Coastguard Worker 
231*33b1fccfSAndroid Build Coastguard Worker 	inode->z_advise |= Z_EROFS_ADVISE_FRAGMENT_PCLUSTER;
232*33b1fccfSAndroid Build Coastguard Worker 	erofs_sb_set_fragments(inode->sbi);
233*33b1fccfSAndroid Build Coastguard Worker }
234*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_pack_file_from_fd(struct erofs_inode * inode,int fd,u32 tofcrc)235*33b1fccfSAndroid Build Coastguard Worker int z_erofs_pack_file_from_fd(struct erofs_inode *inode, int fd,
236*33b1fccfSAndroid Build Coastguard Worker 			      u32 tofcrc)
237*33b1fccfSAndroid Build Coastguard Worker {
238*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_FTELLO64
239*33b1fccfSAndroid Build Coastguard Worker 	off64_t offset = ftello64(packedfile);
240*33b1fccfSAndroid Build Coastguard Worker #else
241*33b1fccfSAndroid Build Coastguard Worker 	off_t offset = ftello(packedfile);
242*33b1fccfSAndroid Build Coastguard Worker #endif
243*33b1fccfSAndroid Build Coastguard Worker 	char *memblock;
244*33b1fccfSAndroid Build Coastguard Worker 	int rc;
245*33b1fccfSAndroid Build Coastguard Worker 
246*33b1fccfSAndroid Build Coastguard Worker 	if (offset < 0)
247*33b1fccfSAndroid Build Coastguard Worker 		return -errno;
248*33b1fccfSAndroid Build Coastguard Worker 
249*33b1fccfSAndroid Build Coastguard Worker 	inode->fragmentoff = (erofs_off_t)offset;
250*33b1fccfSAndroid Build Coastguard Worker 	inode->fragment_size = inode->i_size;
251*33b1fccfSAndroid Build Coastguard Worker 
252*33b1fccfSAndroid Build Coastguard Worker 	memblock = mmap(NULL, inode->i_size, PROT_READ, MAP_SHARED, fd, 0);
253*33b1fccfSAndroid Build Coastguard Worker 	if (memblock == MAP_FAILED || !memblock) {
254*33b1fccfSAndroid Build Coastguard Worker 		unsigned long long remaining = inode->fragment_size;
255*33b1fccfSAndroid Build Coastguard Worker 
256*33b1fccfSAndroid Build Coastguard Worker 		memblock = NULL;
257*33b1fccfSAndroid Build Coastguard Worker 		while (remaining) {
258*33b1fccfSAndroid Build Coastguard Worker 			char buf[32768];
259*33b1fccfSAndroid Build Coastguard Worker 			unsigned int sz = min_t(unsigned int, remaining,
260*33b1fccfSAndroid Build Coastguard Worker 						sizeof(buf));
261*33b1fccfSAndroid Build Coastguard Worker 
262*33b1fccfSAndroid Build Coastguard Worker 			rc = read(fd, buf, sz);
263*33b1fccfSAndroid Build Coastguard Worker 			if (rc != sz) {
264*33b1fccfSAndroid Build Coastguard Worker 				if (rc < 0)
265*33b1fccfSAndroid Build Coastguard Worker 					rc = -errno;
266*33b1fccfSAndroid Build Coastguard Worker 				else
267*33b1fccfSAndroid Build Coastguard Worker 					rc = -EAGAIN;
268*33b1fccfSAndroid Build Coastguard Worker 				goto out;
269*33b1fccfSAndroid Build Coastguard Worker 			}
270*33b1fccfSAndroid Build Coastguard Worker 			if (fwrite(buf, sz, 1, packedfile) != 1) {
271*33b1fccfSAndroid Build Coastguard Worker 				rc = -EIO;
272*33b1fccfSAndroid Build Coastguard Worker 				goto out;
273*33b1fccfSAndroid Build Coastguard Worker 			}
274*33b1fccfSAndroid Build Coastguard Worker 			remaining -= sz;
275*33b1fccfSAndroid Build Coastguard Worker 		}
276*33b1fccfSAndroid Build Coastguard Worker 		rc = lseek(fd, 0, SEEK_SET);
277*33b1fccfSAndroid Build Coastguard Worker 		if (rc < 0) {
278*33b1fccfSAndroid Build Coastguard Worker 			rc = -errno;
279*33b1fccfSAndroid Build Coastguard Worker 			goto out;
280*33b1fccfSAndroid Build Coastguard Worker 		}
281*33b1fccfSAndroid Build Coastguard Worker 	} else if (fwrite(memblock, inode->fragment_size, 1, packedfile) != 1) {
282*33b1fccfSAndroid Build Coastguard Worker 		rc = -EIO;
283*33b1fccfSAndroid Build Coastguard Worker 		goto out;
284*33b1fccfSAndroid Build Coastguard Worker 	}
285*33b1fccfSAndroid Build Coastguard Worker 
286*33b1fccfSAndroid Build Coastguard Worker 	erofs_dbg("Recording %u fragment data at %lu", inode->fragment_size,
287*33b1fccfSAndroid Build Coastguard Worker 		  inode->fragmentoff);
288*33b1fccfSAndroid Build Coastguard Worker 
289*33b1fccfSAndroid Build Coastguard Worker 	if (memblock)
290*33b1fccfSAndroid Build Coastguard Worker 		rc = z_erofs_fragments_dedupe_insert(memblock,
291*33b1fccfSAndroid Build Coastguard Worker 			inode->fragment_size, inode->fragmentoff, tofcrc);
292*33b1fccfSAndroid Build Coastguard Worker 	else
293*33b1fccfSAndroid Build Coastguard Worker 		rc = 0;
294*33b1fccfSAndroid Build Coastguard Worker out:
295*33b1fccfSAndroid Build Coastguard Worker 	if (memblock)
296*33b1fccfSAndroid Build Coastguard Worker 		munmap(memblock, inode->i_size);
297*33b1fccfSAndroid Build Coastguard Worker 	return rc;
298*33b1fccfSAndroid Build Coastguard Worker }
299*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_pack_fragments(struct erofs_inode * inode,void * data,unsigned int len,u32 tofcrc)300*33b1fccfSAndroid Build Coastguard Worker int z_erofs_pack_fragments(struct erofs_inode *inode, void *data,
301*33b1fccfSAndroid Build Coastguard Worker 			   unsigned int len, u32 tofcrc)
302*33b1fccfSAndroid Build Coastguard Worker {
303*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_FTELLO64
304*33b1fccfSAndroid Build Coastguard Worker 	off64_t offset = ftello64(packedfile);
305*33b1fccfSAndroid Build Coastguard Worker #else
306*33b1fccfSAndroid Build Coastguard Worker 	off_t offset = ftello(packedfile);
307*33b1fccfSAndroid Build Coastguard Worker #endif
308*33b1fccfSAndroid Build Coastguard Worker 	int ret;
309*33b1fccfSAndroid Build Coastguard Worker 
310*33b1fccfSAndroid Build Coastguard Worker 	if (offset < 0)
311*33b1fccfSAndroid Build Coastguard Worker 		return -errno;
312*33b1fccfSAndroid Build Coastguard Worker 
313*33b1fccfSAndroid Build Coastguard Worker 	inode->fragmentoff = (erofs_off_t)offset;
314*33b1fccfSAndroid Build Coastguard Worker 	inode->fragment_size = len;
315*33b1fccfSAndroid Build Coastguard Worker 
316*33b1fccfSAndroid Build Coastguard Worker 	if (fwrite(data, len, 1, packedfile) != 1)
317*33b1fccfSAndroid Build Coastguard Worker 		return -EIO;
318*33b1fccfSAndroid Build Coastguard Worker 
319*33b1fccfSAndroid Build Coastguard Worker 	erofs_dbg("Recording %u fragment data at %lu", inode->fragment_size,
320*33b1fccfSAndroid Build Coastguard Worker 		  inode->fragmentoff);
321*33b1fccfSAndroid Build Coastguard Worker 
322*33b1fccfSAndroid Build Coastguard Worker 	ret = z_erofs_fragments_dedupe_insert(data, len, inode->fragmentoff,
323*33b1fccfSAndroid Build Coastguard Worker 					      tofcrc);
324*33b1fccfSAndroid Build Coastguard Worker 	if (ret)
325*33b1fccfSAndroid Build Coastguard Worker 		return ret;
326*33b1fccfSAndroid Build Coastguard Worker 	return len;
327*33b1fccfSAndroid Build Coastguard Worker }
328*33b1fccfSAndroid Build Coastguard Worker 
erofs_flush_packed_inode(struct erofs_sb_info * sbi)329*33b1fccfSAndroid Build Coastguard Worker int erofs_flush_packed_inode(struct erofs_sb_info *sbi)
330*33b1fccfSAndroid Build Coastguard Worker {
331*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *inode;
332*33b1fccfSAndroid Build Coastguard Worker 
333*33b1fccfSAndroid Build Coastguard Worker 	if (!erofs_sb_has_fragments(sbi))
334*33b1fccfSAndroid Build Coastguard Worker 		return -EINVAL;
335*33b1fccfSAndroid Build Coastguard Worker 	fflush(packedfile);
336*33b1fccfSAndroid Build Coastguard Worker 	if (!ftello(packedfile))
337*33b1fccfSAndroid Build Coastguard Worker 		return 0;
338*33b1fccfSAndroid Build Coastguard Worker 
339*33b1fccfSAndroid Build Coastguard Worker 	inode = erofs_mkfs_build_special_from_fd(sbi, fileno(packedfile),
340*33b1fccfSAndroid Build Coastguard Worker 						 EROFS_PACKED_INODE);
341*33b1fccfSAndroid Build Coastguard Worker 	sbi->packed_nid = erofs_lookupnid(inode);
342*33b1fccfSAndroid Build Coastguard Worker 	erofs_iput(inode);
343*33b1fccfSAndroid Build Coastguard Worker 	return 0;
344*33b1fccfSAndroid Build Coastguard Worker }
345*33b1fccfSAndroid Build Coastguard Worker 
erofs_packedfile_exit(void)346*33b1fccfSAndroid Build Coastguard Worker void erofs_packedfile_exit(void)
347*33b1fccfSAndroid Build Coastguard Worker {
348*33b1fccfSAndroid Build Coastguard Worker 	if (packedfile)
349*33b1fccfSAndroid Build Coastguard Worker 		fclose(packedfile);
350*33b1fccfSAndroid Build Coastguard Worker }
351*33b1fccfSAndroid Build Coastguard Worker 
erofs_packedfile_init(void)352*33b1fccfSAndroid Build Coastguard Worker FILE *erofs_packedfile_init(void)
353*33b1fccfSAndroid Build Coastguard Worker {
354*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_TMPFILE64
355*33b1fccfSAndroid Build Coastguard Worker 	packedfile = tmpfile64();
356*33b1fccfSAndroid Build Coastguard Worker #else
357*33b1fccfSAndroid Build Coastguard Worker 	packedfile = tmpfile();
358*33b1fccfSAndroid Build Coastguard Worker #endif
359*33b1fccfSAndroid Build Coastguard Worker 	if (!packedfile)
360*33b1fccfSAndroid Build Coastguard Worker 		return ERR_PTR(-ENOMEM);
361*33b1fccfSAndroid Build Coastguard Worker 	return packedfile;
362*33b1fccfSAndroid Build Coastguard Worker }
363