|
|
/*
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); }
|