1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * fusectl test file-system 4 * Creates a simple FUSE filesystem with a single read-write file (/test) 5 */ 6 7 #define FUSE_USE_VERSION 26 8 9 #include <fuse.h> 10 #include <stdio.h> 11 #include <string.h> 12 #include <errno.h> 13 #include <fcntl.h> 14 #include <stdlib.h> 15 #include <unistd.h> 16 17 #define MAX(a, b) ((a) > (b) ? (a) : (b)) 18 19 static char *content; 20 static size_t content_size = 0; 21 static const char test_path[] = "/test"; 22 23 static int test_getattr(const char *path, struct stat *st) 24 { 25 memset(st, 0, sizeof(*st)); 26 27 if (!strcmp(path, "/")) { 28 st->st_mode = S_IFDIR | 0755; 29 st->st_nlink = 2; 30 return 0; 31 } 32 33 if (!strcmp(path, test_path)) { 34 st->st_mode = S_IFREG | 0664; 35 st->st_nlink = 1; 36 st->st_size = content_size; 37 return 0; 38 } 39 40 return -ENOENT; 41 } 42 43 static int test_readdir(const char *path, void *buf, fuse_fill_dir_t filler, 44 off_t offset, struct fuse_file_info *fi) 45 { 46 if (strcmp(path, "/")) 47 return -ENOENT; 48 49 filler(buf, ".", NULL, 0); 50 filler(buf, "..", NULL, 0); 51 filler(buf, test_path + 1, NULL, 0); 52 53 return 0; 54 } 55 56 static int test_open(const char *path, struct fuse_file_info *fi) 57 { 58 if (strcmp(path, test_path)) 59 return -ENOENT; 60 61 return 0; 62 } 63 64 static int test_read(const char *path, char *buf, size_t size, off_t offset, 65 struct fuse_file_info *fi) 66 { 67 if (strcmp(path, test_path) != 0) 68 return -ENOENT; 69 70 if (!content || content_size == 0) 71 return 0; 72 73 if (offset >= content_size) 74 return 0; 75 76 if (offset + size > content_size) 77 size = content_size - offset; 78 79 memcpy(buf, content + offset, size); 80 81 return size; 82 } 83 84 static int test_write(const char *path, const char *buf, size_t size, 85 off_t offset, struct fuse_file_info *fi) 86 { 87 size_t new_size; 88 89 if (strcmp(path, test_path) != 0) 90 return -ENOENT; 91 92 if(offset > content_size) 93 return -EINVAL; 94 95 new_size = MAX(offset + size, content_size); 96 97 if (new_size > content_size) 98 content = realloc(content, new_size); 99 100 content_size = new_size; 101 102 if (!content) 103 return -ENOMEM; 104 105 memcpy(content + offset, buf, size); 106 107 return size; 108 } 109 110 static int test_truncate(const char *path, off_t size) 111 { 112 if (strcmp(path, test_path) != 0) 113 return -ENOENT; 114 115 if (size == 0) { 116 free(content); 117 content = NULL; 118 content_size = 0; 119 return 0; 120 } 121 122 content = realloc(content, size); 123 124 if (!content) 125 return -ENOMEM; 126 127 if (size > content_size) 128 memset(content + content_size, 0, size - content_size); 129 130 content_size = size; 131 return 0; 132 } 133 134 static struct fuse_operations memfd_ops = { 135 .getattr = test_getattr, 136 .readdir = test_readdir, 137 .open = test_open, 138 .read = test_read, 139 .write = test_write, 140 .truncate = test_truncate, 141 }; 142 143 int main(int argc, char *argv[]) 144 { 145 return fuse_main(argc, argv, &memfd_ops, NULL); 146 } 147