Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix apfs support #182

Merged
merged 1 commit into from
Apr 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
82 changes: 73 additions & 9 deletions src/apfsclone.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,81 @@
#include "progress.h"
#include "fs_common.h"

static void *get_spaceman_buf(int fd, const struct nx_superblock_t *nxsb)
{
uint32_t block_size = nxsb->nx_block_size;
uint64_t base = nxsb->nx_xp_desc_base;
uint32_t blocks = nxsb->nx_xp_desc_blocks;
int found_nxsb = 0;
checkpoint_map_phys_t *cpm = NULL;
struct spaceman_phys_t *ret = NULL;
obj_phys_t *obj;
const uint32_t type_checkpoint_map =
(OBJ_PHYSICAL | OBJECT_TYPE_CHECKPOINT_MAP);
const uint32_t type_spaceman = (OBJ_EPHEMERAL | OBJECT_TYPE_SPACEMAN);
uint32_t i;

if (base >> 63 || blocks >> 31)
log_mesg(0, 1, 1, fs_opt.debug, "%s: B-tree checkpoint descriptor area not supported\n", __FILE__);
obj = malloc(block_size);
if (!obj)
log_mesg(0, 1, 1, fs_opt.debug, "%s: malloc error %s\n", __FILE__, strerror(errno));
for (; blocks > 0; base++, blocks--) {
if (pread(fd, obj, block_size, base * block_size) != block_size)
log_mesg(0, 1, 1, fs_opt.debug, "%s: pread error %s\n", __FILE__, strerror(errno));
if (obj->o_type == nxsb->nx_o.o_type) {
/* Sanity check: *nxsb has a copy of latest nx_superblock
* if the filesystem is unmounted cleanly. */
if (obj->o_xid < nxsb->nx_o.o_xid)
continue;
if (obj->o_xid > nxsb->nx_o.o_xid)
log_mesg(0, 1, 1, fs_opt.debug, "%s: newer nx_superblock found in descriptor\n", __FILE__);
found_nxsb = 1;
}
if (obj->o_type == type_checkpoint_map) {
/* Find latest checkpoint_map_phys_t */
if (!cpm || cpm->cpm_o.o_xid < obj->o_xid) {
if (!cpm)
cpm = malloc(block_size);
if (!cpm)
log_mesg(0, 1, 1, fs_opt.debug, "%s: malloc error %s\n", __FILE__, strerror(errno));
memcpy(cpm, obj, block_size);
}
}
}
free(obj);

if (!found_nxsb)
log_mesg(0, 1, 1, fs_opt.debug, "%s: nx_superblock not found in descriptor\n", __FILE__);
if (!cpm)
log_mesg(0, 1, 1, fs_opt.debug, "%s: checkpoint_map_phys not found in descriptor\n", __FILE__);
if (!(cpm->cpm_flags & CHECKPOINT_MAP_LAST))
log_mesg(0, 1, 1, fs_opt.debug, "%s: multiple checkpoint_map_phys not supported\n", __FILE__);
for (i = 0; i < cpm->cpm_count; i++) {
if (cpm->cpm_map[i].cpm_oid == nxsb->nx_spaceman_oid &&
cpm->cpm_map[i].cpm_type == type_spaceman) {
ret = malloc(cpm->cpm_map[i].cpm_size);
if (!ret)
log_mesg(0, 1, 1, fs_opt.debug, "%s: malloc error %s\n", __FILE__, strerror(errno));
if (pread(fd, ret, cpm->cpm_map[i].cpm_size,
cpm->cpm_map[i].cpm_paddr * block_size) !=
cpm->cpm_map[i].cpm_size)
log_mesg(0, 1, 1, fs_opt.debug, "%s: pread error %s\n", __FILE__, strerror(errno));
break;
}
}
free(cpm);
if (!ret)
log_mesg(0, 1, 1, fs_opt.debug, "%s: spaceman not found\n", __FILE__);
return ret;
}

int APFSDEV;
struct nx_superblock_t nxsb;

/// get_apfs_free_count
static uint64_t get_apfs_free_count(){

int block_size = 4096;
size_t size = 0;

struct spaceman_phys_t spaceman;
Expand All @@ -44,14 +112,12 @@ static uint64_t get_apfs_free_count(){
int sd = 0;
int cnt = 0;
int total_cnt = 0;
uint64_t read_size = 0;
uint64_t free_count = 0;
uint64_t total_free_count = 0;

spaceman_buf = (char *)malloc(block_size*nxsb.nx_xp_data_len);
memset(spaceman_buf, 0, block_size*nxsb.nx_xp_data_len); // not sure what is real size
read_size = pread(APFSDEV, spaceman_buf, block_size*nxsb.nx_xp_data_len, nxsb.nx_xp_data_base*block_size);
spaceman_buf = get_spaceman_buf(APFSDEV, &nxsb);
memcpy(&spaceman, spaceman_buf, sizeof(spaceman));
free(spaceman_buf);
log_mesg(2, 0, 0, fs_opt.debug, "%s: sm_block_size %x\n", __FILE__, spaceman.sm_block_size);
log_mesg(2, 0, 0, fs_opt.debug, "%s: blocks_per_chunk %x\n", __FILE__, spaceman.sm_blocks_per_chunk);
log_mesg(2, 0 ,0, fs_opt.debug, "%s: sd count=%i\n", __FILE__, sd);
Expand Down Expand Up @@ -109,7 +175,7 @@ void read_bitmap(char* device, file_system_info fs_info, unsigned long* bitmap,
int start = 0;
int bit_size = 1;

uint32_t block_size = 4096;
uint32_t block_size;
size_t size = 0;

struct spaceman_phys_t spaceman;
Expand Down Expand Up @@ -149,9 +215,7 @@ void read_bitmap(char* device, file_system_info fs_info, unsigned long* bitmap,
pc_set_bit(block, bitmap, fs_info.totalblock);
}

spaceman_buf = (char *)malloc(block_size);
memset(spaceman_buf, 0, block_size);
read_size = pread(APFSDEV, spaceman_buf, block_size, nxsb.nx_xp_data_base*block_size);
spaceman_buf = get_spaceman_buf(APFSDEV, &nxsb);
memcpy(&spaceman, spaceman_buf, sizeof(spaceman));

block_size = nxsb.nx_block_size;
Expand Down
20 changes: 20 additions & 0 deletions src/apfsclone.h
Original file line number Diff line number Diff line change
Expand Up @@ -385,3 +385,23 @@ struct chunk_info_block_t {
};


struct checkpoint_mapping {
le_uint32_t cpm_type;
le_uint32_t cpm_subtype;
le_uint32_t cpm_size;
le_uint32_t cpm_pad;
le_oid_t cpm_fs_oid;
le_oid_t cpm_oid;
le_oid_t cpm_paddr;
};
typedef struct checkpoint_mapping checkpoint_mapping_t;

struct checkpoint_map_phys {
obj_phys_t cpm_o;
le_uint32_t cpm_flags;
le_uint32_t cpm_count;
checkpoint_mapping_t cpm_map[];
};
typedef struct checkpoint_map_phys checkpoint_map_phys_t;

const uint32_t CHECKPOINT_MAP_LAST = 0x00000001;