salvage: preserve trustee metadata
All checks were successful
Source release / source-package (push) Successful in 52s
All checks were successful
Source release / source-package (push) Successful in 52s
This commit is contained in:
@@ -19,6 +19,7 @@ typedef int (*nwsalvage_ini_getter)(int entry, char *str,
|
||||
#define NWSALVAGE_USER_NAME_MAX 128
|
||||
#define NWSALVAGE_FINDER_INFO_HEX_LEN 64
|
||||
#define NWSALVAGE_AFP_ENTRY_ID_MAX 32
|
||||
#define NWSALVAGE_TRUSTEE_MAX 100
|
||||
|
||||
struct nwsalvage_config {
|
||||
int enabled;
|
||||
@@ -26,6 +27,11 @@ struct nwsalvage_config {
|
||||
char metadata_repository[NWSALVAGE_REPOSITORY_NAME_MAX];
|
||||
};
|
||||
|
||||
struct nwsalvage_trustee_entry {
|
||||
unsigned long object_id;
|
||||
unsigned int rights;
|
||||
};
|
||||
|
||||
struct nwsalvage_deleted_entry {
|
||||
const char *source;
|
||||
const char *volume_name;
|
||||
@@ -61,6 +67,10 @@ struct nwsalvage_deleted_entry {
|
||||
unsigned int netware_create_time;
|
||||
unsigned long netware_creator_id;
|
||||
unsigned long netware_modifier_id;
|
||||
|
||||
unsigned int inherited_rights_mask;
|
||||
unsigned int trustee_count;
|
||||
struct nwsalvage_trustee_entry trustees[NWSALVAGE_TRUSTEE_MAX];
|
||||
};
|
||||
|
||||
struct nwsalvage_metadata_entry {
|
||||
@@ -98,6 +108,10 @@ struct nwsalvage_metadata_entry {
|
||||
unsigned int netware_create_time;
|
||||
unsigned long netware_creator_id;
|
||||
unsigned long netware_modifier_id;
|
||||
|
||||
unsigned int inherited_rights_mask;
|
||||
unsigned int trustee_count;
|
||||
struct nwsalvage_trustee_entry trustees[NWSALVAGE_TRUSTEE_MAX];
|
||||
};
|
||||
|
||||
int nwsalvage_config_defaults(struct nwsalvage_config *config);
|
||||
|
||||
105
src/nwsalvage.c
105
src/nwsalvage.c
@@ -599,6 +599,98 @@ static int json_get_long(yyjson_val *object, const char *name, long *out)
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static int json_add_trustees(yyjson_mut_doc *doc,
|
||||
yyjson_mut_val *object,
|
||||
const struct nwsalvage_deleted_entry *entry)
|
||||
{
|
||||
yyjson_mut_val *array;
|
||||
unsigned int i;
|
||||
|
||||
if (!doc || !object || !entry) {
|
||||
errno = EINVAL;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (entry->trustee_count > NWSALVAGE_TRUSTEE_MAX) {
|
||||
errno = EINVAL;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
array = yyjson_mut_arr(doc);
|
||||
if (!array) {
|
||||
errno = ENOMEM;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
for (i = 0; i < entry->trustee_count; i++) {
|
||||
yyjson_mut_val *trustee = yyjson_mut_obj(doc);
|
||||
if (!trustee) {
|
||||
errno = ENOMEM;
|
||||
return(-1);
|
||||
}
|
||||
if (json_add_uint64(doc, trustee, "object_id",
|
||||
entry->trustees[i].object_id) < 0 ||
|
||||
json_add_uint64(doc, trustee, "rights",
|
||||
entry->trustees[i].rights) < 0 ||
|
||||
!yyjson_mut_arr_append(array, trustee)) {
|
||||
if (!errno) errno = ENOMEM;
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!yyjson_mut_obj_add_val(doc, object, "trustees", array)) {
|
||||
errno = ENOMEM;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int json_get_trustees(yyjson_val *object,
|
||||
struct nwsalvage_metadata_entry *entry)
|
||||
{
|
||||
yyjson_val *array;
|
||||
yyjson_val *item;
|
||||
size_t idx;
|
||||
size_t max;
|
||||
|
||||
if (!object || !entry) {
|
||||
errno = EINVAL;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
array = yyjson_obj_get(object, "trustees");
|
||||
if (!yyjson_is_arr(array)) {
|
||||
errno = EINVAL;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
max = yyjson_arr_size(array);
|
||||
if (max > NWSALVAGE_TRUSTEE_MAX) {
|
||||
errno = EINVAL;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
entry->trustee_count = (unsigned int)max;
|
||||
yyjson_arr_foreach(array, idx, max, item) {
|
||||
unsigned long long value;
|
||||
|
||||
if (!yyjson_is_obj(item)) {
|
||||
errno = EINVAL;
|
||||
return(-1);
|
||||
}
|
||||
if (json_get_uint64(item, "object_id", &value) < 0)
|
||||
return(-1);
|
||||
entry->trustees[idx].object_id = (unsigned long)value;
|
||||
if (json_get_uint64(item, "rights", &value) < 0)
|
||||
return(-1);
|
||||
entry->trustees[idx].rights = (unsigned int)value;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int nwsalvage_write_metadata(const char *metadata_path,
|
||||
const struct nwsalvage_deleted_entry *entry)
|
||||
{
|
||||
@@ -721,6 +813,12 @@ int nwsalvage_write_metadata(const char *metadata_path,
|
||||
entry->netware_modifier_id) < 0)
|
||||
failed = 1;
|
||||
|
||||
if (!failed && json_add_uint64(doc, object, "inherited_rights_mask",
|
||||
entry->inherited_rights_mask) < 0)
|
||||
failed = 1;
|
||||
if (!failed && json_add_trustees(doc, object, entry) < 0)
|
||||
failed = 1;
|
||||
|
||||
if (!failed && !yyjson_mut_write_file(metadata_path, doc,
|
||||
YYJSON_WRITE_PRETTY_TWO_SPACES |
|
||||
YYJSON_WRITE_NEWLINE_AT_END,
|
||||
@@ -884,6 +982,13 @@ int nwsalvage_read_metadata(const char *metadata_path,
|
||||
else if (!failed)
|
||||
entry->netware_modifier_id = (unsigned long)value;
|
||||
|
||||
if (!failed && json_get_uint64(object, "inherited_rights_mask", &value) < 0)
|
||||
failed = 1;
|
||||
else if (!failed)
|
||||
entry->inherited_rights_mask = (unsigned int)value;
|
||||
if (!failed && json_get_trustees(object, entry) < 0)
|
||||
failed = 1;
|
||||
|
||||
yyjson_doc_free(doc);
|
||||
|
||||
if (failed) {
|
||||
|
||||
@@ -39,3 +39,12 @@ Future runtime tests should add direct coverage for:
|
||||
- `NCP 0x2222 / 87 / 17` Recover Salvageable File,
|
||||
- `NCP 0x2222 / 87 / 18` Purge Salvageable File,
|
||||
- AFP `0x13` as a thin adapter over the shared salvage backend.
|
||||
|
||||
Trustee metadata
|
||||
----------------
|
||||
|
||||
NetWare trustee rights are stored by mars_nwe in the trustee store, keyed by
|
||||
volume/dev/inode, rather than in the file payload itself. Salvage metadata
|
||||
therefore needs to preserve the inherited rights mask and the explicit trustee
|
||||
object/right pairs so recovery can recreate equivalent trustee records for the
|
||||
restored object.
|
||||
|
||||
@@ -243,6 +243,12 @@ int main(void)
|
||||
deleted_entry.netware_create_time = 0x6b20;
|
||||
deleted_entry.netware_creator_id = 0x00000001;
|
||||
deleted_entry.netware_modifier_id = 0x00000002;
|
||||
deleted_entry.inherited_rights_mask = 0x01ff;
|
||||
deleted_entry.trustee_count = 2;
|
||||
deleted_entry.trustees[0].object_id = 0x00000001;
|
||||
deleted_entry.trustees[0].rights = 0x01ff;
|
||||
deleted_entry.trustees[1].object_id = 0x01020304;
|
||||
deleted_entry.trustees[1].rights = 0x0041;
|
||||
|
||||
failures += expect_true(nwsalvage_write_metadata(path, &deleted_entry) == 0,
|
||||
"metadata writer creates parent dirs and JSON");
|
||||
@@ -268,6 +274,12 @@ int main(void)
|
||||
"metadata JSON contains NetWare archive xattr flags");
|
||||
failures += expect_true(file_contains(path, "\"netware_fileinfo_flags\": 15"),
|
||||
"metadata JSON contains NetWare fileinfo xattr flags");
|
||||
failures += expect_true(file_contains(path, "\"inherited_rights_mask\": 511"),
|
||||
"metadata JSON contains trustee inherited rights mask");
|
||||
failures += expect_true(file_contains(path, "\"trustees\":"),
|
||||
"metadata JSON contains trustee rights array");
|
||||
failures += expect_true(file_contains(path, "\"object_id\": 16909060"),
|
||||
"metadata JSON contains trustee object id");
|
||||
failures += expect_true(file_contains(path, "\"attributes\": 8192"),
|
||||
"metadata JSON contains attributes");
|
||||
failures += expect_true(nwsalvage_read_metadata(path, &metadata_entry) == 0,
|
||||
@@ -329,6 +341,18 @@ int main(void)
|
||||
"metadata reader returns NetWare creator id");
|
||||
failures += expect_true(metadata_entry.netware_modifier_id == 0x00000002,
|
||||
"metadata reader returns NetWare modifier id");
|
||||
failures += expect_true(metadata_entry.inherited_rights_mask == 0x01ff,
|
||||
"metadata reader returns trustee inherited rights mask");
|
||||
failures += expect_true(metadata_entry.trustee_count == 2,
|
||||
"metadata reader returns trustee count");
|
||||
failures += expect_true(metadata_entry.trustees[0].object_id == 0x00000001,
|
||||
"metadata reader returns first trustee object id");
|
||||
failures += expect_true(metadata_entry.trustees[0].rights == 0x01ff,
|
||||
"metadata reader returns first trustee rights");
|
||||
failures += expect_true(metadata_entry.trustees[1].object_id == 0x01020304,
|
||||
"metadata reader returns second trustee object id");
|
||||
failures += expect_true(metadata_entry.trustees[1].rights == 0x0041,
|
||||
"metadata reader returns second trustee rights");
|
||||
}
|
||||
remove_test_tree(root);
|
||||
#else
|
||||
|
||||
Reference in New Issue
Block a user