summaryrefslogtreecommitdiff
path: root/draft/fuse-examples/fioc.c
diff options
context:
space:
mode:
Diffstat (limited to 'draft/fuse-examples/fioc.c')
-rw-r--r--draft/fuse-examples/fioc.c211
1 files changed, 211 insertions, 0 deletions
diff --git a/draft/fuse-examples/fioc.c b/draft/fuse-examples/fioc.c
new file mode 100644
index 0000000..bee40b9
--- /dev/null
+++ b/draft/fuse-examples/fioc.c
@@ -0,0 +1,211 @@
+/*
+ FUSE fioc: FUSE ioctl example
+ Copyright (C) 2008 SUSE Linux Products GmbH
+ Copyright (C) 2008 Tejun Heo <teheo@suse.de>
+
+ This program can be distributed under the terms of the GNU GPL.
+ See the file COPYING.
+
+ gcc -Wall fioc.c `pkg-config fuse --cflags --libs` -o fioc
+*/
+
+#define FUSE_USE_VERSION 26
+
+#include <fuse.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+
+#include "fioc.h"
+
+#define FIOC_NAME "fioc"
+
+enum {
+ FIOC_NONE,
+ FIOC_ROOT,
+ FIOC_FILE,
+};
+
+static void *fioc_buf;
+static size_t fioc_size;
+
+static int fioc_resize(size_t new_size)
+{
+ void *new_buf;
+
+ if (new_size == fioc_size)
+ return 0;
+
+ new_buf = realloc(fioc_buf, new_size);
+ if (!new_buf && new_size)
+ return -ENOMEM;
+
+ if (new_size > fioc_size)
+ memset(new_buf + fioc_size, 0, new_size - fioc_size);
+
+ fioc_buf = new_buf;
+ fioc_size = new_size;
+
+ return 0;
+}
+
+static int fioc_expand(size_t new_size)
+{
+ if (new_size > fioc_size)
+ return fioc_resize(new_size);
+ return 0;
+}
+
+static int fioc_file_type(const char *path)
+{
+ if (strcmp(path, "/") == 0)
+ return FIOC_ROOT;
+ if (strcmp(path, "/" FIOC_NAME) == 0)
+ return FIOC_FILE;
+ return FIOC_NONE;
+}
+
+static int fioc_getattr(const char *path, struct stat *stbuf)
+{
+ stbuf->st_uid = getuid();
+ stbuf->st_gid = getgid();
+ stbuf->st_atime = stbuf->st_mtime = time(NULL);
+
+ switch (fioc_file_type(path)) {
+ case FIOC_ROOT:
+ stbuf->st_mode = S_IFDIR | 0755;
+ stbuf->st_nlink = 2;
+ break;
+ case FIOC_FILE:
+ stbuf->st_mode = S_IFREG | 0644;
+ stbuf->st_nlink = 1;
+ stbuf->st_size = fioc_size;
+ break;
+ case FIOC_NONE:
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static int fioc_open(const char *path, struct fuse_file_info *fi)
+{
+ (void) fi;
+
+ if (fioc_file_type(path) != FIOC_NONE)
+ return 0;
+ return -ENOENT;
+}
+
+static int fioc_do_read(char *buf, size_t size, off_t offset)
+{
+ if (offset >= fioc_size)
+ return 0;
+
+ if (size > fioc_size - offset)
+ size = fioc_size - offset;
+
+ memcpy(buf, fioc_buf + offset, size);
+
+ return size;
+}
+
+static int fioc_read(const char *path, char *buf, size_t size,
+ off_t offset, struct fuse_file_info *fi)
+{
+ (void) fi;
+
+ if (fioc_file_type(path) != FIOC_FILE)
+ return -EINVAL;
+
+ return fioc_do_read(buf, size, offset);
+}
+
+static int fioc_do_write(const char *buf, size_t size, off_t offset)
+{
+ if (fioc_expand(offset + size))
+ return -ENOMEM;
+
+ memcpy(fioc_buf + offset, buf, size);
+
+ return size;
+}
+
+static int fioc_write(const char *path, const char *buf, size_t size,
+ off_t offset, struct fuse_file_info *fi)
+{
+ (void) fi;
+
+ if (fioc_file_type(path) != FIOC_FILE)
+ return -EINVAL;
+
+ return fioc_do_write(buf, size, offset);
+}
+
+static int fioc_truncate(const char *path, off_t size)
+{
+ if (fioc_file_type(path) != FIOC_FILE)
+ return -EINVAL;
+
+ return fioc_resize(size);
+}
+
+static int fioc_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+ off_t offset, struct fuse_file_info *fi)
+{
+ (void) fi;
+ (void) offset;
+
+ if (fioc_file_type(path) != FIOC_ROOT)
+ return -ENOENT;
+
+ filler(buf, ".", NULL, 0);
+ filler(buf, "..", NULL, 0);
+ filler(buf, FIOC_NAME, NULL, 0);
+
+ return 0;
+}
+
+static int fioc_ioctl(const char *path, int cmd, void *arg,
+ struct fuse_file_info *fi, unsigned int flags, void *data)
+{
+ (void) arg;
+ (void) fi;
+ (void) flags;
+
+ if (fioc_file_type(path) != FIOC_FILE)
+ return -EINVAL;
+
+ if (flags & FUSE_IOCTL_COMPAT)
+ return -ENOSYS;
+
+ switch (cmd) {
+ case FIOC_GET_SIZE:
+ *(size_t *)data = fioc_size;
+ return 0;
+
+ case FIOC_SET_SIZE:
+ fioc_resize(*(size_t *)data);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static struct fuse_operations fioc_oper = {
+ .getattr = fioc_getattr,
+ .readdir = fioc_readdir,
+ .truncate = fioc_truncate,
+ .open = fioc_open,
+ .read = fioc_read,
+ .write = fioc_write,
+ .ioctl = fioc_ioctl,
+};
+
+int main(int argc, char *argv[])
+{
+ return fuse_main(argc, argv, &fioc_oper, NULL);
+}