Skip to content

Commit

Permalink
Merge branch xfields into main
Browse files Browse the repository at this point in the history
  • Loading branch information
jivanpal committed Aug 28, 2021
2 parents 2a09733 + 54fb438 commit b82b7cd
Show file tree
Hide file tree
Showing 15 changed files with 420 additions and 32 deletions.
2 changes: 1 addition & 1 deletion include/apfs/j.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ typedef struct {
j_key_t hdr;
} __attribute__((packed)) j_dir_stats_key_t;

/** `j_dir_stats_val` **/
/** `j_dir_stats_val_t` **/

typedef struct {
uint64_t num_children;
Expand Down
94 changes: 94 additions & 0 deletions include/drat/func/xf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include "xf.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>

/**
* Given an instance of `xf_blob_t` (such as `j_drec_val_t::xfields` or
* `j_inode_val_t::xfields`), get an array of instances of `xf_pair_t`, which
* allows you to easily access the xfield value for a given xfield key/type,
* since they are then stored directly alongside each other.
*
* xfields:
* A pointer to an instance of `xf_blob_t`, including the data in its
* `xf_data` field.
*
* RETURN VALUE:
* A pointer to the head of an array of pointers to instances of
* `xf_pair_t`. The length of this array is not returned to the caller,
* but the last element of this array will be a NULL pointer. If an error
* occurs, NULL is returned.
*
* When the data in the array is no longer needed, it is the caller's
* responsibility to free the associated memory by passing the pointer
* that was returned by this function to `free_xf_pairs_array()`.
*/
xf_pair_t** get_xf_pairs_array(xf_blob_t* xfields) {
/*
* Create the array to return. We use `calloc()` here so that early return
* in case of error does not cause our call to `free_xf_pairs_array()` to
* `free()` arbitrary pointers. In other words, it makes sure that
* `xf_pairs_array` is always NULL-terminated regardless of how many
* entries it has been populated with so far.
*/
xf_pair_t** xf_pairs_array = calloc(xfields->xf_num_exts + 1, sizeof(xf_pair_t*));
if (!xf_pairs_array) {
fprintf(stderr, "\nERROR: %s: Couldn't create `xf_pairs_array`.\n", __func__);
return NULL;
}

x_field_t* xf_keys = xfields->xf_data;
uint8_t* xf_values = xf_keys + xfields->xf_num_exts;

/*
* Use this value to keep track of how many bytes into `xf_values` the
* current xfield's value starts. This will always be a multiple of 8 before
* we copy a value, since the values are 8-byte aligned.
*/
uint16_t xf_value_cursor_index = 0;

// Populate the array
for (uint16_t i = 0; i < xfields->xf_num_exts; i++) {
// Move to the start of the next 8-byte aligned segment.
uint16_t remainder = xf_value_cursor_index % 8;
if (remainder != 0) {
xf_value_cursor_index += 8 - remainder;
}

xf_pairs_array[i] = malloc(sizeof(x_field_t) + xf_keys[i].x_size);
if (!xf_pairs_array[i]) {
fprintf(stderr, "\nERROR: %s: Couldn't create `xf_pairs_array[%"PRIu16"].`\n", __func__, i);
free_xf_pairs_array(xf_pairs_array);
return NULL;
}

memcpy(xf_pairs_array[i], xf_keys + i, sizeof(x_field_t));
memcpy(&(xf_pairs_array[i]->value), xf_values + xf_value_cursor_index, xf_keys[i].x_size);

xf_value_cursor_index += xf_keys[i].x_size;
}
xf_pairs_array[xfields->xf_num_exts] = NULL;

return xf_pairs_array;
}

/**
* Free memory allocated for a file-system records array that
* was created by a call to `get_xf_pairs_array()`.
*
* xf_pairs_array:
* A pointer to an array of pointers to instances of `xf_pair_t`, as
* returned by a call to `get_xfields_array()`.
*/
void free_xf_pairs_array(xf_pair_t** xf_pairs_array) {
if (!xf_pairs_array) {
return;
}

for (xf_pair_t** cursor = xf_pairs_array; *cursor; cursor++) {
free(*cursor);
}
free(xf_pairs_array);
}
23 changes: 23 additions & 0 deletions include/drat/func/xf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef DRAT_FUNC_XF_H
#define DRAT_FUNC_XF_H

#include <apfs/xf.h>

/**
* Data structure used to collect an xfield's key (an instance of `x_field_t`,
* which contains its type, flags, and the size of its value) and its value
* together. The function `get_xfields_array()`, which returns a pointer
* to an array of instance of this data structure, allows us to more easily
* access xfields without needing to do cumbersome arithmetic to find the xfield
* value in an instance of `xf_blob_t`.
*/
typedef struct {
x_field_t key;
uint8_t value[];
} xf_pair_t;

xf_pair_t** get_xf_pairs_array(xf_blob_t* xfields);

void free_xf_pairs_array(xf_pair_t** xfields_array);

#endif // DRAT_FUNC_XF_H
20 changes: 20 additions & 0 deletions include/drat/string/dstream.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include "dstream.h"

#include <inttypes.h>
#include <stdio.h>

void print_j_dstream(j_dstream_t* dstream) {
printf(
"Size: %"PRIu64" bytes\n"
"Allocated size: %"PRIu64" bytes\n"
"Default crypto ID: %#"PRIx64"\n"
"Total bytes written: %"PRIu64" bytes\n"
"Total bytes read: %"PRIu64" bytes\n",

dstream->size,
dstream->alloced_size,
dstream->default_crypto_id,
dstream->total_bytes_written,
dstream->total_bytes_read
);
}
8 changes: 8 additions & 0 deletions include/drat/string/dstream.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef DRAT_STRING_DSTREAM_H
#define DRAT_STRING_DSTREAM_H

#include <apfs/dstream.h>

void print_j_dstream(j_dstream_t* dstream);

#endif // DRAT_STRING_DSTREAM_H
8 changes: 4 additions & 4 deletions include/drat/string/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include <drat/string/common.h>
#include <drat/string/object.h>
#include <drat/string/general.h>

/**
* Get a human-readable string that lists the optional feature flags that are
Expand Down Expand Up @@ -271,10 +272,9 @@ void print_apfs_superblock(apfs_superblock_t* apsb) {
printf("- block liberations ever made: %" PRIu64 "\n", apsb->apfs_total_blocks_freed);
printf("\n");

printf("UUID: 0x%016" PRIx64 "%016" PRIx64 "\n",
*((uint64_t*)(apsb->apfs_vol_uuid) + 1),
* (uint64_t*)(apsb->apfs_vol_uuid)
);
printf("UUID: ");
print_uuid(apsb->apfs_vol_uuid);
printf("\n");

printf("Formatted by:\n");
print_apfs_modified_by(&(apsb->apfs_formatted_by));
Expand Down
18 changes: 18 additions & 0 deletions include/drat/string/general.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include "general.h"

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

void print_uuid(uuid_t uuid) {
for (int i = 0; i < 16; i++) {
switch (i) {
case 4: case 6: case 8: case 10:
printf("-");
// fall through
default:
printf("%02X", uuid[i]);
break;
}
}
}
8 changes: 8 additions & 0 deletions include/drat/string/general.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef DRAT_STRING_GENERAL_H
#define DRAT_STRING_GENERAL_H

#include <apfs/general.h>

void print_uuid(uuid_t uuid);

#endif // DRAT_STRING_GENERAL_H
53 changes: 36 additions & 17 deletions include/drat/string/j.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,24 @@
#include <drat/asize.h>
#include <drat/time.h>

#include <drat/func/xf.h>

#include <drat/string/common.h>
#include <drat/string/xf.h>

// Helper function for printing objects which have xfields
static void print_xf_details(bool has_xfields, xf_blob_t* xfields) {
printf("Number of extended fields: %u\n", has_xfields ? xfields->xf_num_exts : 0);
if (has_xfields) {
printf("Details of extended fields:\n\n");
xf_pair_t** xf_pairs_array = get_xf_pairs_array(xfields);
if (!xf_pairs_array) {
fprintf(stderr, "\nERROR: %s: Call to `get_xf_pairs_array()` failed.\n", __func__);
} else {
print_xf_pairs_array(xf_pairs_array);
}
}
}

char* j_key_type_to_string(uint8_t j_key_type) {
switch (j_key_type) {
Expand Down Expand Up @@ -136,19 +153,19 @@ char* get_j_inode_bsd_flags_string(uint32_t bsd_flags) {
return get_flags_enum_string(flags, ARRAY_SIZE(flags), bsd_flags, false);
}

void print_j_inode_val(j_inode_val_t* val, bool has_xfields) {
void print_j_inode_val(j_inode_val_t* val, uint16_t val_len) {
printf("Parent ID: 0x%" PRIx64 "\n", val->parent_id);
printf("Private ID: 0x%" PRIx64 "\n", val->private_id);
printf("\n");

char* tmp_string = NULL;
if (val->internal_flags & INODE_HAS_UNCOMPRESSED_SIZE) {
if (asprintf(tmp_string, "%" PRIu64 " bytes", val->uncompressed_size) < 0) {
if (asprintf(&tmp_string, "%" PRIu64 " bytes", val->uncompressed_size) < 0) {
fprintf(stderr, "ABORT: %s:%d: call to asprintf() couldn't allocate sufficient memory", __func__, __LINE__);
exit(-1);
}
} else {
if (asprintf(tmp_string, "(unknown)") < 0) {
if (asprintf(&tmp_string, "(none)") < 0) {
fprintf(stderr, "ABORT: %s:%d: call to asprintf() couldn't allocate sufficient memory", __func__, __LINE__);
exit(-1);
}
Expand Down Expand Up @@ -184,11 +201,7 @@ void print_j_inode_val(j_inode_val_t* val, bool has_xfields) {
printf("\n");
free(tmp_string);

printf("Number of extended fields: %u\n",
has_xfields ? ((xf_blob_t*)(val->xfields))->xf_num_exts : 0
);

// TODO: Print actual details of extended fields/attributes
print_xf_details(val_len != sizeof(j_inode_val_t), val->xfields);
}

void print_j_file_extent_key(j_file_extent_key_t* key) {
Expand Down Expand Up @@ -251,17 +264,23 @@ char* drec_val_to_short_type_string(j_drec_val_t* val) {
}
}

void print_j_drec_val(j_drec_val_t* val, bool has_xfields) {
void print_j_drec_val(j_drec_val_t* val, uint16_t val_len) {
printf("Dentry Virtual OID: 0x%" PRIx64 "\n", val->file_id);
printf("Time added: %s", apfs_timestamp_to_string(val->date_added));
printf("Dentry type: %s\n", drec_val_to_type_string(val));
print_xf_details(val_len != sizeof(j_drec_val_t), val->xfields);
}

printf("No. extended fields: ");
if (!has_xfields) {
printf("0\n");
return;
}
printf("%u\n", ((xf_blob_t*)(val->xfields))->xf_num_exts);

// TODO: Print actual details of extended fields/attributes
void print_j_dir_stats_val(j_dir_stats_val_t* val) {
printf(
"Number of children: %"PRIu64" items\n"
"Total size: %"PRIu64" bytes\n"
"Chained key (parent dir's FSOID): %#"PRIx64"\n"
"Generation count: %"PRIu64" (%#"PRIx64")\n",

val->num_children,
val->total_size,
val->chained_key,
val->gen_count, val->gen_count
);
}
6 changes: 4 additions & 2 deletions include/drat/string/j.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ char* j_inode_mode_to_string(apfs_mode_t mode);
char* get_j_inode_internal_flags_string(uint64_t internal_flags);
char* get_j_inode_bsd_flags_string(uint32_t bsd_flags);

void print_j_inode_val(j_inode_val_t* val, bool has_xfields);
void print_j_inode_val(j_inode_val_t* val, uint16_t val_len);
void print_j_file_extent_key(j_file_extent_key_t* key);
void print_j_file_extent_val(j_file_extent_val_t* val);
void print_j_drec_hashed_key(j_drec_hashed_key_t* key);

char* drec_val_to_type_string(j_drec_val_t* val);
char* drec_val_to_short_type_string(j_drec_val_t* val);
void print_j_drec_val(j_drec_val_t* val, bool has_xfields);
void print_j_drec_val(j_drec_val_t* val, uint16_t val_len);

void print_j_dir_stats_val(j_dir_stats_val_t* val);

#endif // DRAT_STRING_J_H
9 changes: 5 additions & 4 deletions include/drat/string/nx.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <drat/string/common.h>
#include <drat/string/object.h>
#include <drat/string/general.h>

/**
* Get a human-readable string that lists the optional feature flags that are
Expand Down Expand Up @@ -166,10 +167,10 @@ void print_nx_superblock(nx_superblock_t* nxsb) {
printf("Backward-incompatible features:\n%s", incompatible_features_string);
free(incompatible_features_string);

printf("UUID: 0x%016" PRIx64 "%016" PRIx64 "\n",
*((uint64_t*)(nxsb->nx_uuid) + 1),
* (uint64_t*)(nxsb->nx_uuid)
);
printf("UUID: ");
print_uuid(nxsb->nx_uuid);
printf("\n");

printf("Next OID: 0x%" PRIx64 "\n", nxsb->nx_next_oid);
printf("Next XID: 0x%" PRIx64 "\n", nxsb->nx_next_xid);

Expand Down
Loading

0 comments on commit b82b7cd

Please sign in to comment.