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