view src/libmlk-core/core/vfs-directory.c @ 419:1b4e61bdb9ab

core: introduce err.h
author David Demelier <markand@malikania.fr>
date Wed, 12 Oct 2022 15:06:18 +0200
parents 460c78706989
children 7d2ebc334c8c
line wrap: on
line source

/*
 * vfs-directory.c -- VFS subsystem for directories
 *
 * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <port/port.h>

#include "alloc.h"
#include "error.h"
#include "vfs.h"

struct self {
	char base[PATH_MAX];
};

static inline void
normalize(char *path)
{
	size_t len = strlen(path);

	for (char *p = path; *p; ++p)
		if (*p == '\\')
			*p = '/';

	while (len && path[len - 1] == '/')
		path[--len] = 0;
}

static size_t
file_read(struct vfs_file *file, void *buf, size_t bufsz)
{
	return fread(buf, 1, bufsz, file->data);
}

static size_t
file_write(struct vfs_file *file, const void *buf, size_t bufsz)
{
	return fwrite(buf, 1, bufsz, file->data);
}

static int
file_flush(struct vfs_file *file)
{
	return fflush(file->data) == EOF ? -1 : 0;
}

static void
file_finish(struct vfs_file *file)
{
	fclose(file->data);
}

static int
dir_open(struct vfs *vfs, struct vfs_file *file, const char *entry, const char *mode)
{
	struct self *self = vfs->data;
	char path[PATH_MAX];

	snprintf(path, sizeof (path), "%s/%s", self->base, entry);

	if (!(file->data = fopen(path, mode)))
		return errorf("%s: %s", path, strerror(errno));

	file->read = file_read;
	file->write = file_write;
	file->flush = file_flush;
	file->finish = file_finish;

	return 0;
}

static void
dir_finish(struct vfs *vfs)
{
	free(vfs->data);
}

void
vfs_directory(struct vfs *vfs, const char *path)
{
	assert(vfs);
	assert(path);

	struct self *self;

	self = alloc_new(sizeof (*self));
	port_strlcpy(self->base, path, sizeof (self->base));

	/* Remove terminator and switch to UNIX paths. */
	normalize(self->base);

	vfs->data = self;
	vfs->open = dir_open;
	vfs->finish = dir_finish;
}