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