salvage: preserve xattr backed metadata
This commit is contained in:
@@ -48,7 +48,19 @@ struct nwsalvage_deleted_entry {
|
||||
|
||||
const char *finder_info_hex;
|
||||
const char *afp_entry_id;
|
||||
unsigned int afp_attributes;
|
||||
unsigned long long resource_fork_size;
|
||||
|
||||
unsigned int netware_archive_flags;
|
||||
unsigned int netware_archive_date;
|
||||
unsigned int netware_archive_time;
|
||||
unsigned long netware_archiver_id;
|
||||
|
||||
unsigned int netware_fileinfo_flags;
|
||||
unsigned int netware_create_date;
|
||||
unsigned int netware_create_time;
|
||||
unsigned long netware_creator_id;
|
||||
unsigned long netware_modifier_id;
|
||||
};
|
||||
|
||||
struct nwsalvage_metadata_entry {
|
||||
@@ -73,7 +85,19 @@ struct nwsalvage_metadata_entry {
|
||||
|
||||
char finder_info_hex[NWSALVAGE_FINDER_INFO_HEX_LEN + 1];
|
||||
char afp_entry_id[NWSALVAGE_AFP_ENTRY_ID_MAX];
|
||||
unsigned int afp_attributes;
|
||||
unsigned long long resource_fork_size;
|
||||
|
||||
unsigned int netware_archive_flags;
|
||||
unsigned int netware_archive_date;
|
||||
unsigned int netware_archive_time;
|
||||
unsigned long netware_archiver_id;
|
||||
|
||||
unsigned int netware_fileinfo_flags;
|
||||
unsigned int netware_create_date;
|
||||
unsigned int netware_create_time;
|
||||
unsigned long netware_creator_id;
|
||||
unsigned long netware_modifier_id;
|
||||
};
|
||||
|
||||
int nwsalvage_config_defaults(struct nwsalvage_config *config);
|
||||
|
||||
@@ -685,10 +685,42 @@ int nwsalvage_write_metadata(const char *metadata_path,
|
||||
if (!failed && json_add_string(doc, object, "afp_entry_id",
|
||||
entry->afp_entry_id ? entry->afp_entry_id : "") < 0)
|
||||
failed = 1;
|
||||
if (!failed && json_add_uint64(doc, object, "afp_attributes",
|
||||
entry->afp_attributes) < 0)
|
||||
failed = 1;
|
||||
if (!failed && json_add_uint64(doc, object, "resource_fork_size",
|
||||
entry->resource_fork_size) < 0)
|
||||
failed = 1;
|
||||
|
||||
if (!failed && json_add_uint64(doc, object, "netware_archive_flags",
|
||||
entry->netware_archive_flags) < 0)
|
||||
failed = 1;
|
||||
if (!failed && json_add_uint64(doc, object, "netware_archive_date",
|
||||
entry->netware_archive_date) < 0)
|
||||
failed = 1;
|
||||
if (!failed && json_add_uint64(doc, object, "netware_archive_time",
|
||||
entry->netware_archive_time) < 0)
|
||||
failed = 1;
|
||||
if (!failed && json_add_uint64(doc, object, "netware_archiver_id",
|
||||
entry->netware_archiver_id) < 0)
|
||||
failed = 1;
|
||||
|
||||
if (!failed && json_add_uint64(doc, object, "netware_fileinfo_flags",
|
||||
entry->netware_fileinfo_flags) < 0)
|
||||
failed = 1;
|
||||
if (!failed && json_add_uint64(doc, object, "netware_create_date",
|
||||
entry->netware_create_date) < 0)
|
||||
failed = 1;
|
||||
if (!failed && json_add_uint64(doc, object, "netware_create_time",
|
||||
entry->netware_create_time) < 0)
|
||||
failed = 1;
|
||||
if (!failed && json_add_uint64(doc, object, "netware_creator_id",
|
||||
entry->netware_creator_id) < 0)
|
||||
failed = 1;
|
||||
if (!failed && json_add_uint64(doc, object, "netware_modifier_id",
|
||||
entry->netware_modifier_id) < 0)
|
||||
failed = 1;
|
||||
|
||||
if (!failed && !yyjson_mut_write_file(metadata_path, doc,
|
||||
YYJSON_WRITE_PRETTY_TWO_SPACES |
|
||||
YYJSON_WRITE_NEWLINE_AT_END,
|
||||
@@ -805,11 +837,53 @@ int nwsalvage_read_metadata(const char *metadata_path,
|
||||
entry->afp_entry_id,
|
||||
sizeof(entry->afp_entry_id)) < 0)
|
||||
failed = 1;
|
||||
if (!failed && json_get_uint64(object, "afp_attributes", &value) < 0)
|
||||
failed = 1;
|
||||
else if (!failed)
|
||||
entry->afp_attributes = (unsigned int)value;
|
||||
if (!failed && json_get_uint64(object, "resource_fork_size", &value) < 0)
|
||||
failed = 1;
|
||||
else if (!failed)
|
||||
entry->resource_fork_size = value;
|
||||
|
||||
if (!failed && json_get_uint64(object, "netware_archive_flags", &value) < 0)
|
||||
failed = 1;
|
||||
else if (!failed)
|
||||
entry->netware_archive_flags = (unsigned int)value;
|
||||
if (!failed && json_get_uint64(object, "netware_archive_date", &value) < 0)
|
||||
failed = 1;
|
||||
else if (!failed)
|
||||
entry->netware_archive_date = (unsigned int)value;
|
||||
if (!failed && json_get_uint64(object, "netware_archive_time", &value) < 0)
|
||||
failed = 1;
|
||||
else if (!failed)
|
||||
entry->netware_archive_time = (unsigned int)value;
|
||||
if (!failed && json_get_uint64(object, "netware_archiver_id", &value) < 0)
|
||||
failed = 1;
|
||||
else if (!failed)
|
||||
entry->netware_archiver_id = (unsigned long)value;
|
||||
|
||||
if (!failed && json_get_uint64(object, "netware_fileinfo_flags", &value) < 0)
|
||||
failed = 1;
|
||||
else if (!failed)
|
||||
entry->netware_fileinfo_flags = (unsigned int)value;
|
||||
if (!failed && json_get_uint64(object, "netware_create_date", &value) < 0)
|
||||
failed = 1;
|
||||
else if (!failed)
|
||||
entry->netware_create_date = (unsigned int)value;
|
||||
if (!failed && json_get_uint64(object, "netware_create_time", &value) < 0)
|
||||
failed = 1;
|
||||
else if (!failed)
|
||||
entry->netware_create_time = (unsigned int)value;
|
||||
if (!failed && json_get_uint64(object, "netware_creator_id", &value) < 0)
|
||||
failed = 1;
|
||||
else if (!failed)
|
||||
entry->netware_creator_id = (unsigned long)value;
|
||||
if (!failed && json_get_uint64(object, "netware_modifier_id", &value) < 0)
|
||||
failed = 1;
|
||||
else if (!failed)
|
||||
entry->netware_modifier_id = (unsigned long)value;
|
||||
|
||||
yyjson_doc_free(doc);
|
||||
|
||||
if (failed) {
|
||||
|
||||
@@ -10,6 +10,8 @@ contract before `src/nwsalvage.c` exists:
|
||||
|
||||
- deleted file payloads live below the recycle repository,
|
||||
- per-object JSON metadata lives below the salvage repository,
|
||||
- JSON metadata preserves mars_nwe xattr-backed NetWare/AFP fields
|
||||
from `nwarchive` and `nwatalk`,
|
||||
- there is no large per-directory index file,
|
||||
- stale JSON metadata is detectable when the matching recycle payload is gone.
|
||||
|
||||
@@ -20,7 +22,10 @@ Default repository names come from the `nwserv.conf`/`nw.ini` template options:
|
||||
49 .recycle .salvage
|
||||
```
|
||||
|
||||
Expected layout for a deleted `SYS:PUBLIC/PMDFLTS.INI` owned by `SUPERVISOR`:
|
||||
Expected layout for a deleted `SYS:PUBLIC/PMDFLTS.INI` owned by `SUPERVISOR`.
|
||||
The sidecar JSON must carry the server-only metadata needed for exact recover,
|
||||
including NetWare archive/fileinfo xattrs and AFP FinderInfo/entry-id/attribute
|
||||
xattrs:
|
||||
|
||||
```text
|
||||
SYS/.recycle/SUPERVISOR/PUBLIC/PMDFLTS.INI
|
||||
|
||||
@@ -232,7 +232,17 @@ int main(void)
|
||||
deleted_entry.finder_info_hex =
|
||||
"0000000000000000000000000000000000000000000000000000000000000000";
|
||||
deleted_entry.afp_entry_id = "0x2cc1243d";
|
||||
deleted_entry.afp_attributes = 0x0600;
|
||||
deleted_entry.resource_fork_size = 0;
|
||||
deleted_entry.netware_archive_flags = 0x07;
|
||||
deleted_entry.netware_archive_date = 0x5821;
|
||||
deleted_entry.netware_archive_time = 0x6c40;
|
||||
deleted_entry.netware_archiver_id = 0x01020304;
|
||||
deleted_entry.netware_fileinfo_flags = 0x0f;
|
||||
deleted_entry.netware_create_date = 0x5820;
|
||||
deleted_entry.netware_create_time = 0x6b20;
|
||||
deleted_entry.netware_creator_id = 0x00000001;
|
||||
deleted_entry.netware_modifier_id = 0x00000002;
|
||||
|
||||
failures += expect_true(nwsalvage_write_metadata(path, &deleted_entry) == 0,
|
||||
"metadata writer creates parent dirs and JSON");
|
||||
@@ -252,6 +262,12 @@ int main(void)
|
||||
"metadata JSON contains Finder info");
|
||||
failures += expect_true(file_contains(path, "\"afp_entry_id\": \"0x2cc1243d\""),
|
||||
"metadata JSON contains AFP entry id");
|
||||
failures += expect_true(file_contains(path, "\"afp_attributes\": 1536"),
|
||||
"metadata JSON contains AFP xattr attributes");
|
||||
failures += expect_true(file_contains(path, "\"netware_archive_flags\": 7"),
|
||||
"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, "\"attributes\": 8192"),
|
||||
"metadata JSON contains attributes");
|
||||
failures += expect_true(nwsalvage_read_metadata(path, &metadata_entry) == 0,
|
||||
@@ -291,8 +307,28 @@ int main(void)
|
||||
"metadata reader returns Finder info");
|
||||
failures += expect_true(!strcmp(metadata_entry.afp_entry_id, "0x2cc1243d"),
|
||||
"metadata reader returns AFP entry id");
|
||||
failures += expect_true(metadata_entry.afp_attributes == 0x0600,
|
||||
"metadata reader returns AFP attributes");
|
||||
failures += expect_true(metadata_entry.resource_fork_size == 0,
|
||||
"metadata reader returns resource fork size");
|
||||
failures += expect_true(metadata_entry.netware_archive_flags == 0x07,
|
||||
"metadata reader returns NetWare archive flags");
|
||||
failures += expect_true(metadata_entry.netware_archive_date == 0x5821,
|
||||
"metadata reader returns NetWare archive date");
|
||||
failures += expect_true(metadata_entry.netware_archive_time == 0x6c40,
|
||||
"metadata reader returns NetWare archive time");
|
||||
failures += expect_true(metadata_entry.netware_archiver_id == 0x01020304,
|
||||
"metadata reader returns NetWare archiver id");
|
||||
failures += expect_true(metadata_entry.netware_fileinfo_flags == 0x0f,
|
||||
"metadata reader returns NetWare fileinfo flags");
|
||||
failures += expect_true(metadata_entry.netware_create_date == 0x5820,
|
||||
"metadata reader returns NetWare create date");
|
||||
failures += expect_true(metadata_entry.netware_create_time == 0x6b20,
|
||||
"metadata reader returns NetWare create time");
|
||||
failures += expect_true(metadata_entry.netware_creator_id == 0x00000001,
|
||||
"metadata reader returns NetWare creator id");
|
||||
failures += expect_true(metadata_entry.netware_modifier_id == 0x00000002,
|
||||
"metadata reader returns NetWare modifier id");
|
||||
}
|
||||
remove_test_tree(root);
|
||||
#else
|
||||
|
||||
Reference in New Issue
Block a user