├── .gitignore ├── dkms.conf ├── CONTRIBUTING ├── Makefile ├── message.c ├── file.c ├── apfs.h ├── unicode.h ├── dir.h ├── extents.h ├── message.h ├── object.c ├── xattr.h ├── symlink.c ├── btree.h ├── namei.c ├── object.h ├── README ├── inode.h ├── node.h ├── extents.c ├── key.h ├── dir.c ├── key.c ├── btree.c ├── super.h ├── xattr.c ├── inode.c ├── node.c ├── LICENSE └── super.c /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.swp 3 | *.d 4 | *.o 5 | *.symvers 6 | *.mod.c 7 | *.order 8 | *.ko 9 | tags 10 | -------------------------------------------------------------------------------- /dkms.conf: -------------------------------------------------------------------------------- 1 | PACKAGE_NAME="linux-apfs" 2 | PACKAGE_VERSION="0.1" 3 | 4 | BUILT_MODULE_NAME[0]="apfs" 5 | DEST_MODULE_LOCATION[0]="/extra" 6 | 7 | AUTOINSTALL="yes" 8 | -------------------------------------------------------------------------------- /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | 2 | If you want to help with development, please submit your patches for review to 3 | the project's mailing list at . We try to follow 4 | the style guidelines of the Linux kernel. 5 | 6 | I don't own any Apple devices, so testing is needed and very appreciated. Bug 7 | reports should be sent to the mailing list as well. 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # 3 | # Makefile for the out-of-tree Linux APFS module. 4 | # 5 | 6 | KERNELRELEASE ?= $(shell uname -r) 7 | KERNEL_DIR ?= /lib/modules/$(KERNELRELEASE)/build 8 | 9 | obj-m = apfs.o 10 | apfs-y = btree.o dir.o extents.o file.o inode.o key.o message.o \ 11 | namei.o node.o object.o super.o symlink.o unicode.o xattr.o 12 | 13 | default: 14 | make -C $(KERNEL_DIR) M=$(shell pwd) 15 | clean: 16 | make -C $(KERNEL_DIR) M=$(shell pwd) clean 17 | -------------------------------------------------------------------------------- /message.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * linux/fs/apfs/message.c 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #include 9 | #include "message.h" 10 | 11 | void apfs_msg(struct super_block *sb, const char *prefix, const char *fmt, ...) 12 | { 13 | struct va_format vaf; 14 | va_list args; 15 | 16 | va_start(args, fmt); 17 | 18 | vaf.fmt = fmt; 19 | vaf.va = &args; 20 | 21 | printk("%sAPFS (%s): %pV\n", prefix, sb->s_id, &vaf); 22 | 23 | va_end(args); 24 | } 25 | -------------------------------------------------------------------------------- /file.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * linux/fs/apfs/file.c 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #include "apfs.h" 9 | #include "inode.h" 10 | #include "xattr.h" 11 | 12 | const struct file_operations apfs_file_operations = { 13 | .llseek = generic_file_llseek, 14 | .read_iter = generic_file_read_iter, 15 | .mmap = generic_file_readonly_mmap, 16 | .open = generic_file_open, 17 | }; 18 | 19 | const struct inode_operations apfs_file_inode_operations = { 20 | .getattr = apfs_getattr, 21 | .listxattr = apfs_listxattr, 22 | }; 23 | -------------------------------------------------------------------------------- /apfs.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * linux/fs/apfs/apfs.h 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #ifndef _APFS_H 9 | #define _APFS_H 10 | 11 | #define EFSBADCRC EBADMSG /* Bad CRC detected */ 12 | #define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ 13 | 14 | /* 15 | * Inode and file operations 16 | */ 17 | 18 | /* file.c */ 19 | extern const struct file_operations apfs_file_operations; 20 | extern const struct inode_operations apfs_file_inode_operations; 21 | 22 | /* namei.c */ 23 | extern const struct inode_operations apfs_dir_inode_operations; 24 | extern const struct inode_operations apfs_special_inode_operations; 25 | extern const struct dentry_operations apfs_dentry_operations; 26 | 27 | /* symlink.c */ 28 | extern const struct inode_operations apfs_symlink_inode_operations; 29 | 30 | #endif /* _APFS_H */ 31 | -------------------------------------------------------------------------------- /unicode.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * linux/fs/apfs/unicode.h 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #ifndef _APFS_UNICODE_H 9 | #define _APFS_UNICODE_H 10 | 11 | #include 12 | 13 | /* 14 | * This structure helps apfs_normalize_next() to retrieve one normalized 15 | * (and case-folded) UTF-32 character at a time from a UTF-8 string. 16 | */ 17 | struct apfs_unicursor { 18 | const char *utf8curr; /* Start of UTF-8 to decompose and reorder */ 19 | int length; /* Length of normalization until next starter */ 20 | int last_pos; /* Offset in substring of last char returned */ 21 | u8 last_ccc; /* CCC of the last character returned */ 22 | }; 23 | 24 | extern void apfs_init_unicursor(struct apfs_unicursor *cursor, 25 | const char *utf8str); 26 | extern unicode_t apfs_normalize_next(struct apfs_unicursor *cursor, 27 | bool case_fold); 28 | 29 | #endif /* _APFS_UNICODE_H */ 30 | -------------------------------------------------------------------------------- /dir.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * linux/fs/apfs/dir.h 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #ifndef _APFS_DIR_H 9 | #define _APFS_DIR_H 10 | 11 | #include 12 | 13 | struct inode; 14 | struct qstr; 15 | struct apfs_query; 16 | 17 | /* 18 | * Structure of the value of a directory entry. This is the data in 19 | * the catalog nodes for record type APFS_TYPE_DIR_REC. 20 | */ 21 | struct apfs_drec_val { 22 | __le64 file_id; 23 | __le64 date_added; 24 | __le16 flags; 25 | u8 xfields[]; 26 | } __packed; 27 | 28 | /* 29 | * Directory entry record in memory 30 | */ 31 | struct apfs_drec { 32 | u8 *name; 33 | u64 ino; 34 | int name_len; 35 | unsigned int type; 36 | }; 37 | 38 | extern int apfs_drec_from_query(struct apfs_query *query, 39 | struct apfs_drec *drec); 40 | extern int apfs_inode_by_name(struct inode *dir, const struct qstr *child, 41 | u64 *ino); 42 | 43 | extern const struct file_operations apfs_dir_operations; 44 | 45 | #endif /* _APFS_DIR_H */ 46 | -------------------------------------------------------------------------------- /extents.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * linux/fs/apfs/extents.h 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #ifndef _EXTENTS_H 9 | #define _EXTENTS_H 10 | 11 | #include 12 | 13 | struct inode; 14 | struct buffer_head; 15 | struct apfs_query; 16 | 17 | /* File extent records */ 18 | #define APFS_FILE_EXTENT_LEN_MASK 0x00ffffffffffffffULL 19 | #define APFS_FILE_EXTENT_FLAG_MASK 0xff00000000000000ULL 20 | #define APFS_FILE_EXTENT_FLAG_SHIFT 56 21 | 22 | /* 23 | * Structure of a file extent record 24 | */ 25 | struct apfs_file_extent_val { 26 | __le64 len_and_flags; 27 | __le64 phys_block_num; 28 | __le64 crypto_id; 29 | } __packed; 30 | 31 | /* 32 | * Extent record data in memory 33 | */ 34 | struct apfs_file_extent { 35 | u64 logical_addr; 36 | u64 phys_block_num; 37 | u64 len; 38 | }; 39 | 40 | extern int apfs_extent_from_query(struct apfs_query *query, 41 | struct apfs_file_extent *extent); 42 | extern int apfs_get_block(struct inode *inode, sector_t iblock, 43 | struct buffer_head *bh_result, int create); 44 | 45 | #endif /* _EXTENTS_H */ 46 | -------------------------------------------------------------------------------- /message.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * linux/fs/apfs/message.h 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #ifndef _APFS_MESSAGE_H 9 | #define _APFS_MESSAGE_H 10 | 11 | struct super_block; 12 | 13 | extern __printf(3, 4) 14 | void apfs_msg(struct super_block *sb, const char *prefix, const char *fmt, ...); 15 | 16 | #define apfs_emerg(sb, fmt, ...) apfs_msg(sb, KERN_EMERG, fmt, ##__VA_ARGS__) 17 | #define apfs_alert(sb, fmt, ...) apfs_msg(sb, KERN_ALERT, fmt, ##__VA_ARGS__) 18 | #define apfs_crit(sb, fmt, ...) apfs_msg(sb, KERN_CRIT, fmt, ##__VA_ARGS__) 19 | #define apfs_err(sb, fmt, ...) apfs_msg(sb, KERN_ERR, fmt, ##__VA_ARGS__) 20 | #define apfs_warn(sb, fmt, ...) apfs_msg(sb, KERN_WARNING, fmt, ##__VA_ARGS__) 21 | #define apfs_notice(sb, fmt, ...) apfs_msg(sb, KERN_NOTICE, fmt, ##__VA_ARGS__) 22 | #define apfs_info(sb, fmt, ...) apfs_msg(sb, KERN_INFO, fmt, ##__VA_ARGS__) 23 | 24 | #ifdef CONFIG_APFS_DEBUG 25 | #define apfs_debug(sb, fmt, ...) apfs_msg(sb, KERN_DEBUG, fmt, ##__VA_ARGS__) 26 | #else 27 | #define apfs_debug(sb, fmt, ...) no_printk(fmt, ##__VA_ARGS__) 28 | #endif 29 | 30 | #endif /* _APFS_MESSAGE_H */ 31 | -------------------------------------------------------------------------------- /object.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * linux/fs/apfs/object.c 4 | * 5 | * Checksum routines for an APFS object 6 | */ 7 | 8 | #include 9 | #include "object.h" 10 | 11 | /* 12 | * Note that this is not a generic implementation of fletcher64, as it assumes 13 | * a message length that doesn't overflow sum1 and sum2. This constraint is ok 14 | * for apfs, though, since the block size is limited to 2^16. For a more 15 | * generic optimized implementation, see Nakassis (1988). 16 | */ 17 | static u64 apfs_fletcher64(void *addr, size_t len) 18 | { 19 | __le32 *buff = addr; 20 | u64 sum1 = 0; 21 | u64 sum2 = 0; 22 | u64 c1, c2; 23 | int i; 24 | 25 | for (i = 0; i < len/sizeof(u32); i++) { 26 | sum1 += le32_to_cpu(buff[i]); 27 | sum2 += sum1; 28 | } 29 | 30 | c1 = sum1 + sum2; 31 | c1 = 0xFFFFFFFF - do_div(c1, 0xFFFFFFFF); 32 | c2 = sum1 + c1; 33 | c2 = 0xFFFFFFFF - do_div(c2, 0xFFFFFFFF); 34 | 35 | return (c2 << 32) | c1; 36 | } 37 | 38 | int apfs_obj_verify_csum(struct super_block *sb, struct apfs_obj_phys *obj) 39 | { 40 | return (le64_to_cpu(obj->o_cksum) == 41 | apfs_fletcher64((char *) obj + APFS_MAX_CKSUM_SIZE, 42 | sb->s_blocksize - APFS_MAX_CKSUM_SIZE)); 43 | } 44 | -------------------------------------------------------------------------------- /xattr.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * linux/fs/apfs/xattr.h 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #ifndef _APFS_XATTR_H 9 | #define _APFS_XATTR_H 10 | 11 | #include 12 | #include "inode.h" 13 | 14 | /* Extended attributes constants */ 15 | #define APFS_XATTR_MAX_EMBEDDED_SIZE 3804 16 | 17 | /* Extended attributes names */ 18 | #define APFS_XATTR_NAME_SYMLINK "com.apple.fs.symlink" 19 | #define APFS_XATTR_NAME_COMPRESSED "com.apple.decmpfs" 20 | 21 | /* Extended attributes flags */ 22 | enum { 23 | APFS_XATTR_DATA_STREAM = 0x00000001, 24 | APFS_XATTR_DATA_EMBEDDED = 0x00000002, 25 | APFS_XATTR_FILE_SYSTEM_OWNED = 0x00000004, 26 | APFS_XATTR_RESERVED_8 = 0x00000008, 27 | }; 28 | 29 | /* 30 | * Structure of the value of an extended attributes record 31 | */ 32 | struct apfs_xattr_val { 33 | __le16 flags; 34 | __le16 xdata_len; 35 | u8 xdata[0]; 36 | } __packed; 37 | 38 | /* 39 | * Structure used to store the data of an extended attributes record 40 | */ 41 | struct apfs_xattr_dstream { 42 | __le64 xattr_obj_id; 43 | struct apfs_dstream dstream; 44 | } __packed; 45 | 46 | /* 47 | * Xattr record data in memory 48 | */ 49 | struct apfs_xattr { 50 | u8 *name; 51 | u8 *xdata; 52 | int name_len; 53 | int xdata_len; 54 | bool has_dstream; 55 | }; 56 | 57 | extern int apfs_xattr_get(struct inode *inode, const char *name, void *buffer, 58 | size_t size); 59 | extern ssize_t apfs_listxattr(struct dentry *dentry, char *buffer, size_t size); 60 | 61 | extern const struct xattr_handler *apfs_xattr_handlers[]; 62 | 63 | #endif /* _APFS_XATTR_H */ 64 | -------------------------------------------------------------------------------- /symlink.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * linux/fs/apfs/symlink.c 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #include 9 | #include 10 | #include "apfs.h" 11 | #include "message.h" 12 | #include "xattr.h" 13 | 14 | /** 15 | * apfs_get_link - Follow a symbolic link 16 | * @dentry: dentry for the link 17 | * @inode: inode for the link 18 | * @done: delayed call to free the returned buffer after use 19 | * 20 | * Returns a pointer to a buffer containing the target path, or an appropriate 21 | * error pointer in case of failure. 22 | */ 23 | static const char *apfs_get_link(struct dentry *dentry, struct inode *inode, 24 | struct delayed_call *done) 25 | { 26 | struct super_block *sb = inode->i_sb; 27 | char *target, *err; 28 | int size; 29 | 30 | if (!dentry) 31 | return ERR_PTR(-ECHILD); 32 | 33 | size = apfs_xattr_get(inode, APFS_XATTR_NAME_SYMLINK, 34 | NULL /* buffer */, 0 /* size */); 35 | if (size < 0) /* TODO: return a better error code */ 36 | return ERR_PTR(size); 37 | 38 | target = kmalloc(size, GFP_KERNEL); 39 | if (!target) 40 | return ERR_PTR(-ENOMEM); 41 | 42 | size = apfs_xattr_get(inode, APFS_XATTR_NAME_SYMLINK, target, size); 43 | if (size < 0) { 44 | err = ERR_PTR(size); 45 | goto fail; 46 | } 47 | if (size == 0 || *(target + size - 1) != 0) { 48 | /* Target path must be NULL-terminated */ 49 | apfs_alert(sb, "bad link target in inode 0x%llx", 50 | (unsigned long long) inode->i_ino); 51 | err = ERR_PTR(-EFSCORRUPTED); 52 | goto fail; 53 | } 54 | 55 | set_delayed_call(done, kfree_link, target); 56 | return target; 57 | 58 | fail: 59 | kfree(target); 60 | return err; 61 | } 62 | 63 | const struct inode_operations apfs_symlink_inode_operations = { 64 | .get_link = apfs_get_link, 65 | .getattr = apfs_getattr, 66 | .listxattr = apfs_listxattr, 67 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) /* Now this is the default */ 68 | .readlink = generic_readlink, 69 | #endif 70 | }; 71 | -------------------------------------------------------------------------------- /btree.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * linux/fs/apfs/btree.h 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #ifndef _APFS_BTREE_H 9 | #define _APFS_BTREE_H 10 | 11 | #include 12 | 13 | struct super_block; 14 | 15 | /* Flags for the query structure */ 16 | #define APFS_QUERY_TREE_MASK 0007 /* Which b-tree we query */ 17 | #define APFS_QUERY_OMAP 0001 /* This is a b-tree object map query */ 18 | #define APFS_QUERY_CAT 0002 /* This is a catalog tree query */ 19 | #define APFS_QUERY_NEXT 0010 /* Find next of multiple matches */ 20 | #define APFS_QUERY_EXACT 0020 /* Search for an exact match */ 21 | #define APFS_QUERY_DONE 0040 /* The search at this level is over */ 22 | #define APFS_QUERY_ANY_NAME 0100 /* Multiple search for any name */ 23 | #define APFS_QUERY_ANY_NUMBER 0200 /* Multiple search for any number */ 24 | #define APFS_QUERY_MULTIPLE (APFS_QUERY_ANY_NAME | APFS_QUERY_ANY_NUMBER) 25 | 26 | /* 27 | * Structure used to retrieve data from an APFS B-Tree. For now only used 28 | * on the calalog and the object map. 29 | */ 30 | struct apfs_query { 31 | struct apfs_node *node; /* Node being searched */ 32 | struct apfs_key *key; /* What the query is looking for */ 33 | 34 | struct apfs_query *parent; /* Query for parent node */ 35 | unsigned int flags; 36 | 37 | /* Set by the query on success */ 38 | int index; /* Index of the entry in the node */ 39 | int key_off; /* Offset of the key in the node */ 40 | int key_len; /* Length of the key */ 41 | int off; /* Offset of the data in the node */ 42 | int len; /* Length of the data */ 43 | 44 | int depth; /* Put a limit on recursion */ 45 | }; 46 | 47 | extern struct apfs_query *apfs_alloc_query(struct apfs_node *node, 48 | struct apfs_query *parent); 49 | extern void apfs_free_query(struct super_block *sb, struct apfs_query *query); 50 | extern int apfs_btree_query(struct super_block *sb, struct apfs_query **query); 51 | extern struct apfs_node *apfs_omap_read_node(struct super_block *sb, u64 id); 52 | extern int apfs_omap_lookup_block(struct super_block *sb, 53 | struct apfs_node *tbl, u64 id, u64 *block); 54 | 55 | #endif /* _APFS_BTREE_H */ 56 | -------------------------------------------------------------------------------- /namei.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * linux/fs/apfs/namei.c 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #include "apfs.h" 9 | #include "dir.h" 10 | #include "inode.h" 11 | #include "key.h" 12 | #include "super.h" 13 | #include "unicode.h" 14 | #include "xattr.h" 15 | 16 | static struct dentry *apfs_lookup(struct inode *dir, struct dentry *dentry, 17 | unsigned int flags) 18 | { 19 | struct inode *inode = NULL; 20 | u64 ino = 0; 21 | int err; 22 | 23 | if (dentry->d_name.len > APFS_NAME_LEN) 24 | return ERR_PTR(-ENAMETOOLONG); 25 | 26 | err = apfs_inode_by_name(dir, &dentry->d_name, &ino); 27 | if (err && err != -ENODATA) 28 | return ERR_PTR(err); 29 | 30 | if (!err) { 31 | inode = apfs_iget(dir->i_sb, ino); 32 | if (IS_ERR(inode)) 33 | return ERR_CAST(inode); 34 | } 35 | 36 | return d_splice_alias(inode, dentry); 37 | } 38 | 39 | const struct inode_operations apfs_dir_inode_operations = { 40 | .lookup = apfs_lookup, 41 | .getattr = apfs_getattr, 42 | .listxattr = apfs_listxattr, 43 | }; 44 | 45 | const struct inode_operations apfs_special_inode_operations = { 46 | .getattr = apfs_getattr, 47 | .listxattr = apfs_listxattr, 48 | }; 49 | 50 | static int apfs_dentry_hash(const struct dentry *dir, struct qstr *child) 51 | { 52 | struct apfs_unicursor cursor; 53 | unsigned long hash; 54 | bool case_fold = apfs_is_case_insensitive(dir->d_sb); 55 | 56 | apfs_init_unicursor(&cursor, child->name); 57 | hash = init_name_hash(dir); 58 | 59 | while (1) { 60 | int i; 61 | unicode_t utf32; 62 | 63 | utf32 = apfs_normalize_next(&cursor, case_fold); 64 | if (!utf32) 65 | break; 66 | 67 | /* Hash the unicode character one byte at a time */ 68 | for (i = 0; i < 4; ++i) { 69 | hash = partial_name_hash((u8)utf32, hash); 70 | utf32 = utf32 >> 8; 71 | } 72 | } 73 | child->hash = end_name_hash(hash); 74 | 75 | /* TODO: return error instead of truncating invalid UTF-8? */ 76 | return 0; 77 | } 78 | 79 | static int apfs_dentry_compare(const struct dentry *dentry, unsigned int len, 80 | const char *str, const struct qstr *name) 81 | { 82 | return apfs_filename_cmp(dentry->d_sb, name->name, str); 83 | } 84 | 85 | const struct dentry_operations apfs_dentry_operations = { 86 | .d_hash = apfs_dentry_hash, 87 | .d_compare = apfs_dentry_compare, 88 | }; 89 | -------------------------------------------------------------------------------- /object.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * linux/fs/apfs/object.h 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #ifndef _APFS_OBJECT_H 9 | #define _APFS_OBJECT_H 10 | 11 | #include 12 | 13 | /* Object identifiers constants */ 14 | #define APFS_OID_NX_SUPERBLOCK 1 15 | #define APFS_OID_INVALID 0ULL 16 | #define APFS_OID_RESERVED_COUNT 1024 17 | 18 | /* Object type masks */ 19 | #define APFS_OBJECT_TYPE_MASK 0x0000ffff 20 | #define APFS_OBJECT_TYPE_FLAGS_MASK 0xffff0000 21 | #define APFS_OBJ_STORAGETYPE_MASK 0xc0000000 22 | #define APFS_OBJECT_TYPE_FLAGS_DEFINED_MASK 0xf8000000 23 | 24 | /* Object types */ 25 | #define APFS_OBJECT_TYPE_NX_SUPERBLOCK 0x00000001 26 | #define APFS_OBJECT_TYPE_BTREE 0x00000002 27 | #define APFS_OBJECT_TYPE_BTREE_NODE 0x00000003 28 | #define APFS_OBJECT_TYPE_SPACEMAN 0x00000005 29 | #define APFS_OBJECT_TYPE_SPACEMAN_CAB 0x00000006 30 | #define APFS_OBJECT_TYPE_SPACEMAN_CIB 0x00000007 31 | #define APFS_OBJECT_TYPE_SPACEMAN_BITMAP 0x00000008 32 | #define APFS_OBJECT_TYPE_SPACEMAN_FREE_QUEUE 0x00000009 33 | #define APFS_OBJECT_TYPE_EXTENT_LIST_TREE 0x0000000a 34 | #define APFS_OBJECT_TYPE_OMAP 0x0000000b 35 | #define APFS_OBJECT_TYPE_CHECKPOINT_MAP 0x0000000c 36 | #define APFS_OBJECT_TYPE_FS 0x0000000d 37 | #define APFS_OBJECT_TYPE_FSTREE 0x0000000e 38 | #define APFS_OBJECT_TYPE_BLOCKREFTREE 0x0000000f 39 | #define APFS_OBJECT_TYPE_SNAPMETATREE 0x00000010 40 | #define APFS_OBJECT_TYPE_NX_REAPER 0x00000011 41 | #define APFS_OBJECT_TYPE_NX_REAP_LIST 0x00000012 42 | #define APFS_OBJECT_TYPE_OMAP_SNAPSHOT 0x00000013 43 | #define APFS_OBJECT_TYPE_EFI_JUMPSTART 0x00000014 44 | #define APFS_OBJECT_TYPE_FUSION_MIDDLE_TREE 0x00000015 45 | #define APFS_OBJECT_TYPE_NX_FUSION_WBC 0x00000016 46 | #define APFS_OBJECT_TYPE_NX_FUSION_WBC_LIST 0x00000017 47 | #define APFS_OBJECT_TYPE_ER_STATE 0x00000018 48 | #define APFS_OBJECT_TYPE_GBITMAP 0x00000019 49 | #define APFS_OBJECT_TYPE_GBITMAP_TREE 0x0000001a 50 | #define APFS_OBJECT_TYPE_GBITMAP_BLOCK 0x0000001b 51 | #define APFS_OBJECT_TYPE_INVALID 0x00000000 52 | #define APFS_OBJECT_TYPE_TEST 0x000000ff 53 | 54 | /* Object type flags */ 55 | #define APFS_OBJ_VIRTUAL 0x00000000 56 | #define APFS_OBJ_EPHEMERAL 0x80000000 57 | #define APFS_OBJ_PHYSICAL 0x40000000 58 | #define APFS_OBJ_NOHEADER 0x20000000 59 | #define APFS_OBJ_ENCRYPTED 0x10000000 60 | #define APFS_OBJ_NONPERSISTENT 0x08000000 61 | 62 | /* 63 | * On-disk representation of an APFS object 64 | */ 65 | struct apfs_obj_phys { 66 | /*00*/ __le64 o_cksum; /* Fletcher checksum */ 67 | __le64 o_oid; /* Object-id */ 68 | /*10*/ __le64 o_xid; /* Transaction ID */ 69 | __le32 o_type; /* Object type */ 70 | __le32 o_subtype; /* Object subtype */ 71 | } __packed; 72 | 73 | /* 74 | * In-memory representation of an APFS object 75 | */ 76 | struct apfs_object { 77 | struct super_block *sb; 78 | u64 block_nr; 79 | u64 oid; /* Often the same as the block number */ 80 | 81 | /* 82 | * Buffer head containing the one block of the object. TODO: support 83 | * objects with more than one block. 84 | */ 85 | struct buffer_head *bh; 86 | }; 87 | 88 | #define APFS_MAX_CKSUM_SIZE 8 89 | 90 | extern int apfs_obj_verify_csum(struct super_block *sb, 91 | struct apfs_obj_phys *obj); 92 | 93 | #endif /* _APFS_OBJECT_H */ 94 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | Apple File System 3 | ================= 4 | 5 | The Apple File System (APFS) is a copy-on-write filesystem apparently intended 6 | to replace HFS+ on all Apple devices in the near future. This module provides 7 | a degree of experimental read-only support on Linux. 8 | 9 | This repo is a standalone version of 10 | for the purpose of making it easier to build the module out-of-tree. It is 11 | supposed to work with a range of kernel versions starting at 4.9 or before, but 12 | only a few of those have actually been tested. If you run into any problem, 13 | please send a report to . 14 | 15 | The long-term goal is to support writes as well. To help with testing, a set 16 | of userland tools is under development. The git tree can be retrieved from 17 | . 18 | 19 | Known limitations 20 | ================= 21 | 22 | This module is the result of reverse engineering. As it is read-only there 23 | should be no risk of data corruption, but do not expect everything to be read 24 | correctly. Testing in general has been limited so far, so you may experience 25 | crashes. Please report any issues that you find. 26 | 27 | Apple has released other versions of the filesystem to the public before the 28 | current one. I would not expect them to be compatible with this module at all, 29 | but I am open to fixing that if requested. 30 | 31 | Many features are not yet supported: 32 | 33 | o Encryption. 34 | o Compression, though the compressed contents of a file can be read from the 35 | 'com.apple.decmpfs' and 'com.apple.ResourceFork' xattrs as long as they are 36 | under 64k. 37 | o Restoring to a snapshot. 38 | o Access control lists. This is not a priority. 39 | 40 | Build 41 | ===== 42 | 43 | In order to build a module out-of-tree, you will first need the Linux kernel 44 | headers. On Debian, you can get them by running (as root): 45 | 46 | apt-get install linux-headers-$(uname -r) 47 | 48 | Now you can just cd to the linux-apfs-oot directory and run 49 | 50 | make 51 | 52 | The resulting module is the apfs.ko file. Before you can use it you must insert 53 | it into the kernel, as well as its dependencies. Again as root: 54 | 55 | modprobe libcrc32c 56 | insmod apfs.ko 57 | 58 | Mount 59 | ===== 60 | 61 | Like all filesystems, apfs is mounted with 62 | 63 | mount [-o options] device dir 64 | 65 | where 'device' is the path to your device file or filesystem image, and 'dir' 66 | is the mount point. The following options are accepted: 67 | 68 | vol=n 69 | Volume number to mount. The default is volume 0. 70 | 71 | uid=n, gid=n 72 | Override on-disk inode ownership data with given uid/gid. 73 | 74 | cknodes 75 | Verify the checksum on all metadata nodes. Right now this has 76 | a severe performance cost, so it's not recommended. 77 | 78 | So for instance, if you want to mount volume number 2, and you want the metadata 79 | to be checked, you should run (as root): 80 | 81 | mount -o cknodes,vol=2 device dir 82 | 83 | To unmount it, run 84 | 85 | umount dir 86 | 87 | Credits 88 | ======= 89 | 90 | Originally written by Ernesto A. Fernández , 91 | with several contributions from Gabriel Krisman Bertazi 92 | and Arnaud Ferraris . 93 | 94 | Work was first based on reverse engineering done by others [1][2], and later 95 | on the (very incomplete) official specification [3]. Some parts of the code 96 | imitate the ext2 module, and to a lesser degree xfs, udf, gfs2 and hfsplus. 97 | 98 | [1] Hansen, K.H., Toolan, F., Decoding the APFS file system, Digital 99 | Investigation (2017), http://dx.doi.org/10.1016/j.diin.2017.07.003 100 | [2] https://github.com/sgan81/apfs-fuse 101 | [3] https://developer.apple.com/support/apple-file-system/Apple-File-System-Reference.pdf 102 | -------------------------------------------------------------------------------- /inode.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * linux/fs/apfs/inode.h 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #ifndef _APFS_INODE_H 9 | #define _APFS_INODE_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include "extents.h" 15 | 16 | /* Inode numbers for special inodes */ 17 | #define APFS_INVALID_INO_NUM 0 18 | 19 | #define APFS_ROOT_DIR_PARENT 1 /* Root directory parent */ 20 | #define APFS_ROOT_DIR_INO_NUM 2 /* Root directory */ 21 | #define APFS_PRIV_DIR_INO_NUM 3 /* Private directory */ 22 | #define APFS_SNAP_DIR_INO_NUM 6 /* Snapshots metadata */ 23 | 24 | /* Smallest inode number available for user content */ 25 | #define APFS_MIN_USER_INO_NUM 16 26 | 27 | /* 28 | * Structure of an inode as stored as a B-tree value 29 | */ 30 | struct apfs_inode_val { 31 | /*00*/ __le64 parent_id; 32 | __le64 private_id; 33 | /*10*/ __le64 create_time; 34 | __le64 mod_time; 35 | __le64 change_time; 36 | __le64 access_time; 37 | /*30*/ __le64 internal_flags; 38 | union { 39 | __le32 nchildren; 40 | __le32 nlink; 41 | }; 42 | __le32 default_protection_class; 43 | /*40*/ __le32 write_generation_counter; 44 | __le32 bsd_flags; 45 | __le32 owner; 46 | __le32 group; 47 | /*50*/ __le16 mode; 48 | __le16 pad1; 49 | __le64 pad2; 50 | /*5C*/ u8 xfields[]; 51 | } __packed; 52 | 53 | /* Extended field types */ 54 | #define APFS_DREC_EXT_TYPE_SIBLING_ID 1 55 | 56 | #define APFS_INO_EXT_TYPE_SNAP_XID 1 57 | #define APFS_INO_EXT_TYPE_DELTA_TREE_OID 2 58 | #define APFS_INO_EXT_TYPE_DOCUMENT_ID 3 59 | #define APFS_INO_EXT_TYPE_NAME 4 60 | #define APFS_INO_EXT_TYPE_PREV_FSIZE 5 61 | #define APFS_INO_EXT_TYPE_RESERVED_6 6 62 | #define APFS_INO_EXT_TYPE_FINDER_INFO 7 63 | #define APFS_INO_EXT_TYPE_DSTREAM 8 64 | #define APFS_INO_EXT_TYPE_RESERVED_9 9 65 | #define APFS_INO_EXT_TYPE_DIR_STATS_KEY 10 66 | #define APFS_INO_EXT_TYPE_FS_UUID 11 67 | #define APFS_INO_EXT_TYPE_RESERVED_12 12 68 | #define APFS_INO_EXT_TYPE_SPARSE_BYTES 13 69 | #define APFS_INO_EXT_TYPE_RDEV 14 70 | 71 | /* 72 | * Structure used to store the number and size of extended fields of an inode 73 | */ 74 | struct apfs_xf_blob { 75 | __le16 xf_num_exts; 76 | __le16 xf_used_data; 77 | u8 xf_data[]; 78 | } __packed; 79 | 80 | /* 81 | * Structure used to store an inode's extended field 82 | */ 83 | struct apfs_x_field { 84 | u8 x_type; 85 | u8 x_flags; 86 | __le16 x_size; 87 | } __packed; 88 | 89 | /* 90 | * Structure of a data stream record 91 | */ 92 | struct apfs_dstream_id_val { 93 | __le32 refcnt; 94 | } __packed; 95 | 96 | /* 97 | * Structure used to store information about a data stream 98 | */ 99 | struct apfs_dstream { 100 | __le64 size; 101 | __le64 alloced_size; 102 | __le64 default_crypto_id; 103 | __le64 total_bytes_written; 104 | __le64 total_bytes_read; 105 | } __packed; 106 | 107 | /* 108 | * APFS inode data in memory 109 | */ 110 | struct apfs_inode_info { 111 | u64 i_extent_id; /* ID of the extent records */ 112 | struct apfs_file_extent i_cached_extent; /* Latest extent record */ 113 | spinlock_t i_extent_lock; /* Protects i_cached_extent */ 114 | struct timespec64 i_crtime; /* Time of creation */ 115 | 116 | #if BITS_PER_LONG == 32 117 | /* This is the actual inode number; vfs_inode.i_ino could overflow */ 118 | u64 i_ino; 119 | #endif 120 | struct inode vfs_inode; 121 | }; 122 | 123 | static inline struct apfs_inode_info *APFS_I(struct inode *inode) 124 | { 125 | return container_of(inode, struct apfs_inode_info, vfs_inode); 126 | } 127 | 128 | extern struct inode *apfs_iget(struct super_block *sb, u64 cnid); 129 | 130 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) /* No statx yet... */ 131 | extern int apfs_getattr(struct vfsmount *mnt, struct dentry *dentry, 132 | struct kstat *stat); 133 | #else 134 | extern int apfs_getattr(const struct path *path, struct kstat *stat, 135 | u32 request_mask, unsigned int query_flags); 136 | #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) */ 137 | 138 | #endif /* _APFS_INODE_H */ 139 | -------------------------------------------------------------------------------- /node.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * linux/fs/apfs/node.h 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #ifndef _APFS_NODE_H 9 | #define _APFS_NODE_H 10 | 11 | #include 12 | #include 13 | #include "object.h" 14 | 15 | struct apfs_query; 16 | 17 | /* 18 | * On-disk representation of an object map 19 | */ 20 | struct apfs_omap_phys { 21 | /*00*/ struct apfs_obj_phys om_o; 22 | /*20*/ __le32 om_flags; 23 | __le32 om_snap_count; 24 | __le32 om_tree_type; 25 | __le32 om_snapshot_tree_type; 26 | /*30*/ __le64 om_tree_oid; 27 | __le64 om_snapshot_tree_oid; 28 | /*40*/ __le64 om_most_recent_snap; 29 | __le64 om_pending_revert_min; 30 | __le64 om_pending_revert_max; 31 | } __packed; 32 | 33 | /* 34 | * Structure of a value in an object map B-tree 35 | */ 36 | struct apfs_omap_val { 37 | __le32 ov_flags; 38 | __le32 ov_size; 39 | __le64 ov_paddr; 40 | } __packed; 41 | 42 | /* B-tree node flags */ 43 | #define APFS_BTNODE_ROOT 0x0001 44 | #define APFS_BTNODE_LEAF 0x0002 45 | #define APFS_BTNODE_FIXED_KV_SIZE 0x0004 46 | #define APFS_BTNODE_CHECK_KOFF_INVAL 0x8000 47 | 48 | /* B-tree location constants */ 49 | #define APFS_BTOFF_INVALID 0xffff 50 | 51 | /* 52 | * Structure storing a location inside a B-tree node 53 | */ 54 | struct apfs_nloc { 55 | __le16 off; 56 | __le16 len; 57 | } __packed; 58 | 59 | /* 60 | * Structure storing the location of a key/value pair within a B-tree node 61 | */ 62 | struct apfs_kvloc { 63 | struct apfs_nloc k; 64 | struct apfs_nloc v; 65 | } __packed; 66 | 67 | /* 68 | * Structure storing the location of a key/value pair within a B-tree node 69 | * having fixed-size key and value (flag APFS_BTNODE_FIXED_KV_SIZE is present) 70 | */ 71 | struct apfs_kvoff { 72 | __le16 k; 73 | __le16 v; 74 | } __packed; 75 | 76 | /* 77 | * On-disk representation of a B-tree node 78 | */ 79 | struct apfs_btree_node_phys { 80 | /*00*/ struct apfs_obj_phys btn_o; 81 | /*20*/ __le16 btn_flags; 82 | __le16 btn_level; 83 | __le32 btn_nkeys; 84 | /*28*/ struct apfs_nloc btn_table_space; 85 | struct apfs_nloc btn_free_space; 86 | struct apfs_nloc btn_key_free_list; 87 | struct apfs_nloc btn_val_free_list; 88 | /*38*/ __le64 btn_data[]; 89 | } __packed; 90 | 91 | /* 92 | * Structure used to store information about a B-tree that won't change 93 | * over time 94 | */ 95 | struct apfs_btree_info_fixed { 96 | __le32 bt_flags; 97 | __le32 bt_node_size; 98 | __le32 bt_key_size; 99 | __le32 bt_val_size; 100 | } __packed; 101 | 102 | /* 103 | * Structure used to store information about a B-tree (located at the end of 104 | * a B-tree root node block) 105 | */ 106 | struct apfs_btree_info { 107 | struct apfs_btree_info_fixed bt_fixed; 108 | __le32 bt_longest_key; 109 | __le32 bt_longest_val; 110 | __le64 bt_key_count; 111 | __le64 bt_node_count; 112 | } __packed; 113 | 114 | /* 115 | * In-memory representation of an APFS node 116 | */ 117 | struct apfs_node { 118 | u16 flags; /* Node flags */ 119 | u32 records; /* Number of records in the node */ 120 | 121 | int key; /* Offset of the key area in the block */ 122 | int free; /* Offset of the free area in the block */ 123 | int data; /* Offset of the data area in the block */ 124 | 125 | struct apfs_object object; /* Object holding the node */ 126 | 127 | struct kref refcount; 128 | }; 129 | 130 | /** 131 | * apfs_node_is_leaf - Check if a b-tree node is a leaf 132 | * @node: the node to check 133 | */ 134 | static inline bool apfs_node_is_leaf(struct apfs_node *node) 135 | { 136 | return (node->flags & APFS_BTNODE_LEAF) != 0; 137 | } 138 | 139 | /** 140 | * apfs_node_is_root - Check if a b-tree node is the root 141 | * @node: the node to check 142 | */ 143 | static inline bool apfs_node_is_root(struct apfs_node *node) 144 | { 145 | return (node->flags & APFS_BTNODE_ROOT) != 0; 146 | } 147 | 148 | /** 149 | * apfs_node_has_fixed_kv_size - Check if a b-tree node has fixed key/value 150 | * sizes 151 | * @node: the node to check 152 | */ 153 | static inline bool apfs_node_has_fixed_kv_size(struct apfs_node *node) 154 | { 155 | return (node->flags & APFS_BTNODE_FIXED_KV_SIZE) != 0; 156 | } 157 | 158 | extern struct apfs_node *apfs_read_node(struct super_block *sb, u64 block); 159 | extern int apfs_node_query(struct super_block *sb, struct apfs_query *query); 160 | extern int apfs_bno_from_query(struct apfs_query *query, u64 *bno); 161 | 162 | extern void apfs_node_get(struct apfs_node *node); 163 | extern void apfs_node_put(struct apfs_node *node); 164 | 165 | #endif /* _APFS_NODE_H */ 166 | -------------------------------------------------------------------------------- /extents.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * linux/fs/apfs/extents.c 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #include 9 | #include 10 | #include "apfs.h" 11 | #include "btree.h" 12 | #include "extents.h" 13 | #include "inode.h" 14 | #include "key.h" 15 | #include "message.h" 16 | #include "node.h" 17 | #include "super.h" 18 | 19 | /** 20 | * apfs_extent_from_query - Read the extent found by a successful query 21 | * @query: the query that found the record 22 | * @extent: Return parameter. The extent found. 23 | * 24 | * Reads the extent record into @extent and performs some basic sanity checks 25 | * as a protection against crafted filesystems. Returns 0 on success or 26 | * -EFSCORRUPTED otherwise. 27 | */ 28 | int apfs_extent_from_query(struct apfs_query *query, 29 | struct apfs_file_extent *extent) 30 | { 31 | struct super_block *sb = query->node->object.sb; 32 | struct apfs_file_extent_val *ext; 33 | struct apfs_file_extent_key *ext_key; 34 | char *raw = query->node->object.bh->b_data; 35 | u64 ext_len; 36 | 37 | if (query->len != sizeof(*ext) || query->key_len != sizeof(*ext_key)) 38 | return -EFSCORRUPTED; 39 | 40 | ext = (struct apfs_file_extent_val *)(raw + query->off); 41 | ext_key = (struct apfs_file_extent_key *)(raw + query->key_off); 42 | ext_len = le64_to_cpu(ext->len_and_flags) & APFS_FILE_EXTENT_LEN_MASK; 43 | 44 | /* Extent length must be a multiple of the block size */ 45 | if (ext_len & (sb->s_blocksize - 1)) 46 | return -EFSCORRUPTED; 47 | 48 | extent->logical_addr = le64_to_cpu(ext_key->logical_addr); 49 | extent->phys_block_num = le64_to_cpu(ext->phys_block_num); 50 | extent->len = ext_len; 51 | return 0; 52 | } 53 | 54 | /** 55 | * apfs_extent_read - Read the extent record that covers a block 56 | * @inode: inode that owns the record 57 | * @iblock: logical number of the wanted block 58 | * @extent: Return parameter. The extent found. 59 | * 60 | * Finds and caches the extent record. On success, returns a pointer to the 61 | * cache record; on failure, returns an error code. 62 | */ 63 | static int apfs_extent_read(struct inode *inode, sector_t iblock, 64 | struct apfs_file_extent *extent) 65 | { 66 | struct super_block *sb = inode->i_sb; 67 | struct apfs_sb_info *sbi = APFS_SB(sb); 68 | struct apfs_inode_info *ai = APFS_I(inode); 69 | struct apfs_key key; 70 | struct apfs_query *query; 71 | struct apfs_file_extent *cache = &ai->i_cached_extent; 72 | u64 iaddr = iblock << inode->i_blkbits; 73 | int ret = 0; 74 | 75 | spin_lock(&ai->i_extent_lock); 76 | if (iaddr >= cache->logical_addr && 77 | iaddr < cache->logical_addr + cache->len) { 78 | *extent = *cache; 79 | spin_unlock(&ai->i_extent_lock); 80 | return 0; 81 | } 82 | spin_unlock(&ai->i_extent_lock); 83 | 84 | /* We will search for the extent that covers iblock */ 85 | apfs_init_file_extent_key(ai->i_extent_id, iaddr, &key); 86 | 87 | query = apfs_alloc_query(sbi->s_cat_root, NULL /* parent */); 88 | if (!query) 89 | return -ENOMEM; 90 | query->key = &key; 91 | query->flags = APFS_QUERY_CAT; 92 | 93 | ret = apfs_btree_query(sb, &query); 94 | if (ret) 95 | goto done; 96 | 97 | ret = apfs_extent_from_query(query, extent); 98 | if (ret) { 99 | apfs_alert(sb, "bad extent record for inode 0x%llx", 100 | (unsigned long long) inode->i_ino); 101 | goto done; 102 | } 103 | 104 | spin_lock(&ai->i_extent_lock); 105 | *cache = *extent; 106 | spin_unlock(&ai->i_extent_lock); 107 | 108 | done: 109 | apfs_free_query(sb, query); 110 | return ret; 111 | } 112 | 113 | int apfs_get_block(struct inode *inode, sector_t iblock, 114 | struct buffer_head *bh_result, int create) 115 | { 116 | struct super_block *sb = inode->i_sb; 117 | struct apfs_file_extent ext; 118 | u64 blk_off, bno, map_len; 119 | int ret; 120 | 121 | ret = apfs_extent_read(inode, iblock, &ext); 122 | if (ret) 123 | return ret; 124 | 125 | /* Find the block offset of iblock within the extent */ 126 | blk_off = iblock - (ext.logical_addr >> inode->i_blkbits); 127 | 128 | /* Make sure we don't read past the extent boundaries */ 129 | map_len = ext.len - (blk_off << inode->i_blkbits); 130 | if (bh_result->b_size > map_len) 131 | bh_result->b_size = map_len; 132 | 133 | /* 134 | * Save the requested mapping length as map_bh() replaces it with 135 | * the filesystem block size 136 | */ 137 | map_len = bh_result->b_size; 138 | /* Extents representing holes have block number 0 */ 139 | if (ext.phys_block_num != 0) { 140 | /* Find the block number of iblock within the disk */ 141 | bno = ext.phys_block_num + blk_off; 142 | map_bh(bh_result, sb, bno); 143 | } 144 | 145 | bh_result->b_size = map_len; 146 | return 0; 147 | } 148 | -------------------------------------------------------------------------------- /key.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * linux/fs/apfs/key.h 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #ifndef _APFS_KEY_H 9 | #define _APFS_KEY_H 10 | 11 | #include 12 | 13 | struct super_block; 14 | 15 | /* 16 | * Structure of a key in an object map B-tree 17 | */ 18 | struct apfs_omap_key { 19 | __le64 ok_oid; 20 | __le64 ok_xid; 21 | } __packed; 22 | 23 | /* Catalog records types */ 24 | enum { 25 | APFS_TYPE_ANY = 0, 26 | APFS_TYPE_SNAP_METADATA = 1, 27 | APFS_TYPE_EXTENT = 2, 28 | APFS_TYPE_INODE = 3, 29 | APFS_TYPE_XATTR = 4, 30 | APFS_TYPE_SIBLING_LINK = 5, 31 | APFS_TYPE_DSTREAM_ID = 6, 32 | APFS_TYPE_CRYPTO_STATE = 7, 33 | APFS_TYPE_FILE_EXTENT = 8, 34 | APFS_TYPE_DIR_REC = 9, 35 | APFS_TYPE_DIR_STATS = 10, 36 | APFS_TYPE_SNAP_NAME = 11, 37 | APFS_TYPE_SIBLING_MAP = 12, 38 | APFS_TYPE_MAX_VALID = 12, 39 | APFS_TYPE_MAX = 15, 40 | APFS_TYPE_INVALID = 15, 41 | }; 42 | 43 | /* Bit masks for the 'obj_id_and_type' field of a key header */ 44 | #define APFS_OBJ_ID_MASK 0x0fffffffffffffffULL 45 | #define APFS_OBJ_TYPE_MASK 0xf000000000000000ULL 46 | #define APFS_OBJ_TYPE_SHIFT 60 47 | 48 | /* Key header for filesystem-object keys */ 49 | struct apfs_key_header { 50 | __le64 obj_id_and_type; 51 | } __packed; 52 | 53 | /* 54 | * Structure of the key for an inode record 55 | */ 56 | struct apfs_inode_key { 57 | struct apfs_key_header hdr; 58 | } __packed; 59 | 60 | /* 61 | * Structure of the key for a file extent record 62 | */ 63 | struct apfs_file_extent_key { 64 | struct apfs_key_header hdr; 65 | __le64 logical_addr; 66 | } __packed; 67 | 68 | /* 69 | * Structure of the key for a data stream record 70 | */ 71 | struct apfs_dstream_id_key { 72 | struct apfs_key_header hdr; 73 | } __packed; 74 | 75 | /* Bit masks for the 'name_len_and_hash' field of a directory entry */ 76 | #define APFS_DREC_LEN_MASK 0x000003ff 77 | #define APFS_DREC_HASH_MASK 0xfffffc00 78 | #define APFS_DREC_HASH_SHIFT 10 79 | 80 | /* The name length in the catalog key counts the terminating null byte. */ 81 | #define APFS_NAME_LEN (APFS_DREC_LEN_MASK - 1) 82 | 83 | /* Bit masks for the 'type' field of a directory entry */ 84 | enum { 85 | APFS_DREC_TYPE_MASK = 0x000f, 86 | APFS_DREC_RESERVED_10 = 0x0010 87 | }; 88 | 89 | /* 90 | * Structure of the key for a directory entry, including a precomputed 91 | * hash of its name 92 | */ 93 | struct apfs_drec_hashed_key { 94 | struct apfs_key_header hdr; 95 | __le32 name_len_and_hash; 96 | u8 name[0]; 97 | } __packed; 98 | 99 | /* 100 | * Structure of the key for an extended attributes record 101 | */ 102 | struct apfs_xattr_key { 103 | struct apfs_key_header hdr; 104 | __le16 name_len; 105 | u8 name[0]; 106 | } __packed; 107 | 108 | /* 109 | * In-memory representation of a key, as relevant for a b-tree query. 110 | */ 111 | struct apfs_key { 112 | u64 id; 113 | u64 number; /* Extent offset, name hash or transaction id */ 114 | const char *name; /* On-disk name string */ 115 | u8 type; /* Record type (0 for the omap) */ 116 | }; 117 | 118 | /** 119 | * apfs_init_omap_key - Initialize an in-memory key for an omap query 120 | * @oid: object id 121 | * @xid: latest transaction id 122 | * @key: apfs_key structure to initialize 123 | */ 124 | static inline void apfs_init_omap_key(u64 oid, u64 xid, struct apfs_key *key) 125 | { 126 | key->id = oid; 127 | key->type = 0; 128 | key->number = xid; 129 | key->name = NULL; 130 | } 131 | 132 | /** 133 | * apfs_init_inode_key - Initialize an in-memory key for an inode query 134 | * @ino: inode number 135 | * @key: apfs_key structure to initialize 136 | */ 137 | static inline void apfs_init_inode_key(u64 ino, struct apfs_key *key) 138 | { 139 | key->id = ino; 140 | key->type = APFS_TYPE_INODE; 141 | key->number = 0; 142 | key->name = NULL; 143 | } 144 | 145 | /** 146 | * apfs_init_file_extent_key - Initialize an in-memory key for an extent query 147 | * @id: extent id 148 | * @offset: logical address (0 for a multiple query) 149 | * @key: apfs_key structure to initialize 150 | */ 151 | static inline void apfs_init_file_extent_key(u64 id, u64 offset, 152 | struct apfs_key *key) 153 | { 154 | key->id = id; 155 | key->type = APFS_TYPE_FILE_EXTENT; 156 | key->number = offset; 157 | key->name = NULL; 158 | } 159 | 160 | extern void apfs_init_drec_hashed_key(struct super_block *sb, u64 ino, 161 | const char *name, struct apfs_key *key); 162 | 163 | /** 164 | * apfs_init_xattr_key - Initialize an in-memory key for a xattr query 165 | * @ino: inode number of the parent file 166 | * @name: xattr name (NULL for a multiple query) 167 | * @key: apfs_key structure to initialize 168 | */ 169 | static inline void apfs_init_xattr_key(u64 ino, const char *name, 170 | struct apfs_key *key) 171 | { 172 | key->id = ino; 173 | key->type = APFS_TYPE_XATTR; 174 | key->number = 0; 175 | key->name = name; 176 | } 177 | 178 | extern int apfs_filename_cmp(struct super_block *sb, 179 | const char *name1, const char *name2); 180 | extern int apfs_keycmp(struct super_block *sb, 181 | struct apfs_key *k1, struct apfs_key *k2); 182 | extern int apfs_read_cat_key(void *raw, int size, struct apfs_key *key); 183 | extern int apfs_read_omap_key(void *raw, int size, struct apfs_key *key); 184 | 185 | #endif /* _APFS_KEY_H */ 186 | -------------------------------------------------------------------------------- /dir.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * linux/fs/apfs/dir.c 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #include 9 | #include 10 | #include "apfs.h" 11 | #include "btree.h" 12 | #include "dir.h" 13 | #include "key.h" 14 | #include "message.h" 15 | #include "node.h" 16 | #include "super.h" 17 | 18 | /** 19 | * apfs_drec_from_query - Read the directory record found by a successful query 20 | * @query: the query that found the record 21 | * @drec: Return parameter. The directory record found. 22 | * 23 | * Reads the directory record into @drec and performs some basic sanity checks 24 | * as a protection against crafted filesystems. Returns 0 on success or 25 | * -EFSCORRUPTED otherwise. 26 | * 27 | * The caller must not free @query while @drec is in use, because @drec->name 28 | * points to data on disk. 29 | */ 30 | int apfs_drec_from_query(struct apfs_query *query, struct apfs_drec *drec) 31 | { 32 | char *raw = query->node->object.bh->b_data; 33 | struct apfs_drec_hashed_key *de_key; 34 | struct apfs_drec_val *de; 35 | int namelen = query->key_len - sizeof(*de_key); 36 | 37 | if (namelen < 1) 38 | return -EFSCORRUPTED; 39 | if (query->len < sizeof(*de)) 40 | return -EFSCORRUPTED; 41 | 42 | de = (struct apfs_drec_val *)(raw + query->off); 43 | de_key = (struct apfs_drec_hashed_key *)(raw + query->key_off); 44 | 45 | if (namelen != (le32_to_cpu(de_key->name_len_and_hash) & 46 | APFS_DREC_LEN_MASK)) 47 | return -EFSCORRUPTED; 48 | 49 | /* Filename must be NULL-terminated */ 50 | if (de_key->name[namelen - 1] != 0) 51 | return -EFSCORRUPTED; 52 | 53 | drec->name = de_key->name; 54 | drec->name_len = namelen - 1; /* Don't count the NULL termination */ 55 | drec->ino = le64_to_cpu(de->file_id); 56 | 57 | drec->type = le16_to_cpu(de->flags) & APFS_DREC_TYPE_MASK; 58 | if (drec->type != DT_FIFO && drec->type & 1) /* Invalid file type */ 59 | drec->type = DT_UNKNOWN; 60 | return 0; 61 | } 62 | 63 | /** 64 | * apfs_inode_by_name - Find the cnid for a given filename 65 | * @dir: parent directory 66 | * @child: filename 67 | * @ino: on return, the inode number found 68 | * 69 | * Returns 0 and the inode number (which is the cnid of the file 70 | * record); otherwise, return the appropriate error code. 71 | */ 72 | int apfs_inode_by_name(struct inode *dir, const struct qstr *child, u64 *ino) 73 | { 74 | struct super_block *sb = dir->i_sb; 75 | struct apfs_sb_info *sbi = APFS_SB(sb); 76 | struct apfs_key key; 77 | struct apfs_query *query; 78 | struct apfs_drec drec; 79 | u64 cnid = dir->i_ino; 80 | int err; 81 | 82 | apfs_init_drec_hashed_key(sb, cnid, child->name, &key); 83 | 84 | query = apfs_alloc_query(sbi->s_cat_root, NULL /* parent */); 85 | if (!query) 86 | return -ENOMEM; 87 | query->key = &key; 88 | 89 | /* 90 | * Distinct filenames in the same directory may (rarely) share the same 91 | * hash. The query code cannot handle that because their order in the 92 | * b-tree would depend on their unnormalized original names. Just get 93 | * all the candidates and check them one by one. 94 | */ 95 | query->flags |= APFS_QUERY_CAT | APFS_QUERY_ANY_NAME | APFS_QUERY_EXACT; 96 | do { 97 | err = apfs_btree_query(sb, &query); 98 | if (err) 99 | goto out; 100 | err = apfs_drec_from_query(query, &drec); 101 | if (err) 102 | goto out; 103 | } while (unlikely(apfs_filename_cmp(sb, child->name, drec.name))); 104 | 105 | *ino = drec.ino; 106 | out: 107 | apfs_free_query(sb, query); 108 | return err; 109 | } 110 | 111 | static int apfs_readdir(struct file *file, struct dir_context *ctx) 112 | { 113 | struct inode *inode = file_inode(file); 114 | struct super_block *sb = inode->i_sb; 115 | struct apfs_sb_info *sbi = APFS_SB(sb); 116 | struct apfs_key key; 117 | struct apfs_query *query; 118 | u64 cnid = inode->i_ino; 119 | loff_t pos; 120 | int err = 0; 121 | 122 | if (ctx->pos == 0) { 123 | if (!dir_emit_dot(file, ctx)) 124 | return 0; 125 | ctx->pos++; 126 | } 127 | if (ctx->pos == 1) { 128 | if (!dir_emit_dotdot(file, ctx)) 129 | return 0; 130 | ctx->pos++; 131 | } 132 | 133 | query = apfs_alloc_query(sbi->s_cat_root, NULL /* parent */); 134 | if (!query) 135 | return -ENOMEM; 136 | 137 | /* We want all the children for the cnid, regardless of the name */ 138 | apfs_init_drec_hashed_key(sb, cnid, NULL /* name */, &key); 139 | query->key = &key; 140 | query->flags = APFS_QUERY_CAT | APFS_QUERY_MULTIPLE | APFS_QUERY_EXACT; 141 | 142 | pos = ctx->pos - 2; 143 | while (1) { 144 | struct apfs_drec drec; 145 | /* 146 | * We query for the matching records, one by one. After we 147 | * pass ctx->pos we begin to emit them. 148 | * 149 | * TODO: Faster approach for large directories? 150 | */ 151 | 152 | err = apfs_btree_query(sb, &query); 153 | if (err == -ENODATA) { /* Got all the records */ 154 | err = 0; 155 | break; 156 | } 157 | if (err) 158 | break; 159 | 160 | err = apfs_drec_from_query(query, &drec); 161 | if (err) { 162 | apfs_alert(sb, "bad dentry record in directory 0x%llx", 163 | cnid); 164 | break; 165 | } 166 | 167 | err = 0; 168 | if (pos <= 0) { 169 | if (!dir_emit(ctx, drec.name, drec.name_len, 170 | drec.ino, drec.type)) 171 | break; 172 | } 173 | pos--; 174 | } 175 | 176 | if (pos < 0) 177 | ctx->pos -= pos; 178 | apfs_free_query(sb, query); 179 | return err; 180 | } 181 | 182 | const struct file_operations apfs_dir_operations = { 183 | .llseek = generic_file_llseek, 184 | .read = generic_read_dir, 185 | .iterate_shared = apfs_readdir, 186 | }; 187 | -------------------------------------------------------------------------------- /key.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * linux/fs/apfs/key.c 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #include 9 | #include "apfs.h" 10 | #include "key.h" 11 | #include "super.h" 12 | #include "unicode.h" 13 | 14 | /** 15 | * apfs_cat_type - Read the record type of a catalog key 16 | * @key: the raw catalog key 17 | * 18 | * The record type is stored in the last byte of the cnid field; this function 19 | * returns that value. 20 | */ 21 | static inline int apfs_cat_type(struct apfs_key_header *key) 22 | { 23 | return (le64_to_cpu(key->obj_id_and_type) & APFS_OBJ_TYPE_MASK) 24 | >> APFS_OBJ_TYPE_SHIFT; 25 | } 26 | 27 | /** 28 | * apfs_cat_cnid - Read the cnid value on a catalog key 29 | * @key: the raw catalog key 30 | * 31 | * The cnid value shares the its field with the record type. This function 32 | * masks that part away and returns the result. 33 | */ 34 | static inline u64 apfs_cat_cnid(struct apfs_key_header *key) 35 | { 36 | return le64_to_cpu(key->obj_id_and_type) & APFS_OBJ_ID_MASK; 37 | } 38 | 39 | /** 40 | * apfs_filename_cmp - Normalize and compare two APFS filenames 41 | * @sb: filesystem superblock 42 | * @name1, @name2: names to compare 43 | * 44 | * returns 0 if @name1 and @name2 are equal 45 | * < 0 if @name1 comes before @name2 46 | * > 0 if @name1 comes after @name2 47 | */ 48 | int apfs_filename_cmp(struct super_block *sb, 49 | const char *name1, const char *name2) 50 | { 51 | struct apfs_unicursor cursor1, cursor2; 52 | bool case_fold = apfs_is_case_insensitive(sb); 53 | 54 | apfs_init_unicursor(&cursor1, name1); 55 | apfs_init_unicursor(&cursor2, name2); 56 | 57 | while (1) { 58 | unicode_t uni1, uni2; 59 | 60 | uni1 = apfs_normalize_next(&cursor1, case_fold); 61 | uni2 = apfs_normalize_next(&cursor2, case_fold); 62 | 63 | if (uni1 != uni2) 64 | return uni1 < uni2 ? -1 : 1; 65 | if (!uni1) 66 | return 0; 67 | } 68 | } 69 | 70 | /** 71 | * apfs_keycmp - Compare two keys 72 | * @sb: filesystem superblock 73 | * @k1, @k2: keys to compare 74 | * 75 | * returns 0 if @k1 and @k2 are equal 76 | * < 0 if @k1 comes before @k2 in the btree 77 | * > 0 if @k1 comes after @k2 in the btree 78 | */ 79 | int apfs_keycmp(struct super_block *sb, 80 | struct apfs_key *k1, struct apfs_key *k2) 81 | { 82 | if (k1->id != k2->id) 83 | return k1->id < k2->id ? -1 : 1; 84 | if (k1->type != k2->type) 85 | return k1->type < k2->type ? -1 : 1; 86 | if (k1->number != k2->number) 87 | return k1->number < k2->number ? -1 : 1; 88 | if (!k1->name) 89 | return 0; 90 | 91 | /* Normalization seems to be ignored here, even for directory records */ 92 | return strcmp(k1->name, k2->name); 93 | } 94 | 95 | /** 96 | * apfs_read_cat_key - Parse an on-disk catalog key 97 | * @raw: pointer to the raw key 98 | * @size: size of the raw key 99 | * @key: apfs_key structure to store the result 100 | * 101 | * Returns 0 on success, or a negative error code otherwise. 102 | */ 103 | int apfs_read_cat_key(void *raw, int size, struct apfs_key *key) 104 | { 105 | if (size < sizeof(struct apfs_key_header)) 106 | return -EFSCORRUPTED; 107 | key->id = apfs_cat_cnid((struct apfs_key_header *)raw); 108 | key->type = apfs_cat_type((struct apfs_key_header *)raw); 109 | 110 | switch (key->type) { 111 | case APFS_TYPE_DIR_REC: 112 | if (size < sizeof(struct apfs_drec_hashed_key) + 1 || 113 | *((char *)raw + size - 1) != 0) { 114 | /* Filename must have NULL-termination */ 115 | return -EFSCORRUPTED; 116 | } 117 | 118 | /* Name length is not used in key comparisons, only the hash */ 119 | key->number = le32_to_cpu( 120 | ((struct apfs_drec_hashed_key *)raw)->name_len_and_hash) & 121 | APFS_DREC_HASH_MASK; 122 | 123 | key->name = ((struct apfs_drec_hashed_key *)raw)->name; 124 | break; 125 | case APFS_TYPE_XATTR: 126 | if (size < sizeof(struct apfs_xattr_key) + 1 || 127 | *((char *)raw + size - 1) != 0) { 128 | /* xattr name must have NULL-termination */ 129 | return -EFSCORRUPTED; 130 | } 131 | key->number = 0; 132 | key->name = ((struct apfs_xattr_key *)raw)->name; 133 | break; 134 | case APFS_TYPE_FILE_EXTENT: 135 | if (size != sizeof(struct apfs_file_extent_key)) 136 | return -EFSCORRUPTED; 137 | key->number = le64_to_cpu( 138 | ((struct apfs_file_extent_key *)raw)->logical_addr); 139 | key->name = NULL; 140 | break; 141 | default: 142 | key->number = 0; 143 | key->name = NULL; 144 | break; 145 | } 146 | 147 | return 0; 148 | } 149 | 150 | /** 151 | * apfs_read_omap_key - Parse an on-disk object map key 152 | * @raw: pointer to the raw key 153 | * @size: size of the raw key 154 | * @key: apfs_key structure to store the result 155 | * 156 | * Returns 0 on success, or a negative error code otherwise. 157 | */ 158 | int apfs_read_omap_key(void *raw, int size, struct apfs_key *key) 159 | { 160 | if (size < sizeof(struct apfs_omap_key)) 161 | return -EFSCORRUPTED; 162 | 163 | key->id = le64_to_cpu(((struct apfs_omap_key *)raw)->ok_oid); 164 | key->type = 0; 165 | key->number = le64_to_cpu(((struct apfs_omap_key *)raw)->ok_xid); 166 | key->name = NULL; 167 | 168 | return 0; 169 | } 170 | 171 | /** 172 | * apfs_init_drec_hashed_key - Initialize an in-memory key for a dentry query 173 | * @sb: filesystem superblock 174 | * @ino: inode number of the parent directory 175 | * @name: filename (NULL for a multiple query) 176 | * @key: apfs_key structure to initialize 177 | */ 178 | void apfs_init_drec_hashed_key(struct super_block *sb, u64 ino, 179 | const char *name, struct apfs_key *key) 180 | { 181 | struct apfs_unicursor cursor; 182 | bool case_fold = apfs_is_case_insensitive(sb); 183 | u32 hash = 0xFFFFFFFF; 184 | 185 | key->id = ino; 186 | key->type = APFS_TYPE_DIR_REC; 187 | 188 | /* To respect normalization, queries can only consider the hash */ 189 | key->name = NULL; 190 | 191 | if (!name) { 192 | key->number = 0; 193 | return; 194 | } 195 | 196 | apfs_init_unicursor(&cursor, name); 197 | 198 | while (1) { 199 | unicode_t utf32; 200 | 201 | utf32 = apfs_normalize_next(&cursor, case_fold); 202 | if (!utf32) 203 | break; 204 | 205 | hash = crc32c(hash, &utf32, sizeof(utf32)); 206 | } 207 | 208 | /* The filename length doesn't matter, so it's left as zero */ 209 | key->number = hash << APFS_DREC_HASH_SHIFT; 210 | } 211 | -------------------------------------------------------------------------------- /btree.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * linux/fs/apfs/btree.c 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #include 9 | #include 10 | #include "apfs.h" 11 | #include "btree.h" 12 | #include "key.h" 13 | #include "message.h" 14 | #include "node.h" 15 | #include "super.h" 16 | 17 | /** 18 | * apfs_child_from_query - Read the child id found by a successful nonleaf query 19 | * @query: the query that found the record 20 | * @child: Return parameter. The child id found. 21 | * 22 | * Reads the child id in the nonleaf node record into @child and performs a 23 | * basic sanity check as a protection against crafted filesystems. Returns 0 24 | * on success or -EFSCORRUPTED otherwise. 25 | */ 26 | static int apfs_child_from_query(struct apfs_query *query, u64 *child) 27 | { 28 | char *raw = query->node->object.bh->b_data; 29 | 30 | if (query->len != 8) /* The data on a nonleaf node is the child id */ 31 | return -EFSCORRUPTED; 32 | 33 | *child = le64_to_cpup((__le64 *)(raw + query->off)); 34 | return 0; 35 | } 36 | 37 | /** 38 | * apfs_omap_lookup_block - Find the block number of a b-tree node from its id 39 | * @sb: filesystem superblock 40 | * @tbl: Root of the object map to be searched 41 | * @id: id of the node 42 | * @block: on return, the found block number 43 | * 44 | * Returns 0 on success or a negative error code in case of failure. 45 | */ 46 | int apfs_omap_lookup_block(struct super_block *sb, struct apfs_node *tbl, 47 | u64 id, u64 *block) 48 | { 49 | struct apfs_sb_info *sbi = APFS_SB(sb); 50 | struct apfs_query *query; 51 | struct apfs_key key; 52 | int ret = 0; 53 | 54 | query = apfs_alloc_query(tbl, NULL /* parent */); 55 | if (!query) 56 | return -ENOMEM; 57 | 58 | apfs_init_omap_key(id, sbi->s_xid, &key); 59 | query->key = &key; 60 | query->flags |= APFS_QUERY_OMAP; 61 | 62 | ret = apfs_btree_query(sb, &query); 63 | if (ret) 64 | goto fail; 65 | 66 | ret = apfs_bno_from_query(query, block); 67 | if (ret) 68 | apfs_alert(sb, "bad object map leaf block: 0x%llx", 69 | query->node->object.block_nr); 70 | 71 | fail: 72 | apfs_free_query(sb, query); 73 | return ret; 74 | } 75 | 76 | /** 77 | * apfs_alloc_query - Allocates a query structure 78 | * @node: node to be searched 79 | * @parent: query for the parent node 80 | * 81 | * Callers other than apfs_btree_query() should set @parent to NULL, and @node 82 | * to the root of the b-tree. They should also initialize most of the query 83 | * fields themselves; when @parent is not NULL the query will inherit them. 84 | * 85 | * Returns the allocated query, or NULL in case of failure. 86 | */ 87 | struct apfs_query *apfs_alloc_query(struct apfs_node *node, 88 | struct apfs_query *parent) 89 | { 90 | struct apfs_query *query; 91 | 92 | query = kmalloc(sizeof(*query), GFP_KERNEL); 93 | if (!query) 94 | return NULL; 95 | 96 | /* To be released by free_query. */ 97 | apfs_node_get(node); 98 | query->node = node; 99 | query->key = parent ? parent->key : NULL; 100 | query->flags = parent ? 101 | parent->flags & ~(APFS_QUERY_DONE | APFS_QUERY_NEXT) : 0; 102 | query->parent = parent; 103 | /* Start the search with the last record and go backwards */ 104 | query->index = node->records; 105 | query->depth = parent ? parent->depth + 1 : 0; 106 | 107 | return query; 108 | } 109 | 110 | /** 111 | * apfs_free_query - Free a query structure 112 | * @sb: filesystem superblock 113 | * @query: query to free 114 | * 115 | * Also frees the ancestor queries, if they are kept. 116 | */ 117 | void apfs_free_query(struct super_block *sb, struct apfs_query *query) 118 | { 119 | while (query) { 120 | struct apfs_query *parent = query->parent; 121 | 122 | apfs_node_put(query->node); 123 | kfree(query); 124 | query = parent; 125 | } 126 | } 127 | 128 | /** 129 | * apfs_btree_query - Execute a query on a b-tree 130 | * @sb: filesystem superblock 131 | * @query: the query to execute 132 | * 133 | * Searches the b-tree starting at @query->index in @query->node, looking for 134 | * the record corresponding to @query->key. 135 | * 136 | * Returns 0 in case of success and sets the @query->len, @query->off and 137 | * @query->index fields to the results of the query. @query->node will now 138 | * point to the leaf node holding the record. 139 | * 140 | * In case of failure returns an appropriate error code. 141 | */ 142 | int apfs_btree_query(struct super_block *sb, struct apfs_query **query) 143 | { 144 | struct apfs_sb_info *sbi = APFS_SB(sb); 145 | struct apfs_node *node; 146 | struct apfs_query *parent; 147 | u64 child_id, child_blk; 148 | int err; 149 | 150 | next_node: 151 | if ((*query)->depth >= 12) { 152 | /* 153 | * We need a maximum depth for the tree so we can't loop 154 | * forever if the filesystem is damaged. 12 should be more 155 | * than enough to map every block. 156 | */ 157 | apfs_alert(sb, "b-tree is corrupted"); 158 | return -EFSCORRUPTED; 159 | } 160 | 161 | err = apfs_node_query(sb, *query); 162 | if (err == -EAGAIN) { 163 | if (!(*query)->parent) /* We are at the root of the tree */ 164 | return -ENODATA; 165 | 166 | /* Move back up one level and continue the query */ 167 | parent = (*query)->parent; 168 | (*query)->parent = NULL; /* Don't free the parent */ 169 | apfs_free_query(sb, *query); 170 | *query = parent; 171 | goto next_node; 172 | } 173 | if (err) 174 | return err; 175 | if (apfs_node_is_leaf((*query)->node)) /* All done */ 176 | return 0; 177 | 178 | err = apfs_child_from_query(*query, &child_id); 179 | if (err) { 180 | apfs_alert(sb, "bad index block: 0x%llx", 181 | (*query)->node->object.block_nr); 182 | return err; 183 | } 184 | 185 | /* 186 | * The omap maps a node id into a block number. The nodes 187 | * of the omap itself do not need this translation. 188 | */ 189 | if ((*query)->flags & APFS_QUERY_OMAP) { 190 | child_blk = child_id; 191 | } else { 192 | /* 193 | * we are always performing lookup from omap root. Might 194 | * need improvement in the future. 195 | */ 196 | err = apfs_omap_lookup_block(sb, sbi->s_omap_root, 197 | child_id, &child_blk); 198 | if (err) 199 | return err; 200 | } 201 | 202 | /* Now go a level deeper and search the child */ 203 | node = apfs_read_node(sb, child_blk); 204 | if (IS_ERR(node)) 205 | return PTR_ERR(node); 206 | 207 | if (node->object.oid != child_id) 208 | apfs_debug(sb, "corrupt b-tree"); 209 | 210 | if ((*query)->flags & APFS_QUERY_MULTIPLE) { 211 | /* 212 | * We are looking for multiple entries, so we must remember 213 | * the parent node and index to continue the search later. 214 | */ 215 | *query = apfs_alloc_query(node, *query); 216 | apfs_node_put(node); 217 | } else { 218 | /* Reuse the same query structure to search the child */ 219 | apfs_node_put((*query)->node); 220 | (*query)->node = node; 221 | (*query)->index = node->records; 222 | (*query)->depth++; 223 | } 224 | goto next_node; 225 | } 226 | 227 | /** 228 | * apfs_omap_read_node - Find and read a node from a b-tree 229 | * @id: id for the seeked node 230 | * 231 | * Returns NULL is case of failure, otherwise a pointer to the resulting 232 | * apfs_node structure. 233 | */ 234 | struct apfs_node *apfs_omap_read_node(struct super_block *sb, u64 id) 235 | { 236 | struct apfs_sb_info *sbi = APFS_SB(sb); 237 | struct apfs_node *result; 238 | u64 block; 239 | int err; 240 | 241 | err = apfs_omap_lookup_block(sb, sbi->s_omap_root, id, &block); 242 | if (err) 243 | return ERR_PTR(err); 244 | 245 | result = apfs_read_node(sb, block); 246 | if (IS_ERR(result)) 247 | return result; 248 | 249 | if (result->object.oid != id) 250 | apfs_debug(sb, "corrupt b-tree"); 251 | 252 | return result; 253 | } 254 | -------------------------------------------------------------------------------- /super.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * linux/fs/apfs/super.h 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #ifndef _APFS_SUPER_H 9 | #define _APFS_SUPER_H 10 | 11 | #include 12 | #include 13 | #include "object.h" 14 | 15 | /* 16 | * Structure used to store a range of physical blocks 17 | */ 18 | struct apfs_prange { 19 | __le64 pr_start_paddr; 20 | __le64 pr_block_count; 21 | } __packed; 22 | 23 | /* Main container */ 24 | 25 | /* Container constants */ 26 | #define APFS_SUPER_MAGIC 0x4253584E 27 | 28 | #define APFS_NX_MAGIC APFS_SUPER_MAGIC 29 | #define APFS_NX_BLOCK_NUM 0 30 | #define APFS_NX_MAX_FILE_SYSTEMS 100 31 | 32 | #define APFS_NX_EPH_INFO_COUNT 4 33 | #define APFS_NX_EPH_MIN_BLOCK_COUNT 8 34 | #define APFS_NX_MAX_FILE_SYSTEM_EPH_STRUCTS 4 35 | #define APFS_NX_TX_MIN_CHECKPOINT_COUNT 4 36 | #define APFS_NX_EPH_INFO_VERSION_1 1 37 | 38 | /* Container flags */ 39 | #define APFS_NX_RESERVED_1 0x00000001LL 40 | #define APFS_NX_RESERVED_2 0x00000002LL 41 | #define APFS_NX_CRYPTO_SW 0x00000004LL 42 | 43 | /* Optional container feature flags */ 44 | #define APFS_NX_FEATURE_DEFRAG 0x0000000000000001ULL 45 | #define APFS_NX_FEATURE_LCFD 0x0000000000000002ULL 46 | #define APFS_NX_SUPPORTED_FEATURES_MASK (APFS_NX_FEATURE_DEFRAG | \ 47 | APFS_NX_FEATURE_LCFD) 48 | 49 | /* Read-only compatible container feature flags */ 50 | #define APFS_NX_SUPPORTED_ROCOMPAT_MASK (0x0ULL) 51 | 52 | /* Incompatible container feature flags */ 53 | #define APFS_NX_INCOMPAT_VERSION1 0x0000000000000001ULL 54 | #define APFS_NX_INCOMPAT_VERSION2 0x0000000000000002ULL 55 | #define APFS_NX_INCOMPAT_FUSION 0x0000000000000100ULL 56 | #define APFS_NX_SUPPORTED_INCOMPAT_MASK (APFS_NX_INCOMPAT_VERSION2 \ 57 | | APFS_NX_INCOMPAT_FUSION) 58 | 59 | /* Block and container sizes */ 60 | #define APFS_NX_MINIMUM_BLOCK_SIZE 4096 61 | #define APFS_NX_DEFAULT_BLOCK_SIZE 4096 62 | #define APFS_NX_MAXIMUM_BLOCK_SIZE 65536 63 | #define APFS_NX_MINIMUM_CONTAINER_SIZE 1048576 64 | 65 | /* Indexes into a container superblock's array of counters */ 66 | enum { 67 | APFS_NX_CNTR_OBJ_CKSUM_SET = 0, 68 | APFS_NX_CNTR_OBJ_CKSUM_FAIL = 1, 69 | 70 | APFS_NX_NUM_COUNTERS = 32 71 | }; 72 | 73 | /* 74 | * On-disk representation of the container superblock 75 | */ 76 | struct apfs_nx_superblock { 77 | /*00*/ struct apfs_obj_phys nx_o; 78 | /*20*/ __le32 nx_magic; 79 | __le32 nx_block_size; 80 | __le64 nx_block_count; 81 | 82 | /*30*/ __le64 nx_features; 83 | __le64 nx_readonly_compatible_features; 84 | __le64 nx_incompatible_features; 85 | 86 | /*48*/ char nx_uuid[16]; 87 | 88 | /*58*/ __le64 nx_next_oid; 89 | __le64 nx_next_xid; 90 | 91 | /*68*/ __le32 nx_xp_desc_blocks; 92 | __le32 nx_xp_data_blocks; 93 | /*70*/ __le64 nx_xp_desc_base; 94 | __le64 nx_xp_data_base; 95 | __le32 nx_xp_desc_next; 96 | __le32 nx_xp_data_next; 97 | /*88*/ __le32 nx_xp_desc_index; 98 | __le32 nx_xp_desc_len; 99 | __le32 nx_xp_data_index; 100 | __le32 nx_xp_data_len; 101 | 102 | /*98*/ __le64 nx_spaceman_oid; 103 | __le64 nx_omap_oid; 104 | __le64 nx_reaper_oid; 105 | 106 | /*B0*/ __le32 nx_test_type; 107 | 108 | __le32 nx_max_file_systems; 109 | /*B8*/ __le64 nx_fs_oid[APFS_NX_MAX_FILE_SYSTEMS]; 110 | /*3D8*/ __le64 nx_counters[APFS_NX_NUM_COUNTERS]; 111 | /*4D8*/ struct apfs_prange nx_blocked_out_prange; 112 | __le64 nx_evict_mapping_tree_oid; 113 | /*4F0*/ __le64 nx_flags; 114 | __le64 nx_efi_jumpstart; 115 | /*500*/ char nx_fusion_uuid[16]; 116 | struct apfs_prange nx_keylocker; 117 | /*520*/ __le64 nx_ephemeral_info[APFS_NX_EPH_INFO_COUNT]; 118 | 119 | /*540*/ __le64 nx_test_oid; 120 | 121 | __le64 nx_fusion_mt_oid; 122 | /*550*/ __le64 nx_fusion_wbc_oid; 123 | struct apfs_prange nx_fusion_wbc; 124 | } __packed; 125 | 126 | /* Volume */ 127 | 128 | /* Volume constants */ 129 | #define APFS_MAGIC 0x42535041 130 | 131 | #define APFS_MAX_HIST 8 132 | #define APFS_VOLNAME_LEN 256 133 | 134 | /* Volume flags */ 135 | #define APFS_FS_UNENCRYPTED 0x00000001LL 136 | #define APFS_FS_EFFACEABLE 0x00000002LL 137 | #define APFS_FS_RESERVED_4 0x00000004LL 138 | #define APFS_FS_ONEKEY 0x00000008LL 139 | #define APFS_FS_SPILLEDOVER 0x00000010LL 140 | #define APFS_FS_RUN_SPILLOVER_CLEANER 0x00000020LL 141 | #define APFS_FS_FLAGS_VALID_MASK (APFS_FS_UNENCRYPTED \ 142 | | APFS_FS_EFFACEABLE \ 143 | | APFS_FS_RESERVED_4 \ 144 | | APFS_FS_ONEKEY \ 145 | | APFS_FS_SPILLEDOVER \ 146 | | APFS_FS_RUN_SPILLOVER_CLEANER) 147 | 148 | #define APFS_FS_CRYPTOFLAGS (APFS_FS_UNENCRYPTED \ 149 | | APFS_FS_EFFACEABLE \ 150 | | APFS_FS_ONEKEY) 151 | 152 | /* Optional volume feature flags */ 153 | #define APFS_FEATURE_DEFRAG_PRERELEASE 0x00000001LL 154 | #define APFS_FEATURE_HARDLINK_MAP_RECORDS 0x00000002LL 155 | #define APFS_FEATURE_DEFRAG 0x00000004LL 156 | 157 | #define APFS_SUPPORTED_FEATURES_MASK (APFS_FEATURE_DEFRAG \ 158 | | APFS_FEATURE_DEFRAG_PRERELEASE \ 159 | | APFS_FEATURE_HARDLINK_MAP_RECORDS) 160 | 161 | /* Read-only compatible volume feature flags */ 162 | #define APFS_SUPPORTED_ROCOMPAT_MASK (0x0ULL) 163 | 164 | /* Incompatible volume feature flags */ 165 | #define APFS_INCOMPAT_CASE_INSENSITIVE 0x00000001LL 166 | #define APFS_INCOMPAT_DATALESS_SNAPS 0x00000002LL 167 | #define APFS_INCOMPAT_ENC_ROLLED 0x00000004LL 168 | #define APFS_INCOMPAT_NORMALIZATION_INSENSITIVE 0x00000008LL 169 | 170 | #define APFS_SUPPORTED_INCOMPAT_MASK (APFS_INCOMPAT_CASE_INSENSITIVE \ 171 | | APFS_INCOMPAT_DATALESS_SNAPS \ 172 | | APFS_INCOMPAT_ENC_ROLLED \ 173 | | APFS_INCOMPAT_NORMALIZATION_INSENSITIVE) 174 | 175 | #define APFS_MODIFIED_NAMELEN 32 176 | 177 | /* 178 | * Structure containing information about a program that modified the volume 179 | */ 180 | struct apfs_modified_by { 181 | char id[APFS_MODIFIED_NAMELEN]; 182 | __le64 timestamp; 183 | __le64 last_xid; 184 | } __packed; 185 | 186 | /* 187 | * Structure used to store the encryption state 188 | */ 189 | struct apfs_wrapped_meta_crypto_state { 190 | __le16 major_version; 191 | __le16 minor_version; 192 | __le32 cpflags; 193 | __le32 persistent_class; 194 | __le32 key_os_version; 195 | __le16 key_revision; 196 | __le16 unused; 197 | } __packed; 198 | 199 | /* 200 | * On-disk representation of a volume superblock 201 | */ 202 | struct apfs_superblock { 203 | /*00*/ struct apfs_obj_phys apfs_o; 204 | 205 | /*20*/ __le32 apfs_magic; 206 | __le32 apfs_fs_index; 207 | 208 | /*28*/ __le64 apfs_features; 209 | __le64 apfs_readonly_compatible_features; 210 | __le64 apfs_incompatible_features; 211 | 212 | /*40*/ __le64 apfs_unmount_time; 213 | 214 | __le64 apfs_fs_reserve_block_count; 215 | __le64 apfs_fs_quota_block_count; 216 | __le64 apfs_fs_alloc_count; 217 | 218 | /*60*/ struct apfs_wrapped_meta_crypto_state apfs_meta_crypto; 219 | 220 | /*74*/ __le32 apfs_root_tree_type; 221 | __le32 apfs_extentref_tree_type; 222 | __le32 apfs_snap_meta_tree_type; 223 | 224 | /*80*/ __le64 apfs_omap_oid; 225 | __le64 apfs_root_tree_oid; 226 | __le64 apfs_extentref_tree_oid; 227 | __le64 apfs_snap_meta_tree_oid; 228 | 229 | /*A0*/ __le64 apfs_revert_to_xid; 230 | __le64 apfs_revert_to_sblock_oid; 231 | 232 | /*B0*/ __le64 apfs_next_obj_id; 233 | 234 | /*B8*/ __le64 apfs_num_files; 235 | __le64 apfs_num_directories; 236 | __le64 apfs_num_symlinks; 237 | __le64 apfs_num_other_fsobjects; 238 | __le64 apfs_num_snapshots; 239 | 240 | /*E0*/ __le64 apfs_total_blocks_alloced; 241 | __le64 apfs_total_blocks_freed; 242 | 243 | /*F0*/ char apfs_vol_uuid[16]; 244 | /*100*/ __le64 apfs_last_mod_time; 245 | 246 | __le64 apfs_fs_flags; 247 | 248 | /*110*/ struct apfs_modified_by apfs_formatted_by; 249 | /*140*/ struct apfs_modified_by apfs_modified_by[APFS_MAX_HIST]; 250 | 251 | /*2C0*/ u8 apfs_volname[APFS_VOLNAME_LEN]; 252 | /*3C0*/ __le32 apfs_next_doc_id; 253 | 254 | __le16 apfs_role; 255 | __le16 reserved; 256 | 257 | /*3C8*/ __le64 apfs_root_to_xid; 258 | __le64 apfs_er_state_oid; 259 | } __packed; 260 | 261 | /* Mount option flags */ 262 | #define APFS_UID_OVERRIDE 1 263 | #define APFS_GID_OVERRIDE 2 264 | #define APFS_CHECK_NODES 4 265 | 266 | /* 267 | * Superblock data in memory, both from the main superblock and the volume 268 | * checkpoint superblock. 269 | */ 270 | struct apfs_sb_info { 271 | struct apfs_nx_superblock *s_msb_raw; /* On-disk main sb */ 272 | struct apfs_superblock *s_vsb_raw; /* On-disk volume sb */ 273 | 274 | u64 s_xid; /* Latest transaction id */ 275 | struct apfs_node *s_cat_root; /* Root of the catalog tree */ 276 | struct apfs_node *s_omap_root; /* Root of the object map tree */ 277 | 278 | struct apfs_object s_mobject; /* Main superblock object */ 279 | struct apfs_object s_vobject; /* Volume superblock object */ 280 | 281 | /* Mount options */ 282 | unsigned int s_flags; 283 | unsigned int s_vol_nr; /* Index of the volume in the sb list */ 284 | kuid_t s_uid; /* uid to override on-disk uid */ 285 | kgid_t s_gid; /* gid to override on-disk gid */ 286 | 287 | /* TODO: handle block sizes above the maximum of PAGE_SIZE? */ 288 | unsigned long s_blocksize; 289 | unsigned char s_blocksize_bits; 290 | }; 291 | 292 | static inline struct apfs_sb_info *APFS_SB(struct super_block *sb) 293 | { 294 | return sb->s_fs_info; 295 | } 296 | 297 | static inline bool apfs_is_case_insensitive(struct super_block *sb) 298 | { 299 | return (APFS_SB(sb)->s_vsb_raw->apfs_incompatible_features & 300 | cpu_to_le64(APFS_INCOMPAT_CASE_INSENSITIVE)) != 0; 301 | } 302 | 303 | #endif /* _APFS_SUPER_H */ 304 | -------------------------------------------------------------------------------- /xattr.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * linux/fs/apfs/xattr.c 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #include 9 | #include 10 | #include "apfs.h" 11 | #include "btree.h" 12 | #include "extents.h" 13 | #include "key.h" 14 | #include "super.h" 15 | #include "node.h" 16 | #include "message.h" 17 | #include "xattr.h" 18 | 19 | /** 20 | * apfs_xattr_from_query - Read the xattr record found by a successful query 21 | * @query: the query that found the record 22 | * @xattr: Return parameter. The xattr record found. 23 | * 24 | * Reads the xattr record into @xattr and performs some basic sanity checks 25 | * as a protection against crafted filesystems. Returns 0 on success or 26 | * -EFSCORRUPTED otherwise. 27 | * 28 | * The caller must not free @query while @xattr is in use, because @xattr->name 29 | * and @xattr->xdata point to data on disk. 30 | */ 31 | static int apfs_xattr_from_query(struct apfs_query *query, 32 | struct apfs_xattr *xattr) 33 | { 34 | struct apfs_xattr_val *xattr_val; 35 | struct apfs_xattr_key *xattr_key; 36 | char *raw = query->node->object.bh->b_data; 37 | int datalen = query->len - sizeof(*xattr_val); 38 | int namelen = query->key_len - sizeof(*xattr_key); 39 | 40 | if (namelen < 1 || datalen < 0) 41 | return -EFSCORRUPTED; 42 | 43 | xattr_val = (struct apfs_xattr_val *)(raw + query->off); 44 | xattr_key = (struct apfs_xattr_key *)(raw + query->key_off); 45 | 46 | if (namelen != le16_to_cpu(xattr_key->name_len)) 47 | return -EFSCORRUPTED; 48 | 49 | /* The xattr name must be NULL-terminated */ 50 | if (xattr_key->name[namelen - 1] != 0) 51 | return -EFSCORRUPTED; 52 | 53 | xattr->has_dstream = le16_to_cpu(xattr_val->flags) & 54 | APFS_XATTR_DATA_STREAM; 55 | 56 | if (xattr->has_dstream && datalen != sizeof(struct apfs_xattr_dstream)) 57 | return -EFSCORRUPTED; 58 | if (!xattr->has_dstream && datalen != le16_to_cpu(xattr_val->xdata_len)) 59 | return -EFSCORRUPTED; 60 | 61 | xattr->name = xattr_key->name; 62 | xattr->name_len = namelen - 1; /* Don't count the NULL termination */ 63 | xattr->xdata = xattr_val->xdata; 64 | xattr->xdata_len = datalen; 65 | return 0; 66 | } 67 | 68 | /** 69 | * apfs_xattr_extents_read - Read the value of a xattr from its extents 70 | * @parent: inode the attribute belongs to 71 | * @xattr: the xattr structure 72 | * @buffer: where to copy the attribute value 73 | * @size: size of @buffer 74 | * 75 | * Copies the value of @xattr to @buffer, if provided. If @buffer is NULL, just 76 | * computes the size of the buffer required. 77 | * 78 | * Returns the number of bytes used/required, or a negative error code in case 79 | * of failure. 80 | */ 81 | static int apfs_xattr_extents_read(struct inode *parent, 82 | struct apfs_xattr *xattr, 83 | void *buffer, size_t size) 84 | { 85 | struct super_block *sb = parent->i_sb; 86 | struct apfs_sb_info *sbi = APFS_SB(sb); 87 | struct apfs_key key; 88 | struct apfs_query *query; 89 | struct apfs_xattr_dstream *xdata; 90 | u64 extent_id; 91 | int length; 92 | int ret; 93 | int i; 94 | 95 | xdata = (struct apfs_xattr_dstream *) xattr->xdata; 96 | length = le64_to_cpu(xdata->dstream.size); 97 | if (length < 0 || length < le64_to_cpu(xdata->dstream.size)) 98 | return -E2BIG; 99 | 100 | if (!buffer) /* All we want is the length */ 101 | return length; 102 | if (length > size) /* xattr won't fit in the buffer */ 103 | return -ERANGE; 104 | 105 | extent_id = le64_to_cpu(xdata->xattr_obj_id); 106 | /* We will read all the extents, starting with the last one */ 107 | apfs_init_file_extent_key(extent_id, 0 /* offset */, &key); 108 | 109 | query = apfs_alloc_query(sbi->s_cat_root, NULL /* parent */); 110 | if (!query) 111 | return -ENOMEM; 112 | query->key = &key; 113 | query->flags = APFS_QUERY_CAT | APFS_QUERY_MULTIPLE | APFS_QUERY_EXACT; 114 | 115 | /* 116 | * The logic in this loop would allow a crafted filesystem with a large 117 | * number of redundant extents to become stuck for a long time. We use 118 | * the xattr length to put a limit on the number of iterations. 119 | */ 120 | ret = -EFSCORRUPTED; 121 | for (i = 0; i < (length >> parent->i_blkbits) + 2; i++) { 122 | struct apfs_file_extent ext; 123 | u64 block_count, file_off; 124 | int err; 125 | int j; 126 | 127 | err = apfs_btree_query(sb, &query); 128 | if (err == -ENODATA) { /* No more records to search */ 129 | ret = length; 130 | goto done; 131 | } 132 | if (err) { 133 | ret = err; 134 | goto done; 135 | } 136 | 137 | err = apfs_extent_from_query(query, &ext); 138 | if (err) { 139 | apfs_alert(sb, "bad extent for xattr in inode 0x%llx", 140 | (unsigned long long) parent->i_ino); 141 | ret = err; 142 | goto done; 143 | } 144 | 145 | block_count = ext.len >> sb->s_blocksize_bits; 146 | file_off = ext.logical_addr; 147 | for (j = 0; j < block_count; ++j) { 148 | struct buffer_head *bh; 149 | int bytes; 150 | 151 | if (length <= file_off) /* Read the whole extent */ 152 | break; 153 | bytes = min(sb->s_blocksize, 154 | (unsigned long)(length - file_off)); 155 | 156 | bh = sb_bread(sb, ext.phys_block_num + j); 157 | if (!bh) { 158 | ret = -EIO; 159 | goto done; 160 | } 161 | memcpy(buffer + file_off, bh->b_data, bytes); 162 | brelse(bh); 163 | file_off = file_off + bytes; 164 | } 165 | } 166 | 167 | done: 168 | apfs_free_query(sb, query); 169 | return ret; 170 | } 171 | 172 | /** 173 | * apfs_xattr_inline_read - Read the value of an inline xattr 174 | * @parent: inode the attribute belongs to 175 | * @xattr: the xattr structure 176 | * @buffer: where to copy the attribute value 177 | * @size: size of @buffer 178 | * 179 | * Copies the inline value of @xattr to @buffer, if provided. If @buffer is 180 | * NULL, just computes the size of the buffer required. 181 | * 182 | * Returns the number of bytes used/required, or a negative error code in case 183 | * of failure. 184 | */ 185 | static int apfs_xattr_inline_read(struct inode *parent, 186 | struct apfs_xattr *xattr, 187 | void *buffer, size_t size) 188 | { 189 | int length = xattr->xdata_len; 190 | 191 | if (!buffer) /* All we want is the length */ 192 | return length; 193 | if (length > size) /* xattr won't fit in the buffer */ 194 | return -ERANGE; 195 | memcpy(buffer, xattr->xdata, length); 196 | return length; 197 | } 198 | 199 | /** 200 | * apfs_xattr_get - Find and read a named attribute 201 | * @inode: inode the attribute belongs to 202 | * @name: name of the attribute 203 | * @buffer: where to copy the attribute value 204 | * @size: size of @buffer 205 | * 206 | * Finds an extended attribute and copies its value to @buffer, if provided. If 207 | * @buffer is NULL, just computes the size of the buffer required. 208 | * 209 | * Returns the number of bytes used/required, or a negative error code in case 210 | * of failure. 211 | */ 212 | int apfs_xattr_get(struct inode *inode, const char *name, void *buffer, 213 | size_t size) 214 | { 215 | struct super_block *sb = inode->i_sb; 216 | struct apfs_sb_info *sbi = APFS_SB(sb); 217 | struct apfs_key key; 218 | struct apfs_query *query; 219 | struct apfs_xattr xattr; 220 | u64 cnid = inode->i_ino; 221 | int ret; 222 | 223 | apfs_init_xattr_key(cnid, name, &key); 224 | 225 | query = apfs_alloc_query(sbi->s_cat_root, NULL /* parent */); 226 | if (!query) 227 | return -ENOMEM; 228 | query->key = &key; 229 | query->flags |= APFS_QUERY_CAT | APFS_QUERY_EXACT; 230 | 231 | ret = apfs_btree_query(sb, &query); 232 | if (ret) 233 | goto done; 234 | 235 | ret = apfs_xattr_from_query(query, &xattr); 236 | if (ret) { 237 | apfs_alert(sb, "bad xattr record in inode 0x%llx", cnid); 238 | goto done; 239 | } 240 | 241 | if (xattr.has_dstream) 242 | ret = apfs_xattr_extents_read(inode, &xattr, buffer, size); 243 | else 244 | ret = apfs_xattr_inline_read(inode, &xattr, buffer, size); 245 | 246 | done: 247 | apfs_free_query(sb, query); 248 | return ret; 249 | } 250 | 251 | static int apfs_xattr_osx_get(const struct xattr_handler *handler, 252 | struct dentry *unused, struct inode *inode, 253 | const char *name, void *buffer, size_t size) 254 | { 255 | /* Ignore the fake 'osx' prefix */ 256 | return apfs_xattr_get(inode, name, buffer, size); 257 | } 258 | 259 | static const struct xattr_handler apfs_xattr_osx_handler = { 260 | .prefix = XATTR_MAC_OSX_PREFIX, 261 | .get = apfs_xattr_osx_get, 262 | }; 263 | 264 | /* On-disk xattrs have no namespace; use a fake 'osx' prefix in the kernel */ 265 | const struct xattr_handler *apfs_xattr_handlers[] = { 266 | &apfs_xattr_osx_handler, 267 | NULL 268 | }; 269 | 270 | ssize_t apfs_listxattr(struct dentry *dentry, char *buffer, size_t size) 271 | { 272 | struct inode *inode = d_inode(dentry); 273 | struct super_block *sb = inode->i_sb; 274 | struct apfs_sb_info *sbi = APFS_SB(sb); 275 | struct apfs_key key; 276 | struct apfs_query *query; 277 | u64 cnid = inode->i_ino; 278 | size_t free = size; 279 | ssize_t ret; 280 | 281 | query = apfs_alloc_query(sbi->s_cat_root, NULL /* parent */); 282 | if (!query) 283 | return -ENOMEM; 284 | 285 | /* We want all the xattrs for the cnid, regardless of the name */ 286 | apfs_init_xattr_key(cnid, NULL /* name */, &key); 287 | query->key = &key; 288 | query->flags = APFS_QUERY_CAT | APFS_QUERY_MULTIPLE | APFS_QUERY_EXACT; 289 | 290 | while (1) { 291 | struct apfs_xattr xattr; 292 | 293 | ret = apfs_btree_query(sb, &query); 294 | if (ret == -ENODATA) { /* Got all the xattrs */ 295 | ret = size - free; 296 | break; 297 | } 298 | if (ret) 299 | break; 300 | 301 | ret = apfs_xattr_from_query(query, &xattr); 302 | if (ret) { 303 | apfs_alert(sb, "bad xattr key in inode %llx", cnid); 304 | break; 305 | } 306 | 307 | if (buffer) { 308 | /* Prepend the fake 'osx' prefix before listing */ 309 | if (xattr.name_len + XATTR_MAC_OSX_PREFIX_LEN + 1 > 310 | free) { 311 | ret = -ERANGE; 312 | break; 313 | } 314 | memcpy(buffer, XATTR_MAC_OSX_PREFIX, 315 | XATTR_MAC_OSX_PREFIX_LEN); 316 | buffer += XATTR_MAC_OSX_PREFIX_LEN; 317 | memcpy(buffer, xattr.name, xattr.name_len + 1); 318 | buffer += xattr.name_len + 1; 319 | } 320 | free -= xattr.name_len + XATTR_MAC_OSX_PREFIX_LEN + 1; 321 | } 322 | 323 | apfs_free_query(sb, query); 324 | return ret; 325 | } 326 | -------------------------------------------------------------------------------- /inode.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * linux/fs/apfs/inode.c 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "apfs.h" 13 | #include "btree.h" 14 | #include "dir.h" 15 | #include "extents.h" 16 | #include "inode.h" 17 | #include "key.h" 18 | #include "message.h" 19 | #include "node.h" 20 | #include "super.h" 21 | #include "xattr.h" 22 | 23 | static int apfs_readpage(struct file *file, struct page *page) 24 | { 25 | return mpage_readpage(page, apfs_get_block); 26 | } 27 | 28 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) /* Misses mpage_readpages() */ 29 | 30 | static void apfs_readahead(struct readahead_control *rac) 31 | { 32 | mpage_readahead(rac, apfs_get_block); 33 | } 34 | 35 | #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) */ 36 | 37 | static int apfs_readpages(struct file *file, struct address_space *mapping, 38 | struct list_head *pages, unsigned int nr_pages) 39 | { 40 | return mpage_readpages(mapping, pages, nr_pages, apfs_get_block); 41 | } 42 | 43 | #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) */ 44 | 45 | static sector_t apfs_bmap(struct address_space *mapping, sector_t block) 46 | { 47 | return generic_block_bmap(mapping, block, apfs_get_block); 48 | } 49 | 50 | static const struct address_space_operations apfs_aops = { 51 | .readpage = apfs_readpage, 52 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) 53 | .readahead = apfs_readahead, 54 | #else 55 | .readpages = apfs_readpages, 56 | #endif 57 | .bmap = apfs_bmap, 58 | }; 59 | 60 | /** 61 | * apfs_inode_from_query - Read the inode found by a successful query 62 | * @query: the query that found the record 63 | * @inode: vfs inode to be filled with the read data 64 | * 65 | * Reads the inode record into @inode and performs some basic sanity checks, 66 | * mostly as a protection against crafted filesystems. Returns 0 on success 67 | * or a negative error code otherwise. 68 | */ 69 | static int apfs_inode_from_query(struct apfs_query *query, struct inode *inode) 70 | { 71 | struct apfs_inode_info *ai = APFS_I(inode); 72 | struct apfs_inode_val *inode_val; 73 | struct apfs_dstream *dstream = NULL; 74 | struct apfs_xf_blob *xblob; 75 | struct apfs_x_field *xfield; 76 | char *raw = query->node->object.bh->b_data; 77 | int rest, i; 78 | u64 secs; 79 | 80 | if (query->len < sizeof(*inode_val)) 81 | return -EFSCORRUPTED; 82 | 83 | inode_val = (struct apfs_inode_val *)(raw + query->off); 84 | 85 | ai->i_extent_id = le64_to_cpu(inode_val->private_id); 86 | inode->i_mode = le16_to_cpu(inode_val->mode); 87 | i_uid_write(inode, (uid_t)le32_to_cpu(inode_val->owner)); 88 | i_gid_write(inode, (gid_t)le32_to_cpu(inode_val->group)); 89 | 90 | if (S_ISREG(inode->i_mode) || S_ISLNK(inode->i_mode)) { 91 | /* 92 | * It seems that hard links are only allowed for regular files, 93 | * and perhaps for symlinks. 94 | * 95 | * Directory inodes don't store their link count, so to provide 96 | * it we would have to actually count the subdirectories. The 97 | * HFS/HFS+ modules just leave it at 1, and so do we, for now. 98 | */ 99 | set_nlink(inode, le32_to_cpu(inode_val->nlink)); 100 | } 101 | 102 | /* APFS stores the time as unsigned nanoseconds since the epoch */ 103 | secs = le64_to_cpu(inode_val->access_time); 104 | inode->i_atime.tv_nsec = do_div(secs, NSEC_PER_SEC); 105 | inode->i_atime.tv_sec = secs; 106 | secs = le64_to_cpu(inode_val->change_time); 107 | inode->i_ctime.tv_nsec = do_div(secs, NSEC_PER_SEC); 108 | inode->i_ctime.tv_sec = secs; 109 | secs = le64_to_cpu(inode_val->mod_time); 110 | inode->i_mtime.tv_nsec = do_div(secs, NSEC_PER_SEC); 111 | inode->i_mtime.tv_sec = secs; 112 | secs = le64_to_cpu(inode_val->create_time); 113 | ai->i_crtime.tv_nsec = do_div(secs, NSEC_PER_SEC); 114 | ai->i_crtime.tv_sec = secs; 115 | 116 | xblob = (struct apfs_xf_blob *) inode_val->xfields; 117 | xfield = (struct apfs_x_field *) xblob->xf_data; 118 | rest = query->len - (sizeof(*inode_val) + sizeof(*xblob)); 119 | rest -= le16_to_cpu(xblob->xf_num_exts) * sizeof(xfield[0]); 120 | if (rest < 0) 121 | return -EFSCORRUPTED; 122 | for (i = 0; i < le16_to_cpu(xblob->xf_num_exts); ++i) { 123 | int attrlen; 124 | 125 | /* Attribute length is padded to a multiple of 8 */ 126 | attrlen = round_up(le16_to_cpu(xfield[i].x_size), 8); 127 | if (attrlen > rest) 128 | break; 129 | if (xfield[i].x_type == APFS_INO_EXT_TYPE_DSTREAM) { 130 | /* The only optional attr we care about, for now */ 131 | dstream = (struct apfs_dstream *) 132 | ((char *)inode_val + query->len - rest); 133 | break; 134 | } 135 | rest -= attrlen; 136 | } 137 | 138 | if (dstream) { 139 | inode->i_size = le64_to_cpu(dstream->size); 140 | inode->i_blocks = le64_to_cpu(dstream->alloced_size) >> 9; 141 | } else { 142 | /* 143 | * This inode is "empty", but it may actually hold compressed 144 | * data in the named attribute com.apple.decmpfs, and sometimes 145 | * in com.apple.ResourceFork 146 | */ 147 | inode->i_size = inode->i_blocks = 0; 148 | } 149 | 150 | return 0; 151 | } 152 | 153 | /** 154 | * apfs_inode_lookup - Lookup an inode record in the b-tree and read its data 155 | * @inode: vfs inode to lookup and fill 156 | * 157 | * Queries the b-tree for the @inode->i_ino inode record and reads its data to 158 | * @inode. Returns 0 on success or a negative error code otherwise. 159 | */ 160 | static int apfs_inode_lookup(struct inode *inode) 161 | { 162 | struct super_block *sb = inode->i_sb; 163 | struct apfs_sb_info *sbi = APFS_SB(sb); 164 | struct apfs_key key; 165 | struct apfs_query *query; 166 | u64 cnid = inode->i_ino; 167 | int ret; 168 | 169 | apfs_init_inode_key(cnid, &key); 170 | 171 | query = apfs_alloc_query(sbi->s_cat_root, NULL /* parent */); 172 | if (!query) 173 | return -ENOMEM; 174 | query->key = &key; 175 | query->flags |= APFS_QUERY_CAT | APFS_QUERY_EXACT; 176 | 177 | ret = apfs_btree_query(sb, &query); 178 | if (ret) 179 | goto done; 180 | 181 | ret = apfs_inode_from_query(query, inode); 182 | if (ret) 183 | apfs_alert(sb, "bad inode record for inode 0x%llx", cnid); 184 | 185 | done: 186 | apfs_free_query(sb, query); 187 | return ret; 188 | } 189 | 190 | #if BITS_PER_LONG == 64 191 | #define apfs_iget_locked iget_locked 192 | #else /* 64-bit inode numbers may not fit in the vfs inode */ 193 | 194 | /** 195 | * apfs_test_inode - Check if the inode matches a 64-bit inode number 196 | * @inode: inode to test 197 | * @cnid: pointer to the inode number 198 | */ 199 | static int apfs_test_inode(struct inode *inode, void *cnid) 200 | { 201 | struct apfs_inode_info *ai = APFS_I(inode); 202 | u64 *ino = cnid; 203 | 204 | return ai->i_ino == *ino; 205 | } 206 | 207 | /** 208 | * apfs_set_inode - Set a 64-bit inode number on the given inode 209 | * @inode: inode to set 210 | * @cnid: pointer to the inode number 211 | */ 212 | static int apfs_set_inode(struct inode *inode, void *cnid) 213 | { 214 | struct apfs_inode_info *ai = APFS_I(inode); 215 | u64 *ino = cnid; 216 | 217 | ai->i_ino = *ino; 218 | inode->i_ino = *ino; /* Just discard the higher bits here... */ 219 | return 0; 220 | } 221 | 222 | /** 223 | * apfs_iget_locked - Wrapper for iget5_locked() 224 | * @sb: filesystem superblock 225 | * @cnid: 64-bit inode number 226 | * 227 | * Works the same as iget_locked(), but supports 64-bit inode numbers. 228 | */ 229 | static struct inode *apfs_iget_locked(struct super_block *sb, u64 cnid) 230 | { 231 | return iget5_locked(sb, cnid, apfs_test_inode, apfs_set_inode, &cnid); 232 | } 233 | 234 | #endif /* BITS_PER_LONG == 64 */ 235 | 236 | /** 237 | * apfs_iget - Populate inode structures with metadata from disk 238 | * @sb: filesystem superblock 239 | * @cnid: inode number 240 | * 241 | * Populates the vfs inode and the corresponding apfs_inode_info structure. 242 | * Returns a pointer to the vfs inode in case of success, or an appropriate 243 | * error pointer otherwise. 244 | */ 245 | struct inode *apfs_iget(struct super_block *sb, u64 cnid) 246 | { 247 | struct apfs_sb_info *sbi = APFS_SB(sb); 248 | struct inode *inode; 249 | int err; 250 | 251 | inode = apfs_iget_locked(sb, cnid); 252 | if (!inode) 253 | return ERR_PTR(-ENOMEM); 254 | if (!(inode->i_state & I_NEW)) 255 | return inode; 256 | 257 | err = apfs_inode_lookup(inode); 258 | if (err) { 259 | iget_failed(inode); 260 | return ERR_PTR(err); 261 | } 262 | 263 | /* Allow the user to override the ownership */ 264 | if (sbi->s_flags & APFS_UID_OVERRIDE) 265 | inode->i_uid = sbi->s_uid; 266 | if (sbi->s_flags & APFS_GID_OVERRIDE) 267 | inode->i_gid = sbi->s_gid; 268 | 269 | /* A lot of operations still missing, of course */ 270 | if (S_ISREG(inode->i_mode)) { 271 | inode->i_op = &apfs_file_inode_operations; 272 | inode->i_fop = &apfs_file_operations; 273 | inode->i_mapping->a_ops = &apfs_aops; 274 | } else if (S_ISDIR(inode->i_mode)) { 275 | inode->i_op = &apfs_dir_inode_operations; 276 | inode->i_fop = &apfs_dir_operations; 277 | } else if (S_ISLNK(inode->i_mode)) { 278 | inode->i_op = &apfs_symlink_inode_operations; 279 | } else { 280 | inode->i_op = &apfs_special_inode_operations; 281 | } 282 | 283 | /* Inode flags are not important for now, leave them at 0 */ 284 | unlock_new_inode(inode); 285 | return inode; 286 | } 287 | 288 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) /* No statx yet... */ 289 | 290 | int apfs_getattr(struct vfsmount *mnt, struct dentry *dentry, 291 | struct kstat *stat) 292 | { 293 | struct inode *inode = d_inode(dentry); 294 | 295 | generic_fillattr(inode, stat); 296 | #if BITS_PER_LONG == 32 297 | stat->ino = ai->i_ino; 298 | #endif /* BITS_PER_LONG == 32 */ 299 | return 0; 300 | } 301 | 302 | #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) */ 303 | 304 | int apfs_getattr(const struct path *path, struct kstat *stat, 305 | u32 request_mask, unsigned int query_flags) 306 | { 307 | struct inode *inode = d_inode(path->dentry); 308 | struct apfs_inode_info *ai = APFS_I(inode); 309 | 310 | stat->result_mask |= STATX_BTIME; 311 | stat->btime = ai->i_crtime; 312 | 313 | if (apfs_xattr_get(inode, APFS_XATTR_NAME_COMPRESSED, NULL, 0) >= 0) 314 | stat->attributes |= STATX_ATTR_COMPRESSED; 315 | 316 | stat->attributes_mask |= STATX_ATTR_COMPRESSED; 317 | 318 | generic_fillattr(inode, stat); 319 | #if BITS_PER_LONG == 32 320 | stat->ino = ai->i_ino; 321 | #endif /* BITS_PER_LONG == 32 */ 322 | return 0; 323 | } 324 | 325 | #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) */ 326 | -------------------------------------------------------------------------------- /node.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * linux/fs/apfs/node.c 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #include 9 | #include 10 | #include "apfs.h" 11 | #include "btree.h" 12 | #include "key.h" 13 | #include "message.h" 14 | #include "node.h" 15 | #include "object.h" 16 | #include "super.h" 17 | 18 | /** 19 | * apfs_node_is_valid - Check basic sanity of the node index 20 | * @sb: filesystem superblock 21 | * @node: node to check 22 | * 23 | * Verifies that the node index fits in a single block, and that the number 24 | * of records fits in the index. Without this check a crafted filesystem could 25 | * pretend to have too many records, and calls to apfs_node_locate_key() and 26 | * apfs_node_locate_data() would read beyond the limits of the node. 27 | */ 28 | static bool apfs_node_is_valid(struct super_block *sb, 29 | struct apfs_node *node) 30 | { 31 | int records = node->records; 32 | int index_size = node->key - sizeof(struct apfs_btree_node_phys); 33 | int entry_size; 34 | 35 | if (!records) /* Empty nodes could keep a multiple query spinning */ 36 | return false; 37 | 38 | if (node->key > sb->s_blocksize) 39 | return false; 40 | 41 | entry_size = (apfs_node_has_fixed_kv_size(node)) ? 42 | sizeof(struct apfs_kvoff) : sizeof(struct apfs_kvloc); 43 | 44 | return records * entry_size <= index_size; 45 | } 46 | 47 | static void apfs_node_release(struct kref *kref) 48 | { 49 | struct apfs_node *node = 50 | container_of(kref, struct apfs_node, refcount); 51 | 52 | brelse(node->object.bh); 53 | kfree(node); 54 | } 55 | 56 | void apfs_node_get(struct apfs_node *node) 57 | { 58 | kref_get(&node->refcount); 59 | } 60 | 61 | void apfs_node_put(struct apfs_node *node) 62 | { 63 | kref_put(&node->refcount, apfs_node_release); 64 | } 65 | 66 | /** 67 | * apfs_read_node - Read a node header from disk 68 | * @sb: filesystem superblock 69 | * @block: number of the block where the node is stored 70 | * 71 | * Returns ERR_PTR in case of failure, otherwise return a pointer to the 72 | * resulting apfs_node structure with the initial reference taken. 73 | * 74 | * For now we assume the node has not been read before. 75 | */ 76 | struct apfs_node *apfs_read_node(struct super_block *sb, u64 block) 77 | { 78 | struct apfs_sb_info *sbi = APFS_SB(sb); 79 | struct buffer_head *bh; 80 | struct apfs_btree_node_phys *raw; 81 | struct apfs_node *node; 82 | 83 | bh = sb_bread(sb, block); 84 | if (!bh) { 85 | apfs_err(sb, "unable to read node"); 86 | return ERR_PTR(-EINVAL); 87 | } 88 | raw = (struct apfs_btree_node_phys *) bh->b_data; 89 | 90 | node = kmalloc(sizeof(*node), GFP_KERNEL); 91 | if (!node) { 92 | brelse(bh); 93 | return ERR_PTR(-ENOMEM); 94 | } 95 | 96 | node->flags = le16_to_cpu(raw->btn_flags); 97 | node->records = le32_to_cpu(raw->btn_nkeys); 98 | node->key = sizeof(*raw) + le16_to_cpu(raw->btn_table_space.off) 99 | + le16_to_cpu(raw->btn_table_space.len); 100 | node->free = node->key + le16_to_cpu(raw->btn_free_space.off); 101 | node->data = node->free + le16_to_cpu(raw->btn_free_space.len); 102 | 103 | node->object.sb = sb; 104 | node->object.block_nr = block; 105 | node->object.oid = le64_to_cpu(raw->btn_o.o_oid); 106 | node->object.bh = bh; 107 | 108 | kref_init(&node->refcount); 109 | 110 | if (sbi->s_flags & APFS_CHECK_NODES && 111 | !apfs_obj_verify_csum(sb, &raw->btn_o)) { 112 | apfs_alert(sb, "bad checksum for node in block 0x%llx", block); 113 | apfs_node_put(node); 114 | return ERR_PTR(-EFSBADCRC); 115 | } 116 | if (!apfs_node_is_valid(sb, node)) { 117 | apfs_alert(sb, "bad node in block 0x%llx", block); 118 | apfs_node_put(node); 119 | return ERR_PTR(-EFSCORRUPTED); 120 | } 121 | 122 | return node; 123 | } 124 | 125 | /** 126 | * apfs_node_locate_key - Locate the key of a node record 127 | * @node: node to be searched 128 | * @index: number of the entry to locate 129 | * @off: on return will hold the offset in the block 130 | * 131 | * Returns the length of the key, or 0 in case of failure. The function checks 132 | * that this length fits within the block; callers must use the returned value 133 | * to make sure they never operate outside its bounds. 134 | */ 135 | static int apfs_node_locate_key(struct apfs_node *node, int index, int *off) 136 | { 137 | struct super_block *sb = node->object.sb; 138 | struct apfs_btree_node_phys *raw; 139 | int len; 140 | 141 | if (index >= node->records) 142 | return 0; 143 | 144 | raw = (struct apfs_btree_node_phys *)node->object.bh->b_data; 145 | if (apfs_node_has_fixed_kv_size(node)) { 146 | struct apfs_kvoff *entry; 147 | 148 | entry = (struct apfs_kvoff *)raw->btn_data + index; 149 | len = 16; 150 | /* Translate offset in key area to offset in block */ 151 | *off = node->key + le16_to_cpu(entry->k); 152 | } else { 153 | /* These node types have variable length keys and data */ 154 | struct apfs_kvloc *entry; 155 | 156 | entry = (struct apfs_kvloc *)raw->btn_data + index; 157 | len = le16_to_cpu(entry->k.len); 158 | /* Translate offset in key area to offset in block */ 159 | *off = node->key + le16_to_cpu(entry->k.off); 160 | } 161 | 162 | if (*off + len > sb->s_blocksize) { 163 | /* Avoid out-of-bounds read if corrupted */ 164 | return 0; 165 | } 166 | return len; 167 | } 168 | 169 | /** 170 | * apfs_node_locate_data - Locate the data of a node record 171 | * @node: node to be searched 172 | * @index: number of the entry to locate 173 | * @off: on return will hold the offset in the block 174 | * 175 | * Returns the length of the data, or 0 in case of failure. The function checks 176 | * that this length fits within the block; callers must use the returned value 177 | * to make sure they never operate outside its bounds. 178 | */ 179 | static int apfs_node_locate_data(struct apfs_node *node, int index, int *off) 180 | { 181 | struct super_block *sb = node->object.sb; 182 | struct apfs_btree_node_phys *raw; 183 | int len; 184 | 185 | if (index >= node->records) 186 | return 0; 187 | 188 | raw = (struct apfs_btree_node_phys *)node->object.bh->b_data; 189 | if (apfs_node_has_fixed_kv_size(node)) { 190 | /* These node types have fixed length keys and data */ 191 | struct apfs_kvoff *entry; 192 | 193 | entry = (struct apfs_kvoff *)raw->btn_data + index; 194 | /* Node type decides length */ 195 | len = apfs_node_is_leaf(node) ? 16 : 8; 196 | /* 197 | * Data offsets are counted backwards from the end of the 198 | * block, or from the beginning of the footer when it exists 199 | */ 200 | if (apfs_node_is_root(node)) /* has footer */ 201 | *off = sb->s_blocksize - sizeof(struct apfs_btree_info) 202 | - le16_to_cpu(entry->v); 203 | else 204 | *off = sb->s_blocksize - le16_to_cpu(entry->v); 205 | } else { 206 | /* These node types have variable length keys and data */ 207 | struct apfs_kvloc *entry; 208 | 209 | entry = (struct apfs_kvloc *)raw->btn_data + index; 210 | len = le16_to_cpu(entry->v.len); 211 | /* 212 | * Data offsets are counted backwards from the end of the 213 | * block, or from the beginning of the footer when it exists 214 | */ 215 | if (apfs_node_is_root(node)) /* has footer */ 216 | *off = sb->s_blocksize - sizeof(struct apfs_btree_info) 217 | - le16_to_cpu(entry->v.off); 218 | else 219 | *off = sb->s_blocksize - le16_to_cpu(entry->v.off); 220 | } 221 | 222 | if (*off < 0 || *off + len > sb->s_blocksize) { 223 | /* Avoid out-of-bounds read if corrupted */ 224 | return 0; 225 | } 226 | return len; 227 | } 228 | 229 | /** 230 | * apfs_key_from_query - Read the current key from a query structure 231 | * @query: the query, with @query->key_off and @query->key_len already set 232 | * @key: return parameter for the key 233 | * 234 | * Reads the key into @key and performs some basic sanity checks as a 235 | * protection against crafted filesystems. Returns 0 on success or a 236 | * negative error code otherwise. 237 | */ 238 | static int apfs_key_from_query(struct apfs_query *query, struct apfs_key *key) 239 | { 240 | struct super_block *sb = query->node->object.sb; 241 | char *raw = query->node->object.bh->b_data; 242 | void *raw_key = (void *)(raw + query->key_off); 243 | int err = 0; 244 | 245 | switch (query->flags & APFS_QUERY_TREE_MASK) { 246 | case APFS_QUERY_CAT: 247 | err = apfs_read_cat_key(raw_key, query->key_len, key); 248 | break; 249 | case APFS_QUERY_OMAP: 250 | err = apfs_read_omap_key(raw_key, query->key_len, key); 251 | break; 252 | default: 253 | /* Not implemented yet */ 254 | err = -EINVAL; 255 | break; 256 | } 257 | if (err) { 258 | apfs_alert(sb, "bad node key in block 0x%llx", 259 | query->node->object.block_nr); 260 | } 261 | 262 | /* A multiple query must ignore some of these fields */ 263 | if (query->flags & APFS_QUERY_ANY_NAME) 264 | key->name = NULL; 265 | if (query->flags & APFS_QUERY_ANY_NUMBER) 266 | key->number = 0; 267 | 268 | return err; 269 | } 270 | 271 | /** 272 | * apfs_node_next - Find the next matching record in the current node 273 | * @sb: filesystem superblock 274 | * @query: multiple query in execution 275 | * 276 | * Returns 0 on success, -EAGAIN if the next record is in another node, 277 | * -ENODATA if no more matching records exist, or another negative error 278 | * code in case of failure. 279 | */ 280 | static int apfs_node_next(struct super_block *sb, struct apfs_query *query) 281 | { 282 | struct apfs_node *node = query->node; 283 | struct apfs_key curr_key; 284 | int cmp, err; 285 | 286 | if (query->flags & APFS_QUERY_DONE) 287 | /* Nothing left to search; the query failed */ 288 | return -ENODATA; 289 | 290 | if (!query->index) /* The next record may be in another node */ 291 | return -EAGAIN; 292 | --query->index; 293 | 294 | query->key_len = apfs_node_locate_key(node, query->index, 295 | &query->key_off); 296 | err = apfs_key_from_query(query, &curr_key); 297 | if (err) 298 | return err; 299 | 300 | cmp = apfs_keycmp(sb, &curr_key, query->key); 301 | 302 | if (cmp > 0) /* Records are out of order */ 303 | return -EFSCORRUPTED; 304 | 305 | if (cmp != 0 && apfs_node_is_leaf(node) && 306 | query->flags & APFS_QUERY_EXACT) 307 | return -ENODATA; 308 | 309 | query->len = apfs_node_locate_data(node, query->index, &query->off); 310 | if (query->len == 0) 311 | return -EFSCORRUPTED; 312 | 313 | if (cmp != 0) { 314 | /* 315 | * This is the last entry that can be relevant in this node. 316 | * Keep searching the children, but don't return to this level. 317 | */ 318 | query->flags |= APFS_QUERY_DONE; 319 | } 320 | 321 | return 0; 322 | } 323 | 324 | /** 325 | * apfs_node_query - Execute a query on a single node 326 | * @sb: filesystem superblock 327 | * @query: the query to execute 328 | * 329 | * The search will start at index @query->index, looking for the key that comes 330 | * right before @query->key, according to the order given by apfs_keycmp(). 331 | * 332 | * The @query->index will be updated to the last index checked. This is 333 | * important when searching for multiple entries, since the query may need 334 | * to remember where it was on this level. If we are done with this node, the 335 | * query will be flagged as APFS_QUERY_DONE, and the search will end in failure 336 | * as soon as we return to this level. The function may also return -EAGAIN, 337 | * to signal that the search should go on in a different branch. 338 | * 339 | * On success returns 0; the offset of the data within the block will be saved 340 | * in @query->off, and its length in @query->len. The function checks that this 341 | * length fits within the block; callers must use the returned value to make 342 | * sure they never operate outside its bounds. 343 | * 344 | * -ENODATA will be returned if no appropriate entry was found, -EFSCORRUPTED 345 | * in case of corruption. 346 | */ 347 | int apfs_node_query(struct super_block *sb, struct apfs_query *query) 348 | { 349 | struct apfs_node *node = query->node; 350 | int left, right; 351 | int cmp; 352 | int err; 353 | 354 | if (query->flags & APFS_QUERY_NEXT) 355 | return apfs_node_next(sb, query); 356 | 357 | /* Search by bisection */ 358 | cmp = 1; 359 | left = 0; 360 | do { 361 | struct apfs_key curr_key; 362 | if (cmp > 0) { 363 | right = query->index - 1; 364 | if (right < left) 365 | return -ENODATA; 366 | query->index = (left + right) / 2; 367 | } else { 368 | left = query->index; 369 | query->index = DIV_ROUND_UP(left + right, 2); 370 | } 371 | 372 | query->key_len = apfs_node_locate_key(node, query->index, 373 | &query->key_off); 374 | err = apfs_key_from_query(query, &curr_key); 375 | if (err) 376 | return err; 377 | 378 | cmp = apfs_keycmp(sb, &curr_key, query->key); 379 | if (cmp == 0 && !(query->flags & APFS_QUERY_MULTIPLE)) 380 | break; 381 | } while (left != right); 382 | 383 | if (cmp > 0) 384 | return -ENODATA; 385 | 386 | if (cmp != 0 && apfs_node_is_leaf(query->node) && 387 | query->flags & APFS_QUERY_EXACT) 388 | return -ENODATA; 389 | 390 | if (query->flags & APFS_QUERY_MULTIPLE) { 391 | if (cmp != 0) /* Last relevant entry in level */ 392 | query->flags |= APFS_QUERY_DONE; 393 | query->flags |= APFS_QUERY_NEXT; 394 | } 395 | 396 | query->len = apfs_node_locate_data(node, query->index, &query->off); 397 | if (query->len == 0) 398 | return -EFSCORRUPTED; 399 | return 0; 400 | } 401 | 402 | /** 403 | * apfs_bno_from_query - Read the block number found by a successful omap query 404 | * @query: the query that found the record 405 | * @bno: Return parameter. The block number found. 406 | * 407 | * Reads the block number in the omap record into @bno and performs a basic 408 | * sanity check as a protection against crafted filesystems. Returns 0 on 409 | * success or -EFSCORRUPTED otherwise. 410 | */ 411 | int apfs_bno_from_query(struct apfs_query *query, u64 *bno) 412 | { 413 | struct apfs_omap_val *omap_val; 414 | char *raw = query->node->object.bh->b_data; 415 | 416 | if (query->len != sizeof(*omap_val)) 417 | return -EFSCORRUPTED; 418 | 419 | omap_val = (struct apfs_omap_val *)(raw + query->off); 420 | *bno = le64_to_cpu(omap_val->ov_paddr); 421 | return 0; 422 | } 423 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /super.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * linux/fs/apfs/super.c 4 | * 5 | * Copyright (C) 2018 Ernesto A. Fernández 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "apfs.h" 18 | #include "btree.h" 19 | #include "inode.h" 20 | #include "message.h" 21 | #include "node.h" 22 | #include "object.h" 23 | #include "super.h" 24 | #include "xattr.h" 25 | 26 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) /* iversion came in 4.16 */ 27 | #include 28 | #endif 29 | 30 | /** 31 | * apfs_read_super_copy - Read the copy of the container superblock in block 0 32 | * @sb: superblock structure 33 | * 34 | * Returns a pointer to the buffer head, or an error pointer in case of failure. 35 | */ 36 | static struct buffer_head *apfs_read_super_copy(struct super_block *sb) 37 | { 38 | struct buffer_head *bh; 39 | struct apfs_nx_superblock *msb_raw; 40 | int blocksize; 41 | int err = -EINVAL; 42 | 43 | /* 44 | * For now assume a small blocksize, we only need it so that we can 45 | * read the actual blocksize from disk. 46 | */ 47 | if (!sb_set_blocksize(sb, APFS_NX_DEFAULT_BLOCK_SIZE)) { 48 | apfs_err(sb, "unable to set blocksize"); 49 | return ERR_PTR(err); 50 | } 51 | bh = sb_bread(sb, APFS_NX_BLOCK_NUM); 52 | if (!bh) { 53 | apfs_err(sb, "unable to read superblock"); 54 | return ERR_PTR(err); 55 | } 56 | msb_raw = (struct apfs_nx_superblock *)bh->b_data; 57 | blocksize = le32_to_cpu(msb_raw->nx_block_size); 58 | 59 | if (sb->s_blocksize != blocksize) { 60 | brelse(bh); 61 | 62 | if (!sb_set_blocksize(sb, blocksize)) { 63 | apfs_err(sb, "bad blocksize %d", blocksize); 64 | return ERR_PTR(err); 65 | } 66 | bh = sb_bread(sb, APFS_NX_BLOCK_NUM); 67 | if (!bh) { 68 | apfs_err(sb, "unable to read superblock 2nd time"); 69 | return ERR_PTR(err); 70 | } 71 | msb_raw = (struct apfs_nx_superblock *)bh->b_data; 72 | } 73 | 74 | sb->s_magic = le32_to_cpu(msb_raw->nx_magic); 75 | if (sb->s_magic != APFS_NX_MAGIC) { 76 | apfs_err(sb, "not an apfs filesystem"); 77 | goto fail; 78 | } 79 | if (!apfs_obj_verify_csum(sb, &msb_raw->nx_o)) { 80 | apfs_err(sb, "inconsistent container superblock"); 81 | err = -EFSBADCRC; 82 | goto fail; 83 | } 84 | return bh; 85 | 86 | fail: 87 | brelse(bh); 88 | return ERR_PTR(err); 89 | } 90 | 91 | /** 92 | * apfs_map_main_super - Find the container superblock and map it into memory 93 | * @sb: superblock structure 94 | * 95 | * Returns a negative error code in case of failure. On success, returns 0 96 | * and sets the s_msb_raw, s_mobject and s_xid fields of APFS_SB(@sb). 97 | */ 98 | static int apfs_map_main_super(struct super_block *sb) 99 | { 100 | struct apfs_sb_info *sbi = APFS_SB(sb); 101 | struct buffer_head *bh; 102 | struct buffer_head *desc_bh = NULL; 103 | struct apfs_nx_superblock *msb_raw; 104 | u64 xid, bno = APFS_NX_BLOCK_NUM; 105 | u64 desc_base; 106 | u32 desc_blocks; 107 | int err = -EINVAL; 108 | int i; 109 | 110 | /* Read the superblock from the last clean unmount */ 111 | bh = apfs_read_super_copy(sb); 112 | if (IS_ERR(bh)) 113 | return PTR_ERR(bh); 114 | msb_raw = (struct apfs_nx_superblock *)bh->b_data; 115 | 116 | /* We want to mount the latest valid checkpoint among the descriptors */ 117 | desc_base = le64_to_cpu(msb_raw->nx_xp_desc_base); 118 | if (desc_base >> 63 != 0) { 119 | /* The highest bit is set when checkpoints are not contiguous */ 120 | apfs_err(sb, "checkpoint descriptor tree not yet supported"); 121 | goto fail; 122 | } 123 | desc_blocks = le32_to_cpu(msb_raw->nx_xp_desc_blocks); 124 | if (desc_blocks > 10000) { /* Arbitrary loop limit, is it enough? */ 125 | apfs_err(sb, "too many checkpoint descriptors?"); 126 | err = -EFSCORRUPTED; 127 | goto fail; 128 | } 129 | 130 | /* Now we go through the checkpoints one by one */ 131 | xid = le64_to_cpu(msb_raw->nx_o.o_xid); 132 | for (i = 0; i < desc_blocks; ++i) { 133 | struct apfs_nx_superblock *desc_raw; 134 | 135 | brelse(desc_bh); 136 | desc_bh = sb_bread(sb, desc_base + i); 137 | if (!desc_bh) { 138 | apfs_err(sb, "unable to read checkpoint descriptor"); 139 | goto fail; 140 | } 141 | desc_raw = (struct apfs_nx_superblock *)desc_bh->b_data; 142 | 143 | if (le32_to_cpu(desc_raw->nx_magic) != APFS_NX_MAGIC) 144 | continue; /* Not a superblock */ 145 | if (le64_to_cpu(desc_raw->nx_o.o_xid) <= xid) 146 | continue; /* Old */ 147 | if (!apfs_obj_verify_csum(sb, &desc_raw->nx_o)) 148 | continue; /* Corrupted */ 149 | 150 | xid = le64_to_cpu(desc_raw->nx_o.o_xid); 151 | msb_raw = desc_raw; 152 | bno = desc_base + i; 153 | brelse(bh); 154 | bh = desc_bh; 155 | desc_bh = NULL; 156 | } 157 | 158 | sbi->s_xid = xid; 159 | sbi->s_msb_raw = msb_raw; 160 | sbi->s_mobject.sb = sb; 161 | sbi->s_mobject.block_nr = bno; 162 | sbi->s_mobject.oid = le64_to_cpu(msb_raw->nx_o.o_oid); 163 | sbi->s_mobject.bh = bh; 164 | return 0; 165 | 166 | fail: 167 | brelse(bh); 168 | return err; 169 | } 170 | 171 | /** 172 | * apfs_unmap_main_super - Clean up apfs_map_main_super() 173 | * @sb: filesystem superblock 174 | */ 175 | static inline void apfs_unmap_main_super(struct super_block *sb) 176 | { 177 | struct apfs_sb_info *sbi = APFS_SB(sb); 178 | 179 | brelse(sbi->s_mobject.bh); 180 | } 181 | 182 | /** 183 | * apfs_map_volume_super - Find the volume superblock and map it into memory 184 | * @sb: superblock structure 185 | * 186 | * Returns a negative error code in case of failure. On success, returns 0 187 | * and sets APFS_SB(@sb)->s_vsb_raw and APFS_SB(@sb)->s_vobject. 188 | */ 189 | static int apfs_map_volume_super(struct super_block *sb) 190 | { 191 | struct apfs_sb_info *sbi = APFS_SB(sb); 192 | struct apfs_nx_superblock *msb_raw = sbi->s_msb_raw; 193 | struct apfs_superblock *vsb_raw; 194 | struct apfs_omap_phys *msb_omap_raw; 195 | struct apfs_node *vnode; 196 | struct buffer_head *bh; 197 | u64 vol_id; 198 | u64 msb_omap, vb, vsb; 199 | int err; 200 | 201 | /* Get the id for the requested volume number */ 202 | if (sbi->s_vol_nr >= APFS_NX_MAX_FILE_SYSTEMS) { 203 | apfs_err(sb, "volume number out of range"); 204 | return -EINVAL; 205 | } 206 | vol_id = le64_to_cpu(msb_raw->nx_fs_oid[sbi->s_vol_nr]); 207 | if (vol_id == 0) { 208 | apfs_err(sb, "requested volume does not exist"); 209 | return -EINVAL; 210 | } 211 | 212 | /* Get the container's object map */ 213 | msb_omap = le64_to_cpu(msb_raw->nx_omap_oid); 214 | bh = sb_bread(sb, msb_omap); 215 | if (!bh) { 216 | apfs_err(sb, "unable to read container object map"); 217 | return -EINVAL; 218 | } 219 | msb_omap_raw = (struct apfs_omap_phys *)bh->b_data; 220 | if (!apfs_obj_verify_csum(sb, &msb_omap_raw->om_o)) { 221 | apfs_err(sb, "bad checksum for the container object map"); 222 | err = -EFSBADCRC; 223 | goto fail; 224 | } 225 | 226 | /* Get the Volume Block */ 227 | vb = le64_to_cpu(msb_omap_raw->om_tree_oid); 228 | msb_omap_raw = NULL; 229 | brelse(bh); 230 | 231 | vnode = apfs_read_node(sb, vb); 232 | if (IS_ERR(vnode)) { 233 | apfs_err(sb, "unable to read volume block"); 234 | return PTR_ERR(vnode); 235 | } 236 | 237 | err = apfs_omap_lookup_block(sb, vnode, vol_id, &vsb); 238 | apfs_node_put(vnode); 239 | if (err) { 240 | apfs_err(sb, "volume not found, likely corruption"); 241 | return err; 242 | } 243 | 244 | bh = sb_bread(sb, vsb); 245 | if (!bh) { 246 | apfs_err(sb, "unable to read volume superblock"); 247 | return -EINVAL; 248 | } 249 | 250 | vsb_raw = (struct apfs_superblock *)bh->b_data; 251 | if (le32_to_cpu(vsb_raw->apfs_magic) != APFS_MAGIC) { 252 | apfs_err(sb, "wrong magic in volume superblock"); 253 | err = -EINVAL; 254 | goto fail; 255 | } 256 | if (!apfs_obj_verify_csum(sb, &vsb_raw->apfs_o)) { 257 | apfs_err(sb, "inconsistent volume superblock"); 258 | err = -EFSBADCRC; 259 | goto fail; 260 | } 261 | 262 | sbi->s_vsb_raw = vsb_raw; 263 | sbi->s_vobject.sb = sb; 264 | sbi->s_vobject.block_nr = vsb; 265 | sbi->s_vobject.oid = le64_to_cpu(vsb_raw->apfs_o.o_oid); 266 | sbi->s_vobject.bh = bh; 267 | return 0; 268 | 269 | fail: 270 | brelse(bh); 271 | return err; 272 | } 273 | 274 | /** 275 | * apfs_unmap_volume_super - Clean up apfs_map_volume_super() 276 | * @sb: filesystem superblock 277 | */ 278 | static inline void apfs_unmap_volume_super(struct super_block *sb) 279 | { 280 | struct apfs_sb_info *sbi = APFS_SB(sb); 281 | 282 | brelse(sbi->s_vobject.bh); 283 | } 284 | 285 | /** 286 | * apfs_read_omap - Find and read the omap root node 287 | * @sb: superblock structure 288 | * 289 | * On success, returns 0 and sets APFS_SB(@sb)->s_omap_root; on failure returns 290 | * a negative error code. 291 | */ 292 | static int apfs_read_omap(struct super_block *sb) 293 | { 294 | struct apfs_sb_info *sbi = APFS_SB(sb); 295 | struct apfs_superblock *vsb_raw = sbi->s_vsb_raw; 296 | struct apfs_omap_phys *omap_raw; 297 | struct apfs_node *omap_root; 298 | struct buffer_head *bh; 299 | u64 omap_blk, omap_root_blk; 300 | 301 | /* Get the block holding the volume omap information */ 302 | omap_blk = le64_to_cpu(vsb_raw->apfs_omap_oid); 303 | bh = sb_bread(sb, omap_blk); 304 | if (!bh) { 305 | apfs_err(sb, "unable to read the volume object map"); 306 | return -EINVAL; 307 | } 308 | omap_raw = (struct apfs_omap_phys *)bh->b_data; 309 | if (!apfs_obj_verify_csum(sb, &omap_raw->om_o)) { 310 | apfs_err(sb, "bad checksum for the volume object map"); 311 | brelse(bh); 312 | return -EFSBADCRC; 313 | } 314 | 315 | /* Get the volume's object map */ 316 | omap_root_blk = le64_to_cpu(omap_raw->om_tree_oid); 317 | brelse(bh); 318 | omap_root = apfs_read_node(sb, omap_root_blk); 319 | if (IS_ERR(omap_root)) { 320 | apfs_err(sb, "unable to read the omap root node"); 321 | return PTR_ERR(omap_root); 322 | } 323 | 324 | sbi->s_omap_root = omap_root; 325 | return 0; 326 | } 327 | 328 | /** 329 | * apfs_read_catalog - Find and read the catalog root node 330 | * @sb: superblock structure 331 | * 332 | * On success, returns 0 and sets APFS_SB(@sb)->s_cat_root; on failure returns 333 | * a negative error code. 334 | */ 335 | static int apfs_read_catalog(struct super_block *sb) 336 | { 337 | struct apfs_sb_info *sbi = APFS_SB(sb); 338 | struct apfs_superblock *vsb_raw = sbi->s_vsb_raw; 339 | struct apfs_node *root_node; 340 | u64 root_id; 341 | 342 | root_id = le64_to_cpu(vsb_raw->apfs_root_tree_oid); 343 | root_node = apfs_omap_read_node(sb, root_id); 344 | if (IS_ERR(root_node)) { 345 | apfs_err(sb, "unable to read catalog root node"); 346 | return PTR_ERR(root_node); 347 | } 348 | sbi->s_cat_root = root_node; 349 | return 0; 350 | } 351 | 352 | static void apfs_put_super(struct super_block *sb) 353 | { 354 | struct apfs_sb_info *sbi = APFS_SB(sb); 355 | 356 | apfs_node_put(sbi->s_cat_root); 357 | apfs_node_put(sbi->s_omap_root); 358 | 359 | apfs_unmap_main_super(sb); 360 | apfs_unmap_volume_super(sb); 361 | 362 | sb->s_fs_info = NULL; 363 | kfree(sbi); 364 | } 365 | 366 | static struct kmem_cache *apfs_inode_cachep; 367 | 368 | static struct inode *apfs_alloc_inode(struct super_block *sb) 369 | { 370 | struct apfs_inode_info *ai; 371 | 372 | ai = kmem_cache_alloc(apfs_inode_cachep, GFP_KERNEL); 373 | if (!ai) 374 | return NULL; 375 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) /* iversion came in 4.16 */ 376 | inode_set_iversion(&ai->vfs_inode, 1); 377 | #else 378 | ai->vfs_inode.i_version = 1; 379 | #endif 380 | return &ai->vfs_inode; 381 | } 382 | 383 | static void apfs_i_callback(struct rcu_head *head) 384 | { 385 | struct inode *inode = container_of(head, struct inode, i_rcu); 386 | 387 | kmem_cache_free(apfs_inode_cachep, APFS_I(inode)); 388 | } 389 | 390 | static void apfs_destroy_inode(struct inode *inode) 391 | { 392 | call_rcu(&inode->i_rcu, apfs_i_callback); 393 | } 394 | 395 | static void init_once(void *p) 396 | { 397 | struct apfs_inode_info *ai = (struct apfs_inode_info *)p; 398 | 399 | spin_lock_init(&ai->i_extent_lock); 400 | ai->i_cached_extent.len = 0; 401 | inode_init_once(&ai->vfs_inode); 402 | } 403 | 404 | static int __init init_inodecache(void) 405 | { 406 | apfs_inode_cachep = kmem_cache_create("apfs_inode_cache", 407 | sizeof(struct apfs_inode_info), 408 | 0, (SLAB_RECLAIM_ACCOUNT| 409 | SLAB_MEM_SPREAD|SLAB_ACCOUNT), 410 | init_once); 411 | if (apfs_inode_cachep == NULL) 412 | return -ENOMEM; 413 | return 0; 414 | } 415 | 416 | static void destroy_inodecache(void) 417 | { 418 | /* 419 | * Make sure all delayed rcu free inodes are flushed before we 420 | * destroy cache. 421 | */ 422 | rcu_barrier(); 423 | kmem_cache_destroy(apfs_inode_cachep); 424 | } 425 | 426 | /** 427 | * apfs_count_used_blocks - Count the blocks in use across all volumes 428 | * @sb: filesystem superblock 429 | * @count: on return it will store the block count 430 | * 431 | * This function probably belongs in a separate file, but for now it is 432 | * only called by statfs. 433 | */ 434 | static int apfs_count_used_blocks(struct super_block *sb, u64 *count) 435 | { 436 | struct apfs_sb_info *sbi = APFS_SB(sb); 437 | struct apfs_nx_superblock *msb_raw = sbi->s_msb_raw; 438 | struct apfs_node *vnode; 439 | struct apfs_omap_phys *msb_omap_raw; 440 | struct buffer_head *bh; 441 | u64 msb_omap, vb; 442 | int i; 443 | int err = 0; 444 | 445 | /* Get the container's object map */ 446 | msb_omap = le64_to_cpu(msb_raw->nx_omap_oid); 447 | bh = sb_bread(sb, msb_omap); 448 | if (!bh) { 449 | apfs_err(sb, "unable to read container object map"); 450 | return -EIO; 451 | } 452 | msb_omap_raw = (struct apfs_omap_phys *)bh->b_data; 453 | 454 | /* Get the Volume Block */ 455 | vb = le64_to_cpu(msb_omap_raw->om_tree_oid); 456 | msb_omap_raw = NULL; 457 | brelse(bh); 458 | bh = NULL; 459 | vnode = apfs_read_node(sb, vb); 460 | if (IS_ERR(vnode)) { 461 | apfs_err(sb, "unable to read volume block"); 462 | return PTR_ERR(vnode); 463 | } 464 | 465 | /* Iterate through the checkpoint superblocks and add the used blocks */ 466 | *count = 0; 467 | for (i = 0; i < APFS_NX_MAX_FILE_SYSTEMS; i++) { 468 | struct apfs_superblock *vsb_raw; 469 | u64 vol_id; 470 | u64 vol_bno; 471 | 472 | vol_id = le64_to_cpu(msb_raw->nx_fs_oid[i]); 473 | if (vol_id == 0) /* All volumes have been checked */ 474 | break; 475 | err = apfs_omap_lookup_block(sb, vnode, vol_id, &vol_bno); 476 | if (err) 477 | break; 478 | 479 | bh = sb_bread(sb, vol_bno); 480 | if (!bh) { 481 | err = -EIO; 482 | apfs_err(sb, "unable to read volume superblock"); 483 | break; 484 | } 485 | vsb_raw = (struct apfs_superblock *)bh->b_data; 486 | *count += le64_to_cpu(vsb_raw->apfs_fs_alloc_count); 487 | brelse(bh); 488 | } 489 | 490 | apfs_node_put(vnode); 491 | return err; 492 | } 493 | 494 | static int apfs_statfs(struct dentry *dentry, struct kstatfs *buf) 495 | { 496 | struct super_block *sb = dentry->d_sb; 497 | struct apfs_sb_info *sbi = APFS_SB(sb); 498 | struct apfs_nx_superblock *msb_raw = sbi->s_msb_raw; 499 | struct apfs_superblock *vol = sbi->s_vsb_raw; 500 | u64 fsid, used_blocks = 0; 501 | int err; 502 | 503 | buf->f_type = APFS_SUPER_MAGIC; 504 | /* Nodes are assumed to fit in a page, for now */ 505 | buf->f_bsize = sb->s_blocksize; 506 | 507 | /* Volumes share the whole disk space */ 508 | buf->f_blocks = le64_to_cpu(msb_raw->nx_block_count); 509 | err = apfs_count_used_blocks(sb, &used_blocks); 510 | if (err) 511 | return err; 512 | buf->f_bfree = buf->f_blocks - used_blocks; 513 | buf->f_bavail = buf->f_bfree; /* I don't know any better */ 514 | 515 | /* The file count is only for the mounted volume */ 516 | buf->f_files = le64_to_cpu(vol->apfs_num_files) + 517 | le64_to_cpu(vol->apfs_num_directories) + 518 | le64_to_cpu(vol->apfs_num_symlinks) + 519 | le64_to_cpu(vol->apfs_num_other_fsobjects); 520 | 521 | /* 522 | * buf->f_ffree is left undefined for now. Maybe it should report the 523 | * number of available cnids, like hfsplus attempts to do. 524 | */ 525 | 526 | buf->f_namelen = 255; /* Again, I don't know any better */ 527 | 528 | /* There are no clear rules for the fsid, so we follow ext2 here */ 529 | fsid = le64_to_cpup((void *)vol->apfs_vol_uuid) ^ 530 | le64_to_cpup((void *)vol->apfs_vol_uuid + sizeof(u64)); 531 | buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL; 532 | buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL; 533 | 534 | return 0; 535 | } 536 | 537 | static int apfs_show_options(struct seq_file *seq, struct dentry *root) 538 | { 539 | struct apfs_sb_info *sbi = APFS_SB(root->d_sb); 540 | 541 | if (sbi->s_vol_nr != 0) 542 | seq_printf(seq, ",vol=%u", sbi->s_vol_nr); 543 | if (sbi->s_flags & APFS_UID_OVERRIDE) 544 | seq_printf(seq, ",uid=%u", from_kuid(&init_user_ns, 545 | sbi->s_uid)); 546 | if (sbi->s_flags & APFS_GID_OVERRIDE) 547 | seq_printf(seq, ",gid=%u", from_kgid(&init_user_ns, 548 | sbi->s_gid)); 549 | if (sbi->s_flags & APFS_CHECK_NODES) 550 | seq_puts(seq, ",cknodes"); 551 | 552 | return 0; 553 | } 554 | 555 | static const struct super_operations apfs_sops = { 556 | .alloc_inode = apfs_alloc_inode, 557 | .destroy_inode = apfs_destroy_inode, 558 | .put_super = apfs_put_super, 559 | .statfs = apfs_statfs, 560 | .show_options = apfs_show_options, 561 | }; 562 | 563 | enum { 564 | Opt_cknodes, Opt_uid, Opt_gid, Opt_vol, Opt_err, 565 | }; 566 | 567 | static const match_table_t tokens = { 568 | {Opt_cknodes, "cknodes"}, 569 | {Opt_uid, "uid=%u"}, 570 | {Opt_gid, "gid=%u"}, 571 | {Opt_vol, "vol=%u"}, 572 | {Opt_err, NULL} 573 | }; 574 | 575 | /* 576 | * Many of the parse_options() functions in other file systems return 0 577 | * on error. This one returns an error code, and 0 on success. 578 | */ 579 | static int parse_options(struct super_block *sb, char *options) 580 | { 581 | struct apfs_sb_info *sbi = APFS_SB(sb); 582 | char *p; 583 | substring_t args[MAX_OPT_ARGS]; 584 | int option; 585 | int err = 0; 586 | 587 | /* Set default values before parsing */ 588 | sbi->s_vol_nr = 0; 589 | sbi->s_flags = 0; 590 | 591 | if (!options) 592 | return 0; 593 | 594 | while ((p = strsep(&options, ",")) != NULL) { 595 | int token; 596 | 597 | if (!*p) 598 | continue; 599 | token = match_token(p, tokens, args); 600 | switch (token) { 601 | case Opt_cknodes: 602 | /* 603 | * Right now, node checksums are too costly to enable 604 | * by default. TODO: try to improve this. 605 | */ 606 | sbi->s_flags |= APFS_CHECK_NODES; 607 | break; 608 | case Opt_uid: 609 | err = match_int(&args[0], &option); 610 | if (err) 611 | return err; 612 | sbi->s_uid = make_kuid(current_user_ns(), option); 613 | if (!uid_valid(sbi->s_uid)) { 614 | apfs_err(sb, "invalid uid"); 615 | return -EINVAL; 616 | } 617 | sbi->s_flags |= APFS_UID_OVERRIDE; 618 | break; 619 | case Opt_gid: 620 | err = match_int(&args[0], &option); 621 | if (err) 622 | return err; 623 | sbi->s_gid = make_kgid(current_user_ns(), option); 624 | if (!gid_valid(sbi->s_gid)) { 625 | apfs_err(sb, "invalid gid"); 626 | return -EINVAL; 627 | } 628 | sbi->s_flags |= APFS_GID_OVERRIDE; 629 | break; 630 | case Opt_vol: 631 | err = match_int(&args[0], &sbi->s_vol_nr); 632 | if (err) 633 | return err; 634 | break; 635 | default: 636 | return -EINVAL; 637 | } 638 | } 639 | return 0; 640 | } 641 | 642 | static int apfs_fill_super(struct super_block *sb, void *data, int silent) 643 | { 644 | struct apfs_sb_info *sbi; 645 | struct inode *root; 646 | int err; 647 | 648 | apfs_notice(sb, "this module is read-only"); 649 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) /* SB_RDONLY came in 4.14 */ 650 | sb->s_flags |= SB_RDONLY; 651 | #else 652 | sb->s_flags |= MS_RDONLY; 653 | #endif 654 | 655 | sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); 656 | if (!sbi) 657 | return -ENOMEM; 658 | sb->s_fs_info = sbi; 659 | 660 | err = apfs_map_main_super(sb); 661 | if (err) 662 | goto failed_main_super; 663 | 664 | /* For now we only support blocksize < PAGE_SIZE */ 665 | sbi->s_blocksize = sb->s_blocksize; 666 | sbi->s_blocksize_bits = sb->s_blocksize_bits; 667 | 668 | err = parse_options(sb, data); 669 | if (err) 670 | goto failed_volume_super; 671 | 672 | err = apfs_map_volume_super(sb); 673 | if (err) 674 | goto failed_volume_super; 675 | 676 | /* The omap needs to be set before the call to apfs_read_catalog() */ 677 | err = apfs_read_omap(sb); 678 | if (err) 679 | goto failed_omap; 680 | 681 | err = apfs_read_catalog(sb); 682 | if (err) 683 | goto failed_cat; 684 | 685 | sb->s_op = &apfs_sops; 686 | sb->s_d_op = &apfs_dentry_operations; 687 | sb->s_xattr = apfs_xattr_handlers; 688 | sb->s_maxbytes = MAX_LFS_FILESIZE; 689 | 690 | root = apfs_iget(sb, APFS_ROOT_DIR_INO_NUM); 691 | if (IS_ERR(root)) { 692 | apfs_err(sb, "unable to get root inode"); 693 | err = PTR_ERR(root); 694 | goto failed_mount; 695 | } 696 | sb->s_root = d_make_root(root); 697 | if (!sb->s_root) { 698 | apfs_err(sb, "unable to get root dentry"); 699 | err = -ENOMEM; 700 | goto failed_mount; 701 | } 702 | return 0; 703 | 704 | failed_mount: 705 | apfs_node_put(sbi->s_cat_root); 706 | failed_cat: 707 | apfs_node_put(sbi->s_omap_root); 708 | failed_omap: 709 | apfs_unmap_volume_super(sb); 710 | failed_volume_super: 711 | apfs_unmap_main_super(sb); 712 | failed_main_super: 713 | sb->s_fs_info = NULL; 714 | kfree(sbi); 715 | return err; 716 | } 717 | 718 | static struct dentry *apfs_mount(struct file_system_type *fs_type, 719 | int flags, const char *dev_name, void *data) 720 | { 721 | return mount_bdev(fs_type, flags, dev_name, data, apfs_fill_super); 722 | } 723 | 724 | static struct file_system_type apfs_fs_type = { 725 | .owner = THIS_MODULE, 726 | .name = "apfs", 727 | .mount = apfs_mount, 728 | .kill_sb = kill_block_super, 729 | .fs_flags = FS_REQUIRES_DEV, 730 | }; 731 | MODULE_ALIAS_FS("apfs"); 732 | 733 | static int __init init_apfs_fs(void) 734 | { 735 | int err = 0; 736 | 737 | err = init_inodecache(); 738 | if (err) 739 | return err; 740 | err = register_filesystem(&apfs_fs_type); 741 | if (err) 742 | destroy_inodecache(); 743 | return err; 744 | } 745 | 746 | static void __exit exit_apfs_fs(void) 747 | { 748 | unregister_filesystem(&apfs_fs_type); 749 | destroy_inodecache(); 750 | } 751 | 752 | MODULE_AUTHOR("Ernesto A. Fernández"); 753 | MODULE_DESCRIPTION("Apple File System"); 754 | MODULE_LICENSE("GPL"); 755 | module_init(init_apfs_fs) 756 | module_exit(exit_apfs_fs) 757 | --------------------------------------------------------------------------------