diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/erofs/blobchunk.h | 10 | ||||
-rw-r--r-- | include/erofs/block_list.h | 7 | ||||
-rw-r--r-- | include/erofs/cache.h | 15 | ||||
-rw-r--r-- | include/erofs/compress.h | 12 | ||||
-rw-r--r-- | include/erofs/compress_hints.h | 2 | ||||
-rw-r--r-- | include/erofs/config.h | 5 | ||||
-rw-r--r-- | include/erofs/decompress.h | 1 | ||||
-rw-r--r-- | include/erofs/defs.h | 34 | ||||
-rw-r--r-- | include/erofs/dir.h | 3 | ||||
-rw-r--r-- | include/erofs/diskbuf.h | 30 | ||||
-rw-r--r-- | include/erofs/err.h | 6 | ||||
-rw-r--r-- | include/erofs/fragments.h | 13 | ||||
-rw-r--r-- | include/erofs/hashmap.h | 5 | ||||
-rw-r--r-- | include/erofs/inode.h | 20 | ||||
-rw-r--r-- | include/erofs/internal.h | 138 | ||||
-rw-r--r-- | include/erofs/io.h | 40 | ||||
-rw-r--r-- | include/erofs/list.h | 20 | ||||
-rw-r--r-- | include/erofs/rebuild.h | 21 | ||||
-rw-r--r-- | include/erofs/tar.h | 60 | ||||
-rw-r--r-- | include/erofs/xattr.h | 55 | ||||
-rw-r--r-- | include/erofs/xxhash.h | 27 | ||||
-rw-r--r-- | include/erofs_fs.h | 294 |
22 files changed, 540 insertions, 278 deletions
diff --git a/include/erofs/blobchunk.h b/include/erofs/blobchunk.h index 49cb7bf..89c8048 100644 --- a/include/erofs/blobchunk.h +++ b/include/erofs/blobchunk.h @@ -14,12 +14,16 @@ extern "C" #include "erofs/internal.h" +struct erofs_blobchunk *erofs_get_unhashed_chunk(unsigned int device_id, + erofs_blk_t blkaddr, erofs_off_t sourceoffset); int erofs_blob_write_chunk_indexes(struct erofs_inode *inode, erofs_off_t off); -int erofs_blob_write_chunked_file(struct erofs_inode *inode); -int erofs_blob_remap(void); +int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd, + erofs_off_t startoff); +int tarerofs_write_chunkes(struct erofs_inode *inode, erofs_off_t data_offset); +int erofs_mkfs_dump_blobs(struct erofs_sb_info *sbi); void erofs_blob_exit(void); int erofs_blob_init(const char *blobfile_path); -int erofs_generate_devtable(void); +int erofs_mkfs_init_devices(struct erofs_sb_info *sbi, unsigned int devices); #ifdef __cplusplus } diff --git a/include/erofs/block_list.h b/include/erofs/block_list.h index 78fab44..9f9975e 100644 --- a/include/erofs/block_list.h +++ b/include/erofs/block_list.h @@ -13,9 +13,12 @@ extern "C" #include "internal.h" +int erofs_blocklist_open(char *filename, bool srcmap); +void erofs_blocklist_close(void); + +void tarerofs_blocklist_write(erofs_blk_t blkaddr, erofs_blk_t nblocks, + erofs_off_t srcoff); #ifdef WITH_ANDROID -int erofs_droid_blocklist_fopen(void); -void erofs_droid_blocklist_fclose(void); void erofs_droid_blocklist_write(struct erofs_inode *inode, erofs_blk_t blk_start, erofs_blk_t nblocks); void erofs_droid_blocklist_write_tail_end(struct erofs_inode *inode, diff --git a/include/erofs/cache.h b/include/erofs/cache.h index de12399..de5584e 100644 --- a/include/erofs/cache.h +++ b/include/erofs/cache.h @@ -22,10 +22,12 @@ struct erofs_buffer_block; #define META 1 /* including inline xattrs, extent */ #define INODE 2 +/* directory data */ +#define DIRA 3 /* shared xattrs */ -#define XATTR 3 +#define XATTR 4 /* device table */ -#define DEVT 4 +#define DEVT 5 struct erofs_bhops { bool (*preflush)(struct erofs_buffer_head *bh); @@ -55,11 +57,14 @@ struct erofs_buffer_block { static inline const int get_alignsize(int type, int *type_ret) { if (type == DATA) - return EROFS_BLKSIZ; + return erofs_blksiz(&sbi); if (type == INODE) { *type_ret = META; return sizeof(struct erofs_inode_compact); + } else if (type == DIRA) { + *type_ret = META; + return erofs_blksiz(&sbi); } else if (type == XATTR) { *type_ret = META; return sizeof(struct erofs_xattr_entry); @@ -75,7 +80,6 @@ static inline const int get_alignsize(int type, int *type_ret) extern const struct erofs_bhops erofs_drop_directly_bhops; extern const struct erofs_bhops erofs_skip_write_bhops; -extern const struct erofs_bhops erofs_buf_write_bhops; static inline erofs_off_t erofs_btell(struct erofs_buffer_head *bh, bool end) { @@ -84,7 +88,7 @@ static inline erofs_off_t erofs_btell(struct erofs_buffer_head *bh, bool end) if (bb->blkaddr == NULL_ADDR) return NULL_ADDR_UL; - return blknr_to_addr(bb->blkaddr) + + return erofs_pos(&sbi, bb->blkaddr) + (end ? list_next_entry(bh, list)->off : bh->off); } @@ -108,6 +112,7 @@ erofs_blk_t erofs_mapbh(struct erofs_buffer_block *bb); bool erofs_bflush(struct erofs_buffer_block *bb); void erofs_bdrop(struct erofs_buffer_head *bh, bool tryrevoke); +erofs_blk_t erofs_total_metablocks(void); #ifdef __cplusplus } diff --git a/include/erofs/compress.h b/include/erofs/compress.h index 08af9e3..46cff03 100644 --- a/include/erofs/compress.h +++ b/include/erofs/compress.h @@ -19,18 +19,22 @@ extern "C" void z_erofs_drop_inline_pcluster(struct erofs_inode *inode); int erofs_write_compressed_file(struct erofs_inode *inode, int fd); -int z_erofs_compress_init(struct erofs_buffer_head *bh); +int z_erofs_compress_init(struct erofs_sb_info *sbi, + struct erofs_buffer_head *bh); int z_erofs_compress_exit(void); -const char *z_erofs_list_available_compressors(unsigned int i); +const char *z_erofs_list_supported_algorithms(int i, unsigned int *mask); +const char *z_erofs_list_available_compressors(int *i); static inline bool erofs_is_packed_inode(struct erofs_inode *inode) { + erofs_nid_t packed_nid = inode->sbi->packed_nid; + if (inode->nid == EROFS_PACKED_NID_UNALLOCATED) { - DBG_BUGON(sbi.packed_nid != EROFS_PACKED_NID_UNALLOCATED); + DBG_BUGON(packed_nid != EROFS_PACKED_NID_UNALLOCATED); return true; } - return (sbi.packed_nid > 0 && inode->nid == sbi.packed_nid); + return (packed_nid > 0 && inode->nid == packed_nid); } #ifdef __cplusplus diff --git a/include/erofs/compress_hints.h b/include/erofs/compress_hints.h index d836f22..9f0d8ae 100644 --- a/include/erofs/compress_hints.h +++ b/include/erofs/compress_hints.h @@ -25,7 +25,7 @@ struct erofs_compress_hints { bool z_erofs_apply_compress_hints(struct erofs_inode *inode); void erofs_cleanup_compress_hints(void); -int erofs_load_compress_hints(void); +int erofs_load_compress_hints(struct erofs_sb_info *sbi); #ifdef __cplusplus } diff --git a/include/erofs/config.h b/include/erofs/config.h index 648a3e8..e342722 100644 --- a/include/erofs/config.h +++ b/include/erofs/config.h @@ -45,13 +45,16 @@ struct erofs_configure { #endif char c_timeinherit; char c_chunkbits; - bool c_noinline_data; + bool c_inline_data; bool c_ztailpacking; bool c_fragments; bool c_all_fragments; bool c_dedupe; bool c_ignore_mtime; bool c_showprogress; + bool c_extra_ea_name_prefixes; + bool c_xattr_name_filter; + bool c_ovlfs_strip; #ifdef HAVE_LIBSELINUX struct selabel_handle *sehnd; diff --git a/include/erofs/decompress.h b/include/erofs/decompress.h index a9067cb..0d55483 100644 --- a/include/erofs/decompress.h +++ b/include/erofs/decompress.h @@ -14,6 +14,7 @@ extern "C" #include "internal.h" struct z_erofs_decompress_req { + struct erofs_sb_info *sbi; char *in, *out; /* diff --git a/include/erofs/defs.h b/include/erofs/defs.h index e5aa23c..fefa7e7 100644 --- a/include/erofs/defs.h +++ b/include/erofs/defs.h @@ -179,9 +179,29 @@ typedef int64_t s64; #define __maybe_unused __attribute__((__unused__)) #endif -static inline u32 get_unaligned_le32(const u8 *p) +#define __packed __attribute__((__packed__)) + +#define __get_unaligned_t(type, ptr) ({ \ + const struct { type x; } __packed *__pptr = (typeof(__pptr))(ptr); \ + __pptr->x; \ +}) + +#define __put_unaligned_t(type, val, ptr) do { \ + struct { type x; } __packed *__pptr = (typeof(__pptr))(ptr); \ + __pptr->x = (val); \ +} while (0) + +#define get_unaligned(ptr) __get_unaligned_t(typeof(*(ptr)), (ptr)) +#define put_unaligned(val, ptr) __put_unaligned_t(typeof(*(ptr)), (val), (ptr)) + +static inline u32 get_unaligned_le32(const void *p) +{ + return le32_to_cpu(__get_unaligned_t(__le32, p)); +} + +static inline void put_unaligned_le32(u32 val, void *p) { - return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; + __put_unaligned_t(__le32, cpu_to_le32(val), p); } /** @@ -266,6 +286,11 @@ static inline unsigned int fls_long(unsigned long x) return x ? sizeof(x) * 8 - __builtin_clz(x) : 0; } +static inline unsigned long lowbit(unsigned long n) +{ + return n & -n; +} + /** * __roundup_pow_of_two() - round up to nearest power of two * @n: value to round up @@ -313,11 +338,6 @@ unsigned long __roundup_pow_of_two(unsigned long n) #define ST_MTIM_NSEC(stbuf) 0 #endif -#ifdef __APPLE__ -#define stat64 stat -#define lstat64 lstat -#endif - #ifdef __cplusplus } #endif diff --git a/include/erofs/dir.h b/include/erofs/dir.h index 74bffb5..5460ac4 100644 --- a/include/erofs/dir.h +++ b/include/erofs/dir.h @@ -62,7 +62,8 @@ struct erofs_dir_context { /* Iterate over inodes that are in directory */ int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck); /* Get a full pathname of the inode NID */ -int erofs_get_pathname(erofs_nid_t nid, char *buf, size_t size); +int erofs_get_pathname(struct erofs_sb_info *sbi, erofs_nid_t nid, + char *buf, size_t size); #ifdef __cplusplus } diff --git a/include/erofs/diskbuf.h b/include/erofs/diskbuf.h new file mode 100644 index 0000000..29d9fe2 --- /dev/null +++ b/include/erofs/diskbuf.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0 */ +#ifndef __EROFS_DISKBUF_H +#define __EROFS_DISKBUF_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "erofs/defs.h" + +struct erofs_diskbuf { + void *sp; /* internal stream pointer */ + u64 offset; /* internal offset */ +}; + +int erofs_diskbuf_getfd(struct erofs_diskbuf *db, u64 *off); + +int erofs_diskbuf_reserve(struct erofs_diskbuf *db, int sid, u64 *off); +void erofs_diskbuf_commit(struct erofs_diskbuf *db, u64 len); +void erofs_diskbuf_close(struct erofs_diskbuf *db); + +int erofs_diskbuf_init(unsigned int nstrms); +void erofs_diskbuf_exit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/erofs/err.h b/include/erofs/err.h index 08b0bdb..2ae9e21 100644 --- a/include/erofs/err.h +++ b/include/erofs/err.h @@ -33,6 +33,12 @@ static inline long PTR_ERR(const void *ptr) return (long) ptr; } +static inline void * ERR_CAST(const void *ptr) +{ + /* cast away the const */ + return (void *) ptr; +} + #ifdef __cplusplus } #endif diff --git a/include/erofs/fragments.h b/include/erofs/fragments.h index 21753ec..4c6f755 100644 --- a/include/erofs/fragments.h +++ b/include/erofs/fragments.h @@ -12,17 +12,20 @@ extern "C" #include "erofs/internal.h" -extern const char *frags_packedname; -#define EROFS_PACKED_INODE frags_packedname +extern const char *erofs_frags_packedname; +#define EROFS_PACKED_INODE erofs_frags_packedname + +FILE *erofs_packedfile_init(void); +void erofs_packedfile_exit(void); +struct erofs_inode *erofs_mkfs_build_packedfile(void); int z_erofs_fragments_dedupe(struct erofs_inode *inode, int fd, u32 *tofcrc); int z_erofs_pack_file_from_fd(struct erofs_inode *inode, int fd, u32 tofcrc); int z_erofs_pack_fragments(struct erofs_inode *inode, void *data, unsigned int len, u32 tofcrc); void z_erofs_fragments_commit(struct erofs_inode *inode); -struct erofs_inode *erofs_mkfs_build_fragments(void); -int erofs_fragments_init(void); -void erofs_fragments_exit(void); +int z_erofs_fragments_init(void); +void z_erofs_fragments_exit(void); #ifdef __cplusplus } diff --git a/include/erofs/hashmap.h b/include/erofs/hashmap.h index 3d38578..d25092d 100644 --- a/include/erofs/hashmap.h +++ b/include/erofs/hashmap.h @@ -61,7 +61,7 @@ struct hashmap_iter { /* hashmap functions */ void hashmap_init(struct hashmap *map, hashmap_cmp_fn equals_function, size_t initial_size); -void hashmap_free(struct hashmap *map, int free_entries); +int hashmap_free(struct hashmap *map); /* hashmap_entry functions */ static inline void hashmap_entry_init(void *entry, unsigned int hash) @@ -75,8 +75,7 @@ static inline void hashmap_entry_init(void *entry, unsigned int hash) void *hashmap_get(const struct hashmap *map, const void *key, const void *keydata); void *hashmap_get_next(const struct hashmap *map, const void *entry); void hashmap_add(struct hashmap *map, void *entry); -void *hashmap_put(struct hashmap *map, void *entry); -void *hashmap_remove(struct hashmap *map, const void *key, const void *keydata); +void *hashmap_remove(struct hashmap *map, const void *key); static inline void *hashmap_get_from_hash(const struct hashmap *map, unsigned int hash, diff --git a/include/erofs/inode.h b/include/erofs/inode.h index bf20cd3..bcfd98e 100644 --- a/include/erofs/inode.h +++ b/include/erofs/inode.h @@ -15,13 +15,29 @@ extern "C" #include "erofs/internal.h" +static inline struct erofs_inode *erofs_igrab(struct erofs_inode *inode) +{ + ++inode->i_count; + return inode; +} + +u32 erofs_new_encode_dev(dev_t dev); unsigned char erofs_mode_to_ftype(umode_t mode); unsigned char erofs_ftype_to_dtype(unsigned int filetype); void erofs_inode_manager_init(void); +void erofs_insert_ihash(struct erofs_inode *inode, dev_t dev, ino_t ino); +struct erofs_inode *erofs_iget(dev_t dev, ino_t ino); +struct erofs_inode *erofs_iget_by_nid(erofs_nid_t nid); unsigned int erofs_iput(struct erofs_inode *inode); erofs_nid_t erofs_lookupnid(struct erofs_inode *inode); -struct erofs_inode *erofs_mkfs_build_tree_from_path(struct erofs_inode *parent, - const char *path); +struct erofs_dentry *erofs_d_alloc(struct erofs_inode *parent, + const char *name); +int erofs_rebuild_dump_tree(struct erofs_inode *dir); +int erofs_init_empty_dir(struct erofs_inode *dir); +int __erofs_fill_inode(struct erofs_inode *inode, struct stat *st, + const char *path); +struct erofs_inode *erofs_new_inode(void); +struct erofs_inode *erofs_mkfs_build_tree_from_path(const char *path); struct erofs_inode *erofs_mkfs_build_special_from_fd(int fd, const char *name); #ifdef __cplusplus diff --git a/include/erofs/internal.h b/include/erofs/internal.h index d4ae3b8..d859905 100644 --- a/include/erofs/internal.h +++ b/include/erofs/internal.h @@ -17,36 +17,20 @@ extern "C" typedef unsigned short umode_t; -#define __packed __attribute__((__packed__)) - #include "erofs_fs.h" #include <fcntl.h> #include <sys/types.h> /* for off_t definition */ +#include <sys/stat.h> /* for S_ISCHR definition */ +#include <stdio.h> #ifndef PATH_MAX #define PATH_MAX 4096 /* # chars in a path name including nul */ #endif -#ifndef PAGE_SHIFT -#define PAGE_SHIFT (12) -#endif - -#ifndef PAGE_SIZE -#define PAGE_SIZE (1U << PAGE_SHIFT) -#endif - -/* no obvious reason to support explicit PAGE_SIZE != 4096 for now */ -#if PAGE_SIZE != 4096 -#warning EROFS may be incompatible on your platform -#endif - -#ifndef PAGE_MASK -#define PAGE_MASK (~(PAGE_SIZE-1)) +#ifndef EROFS_MAX_BLOCK_SIZE +#define EROFS_MAX_BLOCK_SIZE 4096 #endif -#define LOG_BLOCK_SIZE (12) -#define EROFS_BLKSIZ (1U << LOG_BLOCK_SIZE) - #define EROFS_ISLOTBITS 5 #define EROFS_SLOTSIZE (1U << EROFS_ISLOTBITS) @@ -58,23 +42,33 @@ typedef u32 erofs_blk_t; #define NULL_ADDR ((unsigned int)-1) #define NULL_ADDR_UL ((unsigned long)-1) -#define erofs_blknr(addr) ((addr) / EROFS_BLKSIZ) -#define erofs_blkoff(addr) ((addr) % EROFS_BLKSIZ) -#define blknr_to_addr(nr) ((erofs_off_t)(nr) * EROFS_BLKSIZ) +/* global sbi */ +extern struct erofs_sb_info sbi; -#define BLK_ROUND_UP(addr) DIV_ROUND_UP(addr, EROFS_BLKSIZ) +#define erofs_blksiz(sbi) (1u << (sbi)->blkszbits) +#define erofs_blknr(sbi, addr) ((addr) >> (sbi)->blkszbits) +#define erofs_blkoff(sbi, addr) ((addr) & (erofs_blksiz(sbi) - 1)) +#define erofs_pos(sbi, nr) ((erofs_off_t)(nr) << (sbi)->blkszbits) +#define BLK_ROUND_UP(sbi, addr) DIV_ROUND_UP(addr, erofs_blksiz(sbi)) struct erofs_buffer_head; struct erofs_device_info { + u8 tag[64]; u32 blocks; u32 mapped_blkaddr; }; +struct erofs_xattr_prefix_item { + struct erofs_xattr_long_prefix *prefix; + u8 infix_len; +}; + #define EROFS_PACKED_NID_UNALLOCATED -1 struct erofs_sb_info { struct erofs_device_info *devs; + char *devname; u64 total_blocks; u64 primarydevice_blocks; @@ -87,7 +81,9 @@ struct erofs_sb_info { u64 build_time; u32 build_time_nsec; + u8 extslots; unsigned char islotbits; + unsigned char blkszbits; /* what we really care is nid, rather than ino.. */ erofs_nid_t root_nid; @@ -107,35 +103,40 @@ struct erofs_sb_info { u16 device_id_mask; /* used for others */ }; erofs_nid_t packed_nid; -}; + u32 xattr_prefix_start; + u8 xattr_prefix_count; + struct erofs_xattr_prefix_item *xattr_prefixes; -/* make sure that any user of the erofs headers has atleast 64bit off_t type */ -extern int erofs_assert_largefile[sizeof(off_t)-8]; + int devfd, devblksz; + u64 devsz; + dev_t dev; + unsigned int nblobs; + unsigned int blobfd[256]; -/* global sbi */ -extern struct erofs_sb_info sbi; + struct list_head list; -static inline erofs_off_t iloc(erofs_nid_t nid) -{ - return blknr_to_addr(sbi.meta_blkaddr) + (nid << sbi.islotbits); -} + u64 saved_by_deduplication; +}; + +/* make sure that any user of the erofs headers has atleast 64bit off_t type */ +extern int erofs_assert_largefile[sizeof(off_t)-8]; #define EROFS_FEATURE_FUNCS(name, compat, feature) \ -static inline bool erofs_sb_has_##name(void) \ +static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \ { \ - return sbi.feature_##compat & EROFS_FEATURE_##feature; \ + return sbi->feature_##compat & EROFS_FEATURE_##feature; \ } \ -static inline void erofs_sb_set_##name(void) \ +static inline void erofs_sb_set_##name(struct erofs_sb_info *sbi) \ { \ - sbi.feature_##compat |= EROFS_FEATURE_##feature; \ + sbi->feature_##compat |= EROFS_FEATURE_##feature; \ } \ -static inline void erofs_sb_clear_##name(void) \ +static inline void erofs_sb_clear_##name(struct erofs_sb_info *sbi) \ { \ - sbi.feature_##compat &= ~EROFS_FEATURE_##feature; \ + sbi->feature_##compat &= ~EROFS_FEATURE_##feature; \ } -EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING) +EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_ZERO_PADDING) EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS) EROFS_FEATURE_FUNCS(big_pcluster, incompat, INCOMPAT_BIG_PCLUSTER) EROFS_FEATURE_FUNCS(chunked_file, incompat, INCOMPAT_CHUNKED_FILE) @@ -143,23 +144,31 @@ EROFS_FEATURE_FUNCS(device_table, incompat, INCOMPAT_DEVICE_TABLE) EROFS_FEATURE_FUNCS(ztailpacking, incompat, INCOMPAT_ZTAILPACKING) EROFS_FEATURE_FUNCS(fragments, incompat, INCOMPAT_FRAGMENTS) EROFS_FEATURE_FUNCS(dedupe, incompat, INCOMPAT_DEDUPE) +EROFS_FEATURE_FUNCS(xattr_prefixes, incompat, INCOMPAT_XATTR_PREFIXES) EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM) +EROFS_FEATURE_FUNCS(xattr_filter, compat, COMPAT_XATTR_FILTER) #define EROFS_I_EA_INITED (1 << 0) #define EROFS_I_Z_INITED (1 << 1) +struct erofs_diskbuf; + struct erofs_inode { struct list_head i_hash, i_subdirs, i_xattrs; union { /* (erofsfuse) runtime flags */ unsigned int flags; - /* (mkfs.erofs) device ID containing source file */ - u32 dev; + /* (mkfs.erofs) queued sub-directories blocking dump */ + u32 subdirs_queued; }; unsigned int i_count; + struct erofs_sb_info *sbi; struct erofs_inode *i_parent; + /* (mkfs.erofs) device ID containing source file */ + u32 dev; + umode_t i_mode; erofs_off_t i_size; @@ -181,12 +190,20 @@ struct erofs_inode { } u; char *i_srcpath; - + union { + char *i_link; + struct erofs_diskbuf *i_diskbuf; + }; unsigned char datalayout; unsigned char inode_isize; /* inline tail-end packing size */ unsigned short idata_size; bool compressed_idata; + bool lazy_tailblock; + bool with_diskbuf; + bool opaque; + /* OVL: non-merge dir that may contain whiteout entries */ + bool whiteouts; unsigned int xattr_isize; unsigned int extent_isize; @@ -224,6 +241,14 @@ struct erofs_inode { unsigned int fragment_size; }; +static inline erofs_off_t erofs_iloc(struct erofs_inode *inode) +{ + struct erofs_sb_info *sbi = inode->sbi; + + return erofs_pos(sbi, sbi->meta_blkaddr) + + (inode->nid << sbi->islotbits); +} + static inline bool is_inode_layout_compression(struct erofs_inode *inode) { return erofs_inode_is_data_compressed(inode->datalayout); @@ -310,7 +335,7 @@ enum { #define EROFS_MAP_PARTIAL_REF (1 << BH_Partialref) struct erofs_map_blocks { - char mpage[EROFS_BLKSIZ]; + char mpage[EROFS_MAX_BLOCK_SIZE]; erofs_off_t m_pa, m_la; u64 m_plen, m_llen; @@ -341,13 +366,12 @@ struct erofs_map_dev { }; /* super.c */ -int erofs_read_superblock(void); -void erofs_put_super(void); +int erofs_read_superblock(struct erofs_sb_info *sbi); +void erofs_put_super(struct erofs_sb_info *sbi); /* namei.c */ int erofs_read_inode_from_disk(struct erofs_inode *vi); int erofs_ilookup(const char *path, struct erofs_inode *vi); -int erofs_read_inode_from_disk(struct erofs_inode *vi); /* data.c */ int erofs_pread(struct erofs_inode *inode, char *buf, @@ -355,11 +379,13 @@ int erofs_pread(struct erofs_inode *inode, char *buf, int erofs_map_blocks(struct erofs_inode *inode, struct erofs_map_blocks *map, int flags); int erofs_map_dev(struct erofs_sb_info *sbi, struct erofs_map_dev *map); -int erofs_read_one_data(struct erofs_map_blocks *map, char *buffer, u64 offset, - size_t len); +int erofs_read_one_data(struct erofs_inode *inode, struct erofs_map_blocks *map, + char *buffer, u64 offset, size_t len); int z_erofs_read_one_data(struct erofs_inode *inode, struct erofs_map_blocks *map, char *raw, char *buffer, erofs_off_t skip, erofs_off_t length, bool trimmed); +void *erofs_read_metadata(struct erofs_sb_info *sbi, erofs_nid_t nid, + erofs_off_t *offset, int *lengthp); static inline int erofs_get_occupied_size(const struct erofs_inode *inode, erofs_off_t *size) @@ -371,12 +397,12 @@ static inline int erofs_get_occupied_size(const struct erofs_inode *inode, case EROFS_INODE_CHUNK_BASED: *size = inode->i_size; break; - case EROFS_INODE_FLAT_COMPRESSION_LEGACY: - case EROFS_INODE_FLAT_COMPRESSION: - *size = inode->u.i_blocks * EROFS_BLKSIZ; + case EROFS_INODE_COMPRESSED_FULL: + case EROFS_INODE_COMPRESSED_COMPACT: + *size = inode->u.i_blocks * erofs_blksiz(inode->sbi); break; default: - return -ENOTSUP; + return -EOPNOTSUPP; } return 0; } @@ -410,6 +436,12 @@ static inline u32 erofs_crc32c(u32 crc, const u8 *in, size_t len) return crc; } +#define EROFS_WHITEOUT_DEV 0 +static inline bool erofs_inode_is_whiteout(struct erofs_inode *inode) +{ + return S_ISCHR(inode->i_mode) && inode->u.i_rdev == EROFS_WHITEOUT_DEV; +} + #ifdef __cplusplus } #endif diff --git a/include/erofs/io.h b/include/erofs/io.h index 0f58c70..4db5716 100644 --- a/include/erofs/io.h +++ b/include/erofs/io.h @@ -22,36 +22,36 @@ extern "C" #define O_BINARY 0 #endif -void blob_closeall(void); -int blob_open_ro(const char *dev); -int dev_open(const char *devname); -int dev_open_ro(const char *dev); -void dev_close(void); -int dev_write(const void *buf, u64 offset, size_t len); -int dev_read(int device_id, void *buf, u64 offset, size_t len); -int dev_fillzero(u64 offset, size_t len, bool padding); -int dev_fsync(void); -int dev_resize(erofs_blk_t nblocks); -u64 dev_length(void); - -extern int erofs_devfd; +void blob_closeall(struct erofs_sb_info *sbi); +int blob_open_ro(struct erofs_sb_info *sbi, const char *dev); +int dev_open(struct erofs_sb_info *sbi, const char *devname); +int dev_open_ro(struct erofs_sb_info *sbi, const char *dev); +void dev_close(struct erofs_sb_info *sbi); +int dev_write(struct erofs_sb_info *sbi, const void *buf, + u64 offset, size_t len); +int dev_read(struct erofs_sb_info *sbi, int device_id, + void *buf, u64 offset, size_t len); +int dev_fillzero(struct erofs_sb_info *sbi, u64 offset, + size_t len, bool padding); +int dev_fsync(struct erofs_sb_info *sbi); +int dev_resize(struct erofs_sb_info *sbi, erofs_blk_t nblocks); ssize_t erofs_copy_file_range(int fd_in, erofs_off_t *off_in, int fd_out, erofs_off_t *off_out, size_t length); -static inline int blk_write(const void *buf, erofs_blk_t blkaddr, - u32 nblocks) +static inline int blk_write(struct erofs_sb_info *sbi, const void *buf, + erofs_blk_t blkaddr, u32 nblocks) { - return dev_write(buf, blknr_to_addr(blkaddr), - blknr_to_addr(nblocks)); + return dev_write(sbi, buf, erofs_pos(sbi, blkaddr), + erofs_pos(sbi, nblocks)); } -static inline int blk_read(int device_id, void *buf, +static inline int blk_read(struct erofs_sb_info *sbi, int device_id, void *buf, erofs_blk_t start, u32 nblocks) { - return dev_read(device_id, buf, blknr_to_addr(start), - blknr_to_addr(nblocks)); + return dev_read(sbi, device_id, buf, erofs_pos(sbi, start), + erofs_pos(sbi, nblocks)); } #ifdef __cplusplus diff --git a/include/erofs/list.h b/include/erofs/list.h index 3f5da1a..d7a9fee 100644 --- a/include/erofs/list.h +++ b/include/erofs/list.h @@ -70,6 +70,26 @@ static inline int list_empty(struct list_head *head) return head->next == head; } +static inline void __list_splice(struct list_head *list, + struct list_head *prev, struct list_head *next) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + + first->prev = prev; + prev->next = first; + + last->next = next; + next->prev = last; +} + +static inline void list_splice_tail(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head->prev, head); +} + #define list_entry(ptr, type, member) container_of(ptr, type, member) #define list_first_entry(ptr, type, member) \ diff --git a/include/erofs/rebuild.h b/include/erofs/rebuild.h new file mode 100644 index 0000000..e99ce74 --- /dev/null +++ b/include/erofs/rebuild.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0 */ +#ifndef __EROFS_REBUILD_H +#define __EROFS_REBUILD_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "internal.h" + +struct erofs_dentry *erofs_rebuild_get_dentry(struct erofs_inode *pwd, + char *path, bool aufs, bool *whout, bool *opq, bool to_head); + +int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_sb_info *sbi); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/erofs/tar.h b/include/erofs/tar.h new file mode 100644 index 0000000..a76f740 --- /dev/null +++ b/include/erofs/tar.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0 */ +#ifndef __EROFS_TAR_H +#define __EROFS_TAR_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if defined(HAVE_ZLIB) +#include <zlib.h> +#endif +#include <sys/stat.h> + +#include "internal.h" + +struct erofs_pax_header { + struct stat st; + struct list_head xattrs; + bool use_mtime; + bool use_size; + bool use_uid; + bool use_gid; + char *path, *link; +}; + +#define EROFS_IOS_DECODER_NONE 0 +#define EROFS_IOS_DECODER_GZIP 1 + +struct erofs_iostream { + union { + int fd; /* original fd */ + void *handler; + }; + u64 sz; + char *buffer; + unsigned int head, tail, bufsize; + int decoder; + bool feof; +}; + +struct erofs_tarfile { + struct erofs_pax_header global; + struct erofs_iostream ios; + char *mapfile; + + int fd; + u64 offset; + bool index_mode, aufs; +}; + +void erofs_iostream_close(struct erofs_iostream *ios); +int erofs_iostream_open(struct erofs_iostream *ios, int fd, int decoder); +int tarerofs_parse_tar(struct erofs_inode *root, struct erofs_tarfile *tar); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h index a0528c0..0f76037 100644 --- a/include/erofs/xattr.h +++ b/include/erofs/xattr.h @@ -24,15 +24,17 @@ static inline unsigned int inlinexattr_header_size(struct erofs_inode *vi) sizeof(u32) * vi->xattr_shared_count; } -static inline erofs_blk_t xattrblock_addr(unsigned int xattr_id) +static inline erofs_blk_t xattrblock_addr(struct erofs_inode *vi, + unsigned int xattr_id) { - return sbi.xattr_blkaddr + - xattr_id * sizeof(__u32) / EROFS_BLKSIZ; + return vi->sbi->xattr_blkaddr + + erofs_blknr(vi->sbi, xattr_id * sizeof(__u32)); } -static inline unsigned int xattrblock_offset(unsigned int xattr_id) +static inline unsigned int xattrblock_offset(struct erofs_inode *vi, + unsigned int xattr_id) { - return (xattr_id * sizeof(__u32)) % EROFS_BLKSIZ; + return erofs_blkoff(vi->sbi, xattr_id * sizeof(__u32)); } #define EROFS_INODE_XATTR_ICOUNT(_size) ({\ @@ -41,34 +43,23 @@ static inline unsigned int xattrblock_offset(unsigned int xattr_id) (_size - sizeof(struct erofs_xattr_ibody_header)) / \ sizeof(struct erofs_xattr_entry) + 1; }) -#ifndef XATTR_USER_PREFIX -#define XATTR_USER_PREFIX "user." -#endif -#ifndef XATTR_USER_PREFIX_LEN -#define XATTR_USER_PREFIX_LEN (sizeof(XATTR_USER_PREFIX) - 1) -#endif -#ifndef XATTR_SECURITY_PREFIX -#define XATTR_SECURITY_PREFIX "security." -#endif -#ifndef XATTR_SECURITY_PREFIX_LEN -#define XATTR_SECURITY_PREFIX_LEN (sizeof(XATTR_SECURITY_PREFIX) - 1) -#endif -#ifndef XATTR_TRUSTED_PREFIX -#define XATTR_TRUSTED_PREFIX "trusted." -#endif -#ifndef XATTR_TRUSTED_PREFIX_LEN -#define XATTR_TRUSTED_PREFIX_LEN (sizeof(XATTR_TRUSTED_PREFIX) - 1) -#endif -#ifndef XATTR_NAME_POSIX_ACL_ACCESS -#define XATTR_NAME_POSIX_ACL_ACCESS "system.posix_acl_access" -#endif -#ifndef XATTR_NAME_POSIX_ACL_DEFAULT -#define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default" -#endif - +int erofs_scan_file_xattrs(struct erofs_inode *inode); int erofs_prepare_xattr_ibody(struct erofs_inode *inode); -char *erofs_export_xattr_ibody(struct list_head *ixattrs, unsigned int size); -int erofs_build_shared_xattrs_from_path(const char *path); +char *erofs_export_xattr_ibody(struct erofs_inode *inode); +int erofs_build_shared_xattrs_from_path(struct erofs_sb_info *sbi, const char *path); + +int erofs_xattr_insert_name_prefix(const char *prefix); +void erofs_xattr_cleanup_name_prefixes(void); +int erofs_xattr_write_name_prefixes(struct erofs_sb_info *sbi, FILE *f); +void erofs_xattr_prefixes_cleanup(struct erofs_sb_info *sbi); +int erofs_xattr_prefixes_init(struct erofs_sb_info *sbi); + +int erofs_setxattr(struct erofs_inode *inode, char *key, + const void *value, size_t size); +int erofs_set_opaque_xattr(struct erofs_inode *inode); +void erofs_clear_opaque_xattr(struct erofs_inode *inode); +int erofs_set_origin_xattr(struct erofs_inode *inode); +int erofs_read_xattrs_from_disk(struct erofs_inode *inode); #ifdef __cplusplus } diff --git a/include/erofs/xxhash.h b/include/erofs/xxhash.h new file mode 100644 index 0000000..5441209 --- /dev/null +++ b/include/erofs/xxhash.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0+ */ +#ifndef __EROFS_XXHASH_H +#define __EROFS_XXHASH_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdint.h> + +/** + * xxh32() - calculate the 32-bit hash of the input with a given seed. + * + * @input: The data to hash. + * @length: The length of the data to hash. + * @seed: The seed can be used to alter the result predictably. + * + * Return: The 32-bit hash of the data. + */ +uint32_t xxh32(const void *input, size_t length, uint32_t seed); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/erofs_fs.h b/include/erofs_fs.h index 8835a76..eba6c26 100644 --- a/include/erofs_fs.h +++ b/include/erofs_fs.h @@ -3,7 +3,7 @@ * EROFS (Enhanced ROM File System) on-disk format definition * * Copyright (C) 2017-2018 HUAWEI, Inc. - * http://www.huawei.com/ + * https://www.huawei.com/ * Copyright (C) 2021, Alibaba Cloud */ #ifndef __EROFS_FS_H @@ -12,40 +12,42 @@ #define EROFS_SUPER_MAGIC_V1 0xE0F5E1E2 #define EROFS_SUPER_OFFSET 1024 -#define EROFS_FEATURE_COMPAT_SB_CHKSUM 0x00000001 -#define EROFS_FEATURE_COMPAT_MTIME 0x00000002 +#define EROFS_FEATURE_COMPAT_SB_CHKSUM 0x00000001 +#define EROFS_FEATURE_COMPAT_MTIME 0x00000002 +#define EROFS_FEATURE_COMPAT_XATTR_FILTER 0x00000004 /* * Any bits that aren't in EROFS_ALL_FEATURE_INCOMPAT should * be incompatible with this kernel version. */ -#define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING 0x00000001 +#define EROFS_FEATURE_INCOMPAT_ZERO_PADDING 0x00000001 #define EROFS_FEATURE_INCOMPAT_COMPR_CFGS 0x00000002 #define EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER 0x00000002 #define EROFS_FEATURE_INCOMPAT_CHUNKED_FILE 0x00000004 #define EROFS_FEATURE_INCOMPAT_DEVICE_TABLE 0x00000008 +#define EROFS_FEATURE_INCOMPAT_COMPR_HEAD2 0x00000008 #define EROFS_FEATURE_INCOMPAT_ZTAILPACKING 0x00000010 #define EROFS_FEATURE_INCOMPAT_FRAGMENTS 0x00000020 #define EROFS_FEATURE_INCOMPAT_DEDUPE 0x00000020 +#define EROFS_FEATURE_INCOMPAT_XATTR_PREFIXES 0x00000040 #define EROFS_ALL_FEATURE_INCOMPAT \ - (EROFS_FEATURE_INCOMPAT_LZ4_0PADDING | \ + (EROFS_FEATURE_INCOMPAT_ZERO_PADDING | \ EROFS_FEATURE_INCOMPAT_COMPR_CFGS | \ EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER | \ EROFS_FEATURE_INCOMPAT_CHUNKED_FILE | \ EROFS_FEATURE_INCOMPAT_DEVICE_TABLE | \ + EROFS_FEATURE_INCOMPAT_COMPR_HEAD2 | \ EROFS_FEATURE_INCOMPAT_ZTAILPACKING | \ EROFS_FEATURE_INCOMPAT_FRAGMENTS | \ - EROFS_FEATURE_INCOMPAT_DEDUPE) + EROFS_FEATURE_INCOMPAT_DEDUPE | \ + EROFS_FEATURE_INCOMPAT_XATTR_PREFIXES) #define EROFS_SB_EXTSLOT_SIZE 16 struct erofs_deviceslot { - union { - u8 uuid[16]; /* used for device manager later */ - u8 userdata[64]; /* digest(sha256), etc. */ - } u; - __le32 blocks; /* total fs blocks of this device */ - __le32 mapped_blkaddr; /* map starting at mapped_blkaddr */ + u8 tag[64]; /* digest(sha256), etc. */ + __le32 blocks; /* total fs blocks of this device */ + __le32 mapped_blkaddr; /* map starting at mapped_blkaddr */ u8 reserved[56]; }; #define EROFS_DEVT_SLOT_SIZE sizeof(struct erofs_deviceslot) @@ -55,14 +57,14 @@ struct erofs_super_block { __le32 magic; /* file system magic number */ __le32 checksum; /* crc32c(super_block) */ __le32 feature_compat; - __u8 blkszbits; /* support block_size == PAGE_SIZE only */ + __u8 blkszbits; /* filesystem block size in bit shift */ __u8 sb_extslots; /* superblock size = 128 + sb_extslots * 16 */ __le16 root_nid; /* nid of root directory */ __le64 inos; /* total valid ino # (== f_files - f_favail) */ - __le64 build_time; /* inode v1 time derivation */ - __le32 build_time_nsec; /* inode v1 time derivation in nano scale */ + __le64 build_time; /* compact inode time derivation */ + __le32 build_time_nsec; /* compact inode time derivation in ns scale */ __le32 blocks; /* used for statfs */ __le32 meta_blkaddr; /* start block address of metadata area */ __le32 xattr_blkaddr; /* start block address of shared xattr area */ @@ -77,41 +79,39 @@ struct erofs_super_block { } __packed u1; __le16 extra_devices; /* # of devices besides the primary device */ __le16 devt_slotoff; /* startoff = devt_slotoff * devt_slotsize */ - __u8 reserved[6]; + __u8 dirblkbits; /* directory block size in bit shift */ + __u8 xattr_prefix_count; /* # of long xattr name prefixes */ + __le32 xattr_prefix_start; /* start of long xattr prefixes */ __le64 packed_nid; /* nid of the special packed inode */ - __u8 reserved2[24]; + __u8 xattr_filter_reserved; /* reserved for xattr name filter */ + __u8 reserved2[23]; }; /* - * erofs inode datalayout (i_format in on-disk inode): - * 0 - inode plain without inline data A: - * inode, [xattrs], ... | ... | no-holed data - * 1 - inode VLE compression B (legacy): - * inode, [xattrs], extents ... | ... - * 2 - inode plain with inline data C: - * inode, [xattrs], last_inline_data, ... | ... | no-holed data - * 3 - inode compression D: - * inode, [xattrs], map_header, extents ... | ... - * 4 - inode chunk-based E: - * inode, [xattrs], chunk indexes ... | ... + * EROFS inode datalayout (i_format in on-disk inode): + * 0 - uncompressed flat inode without tail-packing inline data: + * 1 - compressed inode with non-compact indexes: + * 2 - uncompressed flat inode with tail-packing inline data: + * 3 - compressed inode with compact indexes: + * 4 - chunk-based inode with (optional) multi-device support: * 5~7 - reserved */ enum { EROFS_INODE_FLAT_PLAIN = 0, - EROFS_INODE_FLAT_COMPRESSION_LEGACY = 1, + EROFS_INODE_COMPRESSED_FULL = 1, EROFS_INODE_FLAT_INLINE = 2, - EROFS_INODE_FLAT_COMPRESSION = 3, + EROFS_INODE_COMPRESSED_COMPACT = 3, EROFS_INODE_CHUNK_BASED = 4, EROFS_INODE_DATALAYOUT_MAX }; static inline bool erofs_inode_is_data_compressed(unsigned int datamode) { - return datamode == EROFS_INODE_FLAT_COMPRESSION || - datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY; + return datamode == EROFS_INODE_COMPRESSED_COMPACT || + datamode == EROFS_INODE_COMPRESSED_FULL; } -/* bit definitions of inode i_advise */ +/* bit definitions of inode i_format */ #define EROFS_I_VERSION_BITS 1 #define EROFS_I_DATALAYOUT_BITS 3 @@ -129,11 +129,30 @@ static inline bool erofs_inode_is_data_compressed(unsigned int datamode) #define EROFS_CHUNK_FORMAT_ALL \ (EROFS_CHUNK_FORMAT_BLKBITS_MASK | EROFS_CHUNK_FORMAT_INDEXES) +/* 32-byte on-disk inode */ +#define EROFS_INODE_LAYOUT_COMPACT 0 +/* 64-byte on-disk inode */ +#define EROFS_INODE_LAYOUT_EXTENDED 1 + struct erofs_inode_chunk_info { __le16 format; /* chunk blkbits, etc. */ __le16 reserved; }; +union erofs_inode_i_u { + /* total compressed blocks for compressed inodes */ + __le32 compressed_blocks; + + /* block address for uncompressed flat inodes */ + __le32 raw_blkaddr; + + /* for device files, used to indicate old/new device # */ + __le32 rdev; + + /* for chunk-based files, it contains the summary info */ + struct erofs_inode_chunk_info c; +}; + /* 32-byte reduced form of an ondisk inode */ struct erofs_inode_compact { __le16 i_format; /* inode format hints */ @@ -144,28 +163,14 @@ struct erofs_inode_compact { __le16 i_nlink; __le32 i_size; __le32 i_reserved; - union { - /* file total compressed blocks for data mapping 1 */ - __le32 compressed_blocks; - __le32 raw_blkaddr; + union erofs_inode_i_u i_u; - /* for device files, used to indicate old/new device # */ - __le32 rdev; - - /* for chunk-based files, it contains the summary info */ - struct erofs_inode_chunk_info c; - } i_u; - __le32 i_ino; /* only used for 32-bit stat compatibility */ + __le32 i_ino; /* only used for 32-bit stat compatibility */ __le16 i_uid; __le16 i_gid; __le32 i_reserved2; }; -/* 32 bytes on-disk inode */ -#define EROFS_INODE_LAYOUT_COMPACT 0 -/* 64 bytes on-disk inode */ -#define EROFS_INODE_LAYOUT_EXTENDED 1 - /* 64-byte complete form of an ondisk inode */ struct erofs_inode_extended { __le16 i_format; /* inode format hints */ @@ -175,21 +180,9 @@ struct erofs_inode_extended { __le16 i_mode; __le16 i_reserved; __le64 i_size; - union { - /* file total compressed blocks for data mapping 1 */ - __le32 compressed_blocks; - __le32 raw_blkaddr; - - /* for device files, used to indicate old/new device # */ - __le32 rdev; - - /* for chunk-based files, it contains the summary info */ - struct erofs_inode_chunk_info c; - } i_u; - - /* only used for 32-bit stat compatibility */ - __le32 i_ino; + union erofs_inode_i_u i_u; + __le32 i_ino; /* only used for 32-bit stat compatibility */ __le32 i_uid; __le32 i_gid; __le64 i_mtime; @@ -198,10 +191,6 @@ struct erofs_inode_extended { __u8 i_reserved2[16]; }; -#define EROFS_MAX_SHARED_XATTRS (128) -/* h_shared_count between 129 ... 255 are special # */ -#define EROFS_SHARED_XATTR_EXTENT (255) - /* * inline xattrs (n == i_xattr_icount): * erofs_xattr_ibody_header(1) + (n - 1) * 4 bytes @@ -214,7 +203,7 @@ struct erofs_inode_extended { * for read-only fs, no need to introduce h_refcount */ struct erofs_xattr_ibody_header { - __le32 h_reserved; + __le32 h_name_filter; /* bit value 1 indicates not-present */ __u8 h_shared_count; __u8 h_reserved2[7]; __le32 h_shared_xattrs[0]; /* shared xattr id array */ @@ -228,6 +217,17 @@ struct erofs_xattr_ibody_header { #define EROFS_XATTR_INDEX_LUSTRE 5 #define EROFS_XATTR_INDEX_SECURITY 6 +/* + * bit 7 of e_name_index is set when it refers to a long xattr name prefix, + * while the remained lower bits represent the index of the prefix. + */ +#define EROFS_XATTR_LONG_PREFIX 0x80 +#define EROFS_XATTR_LONG_PREFIX_MASK 0x7f + +#define EROFS_XATTR_FILTER_BITS 32 +#define EROFS_XATTR_FILTER_DEFAULT UINT32_MAX +#define EROFS_XATTR_FILTER_SEED 0x25BBE08F + /* xattr entry (for both inline & shared xattrs) */ struct erofs_xattr_entry { __u8 e_name_len; /* length of name */ @@ -237,6 +237,12 @@ struct erofs_xattr_entry { char e_name[0]; /* attribute name */ }; +/* long xattr name prefix */ +struct erofs_xattr_long_prefix { + __u8 base_index; /* short xattr name prefix index */ + char infix[0]; /* infix apart from short prefix */ +}; + static inline unsigned int erofs_xattr_ibody_size(__le16 i_xattr_icount) { if (!i_xattr_icount) @@ -267,6 +273,29 @@ struct erofs_inode_chunk_index { __le32 blkaddr; /* start block address of this inode chunk */ }; +/* dirent sorts in alphabet order, thus we can do binary search */ +struct erofs_dirent { + __le64 nid; /* node number */ + __le16 nameoff; /* start offset of file name */ + __u8 file_type; /* file type */ + __u8 reserved; /* reserved */ +} __packed; + +/* file types used in inode_info->flags */ +enum { + EROFS_FT_UNKNOWN, + EROFS_FT_REG_FILE, + EROFS_FT_DIR, + EROFS_FT_CHRDEV, + EROFS_FT_BLKDEV, + EROFS_FT_FIFO, + EROFS_FT_SOCK, + EROFS_FT_SYMLINK, + EROFS_FT_MAX +}; + +#define EROFS_NAME_LEN 255 + /* maximum supported size of a physical compression cluster */ #define Z_EROFS_PCLUSTER_MAX_SIZE (1024 * 1024) @@ -274,9 +303,10 @@ struct erofs_inode_chunk_index { enum { Z_EROFS_COMPRESSION_LZ4 = 0, Z_EROFS_COMPRESSION_LZMA = 1, + Z_EROFS_COMPRESSION_DEFLATE = 2, Z_EROFS_COMPRESSION_MAX }; -#define Z_EROFS_ALL_COMPR_ALGS (1 << (Z_EROFS_COMPRESSION_MAX - 1)) +#define Z_EROFS_ALL_COMPR_ALGS ((1 << Z_EROFS_COMPRESSION_MAX) - 1) /* 14 bytes (+ length field = 16 bytes) */ struct z_erofs_lz4_cfgs { @@ -291,8 +321,15 @@ struct z_erofs_lzma_cfgs { __le16 format; u8 reserved[8]; } __packed; + #define Z_EROFS_LZMA_MAX_DICT_SIZE (8 * Z_EROFS_PCLUSTER_MAX_SIZE) +/* 6 bytes (+ length field = 8 bytes) */ +struct z_erofs_deflate_cfgs { + u8 windowbits; /* 8..15 for DEFLATE */ + u8 reserved[5]; +} __packed; + /* * bit 0 : COMPACTED_2B indexes (0 - off; 1 - on) * e.g. for 4k logical cluster size, 4B if compacted 2B is off; @@ -310,15 +347,15 @@ struct z_erofs_lzma_cfgs { #define Z_EROFS_ADVISE_INTERLACED_PCLUSTER 0x0010 #define Z_EROFS_ADVISE_FRAGMENT_PCLUSTER 0x0020 -#define Z_EROFS_FRAGMENT_INODE_BIT 7 +#define Z_EROFS_FRAGMENT_INODE_BIT 7 struct z_erofs_map_header { union { /* fragment data offset in the packed inode */ - __le32 h_fragmentoff; + __le32 h_fragmentoff; struct { __le16 h_reserved1; /* indicates the encoded size of tailpacking data */ - __le16 h_idata_size; + __le16 h_idata_size; }; }; __le16 h_advise; @@ -335,105 +372,81 @@ struct z_erofs_map_header { __u8 h_clusterbits; }; -#define Z_EROFS_VLE_LEGACY_HEADER_PADDING 8 - /* - * Fixed-sized output compression ondisk Logical Extent cluster type: - * 0 - literal (uncompressed) cluster - * 1 - compressed cluster (for the head logical cluster) - * 2 - compressed cluster (for the other logical clusters) + * On-disk logical cluster type: + * 0 - literal (uncompressed) lcluster + * 1,3 - compressed lcluster (for HEAD lclusters) + * 2 - compressed lcluster (for NONHEAD lclusters) * * In detail, - * 0 - literal (uncompressed) cluster, + * 0 - literal (uncompressed) lcluster, * di_advise = 0 - * di_clusterofs = the literal data offset of the cluster - * di_blkaddr = the blkaddr of the literal cluster + * di_clusterofs = the literal data offset of the lcluster + * di_blkaddr = the blkaddr of the literal pcluster * - * 1 - compressed cluster (for the head logical cluster) - * di_advise = 1 - * di_clusterofs = the decompressed data offset of the cluster - * di_blkaddr = the blkaddr of the compressed cluster + * 1,3 - compressed lcluster (for HEAD lclusters) + * di_advise = 1 or 3 + * di_clusterofs = the decompressed data offset of the lcluster + * di_blkaddr = the blkaddr of the compressed pcluster * - * 2 - compressed cluster (for the other logical clusters) + * 2 - compressed lcluster (for NONHEAD lclusters) * di_advise = 2 * di_clusterofs = - * the decompressed data offset in its own head cluster - * di_u.delta[0] = distance to its corresponding head cluster - * di_u.delta[1] = distance to its corresponding tail cluster - * (di_advise could be 0, 1 or 2) + * the decompressed data offset in its own HEAD lcluster + * di_u.delta[0] = distance to this HEAD lcluster + * di_u.delta[1] = distance to the next HEAD lcluster */ enum { - Z_EROFS_VLE_CLUSTER_TYPE_PLAIN = 0, - Z_EROFS_VLE_CLUSTER_TYPE_HEAD = 1, - Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD = 2, - Z_EROFS_VLE_CLUSTER_TYPE_RESERVED = 3, - Z_EROFS_VLE_CLUSTER_TYPE_MAX + Z_EROFS_LCLUSTER_TYPE_PLAIN = 0, + Z_EROFS_LCLUSTER_TYPE_HEAD1 = 1, + Z_EROFS_LCLUSTER_TYPE_NONHEAD = 2, + Z_EROFS_LCLUSTER_TYPE_HEAD2 = 3, + Z_EROFS_LCLUSTER_TYPE_MAX }; -#define Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS 2 -#define Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT 0 +#define Z_EROFS_LI_LCLUSTER_TYPE_BITS 2 +#define Z_EROFS_LI_LCLUSTER_TYPE_BIT 0 /* (noncompact only, HEAD) This pcluster refers to partial decompressed data */ -#define Z_EROFS_VLE_DI_PARTIAL_REF (1 << 15) +#define Z_EROFS_LI_PARTIAL_REF (1 << 15) /* * D0_CBLKCNT will be marked _only_ at the 1st non-head lcluster to store the * compressed block count of a compressed extent (in logical clusters, aka. * block count of a pcluster). */ -#define Z_EROFS_VLE_DI_D0_CBLKCNT (1 << 11) +#define Z_EROFS_LI_D0_CBLKCNT (1 << 11) -struct z_erofs_vle_decompressed_index { +struct z_erofs_lcluster_index { __le16 di_advise; - /* where to decompress in the head cluster */ + /* where to decompress in the head lcluster */ __le16 di_clusterofs; union { - /* for the head cluster */ + /* for the HEAD lclusters */ __le32 blkaddr; /* - * for the rest clusters - * eg. for 4k page-sized cluster, maximum 4K*64k = 256M) - * [0] - pointing to the head cluster - * [1] - pointing to the tail cluster + * for the NONHEAD lclusters + * [0] - distance to its HEAD lcluster + * [1] - distance to the next HEAD lcluster */ __le16 delta[2]; } di_u; }; -#define Z_EROFS_VLE_LEGACY_INDEX_ALIGN(size) \ - (round_up(size, sizeof(struct z_erofs_vle_decompressed_index)) + \ - sizeof(struct z_erofs_map_header) + Z_EROFS_VLE_LEGACY_HEADER_PADDING) - -#define Z_EROFS_VLE_EXTENT_ALIGN(size) round_up(size, \ - sizeof(struct z_erofs_vle_decompressed_index)) - -/* dirent sorts in alphabet order, thus we can do binary search */ -struct erofs_dirent { - __le64 nid; /* node number */ - __le16 nameoff; /* start offset of file name */ - __u8 file_type; /* file type */ - __u8 reserved; /* reserved */ -} __packed; - -/* file types used in inode_info->flags */ -enum { - EROFS_FT_UNKNOWN, - EROFS_FT_REG_FILE, - EROFS_FT_DIR, - EROFS_FT_CHRDEV, - EROFS_FT_BLKDEV, - EROFS_FT_FIFO, - EROFS_FT_SOCK, - EROFS_FT_SYMLINK, - EROFS_FT_MAX -}; - -#define EROFS_NAME_LEN 255 +#define Z_EROFS_FULL_INDEX_ALIGN(end) \ + (round_up(end, 8) + sizeof(struct z_erofs_map_header) + 8) /* check the EROFS on-disk layout strictly at compile time */ static inline void erofs_check_ondisk_layout_definitions(void) { + const union { + struct z_erofs_map_header h; + __le64 v; + } fmh __maybe_unused = { + .h.h_clusterbits = 1 << Z_EROFS_FRAGMENT_INODE_BIT, + }; + BUILD_BUG_ON(sizeof(struct erofs_super_block) != 128); BUILD_BUG_ON(sizeof(struct erofs_inode_compact) != 32); BUILD_BUG_ON(sizeof(struct erofs_inode_extended) != 64); @@ -442,15 +455,18 @@ static inline void erofs_check_ondisk_layout_definitions(void) BUILD_BUG_ON(sizeof(struct erofs_inode_chunk_info) != 4); BUILD_BUG_ON(sizeof(struct erofs_inode_chunk_index) != 8); BUILD_BUG_ON(sizeof(struct z_erofs_map_header) != 8); - BUILD_BUG_ON(sizeof(struct z_erofs_vle_decompressed_index) != 8); + BUILD_BUG_ON(sizeof(struct z_erofs_lcluster_index) != 8); BUILD_BUG_ON(sizeof(struct erofs_dirent) != 12); /* keep in sync between 2 index structures for better extendibility */ BUILD_BUG_ON(sizeof(struct erofs_inode_chunk_index) != - sizeof(struct z_erofs_vle_decompressed_index)); + sizeof(struct z_erofs_lcluster_index)); BUILD_BUG_ON(sizeof(struct erofs_deviceslot) != 128); - BUILD_BUG_ON(BIT(Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS) < - Z_EROFS_VLE_CLUSTER_TYPE_MAX - 1); + BUILD_BUG_ON(BIT(Z_EROFS_LI_LCLUSTER_TYPE_BITS) < + Z_EROFS_LCLUSTER_TYPE_MAX - 1); + /* exclude old compiler versions like gcc 7.5.0 */ + BUILD_BUG_ON(__builtin_constant_p(fmh.v) ? + fmh.v != cpu_to_le64(1ULL << 63) : 0); } #endif |