xref: /aosp_15_r20/external/erofs-utils/lib/rebuild.c (revision 33b1fccf6a0fada2c2875d400ed01119b7676ee5)
1*33b1fccfSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
2*33b1fccfSAndroid Build Coastguard Worker #define _GNU_SOURCE
3*33b1fccfSAndroid Build Coastguard Worker #include <unistd.h>
4*33b1fccfSAndroid Build Coastguard Worker #include <stdlib.h>
5*33b1fccfSAndroid Build Coastguard Worker #include <string.h>
6*33b1fccfSAndroid Build Coastguard Worker #include <sys/stat.h>
7*33b1fccfSAndroid Build Coastguard Worker #include <config.h>
8*33b1fccfSAndroid Build Coastguard Worker #if defined(HAVE_SYS_SYSMACROS_H)
9*33b1fccfSAndroid Build Coastguard Worker #include <sys/sysmacros.h>
10*33b1fccfSAndroid Build Coastguard Worker #endif
11*33b1fccfSAndroid Build Coastguard Worker #include "erofs/print.h"
12*33b1fccfSAndroid Build Coastguard Worker #include "erofs/inode.h"
13*33b1fccfSAndroid Build Coastguard Worker #include "erofs/rebuild.h"
14*33b1fccfSAndroid Build Coastguard Worker #include "erofs/dir.h"
15*33b1fccfSAndroid Build Coastguard Worker #include "erofs/xattr.h"
16*33b1fccfSAndroid Build Coastguard Worker #include "erofs/blobchunk.h"
17*33b1fccfSAndroid Build Coastguard Worker #include "erofs/internal.h"
18*33b1fccfSAndroid Build Coastguard Worker #include "liberofs_uuid.h"
19*33b1fccfSAndroid Build Coastguard Worker 
20*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LINUX_AUFS_TYPE_H
21*33b1fccfSAndroid Build Coastguard Worker #include <linux/aufs_type.h>
22*33b1fccfSAndroid Build Coastguard Worker #else
23*33b1fccfSAndroid Build Coastguard Worker #define AUFS_WH_PFX		".wh."
24*33b1fccfSAndroid Build Coastguard Worker #define AUFS_DIROPQ_NAME	AUFS_WH_PFX ".opq"
25*33b1fccfSAndroid Build Coastguard Worker #define AUFS_WH_DIROPQ		AUFS_WH_PFX AUFS_DIROPQ_NAME
26*33b1fccfSAndroid Build Coastguard Worker #endif
27*33b1fccfSAndroid Build Coastguard Worker 
erofs_rebuild_mkdir(struct erofs_inode * dir,const char * s)28*33b1fccfSAndroid Build Coastguard Worker static struct erofs_dentry *erofs_rebuild_mkdir(struct erofs_inode *dir,
29*33b1fccfSAndroid Build Coastguard Worker 						const char *s)
30*33b1fccfSAndroid Build Coastguard Worker {
31*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *inode;
32*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_dentry *d;
33*33b1fccfSAndroid Build Coastguard Worker 
34*33b1fccfSAndroid Build Coastguard Worker 	inode = erofs_new_inode(dir->sbi);
35*33b1fccfSAndroid Build Coastguard Worker 	if (IS_ERR(inode))
36*33b1fccfSAndroid Build Coastguard Worker 		return ERR_CAST(inode);
37*33b1fccfSAndroid Build Coastguard Worker 
38*33b1fccfSAndroid Build Coastguard Worker 	if (asprintf(&inode->i_srcpath, "%s/%s",
39*33b1fccfSAndroid Build Coastguard Worker 		     dir->i_srcpath ? : "", s) < 0) {
40*33b1fccfSAndroid Build Coastguard Worker 		erofs_iput(inode);
41*33b1fccfSAndroid Build Coastguard Worker 		return ERR_PTR(-ENOMEM);
42*33b1fccfSAndroid Build Coastguard Worker 	}
43*33b1fccfSAndroid Build Coastguard Worker 	inode->i_mode = S_IFDIR | 0755;
44*33b1fccfSAndroid Build Coastguard Worker 	inode->i_parent = dir;
45*33b1fccfSAndroid Build Coastguard Worker 	inode->i_uid = getuid();
46*33b1fccfSAndroid Build Coastguard Worker 	inode->i_gid = getgid();
47*33b1fccfSAndroid Build Coastguard Worker 	inode->i_mtime = inode->sbi->build_time;
48*33b1fccfSAndroid Build Coastguard Worker 	inode->i_mtime_nsec = inode->sbi->build_time_nsec;
49*33b1fccfSAndroid Build Coastguard Worker 	erofs_init_empty_dir(inode);
50*33b1fccfSAndroid Build Coastguard Worker 
51*33b1fccfSAndroid Build Coastguard Worker 	d = erofs_d_alloc(dir, s);
52*33b1fccfSAndroid Build Coastguard Worker 	if (IS_ERR(d)) {
53*33b1fccfSAndroid Build Coastguard Worker 		erofs_iput(inode);
54*33b1fccfSAndroid Build Coastguard Worker 	} else {
55*33b1fccfSAndroid Build Coastguard Worker 		d->type = EROFS_FT_DIR;
56*33b1fccfSAndroid Build Coastguard Worker 		d->inode = inode;
57*33b1fccfSAndroid Build Coastguard Worker 	}
58*33b1fccfSAndroid Build Coastguard Worker 	return d;
59*33b1fccfSAndroid Build Coastguard Worker }
60*33b1fccfSAndroid Build Coastguard Worker 
erofs_rebuild_get_dentry(struct erofs_inode * pwd,char * path,bool aufs,bool * whout,bool * opq,bool to_head)61*33b1fccfSAndroid Build Coastguard Worker struct erofs_dentry *erofs_rebuild_get_dentry(struct erofs_inode *pwd,
62*33b1fccfSAndroid Build Coastguard Worker 		char *path, bool aufs, bool *whout, bool *opq, bool to_head)
63*33b1fccfSAndroid Build Coastguard Worker {
64*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_dentry *d = NULL;
65*33b1fccfSAndroid Build Coastguard Worker 	unsigned int len = strlen(path);
66*33b1fccfSAndroid Build Coastguard Worker 	char *s = path;
67*33b1fccfSAndroid Build Coastguard Worker 
68*33b1fccfSAndroid Build Coastguard Worker 	*whout = false;
69*33b1fccfSAndroid Build Coastguard Worker 	*opq = false;
70*33b1fccfSAndroid Build Coastguard Worker 
71*33b1fccfSAndroid Build Coastguard Worker 	while (s < path + len) {
72*33b1fccfSAndroid Build Coastguard Worker 		char *slash = memchr(s, '/', path + len - s);
73*33b1fccfSAndroid Build Coastguard Worker 
74*33b1fccfSAndroid Build Coastguard Worker 		if (slash) {
75*33b1fccfSAndroid Build Coastguard Worker 			if (s == slash) {
76*33b1fccfSAndroid Build Coastguard Worker 				while (*++s == '/');	/* skip '//...' */
77*33b1fccfSAndroid Build Coastguard Worker 				continue;
78*33b1fccfSAndroid Build Coastguard Worker 			}
79*33b1fccfSAndroid Build Coastguard Worker 			*slash = '\0';
80*33b1fccfSAndroid Build Coastguard Worker 		}
81*33b1fccfSAndroid Build Coastguard Worker 
82*33b1fccfSAndroid Build Coastguard Worker 		if (!memcmp(s, ".", 2)) {
83*33b1fccfSAndroid Build Coastguard Worker 			/* null */
84*33b1fccfSAndroid Build Coastguard Worker 		} else if (!memcmp(s, "..", 3)) {
85*33b1fccfSAndroid Build Coastguard Worker 			pwd = pwd->i_parent;
86*33b1fccfSAndroid Build Coastguard Worker 		} else {
87*33b1fccfSAndroid Build Coastguard Worker 			struct erofs_inode *inode = NULL;
88*33b1fccfSAndroid Build Coastguard Worker 
89*33b1fccfSAndroid Build Coastguard Worker 			if (aufs && !slash) {
90*33b1fccfSAndroid Build Coastguard Worker 				if (!memcmp(s, AUFS_WH_DIROPQ, sizeof(AUFS_WH_DIROPQ))) {
91*33b1fccfSAndroid Build Coastguard Worker 					*opq = true;
92*33b1fccfSAndroid Build Coastguard Worker 					break;
93*33b1fccfSAndroid Build Coastguard Worker 				}
94*33b1fccfSAndroid Build Coastguard Worker 				if (!memcmp(s, AUFS_WH_PFX, sizeof(AUFS_WH_PFX) - 1)) {
95*33b1fccfSAndroid Build Coastguard Worker 					s += sizeof(AUFS_WH_PFX) - 1;
96*33b1fccfSAndroid Build Coastguard Worker 					*whout = true;
97*33b1fccfSAndroid Build Coastguard Worker 				}
98*33b1fccfSAndroid Build Coastguard Worker 			}
99*33b1fccfSAndroid Build Coastguard Worker 
100*33b1fccfSAndroid Build Coastguard Worker 			list_for_each_entry(d, &pwd->i_subdirs, d_child) {
101*33b1fccfSAndroid Build Coastguard Worker 				if (!strcmp(d->name, s)) {
102*33b1fccfSAndroid Build Coastguard Worker 					if (d->type != EROFS_FT_DIR && slash)
103*33b1fccfSAndroid Build Coastguard Worker 						return ERR_PTR(-EIO);
104*33b1fccfSAndroid Build Coastguard Worker 					inode = d->inode;
105*33b1fccfSAndroid Build Coastguard Worker 					break;
106*33b1fccfSAndroid Build Coastguard Worker 				}
107*33b1fccfSAndroid Build Coastguard Worker 			}
108*33b1fccfSAndroid Build Coastguard Worker 
109*33b1fccfSAndroid Build Coastguard Worker 			if (inode) {
110*33b1fccfSAndroid Build Coastguard Worker 				if (to_head) {
111*33b1fccfSAndroid Build Coastguard Worker 					list_del(&d->d_child);
112*33b1fccfSAndroid Build Coastguard Worker 					list_add(&d->d_child, &pwd->i_subdirs);
113*33b1fccfSAndroid Build Coastguard Worker 				}
114*33b1fccfSAndroid Build Coastguard Worker 				pwd = inode;
115*33b1fccfSAndroid Build Coastguard Worker 			} else if (!slash) {
116*33b1fccfSAndroid Build Coastguard Worker 				d = erofs_d_alloc(pwd, s);
117*33b1fccfSAndroid Build Coastguard Worker 				if (IS_ERR(d))
118*33b1fccfSAndroid Build Coastguard Worker 					return d;
119*33b1fccfSAndroid Build Coastguard Worker 				d->type = EROFS_FT_UNKNOWN;
120*33b1fccfSAndroid Build Coastguard Worker 				d->inode = pwd;
121*33b1fccfSAndroid Build Coastguard Worker 			} else {
122*33b1fccfSAndroid Build Coastguard Worker 				d = erofs_rebuild_mkdir(pwd, s);
123*33b1fccfSAndroid Build Coastguard Worker 				if (IS_ERR(d))
124*33b1fccfSAndroid Build Coastguard Worker 					return d;
125*33b1fccfSAndroid Build Coastguard Worker 				pwd = d->inode;
126*33b1fccfSAndroid Build Coastguard Worker 			}
127*33b1fccfSAndroid Build Coastguard Worker 		}
128*33b1fccfSAndroid Build Coastguard Worker 		if (slash) {
129*33b1fccfSAndroid Build Coastguard Worker 			*slash = '/';
130*33b1fccfSAndroid Build Coastguard Worker 			s = slash + 1;
131*33b1fccfSAndroid Build Coastguard Worker 		} else {
132*33b1fccfSAndroid Build Coastguard Worker 			break;
133*33b1fccfSAndroid Build Coastguard Worker 		}
134*33b1fccfSAndroid Build Coastguard Worker 	}
135*33b1fccfSAndroid Build Coastguard Worker 	return d;
136*33b1fccfSAndroid Build Coastguard Worker }
137*33b1fccfSAndroid Build Coastguard Worker 
erofs_rebuild_write_blob_index(struct erofs_sb_info * dst_sb,struct erofs_inode * inode)138*33b1fccfSAndroid Build Coastguard Worker static int erofs_rebuild_write_blob_index(struct erofs_sb_info *dst_sb,
139*33b1fccfSAndroid Build Coastguard Worker 					  struct erofs_inode *inode)
140*33b1fccfSAndroid Build Coastguard Worker {
141*33b1fccfSAndroid Build Coastguard Worker 	int ret;
142*33b1fccfSAndroid Build Coastguard Worker 	unsigned int count, unit, chunkbits, i;
143*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode_chunk_index *idx;
144*33b1fccfSAndroid Build Coastguard Worker 	erofs_off_t chunksize;
145*33b1fccfSAndroid Build Coastguard Worker 	erofs_blk_t blkaddr;
146*33b1fccfSAndroid Build Coastguard Worker 
147*33b1fccfSAndroid Build Coastguard Worker 	/* TODO: fill data map in other layouts */
148*33b1fccfSAndroid Build Coastguard Worker 	if (inode->datalayout == EROFS_INODE_CHUNK_BASED) {
149*33b1fccfSAndroid Build Coastguard Worker 		chunkbits = inode->u.chunkbits;
150*33b1fccfSAndroid Build Coastguard Worker 		if (chunkbits < dst_sb->blkszbits) {
151*33b1fccfSAndroid Build Coastguard Worker 			erofs_err("%s: chunk size %u is smaller than the target block size %u",
152*33b1fccfSAndroid Build Coastguard Worker 				  inode->i_srcpath, 1U << chunkbits,
153*33b1fccfSAndroid Build Coastguard Worker 				  1U << dst_sb->blkszbits);
154*33b1fccfSAndroid Build Coastguard Worker 			return -EINVAL;
155*33b1fccfSAndroid Build Coastguard Worker 		}
156*33b1fccfSAndroid Build Coastguard Worker 	} else if (inode->datalayout == EROFS_INODE_FLAT_PLAIN) {
157*33b1fccfSAndroid Build Coastguard Worker 		chunkbits = ilog2(inode->i_size - 1) + 1;
158*33b1fccfSAndroid Build Coastguard Worker 		if (chunkbits < dst_sb->blkszbits)
159*33b1fccfSAndroid Build Coastguard Worker 			chunkbits = dst_sb->blkszbits;
160*33b1fccfSAndroid Build Coastguard Worker 		if (chunkbits - dst_sb->blkszbits > EROFS_CHUNK_FORMAT_BLKBITS_MASK)
161*33b1fccfSAndroid Build Coastguard Worker 			chunkbits = EROFS_CHUNK_FORMAT_BLKBITS_MASK + dst_sb->blkszbits;
162*33b1fccfSAndroid Build Coastguard Worker 	} else {
163*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("%s: unsupported datalayout %d ", inode->i_srcpath,
164*33b1fccfSAndroid Build Coastguard Worker 			  inode->datalayout);
165*33b1fccfSAndroid Build Coastguard Worker 		return -EOPNOTSUPP;
166*33b1fccfSAndroid Build Coastguard Worker 	}
167*33b1fccfSAndroid Build Coastguard Worker 
168*33b1fccfSAndroid Build Coastguard Worker 	chunksize = 1ULL << chunkbits;
169*33b1fccfSAndroid Build Coastguard Worker 	count = DIV_ROUND_UP(inode->i_size, chunksize);
170*33b1fccfSAndroid Build Coastguard Worker 
171*33b1fccfSAndroid Build Coastguard Worker 	unit = sizeof(struct erofs_inode_chunk_index);
172*33b1fccfSAndroid Build Coastguard Worker 	inode->extent_isize = count * unit;
173*33b1fccfSAndroid Build Coastguard Worker 	idx = malloc(max(sizeof(*idx), sizeof(void *)));
174*33b1fccfSAndroid Build Coastguard Worker 	if (!idx)
175*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
176*33b1fccfSAndroid Build Coastguard Worker 	inode->chunkindexes = idx;
177*33b1fccfSAndroid Build Coastguard Worker 
178*33b1fccfSAndroid Build Coastguard Worker 	for (i = 0; i < count; i++) {
179*33b1fccfSAndroid Build Coastguard Worker 		struct erofs_blobchunk *chunk;
180*33b1fccfSAndroid Build Coastguard Worker 		struct erofs_map_blocks map = {
181*33b1fccfSAndroid Build Coastguard Worker 			.index = UINT_MAX,
182*33b1fccfSAndroid Build Coastguard Worker 		};
183*33b1fccfSAndroid Build Coastguard Worker 
184*33b1fccfSAndroid Build Coastguard Worker 		map.m_la = i << chunkbits;
185*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_map_blocks(inode, &map, 0);
186*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
187*33b1fccfSAndroid Build Coastguard Worker 			goto err;
188*33b1fccfSAndroid Build Coastguard Worker 
189*33b1fccfSAndroid Build Coastguard Worker 		blkaddr = erofs_blknr(dst_sb, map.m_pa);
190*33b1fccfSAndroid Build Coastguard Worker 		chunk = erofs_get_unhashed_chunk(inode->dev, blkaddr, 0);
191*33b1fccfSAndroid Build Coastguard Worker 		if (IS_ERR(chunk)) {
192*33b1fccfSAndroid Build Coastguard Worker 			ret = PTR_ERR(chunk);
193*33b1fccfSAndroid Build Coastguard Worker 			goto err;
194*33b1fccfSAndroid Build Coastguard Worker 		}
195*33b1fccfSAndroid Build Coastguard Worker 		*(void **)idx++ = chunk;
196*33b1fccfSAndroid Build Coastguard Worker 
197*33b1fccfSAndroid Build Coastguard Worker 	}
198*33b1fccfSAndroid Build Coastguard Worker 	inode->datalayout = EROFS_INODE_CHUNK_BASED;
199*33b1fccfSAndroid Build Coastguard Worker 	inode->u.chunkformat = EROFS_CHUNK_FORMAT_INDEXES;
200*33b1fccfSAndroid Build Coastguard Worker 	inode->u.chunkformat |= chunkbits - dst_sb->blkszbits;
201*33b1fccfSAndroid Build Coastguard Worker 	return 0;
202*33b1fccfSAndroid Build Coastguard Worker err:
203*33b1fccfSAndroid Build Coastguard Worker 	free(inode->chunkindexes);
204*33b1fccfSAndroid Build Coastguard Worker 	inode->chunkindexes = NULL;
205*33b1fccfSAndroid Build Coastguard Worker 	return ret;
206*33b1fccfSAndroid Build Coastguard Worker }
207*33b1fccfSAndroid Build Coastguard Worker 
erofs_rebuild_update_inode(struct erofs_sb_info * dst_sb,struct erofs_inode * inode,enum erofs_rebuild_datamode datamode)208*33b1fccfSAndroid Build Coastguard Worker static int erofs_rebuild_update_inode(struct erofs_sb_info *dst_sb,
209*33b1fccfSAndroid Build Coastguard Worker 				      struct erofs_inode *inode,
210*33b1fccfSAndroid Build Coastguard Worker 				      enum erofs_rebuild_datamode datamode)
211*33b1fccfSAndroid Build Coastguard Worker {
212*33b1fccfSAndroid Build Coastguard Worker 	int err = 0;
213*33b1fccfSAndroid Build Coastguard Worker 
214*33b1fccfSAndroid Build Coastguard Worker 	switch (inode->i_mode & S_IFMT) {
215*33b1fccfSAndroid Build Coastguard Worker 	case S_IFCHR:
216*33b1fccfSAndroid Build Coastguard Worker 		if (erofs_inode_is_whiteout(inode))
217*33b1fccfSAndroid Build Coastguard Worker 			inode->i_parent->whiteouts = true;
218*33b1fccfSAndroid Build Coastguard Worker 		/* fallthrough */
219*33b1fccfSAndroid Build Coastguard Worker 	case S_IFBLK:
220*33b1fccfSAndroid Build Coastguard Worker 	case S_IFIFO:
221*33b1fccfSAndroid Build Coastguard Worker 	case S_IFSOCK:
222*33b1fccfSAndroid Build Coastguard Worker 		inode->i_size = 0;
223*33b1fccfSAndroid Build Coastguard Worker 		erofs_dbg("\tdev: %d %d", major(inode->u.i_rdev),
224*33b1fccfSAndroid Build Coastguard Worker 			  minor(inode->u.i_rdev));
225*33b1fccfSAndroid Build Coastguard Worker 		inode->u.i_rdev = erofs_new_encode_dev(inode->u.i_rdev);
226*33b1fccfSAndroid Build Coastguard Worker 		break;
227*33b1fccfSAndroid Build Coastguard Worker 	case S_IFDIR:
228*33b1fccfSAndroid Build Coastguard Worker 		err = erofs_init_empty_dir(inode);
229*33b1fccfSAndroid Build Coastguard Worker 		break;
230*33b1fccfSAndroid Build Coastguard Worker 	case S_IFLNK:
231*33b1fccfSAndroid Build Coastguard Worker 		inode->i_link = malloc(inode->i_size + 1);
232*33b1fccfSAndroid Build Coastguard Worker 		if (!inode->i_link)
233*33b1fccfSAndroid Build Coastguard Worker 			return -ENOMEM;
234*33b1fccfSAndroid Build Coastguard Worker 		err = erofs_pread(inode, inode->i_link, inode->i_size, 0);
235*33b1fccfSAndroid Build Coastguard Worker 		erofs_dbg("\tsymlink: %s -> %s", inode->i_srcpath, inode->i_link);
236*33b1fccfSAndroid Build Coastguard Worker 		break;
237*33b1fccfSAndroid Build Coastguard Worker 	case S_IFREG:
238*33b1fccfSAndroid Build Coastguard Worker 		if (!inode->i_size) {
239*33b1fccfSAndroid Build Coastguard Worker 			inode->u.i_blkaddr = NULL_ADDR;
240*33b1fccfSAndroid Build Coastguard Worker 			break;
241*33b1fccfSAndroid Build Coastguard Worker 		}
242*33b1fccfSAndroid Build Coastguard Worker 		if (datamode == EROFS_REBUILD_DATA_BLOB_INDEX)
243*33b1fccfSAndroid Build Coastguard Worker 			err = erofs_rebuild_write_blob_index(dst_sb, inode);
244*33b1fccfSAndroid Build Coastguard Worker 		else if (datamode == EROFS_REBUILD_DATA_RESVSP)
245*33b1fccfSAndroid Build Coastguard Worker 			inode->datasource = EROFS_INODE_DATA_SOURCE_RESVSP;
246*33b1fccfSAndroid Build Coastguard Worker 		else
247*33b1fccfSAndroid Build Coastguard Worker 			err = -EOPNOTSUPP;
248*33b1fccfSAndroid Build Coastguard Worker 		break;
249*33b1fccfSAndroid Build Coastguard Worker 	default:
250*33b1fccfSAndroid Build Coastguard Worker 		return -EINVAL;
251*33b1fccfSAndroid Build Coastguard Worker 	}
252*33b1fccfSAndroid Build Coastguard Worker 	return err;
253*33b1fccfSAndroid Build Coastguard Worker }
254*33b1fccfSAndroid Build Coastguard Worker 
255*33b1fccfSAndroid Build Coastguard Worker /*
256*33b1fccfSAndroid Build Coastguard Worker  * @mergedir: parent directory in the merged tree
257*33b1fccfSAndroid Build Coastguard Worker  * @ctx.dir:  parent directory when itering erofs_iterate_dir()
258*33b1fccfSAndroid Build Coastguard Worker  * @datamode: indicate how to import inode data
259*33b1fccfSAndroid Build Coastguard Worker  */
260*33b1fccfSAndroid Build Coastguard Worker struct erofs_rebuild_dir_context {
261*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_dir_context ctx;
262*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *mergedir;
263*33b1fccfSAndroid Build Coastguard Worker 	enum erofs_rebuild_datamode datamode;
264*33b1fccfSAndroid Build Coastguard Worker };
265*33b1fccfSAndroid Build Coastguard Worker 
erofs_rebuild_dirent_iter(struct erofs_dir_context * ctx)266*33b1fccfSAndroid Build Coastguard Worker static int erofs_rebuild_dirent_iter(struct erofs_dir_context *ctx)
267*33b1fccfSAndroid Build Coastguard Worker {
268*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_rebuild_dir_context *rctx = (void *)ctx;
269*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *mergedir = rctx->mergedir;
270*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *dir = ctx->dir;
271*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *inode, *candidate;
272*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode src;
273*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_dentry *d;
274*33b1fccfSAndroid Build Coastguard Worker 	char *path, *dname;
275*33b1fccfSAndroid Build Coastguard Worker 	bool dumb;
276*33b1fccfSAndroid Build Coastguard Worker 	int ret;
277*33b1fccfSAndroid Build Coastguard Worker 
278*33b1fccfSAndroid Build Coastguard Worker 	if (ctx->dot_dotdot)
279*33b1fccfSAndroid Build Coastguard Worker 		return 0;
280*33b1fccfSAndroid Build Coastguard Worker 
281*33b1fccfSAndroid Build Coastguard Worker 	ret = asprintf(&path, "%s/%.*s", rctx->mergedir->i_srcpath,
282*33b1fccfSAndroid Build Coastguard Worker 		       ctx->de_namelen, ctx->dname);
283*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
284*33b1fccfSAndroid Build Coastguard Worker 		return ret;
285*33b1fccfSAndroid Build Coastguard Worker 
286*33b1fccfSAndroid Build Coastguard Worker 	erofs_dbg("parsing %s", path);
287*33b1fccfSAndroid Build Coastguard Worker 	dname = path + strlen(mergedir->i_srcpath) + 1;
288*33b1fccfSAndroid Build Coastguard Worker 
289*33b1fccfSAndroid Build Coastguard Worker 	d = erofs_rebuild_get_dentry(mergedir, dname, false,
290*33b1fccfSAndroid Build Coastguard Worker 				     &dumb, &dumb, false);
291*33b1fccfSAndroid Build Coastguard Worker 	if (IS_ERR(d)) {
292*33b1fccfSAndroid Build Coastguard Worker 		ret = PTR_ERR(d);
293*33b1fccfSAndroid Build Coastguard Worker 		goto out;
294*33b1fccfSAndroid Build Coastguard Worker 	}
295*33b1fccfSAndroid Build Coastguard Worker 
296*33b1fccfSAndroid Build Coastguard Worker 	ret = 0;
297*33b1fccfSAndroid Build Coastguard Worker 	if (d->type != EROFS_FT_UNKNOWN) {
298*33b1fccfSAndroid Build Coastguard Worker 		/*
299*33b1fccfSAndroid Build Coastguard Worker 		 * bail out if the file exists in the upper layers.  (Note that
300*33b1fccfSAndroid Build Coastguard Worker 		 * extended attributes won't be merged too even for dirs.)
301*33b1fccfSAndroid Build Coastguard Worker 		 */
302*33b1fccfSAndroid Build Coastguard Worker 		if (!S_ISDIR(d->inode->i_mode) || d->inode->opaque)
303*33b1fccfSAndroid Build Coastguard Worker 			goto out;
304*33b1fccfSAndroid Build Coastguard Worker 
305*33b1fccfSAndroid Build Coastguard Worker 		/* merge directory entries */
306*33b1fccfSAndroid Build Coastguard Worker 		src = (struct erofs_inode) {
307*33b1fccfSAndroid Build Coastguard Worker 			.sbi = dir->sbi,
308*33b1fccfSAndroid Build Coastguard Worker 			.nid = ctx->de_nid
309*33b1fccfSAndroid Build Coastguard Worker 		};
310*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_read_inode_from_disk(&src);
311*33b1fccfSAndroid Build Coastguard Worker 		if (ret || !S_ISDIR(src.i_mode))
312*33b1fccfSAndroid Build Coastguard Worker 			goto out;
313*33b1fccfSAndroid Build Coastguard Worker 		mergedir = d->inode;
314*33b1fccfSAndroid Build Coastguard Worker 		inode = dir = &src;
315*33b1fccfSAndroid Build Coastguard Worker 	} else {
316*33b1fccfSAndroid Build Coastguard Worker 		u64 nid;
317*33b1fccfSAndroid Build Coastguard Worker 
318*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(mergedir != d->inode);
319*33b1fccfSAndroid Build Coastguard Worker 		inode = erofs_new_inode(dir->sbi);
320*33b1fccfSAndroid Build Coastguard Worker 		if (IS_ERR(inode)) {
321*33b1fccfSAndroid Build Coastguard Worker 			ret = PTR_ERR(inode);
322*33b1fccfSAndroid Build Coastguard Worker 			goto out;
323*33b1fccfSAndroid Build Coastguard Worker 		}
324*33b1fccfSAndroid Build Coastguard Worker 
325*33b1fccfSAndroid Build Coastguard Worker 		/* reuse i_ino[0] to read nid in source fs */
326*33b1fccfSAndroid Build Coastguard Worker 		nid = inode->i_ino[0];
327*33b1fccfSAndroid Build Coastguard Worker 		inode->sbi = dir->sbi;
328*33b1fccfSAndroid Build Coastguard Worker 		inode->nid = ctx->de_nid;
329*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_read_inode_from_disk(inode);
330*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
331*33b1fccfSAndroid Build Coastguard Worker 			goto out;
332*33b1fccfSAndroid Build Coastguard Worker 
333*33b1fccfSAndroid Build Coastguard Worker 		/* restore nid in new generated fs */
334*33b1fccfSAndroid Build Coastguard Worker 		inode->i_ino[1] = inode->i_ino[0];
335*33b1fccfSAndroid Build Coastguard Worker 		inode->i_ino[0] = nid;
336*33b1fccfSAndroid Build Coastguard Worker 		inode->dev = inode->sbi->dev;
337*33b1fccfSAndroid Build Coastguard Worker 
338*33b1fccfSAndroid Build Coastguard Worker 		if (S_ISREG(inode->i_mode) && inode->i_nlink > 1 &&
339*33b1fccfSAndroid Build Coastguard Worker 		    (candidate = erofs_iget(inode->dev, ctx->de_nid))) {
340*33b1fccfSAndroid Build Coastguard Worker 			/* hardlink file */
341*33b1fccfSAndroid Build Coastguard Worker 			erofs_iput(inode);
342*33b1fccfSAndroid Build Coastguard Worker 			inode = candidate;
343*33b1fccfSAndroid Build Coastguard Worker 			if (S_ISDIR(inode->i_mode)) {
344*33b1fccfSAndroid Build Coastguard Worker 				erofs_err("hardlink directory not supported");
345*33b1fccfSAndroid Build Coastguard Worker 				ret = -EISDIR;
346*33b1fccfSAndroid Build Coastguard Worker 				goto out;
347*33b1fccfSAndroid Build Coastguard Worker 			}
348*33b1fccfSAndroid Build Coastguard Worker 			inode->i_nlink++;
349*33b1fccfSAndroid Build Coastguard Worker 			erofs_dbg("\thardlink: %s -> %s", path, inode->i_srcpath);
350*33b1fccfSAndroid Build Coastguard Worker 		} else {
351*33b1fccfSAndroid Build Coastguard Worker 			ret = erofs_read_xattrs_from_disk(inode);
352*33b1fccfSAndroid Build Coastguard Worker 			if (ret) {
353*33b1fccfSAndroid Build Coastguard Worker 				erofs_iput(inode);
354*33b1fccfSAndroid Build Coastguard Worker 				goto out;
355*33b1fccfSAndroid Build Coastguard Worker 			}
356*33b1fccfSAndroid Build Coastguard Worker 
357*33b1fccfSAndroid Build Coastguard Worker 			inode->i_parent = d->inode;
358*33b1fccfSAndroid Build Coastguard Worker 			inode->i_srcpath = path;
359*33b1fccfSAndroid Build Coastguard Worker 			path = NULL;
360*33b1fccfSAndroid Build Coastguard Worker 			inode->i_ino[1] = inode->nid;
361*33b1fccfSAndroid Build Coastguard Worker 			inode->i_nlink = 1;
362*33b1fccfSAndroid Build Coastguard Worker 
363*33b1fccfSAndroid Build Coastguard Worker 			ret = erofs_rebuild_update_inode(&g_sbi, inode,
364*33b1fccfSAndroid Build Coastguard Worker 							 rctx->datamode);
365*33b1fccfSAndroid Build Coastguard Worker 			if (ret) {
366*33b1fccfSAndroid Build Coastguard Worker 				erofs_iput(inode);
367*33b1fccfSAndroid Build Coastguard Worker 				goto out;
368*33b1fccfSAndroid Build Coastguard Worker 			}
369*33b1fccfSAndroid Build Coastguard Worker 
370*33b1fccfSAndroid Build Coastguard Worker 			erofs_insert_ihash(inode);
371*33b1fccfSAndroid Build Coastguard Worker 			mergedir = dir = inode;
372*33b1fccfSAndroid Build Coastguard Worker 		}
373*33b1fccfSAndroid Build Coastguard Worker 
374*33b1fccfSAndroid Build Coastguard Worker 		d->inode = inode;
375*33b1fccfSAndroid Build Coastguard Worker 		d->type = erofs_mode_to_ftype(inode->i_mode);
376*33b1fccfSAndroid Build Coastguard Worker 	}
377*33b1fccfSAndroid Build Coastguard Worker 
378*33b1fccfSAndroid Build Coastguard Worker 	if (S_ISDIR(inode->i_mode)) {
379*33b1fccfSAndroid Build Coastguard Worker 		struct erofs_rebuild_dir_context nctx = *rctx;
380*33b1fccfSAndroid Build Coastguard Worker 
381*33b1fccfSAndroid Build Coastguard Worker 		nctx.mergedir = mergedir;
382*33b1fccfSAndroid Build Coastguard Worker 		nctx.ctx.dir = dir;
383*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_iterate_dir(&nctx.ctx, false);
384*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
385*33b1fccfSAndroid Build Coastguard Worker 			goto out;
386*33b1fccfSAndroid Build Coastguard Worker 	}
387*33b1fccfSAndroid Build Coastguard Worker 
388*33b1fccfSAndroid Build Coastguard Worker 	/* reset sbi, nid after subdirs are all loaded for the final dump */
389*33b1fccfSAndroid Build Coastguard Worker 	inode->sbi = &g_sbi;
390*33b1fccfSAndroid Build Coastguard Worker 	inode->nid = 0;
391*33b1fccfSAndroid Build Coastguard Worker out:
392*33b1fccfSAndroid Build Coastguard Worker 	free(path);
393*33b1fccfSAndroid Build Coastguard Worker 	return ret;
394*33b1fccfSAndroid Build Coastguard Worker }
395*33b1fccfSAndroid Build Coastguard Worker 
erofs_rebuild_load_tree(struct erofs_inode * root,struct erofs_sb_info * sbi,enum erofs_rebuild_datamode mode)396*33b1fccfSAndroid Build Coastguard Worker int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_sb_info *sbi,
397*33b1fccfSAndroid Build Coastguard Worker 			    enum erofs_rebuild_datamode mode)
398*33b1fccfSAndroid Build Coastguard Worker {
399*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode inode = {};
400*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_rebuild_dir_context ctx;
401*33b1fccfSAndroid Build Coastguard Worker 	char uuid_str[37];
402*33b1fccfSAndroid Build Coastguard Worker 	char *fsid = sbi->devname;
403*33b1fccfSAndroid Build Coastguard Worker 	int ret;
404*33b1fccfSAndroid Build Coastguard Worker 
405*33b1fccfSAndroid Build Coastguard Worker 	if (!fsid) {
406*33b1fccfSAndroid Build Coastguard Worker 		erofs_uuid_unparse_lower(sbi->uuid, uuid_str);
407*33b1fccfSAndroid Build Coastguard Worker 		fsid = uuid_str;
408*33b1fccfSAndroid Build Coastguard Worker 	}
409*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_read_superblock(sbi);
410*33b1fccfSAndroid Build Coastguard Worker 	if (ret) {
411*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("failed to read superblock of %s", fsid);
412*33b1fccfSAndroid Build Coastguard Worker 		return ret;
413*33b1fccfSAndroid Build Coastguard Worker 	}
414*33b1fccfSAndroid Build Coastguard Worker 
415*33b1fccfSAndroid Build Coastguard Worker 	inode.nid = sbi->root_nid;
416*33b1fccfSAndroid Build Coastguard Worker 	inode.sbi = sbi;
417*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_read_inode_from_disk(&inode);
418*33b1fccfSAndroid Build Coastguard Worker 	if (ret) {
419*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("failed to read root inode of %s", fsid);
420*33b1fccfSAndroid Build Coastguard Worker 		return ret;
421*33b1fccfSAndroid Build Coastguard Worker 	}
422*33b1fccfSAndroid Build Coastguard Worker 	inode.i_srcpath = strdup("/");
423*33b1fccfSAndroid Build Coastguard Worker 
424*33b1fccfSAndroid Build Coastguard Worker 	ctx = (struct erofs_rebuild_dir_context) {
425*33b1fccfSAndroid Build Coastguard Worker 		.ctx.dir = &inode,
426*33b1fccfSAndroid Build Coastguard Worker 		.ctx.cb = erofs_rebuild_dirent_iter,
427*33b1fccfSAndroid Build Coastguard Worker 		.mergedir = root,
428*33b1fccfSAndroid Build Coastguard Worker 		.datamode = mode,
429*33b1fccfSAndroid Build Coastguard Worker 	};
430*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_iterate_dir(&ctx.ctx, false);
431*33b1fccfSAndroid Build Coastguard Worker 	free(inode.i_srcpath);
432*33b1fccfSAndroid Build Coastguard Worker 	return ret;
433*33b1fccfSAndroid Build Coastguard Worker }
434*33b1fccfSAndroid Build Coastguard Worker 
erofs_rebuild_basedir_dirent_iter(struct erofs_dir_context * ctx)435*33b1fccfSAndroid Build Coastguard Worker static int erofs_rebuild_basedir_dirent_iter(struct erofs_dir_context *ctx)
436*33b1fccfSAndroid Build Coastguard Worker {
437*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_rebuild_dir_context *rctx = (void *)ctx;
438*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *dir = ctx->dir;
439*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *mergedir = rctx->mergedir;
440*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_dentry *d;
441*33b1fccfSAndroid Build Coastguard Worker 	char *dname;
442*33b1fccfSAndroid Build Coastguard Worker 	bool dumb;
443*33b1fccfSAndroid Build Coastguard Worker 	int ret;
444*33b1fccfSAndroid Build Coastguard Worker 
445*33b1fccfSAndroid Build Coastguard Worker 	if (ctx->dot_dotdot)
446*33b1fccfSAndroid Build Coastguard Worker 		return 0;
447*33b1fccfSAndroid Build Coastguard Worker 
448*33b1fccfSAndroid Build Coastguard Worker 	dname = strndup(ctx->dname, ctx->de_namelen);
449*33b1fccfSAndroid Build Coastguard Worker 	if (!dname)
450*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
451*33b1fccfSAndroid Build Coastguard Worker 	d = erofs_rebuild_get_dentry(mergedir, dname, false,
452*33b1fccfSAndroid Build Coastguard Worker 				     &dumb, &dumb, false);
453*33b1fccfSAndroid Build Coastguard Worker 	if (IS_ERR(d)) {
454*33b1fccfSAndroid Build Coastguard Worker 		ret = PTR_ERR(d);
455*33b1fccfSAndroid Build Coastguard Worker 		goto out;
456*33b1fccfSAndroid Build Coastguard Worker 	}
457*33b1fccfSAndroid Build Coastguard Worker 
458*33b1fccfSAndroid Build Coastguard Worker 	if (d->type == EROFS_FT_UNKNOWN) {
459*33b1fccfSAndroid Build Coastguard Worker 		d->nid = ctx->de_nid;
460*33b1fccfSAndroid Build Coastguard Worker 		d->type = ctx->de_ftype;
461*33b1fccfSAndroid Build Coastguard Worker 		d->validnid = true;
462*33b1fccfSAndroid Build Coastguard Worker 		if (!mergedir->whiteouts && erofs_dentry_is_wht(dir->sbi, d))
463*33b1fccfSAndroid Build Coastguard Worker 			mergedir->whiteouts = true;
464*33b1fccfSAndroid Build Coastguard Worker 	} else {
465*33b1fccfSAndroid Build Coastguard Worker 		struct erofs_inode *inode = d->inode;
466*33b1fccfSAndroid Build Coastguard Worker 
467*33b1fccfSAndroid Build Coastguard Worker 		/* update sub-directories only for recursively loading */
468*33b1fccfSAndroid Build Coastguard Worker 		if (S_ISDIR(inode->i_mode)) {
469*33b1fccfSAndroid Build Coastguard Worker 			list_del(&inode->i_hash);
470*33b1fccfSAndroid Build Coastguard Worker 			inode->dev = dir->sbi->dev;
471*33b1fccfSAndroid Build Coastguard Worker 			inode->i_ino[1] = ctx->de_nid;
472*33b1fccfSAndroid Build Coastguard Worker 			erofs_insert_ihash(inode);
473*33b1fccfSAndroid Build Coastguard Worker 		}
474*33b1fccfSAndroid Build Coastguard Worker 	}
475*33b1fccfSAndroid Build Coastguard Worker 	ret = 0;
476*33b1fccfSAndroid Build Coastguard Worker out:
477*33b1fccfSAndroid Build Coastguard Worker 	free(dname);
478*33b1fccfSAndroid Build Coastguard Worker 	return ret;
479*33b1fccfSAndroid Build Coastguard Worker }
480*33b1fccfSAndroid Build Coastguard Worker 
erofs_rebuild_load_basedir(struct erofs_inode * dir)481*33b1fccfSAndroid Build Coastguard Worker int erofs_rebuild_load_basedir(struct erofs_inode *dir)
482*33b1fccfSAndroid Build Coastguard Worker {
483*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode fakeinode = {
484*33b1fccfSAndroid Build Coastguard Worker 		.sbi = dir->sbi,
485*33b1fccfSAndroid Build Coastguard Worker 		.nid = dir->i_ino[1],
486*33b1fccfSAndroid Build Coastguard Worker 	};
487*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_rebuild_dir_context ctx;
488*33b1fccfSAndroid Build Coastguard Worker 	int ret;
489*33b1fccfSAndroid Build Coastguard Worker 
490*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_read_inode_from_disk(&fakeinode);
491*33b1fccfSAndroid Build Coastguard Worker 	if (ret) {
492*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("failed to read inode @ %llu", fakeinode.nid);
493*33b1fccfSAndroid Build Coastguard Worker 		return ret;
494*33b1fccfSAndroid Build Coastguard Worker 	}
495*33b1fccfSAndroid Build Coastguard Worker 
496*33b1fccfSAndroid Build Coastguard Worker 	/* Inherit the maximum xattr size for the root directory */
497*33b1fccfSAndroid Build Coastguard Worker 	if (__erofs_unlikely(IS_ROOT(dir)))
498*33b1fccfSAndroid Build Coastguard Worker 		dir->xattr_isize = fakeinode.xattr_isize;
499*33b1fccfSAndroid Build Coastguard Worker 
500*33b1fccfSAndroid Build Coastguard Worker 	ctx = (struct erofs_rebuild_dir_context) {
501*33b1fccfSAndroid Build Coastguard Worker 		.ctx.dir = &fakeinode,
502*33b1fccfSAndroid Build Coastguard Worker 		.ctx.cb = erofs_rebuild_basedir_dirent_iter,
503*33b1fccfSAndroid Build Coastguard Worker 		.mergedir = dir,
504*33b1fccfSAndroid Build Coastguard Worker 	};
505*33b1fccfSAndroid Build Coastguard Worker 	return erofs_iterate_dir(&ctx.ctx, false);
506*33b1fccfSAndroid Build Coastguard Worker }
507