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