view src/objstore/posix/obj_create.c @ 891:77a35abc6a24

objstore: move dir buffer making helper to dir.c This is where it belongs since it doesn't do anything directly with objects. Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Mon, 19 Dec 2022 19:44:45 -0500
parents 8d3171c87786
children
line wrap: on
line source

/*
 * Copyright (c) 2018-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 "posix.h"

/*
 * Low-level new object creation
 */

static int create_objver(int objfd,
			 const struct nvclock *clock, const struct nattr *attrs,
			 struct buffer *contents)
{
	struct posix_ver_header hdr;
	char vername[PATH_MAX];
	int ret;
	int fd;

	ret = nvclock_to_str(clock, vername, sizeof(vername));
	if (ret)
		return ret;

	fd = xopenat(objfd, vername, O_RDWR | O_CREAT | O_EXCL, 0600);
	if (fd < 0)
		return fd;

	hdr.mode  = attrs->mode;
	hdr.nlink = attrs->nlink;
	hdr.size  = attrs->size;
	hdr.atime = attrs->atime;
	hdr.btime = attrs->btime;
	hdr.ctime = attrs->ctime;
	hdr.mtime = attrs->mtime;
	hdr.owner = attrs->owner;
	hdr.group = attrs->group;

	ret = write_ver_header(NULL, fd, &hdr);
	if (ret)
		goto err;

	/* truncate the file to match the size in attrs */
	ret = xftruncate(fd, sizeof(struct posix_ver_header) +
			 p2roundup(attrs->size, BLOCK_SIZE));
	if (ret)
		goto err;

	/* write out the dir contents if we got them */
	if (contents) {
		VERIFY(NATTR_ISDIR(attrs->mode));
		VERIFY3U(attrs->size, ==, buffer_size(contents));

		ret = write_ver_data(NULL, fd, buffer_data(contents),
				     buffer_size(contents), 0);
		if (ret < 0)
			goto err;
		if (ret != buffer_size(contents)) {
			ret = -EPIPE;
			goto err;
		}
	}

	xclose(fd);

	return 0;

err:
	xclose(fd);

	xunlinkat(objfd, vername, 0);

	return ret;
}

int create_obj(int rootfd, uint64_t this_host, uint64_t this_uniq,
	       const struct nvclock *clock, const struct nattr *_attrs,
	       struct buffer *contents)
{
	struct nattr attrs;
	char objname[34];
	int ret;
	int fd;

	attrs = *_attrs;

	snprintf(objname, sizeof(objname), "%016"PRIx64"-%016"PRIx64,
		 this_host, this_uniq);

	/* create the object directory */
	ret = xmkdirat(rootfd, objname, 0700);
	if (ret)
		return ret;

	/* open the object directory */
	fd = xopenat(rootfd, objname, O_RDONLY, 0);
	if (fd < 0) {
		ret = fd;
		goto err;
	}

	/* create the object version file */
	ret = create_objver(fd, clock, &attrs, contents);
	if (ret)
		goto err_close;

	xclose(fd);

	return ret;

err_close:
	xclose(fd);

err:
	xunlinkat(rootfd, objname, 0);

	return ret;
}

/* create a root directory */
int create_rootdir(int rootfd, uint64_t host, uint64_t uniq)
{
	const uint64_t now = gettime();
	struct nattr attrs = {
		.mode  = NATTR_DIR | 0700,
		.nlink = 1, /* even new dirs have a link count of 1 */
		.size  = 0, /* overwritten below */
		.atime = now,
		.btime = now,
		.ctime = now,
		.mtime = now,
		.owner = 0,
		.group = 0,
	};
	struct nvclock clock;
	struct buffer contents;
	int ret;

	nvclock_reset(&clock);
	VERIFY0(nvclock_inc(&clock));

	/*
	 * construct an empty directory
	 */
	ret = buffer_init_heap(&contents, BLOCK_SIZE); /* size guess */
	if (ret)
		return ret;

	ret = dir_make_buffer(host, uniq, host, uniq, &contents);
	if (ret)
		goto err;

	/* overwrite the requested size */
	attrs.size = buffer_size(&contents);

	ret = create_obj(rootfd, host, uniq, &clock, &attrs, &contents);

err:
	buffer_free(&contents);

	return ret;
}