147 lines
2.7 KiB
C
147 lines
2.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* fusectl test file-system
|
|
* Creates a simple FUSE filesystem with a single read-write file (/test)
|
|
*/
|
|
|
|
#define FUSE_USE_VERSION 26
|
|
|
|
#include <fuse.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
|
|
static char *content;
|
|
static size_t content_size = 0;
|
|
static const char test_path[] = "/test";
|
|
|
|
static int test_getattr(const char *path, struct stat *st)
|
|
{
|
|
memset(st, 0, sizeof(*st));
|
|
|
|
if (!strcmp(path, "/")) {
|
|
st->st_mode = S_IFDIR | 0755;
|
|
st->st_nlink = 2;
|
|
return 0;
|
|
}
|
|
|
|
if (!strcmp(path, test_path)) {
|
|
st->st_mode = S_IFREG | 0664;
|
|
st->st_nlink = 1;
|
|
st->st_size = content_size;
|
|
return 0;
|
|
}
|
|
|
|
return -ENOENT;
|
|
}
|
|
|
|
static int test_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
|
off_t offset, struct fuse_file_info *fi)
|
|
{
|
|
if (strcmp(path, "/"))
|
|
return -ENOENT;
|
|
|
|
filler(buf, ".", NULL, 0);
|
|
filler(buf, "..", NULL, 0);
|
|
filler(buf, test_path + 1, NULL, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_open(const char *path, struct fuse_file_info *fi)
|
|
{
|
|
if (strcmp(path, test_path))
|
|
return -ENOENT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_read(const char *path, char *buf, size_t size, off_t offset,
|
|
struct fuse_file_info *fi)
|
|
{
|
|
if (strcmp(path, test_path) != 0)
|
|
return -ENOENT;
|
|
|
|
if (!content || content_size == 0)
|
|
return 0;
|
|
|
|
if (offset >= content_size)
|
|
return 0;
|
|
|
|
if (offset + size > content_size)
|
|
size = content_size - offset;
|
|
|
|
memcpy(buf, content + offset, size);
|
|
|
|
return size;
|
|
}
|
|
|
|
static int test_write(const char *path, const char *buf, size_t size,
|
|
off_t offset, struct fuse_file_info *fi)
|
|
{
|
|
size_t new_size;
|
|
|
|
if (strcmp(path, test_path) != 0)
|
|
return -ENOENT;
|
|
|
|
if(offset > content_size)
|
|
return -EINVAL;
|
|
|
|
new_size = MAX(offset + size, content_size);
|
|
|
|
if (new_size > content_size)
|
|
content = realloc(content, new_size);
|
|
|
|
content_size = new_size;
|
|
|
|
if (!content)
|
|
return -ENOMEM;
|
|
|
|
memcpy(content + offset, buf, size);
|
|
|
|
return size;
|
|
}
|
|
|
|
static int test_truncate(const char *path, off_t size)
|
|
{
|
|
if (strcmp(path, test_path) != 0)
|
|
return -ENOENT;
|
|
|
|
if (size == 0) {
|
|
free(content);
|
|
content = NULL;
|
|
content_size = 0;
|
|
return 0;
|
|
}
|
|
|
|
content = realloc(content, size);
|
|
|
|
if (!content)
|
|
return -ENOMEM;
|
|
|
|
if (size > content_size)
|
|
memset(content + content_size, 0, size - content_size);
|
|
|
|
content_size = size;
|
|
return 0;
|
|
}
|
|
|
|
static struct fuse_operations memfd_ops = {
|
|
.getattr = test_getattr,
|
|
.readdir = test_readdir,
|
|
.open = test_open,
|
|
.read = test_read,
|
|
.write = test_write,
|
|
.truncate = test_truncate,
|
|
};
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
return fuse_main(argc, argv, &memfd_ops, NULL);
|
|
}
|