# HG changeset patch # User Josef 'Jeff' Sipek # Date 1671497375 18000 # Node ID 9b1ce98807c01f2841b71b35d36eafb66fc0f73f # Parent 77a35abc6a248e518c4517bbd340fb194f5fa709 objstore: drop redundant _dir from a handful of file names Signed-off-by: Josef 'Jeff' Sipek diff -r 77a35abc6a24 -r 9b1ce98807c0 src/objstore/CMakeLists.txt --- a/src/objstore/CMakeLists.txt Mon Dec 19 19:44:45 2022 -0500 +++ b/src/objstore/CMakeLists.txt Mon Dec 19 19:49:35 2022 -0500 @@ -28,12 +28,12 @@ dirent_target_packing.c obj.c obj_attr.c + obj_create.c obj_dir.c - obj_dir_create.c - obj_dir_link.c - obj_dir_unlink.c + obj_link.c obj_ops.c obj_rw.c + obj_unlink.c objstore.c txn.c vdev.c diff -r 77a35abc6a24 -r 9b1ce98807c0 src/objstore/obj_create.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/objstore/obj_create.c Mon Dec 19 19:49:35 2022 -0500 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2015-2020,2022 Josef 'Jeff' Sipek + * + * 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" + +#include + +int dir_create(struct txn *txn, struct objver *dirver, const char *name, + uint32_t owner, uint32_t group, uint16_t mode, + struct noid *_child) +{ + const uint64_t now = gettime(); + struct nattr attrs = { + .mode = mode, + .nlink = 1, /* even new dirs start with link count of 1 */ + .size = NATTR_ISDIR(mode) ? DIR_BLOCK_SIZE : 0, + .atime = now, + .btime = now, + .ctime = now, + .mtime = now, + .owner = owner, + .group = group, + }; + uint8_t raw[DIR_BLOCK_SIZE]; + struct objver *child; + struct ndirent_mem ent; + bool update_existing; + uint16_t ndirents; + uint64_t diroff; + int ret; + + ASSERT(!NATTR_ISGRAFT(mode)); + + ret = dir_lookup_entry(dirver, name, raw, &ent, &diroff, &ndirents); + if (ret) { + /* error or didn't find anything */ + if (ret != -ENOENT) + return ret; + + update_existing = false; + } else { + /* found something */ + if (!ent.all_deleted) + return -EEXIST; + + update_existing = true; + } + + /* create the child */ + child = obj_create(txn, &attrs, &dirver->obj->oid); + if (IS_ERR(child)) + return PTR_ERR(child); + + /* if the child is a directory, write out empty directory contents */ + if (NATTR_ISDIR(child->attrs.mode)) { + uint8_t raw[DIR_BLOCK_SIZE]; + struct buffer contents; + ssize_t ret2; + + buffer_init_static(&contents, raw, sizeof(raw), sizeof(raw), + true); + + ret = dir_make_buffer(noid_get_allocator(&child->obj->oid), + noid_get_uniq(&child->obj->oid), + noid_get_allocator(&dirver->obj->oid), + noid_get_uniq(&dirver->obj->oid), + &contents); + if (ret) + goto err; + + ret2 = obj_write(txn, child, raw, sizeof(raw), 0); + if (ret2 < 0) { + ret = ret2; + goto err; + } + + if (ret2 != sizeof(raw)) { + ret = -EIO; + goto err; + } + } + + /* add dirent to parent dir */ + if (!update_existing) { + ret = dir_add_dirent(txn, dirver, name, mode, &child->obj->oid); + if (ret) + goto err; + } else { + ret = dir_update_dirent(txn, dirver, raw, diroff, ndirents, + name, mode, &child->obj->oid); + if (ret) + goto err; + } + + /* + * We don't track nlinks on directories (it is always 1), but if we + * did we'd increment the parent dir's link count here. + */ + + *_child = child->obj->oid; + + ret = 0; + +err: + obj_putref(child->obj); + + return ret; +} diff -r 77a35abc6a24 -r 9b1ce98807c0 src/objstore/obj_dir_create.c --- a/src/objstore/obj_dir_create.c Mon Dec 19 19:44:45 2022 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2015-2020,2022 Josef 'Jeff' Sipek - * - * 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" - -#include - -int dir_create(struct txn *txn, struct objver *dirver, const char *name, - uint32_t owner, uint32_t group, uint16_t mode, - struct noid *_child) -{ - const uint64_t now = gettime(); - struct nattr attrs = { - .mode = mode, - .nlink = 1, /* even new dirs start with link count of 1 */ - .size = NATTR_ISDIR(mode) ? DIR_BLOCK_SIZE : 0, - .atime = now, - .btime = now, - .ctime = now, - .mtime = now, - .owner = owner, - .group = group, - }; - uint8_t raw[DIR_BLOCK_SIZE]; - struct objver *child; - struct ndirent_mem ent; - bool update_existing; - uint16_t ndirents; - uint64_t diroff; - int ret; - - ASSERT(!NATTR_ISGRAFT(mode)); - - ret = dir_lookup_entry(dirver, name, raw, &ent, &diroff, &ndirents); - if (ret) { - /* error or didn't find anything */ - if (ret != -ENOENT) - return ret; - - update_existing = false; - } else { - /* found something */ - if (!ent.all_deleted) - return -EEXIST; - - update_existing = true; - } - - /* create the child */ - child = obj_create(txn, &attrs, &dirver->obj->oid); - if (IS_ERR(child)) - return PTR_ERR(child); - - /* if the child is a directory, write out empty directory contents */ - if (NATTR_ISDIR(child->attrs.mode)) { - uint8_t raw[DIR_BLOCK_SIZE]; - struct buffer contents; - ssize_t ret2; - - buffer_init_static(&contents, raw, sizeof(raw), sizeof(raw), - true); - - ret = dir_make_buffer(noid_get_allocator(&child->obj->oid), - noid_get_uniq(&child->obj->oid), - noid_get_allocator(&dirver->obj->oid), - noid_get_uniq(&dirver->obj->oid), - &contents); - if (ret) - goto err; - - ret2 = obj_write(txn, child, raw, sizeof(raw), 0); - if (ret2 < 0) { - ret = ret2; - goto err; - } - - if (ret2 != sizeof(raw)) { - ret = -EIO; - goto err; - } - } - - /* add dirent to parent dir */ - if (!update_existing) { - ret = dir_add_dirent(txn, dirver, name, mode, &child->obj->oid); - if (ret) - goto err; - } else { - ret = dir_update_dirent(txn, dirver, raw, diroff, ndirents, - name, mode, &child->obj->oid); - if (ret) - goto err; - } - - /* - * We don't track nlinks on directories (it is always 1), but if we - * did we'd increment the parent dir's link count here. - */ - - *_child = child->obj->oid; - - ret = 0; - -err: - obj_putref(child->obj); - - return ret; -} diff -r 77a35abc6a24 -r 9b1ce98807c0 src/objstore/obj_dir_link.c --- a/src/objstore/obj_dir_link.c Mon Dec 19 19:44:45 2022 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2020,2022 Josef 'Jeff' Sipek - * - * 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" - -#include - -int dir_symlink(struct txn *txn, struct objver *dirver, const char *name, - uint32_t owner, uint32_t group, uint16_t mode, - const char *target, struct noid *_child) -{ - const uint64_t now = gettime(); - struct nattr attrs = { - .mode = mode, - .nlink = 1, - .size = strlen(target), - .atime = now, - .btime = now, - .ctime = now, - .mtime = now, - .owner = owner, - .group = group, - }; - uint8_t raw[DIR_BLOCK_SIZE]; - struct ndirent_mem ent; - bool update_existing; - struct objver *child; - uint16_t ndirents; - uint64_t diroff; - ssize_t ret; - - ASSERT(NATTR_ISLNK(mode)); - - ret = dir_lookup_entry(dirver, name, raw, &ent, &diroff, &ndirents); - if (ret) { - /* error or didn't find anything */ - if (ret != -ENOENT) - return ret; - - update_existing = false; - } else { - /* found something */ - if (!ent.all_deleted) - return -EEXIST; - - update_existing = true; - } - - /* make new oid for the child */ - child = obj_create(txn, &attrs, &dirver->obj->oid); - if (IS_ERR(child)) - return PTR_ERR(child); - - /* write out symlink target */ - ret = obj_write(txn, child, target, strlen(target), 0); - if (ret < 0) - goto err; - - if (ret != strlen(target)) { - ret = -EIO; - goto err; - } - - /* add dirent to parent dir */ - if (!update_existing) { - ret = dir_add_dirent(txn, dirver, name, mode, &child->obj->oid); - if (ret) - return ret; - } else { - ret = dir_update_dirent(txn, dirver, raw, diroff, ndirents, - name, mode, &child->obj->oid); - if (ret) - return ret; - } - - *_child = child->obj->oid; - - ret = 0; - -err: - obj_putref(child->obj); - - return ret; -} diff -r 77a35abc6a24 -r 9b1ce98807c0 src/objstore/obj_dir_unlink.c --- a/src/objstore/obj_dir_unlink.c Mon Dec 19 19:44:45 2022 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2015-2020,2022 Josef 'Jeff' Sipek - * - * 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" - -static int __dir_unlink_update(struct dirblock *block, const char *name, - const struct noid *desired, bool rmdir) -{ - 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->deleted) - continue; - - if (noid_is_null(desired)) - break; /* found it */ - - /* looking for a specific target */ - - if (tgt->type == NDIRENT_TYPE_GRAFT) { - if (xuuid_compare(&tgt->graft, noid_get_vol(desired))) - continue; - } else { - if ((tgt->host != noid_get_allocator(desired)) || - (tgt->uniq != noid_get_uniq(desired))) - continue; - } - } - - VERIFY3U(j, <, block->entries[i].dirent.ntgts); - VERIFY(!block->entries[i].tgts[j].deleted); - - if (rmdir && (block->entries[i].tgts[j].type != NDIRENT_TYPE_DIR)) - return -ENOTDIR; - if (!rmdir && (block->entries[i].tgts[j].type == NDIRENT_TYPE_DIR)) - return -EISDIR; - - if (!rmdir) - FIXME("need to decrement the target's link count"); - - /* update the target */ - block->entries[i].tgts[j].deleted = true; - - non_deleted_targets = 0; - for (j = 0; j < block->entries[i].dirent.ntgts; j++) - if (!block->entries[i].tgts[j].deleted) - non_deleted_targets++; - - if (!block->entries[i].dirent.conflicts) - VERIFY3U(non_deleted_targets, ==, 0); - - block->entries[i].dirent.conflicts = (non_deleted_targets > 1); - block->entries[i].dirent.all_deleted = (non_deleted_targets == 0); - - return 0; -} - -int dir_unlink(struct txn *txn, struct objver *dirver, const char *name, - const struct noid *desired, bool rmdir) -{ - uint8_t raw[DIR_BLOCK_SIZE]; - struct ndirent_mem ent; - struct dirblock block; - struct buffer buffer; - uint64_t diroff; - uint16_t ndirents; - ssize_t ret; - - ret = dir_lookup_entry(dirver, name, raw, &ent, &diroff, - &ndirents); - if (ret) - return ret; - - if (ent.all_deleted) - return -ENOENT; - - if (ent.conflicts && noid_is_null(desired)) - return -ENOTUNIQ; - - /* parse the block */ - ret = dirblock_parse(&block, raw, ndirents); - if (ret) - return ret; - - /* update the dirent target */ - ret = __dir_unlink_update(&block, name, desired, rmdir); - if (ret) - return ret; - - /* serialize the block & write it out */ - buffer_init_static(&buffer, raw, 0, sizeof(raw), 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; -} diff -r 77a35abc6a24 -r 9b1ce98807c0 src/objstore/obj_link.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/objstore/obj_link.c Mon Dec 19 19:49:35 2022 -0500 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2020,2022 Josef 'Jeff' Sipek + * + * 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" + +#include + +int dir_symlink(struct txn *txn, struct objver *dirver, const char *name, + uint32_t owner, uint32_t group, uint16_t mode, + const char *target, struct noid *_child) +{ + const uint64_t now = gettime(); + struct nattr attrs = { + .mode = mode, + .nlink = 1, + .size = strlen(target), + .atime = now, + .btime = now, + .ctime = now, + .mtime = now, + .owner = owner, + .group = group, + }; + uint8_t raw[DIR_BLOCK_SIZE]; + struct ndirent_mem ent; + bool update_existing; + struct objver *child; + uint16_t ndirents; + uint64_t diroff; + ssize_t ret; + + ASSERT(NATTR_ISLNK(mode)); + + ret = dir_lookup_entry(dirver, name, raw, &ent, &diroff, &ndirents); + if (ret) { + /* error or didn't find anything */ + if (ret != -ENOENT) + return ret; + + update_existing = false; + } else { + /* found something */ + if (!ent.all_deleted) + return -EEXIST; + + update_existing = true; + } + + /* make new oid for the child */ + child = obj_create(txn, &attrs, &dirver->obj->oid); + if (IS_ERR(child)) + return PTR_ERR(child); + + /* write out symlink target */ + ret = obj_write(txn, child, target, strlen(target), 0); + if (ret < 0) + goto err; + + if (ret != strlen(target)) { + ret = -EIO; + goto err; + } + + /* add dirent to parent dir */ + if (!update_existing) { + ret = dir_add_dirent(txn, dirver, name, mode, &child->obj->oid); + if (ret) + return ret; + } else { + ret = dir_update_dirent(txn, dirver, raw, diroff, ndirents, + name, mode, &child->obj->oid); + if (ret) + return ret; + } + + *_child = child->obj->oid; + + ret = 0; + +err: + obj_putref(child->obj); + + return ret; +} diff -r 77a35abc6a24 -r 9b1ce98807c0 src/objstore/obj_unlink.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/objstore/obj_unlink.c Mon Dec 19 19:49:35 2022 -0500 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2015-2020,2022 Josef 'Jeff' Sipek + * + * 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" + +static int __dir_unlink_update(struct dirblock *block, const char *name, + const struct noid *desired, bool rmdir) +{ + 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->deleted) + continue; + + if (noid_is_null(desired)) + break; /* found it */ + + /* looking for a specific target */ + + if (tgt->type == NDIRENT_TYPE_GRAFT) { + if (xuuid_compare(&tgt->graft, noid_get_vol(desired))) + continue; + } else { + if ((tgt->host != noid_get_allocator(desired)) || + (tgt->uniq != noid_get_uniq(desired))) + continue; + } + } + + VERIFY3U(j, <, block->entries[i].dirent.ntgts); + VERIFY(!block->entries[i].tgts[j].deleted); + + if (rmdir && (block->entries[i].tgts[j].type != NDIRENT_TYPE_DIR)) + return -ENOTDIR; + if (!rmdir && (block->entries[i].tgts[j].type == NDIRENT_TYPE_DIR)) + return -EISDIR; + + if (!rmdir) + FIXME("need to decrement the target's link count"); + + /* update the target */ + block->entries[i].tgts[j].deleted = true; + + non_deleted_targets = 0; + for (j = 0; j < block->entries[i].dirent.ntgts; j++) + if (!block->entries[i].tgts[j].deleted) + non_deleted_targets++; + + if (!block->entries[i].dirent.conflicts) + VERIFY3U(non_deleted_targets, ==, 0); + + block->entries[i].dirent.conflicts = (non_deleted_targets > 1); + block->entries[i].dirent.all_deleted = (non_deleted_targets == 0); + + return 0; +} + +int dir_unlink(struct txn *txn, struct objver *dirver, const char *name, + const struct noid *desired, bool rmdir) +{ + uint8_t raw[DIR_BLOCK_SIZE]; + struct ndirent_mem ent; + struct dirblock block; + struct buffer buffer; + uint64_t diroff; + uint16_t ndirents; + ssize_t ret; + + ret = dir_lookup_entry(dirver, name, raw, &ent, &diroff, + &ndirents); + if (ret) + return ret; + + if (ent.all_deleted) + return -ENOENT; + + if (ent.conflicts && noid_is_null(desired)) + return -ENOTUNIQ; + + /* parse the block */ + ret = dirblock_parse(&block, raw, ndirents); + if (ret) + return ret; + + /* update the dirent target */ + ret = __dir_unlink_update(&block, name, desired, rmdir); + if (ret) + return ret; + + /* serialize the block & write it out */ + buffer_init_static(&buffer, raw, 0, sizeof(raw), 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; +}