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