Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
19static char *content;
20static size_t content_size = 0;
21static const char test_path[] = "/test";
22
23static 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
43static 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
56static 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
64static 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
84static 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
110static 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
134static 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
143int main(int argc, char *argv[])
144{
145 return fuse_main(argc, argv, &memfd_ops, NULL);
146}