changeset 882:f9ea425467d3

objstore: implement symlink Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Sun, 18 Dec 2022 10:15:13 -0500
parents 180558179a08
children c61456afbba3
files src/objstore/CMakeLists.txt src/objstore/obj_dir_link.c src/objstore/obj_ops.c src/objstore/objstore_impl.h
diffstat 4 files changed, 151 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/src/objstore/CMakeLists.txt	Sat Dec 17 20:40:39 2022 -0500
+++ b/src/objstore/CMakeLists.txt	Sun Dec 18 10:15:13 2022 -0500
@@ -29,6 +29,7 @@
 	obj.c
 	obj_dir.c
 	obj_dir_create.c
+	obj_dir_link.c
 	obj_dir_unlink.c
 	obj_ops.c
 	obj_txn.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/objstore/obj_dir_link.c	Sun Dec 18 10:15:13 2022 -0500
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 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"
+
+#include <jeffpc/time.h>
+
+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;
+}
--- a/src/objstore/obj_ops.c	Sat Dec 17 20:40:39 2022 -0500
+++ b/src/objstore/obj_ops.c	Sun Dec 18 10:15:13 2022 -0500
@@ -426,7 +426,50 @@
 		     uint32_t owner, uint32_t group, uint16_t mode,
 		     const char *target, struct noid *child)
 {
-	return -ENOTSUP;
+	struct objver *newver;
+	struct obj *dir;
+	struct txn txn;
+	int ret;
+
+	if (!diropen || !name || !target)
+		return -EINVAL;
+
+	/* must have a type */
+	if (!NATTR_ISLNK(mode))
+		return -EINVAL;
+
+	dir = diropen->obj;
+
+	if (diropen->qualified)
+		return -EROFS;
+
+	MXLOCK(&dir->lock);
+
+	if (!NATTR_ISDIR(diropen->ver->attrs.mode)) {
+		ret = -ENOTDIR;
+		goto err;
+	}
+
+	ret = txn_begin(&txn, diropen->ver->obj->clone);
+	if (ret)
+		goto err;
+
+	newver = obj_cow(&txn, diropen);
+	if (IS_ERR(newver)) {
+		ret = PTR_ERR(newver);
+		goto err_txn;
+	}
+
+	ret = dir_symlink(&txn, newver, name, owner, group, mode, target, child);
+
+err_txn:
+	ret = txn_commitabort(&txn, ret);
+	newver = NULL; /* prevent accidental use */
+
+err:
+	MXUNLOCK(&dir->lock);
+
+	return ret;
 }
 
 int objstore_link(struct objstore_open_obj_info *diropen, const char *name,
--- a/src/objstore/objstore_impl.h	Sat Dec 17 20:40:39 2022 -0500
+++ b/src/objstore/objstore_impl.h	Sun Dec 18 10:15:13 2022 -0500
@@ -105,6 +105,9 @@
 extern int dir_create(struct txn *txn, struct objver *dirver, const char *name,
 		      uint32_t owner, uint32_t group, uint16_t mode,
 		      struct noid *child);
+extern 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);
 extern int dir_unlink(struct txn *txn, struct objver *dirver, const char *name,
 		      const struct noid *desired, bool rmdir);