Mercurial > nomad
changeset 785:c2a9fdacbfcc
objstore: add dirblock_parse
Parse an entire directory block into a struct dirblock. It preserves the
dirent ordering.
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Thu, 26 Mar 2020 15:14:03 -0400 |
parents | 6c935af513e5 |
children | 3fc635b4636f |
files | src/objstore/dir.h src/objstore/dirblock.c |
diffstat | 2 files changed, 72 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/src/objstore/dir.h Tue Mar 31 13:09:19 2020 -0400 +++ b/src/objstore/dir.h Thu Mar 26 15:14:03 2020 -0400 @@ -210,6 +210,7 @@ }; extern void dirblock_init(struct dirblock *block); +extern int dirblock_parse(struct dirblock *block, uint8_t *raw, uint16_t ndirents); extern int dirblock_serialize(struct dirblock *block, struct buffer *buf); extern int dirblock_add_dirent(struct dirblock *block, const char *name, const struct ndirent_tgt *tgt);
--- a/src/objstore/dirblock.c Tue Mar 31 13:09:19 2020 -0400 +++ b/src/objstore/dirblock.c Thu Mar 26 15:14:03 2020 -0400 @@ -36,6 +36,77 @@ block->ntgts = 0; } +/* parse a block */ +int dirblock_parse(struct dirblock *block, uint8_t *raw, uint16_t ndirents) +{ + size_t i, j; + + dirblock_init(block); + + /* for each dirent */ + for (i = 0; i < ndirents; i++) { + const int idx = block->ndirents; + struct ndirent_mem *dirent = &block->entries[idx].dirent; + size_t non_deleted_targets; + struct buffer tgtbuf; + int ret; + + dirent_be2cpu(dirent, + (void *) &raw[sizeof(struct obj_dir_header) + + sizeof(struct ndirent_phys) * i]); + + /* complete the fixed sized dirent */ + block->entries[idx].name = &block->names[block->name_bytes]; + block->entries[idx].tgts = &block->tgts[block->ntgts]; + + /* save the name */ + memcpy(&block->names[block->name_bytes], &raw[dirent->nameoff], + dirent->namelen); + + /* save the targets */ + buffer_init_static(&tgtbuf, &raw[dirent->tgtoff], + DIR_BLOCK_SIZE - dirent->tgtoff, false); + + non_deleted_targets = 0; + for (j = block->ntgts; j < (block->ntgts + dirent->ntgts); j++) { + ret = unpack_dirent_tgt(&tgtbuf, &block->tgts[j]); + if (ret) + return ret; + + if (!block->tgts[j].deleted) + non_deleted_targets++; + } + + /* check and correct dirent flags */ + if (dirent->conflicts != (non_deleted_targets > 1)) + cmn_err(CE_WARN, "Parsed dirent conflicts (%s) " + "mismatches targets (%zu !deleted)...fixed", + dirent->conflicts ? "true" : "false", + non_deleted_targets); + if (dirent->all_deleted != (non_deleted_targets == 0)) + cmn_err(CE_WARN, "Parsed dirent all_deleted (%s) " + "mismatches targets (%zu !deleted)...fixed", + dirent->all_deleted ? "true" : "false", + non_deleted_targets); + + dirent->conflicts = (non_deleted_targets > 1); + dirent->all_deleted = (non_deleted_targets == 0); + + /* update block state */ + block->used_bytes += sizeof(struct ndirent_phys) + + dirent->namelen + buffer_offset(&tgtbuf); + block->name_bytes += dirent->namelen; + block->ndirents++; + block->ntgts += dirent->ntgts; + + /* poison the block's memory entries to avoid accidents */ + dirent->tgtoff = DIRBLOCK_DIRENT_OFFSET_POISON; + dirent->nameoff = DIRBLOCK_DIRENT_OFFSET_POISON; + } + + return 0; +} + static void __dirblock_serialize_check_dirent(struct dirblock *block, size_t dirent) {