1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
/*
* Copyright (C) 2019 Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
*/
#ifndef _SUPER_H
#define _SUPER_H
#include <apfs/raw.h>
#include <apfs/types.h>
#include "htable.h"
#include "object.h"
#include "spaceman.h"
struct volume_group {
char vg_id[16];
bool vg_system_seen;
bool vg_data_seen;
};
/**
* An entry in a linked list of b-trees
*/
struct listed_btree {
struct btree *btree;
struct listed_btree *next;
};
struct volume_superblock {
struct apfs_superblock *v_raw;
struct btree *v_omap;
struct btree *v_cat;
struct btree *v_extent_ref;
struct listed_btree *v_snap_extrefs; /* Snapshots have their own */
struct btree *v_snap_meta;
struct btree *v_snapshots;
struct btree *v_fext;
struct htable_entry **v_omap_table; /* Hash table of omap records */
struct htable_entry **v_inode_table; /* Hash table of all inodes */
struct htable_entry **v_dstream_table; /* Hash table of all dstreams */
struct htable_entry **v_cnid_table; /* Hash table of all cnids */
struct htable_entry **v_extent_table; /* Hash table of all extents */
struct htable_entry **v_snap_table; /* Hash table of all snapshots */
struct htable_entry **v_dirstat_table; /* Hash table of all dir stats */
struct htable_entry **v_crypto_table; /* Hash table of all crypto states */
bool v_in_snapshot; /* Is this a snapshot volume? */
/* Volume stats as measured by the fsck */
u64 v_file_count; /* Number of files */
u64 v_dir_count; /* Number of directories */
u64 v_symlink_count; /* Number of symlinks */
u64 v_special_count; /* Number of other filesystem objects */
u64 v_block_count; /* Number of blocks currently allocated */
u64 v_snap_count; /* Number of snapshots */
u64 v_snap_max_xid; /* Maximum xid among snapshots */
bool v_has_root; /* Is there a root directory? */
bool v_has_priv; /* Is there a private directory? */
/* Volume information read from the on-disk structure */
u64 v_extref_oid; /* Object id for the extent reference tree */
u64 v_omap_oid; /* Object id for object map tree */
u64 v_snap_meta_oid; /* Object id for the snapshot metadata tree */
u64 v_fext_tree_oid; /* Object id for the fext tree */
u64 v_integrity_oid; /* Object id for the integrity metadata */
u64 v_first_xid; /* Transaction that created the volume */
u64 v_last_xid; /* Transaction that last modified the volume */
u64 v_next_obj_id; /* Next cnid to be assigned */
u32 v_next_doc_id; /* Next document identifier to be assigned */
u32 v_index; /* Index in the container's volume array */
bool v_encrypted; /* Is the volume encrypted? */
u8 v_hash[32]; /* For a sealed volume, the root SHA-256 */
struct object v_obj; /* Object holding the volume sb */
};
/* Superblock data in memory */
struct super_block {
struct apfs_nx_superblock *s_raw;
void *s_bitmap; /* Allocation bitmap for the whole container */
void *s_ip_bitmap; /* Allocation bitmap for the internal pool */
struct btree *s_omap;
struct object *s_reaper;
unsigned long s_blocksize;
unsigned char s_blocksize_bits;
u64 s_block_count; /* Number of blocks in the container */
u64 s_xid; /* Transaction id for the superblock */
u64 s_next_oid; /* Next virtual object id to be used */
u32 s_max_vols; /* Maximum number of volumes allowed */
u64 s_data_base; /* Base address of the checkpoint data area */
u32 s_data_blocks; /* Number of blocks in the checkpoint data area */
u32 s_data_index; /* Index of first valid block in checkpoint data */
u32 s_data_len; /* Number of valid blocks in checkpoint data area */
u64 s_reaper_fs_id; /* Volume id reported by the reaper */
/* Hash table of ephemeral object mappings for the checkpoint */
struct htable_entry **s_cpoint_map_table;
/* Hash table of virtual object mappings for the container */
struct htable_entry **s_omap_table;
struct spaceman s_spaceman; /* Information about the space manager */
/* Information about the one volume group in the container, if any */
struct volume_group *s_volume_group;
/* This is excessive in most cases. TODO: switch to a linked list? */
struct volume_superblock *s_volumes[APFS_NX_MAX_FILE_SYSTEMS];
};
/*
* Checkpoint mapping data in memory
*/
struct cpoint_map {
struct htable_entry m_htable; /* Hash table entry header */
bool m_seen; /* Has this ephemeral oid been seen in use? */
u32 m_type; /* Type of the object */
u32 m_subtype; /* Subtype of the object */
u64 m_paddr; /* Physical address of the object */
u32 m_size; /* Size of the object in bytes */
};
#define m_oid m_htable.h_id /* Ephemeral object id */
static inline bool apfs_is_case_insensitive(void)
{
extern struct volume_superblock *vsb;
return (vsb->v_raw->apfs_incompatible_features &
cpu_to_le64(APFS_INCOMPAT_CASE_INSENSITIVE)) != 0;
}
static inline bool apfs_is_normalization_insensitive(void)
{
extern struct volume_superblock *vsb;
u64 flags = le64_to_cpu(vsb->v_raw->apfs_incompatible_features);
if (apfs_is_case_insensitive())
return true;
if (flags & APFS_INCOMPAT_NORMALIZATION_INSENSITIVE)
return true;
return false;
}
static inline bool apfs_volume_is_sealed(void)
{
u64 flags = le64_to_cpu(vsb->v_raw->apfs_incompatible_features);
return flags & APFS_INCOMPAT_SEALED_VOLUME;
}
static inline bool apfs_volume_is_in_group(void)
{
u64 features = le64_to_cpu(vsb->v_raw->apfs_features);
return features & APFS_FEATURE_VOLGRP_SYSTEM_INO_SPACE;
}
static inline u16 apfs_volume_role(void)
{
return le16_to_cpu(vsb->v_raw->apfs_role);
}
static inline bool apfs_is_data_volume_in_group(void)
{
u16 role = apfs_volume_role();
return apfs_volume_is_in_group() && role == APFS_VOL_ROLE_DATA;
}
static inline bool apfs_is_system_volume_in_group(void)
{
u16 role = apfs_volume_role();
return apfs_volume_is_in_group() && role == APFS_VOL_ROLE_SYSTEM;
}
/**
* uuid_is_null - Check if all bytes of a uuid are zero
* @uuid: the uuid to check
*
* TODO: reuse this for other uuid checks
*/
static inline bool uuid_is_null(char uuid[16])
{
int i;
for (i = 0; i < 16; ++i) {
if (uuid[i])
return false;
}
return true;
}
extern void parse_filesystem(void);
extern struct volume_superblock *alloc_volume_super(bool snap);
extern void read_volume_super(int vol, struct volume_superblock *vsb, struct object *obj);
extern void check_volume_super(void);
#endif /* _SUPER_H */
|