X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lib%2Fext2fs%2Fext2fs.h;h=d842c339cc4396e20b939eb4be6e048e2cddcad7;hb=1ef93745227af455da045cdf4a48ec1ae38c518c;hp=a7b6116015c9028553fc21ac5f30487f61effaa5;hpb=be31a8de5a37b481d1aa44e52653575f08eeb288;p=tools%2Fe2fsprogs.git diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index a7b6116..d842c33 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -18,6 +18,12 @@ #define EXT2FS_ATTR(x) #endif +#ifdef CONFIG_TDB +#define EXT2FS_NO_TDB_UNUSED +#else +#define EXT2FS_NO_TDB_UNUSED EXT2FS_ATTR((unused)) +#endif + #ifdef __cplusplus extern "C" { #endif @@ -39,6 +45,8 @@ extern "C" { #define SUPERBLOCK_OFFSET 1024 #define SUPERBLOCK_SIZE 1024 +#define UUID_STR_SIZE 37 + /* * The last ext2fs revision level that this version of the library is * able to support. @@ -52,6 +60,7 @@ extern "C" { #include #include #include +#include #include #if EXT2_FLAT_INCLUDES @@ -64,18 +73,12 @@ extern "C" { #include #endif /* EXT2_FLAT_INCLUDES */ -#ifdef __CHECK_ENDIAN__ -#define __bitwise __attribute__((bitwise)) -#else -#define __bitwise -#endif - typedef __u32 __bitwise ext2_ino_t; typedef __u32 __bitwise blk_t; typedef __u64 __bitwise blk64_t; typedef __u32 __bitwise dgrp_t; -typedef __u32 __bitwise ext2_off_t; -typedef __u64 __bitwise ext2_off64_t; +typedef __s32 __bitwise ext2_off_t; +typedef __s64 __bitwise ext2_off64_t; typedef __s64 __bitwise e2_blkcnt_t; typedef __u32 __bitwise ext2_dirhash_t; @@ -91,6 +94,8 @@ typedef __u32 __bitwise ext2_dirhash_t; #include #endif +#include "hashmap.h" + /* * Portability help for Microsoft Visual C++ */ @@ -106,9 +111,14 @@ typedef struct struct_ext2_filsys *ext2_filsys; #define EXT2FS_UNMARK_ERROR 1 #define EXT2FS_TEST_ERROR 2 -typedef struct ext2fs_struct_generic_bitmap *ext2fs_generic_bitmap; -typedef struct ext2fs_struct_generic_bitmap *ext2fs_inode_bitmap; -typedef struct ext2fs_struct_generic_bitmap *ext2fs_block_bitmap; +struct ext2fs_struct_generic_bitmap_base { + errcode_t magic; + ext2_filsys fs; +}; + +typedef struct ext2fs_struct_generic_bitmap_base *ext2fs_generic_bitmap; +typedef struct ext2fs_struct_generic_bitmap_base *ext2fs_inode_bitmap; +typedef struct ext2fs_struct_generic_bitmap_base *ext2fs_block_bitmap; #define EXT2_FIRST_INODE(s) EXT2_FIRST_INO(s) @@ -192,6 +202,11 @@ typedef struct ext2_file *ext2_file_t; #define EXT2_FLAG_DIRECT_IO 0x80000 #define EXT2_FLAG_SKIP_MMP 0x100000 #define EXT2_FLAG_IGNORE_CSUM_ERRORS 0x200000 +#define EXT2_FLAG_SHARE_DUP 0x400000 +#define EXT2_FLAG_IGNORE_SB_ERRORS 0x800000 +#define EXT2_FLAG_BBITMAP_TAIL_PROBLEM 0x1000000 +#define EXT2_FLAG_IBITMAP_TAIL_PROBLEM 0x2000000 +#define EXT2_FLAG_THREADS 0x4000000 /* * Special flag in the ext2 inode i_flag field that means that this is @@ -206,6 +221,13 @@ typedef struct ext2_file *ext2_file_t; #define EXT2_MKJOURNAL_LAZYINIT 0x0000002 /* don't zero journal inode before use*/ #define EXT2_MKJOURNAL_NO_MNT_CHECK 0x0000004 /* don't check mount status */ +/* + * Normal journal area size to fast commit area size ratio. This is used to + * set default size of fast commit area. + */ +#define EXT2_JOURNAL_TO_FC_BLKS_RATIO 64 + +struct blk_alloc_ctx; struct opaque_ext2_group_desc; struct struct_ext2_filsys { @@ -239,7 +261,7 @@ struct struct_ext2_filsys { time_t now; int cluster_ratio_bits; __u16 default_bitmap_type; - __u16 pad; + __u16 fs_num_threads; /* * Reserved for future expansion */ @@ -261,6 +283,8 @@ struct struct_ext2_filsys { */ errcode_t (*get_alloc_block)(ext2_filsys fs, blk64_t goal, blk64_t *ret); + errcode_t (*get_alloc_block2)(ext2_filsys fs, blk64_t goal, + blk64_t *ret, struct blk_alloc_ctx *ctx); void (*block_alloc_stats)(ext2_filsys fs, blk64_t blk, int inuse); /* @@ -280,6 +304,20 @@ struct struct_ext2_filsys { /* Precomputed FS UUID checksum for seeding other checksums */ __u32 csum_seed; + + io_channel journal_io; + char *journal_name; + + /* New block range allocation hooks */ + errcode_t (*new_range)(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, blk64_t *pblk, blk64_t *plen); + void (*block_alloc_stats_range)(ext2_filsys fs, blk64_t blk, blk_t num, + int inuse); + + /* hashmap for SHA of data blocks */ + struct ext2fs_hashmap* block_sha_map; + + const struct ext2fs_nls_table *encoding; }; #if EXT2_FLAT_INCLUDES @@ -314,7 +352,7 @@ struct struct_ext2_filsys { * * BLOCK_FLAG_DEPTH_TRAVERSE indicates that the iterator function for * the indirect, doubly indirect, etc. blocks should be called after - * all of the blocks containined in the indirect blocks are processed. + * all of the blocks contained in the indirect blocks are processed. * This is useful if you are going to be deallocating blocks from an * inode. * @@ -343,6 +381,17 @@ struct struct_ext2_filsys { #define BLOCK_COUNT_TIND (-3) #define BLOCK_COUNT_TRANSLATOR (-4) +#define BLOCK_ALLOC_UNKNOWN 0 +#define BLOCK_ALLOC_DATA 1 +#define BLOCK_ALLOC_METADATA 2 + +struct blk_alloc_ctx { + ext2_ino_t ino; + struct ext2_inode *inode; + blk64_t lblk; + int flags; +}; + #if 0 /* * Flags for ext2fs_move_blocks @@ -397,7 +446,7 @@ typedef struct ext2_extent_path *ext2_extent_path_t; /* * Flags used by ext2fs_extent_delete() */ -#define EXT2_EXTENT_DELETE_KEEP_EMPTY 0x001 /* keep node if last extnt gone */ +#define EXT2_EXTENT_DELETE_KEEP_EMPTY 0x001 /* keep node if last extent gone */ /* * Flags used by ext2fs_extent_set_bmap() @@ -460,6 +509,7 @@ typedef struct ext2_struct_inode_scan *ext2_inode_scan; #define EXT2_SF_BAD_EXTRA_BYTES 0x0004 #define EXT2_SF_SKIP_MISSING_ITABLE 0x0008 #define EXT2_SF_DO_LAZY 0x0010 +#define EXT2_SF_WARN_GARBAGE_INODES 0x0020 /* * ext2fs_check_if_mounted flags @@ -519,6 +569,7 @@ typedef struct ext2_struct_inode_scan *ext2_inode_scan; * ext2_icount_t abstraction */ #define EXT2_ICOUNT_OPT_INCREMENT 0x01 +#define EXT2_ICOUNT_OPT_FULLMAP 0x02 typedef struct ext2_icount *ext2_icount_t; @@ -527,6 +578,8 @@ typedef struct ext2_icount *ext2_icount_t; */ #define BMAP_ALLOC 0x0001 #define BMAP_SET 0x0002 +#define BMAP_UNINIT 0x0004 +#define BMAP_ZERO 0x0008 /* * Returned flags from ext2fs_bmap @@ -534,6 +587,16 @@ typedef struct ext2_icount *ext2_icount_t; #define BMAP_RET_UNINIT 0x0001 /* + * Flags for ext2fs_read_inode2 + */ +#define READ_INODE_NOCSUM 0x0001 + +/* + * Flags for ext2fs_write_inode2 + */ +#define WRITE_INODE_NOCSUM 0x0001 + +/* * Flags for imager.c functions */ #define IMAGER_FLAG_INODEMAP 1 @@ -546,12 +609,12 @@ typedef struct ext2_icount *ext2_icount_t; #define EXT2_CHECK_MAGIC(struct, code) \ if ((struct)->magic != (code)) return (code) - /* - * For ext2 compression support + * Flags for returning status of ext2fs_expand_extra_isize() */ -#define EXT2FS_COMPRESSED_BLKADDR ((blk_t) -1) -#define HOLE_BLKADDR(_b) ((_b) == 0 || (_b) == EXT2FS_COMPRESSED_BLKADDR) +#define EXT2_EXPAND_EISIZE_UNSAFE 0x0001 +#define EXT2_EXPAND_EISIZE_NEW_BLOCK 0x0002 +#define EXT2_EXPAND_EISIZE_NOSPC 0x0004 /* * Features supported by this version of the library @@ -562,20 +625,9 @@ typedef struct ext2_icount *ext2_icount_t; EXT2_FEATURE_COMPAT_RESIZE_INODE|\ EXT2_FEATURE_COMPAT_DIR_INDEX|\ EXT2_FEATURE_COMPAT_EXT_ATTR|\ - EXT4_FEATURE_COMPAT_SPARSE_SUPER2) - -/* This #ifdef is temporary until compression is fully supported */ -#ifdef ENABLE_COMPRESSION -#ifndef I_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL -/* If the below warning bugs you, then have - `CPPFLAGS=-DI_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL' in your - environment at configure time. */ - #warning "Compression support is experimental" -#endif -#define EXT2_LIB_INCOMPAT_COMPRESSION EXT2_FEATURE_INCOMPAT_COMPRESSION -#else -#define EXT2_LIB_INCOMPAT_COMPRESSION (0) -#endif + EXT4_FEATURE_COMPAT_SPARSE_SUPER2|\ + EXT4_FEATURE_COMPAT_FAST_COMMIT|\ + EXT4_FEATURE_COMPAT_STABLE_INODES) #ifdef CONFIG_MMP #define EXT4_LIB_INCOMPAT_MMP EXT4_FEATURE_INCOMPAT_MMP @@ -583,22 +635,21 @@ typedef struct ext2_icount *ext2_icount_t; #define EXT4_LIB_INCOMPAT_MMP (0) #endif -#ifdef CONFIG_QUOTA -#define EXT4_LIB_RO_COMPAT_QUOTA EXT4_FEATURE_RO_COMPAT_QUOTA -#else -#define EXT4_LIB_RO_COMPAT_QUOTA (0) -#endif - #define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\ - EXT2_LIB_INCOMPAT_COMPRESSION|\ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\ EXT2_FEATURE_INCOMPAT_META_BG|\ EXT3_FEATURE_INCOMPAT_RECOVER|\ EXT3_FEATURE_INCOMPAT_EXTENTS|\ EXT4_FEATURE_INCOMPAT_FLEX_BG|\ + EXT4_FEATURE_INCOMPAT_EA_INODE|\ + EXT4_FEATURE_INCOMPAT_DIRDATA|\ EXT4_LIB_INCOMPAT_MMP|\ EXT4_FEATURE_INCOMPAT_64BIT|\ - EXT4_FEATURE_INCOMPAT_INLINE_DATA) + EXT4_FEATURE_INCOMPAT_INLINE_DATA|\ + EXT4_FEATURE_INCOMPAT_ENCRYPT|\ + EXT4_FEATURE_INCOMPAT_CASEFOLD|\ + EXT4_FEATURE_INCOMPAT_CSUM_SEED|\ + EXT4_FEATURE_INCOMPAT_LARGEDIR) #define EXT2_LIB_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\ EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\ @@ -607,14 +658,18 @@ typedef struct ext2_icount *ext2_icount_t; EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|\ EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\ EXT4_FEATURE_RO_COMPAT_BIGALLOC|\ - EXT4_LIB_RO_COMPAT_QUOTA|\ - EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) + EXT4_FEATURE_RO_COMPAT_QUOTA|\ + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\ + EXT4_FEATURE_RO_COMPAT_READONLY |\ + EXT4_FEATURE_RO_COMPAT_PROJECT |\ + EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS |\ + EXT4_FEATURE_RO_COMPAT_VERITY) /* * These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed * to ext2fs_openfs() */ -#define EXT2_LIB_SOFTSUPP_INCOMPAT (EXT4_FEATURE_INCOMPAT_INLINE_DATA) +#define EXT2_LIB_SOFTSUPP_INCOMPAT (0) #define EXT2_LIB_SOFTSUPP_RO_COMPAT (EXT4_FEATURE_RO_COMPAT_REPLICA) @@ -648,13 +703,20 @@ struct ext2_xattr_handle; #define XATTR_CHANGED 2 /* + * flags for ext2fs_rw_bitmaps() + */ +#define EXT2FS_BITMAPS_WRITE 0x0001 +#define EXT2FS_BITMAPS_BLOCK 0x0002 +#define EXT2FS_BITMAPS_INODE 0x0004 +#define EXT2FS_BITMAPS_VALID_FLAGS 0x0007 + +/* * function prototypes */ static inline int ext2fs_has_group_desc_csum(ext2_filsys fs) { - return EXT2_HAS_RO_COMPAT_FEATURE(fs->super, - EXT4_FEATURE_RO_COMPAT_GDT_CSUM | - EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); + return ext2fs_has_feature_metadata_csum(fs->super) || + ext2fs_has_feature_gdt_csum(fs->super); } /* The LARGE_FILE feature should be set if we have stored files 2GB+ in size */ @@ -664,12 +726,16 @@ static inline int ext2fs_needs_large_file_feature(unsigned long long file_size) } /* alloc.c */ +extern void ext2fs_clear_block_uninit(ext2_filsys fs, dgrp_t group); extern errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, int mode, ext2fs_inode_bitmap map, ext2_ino_t *ret); extern errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal, ext2fs_block_bitmap map, blk_t *ret); extern errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal, ext2fs_block_bitmap map, blk64_t *ret); +extern errcode_t ext2fs_new_block3(ext2_filsys fs, blk64_t goal, + ext2fs_block_bitmap map, blk64_t *ret, + struct blk_alloc_ctx *ctx); extern errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish, int num, ext2fs_block_bitmap map, @@ -682,6 +748,10 @@ extern errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal, char *block_buf, blk_t *ret); extern errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal, char *block_buf, blk64_t *ret); +extern errcode_t ext2fs_alloc_block3(ext2_filsys fs, blk64_t goal, + char *block_buf, blk64_t *ret, + struct blk_alloc_ctx *ctx); + extern void ext2fs_set_alloc_block_callback(ext2_filsys fs, errcode_t (*func)(ext2_filsys fs, blk64_t goal, @@ -689,6 +759,29 @@ extern void ext2fs_set_alloc_block_callback(ext2_filsys fs, errcode_t (**old)(ext2_filsys fs, blk64_t goal, blk64_t *ret)); +blk64_t ext2fs_find_inode_goal(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, blk64_t lblk); +extern void ext2fs_set_new_range_callback(ext2_filsys fs, + errcode_t (*func)(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, blk64_t *pblk, blk64_t *plen), + errcode_t (**old)(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, blk64_t *pblk, blk64_t *plen)); +extern void ext2fs_set_block_alloc_stats_range_callback(ext2_filsys fs, + void (*func)(ext2_filsys fs, blk64_t blk, + blk_t num, int inuse), + void (**old)(ext2_filsys fs, blk64_t blk, + blk_t num, int inuse)); +#define EXT2_NEWRANGE_FIXED_GOAL (0x1) +#define EXT2_NEWRANGE_MIN_LENGTH (0x2) +#define EXT2_NEWRANGE_ALL_FLAGS (0x3) +errcode_t ext2fs_new_range(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, ext2fs_block_bitmap map, blk64_t *pblk, + blk64_t *plen); +#define EXT2_ALLOCRANGE_FIXED_GOAL (0x1) +#define EXT2_ALLOCRANGE_ZERO_BLOCKS (0x2) +#define EXT2_ALLOCRANGE_ALL_FLAGS (0x3) +errcode_t ext2fs_alloc_range(ext2_filsys fs, int flags, blk64_t goal, + blk_t len, blk64_t *ret); /* alloc_sb.c */ extern int ext2fs_reserve_super_and_bgd(ext2_filsys fs, @@ -744,6 +837,8 @@ extern int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, extern void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter); extern errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src, ext2_badblocks_list *dest); +extern errcode_t ext2fs_badblocks_merge(ext2_badblocks_list src, + ext2_badblocks_list dest); extern int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2); extern int ext2fs_u32_list_count(ext2_u32_list bb); @@ -767,10 +862,10 @@ extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap); extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap); extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src, ext2fs_generic_bitmap *dest); -extern errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs); -extern errcode_t ext2fs_write_block_bitmap (ext2_filsys fs); -extern errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs); -extern errcode_t ext2fs_read_block_bitmap(ext2_filsys fs); +errcode_t ext2fs_merge_bitmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap dest, + ext2fs_generic_bitmap dup, + ext2fs_generic_bitmap dup_allowed); extern errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs, const char *descr, ext2fs_block_bitmap *ret); @@ -789,8 +884,6 @@ extern errcode_t ext2fs_fudge_block_bitmap_end2(ext2fs_block_bitmap bitmap, blk64_t end, blk64_t *oend); extern void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap); extern void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap); -extern errcode_t ext2fs_read_bitmaps(ext2_filsys fs); -extern errcode_t ext2fs_write_bitmaps(ext2_filsys fs); extern errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end, ext2fs_inode_bitmap bmap); extern errcode_t ext2fs_resize_inode_bitmap2(__u64 new_end, @@ -840,7 +933,9 @@ extern int ext2fs_group_blocks_count(ext2_filsys fs, dgrp_t group); extern blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs, struct ext2_inode *inode); extern blk64_t ext2fs_inode_i_blocks(ext2_filsys fs, - struct ext2_inode *inode); + struct ext2_inode *inode); +extern blk64_t ext2fs_get_stat_i_blocks(ext2_filsys fs, + struct ext2_inode *inode); extern blk64_t ext2fs_blocks_count(struct ext2_super_block *super); extern void ext2fs_blocks_count_set(struct ext2_super_block *super, blk64_t blk); @@ -894,6 +989,8 @@ extern blk64_t ext2fs_file_acl_block(ext2_filsys fs, const struct ext2_inode *inode); extern void ext2fs_file_acl_block_set(ext2_filsys fs, struct ext2_inode *inode, blk64_t blk); +extern errcode_t ext2fs_inode_size_set(ext2_filsys fs, struct ext2_inode *inode, + ext2_off64_t size); /* block.c */ extern errcode_t ext2fs_block_iterate(ext2_filsys fs, @@ -955,6 +1052,7 @@ extern errcode_t ext2fs_check_desc(ext2_filsys fs); /* closefs.c */ extern errcode_t ext2fs_close(ext2_filsys fs); extern errcode_t ext2fs_close2(ext2_filsys fs, int flags); +extern errcode_t ext2fs_close_free(ext2_filsys *fs); extern errcode_t ext2fs_flush(ext2_filsys fs); extern errcode_t ext2fs_flush2(ext2_filsys fs, int flags); extern int ext2fs_bg_has_super(ext2_filsys fs, dgrp_t group_block); @@ -977,6 +1075,7 @@ extern __u32 ext2fs_crc32_be(__u32 crc, unsigned char const *p, size_t len); extern __u32 ext2fs_crc32c_le(__u32 crc, unsigned char const *p, size_t len); /* csum.c */ +extern void ext2fs_init_csum_seed(ext2_filsys fs); extern errcode_t ext2fs_mmp_csum_set(ext2_filsys fs, struct mmp_struct *mmp); extern int ext2fs_mmp_csum_verify(ext2_filsys, struct mmp_struct *mmp); extern int ext2fs_verify_csum_type(ext2_filsys fs, struct ext2_super_block *sb); @@ -1008,6 +1107,9 @@ extern errcode_t ext2fs_get_dx_countlimit(ext2_filsys fs, struct ext2_dir_entry *dirent, struct ext2_dx_countlimit **cc, int *offset); +extern errcode_t ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent, + __u32 *crc, struct ext2_dx_tail **ret_t); extern errcode_t ext2fs_extent_block_csum_set(ext2_filsys fs, ext2_ino_t inum, struct ext3_extent_header *eh); @@ -1037,6 +1139,7 @@ extern errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk, int blockcnt); extern errcode_t ext2fs_add_dir_block2(ext2_dblist dblist, ext2_ino_t ino, blk64_t blk, e2_blkcnt_t blockcnt); +extern errcode_t ext2fs_merge_dblist(ext2_dblist src, ext2_dblist dest); extern void ext2fs_dblist_sort(ext2_dblist dblist, EXT2_QSORT_TYPE (*sortfunc)(const void *, const void *)); @@ -1046,11 +1149,17 @@ extern void ext2fs_dblist_sort2(ext2_dblist dblist, extern errcode_t ext2fs_dblist_iterate(ext2_dblist dblist, int (*func)(ext2_filsys fs, struct ext2_db_entry *db_info, void *priv_data), - void *priv_data); + void *priv_data); extern errcode_t ext2fs_dblist_iterate2(ext2_dblist dblist, int (*func)(ext2_filsys fs, struct ext2_db_entry2 *db_info, void *priv_data), - void *priv_data); + void *priv_data); +extern errcode_t ext2fs_dblist_iterate3(ext2_dblist dblist, + int (*func)(ext2_filsys fs, struct ext2_db_entry2 *db_info, + void *priv_data), + unsigned long long start, + unsigned long long count, + void *priv_data); extern errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk, int blockcnt); extern errcode_t ext2fs_set_dir_block2(ext2_dblist dblist, ext2_ino_t ino, @@ -1079,6 +1188,13 @@ extern errcode_t void *priv_data), void *priv_data); +#if 0 +/* digest_encode.c */ +#define EXT2FS_DIGEST_SIZE EXT2FS_SHA256_LENGTH +extern int ext2fs_digest_encode(const char *src, int len, char *dst); +extern int ext2fs_digest_decode(const char *src, int len, char *dst); +#endif + /* dirblock.c */ extern errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block, void *buf); @@ -1103,6 +1219,12 @@ extern errcode_t ext2fs_dirhash(int version, const char *name, int len, ext2_dirhash_t *ret_hash, ext2_dirhash_t *ret_minor_hash); +extern errcode_t ext2fs_dirhash2(int version, const char *name, int len, + const struct ext2fs_nls_table *charset, + int hash_flags, + const __u32 *seed, + ext2_dirhash_t *ret_hash, + ext2_dirhash_t *ret_minor_hash); /* dir_iterate.c */ extern errcode_t ext2fs_get_rec_len(ext2_filsys fs, @@ -1141,8 +1263,25 @@ extern errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest); extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir); /* ext_attr.c */ +extern errcode_t ext2fs_attr_get(ext2_filsys fs, struct ext2_inode *inode, + int name_index, const char *name, char *buffer, + size_t buffer_size, int *easize); + extern __u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, void *data); +extern errcode_t ext2fs_ext_attr_hash_entry2(ext2_filsys fs, + struct ext2_ext_attr_entry *entry, + void *data, __u32 *hash); +int ext2fs_attr_get_next_attr(struct ext2_ext_attr_entry *entry, int name_index, + char *buffer, int buffer_size, int start); +errcode_t ext2fs_attr_set(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + int name_index, const char *name, const char *value, + int value_len, int flags); +extern errcode_t ext2fs_expand_extra_isize(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode_large *inode, + int new_extra_isize, int *ret, + int *needed_size); extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf); extern errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block, void *buf); @@ -1168,7 +1307,8 @@ errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle); errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle); errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h, int (*func)(char *name, char *value, - size_t value_len, void *data), + size_t value_len, + ext2_ino_t inode_num, void *data), void *data); errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key, void **value, size_t *value_len); @@ -1183,9 +1323,18 @@ errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino, errcode_t ext2fs_xattrs_close(struct ext2_xattr_handle **handle); errcode_t ext2fs_free_ext_attr(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode_large *inode); -size_t ext2fs_xattrs_count(struct ext2_xattr_handle *handle); +errcode_t ext2fs_xattrs_count(struct ext2_xattr_handle *handle, size_t *count); errcode_t ext2fs_xattr_inode_max_size(ext2_filsys fs, ext2_ino_t ino, size_t *size); +#define XATTR_HANDLE_FLAG_RAW 0x0001 +errcode_t ext2fs_xattrs_flags(struct ext2_xattr_handle *handle, + unsigned int *new_flags, unsigned int *old_flags); +extern void ext2fs_ext_attr_block_rehash(struct ext2_ext_attr_header *header, + struct ext2_ext_attr_entry *end); +extern __u32 ext2fs_get_ea_inode_hash(struct ext2_inode *inode); +extern void ext2fs_set_ea_inode_hash(struct ext2_inode *inode, __u32 hash); +extern __u64 ext2fs_get_ea_inode_ref(struct ext2_inode *inode); +extern void ext2fs_set_ea_inode_ref(struct ext2_inode *inode, __u64 ref_count); /* extent.c */ extern errcode_t ext2fs_extent_header_verify(void *ptr, int size); @@ -1213,6 +1362,23 @@ extern errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle, extern errcode_t ext2fs_extent_goto2(ext2_extent_handle_t handle, int leaf_level, blk64_t blk); extern errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle); +extern size_t ext2fs_max_extent_depth(ext2_extent_handle_t handle); +extern errcode_t ext2fs_fix_extents_checksums(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode); +extern errcode_t ext2fs_count_blocks(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, blk64_t *ret_count); +extern errcode_t ext2fs_decode_extent(struct ext2fs_extent *to, void *from, + int len); + +/* fallocate.c */ +#define EXT2_FALLOCATE_ZERO_BLOCKS (0x1) +#define EXT2_FALLOCATE_FORCE_INIT (0x2) +#define EXT2_FALLOCATE_FORCE_UNINIT (0x4) +#define EXT2_FALLOCATE_INIT_BEYOND_EOF (0x8) +#define EXT2_FALLOCATE_ALL_FLAGS (0xF) +errcode_t ext2fs_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino, + struct ext2_inode *inode, blk64_t goal, + blk64_t start, blk64_t len); /* fileio.c */ extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino, @@ -1310,6 +1476,10 @@ void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap); errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap, __u64 new_end, __u64 new_real_end); +errcode_t ext2fs_merge_generic_bmap(ext2fs_generic_bitmap gen_src, + ext2fs_generic_bitmap gen_dest, + ext2fs_generic_bitmap gen_dup, + ext2fs_generic_bitmap dup_allowed); errcode_t ext2fs_compare_generic_bmap(errcode_t neq, ext2fs_generic_bitmap bm1, ext2fs_generic_bitmap bm2); @@ -1321,6 +1491,8 @@ errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap, void *in); errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs, ext2fs_block_bitmap *bitmap); +errcode_t ext2fs_count_used_clusters(ext2_filsys fs, blk64_t start, + blk64_t end, blk64_t *out); /* get_num_dirs.c */ extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs); @@ -1359,9 +1531,11 @@ errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf); extern errcode_t ext2fs_initialize(const char *name, int flags, struct ext2_super_block *param, io_manager manager, ext2_filsys *ret_fs); +extern errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs, int super_only); /* icount.c */ extern void ext2fs_free_icount(ext2_icount_t icount); +extern int ext2fs_icount_is_set(ext2_icount_t icount, ext2_ino_t ino); extern errcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir, int flags, ext2_icount_t *ret); extern errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, @@ -1378,6 +1552,7 @@ extern errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret); extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino, __u16 count); +extern errcode_t ext2fs_icount_merge(ext2_icount_t src, ext2_icount_t dest); extern ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount); errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *); @@ -1386,6 +1561,17 @@ errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *); extern errcode_t ext2fs_get_memalign(unsigned long size, unsigned long align, void *ptr); +/* inline_data.c */ +extern errcode_t ext2fs_inline_data_init(ext2_filsys fs, ext2_ino_t ino); +extern errcode_t ext2fs_inline_data_size(ext2_filsys fs, ext2_ino_t ino, + size_t *size); +extern errcode_t ext2fs_inline_data_get(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + void *buf, size_t *size); +extern errcode_t ext2fs_inline_data_set(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + void *buf, size_t size); + /* inode.c */ extern errcode_t ext2fs_create_inode_cache(ext2_filsys fs, unsigned int cache_size); @@ -1395,6 +1581,7 @@ extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino, struct ext2_inode *inode, int bufsize); +#define EXT2_INODE_SCAN_DEFAULT_BUFFER_BLOCKS 8 extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks, ext2_inode_scan *ret_scan); extern void ext2fs_close_inode_scan(ext2_inode_scan scan); @@ -1414,13 +1601,19 @@ extern int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags, extern errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode * inode, int bufsize); -extern errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino, +extern errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode * inode); +extern errcode_t ext2fs_read_inode2(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode, + int bufsize, int flags); extern errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode * inode, int bufsize); extern errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode * inode); +extern errcode_t ext2fs_write_inode2(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode, + int bufsize, int flags); extern errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode * inode); extern errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks); @@ -1468,11 +1661,25 @@ extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino, extern errcode_t ext2fs_new_dir_inline_data(ext2_filsys fs, ext2_ino_t dir_ino, ext2_ino_t parent_ino, __u32 *iblock); +/* nls_utf8.c */ +extern const struct ext2fs_nls_table *ext2fs_load_nls_table(int encoding); +extern int ext2fs_check_encoded_name(const struct ext2fs_nls_table *table, + char *s, size_t len, char **pos); +extern int ext2fs_casefold_cmp(const struct ext2fs_nls_table *table, + const unsigned char *str1, size_t len1, + const unsigned char *str2, size_t len2); + /* mkdir.c */ extern errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, const char *name); /* mkjournal.c */ +struct ext2fs_journal_params { + blk_t num_journal_blocks; + blk_t num_fc_blocks; +}; +extern errcode_t ext2fs_get_journal_params( + struct ext2fs_journal_params *params, ext2_filsys fs); extern errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num, blk_t *ret_blk, int *ret_count); extern errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num, @@ -1480,13 +1687,20 @@ extern errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num, extern errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, __u32 num_blocks, int flags, char **ret_jsb); +extern errcode_t ext2fs_create_journal_superblock2(ext2_filsys fs, + struct ext2fs_journal_params *params, + int flags, char **ret_jsb); extern errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev); extern errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, int flags); extern errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks, blk64_t goal, int flags); +extern errcode_t ext2fs_add_journal_inode3(ext2_filsys fs, + struct ext2fs_journal_params *params, + blk64_t goal, int flags); extern int ext2fs_default_journal_size(__u64 num_blocks); +extern int ext2fs_journal_sb_start(int blocksize); /* openfs.c */ extern errcode_t ext2fs_open(const char *name, int flags, int superblock, @@ -1496,6 +1710,9 @@ extern errcode_t ext2fs_open2(const char *name, const char *io_options, int flags, int superblock, unsigned int block_size, io_manager manager, ext2_filsys *ret_fs); +errcode_t ext2fs_open_channel(ext2_filsys fs, const char *io_options, + io_manager manager, int flags, + int blocksize); /* * The dgrp_t argument to these two functions is not actually a group number * but a block number offset within a group table! Convert with the formula @@ -1514,6 +1731,10 @@ extern errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t char **name); /* link.c */ +#define EXT2FS_UNLINK_FORCE 0x1 /* Forcefully unlink even if + * the inode number doesn't + * match the dirent + */ errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name, ext2_ino_t ino, int flags); errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, const char *name, @@ -1521,7 +1742,8 @@ errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, const char *name, /* symlink.c */ errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, - const char *name, char *target); + const char *name, const char *target); +int ext2fs_is_fast_symlink(struct ext2_inode *inode); /* mmp.c */ errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf); @@ -1554,6 +1776,27 @@ extern errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f, /* res_gdt.c */ extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs); +/* rw_bitmaps.c */ +extern errcode_t ext2fs_rw_bitmaps(ext2_filsys fs, int flags, int num_threads); +extern errcode_t ext2fs_read_bitmaps(ext2_filsys fs); +extern errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs); +extern errcode_t ext2fs_read_block_bitmap(ext2_filsys fs); +extern errcode_t ext2fs_write_bitmaps(ext2_filsys fs); +extern errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs); +extern errcode_t ext2fs_write_block_bitmap (ext2_filsys fs); + +/*sha256.c */ +#define EXT2FS_SHA256_LENGTH 32 +#if 0 +extern void ext2fs_sha256(const unsigned char *in, unsigned long in_size, + unsigned char out[EXT2FS_SHA256_LENGTH]); +#endif + +/* sha512.c */ +#define EXT2FS_SHA512_LENGTH 64 +extern void ext2fs_sha512(const unsigned char *in, unsigned long in_size, + unsigned char out[EXT2FS_SHA512_LENGTH]); + /* swapfs.c */ extern errcode_t ext2fs_dirent_swab_in2(ext2_filsys fs, char *buf, size_t size, int flags); @@ -1600,7 +1843,6 @@ extern errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list, /* inline functions */ #ifdef NO_INLINE_FUNCS -extern void ext2fs_init_csum_seed(ext2_filsys fs); extern errcode_t ext2fs_get_mem(unsigned long size, void *ptr); extern errcode_t ext2fs_get_memzero(unsigned long size, void *ptr); extern errcode_t ext2fs_get_array(unsigned long count, @@ -1610,6 +1852,8 @@ extern errcode_t ext2fs_get_arrayzero(unsigned long count, extern errcode_t ext2fs_free_mem(void *ptr); extern errcode_t ext2fs_resize_mem(unsigned long old_size, unsigned long size, void *ptr); +extern errcode_t ext2fs_resize_array(unsigned long old_count, unsigned long count, + unsigned long size, void *ptr); extern void ext2fs_mark_super_dirty(ext2_filsys fs); extern void ext2fs_mark_changed(ext2_filsys fs); extern int ext2fs_test_changed(ext2_filsys fs); @@ -1626,8 +1870,16 @@ extern blk_t ext2fs_group_first_block(ext2_filsys fs, dgrp_t group); extern blk_t ext2fs_group_last_block(ext2_filsys fs, dgrp_t group); extern blk_t ext2fs_inode_data_blocks(ext2_filsys fs, struct ext2_inode *inode); +extern int ext2fs_htree_intnode_maxrecs(ext2_filsys fs, int blocks); extern unsigned int ext2fs_div_ceil(unsigned int a, unsigned int b); extern __u64 ext2fs_div64_ceil(__u64 a, __u64 b); +extern int ext2fs_dirent_name_len(const struct ext2_dir_entry *entry); +extern void ext2fs_dirent_set_name_len(struct ext2_dir_entry *entry, int len); +extern int ext2fs_dirent_file_type(const struct ext2_dir_entry *entry); +extern void ext2fs_dirent_set_file_type(struct ext2_dir_entry *entry, int type); +extern struct ext2_inode *ext2fs_inode(struct ext2_inode_large * large_inode); +extern const struct ext2_inode *ext2fs_const_inode(const struct ext2_inode_large * large_inode); + #endif /* @@ -1651,16 +1903,6 @@ extern __u64 ext2fs_div64_ceil(__u64 a, __u64 b); #endif /* __STDC_VERSION__ >= 199901L */ #endif -_INLINE_ void ext2fs_init_csum_seed(ext2_filsys fs) -{ - if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, - EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) - return; - - fs->csum_seed = ext2fs_crc32c_le(~0, fs->super->s_uuid, - sizeof(fs->super->s_uuid)); -} - #ifndef EXT2_CUSTOM_MEMORY_ROUTINES #include /* @@ -1689,9 +1931,10 @@ _INLINE_ errcode_t ext2fs_get_memzero(unsigned long size, void *ptr) return 0; } -_INLINE_ errcode_t ext2fs_get_array(unsigned long count, unsigned long size, void *ptr) +_INLINE_ errcode_t ext2fs_get_array(unsigned long count, unsigned long size, + void *ptr) { - if (count && (-1UL)/count old_size) { + void *p; + + memcpy(&p, ptr, sizeof(p)); + memset((char *)p + old_size, 0, size - old_size); + memcpy(ptr, &p, sizeof(p)); + } + + return 0; +} #endif /* Custom memory routines */ /* @@ -1860,6 +2128,36 @@ _INLINE_ blk_t ext2fs_inode_data_blocks(ext2_filsys fs, return (blk_t) ext2fs_inode_data_blocks2(fs, inode); } +_INLINE_ int ext2fs_htree_intnode_maxrecs(ext2_filsys fs, int blocks) +{ + int csum_size = 0; + + if ((EXT2_SB(fs->super)->s_feature_ro_compat & + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) != 0) + csum_size = sizeof(struct ext2_dx_tail); + return blocks * ((fs->blocksize - (8 + csum_size)) / + sizeof(struct ext2_dx_entry)); +} + +_INLINE_ struct ext2_dx_root_info *get_ext2_dx_root_info(ext2_filsys fs, + char *buf) +{ + struct ext2_dir_entry *de = (struct ext2_dir_entry *)buf; + + if (!(fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_DIRDATA)) + return (struct ext2_dx_root_info *)(buf + + EXT2_DIR_NAME_LEN(1) + + EXT2_DIR_NAME_LEN(2)); + + /* get dotdot first */ + de = (struct ext2_dir_entry *)((char *)de + de->rec_len); + + /* dx root info is after dotdot entry */ + de = (struct ext2_dir_entry *)((char *)de + EXT2_DIR_REC_LEN(de)); + + return (struct ext2_dx_root_info *)de; +} + /* * This is an efficient, overflow safe way of calculating ceil((1.0 * a) / b) */ @@ -1879,7 +2177,7 @@ _INLINE_ __u64 ext2fs_div64_ceil(__u64 a, __u64 b) _INLINE_ int ext2fs_dirent_name_len(const struct ext2_dir_entry *entry) { - return entry->name_len & 0xff; + return entry->name_len & EXT2_NAME_LEN; } _INLINE_ void ext2fs_dirent_set_name_len(struct ext2_dir_entry *entry, int len) @@ -1897,9 +2195,63 @@ _INLINE_ void ext2fs_dirent_set_file_type(struct ext2_dir_entry *entry, int type entry->name_len = (entry->name_len & 0xff) | (type << 8); } +_INLINE_ struct ext2_inode *ext2fs_inode(struct ext2_inode_large * large_inode) +{ + /* It is always safe to convert large inode to a small inode */ + return (struct ext2_inode *) large_inode; +} + +_INLINE_ const struct ext2_inode * +ext2fs_const_inode(const struct ext2_inode_large * large_inode) +{ + /* It is always safe to convert large inode to a small inode */ + return (const struct ext2_inode *) large_inode; +} + +static dgrp_t ext2fs_get_avg_group(ext2_filsys fs) +{ +#ifdef HAVE_PTHREAD + dgrp_t average_group; + unsigned flexbg_size; + + if (fs->fs_num_threads <= 1) + return fs->group_desc_count; + + average_group = fs->group_desc_count / fs->fs_num_threads; + if (average_group <= 1) + return 1; + + if (ext2fs_has_feature_flex_bg(fs->super)) { + int times = 1; + + flexbg_size = 1 << fs->super->s_log_groups_per_flex; + if (average_group % flexbg_size) { + times = average_group / flexbg_size; + average_group = times * flexbg_size; + } + } + + return average_group; +#else + return fs->group_desc_count; +#endif +} + #undef _INLINE_ #endif +/* htree levels for ext4 */ +#define EXT4_HTREE_LEVEL_COMPAT 2 +#define EXT4_HTREE_LEVEL 3 + +static inline unsigned int ext2_dir_htree_level(ext2_filsys fs) +{ + if (ext2fs_has_feature_largedir(fs->super)) + return EXT4_HTREE_LEVEL; + + return EXT4_HTREE_LEVEL_COMPAT; +} + #ifdef __cplusplus } #endif