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) 2018-2019 HUAWEI, Inc.
4*33b1fccfSAndroid Build Coastguard Worker * http://www.huawei.com/
5*33b1fccfSAndroid Build Coastguard Worker * Created by Li Guifu <[email protected]>
6*33b1fccfSAndroid Build Coastguard Worker * with heavy changes by Gao Xiang <[email protected]>
7*33b1fccfSAndroid Build Coastguard Worker */
8*33b1fccfSAndroid Build Coastguard Worker #define _GNU_SOURCE
9*33b1fccfSAndroid Build Coastguard Worker #include <string.h>
10*33b1fccfSAndroid Build Coastguard Worker #include <stdlib.h>
11*33b1fccfSAndroid Build Coastguard Worker #include <stdio.h>
12*33b1fccfSAndroid Build Coastguard Worker #include <sys/stat.h>
13*33b1fccfSAndroid Build Coastguard Worker #include <config.h>
14*33b1fccfSAndroid Build Coastguard Worker #if defined(HAVE_SYS_SYSMACROS_H)
15*33b1fccfSAndroid Build Coastguard Worker #include <sys/sysmacros.h>
16*33b1fccfSAndroid Build Coastguard Worker #endif
17*33b1fccfSAndroid Build Coastguard Worker #include <dirent.h>
18*33b1fccfSAndroid Build Coastguard Worker #include "erofs/print.h"
19*33b1fccfSAndroid Build Coastguard Worker #include "erofs/diskbuf.h"
20*33b1fccfSAndroid Build Coastguard Worker #include "erofs/inode.h"
21*33b1fccfSAndroid Build Coastguard Worker #include "erofs/cache.h"
22*33b1fccfSAndroid Build Coastguard Worker #include "erofs/compress.h"
23*33b1fccfSAndroid Build Coastguard Worker #include "erofs/xattr.h"
24*33b1fccfSAndroid Build Coastguard Worker #include "erofs/exclude.h"
25*33b1fccfSAndroid Build Coastguard Worker #include "erofs/block_list.h"
26*33b1fccfSAndroid Build Coastguard Worker #include "erofs/compress_hints.h"
27*33b1fccfSAndroid Build Coastguard Worker #include "erofs/blobchunk.h"
28*33b1fccfSAndroid Build Coastguard Worker #include "erofs/fragments.h"
29*33b1fccfSAndroid Build Coastguard Worker #include "liberofs_private.h"
30*33b1fccfSAndroid Build Coastguard Worker
31*33b1fccfSAndroid Build Coastguard Worker #define S_SHIFT 12
32*33b1fccfSAndroid Build Coastguard Worker static unsigned char erofs_ftype_by_mode[S_IFMT >> S_SHIFT] = {
33*33b1fccfSAndroid Build Coastguard Worker [S_IFREG >> S_SHIFT] = EROFS_FT_REG_FILE,
34*33b1fccfSAndroid Build Coastguard Worker [S_IFDIR >> S_SHIFT] = EROFS_FT_DIR,
35*33b1fccfSAndroid Build Coastguard Worker [S_IFCHR >> S_SHIFT] = EROFS_FT_CHRDEV,
36*33b1fccfSAndroid Build Coastguard Worker [S_IFBLK >> S_SHIFT] = EROFS_FT_BLKDEV,
37*33b1fccfSAndroid Build Coastguard Worker [S_IFIFO >> S_SHIFT] = EROFS_FT_FIFO,
38*33b1fccfSAndroid Build Coastguard Worker [S_IFSOCK >> S_SHIFT] = EROFS_FT_SOCK,
39*33b1fccfSAndroid Build Coastguard Worker [S_IFLNK >> S_SHIFT] = EROFS_FT_SYMLINK,
40*33b1fccfSAndroid Build Coastguard Worker };
41*33b1fccfSAndroid Build Coastguard Worker
erofs_mode_to_ftype(umode_t mode)42*33b1fccfSAndroid Build Coastguard Worker unsigned char erofs_mode_to_ftype(umode_t mode)
43*33b1fccfSAndroid Build Coastguard Worker {
44*33b1fccfSAndroid Build Coastguard Worker return erofs_ftype_by_mode[(mode & S_IFMT) >> S_SHIFT];
45*33b1fccfSAndroid Build Coastguard Worker }
46*33b1fccfSAndroid Build Coastguard Worker
47*33b1fccfSAndroid Build Coastguard Worker static const unsigned char erofs_dtype_by_ftype[EROFS_FT_MAX] = {
48*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_UNKNOWN] = DT_UNKNOWN,
49*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_REG_FILE] = DT_REG,
50*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_DIR] = DT_DIR,
51*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_CHRDEV] = DT_CHR,
52*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_BLKDEV] = DT_BLK,
53*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_FIFO] = DT_FIFO,
54*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_SOCK] = DT_SOCK,
55*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_SYMLINK] = DT_LNK
56*33b1fccfSAndroid Build Coastguard Worker };
57*33b1fccfSAndroid Build Coastguard Worker
58*33b1fccfSAndroid Build Coastguard Worker static const umode_t erofs_dtype_by_umode[EROFS_FT_MAX] = {
59*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_UNKNOWN] = S_IFMT,
60*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_REG_FILE] = S_IFREG,
61*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_DIR] = S_IFDIR,
62*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_CHRDEV] = S_IFCHR,
63*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_BLKDEV] = S_IFBLK,
64*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_FIFO] = S_IFIFO,
65*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_SOCK] = S_IFSOCK,
66*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_SYMLINK] = S_IFLNK
67*33b1fccfSAndroid Build Coastguard Worker };
68*33b1fccfSAndroid Build Coastguard Worker
erofs_ftype_to_mode(unsigned int ftype,unsigned int perm)69*33b1fccfSAndroid Build Coastguard Worker umode_t erofs_ftype_to_mode(unsigned int ftype, unsigned int perm)
70*33b1fccfSAndroid Build Coastguard Worker {
71*33b1fccfSAndroid Build Coastguard Worker if (ftype >= EROFS_FT_MAX)
72*33b1fccfSAndroid Build Coastguard Worker ftype = EROFS_FT_UNKNOWN;
73*33b1fccfSAndroid Build Coastguard Worker
74*33b1fccfSAndroid Build Coastguard Worker return erofs_dtype_by_umode[ftype] | perm;
75*33b1fccfSAndroid Build Coastguard Worker }
76*33b1fccfSAndroid Build Coastguard Worker
erofs_ftype_to_dtype(unsigned int filetype)77*33b1fccfSAndroid Build Coastguard Worker unsigned char erofs_ftype_to_dtype(unsigned int filetype)
78*33b1fccfSAndroid Build Coastguard Worker {
79*33b1fccfSAndroid Build Coastguard Worker if (filetype >= EROFS_FT_MAX)
80*33b1fccfSAndroid Build Coastguard Worker return DT_UNKNOWN;
81*33b1fccfSAndroid Build Coastguard Worker
82*33b1fccfSAndroid Build Coastguard Worker return erofs_dtype_by_ftype[filetype];
83*33b1fccfSAndroid Build Coastguard Worker }
84*33b1fccfSAndroid Build Coastguard Worker
85*33b1fccfSAndroid Build Coastguard Worker #define NR_INODE_HASHTABLE 16384
86*33b1fccfSAndroid Build Coastguard Worker
87*33b1fccfSAndroid Build Coastguard Worker struct list_head inode_hashtable[NR_INODE_HASHTABLE];
88*33b1fccfSAndroid Build Coastguard Worker
erofs_inode_manager_init(void)89*33b1fccfSAndroid Build Coastguard Worker void erofs_inode_manager_init(void)
90*33b1fccfSAndroid Build Coastguard Worker {
91*33b1fccfSAndroid Build Coastguard Worker unsigned int i;
92*33b1fccfSAndroid Build Coastguard Worker
93*33b1fccfSAndroid Build Coastguard Worker for (i = 0; i < NR_INODE_HASHTABLE; ++i)
94*33b1fccfSAndroid Build Coastguard Worker init_list_head(&inode_hashtable[i]);
95*33b1fccfSAndroid Build Coastguard Worker }
96*33b1fccfSAndroid Build Coastguard Worker
erofs_insert_ihash(struct erofs_inode * inode)97*33b1fccfSAndroid Build Coastguard Worker void erofs_insert_ihash(struct erofs_inode *inode)
98*33b1fccfSAndroid Build Coastguard Worker {
99*33b1fccfSAndroid Build Coastguard Worker unsigned int nr = (inode->i_ino[1] ^ inode->dev) % NR_INODE_HASHTABLE;
100*33b1fccfSAndroid Build Coastguard Worker
101*33b1fccfSAndroid Build Coastguard Worker list_add(&inode->i_hash, &inode_hashtable[nr]);
102*33b1fccfSAndroid Build Coastguard Worker }
103*33b1fccfSAndroid Build Coastguard Worker
104*33b1fccfSAndroid Build Coastguard Worker /* get the inode from the (source) inode # */
erofs_iget(dev_t dev,ino_t ino)105*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *erofs_iget(dev_t dev, ino_t ino)
106*33b1fccfSAndroid Build Coastguard Worker {
107*33b1fccfSAndroid Build Coastguard Worker struct list_head *head =
108*33b1fccfSAndroid Build Coastguard Worker &inode_hashtable[(ino ^ dev) % NR_INODE_HASHTABLE];
109*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *inode;
110*33b1fccfSAndroid Build Coastguard Worker
111*33b1fccfSAndroid Build Coastguard Worker list_for_each_entry(inode, head, i_hash)
112*33b1fccfSAndroid Build Coastguard Worker if (inode->i_ino[1] == ino && inode->dev == dev)
113*33b1fccfSAndroid Build Coastguard Worker return erofs_igrab(inode);
114*33b1fccfSAndroid Build Coastguard Worker return NULL;
115*33b1fccfSAndroid Build Coastguard Worker }
116*33b1fccfSAndroid Build Coastguard Worker
erofs_iget_by_nid(erofs_nid_t nid)117*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *erofs_iget_by_nid(erofs_nid_t nid)
118*33b1fccfSAndroid Build Coastguard Worker {
119*33b1fccfSAndroid Build Coastguard Worker struct list_head *head =
120*33b1fccfSAndroid Build Coastguard Worker &inode_hashtable[nid % NR_INODE_HASHTABLE];
121*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *inode;
122*33b1fccfSAndroid Build Coastguard Worker
123*33b1fccfSAndroid Build Coastguard Worker list_for_each_entry(inode, head, i_hash)
124*33b1fccfSAndroid Build Coastguard Worker if (inode->nid == nid)
125*33b1fccfSAndroid Build Coastguard Worker return erofs_igrab(inode);
126*33b1fccfSAndroid Build Coastguard Worker return NULL;
127*33b1fccfSAndroid Build Coastguard Worker }
128*33b1fccfSAndroid Build Coastguard Worker
erofs_iput(struct erofs_inode * inode)129*33b1fccfSAndroid Build Coastguard Worker unsigned int erofs_iput(struct erofs_inode *inode)
130*33b1fccfSAndroid Build Coastguard Worker {
131*33b1fccfSAndroid Build Coastguard Worker struct erofs_dentry *d, *t;
132*33b1fccfSAndroid Build Coastguard Worker unsigned long got = erofs_atomic_dec_return(&inode->i_count);
133*33b1fccfSAndroid Build Coastguard Worker
134*33b1fccfSAndroid Build Coastguard Worker if (got >= 1)
135*33b1fccfSAndroid Build Coastguard Worker return got;
136*33b1fccfSAndroid Build Coastguard Worker
137*33b1fccfSAndroid Build Coastguard Worker list_for_each_entry_safe(d, t, &inode->i_subdirs, d_child)
138*33b1fccfSAndroid Build Coastguard Worker free(d);
139*33b1fccfSAndroid Build Coastguard Worker
140*33b1fccfSAndroid Build Coastguard Worker free(inode->compressmeta);
141*33b1fccfSAndroid Build Coastguard Worker if (inode->eof_tailraw)
142*33b1fccfSAndroid Build Coastguard Worker free(inode->eof_tailraw);
143*33b1fccfSAndroid Build Coastguard Worker list_del(&inode->i_hash);
144*33b1fccfSAndroid Build Coastguard Worker if (inode->i_srcpath)
145*33b1fccfSAndroid Build Coastguard Worker free(inode->i_srcpath);
146*33b1fccfSAndroid Build Coastguard Worker
147*33b1fccfSAndroid Build Coastguard Worker if (inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF) {
148*33b1fccfSAndroid Build Coastguard Worker erofs_diskbuf_close(inode->i_diskbuf);
149*33b1fccfSAndroid Build Coastguard Worker free(inode->i_diskbuf);
150*33b1fccfSAndroid Build Coastguard Worker } else if (inode->i_link) {
151*33b1fccfSAndroid Build Coastguard Worker free(inode->i_link);
152*33b1fccfSAndroid Build Coastguard Worker }
153*33b1fccfSAndroid Build Coastguard Worker free(inode);
154*33b1fccfSAndroid Build Coastguard Worker return 0;
155*33b1fccfSAndroid Build Coastguard Worker }
156*33b1fccfSAndroid Build Coastguard Worker
erofs_d_alloc(struct erofs_inode * parent,const char * name)157*33b1fccfSAndroid Build Coastguard Worker struct erofs_dentry *erofs_d_alloc(struct erofs_inode *parent,
158*33b1fccfSAndroid Build Coastguard Worker const char *name)
159*33b1fccfSAndroid Build Coastguard Worker {
160*33b1fccfSAndroid Build Coastguard Worker struct erofs_dentry *d = malloc(sizeof(*d));
161*33b1fccfSAndroid Build Coastguard Worker
162*33b1fccfSAndroid Build Coastguard Worker if (!d)
163*33b1fccfSAndroid Build Coastguard Worker return ERR_PTR(-ENOMEM);
164*33b1fccfSAndroid Build Coastguard Worker
165*33b1fccfSAndroid Build Coastguard Worker strncpy(d->name, name, EROFS_NAME_LEN - 1);
166*33b1fccfSAndroid Build Coastguard Worker d->name[EROFS_NAME_LEN - 1] = '\0';
167*33b1fccfSAndroid Build Coastguard Worker d->inode = NULL;
168*33b1fccfSAndroid Build Coastguard Worker d->type = EROFS_FT_UNKNOWN;
169*33b1fccfSAndroid Build Coastguard Worker d->validnid = false;
170*33b1fccfSAndroid Build Coastguard Worker list_add_tail(&d->d_child, &parent->i_subdirs);
171*33b1fccfSAndroid Build Coastguard Worker return d;
172*33b1fccfSAndroid Build Coastguard Worker }
173*33b1fccfSAndroid Build Coastguard Worker
174*33b1fccfSAndroid Build Coastguard Worker /* allocate main data for a inode */
__allocate_inode_bh_data(struct erofs_inode * inode,unsigned long nblocks,int type)175*33b1fccfSAndroid Build Coastguard Worker static int __allocate_inode_bh_data(struct erofs_inode *inode,
176*33b1fccfSAndroid Build Coastguard Worker unsigned long nblocks,
177*33b1fccfSAndroid Build Coastguard Worker int type)
178*33b1fccfSAndroid Build Coastguard Worker {
179*33b1fccfSAndroid Build Coastguard Worker struct erofs_bufmgr *bmgr = inode->sbi->bmgr;
180*33b1fccfSAndroid Build Coastguard Worker struct erofs_buffer_head *bh;
181*33b1fccfSAndroid Build Coastguard Worker int ret;
182*33b1fccfSAndroid Build Coastguard Worker
183*33b1fccfSAndroid Build Coastguard Worker if (!nblocks) {
184*33b1fccfSAndroid Build Coastguard Worker /* it has only tail-end data */
185*33b1fccfSAndroid Build Coastguard Worker inode->u.i_blkaddr = NULL_ADDR;
186*33b1fccfSAndroid Build Coastguard Worker return 0;
187*33b1fccfSAndroid Build Coastguard Worker }
188*33b1fccfSAndroid Build Coastguard Worker
189*33b1fccfSAndroid Build Coastguard Worker /* allocate main data buffer */
190*33b1fccfSAndroid Build Coastguard Worker bh = erofs_balloc(bmgr, type, erofs_pos(inode->sbi, nblocks), 0, 0);
191*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(bh))
192*33b1fccfSAndroid Build Coastguard Worker return PTR_ERR(bh);
193*33b1fccfSAndroid Build Coastguard Worker
194*33b1fccfSAndroid Build Coastguard Worker bh->op = &erofs_skip_write_bhops;
195*33b1fccfSAndroid Build Coastguard Worker inode->bh_data = bh;
196*33b1fccfSAndroid Build Coastguard Worker
197*33b1fccfSAndroid Build Coastguard Worker /* get blkaddr of the bh */
198*33b1fccfSAndroid Build Coastguard Worker ret = erofs_mapbh(NULL, bh->block);
199*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(ret < 0);
200*33b1fccfSAndroid Build Coastguard Worker
201*33b1fccfSAndroid Build Coastguard Worker /* write blocks except for the tail-end block */
202*33b1fccfSAndroid Build Coastguard Worker inode->u.i_blkaddr = bh->block->blkaddr;
203*33b1fccfSAndroid Build Coastguard Worker return 0;
204*33b1fccfSAndroid Build Coastguard Worker }
205*33b1fccfSAndroid Build Coastguard Worker
comp_subdir(const void * a,const void * b)206*33b1fccfSAndroid Build Coastguard Worker static int comp_subdir(const void *a, const void *b)
207*33b1fccfSAndroid Build Coastguard Worker {
208*33b1fccfSAndroid Build Coastguard Worker const struct erofs_dentry *da, *db;
209*33b1fccfSAndroid Build Coastguard Worker
210*33b1fccfSAndroid Build Coastguard Worker da = *((const struct erofs_dentry **)a);
211*33b1fccfSAndroid Build Coastguard Worker db = *((const struct erofs_dentry **)b);
212*33b1fccfSAndroid Build Coastguard Worker return strcmp(da->name, db->name);
213*33b1fccfSAndroid Build Coastguard Worker }
214*33b1fccfSAndroid Build Coastguard Worker
erofs_init_empty_dir(struct erofs_inode * dir)215*33b1fccfSAndroid Build Coastguard Worker int erofs_init_empty_dir(struct erofs_inode *dir)
216*33b1fccfSAndroid Build Coastguard Worker {
217*33b1fccfSAndroid Build Coastguard Worker struct erofs_dentry *d;
218*33b1fccfSAndroid Build Coastguard Worker
219*33b1fccfSAndroid Build Coastguard Worker /* dot is pointed to the current dir inode */
220*33b1fccfSAndroid Build Coastguard Worker d = erofs_d_alloc(dir, ".");
221*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(d))
222*33b1fccfSAndroid Build Coastguard Worker return PTR_ERR(d);
223*33b1fccfSAndroid Build Coastguard Worker d->inode = erofs_igrab(dir);
224*33b1fccfSAndroid Build Coastguard Worker d->type = EROFS_FT_DIR;
225*33b1fccfSAndroid Build Coastguard Worker
226*33b1fccfSAndroid Build Coastguard Worker /* dotdot is pointed to the parent dir */
227*33b1fccfSAndroid Build Coastguard Worker d = erofs_d_alloc(dir, "..");
228*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(d))
229*33b1fccfSAndroid Build Coastguard Worker return PTR_ERR(d);
230*33b1fccfSAndroid Build Coastguard Worker d->inode = erofs_igrab(erofs_parent_inode(dir));
231*33b1fccfSAndroid Build Coastguard Worker d->type = EROFS_FT_DIR;
232*33b1fccfSAndroid Build Coastguard Worker
233*33b1fccfSAndroid Build Coastguard Worker dir->i_nlink = 2;
234*33b1fccfSAndroid Build Coastguard Worker return 0;
235*33b1fccfSAndroid Build Coastguard Worker }
236*33b1fccfSAndroid Build Coastguard Worker
erofs_prepare_dir_file(struct erofs_inode * dir,unsigned int nr_subdirs)237*33b1fccfSAndroid Build Coastguard Worker static int erofs_prepare_dir_file(struct erofs_inode *dir,
238*33b1fccfSAndroid Build Coastguard Worker unsigned int nr_subdirs)
239*33b1fccfSAndroid Build Coastguard Worker {
240*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = dir->sbi;
241*33b1fccfSAndroid Build Coastguard Worker struct erofs_dentry *d, *n, **sorted_d;
242*33b1fccfSAndroid Build Coastguard Worker unsigned int i;
243*33b1fccfSAndroid Build Coastguard Worker unsigned int d_size = 0;
244*33b1fccfSAndroid Build Coastguard Worker
245*33b1fccfSAndroid Build Coastguard Worker sorted_d = malloc(nr_subdirs * sizeof(d));
246*33b1fccfSAndroid Build Coastguard Worker if (!sorted_d)
247*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
248*33b1fccfSAndroid Build Coastguard Worker i = 0;
249*33b1fccfSAndroid Build Coastguard Worker list_for_each_entry_safe(d, n, &dir->i_subdirs, d_child) {
250*33b1fccfSAndroid Build Coastguard Worker list_del(&d->d_child);
251*33b1fccfSAndroid Build Coastguard Worker sorted_d[i++] = d;
252*33b1fccfSAndroid Build Coastguard Worker }
253*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(i != nr_subdirs);
254*33b1fccfSAndroid Build Coastguard Worker qsort(sorted_d, nr_subdirs, sizeof(d), comp_subdir);
255*33b1fccfSAndroid Build Coastguard Worker for (i = 0; i < nr_subdirs; i++)
256*33b1fccfSAndroid Build Coastguard Worker list_add_tail(&sorted_d[i]->d_child, &dir->i_subdirs);
257*33b1fccfSAndroid Build Coastguard Worker free(sorted_d);
258*33b1fccfSAndroid Build Coastguard Worker
259*33b1fccfSAndroid Build Coastguard Worker /* let's calculate dir size */
260*33b1fccfSAndroid Build Coastguard Worker list_for_each_entry(d, &dir->i_subdirs, d_child) {
261*33b1fccfSAndroid Build Coastguard Worker int len = strlen(d->name) + sizeof(struct erofs_dirent);
262*33b1fccfSAndroid Build Coastguard Worker
263*33b1fccfSAndroid Build Coastguard Worker if (erofs_blkoff(sbi, d_size) + len > erofs_blksiz(sbi))
264*33b1fccfSAndroid Build Coastguard Worker d_size = round_up(d_size, erofs_blksiz(sbi));
265*33b1fccfSAndroid Build Coastguard Worker d_size += len;
266*33b1fccfSAndroid Build Coastguard Worker }
267*33b1fccfSAndroid Build Coastguard Worker dir->i_size = d_size;
268*33b1fccfSAndroid Build Coastguard Worker
269*33b1fccfSAndroid Build Coastguard Worker /* no compression for all dirs */
270*33b1fccfSAndroid Build Coastguard Worker dir->datalayout = EROFS_INODE_FLAT_INLINE;
271*33b1fccfSAndroid Build Coastguard Worker
272*33b1fccfSAndroid Build Coastguard Worker /* it will be used in erofs_prepare_inode_buffer */
273*33b1fccfSAndroid Build Coastguard Worker dir->idata_size = d_size % erofs_blksiz(sbi);
274*33b1fccfSAndroid Build Coastguard Worker return 0;
275*33b1fccfSAndroid Build Coastguard Worker }
276*33b1fccfSAndroid Build Coastguard Worker
fill_dirblock(char * buf,unsigned int size,unsigned int q,struct erofs_dentry * head,struct erofs_dentry * end)277*33b1fccfSAndroid Build Coastguard Worker static void fill_dirblock(char *buf, unsigned int size, unsigned int q,
278*33b1fccfSAndroid Build Coastguard Worker struct erofs_dentry *head, struct erofs_dentry *end)
279*33b1fccfSAndroid Build Coastguard Worker {
280*33b1fccfSAndroid Build Coastguard Worker unsigned int p = 0;
281*33b1fccfSAndroid Build Coastguard Worker
282*33b1fccfSAndroid Build Coastguard Worker /* write out all erofs_dirents + filenames */
283*33b1fccfSAndroid Build Coastguard Worker while (head != end) {
284*33b1fccfSAndroid Build Coastguard Worker const unsigned int namelen = strlen(head->name);
285*33b1fccfSAndroid Build Coastguard Worker struct erofs_dirent d = {
286*33b1fccfSAndroid Build Coastguard Worker .nid = cpu_to_le64(head->nid),
287*33b1fccfSAndroid Build Coastguard Worker .nameoff = cpu_to_le16(q),
288*33b1fccfSAndroid Build Coastguard Worker .file_type = head->type,
289*33b1fccfSAndroid Build Coastguard Worker };
290*33b1fccfSAndroid Build Coastguard Worker
291*33b1fccfSAndroid Build Coastguard Worker memcpy(buf + p, &d, sizeof(d));
292*33b1fccfSAndroid Build Coastguard Worker memcpy(buf + q, head->name, namelen);
293*33b1fccfSAndroid Build Coastguard Worker p += sizeof(d);
294*33b1fccfSAndroid Build Coastguard Worker q += namelen;
295*33b1fccfSAndroid Build Coastguard Worker
296*33b1fccfSAndroid Build Coastguard Worker head = list_next_entry(head, d_child);
297*33b1fccfSAndroid Build Coastguard Worker }
298*33b1fccfSAndroid Build Coastguard Worker memset(buf + q, 0, size - q);
299*33b1fccfSAndroid Build Coastguard Worker }
300*33b1fccfSAndroid Build Coastguard Worker
write_dirblock(struct erofs_sb_info * sbi,unsigned int q,struct erofs_dentry * head,struct erofs_dentry * end,erofs_blk_t blkaddr)301*33b1fccfSAndroid Build Coastguard Worker static int write_dirblock(struct erofs_sb_info *sbi,
302*33b1fccfSAndroid Build Coastguard Worker unsigned int q, struct erofs_dentry *head,
303*33b1fccfSAndroid Build Coastguard Worker struct erofs_dentry *end, erofs_blk_t blkaddr)
304*33b1fccfSAndroid Build Coastguard Worker {
305*33b1fccfSAndroid Build Coastguard Worker char buf[EROFS_MAX_BLOCK_SIZE];
306*33b1fccfSAndroid Build Coastguard Worker
307*33b1fccfSAndroid Build Coastguard Worker fill_dirblock(buf, erofs_blksiz(sbi), q, head, end);
308*33b1fccfSAndroid Build Coastguard Worker return erofs_blk_write(sbi, buf, blkaddr, 1);
309*33b1fccfSAndroid Build Coastguard Worker }
310*33b1fccfSAndroid Build Coastguard Worker
erofs_lookupnid(struct erofs_inode * inode)311*33b1fccfSAndroid Build Coastguard Worker erofs_nid_t erofs_lookupnid(struct erofs_inode *inode)
312*33b1fccfSAndroid Build Coastguard Worker {
313*33b1fccfSAndroid Build Coastguard Worker struct erofs_buffer_head *const bh = inode->bh;
314*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = inode->sbi;
315*33b1fccfSAndroid Build Coastguard Worker erofs_off_t off, meta_offset;
316*33b1fccfSAndroid Build Coastguard Worker
317*33b1fccfSAndroid Build Coastguard Worker if (bh && (long long)inode->nid <= 0) {
318*33b1fccfSAndroid Build Coastguard Worker erofs_mapbh(NULL, bh->block);
319*33b1fccfSAndroid Build Coastguard Worker off = erofs_btell(bh, false);
320*33b1fccfSAndroid Build Coastguard Worker
321*33b1fccfSAndroid Build Coastguard Worker meta_offset = erofs_pos(sbi, sbi->meta_blkaddr);
322*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(off < meta_offset);
323*33b1fccfSAndroid Build Coastguard Worker inode->nid = (off - meta_offset) >> EROFS_ISLOTBITS;
324*33b1fccfSAndroid Build Coastguard Worker erofs_dbg("Assign nid %llu to file %s (mode %05o)",
325*33b1fccfSAndroid Build Coastguard Worker inode->nid, inode->i_srcpath, inode->i_mode);
326*33b1fccfSAndroid Build Coastguard Worker }
327*33b1fccfSAndroid Build Coastguard Worker if (__erofs_unlikely(IS_ROOT(inode)) && inode->nid > 0xffff)
328*33b1fccfSAndroid Build Coastguard Worker return sbi->root_nid;
329*33b1fccfSAndroid Build Coastguard Worker return inode->nid;
330*33b1fccfSAndroid Build Coastguard Worker }
331*33b1fccfSAndroid Build Coastguard Worker
erofs_d_invalidate(struct erofs_dentry * d)332*33b1fccfSAndroid Build Coastguard Worker static void erofs_d_invalidate(struct erofs_dentry *d)
333*33b1fccfSAndroid Build Coastguard Worker {
334*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *const inode = d->inode;
335*33b1fccfSAndroid Build Coastguard Worker
336*33b1fccfSAndroid Build Coastguard Worker if (d->validnid)
337*33b1fccfSAndroid Build Coastguard Worker return;
338*33b1fccfSAndroid Build Coastguard Worker d->nid = erofs_lookupnid(inode);
339*33b1fccfSAndroid Build Coastguard Worker d->validnid = true;
340*33b1fccfSAndroid Build Coastguard Worker erofs_iput(inode);
341*33b1fccfSAndroid Build Coastguard Worker }
342*33b1fccfSAndroid Build Coastguard Worker
erofs_rebuild_inode_fix_pnid(struct erofs_inode * parent,erofs_nid_t nid)343*33b1fccfSAndroid Build Coastguard Worker static int erofs_rebuild_inode_fix_pnid(struct erofs_inode *parent,
344*33b1fccfSAndroid Build Coastguard Worker erofs_nid_t nid)
345*33b1fccfSAndroid Build Coastguard Worker {
346*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode dir = {
347*33b1fccfSAndroid Build Coastguard Worker .sbi = parent->sbi,
348*33b1fccfSAndroid Build Coastguard Worker .nid = nid
349*33b1fccfSAndroid Build Coastguard Worker };
350*33b1fccfSAndroid Build Coastguard Worker unsigned int bsz = erofs_blksiz(dir.sbi);
351*33b1fccfSAndroid Build Coastguard Worker unsigned int err, isz;
352*33b1fccfSAndroid Build Coastguard Worker erofs_off_t boff, off;
353*33b1fccfSAndroid Build Coastguard Worker erofs_nid_t pnid;
354*33b1fccfSAndroid Build Coastguard Worker bool fixed = false;
355*33b1fccfSAndroid Build Coastguard Worker
356*33b1fccfSAndroid Build Coastguard Worker err = erofs_read_inode_from_disk(&dir);
357*33b1fccfSAndroid Build Coastguard Worker if (err)
358*33b1fccfSAndroid Build Coastguard Worker return err;
359*33b1fccfSAndroid Build Coastguard Worker
360*33b1fccfSAndroid Build Coastguard Worker if (!S_ISDIR(dir.i_mode))
361*33b1fccfSAndroid Build Coastguard Worker return -ENOTDIR;
362*33b1fccfSAndroid Build Coastguard Worker
363*33b1fccfSAndroid Build Coastguard Worker if (dir.datalayout != EROFS_INODE_FLAT_INLINE &&
364*33b1fccfSAndroid Build Coastguard Worker dir.datalayout != EROFS_INODE_FLAT_PLAIN)
365*33b1fccfSAndroid Build Coastguard Worker return -EOPNOTSUPP;
366*33b1fccfSAndroid Build Coastguard Worker
367*33b1fccfSAndroid Build Coastguard Worker pnid = erofs_lookupnid(parent);
368*33b1fccfSAndroid Build Coastguard Worker isz = dir.inode_isize + dir.xattr_isize;
369*33b1fccfSAndroid Build Coastguard Worker boff = erofs_pos(dir.sbi, dir.u.i_blkaddr);
370*33b1fccfSAndroid Build Coastguard Worker for (off = 0; off < dir.i_size; off += bsz) {
371*33b1fccfSAndroid Build Coastguard Worker char buf[EROFS_MAX_BLOCK_SIZE];
372*33b1fccfSAndroid Build Coastguard Worker struct erofs_dirent *de = (struct erofs_dirent *)buf;
373*33b1fccfSAndroid Build Coastguard Worker unsigned int nameoff, count, de_nameoff;
374*33b1fccfSAndroid Build Coastguard Worker
375*33b1fccfSAndroid Build Coastguard Worker count = min_t(erofs_off_t, bsz, dir.i_size - off);
376*33b1fccfSAndroid Build Coastguard Worker err = erofs_pread(&dir, buf, count, off);
377*33b1fccfSAndroid Build Coastguard Worker if (err)
378*33b1fccfSAndroid Build Coastguard Worker return err;
379*33b1fccfSAndroid Build Coastguard Worker
380*33b1fccfSAndroid Build Coastguard Worker nameoff = le16_to_cpu(de->nameoff);
381*33b1fccfSAndroid Build Coastguard Worker if (nameoff < sizeof(struct erofs_dirent) ||
382*33b1fccfSAndroid Build Coastguard Worker nameoff >= count) {
383*33b1fccfSAndroid Build Coastguard Worker erofs_err("invalid de[0].nameoff %u @ nid %llu, offset %llu",
384*33b1fccfSAndroid Build Coastguard Worker nameoff, dir.nid | 0ULL, off | 0ULL);
385*33b1fccfSAndroid Build Coastguard Worker return -EFSCORRUPTED;
386*33b1fccfSAndroid Build Coastguard Worker }
387*33b1fccfSAndroid Build Coastguard Worker
388*33b1fccfSAndroid Build Coastguard Worker while ((char *)de < buf + nameoff) {
389*33b1fccfSAndroid Build Coastguard Worker de_nameoff = le16_to_cpu(de->nameoff);
390*33b1fccfSAndroid Build Coastguard Worker if (((char *)(de + 1) >= buf + nameoff ?
391*33b1fccfSAndroid Build Coastguard Worker strnlen(buf + de_nameoff, count - de_nameoff) == 2 :
392*33b1fccfSAndroid Build Coastguard Worker le16_to_cpu(de[1].nameoff) == de_nameoff + 2) &&
393*33b1fccfSAndroid Build Coastguard Worker !memcmp(buf + de_nameoff, "..", 2)) {
394*33b1fccfSAndroid Build Coastguard Worker if (de->nid == cpu_to_le64(pnid))
395*33b1fccfSAndroid Build Coastguard Worker return 0;
396*33b1fccfSAndroid Build Coastguard Worker de->nid = cpu_to_le64(pnid);
397*33b1fccfSAndroid Build Coastguard Worker fixed = true;
398*33b1fccfSAndroid Build Coastguard Worker break;
399*33b1fccfSAndroid Build Coastguard Worker }
400*33b1fccfSAndroid Build Coastguard Worker ++de;
401*33b1fccfSAndroid Build Coastguard Worker }
402*33b1fccfSAndroid Build Coastguard Worker
403*33b1fccfSAndroid Build Coastguard Worker if (!fixed)
404*33b1fccfSAndroid Build Coastguard Worker continue;
405*33b1fccfSAndroid Build Coastguard Worker err = erofs_dev_write(dir.sbi, buf,
406*33b1fccfSAndroid Build Coastguard Worker (off + bsz > dir.i_size &&
407*33b1fccfSAndroid Build Coastguard Worker dir.datalayout == EROFS_INODE_FLAT_INLINE ?
408*33b1fccfSAndroid Build Coastguard Worker erofs_iloc(&dir) + isz : boff + off), count);
409*33b1fccfSAndroid Build Coastguard Worker erofs_dbg("directory %llu pNID is updated to %llu",
410*33b1fccfSAndroid Build Coastguard Worker nid | 0ULL, pnid | 0ULL);
411*33b1fccfSAndroid Build Coastguard Worker break;
412*33b1fccfSAndroid Build Coastguard Worker }
413*33b1fccfSAndroid Build Coastguard Worker if (err || fixed)
414*33b1fccfSAndroid Build Coastguard Worker return err;
415*33b1fccfSAndroid Build Coastguard Worker
416*33b1fccfSAndroid Build Coastguard Worker erofs_err("directory data %llu is corrupted (\"..\" not found)",
417*33b1fccfSAndroid Build Coastguard Worker nid | 0ULL);
418*33b1fccfSAndroid Build Coastguard Worker return -EFSCORRUPTED;
419*33b1fccfSAndroid Build Coastguard Worker }
420*33b1fccfSAndroid Build Coastguard Worker
erofs_write_dir_file(struct erofs_inode * dir)421*33b1fccfSAndroid Build Coastguard Worker static int erofs_write_dir_file(struct erofs_inode *dir)
422*33b1fccfSAndroid Build Coastguard Worker {
423*33b1fccfSAndroid Build Coastguard Worker struct erofs_dentry *head = list_first_entry(&dir->i_subdirs,
424*33b1fccfSAndroid Build Coastguard Worker struct erofs_dentry,
425*33b1fccfSAndroid Build Coastguard Worker d_child);
426*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = dir->sbi;
427*33b1fccfSAndroid Build Coastguard Worker struct erofs_dentry *d;
428*33b1fccfSAndroid Build Coastguard Worker int ret;
429*33b1fccfSAndroid Build Coastguard Worker unsigned int q, used, blkno;
430*33b1fccfSAndroid Build Coastguard Worker
431*33b1fccfSAndroid Build Coastguard Worker q = used = blkno = 0;
432*33b1fccfSAndroid Build Coastguard Worker
433*33b1fccfSAndroid Build Coastguard Worker /* allocate dir main data */
434*33b1fccfSAndroid Build Coastguard Worker ret = __allocate_inode_bh_data(dir, erofs_blknr(sbi, dir->i_size), DIRA);
435*33b1fccfSAndroid Build Coastguard Worker if (ret)
436*33b1fccfSAndroid Build Coastguard Worker return ret;
437*33b1fccfSAndroid Build Coastguard Worker
438*33b1fccfSAndroid Build Coastguard Worker list_for_each_entry(d, &dir->i_subdirs, d_child) {
439*33b1fccfSAndroid Build Coastguard Worker const unsigned int len = strlen(d->name) +
440*33b1fccfSAndroid Build Coastguard Worker sizeof(struct erofs_dirent);
441*33b1fccfSAndroid Build Coastguard Worker
442*33b1fccfSAndroid Build Coastguard Worker /* XXX: a bit hacky, but to avoid another traversal */
443*33b1fccfSAndroid Build Coastguard Worker if (d->validnid && d->type == EROFS_FT_DIR) {
444*33b1fccfSAndroid Build Coastguard Worker ret = erofs_rebuild_inode_fix_pnid(dir, d->nid);
445*33b1fccfSAndroid Build Coastguard Worker if (ret)
446*33b1fccfSAndroid Build Coastguard Worker return ret;
447*33b1fccfSAndroid Build Coastguard Worker }
448*33b1fccfSAndroid Build Coastguard Worker
449*33b1fccfSAndroid Build Coastguard Worker erofs_d_invalidate(d);
450*33b1fccfSAndroid Build Coastguard Worker if (used + len > erofs_blksiz(sbi)) {
451*33b1fccfSAndroid Build Coastguard Worker ret = write_dirblock(sbi, q, head, d,
452*33b1fccfSAndroid Build Coastguard Worker dir->u.i_blkaddr + blkno);
453*33b1fccfSAndroid Build Coastguard Worker if (ret)
454*33b1fccfSAndroid Build Coastguard Worker return ret;
455*33b1fccfSAndroid Build Coastguard Worker
456*33b1fccfSAndroid Build Coastguard Worker head = d;
457*33b1fccfSAndroid Build Coastguard Worker q = used = 0;
458*33b1fccfSAndroid Build Coastguard Worker ++blkno;
459*33b1fccfSAndroid Build Coastguard Worker }
460*33b1fccfSAndroid Build Coastguard Worker used += len;
461*33b1fccfSAndroid Build Coastguard Worker q += sizeof(struct erofs_dirent);
462*33b1fccfSAndroid Build Coastguard Worker }
463*33b1fccfSAndroid Build Coastguard Worker
464*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(used > erofs_blksiz(sbi));
465*33b1fccfSAndroid Build Coastguard Worker if (used == erofs_blksiz(sbi)) {
466*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(dir->i_size % erofs_blksiz(sbi));
467*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(dir->idata_size);
468*33b1fccfSAndroid Build Coastguard Worker return write_dirblock(sbi, q, head, d, dir->u.i_blkaddr + blkno);
469*33b1fccfSAndroid Build Coastguard Worker }
470*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(used != dir->i_size % erofs_blksiz(sbi));
471*33b1fccfSAndroid Build Coastguard Worker if (used) {
472*33b1fccfSAndroid Build Coastguard Worker /* fill tail-end dir block */
473*33b1fccfSAndroid Build Coastguard Worker dir->idata = malloc(used);
474*33b1fccfSAndroid Build Coastguard Worker if (!dir->idata)
475*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
476*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(used != dir->idata_size);
477*33b1fccfSAndroid Build Coastguard Worker fill_dirblock(dir->idata, dir->idata_size, q, head, d);
478*33b1fccfSAndroid Build Coastguard Worker }
479*33b1fccfSAndroid Build Coastguard Worker return 0;
480*33b1fccfSAndroid Build Coastguard Worker }
481*33b1fccfSAndroid Build Coastguard Worker
erofs_write_file_from_buffer(struct erofs_inode * inode,char * buf)482*33b1fccfSAndroid Build Coastguard Worker int erofs_write_file_from_buffer(struct erofs_inode *inode, char *buf)
483*33b1fccfSAndroid Build Coastguard Worker {
484*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = inode->sbi;
485*33b1fccfSAndroid Build Coastguard Worker const unsigned int nblocks = erofs_blknr(sbi, inode->i_size);
486*33b1fccfSAndroid Build Coastguard Worker int ret;
487*33b1fccfSAndroid Build Coastguard Worker
488*33b1fccfSAndroid Build Coastguard Worker inode->datalayout = EROFS_INODE_FLAT_INLINE;
489*33b1fccfSAndroid Build Coastguard Worker
490*33b1fccfSAndroid Build Coastguard Worker ret = __allocate_inode_bh_data(inode, nblocks, DATA);
491*33b1fccfSAndroid Build Coastguard Worker if (ret)
492*33b1fccfSAndroid Build Coastguard Worker return ret;
493*33b1fccfSAndroid Build Coastguard Worker
494*33b1fccfSAndroid Build Coastguard Worker if (nblocks)
495*33b1fccfSAndroid Build Coastguard Worker erofs_blk_write(sbi, buf, inode->u.i_blkaddr, nblocks);
496*33b1fccfSAndroid Build Coastguard Worker inode->idata_size = inode->i_size % erofs_blksiz(sbi);
497*33b1fccfSAndroid Build Coastguard Worker if (inode->idata_size) {
498*33b1fccfSAndroid Build Coastguard Worker inode->idata = malloc(inode->idata_size);
499*33b1fccfSAndroid Build Coastguard Worker if (!inode->idata)
500*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
501*33b1fccfSAndroid Build Coastguard Worker memcpy(inode->idata, buf + erofs_pos(sbi, nblocks),
502*33b1fccfSAndroid Build Coastguard Worker inode->idata_size);
503*33b1fccfSAndroid Build Coastguard Worker }
504*33b1fccfSAndroid Build Coastguard Worker return 0;
505*33b1fccfSAndroid Build Coastguard Worker }
506*33b1fccfSAndroid Build Coastguard Worker
507*33b1fccfSAndroid Build Coastguard Worker /* rules to decide whether a file could be compressed or not */
erofs_file_is_compressible(struct erofs_inode * inode)508*33b1fccfSAndroid Build Coastguard Worker static bool erofs_file_is_compressible(struct erofs_inode *inode)
509*33b1fccfSAndroid Build Coastguard Worker {
510*33b1fccfSAndroid Build Coastguard Worker if (cfg.c_compress_hints_file)
511*33b1fccfSAndroid Build Coastguard Worker return z_erofs_apply_compress_hints(inode);
512*33b1fccfSAndroid Build Coastguard Worker return true;
513*33b1fccfSAndroid Build Coastguard Worker }
514*33b1fccfSAndroid Build Coastguard Worker
write_uncompressed_file_from_fd(struct erofs_inode * inode,int fd)515*33b1fccfSAndroid Build Coastguard Worker static int write_uncompressed_file_from_fd(struct erofs_inode *inode, int fd)
516*33b1fccfSAndroid Build Coastguard Worker {
517*33b1fccfSAndroid Build Coastguard Worker int ret;
518*33b1fccfSAndroid Build Coastguard Worker erofs_blk_t nblocks, i;
519*33b1fccfSAndroid Build Coastguard Worker unsigned int len;
520*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = inode->sbi;
521*33b1fccfSAndroid Build Coastguard Worker
522*33b1fccfSAndroid Build Coastguard Worker inode->datalayout = EROFS_INODE_FLAT_INLINE;
523*33b1fccfSAndroid Build Coastguard Worker nblocks = inode->i_size >> sbi->blkszbits;
524*33b1fccfSAndroid Build Coastguard Worker
525*33b1fccfSAndroid Build Coastguard Worker ret = __allocate_inode_bh_data(inode, nblocks, DATA);
526*33b1fccfSAndroid Build Coastguard Worker if (ret)
527*33b1fccfSAndroid Build Coastguard Worker return ret;
528*33b1fccfSAndroid Build Coastguard Worker
529*33b1fccfSAndroid Build Coastguard Worker for (i = 0; i < nblocks; i += (len >> sbi->blkszbits)) {
530*33b1fccfSAndroid Build Coastguard Worker len = min_t(u64, round_down(UINT_MAX, 1U << sbi->blkszbits),
531*33b1fccfSAndroid Build Coastguard Worker erofs_pos(sbi, nblocks - i));
532*33b1fccfSAndroid Build Coastguard Worker ret = erofs_io_xcopy(&sbi->bdev,
533*33b1fccfSAndroid Build Coastguard Worker erofs_pos(sbi, inode->u.i_blkaddr + i),
534*33b1fccfSAndroid Build Coastguard Worker &((struct erofs_vfile){ .fd = fd }), len,
535*33b1fccfSAndroid Build Coastguard Worker inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF);
536*33b1fccfSAndroid Build Coastguard Worker if (ret)
537*33b1fccfSAndroid Build Coastguard Worker return ret;
538*33b1fccfSAndroid Build Coastguard Worker }
539*33b1fccfSAndroid Build Coastguard Worker
540*33b1fccfSAndroid Build Coastguard Worker /* read the tail-end data */
541*33b1fccfSAndroid Build Coastguard Worker inode->idata_size = inode->i_size % erofs_blksiz(sbi);
542*33b1fccfSAndroid Build Coastguard Worker if (inode->idata_size) {
543*33b1fccfSAndroid Build Coastguard Worker inode->idata = malloc(inode->idata_size);
544*33b1fccfSAndroid Build Coastguard Worker if (!inode->idata)
545*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
546*33b1fccfSAndroid Build Coastguard Worker
547*33b1fccfSAndroid Build Coastguard Worker ret = read(fd, inode->idata, inode->idata_size);
548*33b1fccfSAndroid Build Coastguard Worker if (ret < inode->idata_size) {
549*33b1fccfSAndroid Build Coastguard Worker free(inode->idata);
550*33b1fccfSAndroid Build Coastguard Worker inode->idata = NULL;
551*33b1fccfSAndroid Build Coastguard Worker return -EIO;
552*33b1fccfSAndroid Build Coastguard Worker }
553*33b1fccfSAndroid Build Coastguard Worker }
554*33b1fccfSAndroid Build Coastguard Worker erofs_droid_blocklist_write(inode, inode->u.i_blkaddr, nblocks);
555*33b1fccfSAndroid Build Coastguard Worker return 0;
556*33b1fccfSAndroid Build Coastguard Worker }
557*33b1fccfSAndroid Build Coastguard Worker
erofs_write_unencoded_file(struct erofs_inode * inode,int fd,u64 fpos)558*33b1fccfSAndroid Build Coastguard Worker int erofs_write_unencoded_file(struct erofs_inode *inode, int fd, u64 fpos)
559*33b1fccfSAndroid Build Coastguard Worker {
560*33b1fccfSAndroid Build Coastguard Worker if (cfg.c_chunkbits) {
561*33b1fccfSAndroid Build Coastguard Worker inode->u.chunkbits = cfg.c_chunkbits;
562*33b1fccfSAndroid Build Coastguard Worker /* chunk indexes when explicitly specified */
563*33b1fccfSAndroid Build Coastguard Worker inode->u.chunkformat = 0;
564*33b1fccfSAndroid Build Coastguard Worker if (cfg.c_force_chunkformat == FORCE_INODE_CHUNK_INDEXES)
565*33b1fccfSAndroid Build Coastguard Worker inode->u.chunkformat = EROFS_CHUNK_FORMAT_INDEXES;
566*33b1fccfSAndroid Build Coastguard Worker return erofs_blob_write_chunked_file(inode, fd, fpos);
567*33b1fccfSAndroid Build Coastguard Worker }
568*33b1fccfSAndroid Build Coastguard Worker
569*33b1fccfSAndroid Build Coastguard Worker /* fallback to all data uncompressed */
570*33b1fccfSAndroid Build Coastguard Worker return write_uncompressed_file_from_fd(inode, fd);
571*33b1fccfSAndroid Build Coastguard Worker }
572*33b1fccfSAndroid Build Coastguard Worker
erofs_iflush(struct erofs_inode * inode)573*33b1fccfSAndroid Build Coastguard Worker int erofs_iflush(struct erofs_inode *inode)
574*33b1fccfSAndroid Build Coastguard Worker {
575*33b1fccfSAndroid Build Coastguard Worker const u16 icount = EROFS_INODE_XATTR_ICOUNT(inode->xattr_isize);
576*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = inode->sbi;
577*33b1fccfSAndroid Build Coastguard Worker erofs_off_t off;
578*33b1fccfSAndroid Build Coastguard Worker union {
579*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode_compact dic;
580*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode_extended die;
581*33b1fccfSAndroid Build Coastguard Worker } u = {};
582*33b1fccfSAndroid Build Coastguard Worker int ret;
583*33b1fccfSAndroid Build Coastguard Worker
584*33b1fccfSAndroid Build Coastguard Worker if (inode->bh)
585*33b1fccfSAndroid Build Coastguard Worker off = erofs_btell(inode->bh, false);
586*33b1fccfSAndroid Build Coastguard Worker else
587*33b1fccfSAndroid Build Coastguard Worker off = erofs_iloc(inode);
588*33b1fccfSAndroid Build Coastguard Worker
589*33b1fccfSAndroid Build Coastguard Worker switch (inode->inode_isize) {
590*33b1fccfSAndroid Build Coastguard Worker case sizeof(struct erofs_inode_compact):
591*33b1fccfSAndroid Build Coastguard Worker u.dic.i_format = cpu_to_le16(0 | (inode->datalayout << 1));
592*33b1fccfSAndroid Build Coastguard Worker u.dic.i_xattr_icount = cpu_to_le16(icount);
593*33b1fccfSAndroid Build Coastguard Worker u.dic.i_mode = cpu_to_le16(inode->i_mode);
594*33b1fccfSAndroid Build Coastguard Worker u.dic.i_nlink = cpu_to_le16(inode->i_nlink);
595*33b1fccfSAndroid Build Coastguard Worker u.dic.i_size = cpu_to_le32((u32)inode->i_size);
596*33b1fccfSAndroid Build Coastguard Worker
597*33b1fccfSAndroid Build Coastguard Worker u.dic.i_ino = cpu_to_le32(inode->i_ino[0]);
598*33b1fccfSAndroid Build Coastguard Worker
599*33b1fccfSAndroid Build Coastguard Worker u.dic.i_uid = cpu_to_le16((u16)inode->i_uid);
600*33b1fccfSAndroid Build Coastguard Worker u.dic.i_gid = cpu_to_le16((u16)inode->i_gid);
601*33b1fccfSAndroid Build Coastguard Worker
602*33b1fccfSAndroid Build Coastguard Worker switch (inode->i_mode & S_IFMT) {
603*33b1fccfSAndroid Build Coastguard Worker case S_IFCHR:
604*33b1fccfSAndroid Build Coastguard Worker case S_IFBLK:
605*33b1fccfSAndroid Build Coastguard Worker case S_IFIFO:
606*33b1fccfSAndroid Build Coastguard Worker case S_IFSOCK:
607*33b1fccfSAndroid Build Coastguard Worker u.dic.i_u.rdev = cpu_to_le32(inode->u.i_rdev);
608*33b1fccfSAndroid Build Coastguard Worker break;
609*33b1fccfSAndroid Build Coastguard Worker
610*33b1fccfSAndroid Build Coastguard Worker default:
611*33b1fccfSAndroid Build Coastguard Worker if (is_inode_layout_compression(inode))
612*33b1fccfSAndroid Build Coastguard Worker u.dic.i_u.compressed_blocks =
613*33b1fccfSAndroid Build Coastguard Worker cpu_to_le32(inode->u.i_blocks);
614*33b1fccfSAndroid Build Coastguard Worker else if (inode->datalayout ==
615*33b1fccfSAndroid Build Coastguard Worker EROFS_INODE_CHUNK_BASED)
616*33b1fccfSAndroid Build Coastguard Worker u.dic.i_u.c.format =
617*33b1fccfSAndroid Build Coastguard Worker cpu_to_le16(inode->u.chunkformat);
618*33b1fccfSAndroid Build Coastguard Worker else
619*33b1fccfSAndroid Build Coastguard Worker u.dic.i_u.raw_blkaddr =
620*33b1fccfSAndroid Build Coastguard Worker cpu_to_le32(inode->u.i_blkaddr);
621*33b1fccfSAndroid Build Coastguard Worker break;
622*33b1fccfSAndroid Build Coastguard Worker }
623*33b1fccfSAndroid Build Coastguard Worker break;
624*33b1fccfSAndroid Build Coastguard Worker case sizeof(struct erofs_inode_extended):
625*33b1fccfSAndroid Build Coastguard Worker u.die.i_format = cpu_to_le16(1 | (inode->datalayout << 1));
626*33b1fccfSAndroid Build Coastguard Worker u.die.i_xattr_icount = cpu_to_le16(icount);
627*33b1fccfSAndroid Build Coastguard Worker u.die.i_mode = cpu_to_le16(inode->i_mode);
628*33b1fccfSAndroid Build Coastguard Worker u.die.i_nlink = cpu_to_le32(inode->i_nlink);
629*33b1fccfSAndroid Build Coastguard Worker u.die.i_size = cpu_to_le64(inode->i_size);
630*33b1fccfSAndroid Build Coastguard Worker
631*33b1fccfSAndroid Build Coastguard Worker u.die.i_ino = cpu_to_le32(inode->i_ino[0]);
632*33b1fccfSAndroid Build Coastguard Worker
633*33b1fccfSAndroid Build Coastguard Worker u.die.i_uid = cpu_to_le32(inode->i_uid);
634*33b1fccfSAndroid Build Coastguard Worker u.die.i_gid = cpu_to_le32(inode->i_gid);
635*33b1fccfSAndroid Build Coastguard Worker
636*33b1fccfSAndroid Build Coastguard Worker u.die.i_mtime = cpu_to_le64(inode->i_mtime);
637*33b1fccfSAndroid Build Coastguard Worker u.die.i_mtime_nsec = cpu_to_le32(inode->i_mtime_nsec);
638*33b1fccfSAndroid Build Coastguard Worker
639*33b1fccfSAndroid Build Coastguard Worker switch (inode->i_mode & S_IFMT) {
640*33b1fccfSAndroid Build Coastguard Worker case S_IFCHR:
641*33b1fccfSAndroid Build Coastguard Worker case S_IFBLK:
642*33b1fccfSAndroid Build Coastguard Worker case S_IFIFO:
643*33b1fccfSAndroid Build Coastguard Worker case S_IFSOCK:
644*33b1fccfSAndroid Build Coastguard Worker u.die.i_u.rdev = cpu_to_le32(inode->u.i_rdev);
645*33b1fccfSAndroid Build Coastguard Worker break;
646*33b1fccfSAndroid Build Coastguard Worker
647*33b1fccfSAndroid Build Coastguard Worker default:
648*33b1fccfSAndroid Build Coastguard Worker if (is_inode_layout_compression(inode))
649*33b1fccfSAndroid Build Coastguard Worker u.die.i_u.compressed_blocks =
650*33b1fccfSAndroid Build Coastguard Worker cpu_to_le32(inode->u.i_blocks);
651*33b1fccfSAndroid Build Coastguard Worker else if (inode->datalayout ==
652*33b1fccfSAndroid Build Coastguard Worker EROFS_INODE_CHUNK_BASED)
653*33b1fccfSAndroid Build Coastguard Worker u.die.i_u.c.format =
654*33b1fccfSAndroid Build Coastguard Worker cpu_to_le16(inode->u.chunkformat);
655*33b1fccfSAndroid Build Coastguard Worker else
656*33b1fccfSAndroid Build Coastguard Worker u.die.i_u.raw_blkaddr =
657*33b1fccfSAndroid Build Coastguard Worker cpu_to_le32(inode->u.i_blkaddr);
658*33b1fccfSAndroid Build Coastguard Worker break;
659*33b1fccfSAndroid Build Coastguard Worker }
660*33b1fccfSAndroid Build Coastguard Worker break;
661*33b1fccfSAndroid Build Coastguard Worker default:
662*33b1fccfSAndroid Build Coastguard Worker erofs_err("unsupported on-disk inode version of nid %llu",
663*33b1fccfSAndroid Build Coastguard Worker (unsigned long long)inode->nid);
664*33b1fccfSAndroid Build Coastguard Worker BUG_ON(1);
665*33b1fccfSAndroid Build Coastguard Worker }
666*33b1fccfSAndroid Build Coastguard Worker
667*33b1fccfSAndroid Build Coastguard Worker ret = erofs_dev_write(sbi, &u, off, inode->inode_isize);
668*33b1fccfSAndroid Build Coastguard Worker if (ret)
669*33b1fccfSAndroid Build Coastguard Worker return ret;
670*33b1fccfSAndroid Build Coastguard Worker off += inode->inode_isize;
671*33b1fccfSAndroid Build Coastguard Worker
672*33b1fccfSAndroid Build Coastguard Worker if (inode->xattr_isize) {
673*33b1fccfSAndroid Build Coastguard Worker char *xattrs = erofs_export_xattr_ibody(inode);
674*33b1fccfSAndroid Build Coastguard Worker
675*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(xattrs))
676*33b1fccfSAndroid Build Coastguard Worker return PTR_ERR(xattrs);
677*33b1fccfSAndroid Build Coastguard Worker
678*33b1fccfSAndroid Build Coastguard Worker ret = erofs_dev_write(sbi, xattrs, off, inode->xattr_isize);
679*33b1fccfSAndroid Build Coastguard Worker free(xattrs);
680*33b1fccfSAndroid Build Coastguard Worker if (ret)
681*33b1fccfSAndroid Build Coastguard Worker return ret;
682*33b1fccfSAndroid Build Coastguard Worker
683*33b1fccfSAndroid Build Coastguard Worker off += inode->xattr_isize;
684*33b1fccfSAndroid Build Coastguard Worker }
685*33b1fccfSAndroid Build Coastguard Worker
686*33b1fccfSAndroid Build Coastguard Worker if (inode->extent_isize) {
687*33b1fccfSAndroid Build Coastguard Worker if (inode->datalayout == EROFS_INODE_CHUNK_BASED) {
688*33b1fccfSAndroid Build Coastguard Worker ret = erofs_blob_write_chunk_indexes(inode, off);
689*33b1fccfSAndroid Build Coastguard Worker if (ret)
690*33b1fccfSAndroid Build Coastguard Worker return ret;
691*33b1fccfSAndroid Build Coastguard Worker } else {
692*33b1fccfSAndroid Build Coastguard Worker /* write compression metadata */
693*33b1fccfSAndroid Build Coastguard Worker off = roundup(off, 8);
694*33b1fccfSAndroid Build Coastguard Worker ret = erofs_dev_write(sbi, inode->compressmeta, off,
695*33b1fccfSAndroid Build Coastguard Worker inode->extent_isize);
696*33b1fccfSAndroid Build Coastguard Worker if (ret)
697*33b1fccfSAndroid Build Coastguard Worker return ret;
698*33b1fccfSAndroid Build Coastguard Worker }
699*33b1fccfSAndroid Build Coastguard Worker }
700*33b1fccfSAndroid Build Coastguard Worker return 0;
701*33b1fccfSAndroid Build Coastguard Worker }
702*33b1fccfSAndroid Build Coastguard Worker
erofs_bh_flush_write_inode(struct erofs_buffer_head * bh)703*33b1fccfSAndroid Build Coastguard Worker static int erofs_bh_flush_write_inode(struct erofs_buffer_head *bh)
704*33b1fccfSAndroid Build Coastguard Worker {
705*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *inode = bh->fsprivate;
706*33b1fccfSAndroid Build Coastguard Worker int ret;
707*33b1fccfSAndroid Build Coastguard Worker
708*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(inode->bh != bh);
709*33b1fccfSAndroid Build Coastguard Worker ret = erofs_iflush(inode);
710*33b1fccfSAndroid Build Coastguard Worker if (ret)
711*33b1fccfSAndroid Build Coastguard Worker return ret;
712*33b1fccfSAndroid Build Coastguard Worker inode->bh = NULL;
713*33b1fccfSAndroid Build Coastguard Worker erofs_iput(inode);
714*33b1fccfSAndroid Build Coastguard Worker return erofs_bh_flush_generic_end(bh);
715*33b1fccfSAndroid Build Coastguard Worker }
716*33b1fccfSAndroid Build Coastguard Worker
717*33b1fccfSAndroid Build Coastguard Worker static struct erofs_bhops erofs_write_inode_bhops = {
718*33b1fccfSAndroid Build Coastguard Worker .flush = erofs_bh_flush_write_inode,
719*33b1fccfSAndroid Build Coastguard Worker };
720*33b1fccfSAndroid Build Coastguard Worker
erofs_prepare_tail_block(struct erofs_inode * inode)721*33b1fccfSAndroid Build Coastguard Worker static int erofs_prepare_tail_block(struct erofs_inode *inode)
722*33b1fccfSAndroid Build Coastguard Worker {
723*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = inode->sbi;
724*33b1fccfSAndroid Build Coastguard Worker struct erofs_buffer_head *bh;
725*33b1fccfSAndroid Build Coastguard Worker int ret;
726*33b1fccfSAndroid Build Coastguard Worker
727*33b1fccfSAndroid Build Coastguard Worker if (!inode->idata_size)
728*33b1fccfSAndroid Build Coastguard Worker return 0;
729*33b1fccfSAndroid Build Coastguard Worker
730*33b1fccfSAndroid Build Coastguard Worker bh = inode->bh_data;
731*33b1fccfSAndroid Build Coastguard Worker if (bh) {
732*33b1fccfSAndroid Build Coastguard Worker /* expend a block as the tail block (should be successful) */
733*33b1fccfSAndroid Build Coastguard Worker ret = erofs_bh_balloon(bh, erofs_blksiz(sbi));
734*33b1fccfSAndroid Build Coastguard Worker if (ret != erofs_blksiz(sbi)) {
735*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(1);
736*33b1fccfSAndroid Build Coastguard Worker return -EIO;
737*33b1fccfSAndroid Build Coastguard Worker }
738*33b1fccfSAndroid Build Coastguard Worker } else {
739*33b1fccfSAndroid Build Coastguard Worker inode->lazy_tailblock = true;
740*33b1fccfSAndroid Build Coastguard Worker }
741*33b1fccfSAndroid Build Coastguard Worker if (is_inode_layout_compression(inode))
742*33b1fccfSAndroid Build Coastguard Worker inode->u.i_blocks += 1;
743*33b1fccfSAndroid Build Coastguard Worker return 0;
744*33b1fccfSAndroid Build Coastguard Worker }
745*33b1fccfSAndroid Build Coastguard Worker
erofs_prepare_inode_buffer(struct erofs_inode * inode)746*33b1fccfSAndroid Build Coastguard Worker static int erofs_prepare_inode_buffer(struct erofs_inode *inode)
747*33b1fccfSAndroid Build Coastguard Worker {
748*33b1fccfSAndroid Build Coastguard Worker struct erofs_bufmgr *bmgr = inode->sbi->bmgr;
749*33b1fccfSAndroid Build Coastguard Worker unsigned int inodesize;
750*33b1fccfSAndroid Build Coastguard Worker struct erofs_buffer_head *bh, *ibh;
751*33b1fccfSAndroid Build Coastguard Worker
752*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(inode->bh || inode->bh_inline);
753*33b1fccfSAndroid Build Coastguard Worker
754*33b1fccfSAndroid Build Coastguard Worker inodesize = inode->inode_isize + inode->xattr_isize;
755*33b1fccfSAndroid Build Coastguard Worker if (inode->extent_isize)
756*33b1fccfSAndroid Build Coastguard Worker inodesize = roundup(inodesize, 8) + inode->extent_isize;
757*33b1fccfSAndroid Build Coastguard Worker
758*33b1fccfSAndroid Build Coastguard Worker if (inode->datalayout == EROFS_INODE_FLAT_PLAIN)
759*33b1fccfSAndroid Build Coastguard Worker goto noinline;
760*33b1fccfSAndroid Build Coastguard Worker
761*33b1fccfSAndroid Build Coastguard Worker /* TODO: tailpacking inline of chunk-based format isn't finalized */
762*33b1fccfSAndroid Build Coastguard Worker if (inode->datalayout == EROFS_INODE_CHUNK_BASED)
763*33b1fccfSAndroid Build Coastguard Worker goto noinline;
764*33b1fccfSAndroid Build Coastguard Worker
765*33b1fccfSAndroid Build Coastguard Worker if (!is_inode_layout_compression(inode)) {
766*33b1fccfSAndroid Build Coastguard Worker if (!cfg.c_inline_data && S_ISREG(inode->i_mode)) {
767*33b1fccfSAndroid Build Coastguard Worker inode->datalayout = EROFS_INODE_FLAT_PLAIN;
768*33b1fccfSAndroid Build Coastguard Worker goto noinline;
769*33b1fccfSAndroid Build Coastguard Worker }
770*33b1fccfSAndroid Build Coastguard Worker /*
771*33b1fccfSAndroid Build Coastguard Worker * If the file sizes of uncompressed files are block-aligned,
772*33b1fccfSAndroid Build Coastguard Worker * should use the EROFS_INODE_FLAT_PLAIN data layout.
773*33b1fccfSAndroid Build Coastguard Worker */
774*33b1fccfSAndroid Build Coastguard Worker if (!inode->idata_size)
775*33b1fccfSAndroid Build Coastguard Worker inode->datalayout = EROFS_INODE_FLAT_PLAIN;
776*33b1fccfSAndroid Build Coastguard Worker }
777*33b1fccfSAndroid Build Coastguard Worker
778*33b1fccfSAndroid Build Coastguard Worker bh = erofs_balloc(bmgr, INODE, inodesize, 0, inode->idata_size);
779*33b1fccfSAndroid Build Coastguard Worker if (bh == ERR_PTR(-ENOSPC)) {
780*33b1fccfSAndroid Build Coastguard Worker int ret;
781*33b1fccfSAndroid Build Coastguard Worker
782*33b1fccfSAndroid Build Coastguard Worker if (is_inode_layout_compression(inode))
783*33b1fccfSAndroid Build Coastguard Worker z_erofs_drop_inline_pcluster(inode);
784*33b1fccfSAndroid Build Coastguard Worker else
785*33b1fccfSAndroid Build Coastguard Worker inode->datalayout = EROFS_INODE_FLAT_PLAIN;
786*33b1fccfSAndroid Build Coastguard Worker noinline:
787*33b1fccfSAndroid Build Coastguard Worker /* expend an extra block for tail-end data */
788*33b1fccfSAndroid Build Coastguard Worker ret = erofs_prepare_tail_block(inode);
789*33b1fccfSAndroid Build Coastguard Worker if (ret)
790*33b1fccfSAndroid Build Coastguard Worker return ret;
791*33b1fccfSAndroid Build Coastguard Worker bh = erofs_balloc(bmgr, INODE, inodesize, 0, 0);
792*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(bh))
793*33b1fccfSAndroid Build Coastguard Worker return PTR_ERR(bh);
794*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(inode->bh_inline);
795*33b1fccfSAndroid Build Coastguard Worker } else if (IS_ERR(bh)) {
796*33b1fccfSAndroid Build Coastguard Worker return PTR_ERR(bh);
797*33b1fccfSAndroid Build Coastguard Worker } else if (inode->idata_size) {
798*33b1fccfSAndroid Build Coastguard Worker if (is_inode_layout_compression(inode)) {
799*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(!cfg.c_ztailpacking);
800*33b1fccfSAndroid Build Coastguard Worker erofs_dbg("Inline %scompressed data (%u bytes) to %s",
801*33b1fccfSAndroid Build Coastguard Worker inode->compressed_idata ? "" : "un",
802*33b1fccfSAndroid Build Coastguard Worker inode->idata_size, inode->i_srcpath);
803*33b1fccfSAndroid Build Coastguard Worker erofs_sb_set_ztailpacking(inode->sbi);
804*33b1fccfSAndroid Build Coastguard Worker } else {
805*33b1fccfSAndroid Build Coastguard Worker inode->datalayout = EROFS_INODE_FLAT_INLINE;
806*33b1fccfSAndroid Build Coastguard Worker erofs_dbg("Inline tail-end data (%u bytes) to %s",
807*33b1fccfSAndroid Build Coastguard Worker inode->idata_size, inode->i_srcpath);
808*33b1fccfSAndroid Build Coastguard Worker }
809*33b1fccfSAndroid Build Coastguard Worker
810*33b1fccfSAndroid Build Coastguard Worker /* allocate inline buffer */
811*33b1fccfSAndroid Build Coastguard Worker ibh = erofs_battach(bh, META, inode->idata_size);
812*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(ibh))
813*33b1fccfSAndroid Build Coastguard Worker return PTR_ERR(ibh);
814*33b1fccfSAndroid Build Coastguard Worker
815*33b1fccfSAndroid Build Coastguard Worker ibh->op = &erofs_skip_write_bhops;
816*33b1fccfSAndroid Build Coastguard Worker inode->bh_inline = ibh;
817*33b1fccfSAndroid Build Coastguard Worker }
818*33b1fccfSAndroid Build Coastguard Worker
819*33b1fccfSAndroid Build Coastguard Worker bh->fsprivate = erofs_igrab(inode);
820*33b1fccfSAndroid Build Coastguard Worker bh->op = &erofs_write_inode_bhops;
821*33b1fccfSAndroid Build Coastguard Worker inode->bh = bh;
822*33b1fccfSAndroid Build Coastguard Worker return 0;
823*33b1fccfSAndroid Build Coastguard Worker }
824*33b1fccfSAndroid Build Coastguard Worker
erofs_bh_flush_write_inline(struct erofs_buffer_head * bh)825*33b1fccfSAndroid Build Coastguard Worker static int erofs_bh_flush_write_inline(struct erofs_buffer_head *bh)
826*33b1fccfSAndroid Build Coastguard Worker {
827*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *const inode = bh->fsprivate;
828*33b1fccfSAndroid Build Coastguard Worker const erofs_off_t off = erofs_btell(bh, false);
829*33b1fccfSAndroid Build Coastguard Worker int ret;
830*33b1fccfSAndroid Build Coastguard Worker
831*33b1fccfSAndroid Build Coastguard Worker ret = erofs_dev_write(inode->sbi, inode->idata, off, inode->idata_size);
832*33b1fccfSAndroid Build Coastguard Worker if (ret)
833*33b1fccfSAndroid Build Coastguard Worker return ret;
834*33b1fccfSAndroid Build Coastguard Worker
835*33b1fccfSAndroid Build Coastguard Worker free(inode->idata);
836*33b1fccfSAndroid Build Coastguard Worker inode->idata = NULL;
837*33b1fccfSAndroid Build Coastguard Worker
838*33b1fccfSAndroid Build Coastguard Worker erofs_iput(inode);
839*33b1fccfSAndroid Build Coastguard Worker return erofs_bh_flush_generic_end(bh);
840*33b1fccfSAndroid Build Coastguard Worker }
841*33b1fccfSAndroid Build Coastguard Worker
842*33b1fccfSAndroid Build Coastguard Worker static struct erofs_bhops erofs_write_inline_bhops = {
843*33b1fccfSAndroid Build Coastguard Worker .flush = erofs_bh_flush_write_inline,
844*33b1fccfSAndroid Build Coastguard Worker };
845*33b1fccfSAndroid Build Coastguard Worker
erofs_write_tail_end(struct erofs_inode * inode)846*33b1fccfSAndroid Build Coastguard Worker static int erofs_write_tail_end(struct erofs_inode *inode)
847*33b1fccfSAndroid Build Coastguard Worker {
848*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = inode->sbi;
849*33b1fccfSAndroid Build Coastguard Worker struct erofs_buffer_head *bh, *ibh;
850*33b1fccfSAndroid Build Coastguard Worker
851*33b1fccfSAndroid Build Coastguard Worker bh = inode->bh_data;
852*33b1fccfSAndroid Build Coastguard Worker
853*33b1fccfSAndroid Build Coastguard Worker if (!inode->idata_size)
854*33b1fccfSAndroid Build Coastguard Worker goto out;
855*33b1fccfSAndroid Build Coastguard Worker
856*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(!inode->idata);
857*33b1fccfSAndroid Build Coastguard Worker /* have enough room to inline data */
858*33b1fccfSAndroid Build Coastguard Worker if (inode->bh_inline) {
859*33b1fccfSAndroid Build Coastguard Worker ibh = inode->bh_inline;
860*33b1fccfSAndroid Build Coastguard Worker
861*33b1fccfSAndroid Build Coastguard Worker ibh->fsprivate = erofs_igrab(inode);
862*33b1fccfSAndroid Build Coastguard Worker ibh->op = &erofs_write_inline_bhops;
863*33b1fccfSAndroid Build Coastguard Worker
864*33b1fccfSAndroid Build Coastguard Worker erofs_droid_blocklist_write_tail_end(inode, NULL_ADDR);
865*33b1fccfSAndroid Build Coastguard Worker } else {
866*33b1fccfSAndroid Build Coastguard Worker int ret;
867*33b1fccfSAndroid Build Coastguard Worker erofs_off_t pos, zero_pos;
868*33b1fccfSAndroid Build Coastguard Worker
869*33b1fccfSAndroid Build Coastguard Worker if (!bh) {
870*33b1fccfSAndroid Build Coastguard Worker bh = erofs_balloc(sbi->bmgr, DATA,
871*33b1fccfSAndroid Build Coastguard Worker erofs_blksiz(sbi), 0, 0);
872*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(bh))
873*33b1fccfSAndroid Build Coastguard Worker return PTR_ERR(bh);
874*33b1fccfSAndroid Build Coastguard Worker bh->op = &erofs_skip_write_bhops;
875*33b1fccfSAndroid Build Coastguard Worker
876*33b1fccfSAndroid Build Coastguard Worker /* get blkaddr of bh */
877*33b1fccfSAndroid Build Coastguard Worker ret = erofs_mapbh(NULL, bh->block);
878*33b1fccfSAndroid Build Coastguard Worker inode->u.i_blkaddr = bh->block->blkaddr;
879*33b1fccfSAndroid Build Coastguard Worker inode->bh_data = bh;
880*33b1fccfSAndroid Build Coastguard Worker } else {
881*33b1fccfSAndroid Build Coastguard Worker if (inode->lazy_tailblock) {
882*33b1fccfSAndroid Build Coastguard Worker /* expend a tail block (should be successful) */
883*33b1fccfSAndroid Build Coastguard Worker ret = erofs_bh_balloon(bh, erofs_blksiz(sbi));
884*33b1fccfSAndroid Build Coastguard Worker if (ret != erofs_blksiz(sbi)) {
885*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(1);
886*33b1fccfSAndroid Build Coastguard Worker return -EIO;
887*33b1fccfSAndroid Build Coastguard Worker }
888*33b1fccfSAndroid Build Coastguard Worker inode->lazy_tailblock = false;
889*33b1fccfSAndroid Build Coastguard Worker }
890*33b1fccfSAndroid Build Coastguard Worker ret = erofs_mapbh(NULL, bh->block);
891*33b1fccfSAndroid Build Coastguard Worker }
892*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(ret < 0);
893*33b1fccfSAndroid Build Coastguard Worker pos = erofs_btell(bh, true) - erofs_blksiz(sbi);
894*33b1fccfSAndroid Build Coastguard Worker
895*33b1fccfSAndroid Build Coastguard Worker /* 0'ed data should be padded at head for 0padding conversion */
896*33b1fccfSAndroid Build Coastguard Worker if (erofs_sb_has_lz4_0padding(sbi) && inode->compressed_idata) {
897*33b1fccfSAndroid Build Coastguard Worker zero_pos = pos;
898*33b1fccfSAndroid Build Coastguard Worker pos += erofs_blksiz(sbi) - inode->idata_size;
899*33b1fccfSAndroid Build Coastguard Worker } else {
900*33b1fccfSAndroid Build Coastguard Worker /* pad 0'ed data for the other cases */
901*33b1fccfSAndroid Build Coastguard Worker zero_pos = pos + inode->idata_size;
902*33b1fccfSAndroid Build Coastguard Worker }
903*33b1fccfSAndroid Build Coastguard Worker ret = erofs_dev_write(sbi, inode->idata, pos, inode->idata_size);
904*33b1fccfSAndroid Build Coastguard Worker if (ret)
905*33b1fccfSAndroid Build Coastguard Worker return ret;
906*33b1fccfSAndroid Build Coastguard Worker
907*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(inode->idata_size > erofs_blksiz(sbi));
908*33b1fccfSAndroid Build Coastguard Worker if (inode->idata_size < erofs_blksiz(sbi)) {
909*33b1fccfSAndroid Build Coastguard Worker ret = erofs_dev_fillzero(sbi, zero_pos,
910*33b1fccfSAndroid Build Coastguard Worker erofs_blksiz(sbi) - inode->idata_size,
911*33b1fccfSAndroid Build Coastguard Worker false);
912*33b1fccfSAndroid Build Coastguard Worker if (ret)
913*33b1fccfSAndroid Build Coastguard Worker return ret;
914*33b1fccfSAndroid Build Coastguard Worker }
915*33b1fccfSAndroid Build Coastguard Worker inode->idata_size = 0;
916*33b1fccfSAndroid Build Coastguard Worker free(inode->idata);
917*33b1fccfSAndroid Build Coastguard Worker inode->idata = NULL;
918*33b1fccfSAndroid Build Coastguard Worker
919*33b1fccfSAndroid Build Coastguard Worker erofs_droid_blocklist_write_tail_end(inode, erofs_blknr(sbi, pos));
920*33b1fccfSAndroid Build Coastguard Worker }
921*33b1fccfSAndroid Build Coastguard Worker out:
922*33b1fccfSAndroid Build Coastguard Worker /* now bh_data can drop directly */
923*33b1fccfSAndroid Build Coastguard Worker if (bh) {
924*33b1fccfSAndroid Build Coastguard Worker /*
925*33b1fccfSAndroid Build Coastguard Worker * Don't leave DATA buffers which were written in the global
926*33b1fccfSAndroid Build Coastguard Worker * buffer list. It will make balloc() slowly.
927*33b1fccfSAndroid Build Coastguard Worker */
928*33b1fccfSAndroid Build Coastguard Worker erofs_bdrop(bh, false);
929*33b1fccfSAndroid Build Coastguard Worker inode->bh_data = NULL;
930*33b1fccfSAndroid Build Coastguard Worker }
931*33b1fccfSAndroid Build Coastguard Worker return 0;
932*33b1fccfSAndroid Build Coastguard Worker }
933*33b1fccfSAndroid Build Coastguard Worker
erofs_should_use_inode_extended(struct erofs_inode * inode)934*33b1fccfSAndroid Build Coastguard Worker static bool erofs_should_use_inode_extended(struct erofs_inode *inode)
935*33b1fccfSAndroid Build Coastguard Worker {
936*33b1fccfSAndroid Build Coastguard Worker if (cfg.c_force_inodeversion == FORCE_INODE_EXTENDED)
937*33b1fccfSAndroid Build Coastguard Worker return true;
938*33b1fccfSAndroid Build Coastguard Worker if (inode->i_size > UINT_MAX)
939*33b1fccfSAndroid Build Coastguard Worker return true;
940*33b1fccfSAndroid Build Coastguard Worker if (erofs_is_packed_inode(inode))
941*33b1fccfSAndroid Build Coastguard Worker return false;
942*33b1fccfSAndroid Build Coastguard Worker if (inode->i_uid > USHRT_MAX)
943*33b1fccfSAndroid Build Coastguard Worker return true;
944*33b1fccfSAndroid Build Coastguard Worker if (inode->i_gid > USHRT_MAX)
945*33b1fccfSAndroid Build Coastguard Worker return true;
946*33b1fccfSAndroid Build Coastguard Worker if (inode->i_nlink > USHRT_MAX)
947*33b1fccfSAndroid Build Coastguard Worker return true;
948*33b1fccfSAndroid Build Coastguard Worker if ((inode->i_mtime != inode->sbi->build_time ||
949*33b1fccfSAndroid Build Coastguard Worker inode->i_mtime_nsec != inode->sbi->build_time_nsec) &&
950*33b1fccfSAndroid Build Coastguard Worker !cfg.c_ignore_mtime)
951*33b1fccfSAndroid Build Coastguard Worker return true;
952*33b1fccfSAndroid Build Coastguard Worker return false;
953*33b1fccfSAndroid Build Coastguard Worker }
954*33b1fccfSAndroid Build Coastguard Worker
erofs_new_encode_dev(dev_t dev)955*33b1fccfSAndroid Build Coastguard Worker u32 erofs_new_encode_dev(dev_t dev)
956*33b1fccfSAndroid Build Coastguard Worker {
957*33b1fccfSAndroid Build Coastguard Worker const unsigned int major = major(dev);
958*33b1fccfSAndroid Build Coastguard Worker const unsigned int minor = minor(dev);
959*33b1fccfSAndroid Build Coastguard Worker
960*33b1fccfSAndroid Build Coastguard Worker return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
961*33b1fccfSAndroid Build Coastguard Worker }
962*33b1fccfSAndroid Build Coastguard Worker
963*33b1fccfSAndroid Build Coastguard Worker #ifdef WITH_ANDROID
erofs_droid_inode_fsconfig(struct erofs_inode * inode,struct stat * st,const char * path)964*33b1fccfSAndroid Build Coastguard Worker int erofs_droid_inode_fsconfig(struct erofs_inode *inode,
965*33b1fccfSAndroid Build Coastguard Worker struct stat *st,
966*33b1fccfSAndroid Build Coastguard Worker const char *path)
967*33b1fccfSAndroid Build Coastguard Worker {
968*33b1fccfSAndroid Build Coastguard Worker /* filesystem_config does not preserve file type bits */
969*33b1fccfSAndroid Build Coastguard Worker mode_t stat_file_type_mask = st->st_mode & S_IFMT;
970*33b1fccfSAndroid Build Coastguard Worker unsigned int uid = 0, gid = 0, mode = 0;
971*33b1fccfSAndroid Build Coastguard Worker const char *fspath;
972*33b1fccfSAndroid Build Coastguard Worker char *decorated = NULL;
973*33b1fccfSAndroid Build Coastguard Worker
974*33b1fccfSAndroid Build Coastguard Worker inode->capabilities = 0;
975*33b1fccfSAndroid Build Coastguard Worker if (!cfg.fs_config_file && !cfg.mount_point)
976*33b1fccfSAndroid Build Coastguard Worker return 0;
977*33b1fccfSAndroid Build Coastguard Worker /* avoid loading special inodes */
978*33b1fccfSAndroid Build Coastguard Worker if (path == EROFS_PACKED_INODE)
979*33b1fccfSAndroid Build Coastguard Worker return 0;
980*33b1fccfSAndroid Build Coastguard Worker
981*33b1fccfSAndroid Build Coastguard Worker if (!cfg.mount_point ||
982*33b1fccfSAndroid Build Coastguard Worker /* have to drop the mountpoint for rootdir of canned fsconfig */
983*33b1fccfSAndroid Build Coastguard Worker (cfg.fs_config_file && erofs_fspath(path)[0] == '\0')) {
984*33b1fccfSAndroid Build Coastguard Worker fspath = erofs_fspath(path);
985*33b1fccfSAndroid Build Coastguard Worker } else {
986*33b1fccfSAndroid Build Coastguard Worker if (asprintf(&decorated, "%s/%s", cfg.mount_point,
987*33b1fccfSAndroid Build Coastguard Worker erofs_fspath(path)) <= 0)
988*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
989*33b1fccfSAndroid Build Coastguard Worker fspath = decorated;
990*33b1fccfSAndroid Build Coastguard Worker }
991*33b1fccfSAndroid Build Coastguard Worker
992*33b1fccfSAndroid Build Coastguard Worker if (cfg.fs_config_file)
993*33b1fccfSAndroid Build Coastguard Worker canned_fs_config(fspath, S_ISDIR(st->st_mode),
994*33b1fccfSAndroid Build Coastguard Worker cfg.target_out_path,
995*33b1fccfSAndroid Build Coastguard Worker &uid, &gid, &mode, &inode->capabilities);
996*33b1fccfSAndroid Build Coastguard Worker else
997*33b1fccfSAndroid Build Coastguard Worker fs_config(fspath, S_ISDIR(st->st_mode),
998*33b1fccfSAndroid Build Coastguard Worker cfg.target_out_path,
999*33b1fccfSAndroid Build Coastguard Worker &uid, &gid, &mode, &inode->capabilities);
1000*33b1fccfSAndroid Build Coastguard Worker
1001*33b1fccfSAndroid Build Coastguard Worker erofs_dbg("/%s -> mode = 0x%x, uid = 0x%x, gid = 0x%x, capabilities = 0x%" PRIx64,
1002*33b1fccfSAndroid Build Coastguard Worker fspath, mode, uid, gid, inode->capabilities);
1003*33b1fccfSAndroid Build Coastguard Worker
1004*33b1fccfSAndroid Build Coastguard Worker if (decorated)
1005*33b1fccfSAndroid Build Coastguard Worker free(decorated);
1006*33b1fccfSAndroid Build Coastguard Worker st->st_uid = uid;
1007*33b1fccfSAndroid Build Coastguard Worker st->st_gid = gid;
1008*33b1fccfSAndroid Build Coastguard Worker st->st_mode = mode | stat_file_type_mask;
1009*33b1fccfSAndroid Build Coastguard Worker return 0;
1010*33b1fccfSAndroid Build Coastguard Worker }
1011*33b1fccfSAndroid Build Coastguard Worker #else
erofs_droid_inode_fsconfig(struct erofs_inode * inode,struct stat * st,const char * path)1012*33b1fccfSAndroid Build Coastguard Worker static int erofs_droid_inode_fsconfig(struct erofs_inode *inode,
1013*33b1fccfSAndroid Build Coastguard Worker struct stat *st,
1014*33b1fccfSAndroid Build Coastguard Worker const char *path)
1015*33b1fccfSAndroid Build Coastguard Worker {
1016*33b1fccfSAndroid Build Coastguard Worker return 0;
1017*33b1fccfSAndroid Build Coastguard Worker }
1018*33b1fccfSAndroid Build Coastguard Worker #endif
1019*33b1fccfSAndroid Build Coastguard Worker
__erofs_fill_inode(struct erofs_inode * inode,struct stat * st,const char * path)1020*33b1fccfSAndroid Build Coastguard Worker int __erofs_fill_inode(struct erofs_inode *inode, struct stat *st,
1021*33b1fccfSAndroid Build Coastguard Worker const char *path)
1022*33b1fccfSAndroid Build Coastguard Worker {
1023*33b1fccfSAndroid Build Coastguard Worker int err = erofs_droid_inode_fsconfig(inode, st, path);
1024*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = inode->sbi;
1025*33b1fccfSAndroid Build Coastguard Worker
1026*33b1fccfSAndroid Build Coastguard Worker if (err)
1027*33b1fccfSAndroid Build Coastguard Worker return err;
1028*33b1fccfSAndroid Build Coastguard Worker
1029*33b1fccfSAndroid Build Coastguard Worker inode->i_uid = cfg.c_uid == -1 ? st->st_uid : cfg.c_uid;
1030*33b1fccfSAndroid Build Coastguard Worker inode->i_gid = cfg.c_gid == -1 ? st->st_gid : cfg.c_gid;
1031*33b1fccfSAndroid Build Coastguard Worker
1032*33b1fccfSAndroid Build Coastguard Worker if (inode->i_uid + cfg.c_uid_offset < 0)
1033*33b1fccfSAndroid Build Coastguard Worker erofs_err("uid overflow @ %s", path);
1034*33b1fccfSAndroid Build Coastguard Worker inode->i_uid += cfg.c_uid_offset;
1035*33b1fccfSAndroid Build Coastguard Worker
1036*33b1fccfSAndroid Build Coastguard Worker if (inode->i_gid + cfg.c_gid_offset < 0)
1037*33b1fccfSAndroid Build Coastguard Worker erofs_err("gid overflow @ %s", path);
1038*33b1fccfSAndroid Build Coastguard Worker inode->i_gid += cfg.c_gid_offset;
1039*33b1fccfSAndroid Build Coastguard Worker
1040*33b1fccfSAndroid Build Coastguard Worker inode->i_mtime = st->st_mtime;
1041*33b1fccfSAndroid Build Coastguard Worker inode->i_mtime_nsec = ST_MTIM_NSEC(st);
1042*33b1fccfSAndroid Build Coastguard Worker
1043*33b1fccfSAndroid Build Coastguard Worker switch (cfg.c_timeinherit) {
1044*33b1fccfSAndroid Build Coastguard Worker case TIMESTAMP_CLAMPING:
1045*33b1fccfSAndroid Build Coastguard Worker if (inode->i_mtime < sbi->build_time)
1046*33b1fccfSAndroid Build Coastguard Worker break;
1047*33b1fccfSAndroid Build Coastguard Worker case TIMESTAMP_FIXED:
1048*33b1fccfSAndroid Build Coastguard Worker inode->i_mtime = sbi->build_time;
1049*33b1fccfSAndroid Build Coastguard Worker inode->i_mtime_nsec = sbi->build_time_nsec;
1050*33b1fccfSAndroid Build Coastguard Worker default:
1051*33b1fccfSAndroid Build Coastguard Worker break;
1052*33b1fccfSAndroid Build Coastguard Worker }
1053*33b1fccfSAndroid Build Coastguard Worker
1054*33b1fccfSAndroid Build Coastguard Worker return 0;
1055*33b1fccfSAndroid Build Coastguard Worker }
1056*33b1fccfSAndroid Build Coastguard Worker
erofs_fill_inode(struct erofs_inode * inode,struct stat * st,const char * path)1057*33b1fccfSAndroid Build Coastguard Worker static int erofs_fill_inode(struct erofs_inode *inode, struct stat *st,
1058*33b1fccfSAndroid Build Coastguard Worker const char *path)
1059*33b1fccfSAndroid Build Coastguard Worker {
1060*33b1fccfSAndroid Build Coastguard Worker int err = __erofs_fill_inode(inode, st, path);
1061*33b1fccfSAndroid Build Coastguard Worker
1062*33b1fccfSAndroid Build Coastguard Worker if (err)
1063*33b1fccfSAndroid Build Coastguard Worker return err;
1064*33b1fccfSAndroid Build Coastguard Worker
1065*33b1fccfSAndroid Build Coastguard Worker inode->i_mode = st->st_mode;
1066*33b1fccfSAndroid Build Coastguard Worker inode->i_nlink = 1; /* fix up later if needed */
1067*33b1fccfSAndroid Build Coastguard Worker
1068*33b1fccfSAndroid Build Coastguard Worker switch (inode->i_mode & S_IFMT) {
1069*33b1fccfSAndroid Build Coastguard Worker case S_IFCHR:
1070*33b1fccfSAndroid Build Coastguard Worker case S_IFBLK:
1071*33b1fccfSAndroid Build Coastguard Worker case S_IFIFO:
1072*33b1fccfSAndroid Build Coastguard Worker case S_IFSOCK:
1073*33b1fccfSAndroid Build Coastguard Worker inode->u.i_rdev = erofs_new_encode_dev(st->st_rdev);
1074*33b1fccfSAndroid Build Coastguard Worker case S_IFDIR:
1075*33b1fccfSAndroid Build Coastguard Worker inode->i_size = 0;
1076*33b1fccfSAndroid Build Coastguard Worker break;
1077*33b1fccfSAndroid Build Coastguard Worker case S_IFREG:
1078*33b1fccfSAndroid Build Coastguard Worker case S_IFLNK:
1079*33b1fccfSAndroid Build Coastguard Worker inode->i_size = st->st_size;
1080*33b1fccfSAndroid Build Coastguard Worker break;
1081*33b1fccfSAndroid Build Coastguard Worker default:
1082*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
1083*33b1fccfSAndroid Build Coastguard Worker }
1084*33b1fccfSAndroid Build Coastguard Worker
1085*33b1fccfSAndroid Build Coastguard Worker inode->i_srcpath = strdup(path);
1086*33b1fccfSAndroid Build Coastguard Worker if (!inode->i_srcpath)
1087*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
1088*33b1fccfSAndroid Build Coastguard Worker
1089*33b1fccfSAndroid Build Coastguard Worker if (erofs_should_use_inode_extended(inode)) {
1090*33b1fccfSAndroid Build Coastguard Worker if (cfg.c_force_inodeversion == FORCE_INODE_COMPACT) {
1091*33b1fccfSAndroid Build Coastguard Worker erofs_err("file %s cannot be in compact form",
1092*33b1fccfSAndroid Build Coastguard Worker inode->i_srcpath);
1093*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
1094*33b1fccfSAndroid Build Coastguard Worker }
1095*33b1fccfSAndroid Build Coastguard Worker inode->inode_isize = sizeof(struct erofs_inode_extended);
1096*33b1fccfSAndroid Build Coastguard Worker } else {
1097*33b1fccfSAndroid Build Coastguard Worker inode->inode_isize = sizeof(struct erofs_inode_compact);
1098*33b1fccfSAndroid Build Coastguard Worker }
1099*33b1fccfSAndroid Build Coastguard Worker
1100*33b1fccfSAndroid Build Coastguard Worker inode->dev = st->st_dev;
1101*33b1fccfSAndroid Build Coastguard Worker inode->i_ino[1] = st->st_ino;
1102*33b1fccfSAndroid Build Coastguard Worker erofs_insert_ihash(inode);
1103*33b1fccfSAndroid Build Coastguard Worker return 0;
1104*33b1fccfSAndroid Build Coastguard Worker }
1105*33b1fccfSAndroid Build Coastguard Worker
erofs_new_inode(struct erofs_sb_info * sbi)1106*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *erofs_new_inode(struct erofs_sb_info *sbi)
1107*33b1fccfSAndroid Build Coastguard Worker {
1108*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *inode;
1109*33b1fccfSAndroid Build Coastguard Worker
1110*33b1fccfSAndroid Build Coastguard Worker inode = calloc(1, sizeof(struct erofs_inode));
1111*33b1fccfSAndroid Build Coastguard Worker if (!inode)
1112*33b1fccfSAndroid Build Coastguard Worker return ERR_PTR(-ENOMEM);
1113*33b1fccfSAndroid Build Coastguard Worker
1114*33b1fccfSAndroid Build Coastguard Worker inode->sbi = sbi;
1115*33b1fccfSAndroid Build Coastguard Worker inode->i_ino[0] = sbi->inos++; /* inode serial number */
1116*33b1fccfSAndroid Build Coastguard Worker inode->i_count = 1;
1117*33b1fccfSAndroid Build Coastguard Worker inode->datalayout = EROFS_INODE_FLAT_PLAIN;
1118*33b1fccfSAndroid Build Coastguard Worker
1119*33b1fccfSAndroid Build Coastguard Worker init_list_head(&inode->i_hash);
1120*33b1fccfSAndroid Build Coastguard Worker init_list_head(&inode->i_subdirs);
1121*33b1fccfSAndroid Build Coastguard Worker init_list_head(&inode->i_xattrs);
1122*33b1fccfSAndroid Build Coastguard Worker return inode;
1123*33b1fccfSAndroid Build Coastguard Worker }
1124*33b1fccfSAndroid Build Coastguard Worker
1125*33b1fccfSAndroid Build Coastguard Worker /* get the inode from the source path */
erofs_iget_from_srcpath(struct erofs_sb_info * sbi,const char * path)1126*33b1fccfSAndroid Build Coastguard Worker static struct erofs_inode *erofs_iget_from_srcpath(struct erofs_sb_info *sbi,
1127*33b1fccfSAndroid Build Coastguard Worker const char *path)
1128*33b1fccfSAndroid Build Coastguard Worker {
1129*33b1fccfSAndroid Build Coastguard Worker struct stat st;
1130*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *inode;
1131*33b1fccfSAndroid Build Coastguard Worker int ret;
1132*33b1fccfSAndroid Build Coastguard Worker
1133*33b1fccfSAndroid Build Coastguard Worker ret = lstat(path, &st);
1134*33b1fccfSAndroid Build Coastguard Worker if (ret)
1135*33b1fccfSAndroid Build Coastguard Worker return ERR_PTR(-errno);
1136*33b1fccfSAndroid Build Coastguard Worker
1137*33b1fccfSAndroid Build Coastguard Worker /*
1138*33b1fccfSAndroid Build Coastguard Worker * lookup in hash table first, if it already exists we have a
1139*33b1fccfSAndroid Build Coastguard Worker * hard-link, just return it. Also don't lookup for directories
1140*33b1fccfSAndroid Build Coastguard Worker * since hard-link directory isn't allowed.
1141*33b1fccfSAndroid Build Coastguard Worker */
1142*33b1fccfSAndroid Build Coastguard Worker if (!S_ISDIR(st.st_mode)) {
1143*33b1fccfSAndroid Build Coastguard Worker inode = erofs_iget(st.st_dev, st.st_ino);
1144*33b1fccfSAndroid Build Coastguard Worker if (inode)
1145*33b1fccfSAndroid Build Coastguard Worker return inode;
1146*33b1fccfSAndroid Build Coastguard Worker }
1147*33b1fccfSAndroid Build Coastguard Worker
1148*33b1fccfSAndroid Build Coastguard Worker /* cannot find in the inode cache */
1149*33b1fccfSAndroid Build Coastguard Worker inode = erofs_new_inode(sbi);
1150*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(inode))
1151*33b1fccfSAndroid Build Coastguard Worker return inode;
1152*33b1fccfSAndroid Build Coastguard Worker
1153*33b1fccfSAndroid Build Coastguard Worker ret = erofs_fill_inode(inode, &st, path);
1154*33b1fccfSAndroid Build Coastguard Worker if (ret) {
1155*33b1fccfSAndroid Build Coastguard Worker erofs_iput(inode);
1156*33b1fccfSAndroid Build Coastguard Worker return ERR_PTR(ret);
1157*33b1fccfSAndroid Build Coastguard Worker }
1158*33b1fccfSAndroid Build Coastguard Worker return inode;
1159*33b1fccfSAndroid Build Coastguard Worker }
1160*33b1fccfSAndroid Build Coastguard Worker
erofs_fixup_meta_blkaddr(struct erofs_inode * rootdir)1161*33b1fccfSAndroid Build Coastguard Worker static void erofs_fixup_meta_blkaddr(struct erofs_inode *rootdir)
1162*33b1fccfSAndroid Build Coastguard Worker {
1163*33b1fccfSAndroid Build Coastguard Worker const erofs_off_t rootnid_maxoffset = 0xffff << EROFS_ISLOTBITS;
1164*33b1fccfSAndroid Build Coastguard Worker struct erofs_buffer_head *const bh = rootdir->bh;
1165*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = rootdir->sbi;
1166*33b1fccfSAndroid Build Coastguard Worker erofs_off_t off, meta_offset;
1167*33b1fccfSAndroid Build Coastguard Worker
1168*33b1fccfSAndroid Build Coastguard Worker erofs_mapbh(NULL, bh->block);
1169*33b1fccfSAndroid Build Coastguard Worker off = erofs_btell(bh, false);
1170*33b1fccfSAndroid Build Coastguard Worker
1171*33b1fccfSAndroid Build Coastguard Worker if (off > rootnid_maxoffset)
1172*33b1fccfSAndroid Build Coastguard Worker meta_offset = round_up(off - rootnid_maxoffset, erofs_blksiz(sbi));
1173*33b1fccfSAndroid Build Coastguard Worker else
1174*33b1fccfSAndroid Build Coastguard Worker meta_offset = 0;
1175*33b1fccfSAndroid Build Coastguard Worker sbi->meta_blkaddr = erofs_blknr(sbi, meta_offset);
1176*33b1fccfSAndroid Build Coastguard Worker rootdir->nid = (off - meta_offset) >> EROFS_ISLOTBITS;
1177*33b1fccfSAndroid Build Coastguard Worker }
1178*33b1fccfSAndroid Build Coastguard Worker
erofs_inode_reserve_data_blocks(struct erofs_inode * inode)1179*33b1fccfSAndroid Build Coastguard Worker static int erofs_inode_reserve_data_blocks(struct erofs_inode *inode)
1180*33b1fccfSAndroid Build Coastguard Worker {
1181*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = inode->sbi;
1182*33b1fccfSAndroid Build Coastguard Worker erofs_off_t alignedsz = round_up(inode->i_size, erofs_blksiz(sbi));
1183*33b1fccfSAndroid Build Coastguard Worker erofs_blk_t nblocks = alignedsz >> sbi->blkszbits;
1184*33b1fccfSAndroid Build Coastguard Worker struct erofs_buffer_head *bh;
1185*33b1fccfSAndroid Build Coastguard Worker
1186*33b1fccfSAndroid Build Coastguard Worker /* allocate data blocks */
1187*33b1fccfSAndroid Build Coastguard Worker bh = erofs_balloc(sbi->bmgr, DATA, alignedsz, 0, 0);
1188*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(bh))
1189*33b1fccfSAndroid Build Coastguard Worker return PTR_ERR(bh);
1190*33b1fccfSAndroid Build Coastguard Worker
1191*33b1fccfSAndroid Build Coastguard Worker /* get blkaddr of the bh */
1192*33b1fccfSAndroid Build Coastguard Worker (void)erofs_mapbh(NULL, bh->block);
1193*33b1fccfSAndroid Build Coastguard Worker
1194*33b1fccfSAndroid Build Coastguard Worker /* write blocks except for the tail-end block */
1195*33b1fccfSAndroid Build Coastguard Worker inode->u.i_blkaddr = bh->block->blkaddr;
1196*33b1fccfSAndroid Build Coastguard Worker erofs_bdrop(bh, false);
1197*33b1fccfSAndroid Build Coastguard Worker
1198*33b1fccfSAndroid Build Coastguard Worker inode->datalayout = EROFS_INODE_FLAT_PLAIN;
1199*33b1fccfSAndroid Build Coastguard Worker tarerofs_blocklist_write(inode->u.i_blkaddr, nblocks, inode->i_ino[1]);
1200*33b1fccfSAndroid Build Coastguard Worker return 0;
1201*33b1fccfSAndroid Build Coastguard Worker }
1202*33b1fccfSAndroid Build Coastguard Worker
1203*33b1fccfSAndroid Build Coastguard Worker struct erofs_mkfs_job_ndir_ctx {
1204*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *inode;
1205*33b1fccfSAndroid Build Coastguard Worker void *ictx;
1206*33b1fccfSAndroid Build Coastguard Worker int fd;
1207*33b1fccfSAndroid Build Coastguard Worker u64 fpos;
1208*33b1fccfSAndroid Build Coastguard Worker };
1209*33b1fccfSAndroid Build Coastguard Worker
erofs_mkfs_job_write_file(struct erofs_mkfs_job_ndir_ctx * ctx)1210*33b1fccfSAndroid Build Coastguard Worker static int erofs_mkfs_job_write_file(struct erofs_mkfs_job_ndir_ctx *ctx)
1211*33b1fccfSAndroid Build Coastguard Worker {
1212*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *inode = ctx->inode;
1213*33b1fccfSAndroid Build Coastguard Worker int ret;
1214*33b1fccfSAndroid Build Coastguard Worker
1215*33b1fccfSAndroid Build Coastguard Worker if (inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF &&
1216*33b1fccfSAndroid Build Coastguard Worker lseek(ctx->fd, ctx->fpos, SEEK_SET) < 0) {
1217*33b1fccfSAndroid Build Coastguard Worker ret = -errno;
1218*33b1fccfSAndroid Build Coastguard Worker goto out;
1219*33b1fccfSAndroid Build Coastguard Worker }
1220*33b1fccfSAndroid Build Coastguard Worker
1221*33b1fccfSAndroid Build Coastguard Worker if (ctx->ictx) {
1222*33b1fccfSAndroid Build Coastguard Worker ret = erofs_write_compressed_file(ctx->ictx);
1223*33b1fccfSAndroid Build Coastguard Worker if (ret != -ENOSPC)
1224*33b1fccfSAndroid Build Coastguard Worker goto out;
1225*33b1fccfSAndroid Build Coastguard Worker if (lseek(ctx->fd, ctx->fpos, SEEK_SET) < 0) {
1226*33b1fccfSAndroid Build Coastguard Worker ret = -errno;
1227*33b1fccfSAndroid Build Coastguard Worker goto out;
1228*33b1fccfSAndroid Build Coastguard Worker }
1229*33b1fccfSAndroid Build Coastguard Worker }
1230*33b1fccfSAndroid Build Coastguard Worker /* fallback to all data uncompressed */
1231*33b1fccfSAndroid Build Coastguard Worker ret = erofs_write_unencoded_file(inode, ctx->fd, ctx->fpos);
1232*33b1fccfSAndroid Build Coastguard Worker out:
1233*33b1fccfSAndroid Build Coastguard Worker if (inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF) {
1234*33b1fccfSAndroid Build Coastguard Worker erofs_diskbuf_close(inode->i_diskbuf);
1235*33b1fccfSAndroid Build Coastguard Worker free(inode->i_diskbuf);
1236*33b1fccfSAndroid Build Coastguard Worker inode->i_diskbuf = NULL;
1237*33b1fccfSAndroid Build Coastguard Worker inode->datasource = EROFS_INODE_DATA_SOURCE_NONE;
1238*33b1fccfSAndroid Build Coastguard Worker } else {
1239*33b1fccfSAndroid Build Coastguard Worker close(ctx->fd);
1240*33b1fccfSAndroid Build Coastguard Worker }
1241*33b1fccfSAndroid Build Coastguard Worker return ret;
1242*33b1fccfSAndroid Build Coastguard Worker }
1243*33b1fccfSAndroid Build Coastguard Worker
erofs_mkfs_handle_nondirectory(struct erofs_mkfs_job_ndir_ctx * ctx)1244*33b1fccfSAndroid Build Coastguard Worker static int erofs_mkfs_handle_nondirectory(struct erofs_mkfs_job_ndir_ctx *ctx)
1245*33b1fccfSAndroid Build Coastguard Worker {
1246*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *inode = ctx->inode;
1247*33b1fccfSAndroid Build Coastguard Worker int ret = 0;
1248*33b1fccfSAndroid Build Coastguard Worker
1249*33b1fccfSAndroid Build Coastguard Worker if (S_ISLNK(inode->i_mode)) {
1250*33b1fccfSAndroid Build Coastguard Worker char *symlink = inode->i_link;
1251*33b1fccfSAndroid Build Coastguard Worker
1252*33b1fccfSAndroid Build Coastguard Worker if (!symlink) {
1253*33b1fccfSAndroid Build Coastguard Worker symlink = malloc(inode->i_size);
1254*33b1fccfSAndroid Build Coastguard Worker if (!symlink)
1255*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
1256*33b1fccfSAndroid Build Coastguard Worker ret = readlink(inode->i_srcpath, symlink, inode->i_size);
1257*33b1fccfSAndroid Build Coastguard Worker if (ret < 0) {
1258*33b1fccfSAndroid Build Coastguard Worker free(symlink);
1259*33b1fccfSAndroid Build Coastguard Worker return -errno;
1260*33b1fccfSAndroid Build Coastguard Worker }
1261*33b1fccfSAndroid Build Coastguard Worker }
1262*33b1fccfSAndroid Build Coastguard Worker ret = erofs_write_file_from_buffer(inode, symlink);
1263*33b1fccfSAndroid Build Coastguard Worker free(symlink);
1264*33b1fccfSAndroid Build Coastguard Worker inode->i_link = NULL;
1265*33b1fccfSAndroid Build Coastguard Worker } else if (inode->i_size) {
1266*33b1fccfSAndroid Build Coastguard Worker if (inode->datasource == EROFS_INODE_DATA_SOURCE_RESVSP)
1267*33b1fccfSAndroid Build Coastguard Worker ret = erofs_inode_reserve_data_blocks(inode);
1268*33b1fccfSAndroid Build Coastguard Worker else if (ctx->fd >= 0)
1269*33b1fccfSAndroid Build Coastguard Worker ret = erofs_mkfs_job_write_file(ctx);
1270*33b1fccfSAndroid Build Coastguard Worker }
1271*33b1fccfSAndroid Build Coastguard Worker if (ret)
1272*33b1fccfSAndroid Build Coastguard Worker return ret;
1273*33b1fccfSAndroid Build Coastguard Worker erofs_prepare_inode_buffer(inode);
1274*33b1fccfSAndroid Build Coastguard Worker erofs_write_tail_end(inode);
1275*33b1fccfSAndroid Build Coastguard Worker return 0;
1276*33b1fccfSAndroid Build Coastguard Worker }
1277*33b1fccfSAndroid Build Coastguard Worker
1278*33b1fccfSAndroid Build Coastguard Worker enum erofs_mkfs_jobtype { /* ordered job types */
1279*33b1fccfSAndroid Build Coastguard Worker EROFS_MKFS_JOB_NDIR,
1280*33b1fccfSAndroid Build Coastguard Worker EROFS_MKFS_JOB_DIR,
1281*33b1fccfSAndroid Build Coastguard Worker EROFS_MKFS_JOB_DIR_BH,
1282*33b1fccfSAndroid Build Coastguard Worker EROFS_MKFS_JOB_MAX
1283*33b1fccfSAndroid Build Coastguard Worker };
1284*33b1fccfSAndroid Build Coastguard Worker
1285*33b1fccfSAndroid Build Coastguard Worker struct erofs_mkfs_jobitem {
1286*33b1fccfSAndroid Build Coastguard Worker enum erofs_mkfs_jobtype type;
1287*33b1fccfSAndroid Build Coastguard Worker union {
1288*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *inode;
1289*33b1fccfSAndroid Build Coastguard Worker struct erofs_mkfs_job_ndir_ctx ndir;
1290*33b1fccfSAndroid Build Coastguard Worker } u;
1291*33b1fccfSAndroid Build Coastguard Worker };
1292*33b1fccfSAndroid Build Coastguard Worker
erofs_mkfs_jobfn(struct erofs_mkfs_jobitem * item)1293*33b1fccfSAndroid Build Coastguard Worker static int erofs_mkfs_jobfn(struct erofs_mkfs_jobitem *item)
1294*33b1fccfSAndroid Build Coastguard Worker {
1295*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *inode = item->u.inode;
1296*33b1fccfSAndroid Build Coastguard Worker int ret;
1297*33b1fccfSAndroid Build Coastguard Worker
1298*33b1fccfSAndroid Build Coastguard Worker if (item->type == EROFS_MKFS_JOB_NDIR)
1299*33b1fccfSAndroid Build Coastguard Worker return erofs_mkfs_handle_nondirectory(&item->u.ndir);
1300*33b1fccfSAndroid Build Coastguard Worker
1301*33b1fccfSAndroid Build Coastguard Worker if (item->type == EROFS_MKFS_JOB_DIR) {
1302*33b1fccfSAndroid Build Coastguard Worker ret = erofs_prepare_inode_buffer(inode);
1303*33b1fccfSAndroid Build Coastguard Worker if (ret)
1304*33b1fccfSAndroid Build Coastguard Worker return ret;
1305*33b1fccfSAndroid Build Coastguard Worker inode->bh->op = &erofs_skip_write_bhops;
1306*33b1fccfSAndroid Build Coastguard Worker return 0;
1307*33b1fccfSAndroid Build Coastguard Worker }
1308*33b1fccfSAndroid Build Coastguard Worker
1309*33b1fccfSAndroid Build Coastguard Worker if (item->type == EROFS_MKFS_JOB_DIR_BH) {
1310*33b1fccfSAndroid Build Coastguard Worker ret = erofs_write_dir_file(inode);
1311*33b1fccfSAndroid Build Coastguard Worker if (ret)
1312*33b1fccfSAndroid Build Coastguard Worker return ret;
1313*33b1fccfSAndroid Build Coastguard Worker erofs_write_tail_end(inode);
1314*33b1fccfSAndroid Build Coastguard Worker inode->bh->op = &erofs_write_inode_bhops;
1315*33b1fccfSAndroid Build Coastguard Worker erofs_iput(inode);
1316*33b1fccfSAndroid Build Coastguard Worker return 0;
1317*33b1fccfSAndroid Build Coastguard Worker }
1318*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
1319*33b1fccfSAndroid Build Coastguard Worker }
1320*33b1fccfSAndroid Build Coastguard Worker
1321*33b1fccfSAndroid Build Coastguard Worker #ifdef EROFS_MT_ENABLED
1322*33b1fccfSAndroid Build Coastguard Worker
1323*33b1fccfSAndroid Build Coastguard Worker struct erofs_mkfs_dfops {
1324*33b1fccfSAndroid Build Coastguard Worker pthread_t worker;
1325*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_t lock;
1326*33b1fccfSAndroid Build Coastguard Worker pthread_cond_t full, empty, drain;
1327*33b1fccfSAndroid Build Coastguard Worker struct erofs_mkfs_jobitem *queue;
1328*33b1fccfSAndroid Build Coastguard Worker unsigned int entries, head, tail;
1329*33b1fccfSAndroid Build Coastguard Worker };
1330*33b1fccfSAndroid Build Coastguard Worker
1331*33b1fccfSAndroid Build Coastguard Worker #define EROFS_MT_QUEUE_SIZE 128
1332*33b1fccfSAndroid Build Coastguard Worker
erofs_mkfs_flushjobs(struct erofs_sb_info * sbi)1333*33b1fccfSAndroid Build Coastguard Worker static void erofs_mkfs_flushjobs(struct erofs_sb_info *sbi)
1334*33b1fccfSAndroid Build Coastguard Worker {
1335*33b1fccfSAndroid Build Coastguard Worker struct erofs_mkfs_dfops *q = sbi->mkfs_dfops;
1336*33b1fccfSAndroid Build Coastguard Worker
1337*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_lock(&q->lock);
1338*33b1fccfSAndroid Build Coastguard Worker pthread_cond_wait(&q->drain, &q->lock);
1339*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_unlock(&q->lock);
1340*33b1fccfSAndroid Build Coastguard Worker }
1341*33b1fccfSAndroid Build Coastguard Worker
erofs_mkfs_pop_jobitem(struct erofs_mkfs_dfops * q)1342*33b1fccfSAndroid Build Coastguard Worker static void *erofs_mkfs_pop_jobitem(struct erofs_mkfs_dfops *q)
1343*33b1fccfSAndroid Build Coastguard Worker {
1344*33b1fccfSAndroid Build Coastguard Worker struct erofs_mkfs_jobitem *item;
1345*33b1fccfSAndroid Build Coastguard Worker
1346*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_lock(&q->lock);
1347*33b1fccfSAndroid Build Coastguard Worker while (q->head == q->tail) {
1348*33b1fccfSAndroid Build Coastguard Worker pthread_cond_signal(&q->drain);
1349*33b1fccfSAndroid Build Coastguard Worker pthread_cond_wait(&q->empty, &q->lock);
1350*33b1fccfSAndroid Build Coastguard Worker }
1351*33b1fccfSAndroid Build Coastguard Worker
1352*33b1fccfSAndroid Build Coastguard Worker item = q->queue + q->head;
1353*33b1fccfSAndroid Build Coastguard Worker q->head = (q->head + 1) & (q->entries - 1);
1354*33b1fccfSAndroid Build Coastguard Worker
1355*33b1fccfSAndroid Build Coastguard Worker pthread_cond_signal(&q->full);
1356*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_unlock(&q->lock);
1357*33b1fccfSAndroid Build Coastguard Worker return item;
1358*33b1fccfSAndroid Build Coastguard Worker }
1359*33b1fccfSAndroid Build Coastguard Worker
z_erofs_mt_dfops_worker(void * arg)1360*33b1fccfSAndroid Build Coastguard Worker static void *z_erofs_mt_dfops_worker(void *arg)
1361*33b1fccfSAndroid Build Coastguard Worker {
1362*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = arg;
1363*33b1fccfSAndroid Build Coastguard Worker int ret = 0;
1364*33b1fccfSAndroid Build Coastguard Worker
1365*33b1fccfSAndroid Build Coastguard Worker while (1) {
1366*33b1fccfSAndroid Build Coastguard Worker struct erofs_mkfs_jobitem *item;
1367*33b1fccfSAndroid Build Coastguard Worker
1368*33b1fccfSAndroid Build Coastguard Worker item = erofs_mkfs_pop_jobitem(sbi->mkfs_dfops);
1369*33b1fccfSAndroid Build Coastguard Worker if (item->type >= EROFS_MKFS_JOB_MAX)
1370*33b1fccfSAndroid Build Coastguard Worker break;
1371*33b1fccfSAndroid Build Coastguard Worker ret = erofs_mkfs_jobfn(item);
1372*33b1fccfSAndroid Build Coastguard Worker if (ret)
1373*33b1fccfSAndroid Build Coastguard Worker break;
1374*33b1fccfSAndroid Build Coastguard Worker }
1375*33b1fccfSAndroid Build Coastguard Worker pthread_exit((void *)(uintptr_t)ret);
1376*33b1fccfSAndroid Build Coastguard Worker }
1377*33b1fccfSAndroid Build Coastguard Worker
erofs_mkfs_go(struct erofs_sb_info * sbi,enum erofs_mkfs_jobtype type,void * elem,int size)1378*33b1fccfSAndroid Build Coastguard Worker static int erofs_mkfs_go(struct erofs_sb_info *sbi,
1379*33b1fccfSAndroid Build Coastguard Worker enum erofs_mkfs_jobtype type, void *elem, int size)
1380*33b1fccfSAndroid Build Coastguard Worker {
1381*33b1fccfSAndroid Build Coastguard Worker struct erofs_mkfs_jobitem *item;
1382*33b1fccfSAndroid Build Coastguard Worker struct erofs_mkfs_dfops *q = sbi->mkfs_dfops;
1383*33b1fccfSAndroid Build Coastguard Worker
1384*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_lock(&q->lock);
1385*33b1fccfSAndroid Build Coastguard Worker
1386*33b1fccfSAndroid Build Coastguard Worker while (((q->tail + 1) & (q->entries - 1)) == q->head)
1387*33b1fccfSAndroid Build Coastguard Worker pthread_cond_wait(&q->full, &q->lock);
1388*33b1fccfSAndroid Build Coastguard Worker
1389*33b1fccfSAndroid Build Coastguard Worker item = q->queue + q->tail;
1390*33b1fccfSAndroid Build Coastguard Worker item->type = type;
1391*33b1fccfSAndroid Build Coastguard Worker memcpy(&item->u, elem, size);
1392*33b1fccfSAndroid Build Coastguard Worker q->tail = (q->tail + 1) & (q->entries - 1);
1393*33b1fccfSAndroid Build Coastguard Worker
1394*33b1fccfSAndroid Build Coastguard Worker pthread_cond_signal(&q->empty);
1395*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_unlock(&q->lock);
1396*33b1fccfSAndroid Build Coastguard Worker return 0;
1397*33b1fccfSAndroid Build Coastguard Worker }
1398*33b1fccfSAndroid Build Coastguard Worker #else
erofs_mkfs_go(struct erofs_sb_info * sbi,enum erofs_mkfs_jobtype type,void * elem,int size)1399*33b1fccfSAndroid Build Coastguard Worker static int erofs_mkfs_go(struct erofs_sb_info *sbi,
1400*33b1fccfSAndroid Build Coastguard Worker enum erofs_mkfs_jobtype type, void *elem, int size)
1401*33b1fccfSAndroid Build Coastguard Worker {
1402*33b1fccfSAndroid Build Coastguard Worker struct erofs_mkfs_jobitem item;
1403*33b1fccfSAndroid Build Coastguard Worker
1404*33b1fccfSAndroid Build Coastguard Worker item.type = type;
1405*33b1fccfSAndroid Build Coastguard Worker memcpy(&item.u, elem, size);
1406*33b1fccfSAndroid Build Coastguard Worker return erofs_mkfs_jobfn(&item);
1407*33b1fccfSAndroid Build Coastguard Worker }
erofs_mkfs_flushjobs(struct erofs_sb_info * sbi)1408*33b1fccfSAndroid Build Coastguard Worker static void erofs_mkfs_flushjobs(struct erofs_sb_info *sbi)
1409*33b1fccfSAndroid Build Coastguard Worker {
1410*33b1fccfSAndroid Build Coastguard Worker }
1411*33b1fccfSAndroid Build Coastguard Worker #endif
1412*33b1fccfSAndroid Build Coastguard Worker
erofs_mkfs_handle_directory(struct erofs_inode * dir)1413*33b1fccfSAndroid Build Coastguard Worker static int erofs_mkfs_handle_directory(struct erofs_inode *dir)
1414*33b1fccfSAndroid Build Coastguard Worker {
1415*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = dir->sbi;
1416*33b1fccfSAndroid Build Coastguard Worker DIR *_dir;
1417*33b1fccfSAndroid Build Coastguard Worker struct dirent *dp;
1418*33b1fccfSAndroid Build Coastguard Worker struct erofs_dentry *d;
1419*33b1fccfSAndroid Build Coastguard Worker unsigned int nr_subdirs, i_nlink;
1420*33b1fccfSAndroid Build Coastguard Worker int ret;
1421*33b1fccfSAndroid Build Coastguard Worker
1422*33b1fccfSAndroid Build Coastguard Worker _dir = opendir(dir->i_srcpath);
1423*33b1fccfSAndroid Build Coastguard Worker if (!_dir) {
1424*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to opendir at %s: %s",
1425*33b1fccfSAndroid Build Coastguard Worker dir->i_srcpath, erofs_strerror(-errno));
1426*33b1fccfSAndroid Build Coastguard Worker return -errno;
1427*33b1fccfSAndroid Build Coastguard Worker }
1428*33b1fccfSAndroid Build Coastguard Worker
1429*33b1fccfSAndroid Build Coastguard Worker nr_subdirs = 0;
1430*33b1fccfSAndroid Build Coastguard Worker i_nlink = 0;
1431*33b1fccfSAndroid Build Coastguard Worker while (1) {
1432*33b1fccfSAndroid Build Coastguard Worker char buf[PATH_MAX];
1433*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *inode;
1434*33b1fccfSAndroid Build Coastguard Worker
1435*33b1fccfSAndroid Build Coastguard Worker /*
1436*33b1fccfSAndroid Build Coastguard Worker * set errno to 0 before calling readdir() in order to
1437*33b1fccfSAndroid Build Coastguard Worker * distinguish end of stream and from an error.
1438*33b1fccfSAndroid Build Coastguard Worker */
1439*33b1fccfSAndroid Build Coastguard Worker errno = 0;
1440*33b1fccfSAndroid Build Coastguard Worker dp = readdir(_dir);
1441*33b1fccfSAndroid Build Coastguard Worker if (!dp) {
1442*33b1fccfSAndroid Build Coastguard Worker if (!errno)
1443*33b1fccfSAndroid Build Coastguard Worker break;
1444*33b1fccfSAndroid Build Coastguard Worker ret = -errno;
1445*33b1fccfSAndroid Build Coastguard Worker goto err_closedir;
1446*33b1fccfSAndroid Build Coastguard Worker }
1447*33b1fccfSAndroid Build Coastguard Worker
1448*33b1fccfSAndroid Build Coastguard Worker if (is_dot_dotdot(dp->d_name)) {
1449*33b1fccfSAndroid Build Coastguard Worker ++i_nlink;
1450*33b1fccfSAndroid Build Coastguard Worker continue;
1451*33b1fccfSAndroid Build Coastguard Worker }
1452*33b1fccfSAndroid Build Coastguard Worker
1453*33b1fccfSAndroid Build Coastguard Worker /* skip if it's a exclude file */
1454*33b1fccfSAndroid Build Coastguard Worker if (erofs_is_exclude_path(dir->i_srcpath, dp->d_name))
1455*33b1fccfSAndroid Build Coastguard Worker continue;
1456*33b1fccfSAndroid Build Coastguard Worker
1457*33b1fccfSAndroid Build Coastguard Worker d = erofs_d_alloc(dir, dp->d_name);
1458*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(d)) {
1459*33b1fccfSAndroid Build Coastguard Worker ret = PTR_ERR(d);
1460*33b1fccfSAndroid Build Coastguard Worker goto err_closedir;
1461*33b1fccfSAndroid Build Coastguard Worker }
1462*33b1fccfSAndroid Build Coastguard Worker
1463*33b1fccfSAndroid Build Coastguard Worker ret = snprintf(buf, PATH_MAX, "%s/%s", dir->i_srcpath, d->name);
1464*33b1fccfSAndroid Build Coastguard Worker if (ret < 0 || ret >= PATH_MAX)
1465*33b1fccfSAndroid Build Coastguard Worker goto err_closedir;
1466*33b1fccfSAndroid Build Coastguard Worker
1467*33b1fccfSAndroid Build Coastguard Worker inode = erofs_iget_from_srcpath(sbi, buf);
1468*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(inode)) {
1469*33b1fccfSAndroid Build Coastguard Worker ret = PTR_ERR(inode);
1470*33b1fccfSAndroid Build Coastguard Worker goto err_closedir;
1471*33b1fccfSAndroid Build Coastguard Worker }
1472*33b1fccfSAndroid Build Coastguard Worker d->inode = inode;
1473*33b1fccfSAndroid Build Coastguard Worker d->type = erofs_mode_to_ftype(inode->i_mode);
1474*33b1fccfSAndroid Build Coastguard Worker i_nlink += S_ISDIR(inode->i_mode);
1475*33b1fccfSAndroid Build Coastguard Worker erofs_dbg("file %s added (type %u)", buf, d->type);
1476*33b1fccfSAndroid Build Coastguard Worker nr_subdirs++;
1477*33b1fccfSAndroid Build Coastguard Worker }
1478*33b1fccfSAndroid Build Coastguard Worker closedir(_dir);
1479*33b1fccfSAndroid Build Coastguard Worker
1480*33b1fccfSAndroid Build Coastguard Worker ret = erofs_init_empty_dir(dir);
1481*33b1fccfSAndroid Build Coastguard Worker if (ret)
1482*33b1fccfSAndroid Build Coastguard Worker return ret;
1483*33b1fccfSAndroid Build Coastguard Worker
1484*33b1fccfSAndroid Build Coastguard Worker ret = erofs_prepare_dir_file(dir, nr_subdirs + 2); /* sort subdirs */
1485*33b1fccfSAndroid Build Coastguard Worker if (ret)
1486*33b1fccfSAndroid Build Coastguard Worker return ret;
1487*33b1fccfSAndroid Build Coastguard Worker
1488*33b1fccfSAndroid Build Coastguard Worker /*
1489*33b1fccfSAndroid Build Coastguard Worker * if there're too many subdirs as compact form, set nlink=1
1490*33b1fccfSAndroid Build Coastguard Worker * rather than upgrade to use extented form instead.
1491*33b1fccfSAndroid Build Coastguard Worker */
1492*33b1fccfSAndroid Build Coastguard Worker if (i_nlink > USHRT_MAX &&
1493*33b1fccfSAndroid Build Coastguard Worker dir->inode_isize == sizeof(struct erofs_inode_compact))
1494*33b1fccfSAndroid Build Coastguard Worker dir->i_nlink = 1;
1495*33b1fccfSAndroid Build Coastguard Worker else
1496*33b1fccfSAndroid Build Coastguard Worker dir->i_nlink = i_nlink;
1497*33b1fccfSAndroid Build Coastguard Worker
1498*33b1fccfSAndroid Build Coastguard Worker return erofs_mkfs_go(sbi, EROFS_MKFS_JOB_DIR, &dir, sizeof(dir));
1499*33b1fccfSAndroid Build Coastguard Worker
1500*33b1fccfSAndroid Build Coastguard Worker err_closedir:
1501*33b1fccfSAndroid Build Coastguard Worker closedir(_dir);
1502*33b1fccfSAndroid Build Coastguard Worker return ret;
1503*33b1fccfSAndroid Build Coastguard Worker }
1504*33b1fccfSAndroid Build Coastguard Worker
1505*33b1fccfSAndroid Build Coastguard Worker int erofs_rebuild_load_basedir(struct erofs_inode *dir);
1506*33b1fccfSAndroid Build Coastguard Worker
erofs_dentry_is_wht(struct erofs_sb_info * sbi,struct erofs_dentry * d)1507*33b1fccfSAndroid Build Coastguard Worker bool erofs_dentry_is_wht(struct erofs_sb_info *sbi, struct erofs_dentry *d)
1508*33b1fccfSAndroid Build Coastguard Worker {
1509*33b1fccfSAndroid Build Coastguard Worker if (!d->validnid)
1510*33b1fccfSAndroid Build Coastguard Worker return erofs_inode_is_whiteout(d->inode);
1511*33b1fccfSAndroid Build Coastguard Worker if (d->type == EROFS_FT_CHRDEV) {
1512*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode ei = { .sbi = sbi, .nid = d->nid };
1513*33b1fccfSAndroid Build Coastguard Worker int ret;
1514*33b1fccfSAndroid Build Coastguard Worker
1515*33b1fccfSAndroid Build Coastguard Worker ret = erofs_read_inode_from_disk(&ei);
1516*33b1fccfSAndroid Build Coastguard Worker if (ret) {
1517*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to check DT_WHT: %s",
1518*33b1fccfSAndroid Build Coastguard Worker erofs_strerror(ret));
1519*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(1);
1520*33b1fccfSAndroid Build Coastguard Worker return false;
1521*33b1fccfSAndroid Build Coastguard Worker }
1522*33b1fccfSAndroid Build Coastguard Worker return erofs_inode_is_whiteout(&ei);
1523*33b1fccfSAndroid Build Coastguard Worker }
1524*33b1fccfSAndroid Build Coastguard Worker return false;
1525*33b1fccfSAndroid Build Coastguard Worker }
1526*33b1fccfSAndroid Build Coastguard Worker
erofs_rebuild_handle_directory(struct erofs_inode * dir,bool incremental)1527*33b1fccfSAndroid Build Coastguard Worker static int erofs_rebuild_handle_directory(struct erofs_inode *dir,
1528*33b1fccfSAndroid Build Coastguard Worker bool incremental)
1529*33b1fccfSAndroid Build Coastguard Worker {
1530*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = dir->sbi;
1531*33b1fccfSAndroid Build Coastguard Worker struct erofs_dentry *d, *n;
1532*33b1fccfSAndroid Build Coastguard Worker unsigned int nr_subdirs, i_nlink;
1533*33b1fccfSAndroid Build Coastguard Worker bool delwht = cfg.c_ovlfs_strip && dir->whiteouts;
1534*33b1fccfSAndroid Build Coastguard Worker int ret;
1535*33b1fccfSAndroid Build Coastguard Worker
1536*33b1fccfSAndroid Build Coastguard Worker nr_subdirs = 0;
1537*33b1fccfSAndroid Build Coastguard Worker i_nlink = 0;
1538*33b1fccfSAndroid Build Coastguard Worker
1539*33b1fccfSAndroid Build Coastguard Worker list_for_each_entry_safe(d, n, &dir->i_subdirs, d_child) {
1540*33b1fccfSAndroid Build Coastguard Worker if (delwht && erofs_dentry_is_wht(sbi, d)) {
1541*33b1fccfSAndroid Build Coastguard Worker erofs_dbg("remove whiteout %s", d->inode->i_srcpath);
1542*33b1fccfSAndroid Build Coastguard Worker list_del(&d->d_child);
1543*33b1fccfSAndroid Build Coastguard Worker erofs_d_invalidate(d);
1544*33b1fccfSAndroid Build Coastguard Worker free(d);
1545*33b1fccfSAndroid Build Coastguard Worker continue;
1546*33b1fccfSAndroid Build Coastguard Worker }
1547*33b1fccfSAndroid Build Coastguard Worker i_nlink += (d->type == EROFS_FT_DIR);
1548*33b1fccfSAndroid Build Coastguard Worker ++nr_subdirs;
1549*33b1fccfSAndroid Build Coastguard Worker }
1550*33b1fccfSAndroid Build Coastguard Worker
1551*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(i_nlink < 2); /* should have `.` and `..` */
1552*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(nr_subdirs < i_nlink);
1553*33b1fccfSAndroid Build Coastguard Worker ret = erofs_prepare_dir_file(dir, nr_subdirs);
1554*33b1fccfSAndroid Build Coastguard Worker if (ret)
1555*33b1fccfSAndroid Build Coastguard Worker return ret;
1556*33b1fccfSAndroid Build Coastguard Worker
1557*33b1fccfSAndroid Build Coastguard Worker if (IS_ROOT(dir) && incremental)
1558*33b1fccfSAndroid Build Coastguard Worker dir->datalayout = EROFS_INODE_FLAT_PLAIN;
1559*33b1fccfSAndroid Build Coastguard Worker
1560*33b1fccfSAndroid Build Coastguard Worker /*
1561*33b1fccfSAndroid Build Coastguard Worker * if there're too many subdirs as compact form, set nlink=1
1562*33b1fccfSAndroid Build Coastguard Worker * rather than upgrade to use extented form instead.
1563*33b1fccfSAndroid Build Coastguard Worker */
1564*33b1fccfSAndroid Build Coastguard Worker if (i_nlink > USHRT_MAX &&
1565*33b1fccfSAndroid Build Coastguard Worker dir->inode_isize == sizeof(struct erofs_inode_compact))
1566*33b1fccfSAndroid Build Coastguard Worker dir->i_nlink = 1;
1567*33b1fccfSAndroid Build Coastguard Worker else
1568*33b1fccfSAndroid Build Coastguard Worker dir->i_nlink = i_nlink;
1569*33b1fccfSAndroid Build Coastguard Worker
1570*33b1fccfSAndroid Build Coastguard Worker return erofs_mkfs_go(sbi, EROFS_MKFS_JOB_DIR, &dir, sizeof(dir));
1571*33b1fccfSAndroid Build Coastguard Worker }
1572*33b1fccfSAndroid Build Coastguard Worker
erofs_mkfs_handle_inode(struct erofs_inode * inode)1573*33b1fccfSAndroid Build Coastguard Worker static int erofs_mkfs_handle_inode(struct erofs_inode *inode)
1574*33b1fccfSAndroid Build Coastguard Worker {
1575*33b1fccfSAndroid Build Coastguard Worker const char *relpath = erofs_fspath(inode->i_srcpath);
1576*33b1fccfSAndroid Build Coastguard Worker char *trimmed;
1577*33b1fccfSAndroid Build Coastguard Worker int ret;
1578*33b1fccfSAndroid Build Coastguard Worker
1579*33b1fccfSAndroid Build Coastguard Worker trimmed = erofs_trim_for_progressinfo(relpath[0] ? relpath : "/",
1580*33b1fccfSAndroid Build Coastguard Worker sizeof("Processing ...") - 1);
1581*33b1fccfSAndroid Build Coastguard Worker erofs_update_progressinfo("Processing %s ...", trimmed);
1582*33b1fccfSAndroid Build Coastguard Worker free(trimmed);
1583*33b1fccfSAndroid Build Coastguard Worker
1584*33b1fccfSAndroid Build Coastguard Worker ret = erofs_scan_file_xattrs(inode);
1585*33b1fccfSAndroid Build Coastguard Worker if (ret < 0)
1586*33b1fccfSAndroid Build Coastguard Worker return ret;
1587*33b1fccfSAndroid Build Coastguard Worker
1588*33b1fccfSAndroid Build Coastguard Worker ret = erofs_prepare_xattr_ibody(inode, false);
1589*33b1fccfSAndroid Build Coastguard Worker if (ret < 0)
1590*33b1fccfSAndroid Build Coastguard Worker return ret;
1591*33b1fccfSAndroid Build Coastguard Worker
1592*33b1fccfSAndroid Build Coastguard Worker if (!S_ISDIR(inode->i_mode)) {
1593*33b1fccfSAndroid Build Coastguard Worker struct erofs_mkfs_job_ndir_ctx ctx = { .inode = inode };
1594*33b1fccfSAndroid Build Coastguard Worker
1595*33b1fccfSAndroid Build Coastguard Worker if (!S_ISLNK(inode->i_mode) && inode->i_size) {
1596*33b1fccfSAndroid Build Coastguard Worker ctx.fd = open(inode->i_srcpath, O_RDONLY | O_BINARY);
1597*33b1fccfSAndroid Build Coastguard Worker if (ctx.fd < 0)
1598*33b1fccfSAndroid Build Coastguard Worker return -errno;
1599*33b1fccfSAndroid Build Coastguard Worker
1600*33b1fccfSAndroid Build Coastguard Worker if (cfg.c_compr_opts[0].alg &&
1601*33b1fccfSAndroid Build Coastguard Worker erofs_file_is_compressible(inode)) {
1602*33b1fccfSAndroid Build Coastguard Worker ctx.ictx = erofs_begin_compressed_file(inode,
1603*33b1fccfSAndroid Build Coastguard Worker ctx.fd, 0);
1604*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(ctx.ictx))
1605*33b1fccfSAndroid Build Coastguard Worker return PTR_ERR(ctx.ictx);
1606*33b1fccfSAndroid Build Coastguard Worker }
1607*33b1fccfSAndroid Build Coastguard Worker }
1608*33b1fccfSAndroid Build Coastguard Worker ret = erofs_mkfs_go(inode->sbi, EROFS_MKFS_JOB_NDIR,
1609*33b1fccfSAndroid Build Coastguard Worker &ctx, sizeof(ctx));
1610*33b1fccfSAndroid Build Coastguard Worker } else {
1611*33b1fccfSAndroid Build Coastguard Worker ret = erofs_mkfs_handle_directory(inode);
1612*33b1fccfSAndroid Build Coastguard Worker }
1613*33b1fccfSAndroid Build Coastguard Worker erofs_info("file /%s dumped (mode %05o)", relpath, inode->i_mode);
1614*33b1fccfSAndroid Build Coastguard Worker return ret;
1615*33b1fccfSAndroid Build Coastguard Worker }
1616*33b1fccfSAndroid Build Coastguard Worker
erofs_rebuild_handle_inode(struct erofs_inode * inode,bool incremental)1617*33b1fccfSAndroid Build Coastguard Worker static int erofs_rebuild_handle_inode(struct erofs_inode *inode,
1618*33b1fccfSAndroid Build Coastguard Worker bool incremental)
1619*33b1fccfSAndroid Build Coastguard Worker {
1620*33b1fccfSAndroid Build Coastguard Worker char *trimmed;
1621*33b1fccfSAndroid Build Coastguard Worker int ret;
1622*33b1fccfSAndroid Build Coastguard Worker
1623*33b1fccfSAndroid Build Coastguard Worker trimmed = erofs_trim_for_progressinfo(erofs_fspath(inode->i_srcpath),
1624*33b1fccfSAndroid Build Coastguard Worker sizeof("Processing ...") - 1);
1625*33b1fccfSAndroid Build Coastguard Worker erofs_update_progressinfo("Processing %s ...", trimmed);
1626*33b1fccfSAndroid Build Coastguard Worker free(trimmed);
1627*33b1fccfSAndroid Build Coastguard Worker
1628*33b1fccfSAndroid Build Coastguard Worker if (erofs_should_use_inode_extended(inode)) {
1629*33b1fccfSAndroid Build Coastguard Worker if (cfg.c_force_inodeversion == FORCE_INODE_COMPACT) {
1630*33b1fccfSAndroid Build Coastguard Worker erofs_err("file %s cannot be in compact form",
1631*33b1fccfSAndroid Build Coastguard Worker inode->i_srcpath);
1632*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
1633*33b1fccfSAndroid Build Coastguard Worker }
1634*33b1fccfSAndroid Build Coastguard Worker inode->inode_isize = sizeof(struct erofs_inode_extended);
1635*33b1fccfSAndroid Build Coastguard Worker } else {
1636*33b1fccfSAndroid Build Coastguard Worker inode->inode_isize = sizeof(struct erofs_inode_compact);
1637*33b1fccfSAndroid Build Coastguard Worker }
1638*33b1fccfSAndroid Build Coastguard Worker
1639*33b1fccfSAndroid Build Coastguard Worker if (incremental && S_ISDIR(inode->i_mode) &&
1640*33b1fccfSAndroid Build Coastguard Worker inode->dev == inode->sbi->dev && !inode->opaque) {
1641*33b1fccfSAndroid Build Coastguard Worker ret = erofs_rebuild_load_basedir(inode);
1642*33b1fccfSAndroid Build Coastguard Worker if (ret)
1643*33b1fccfSAndroid Build Coastguard Worker return ret;
1644*33b1fccfSAndroid Build Coastguard Worker }
1645*33b1fccfSAndroid Build Coastguard Worker
1646*33b1fccfSAndroid Build Coastguard Worker /* strip all unnecessary overlayfs xattrs when ovlfs_strip is enabled */
1647*33b1fccfSAndroid Build Coastguard Worker if (cfg.c_ovlfs_strip)
1648*33b1fccfSAndroid Build Coastguard Worker erofs_clear_opaque_xattr(inode);
1649*33b1fccfSAndroid Build Coastguard Worker else if (inode->whiteouts)
1650*33b1fccfSAndroid Build Coastguard Worker erofs_set_origin_xattr(inode);
1651*33b1fccfSAndroid Build Coastguard Worker
1652*33b1fccfSAndroid Build Coastguard Worker ret = erofs_prepare_xattr_ibody(inode, incremental && IS_ROOT(inode));
1653*33b1fccfSAndroid Build Coastguard Worker if (ret < 0)
1654*33b1fccfSAndroid Build Coastguard Worker return ret;
1655*33b1fccfSAndroid Build Coastguard Worker
1656*33b1fccfSAndroid Build Coastguard Worker if (!S_ISDIR(inode->i_mode)) {
1657*33b1fccfSAndroid Build Coastguard Worker struct erofs_mkfs_job_ndir_ctx ctx =
1658*33b1fccfSAndroid Build Coastguard Worker { .inode = inode, .fd = -1 };
1659*33b1fccfSAndroid Build Coastguard Worker
1660*33b1fccfSAndroid Build Coastguard Worker if (S_ISREG(inode->i_mode) && inode->i_size &&
1661*33b1fccfSAndroid Build Coastguard Worker inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF) {
1662*33b1fccfSAndroid Build Coastguard Worker ctx.fd = erofs_diskbuf_getfd(inode->i_diskbuf, &ctx.fpos);
1663*33b1fccfSAndroid Build Coastguard Worker if (ctx.fd < 0)
1664*33b1fccfSAndroid Build Coastguard Worker return ret;
1665*33b1fccfSAndroid Build Coastguard Worker
1666*33b1fccfSAndroid Build Coastguard Worker if (cfg.c_compr_opts[0].alg &&
1667*33b1fccfSAndroid Build Coastguard Worker erofs_file_is_compressible(inode)) {
1668*33b1fccfSAndroid Build Coastguard Worker ctx.ictx = erofs_begin_compressed_file(inode,
1669*33b1fccfSAndroid Build Coastguard Worker ctx.fd, ctx.fpos);
1670*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(ctx.ictx))
1671*33b1fccfSAndroid Build Coastguard Worker return PTR_ERR(ctx.ictx);
1672*33b1fccfSAndroid Build Coastguard Worker }
1673*33b1fccfSAndroid Build Coastguard Worker }
1674*33b1fccfSAndroid Build Coastguard Worker ret = erofs_mkfs_go(inode->sbi, EROFS_MKFS_JOB_NDIR,
1675*33b1fccfSAndroid Build Coastguard Worker &ctx, sizeof(ctx));
1676*33b1fccfSAndroid Build Coastguard Worker } else {
1677*33b1fccfSAndroid Build Coastguard Worker ret = erofs_rebuild_handle_directory(inode, incremental);
1678*33b1fccfSAndroid Build Coastguard Worker }
1679*33b1fccfSAndroid Build Coastguard Worker erofs_info("file %s dumped (mode %05o)", erofs_fspath(inode->i_srcpath),
1680*33b1fccfSAndroid Build Coastguard Worker inode->i_mode);
1681*33b1fccfSAndroid Build Coastguard Worker return ret;
1682*33b1fccfSAndroid Build Coastguard Worker }
1683*33b1fccfSAndroid Build Coastguard Worker
erofs_inode_visited(struct erofs_inode * inode)1684*33b1fccfSAndroid Build Coastguard Worker static bool erofs_inode_visited(struct erofs_inode *inode)
1685*33b1fccfSAndroid Build Coastguard Worker {
1686*33b1fccfSAndroid Build Coastguard Worker return (unsigned long)inode->i_parent & 1UL;
1687*33b1fccfSAndroid Build Coastguard Worker }
1688*33b1fccfSAndroid Build Coastguard Worker
erofs_mark_parent_inode(struct erofs_inode * inode,struct erofs_inode * dir)1689*33b1fccfSAndroid Build Coastguard Worker static void erofs_mark_parent_inode(struct erofs_inode *inode,
1690*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *dir)
1691*33b1fccfSAndroid Build Coastguard Worker {
1692*33b1fccfSAndroid Build Coastguard Worker inode->i_parent = (void *)((unsigned long)dir | 1);
1693*33b1fccfSAndroid Build Coastguard Worker }
1694*33b1fccfSAndroid Build Coastguard Worker
erofs_mkfs_dump_tree(struct erofs_inode * root,bool rebuild,bool incremental)1695*33b1fccfSAndroid Build Coastguard Worker static int erofs_mkfs_dump_tree(struct erofs_inode *root, bool rebuild,
1696*33b1fccfSAndroid Build Coastguard Worker bool incremental)
1697*33b1fccfSAndroid Build Coastguard Worker {
1698*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = root->sbi;
1699*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *dumpdir = erofs_igrab(root);
1700*33b1fccfSAndroid Build Coastguard Worker int err;
1701*33b1fccfSAndroid Build Coastguard Worker
1702*33b1fccfSAndroid Build Coastguard Worker erofs_mark_parent_inode(root, root); /* rootdir mark */
1703*33b1fccfSAndroid Build Coastguard Worker root->next_dirwrite = NULL;
1704*33b1fccfSAndroid Build Coastguard Worker /* update dev/i_ino[1] to keep track of the base image */
1705*33b1fccfSAndroid Build Coastguard Worker if (incremental) {
1706*33b1fccfSAndroid Build Coastguard Worker root->dev = root->sbi->dev;
1707*33b1fccfSAndroid Build Coastguard Worker root->i_ino[1] = sbi->root_nid;
1708*33b1fccfSAndroid Build Coastguard Worker list_del(&root->i_hash);
1709*33b1fccfSAndroid Build Coastguard Worker erofs_insert_ihash(root);
1710*33b1fccfSAndroid Build Coastguard Worker } else if (cfg.c_root_xattr_isize) {
1711*33b1fccfSAndroid Build Coastguard Worker root->xattr_isize = cfg.c_root_xattr_isize;
1712*33b1fccfSAndroid Build Coastguard Worker }
1713*33b1fccfSAndroid Build Coastguard Worker
1714*33b1fccfSAndroid Build Coastguard Worker err = !rebuild ? erofs_mkfs_handle_inode(root) :
1715*33b1fccfSAndroid Build Coastguard Worker erofs_rebuild_handle_inode(root, incremental);
1716*33b1fccfSAndroid Build Coastguard Worker if (err)
1717*33b1fccfSAndroid Build Coastguard Worker return err;
1718*33b1fccfSAndroid Build Coastguard Worker
1719*33b1fccfSAndroid Build Coastguard Worker /* assign root NID immediately for non-incremental builds */
1720*33b1fccfSAndroid Build Coastguard Worker if (!incremental) {
1721*33b1fccfSAndroid Build Coastguard Worker erofs_mkfs_flushjobs(sbi);
1722*33b1fccfSAndroid Build Coastguard Worker erofs_fixup_meta_blkaddr(root);
1723*33b1fccfSAndroid Build Coastguard Worker sbi->root_nid = root->nid;
1724*33b1fccfSAndroid Build Coastguard Worker }
1725*33b1fccfSAndroid Build Coastguard Worker
1726*33b1fccfSAndroid Build Coastguard Worker do {
1727*33b1fccfSAndroid Build Coastguard Worker int err;
1728*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *dir = dumpdir;
1729*33b1fccfSAndroid Build Coastguard Worker /* used for adding sub-directories in reverse order due to FIFO */
1730*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *head, **last = &head;
1731*33b1fccfSAndroid Build Coastguard Worker struct erofs_dentry *d;
1732*33b1fccfSAndroid Build Coastguard Worker
1733*33b1fccfSAndroid Build Coastguard Worker dumpdir = dir->next_dirwrite;
1734*33b1fccfSAndroid Build Coastguard Worker list_for_each_entry(d, &dir->i_subdirs, d_child) {
1735*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *inode = d->inode;
1736*33b1fccfSAndroid Build Coastguard Worker
1737*33b1fccfSAndroid Build Coastguard Worker if (is_dot_dotdot(d->name) || d->validnid)
1738*33b1fccfSAndroid Build Coastguard Worker continue;
1739*33b1fccfSAndroid Build Coastguard Worker
1740*33b1fccfSAndroid Build Coastguard Worker if (!erofs_inode_visited(inode)) {
1741*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(rebuild &&
1742*33b1fccfSAndroid Build Coastguard Worker erofs_parent_inode(inode) != dir);
1743*33b1fccfSAndroid Build Coastguard Worker erofs_mark_parent_inode(inode, dir);
1744*33b1fccfSAndroid Build Coastguard Worker
1745*33b1fccfSAndroid Build Coastguard Worker if (!rebuild)
1746*33b1fccfSAndroid Build Coastguard Worker err = erofs_mkfs_handle_inode(inode);
1747*33b1fccfSAndroid Build Coastguard Worker else
1748*33b1fccfSAndroid Build Coastguard Worker err = erofs_rebuild_handle_inode(inode,
1749*33b1fccfSAndroid Build Coastguard Worker incremental);
1750*33b1fccfSAndroid Build Coastguard Worker if (err)
1751*33b1fccfSAndroid Build Coastguard Worker break;
1752*33b1fccfSAndroid Build Coastguard Worker if (S_ISDIR(inode->i_mode)) {
1753*33b1fccfSAndroid Build Coastguard Worker *last = inode;
1754*33b1fccfSAndroid Build Coastguard Worker last = &inode->next_dirwrite;
1755*33b1fccfSAndroid Build Coastguard Worker (void)erofs_igrab(inode);
1756*33b1fccfSAndroid Build Coastguard Worker }
1757*33b1fccfSAndroid Build Coastguard Worker } else if (!rebuild) {
1758*33b1fccfSAndroid Build Coastguard Worker ++inode->i_nlink;
1759*33b1fccfSAndroid Build Coastguard Worker }
1760*33b1fccfSAndroid Build Coastguard Worker }
1761*33b1fccfSAndroid Build Coastguard Worker *last = dumpdir; /* fixup the last (or the only) one */
1762*33b1fccfSAndroid Build Coastguard Worker dumpdir = head;
1763*33b1fccfSAndroid Build Coastguard Worker err = erofs_mkfs_go(sbi, EROFS_MKFS_JOB_DIR_BH,
1764*33b1fccfSAndroid Build Coastguard Worker &dir, sizeof(dir));
1765*33b1fccfSAndroid Build Coastguard Worker if (err)
1766*33b1fccfSAndroid Build Coastguard Worker return err;
1767*33b1fccfSAndroid Build Coastguard Worker } while (dumpdir);
1768*33b1fccfSAndroid Build Coastguard Worker
1769*33b1fccfSAndroid Build Coastguard Worker return err;
1770*33b1fccfSAndroid Build Coastguard Worker }
1771*33b1fccfSAndroid Build Coastguard Worker
1772*33b1fccfSAndroid Build Coastguard Worker struct erofs_mkfs_buildtree_ctx {
1773*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi;
1774*33b1fccfSAndroid Build Coastguard Worker union {
1775*33b1fccfSAndroid Build Coastguard Worker const char *path;
1776*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *root;
1777*33b1fccfSAndroid Build Coastguard Worker } u;
1778*33b1fccfSAndroid Build Coastguard Worker bool incremental;
1779*33b1fccfSAndroid Build Coastguard Worker };
1780*33b1fccfSAndroid Build Coastguard Worker #ifndef EROFS_MT_ENABLED
1781*33b1fccfSAndroid Build Coastguard Worker #define __erofs_mkfs_build_tree erofs_mkfs_build_tree
1782*33b1fccfSAndroid Build Coastguard Worker #endif
1783*33b1fccfSAndroid Build Coastguard Worker
__erofs_mkfs_build_tree(struct erofs_mkfs_buildtree_ctx * ctx)1784*33b1fccfSAndroid Build Coastguard Worker static int __erofs_mkfs_build_tree(struct erofs_mkfs_buildtree_ctx *ctx)
1785*33b1fccfSAndroid Build Coastguard Worker {
1786*33b1fccfSAndroid Build Coastguard Worker bool from_path = !!ctx->sbi;
1787*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *root;
1788*33b1fccfSAndroid Build Coastguard Worker int err;
1789*33b1fccfSAndroid Build Coastguard Worker
1790*33b1fccfSAndroid Build Coastguard Worker if (from_path) {
1791*33b1fccfSAndroid Build Coastguard Worker root = erofs_iget_from_srcpath(ctx->sbi, ctx->u.path);
1792*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(root))
1793*33b1fccfSAndroid Build Coastguard Worker return PTR_ERR(root);
1794*33b1fccfSAndroid Build Coastguard Worker } else {
1795*33b1fccfSAndroid Build Coastguard Worker root = ctx->u.root;
1796*33b1fccfSAndroid Build Coastguard Worker }
1797*33b1fccfSAndroid Build Coastguard Worker
1798*33b1fccfSAndroid Build Coastguard Worker err = erofs_mkfs_dump_tree(root, !from_path, ctx->incremental);
1799*33b1fccfSAndroid Build Coastguard Worker if (err) {
1800*33b1fccfSAndroid Build Coastguard Worker if (from_path)
1801*33b1fccfSAndroid Build Coastguard Worker erofs_iput(root);
1802*33b1fccfSAndroid Build Coastguard Worker return err;
1803*33b1fccfSAndroid Build Coastguard Worker }
1804*33b1fccfSAndroid Build Coastguard Worker ctx->u.root = root;
1805*33b1fccfSAndroid Build Coastguard Worker return 0;
1806*33b1fccfSAndroid Build Coastguard Worker }
1807*33b1fccfSAndroid Build Coastguard Worker
1808*33b1fccfSAndroid Build Coastguard Worker #ifdef EROFS_MT_ENABLED
erofs_mkfs_build_tree(struct erofs_mkfs_buildtree_ctx * ctx)1809*33b1fccfSAndroid Build Coastguard Worker static int erofs_mkfs_build_tree(struct erofs_mkfs_buildtree_ctx *ctx)
1810*33b1fccfSAndroid Build Coastguard Worker {
1811*33b1fccfSAndroid Build Coastguard Worker struct erofs_mkfs_dfops *q;
1812*33b1fccfSAndroid Build Coastguard Worker int err, err2;
1813*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = ctx->sbi ? ctx->sbi : ctx->u.root->sbi;
1814*33b1fccfSAndroid Build Coastguard Worker
1815*33b1fccfSAndroid Build Coastguard Worker q = malloc(sizeof(*q));
1816*33b1fccfSAndroid Build Coastguard Worker if (!q)
1817*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
1818*33b1fccfSAndroid Build Coastguard Worker
1819*33b1fccfSAndroid Build Coastguard Worker q->entries = EROFS_MT_QUEUE_SIZE;
1820*33b1fccfSAndroid Build Coastguard Worker q->queue = malloc(q->entries * sizeof(*q->queue));
1821*33b1fccfSAndroid Build Coastguard Worker if (!q->queue) {
1822*33b1fccfSAndroid Build Coastguard Worker free(q);
1823*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
1824*33b1fccfSAndroid Build Coastguard Worker }
1825*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_init(&q->lock, NULL);
1826*33b1fccfSAndroid Build Coastguard Worker pthread_cond_init(&q->empty, NULL);
1827*33b1fccfSAndroid Build Coastguard Worker pthread_cond_init(&q->full, NULL);
1828*33b1fccfSAndroid Build Coastguard Worker pthread_cond_init(&q->drain, NULL);
1829*33b1fccfSAndroid Build Coastguard Worker
1830*33b1fccfSAndroid Build Coastguard Worker q->head = 0;
1831*33b1fccfSAndroid Build Coastguard Worker q->tail = 0;
1832*33b1fccfSAndroid Build Coastguard Worker sbi->mkfs_dfops = q;
1833*33b1fccfSAndroid Build Coastguard Worker err = pthread_create(&sbi->dfops_worker, NULL,
1834*33b1fccfSAndroid Build Coastguard Worker z_erofs_mt_dfops_worker, sbi);
1835*33b1fccfSAndroid Build Coastguard Worker if (err)
1836*33b1fccfSAndroid Build Coastguard Worker goto fail;
1837*33b1fccfSAndroid Build Coastguard Worker
1838*33b1fccfSAndroid Build Coastguard Worker err = __erofs_mkfs_build_tree(ctx);
1839*33b1fccfSAndroid Build Coastguard Worker erofs_mkfs_go(sbi, ~0, NULL, 0);
1840*33b1fccfSAndroid Build Coastguard Worker err2 = pthread_join(sbi->dfops_worker, NULL);
1841*33b1fccfSAndroid Build Coastguard Worker if (!err)
1842*33b1fccfSAndroid Build Coastguard Worker err = err2;
1843*33b1fccfSAndroid Build Coastguard Worker
1844*33b1fccfSAndroid Build Coastguard Worker fail:
1845*33b1fccfSAndroid Build Coastguard Worker pthread_cond_destroy(&q->empty);
1846*33b1fccfSAndroid Build Coastguard Worker pthread_cond_destroy(&q->full);
1847*33b1fccfSAndroid Build Coastguard Worker pthread_cond_destroy(&q->drain);
1848*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_destroy(&q->lock);
1849*33b1fccfSAndroid Build Coastguard Worker free(q->queue);
1850*33b1fccfSAndroid Build Coastguard Worker free(q);
1851*33b1fccfSAndroid Build Coastguard Worker return err;
1852*33b1fccfSAndroid Build Coastguard Worker }
1853*33b1fccfSAndroid Build Coastguard Worker #endif
1854*33b1fccfSAndroid Build Coastguard Worker
erofs_mkfs_build_tree_from_path(struct erofs_sb_info * sbi,const char * path)1855*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *erofs_mkfs_build_tree_from_path(struct erofs_sb_info *sbi,
1856*33b1fccfSAndroid Build Coastguard Worker const char *path)
1857*33b1fccfSAndroid Build Coastguard Worker {
1858*33b1fccfSAndroid Build Coastguard Worker struct erofs_mkfs_buildtree_ctx ctx = {
1859*33b1fccfSAndroid Build Coastguard Worker .sbi = sbi,
1860*33b1fccfSAndroid Build Coastguard Worker .u.path = path,
1861*33b1fccfSAndroid Build Coastguard Worker };
1862*33b1fccfSAndroid Build Coastguard Worker int err;
1863*33b1fccfSAndroid Build Coastguard Worker
1864*33b1fccfSAndroid Build Coastguard Worker if (!sbi)
1865*33b1fccfSAndroid Build Coastguard Worker return ERR_PTR(-EINVAL);
1866*33b1fccfSAndroid Build Coastguard Worker err = erofs_mkfs_build_tree(&ctx);
1867*33b1fccfSAndroid Build Coastguard Worker if (err)
1868*33b1fccfSAndroid Build Coastguard Worker return ERR_PTR(err);
1869*33b1fccfSAndroid Build Coastguard Worker return ctx.u.root;
1870*33b1fccfSAndroid Build Coastguard Worker }
1871*33b1fccfSAndroid Build Coastguard Worker
erofs_rebuild_dump_tree(struct erofs_inode * root,bool incremental)1872*33b1fccfSAndroid Build Coastguard Worker int erofs_rebuild_dump_tree(struct erofs_inode *root, bool incremental)
1873*33b1fccfSAndroid Build Coastguard Worker {
1874*33b1fccfSAndroid Build Coastguard Worker return erofs_mkfs_build_tree(&((struct erofs_mkfs_buildtree_ctx) {
1875*33b1fccfSAndroid Build Coastguard Worker .sbi = NULL,
1876*33b1fccfSAndroid Build Coastguard Worker .u.root = root,
1877*33b1fccfSAndroid Build Coastguard Worker .incremental = incremental,
1878*33b1fccfSAndroid Build Coastguard Worker }));
1879*33b1fccfSAndroid Build Coastguard Worker }
1880*33b1fccfSAndroid Build Coastguard Worker
erofs_mkfs_build_special_from_fd(struct erofs_sb_info * sbi,int fd,const char * name)1881*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *erofs_mkfs_build_special_from_fd(struct erofs_sb_info *sbi,
1882*33b1fccfSAndroid Build Coastguard Worker int fd, const char *name)
1883*33b1fccfSAndroid Build Coastguard Worker {
1884*33b1fccfSAndroid Build Coastguard Worker struct stat st;
1885*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *inode;
1886*33b1fccfSAndroid Build Coastguard Worker void *ictx;
1887*33b1fccfSAndroid Build Coastguard Worker int ret;
1888*33b1fccfSAndroid Build Coastguard Worker
1889*33b1fccfSAndroid Build Coastguard Worker ret = lseek(fd, 0, SEEK_SET);
1890*33b1fccfSAndroid Build Coastguard Worker if (ret < 0)
1891*33b1fccfSAndroid Build Coastguard Worker return ERR_PTR(-errno);
1892*33b1fccfSAndroid Build Coastguard Worker
1893*33b1fccfSAndroid Build Coastguard Worker ret = fstat(fd, &st);
1894*33b1fccfSAndroid Build Coastguard Worker if (ret)
1895*33b1fccfSAndroid Build Coastguard Worker return ERR_PTR(-errno);
1896*33b1fccfSAndroid Build Coastguard Worker
1897*33b1fccfSAndroid Build Coastguard Worker inode = erofs_new_inode(sbi);
1898*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(inode))
1899*33b1fccfSAndroid Build Coastguard Worker return inode;
1900*33b1fccfSAndroid Build Coastguard Worker
1901*33b1fccfSAndroid Build Coastguard Worker if (name == EROFS_PACKED_INODE) {
1902*33b1fccfSAndroid Build Coastguard Worker st.st_uid = st.st_gid = 0;
1903*33b1fccfSAndroid Build Coastguard Worker st.st_nlink = 0;
1904*33b1fccfSAndroid Build Coastguard Worker }
1905*33b1fccfSAndroid Build Coastguard Worker
1906*33b1fccfSAndroid Build Coastguard Worker ret = erofs_fill_inode(inode, &st, name);
1907*33b1fccfSAndroid Build Coastguard Worker if (ret) {
1908*33b1fccfSAndroid Build Coastguard Worker free(inode);
1909*33b1fccfSAndroid Build Coastguard Worker return ERR_PTR(ret);
1910*33b1fccfSAndroid Build Coastguard Worker }
1911*33b1fccfSAndroid Build Coastguard Worker
1912*33b1fccfSAndroid Build Coastguard Worker if (name == EROFS_PACKED_INODE) {
1913*33b1fccfSAndroid Build Coastguard Worker inode->sbi->packed_nid = EROFS_PACKED_NID_UNALLOCATED;
1914*33b1fccfSAndroid Build Coastguard Worker inode->nid = inode->sbi->packed_nid;
1915*33b1fccfSAndroid Build Coastguard Worker }
1916*33b1fccfSAndroid Build Coastguard Worker
1917*33b1fccfSAndroid Build Coastguard Worker if (cfg.c_compr_opts[0].alg &&
1918*33b1fccfSAndroid Build Coastguard Worker erofs_file_is_compressible(inode)) {
1919*33b1fccfSAndroid Build Coastguard Worker ictx = erofs_begin_compressed_file(inode, fd, 0);
1920*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(ictx))
1921*33b1fccfSAndroid Build Coastguard Worker return ERR_CAST(ictx);
1922*33b1fccfSAndroid Build Coastguard Worker
1923*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(!ictx);
1924*33b1fccfSAndroid Build Coastguard Worker ret = erofs_write_compressed_file(ictx);
1925*33b1fccfSAndroid Build Coastguard Worker if (ret && ret != -ENOSPC)
1926*33b1fccfSAndroid Build Coastguard Worker return ERR_PTR(ret);
1927*33b1fccfSAndroid Build Coastguard Worker
1928*33b1fccfSAndroid Build Coastguard Worker ret = lseek(fd, 0, SEEK_SET);
1929*33b1fccfSAndroid Build Coastguard Worker if (ret < 0)
1930*33b1fccfSAndroid Build Coastguard Worker return ERR_PTR(-errno);
1931*33b1fccfSAndroid Build Coastguard Worker }
1932*33b1fccfSAndroid Build Coastguard Worker ret = write_uncompressed_file_from_fd(inode, fd);
1933*33b1fccfSAndroid Build Coastguard Worker if (ret)
1934*33b1fccfSAndroid Build Coastguard Worker return ERR_PTR(ret);
1935*33b1fccfSAndroid Build Coastguard Worker erofs_prepare_inode_buffer(inode);
1936*33b1fccfSAndroid Build Coastguard Worker erofs_write_tail_end(inode);
1937*33b1fccfSAndroid Build Coastguard Worker return inode;
1938*33b1fccfSAndroid Build Coastguard Worker }
1939*33b1fccfSAndroid Build Coastguard Worker
erofs_fixup_root_inode(struct erofs_inode * root)1940*33b1fccfSAndroid Build Coastguard Worker int erofs_fixup_root_inode(struct erofs_inode *root)
1941*33b1fccfSAndroid Build Coastguard Worker {
1942*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = root->sbi;
1943*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode oi;
1944*33b1fccfSAndroid Build Coastguard Worker unsigned int ondisk_capacity, ondisk_size;
1945*33b1fccfSAndroid Build Coastguard Worker char *ibuf;
1946*33b1fccfSAndroid Build Coastguard Worker int err;
1947*33b1fccfSAndroid Build Coastguard Worker
1948*33b1fccfSAndroid Build Coastguard Worker if (sbi->root_nid == root->nid) /* for most mkfs cases */
1949*33b1fccfSAndroid Build Coastguard Worker return 0;
1950*33b1fccfSAndroid Build Coastguard Worker
1951*33b1fccfSAndroid Build Coastguard Worker if (root->nid <= 0xffff) {
1952*33b1fccfSAndroid Build Coastguard Worker sbi->root_nid = root->nid;
1953*33b1fccfSAndroid Build Coastguard Worker return 0;
1954*33b1fccfSAndroid Build Coastguard Worker }
1955*33b1fccfSAndroid Build Coastguard Worker
1956*33b1fccfSAndroid Build Coastguard Worker oi = (struct erofs_inode){ .sbi = sbi, .nid = sbi->root_nid };
1957*33b1fccfSAndroid Build Coastguard Worker err = erofs_read_inode_from_disk(&oi);
1958*33b1fccfSAndroid Build Coastguard Worker if (err) {
1959*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to read root inode: %s",
1960*33b1fccfSAndroid Build Coastguard Worker erofs_strerror(err));
1961*33b1fccfSAndroid Build Coastguard Worker return err;
1962*33b1fccfSAndroid Build Coastguard Worker }
1963*33b1fccfSAndroid Build Coastguard Worker
1964*33b1fccfSAndroid Build Coastguard Worker if (oi.datalayout != EROFS_INODE_FLAT_INLINE &&
1965*33b1fccfSAndroid Build Coastguard Worker oi.datalayout != EROFS_INODE_FLAT_PLAIN)
1966*33b1fccfSAndroid Build Coastguard Worker return -EOPNOTSUPP;
1967*33b1fccfSAndroid Build Coastguard Worker
1968*33b1fccfSAndroid Build Coastguard Worker ondisk_capacity = oi.inode_isize + oi.xattr_isize;
1969*33b1fccfSAndroid Build Coastguard Worker if (oi.datalayout == EROFS_INODE_FLAT_INLINE)
1970*33b1fccfSAndroid Build Coastguard Worker ondisk_capacity += erofs_blkoff(sbi, oi.i_size);
1971*33b1fccfSAndroid Build Coastguard Worker
1972*33b1fccfSAndroid Build Coastguard Worker ondisk_size = root->inode_isize + root->xattr_isize;
1973*33b1fccfSAndroid Build Coastguard Worker if (root->extent_isize)
1974*33b1fccfSAndroid Build Coastguard Worker ondisk_size = roundup(ondisk_size, 8) + root->extent_isize;
1975*33b1fccfSAndroid Build Coastguard Worker ondisk_size += root->idata_size;
1976*33b1fccfSAndroid Build Coastguard Worker
1977*33b1fccfSAndroid Build Coastguard Worker if (ondisk_size > ondisk_capacity) {
1978*33b1fccfSAndroid Build Coastguard Worker erofs_err("no enough room for the root inode from nid %llu",
1979*33b1fccfSAndroid Build Coastguard Worker root->nid);
1980*33b1fccfSAndroid Build Coastguard Worker return -ENOSPC;
1981*33b1fccfSAndroid Build Coastguard Worker }
1982*33b1fccfSAndroid Build Coastguard Worker
1983*33b1fccfSAndroid Build Coastguard Worker ibuf = malloc(ondisk_size);
1984*33b1fccfSAndroid Build Coastguard Worker if (!ibuf)
1985*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
1986*33b1fccfSAndroid Build Coastguard Worker err = erofs_dev_read(sbi, 0, ibuf, erofs_iloc(root), ondisk_size);
1987*33b1fccfSAndroid Build Coastguard Worker if (err >= 0)
1988*33b1fccfSAndroid Build Coastguard Worker err = erofs_dev_write(sbi, ibuf, erofs_iloc(&oi), ondisk_size);
1989*33b1fccfSAndroid Build Coastguard Worker free(ibuf);
1990*33b1fccfSAndroid Build Coastguard Worker return err;
1991*33b1fccfSAndroid Build Coastguard Worker }
1992*33b1fccfSAndroid Build Coastguard Worker
erofs_rebuild_make_root(struct erofs_sb_info * sbi)1993*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *erofs_rebuild_make_root(struct erofs_sb_info *sbi)
1994*33b1fccfSAndroid Build Coastguard Worker {
1995*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode *root;
1996*33b1fccfSAndroid Build Coastguard Worker
1997*33b1fccfSAndroid Build Coastguard Worker root = erofs_new_inode(sbi);
1998*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(root))
1999*33b1fccfSAndroid Build Coastguard Worker return root;
2000*33b1fccfSAndroid Build Coastguard Worker root->i_srcpath = strdup("/");
2001*33b1fccfSAndroid Build Coastguard Worker root->i_mode = S_IFDIR | 0777;
2002*33b1fccfSAndroid Build Coastguard Worker root->i_parent = root;
2003*33b1fccfSAndroid Build Coastguard Worker root->i_mtime = root->sbi->build_time;
2004*33b1fccfSAndroid Build Coastguard Worker root->i_mtime_nsec = root->sbi->build_time_nsec;
2005*33b1fccfSAndroid Build Coastguard Worker erofs_init_empty_dir(root);
2006*33b1fccfSAndroid Build Coastguard Worker return root;
2007*33b1fccfSAndroid Build Coastguard Worker }
2008