Mercurial > nomad
view src/objstore/dir.c @ 862:9a63d933a60e
objstore: expose dirent add/update helpers to the rest of objstore
These are useful anytime we want to create a new directory entry - create,
link, symlink, etc.
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Sat, 17 Dec 2022 17:02:07 -0500 |
parents | |
children | 77a35abc6a24 |
line wrap: on
line source
/* * Copyright (c) 2015-2020,2022 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "dir.h" int dir_add_dirent(struct txn *txn, struct objver *dirver, const char *name, uint16_t mode, const struct noid *child) { uint8_t rawbuf[DIR_BLOCK_SIZE]; struct nattr attrs = { .size = dirver->attrs.size + DIR_BLOCK_SIZE, }; struct ndirent_tgt tgt; struct dirblock block; struct buffer buf; ssize_t ret; /* TODO: try to put it into an existing block */ buffer_init_static(&buf, rawbuf, 0, sizeof(rawbuf), true); dirblock_init(&block); tgt.type = mode >> NATTR_TSHIFT; tgt.deleted = false; tgt.host = noid_get_allocator(child); tgt.uniq = noid_get_uniq(child); ret = dirblock_add_dirent(&block, name, &tgt); if (ret) return ret; ret = dirblock_serialize(&block, &buf); if (ret) return ret; /* grow the directory by a block */ obj_setattr(txn, dirver, &attrs, OBJ_ATTR_SIZE); /* fill in the fresh block */ ret = obj_write(txn, dirver, buffer_data(&buf), buffer_size(&buf), dirver->attrs.size - DIR_BLOCK_SIZE); if (ret < 0) return ret; if (ret != buffer_size(&buf)) panic("dir block partial write!"); return 0; } static int __dir_update_dirent(struct dirblock *block, const char *name, uint16_t mode, const struct noid *child) { const size_t namelen = strlen(name); size_t non_deleted_targets; size_t i, j; /* find the dirent */ for (i = 0; i < block->ndirents; i++) { if (namelen != block->entries[i].dirent.namelen) continue; if (!strncmp(name, block->entries[i].name, namelen)) break; } VERIFY3U(i, <, block->ndirents); VERIFY(block->entries[i].dirent.all_deleted); /* find the target */ for (j = 0; j < block->entries[i].dirent.ntgts; j++) { struct ndirent_tgt *tgt = &block->entries[i].tgts[j]; if ((tgt->host != noid_get_allocator(child)) || (tgt->uniq != noid_get_uniq(child))) continue; } /* update the target */ if (j < block->entries[i].dirent.ntgts) { /* found a match - just reset the flag */ block->entries[i].tgts[j].deleted = false; } else { /* not found - allocate a new target */ struct ndirent_tgt tgt; int ret; tgt.type = mode >> NATTR_TSHIFT; tgt.deleted = false; tgt.host = noid_get_allocator(child); tgt.uniq = noid_get_uniq(child); ret = dirblock_add_dirent_target(block, name, &tgt); if (ret) return ret; } non_deleted_targets = 0; for (j = 0; j < block->entries[i].dirent.ntgts; j++) if (!block->entries[i].tgts[j].deleted) non_deleted_targets++; VERIFY3U(non_deleted_targets, ==, 1); block->entries[i].dirent.conflicts = false; block->entries[i].dirent.all_deleted = false; return 0; } int dir_update_dirent(struct txn *txn, struct objver *dirver, uint8_t *raw, uint64_t diroff, uint16_t ndirents, const char *name, uint16_t mode, const struct noid *child) { uint8_t rawbuf[DIR_BLOCK_SIZE]; struct dirblock block; struct buffer buffer; ssize_t ret; /* parse the block */ ret = dirblock_parse(&block, raw, ndirents); if (ret) return ret; /* update the dirent target */ ret = __dir_update_dirent(&block, name, mode, child); if (ret) return ret; /* serialize the block & write it out */ buffer_init_static(&buffer, rawbuf, 0, sizeof(rawbuf), true); ret = dirblock_serialize(&block, &buffer); if (ret) return ret; ret = obj_write(txn, dirver, buffer_data(&buffer), buffer_size(&buffer), diroff); if (ret < 0) return ret; if (ret != buffer_size(&buffer)) panic("dir block partial write!"); return 0; }