libfuse
ioctl.c
Go to the documentation of this file.
1/*
2 FUSE fioc: FUSE ioctl example
3 Copyright (C) 2008 SUSE Linux Products GmbH
4 Copyright (C) 2008 Tejun Heo <teheo@suse.de>
5
6 This program can be distributed under the terms of the GNU GPLv2.
7 See the file COPYING.
8*/
9
25#define FUSE_USE_VERSION 35
26
27#include <fuse.h>
28#include <stdlib.h>
29#include <stdio.h>
30#include <string.h>
31#include <unistd.h>
32#include <time.h>
33#include <errno.h>
34
35#include "ioctl.h"
36
37#define FIOC_NAME "fioc"
38
39enum {
40 FIOC_NONE,
41 FIOC_ROOT,
42 FIOC_FILE,
43};
44
45static void *fioc_buf;
46static size_t fioc_size;
47
48static int fioc_resize(size_t new_size)
49{
50 void *new_buf;
51
52 if (new_size == fioc_size)
53 return 0;
54
55 new_buf = realloc(fioc_buf, new_size);
56 if (!new_buf && new_size)
57 return -ENOMEM;
58
59 if (new_size > fioc_size)
60 memset(new_buf + fioc_size, 0, new_size - fioc_size);
61
62 fioc_buf = new_buf;
63 fioc_size = new_size;
64
65 return 0;
66}
67
68static int fioc_expand(size_t new_size)
69{
70 if (new_size > fioc_size)
71 return fioc_resize(new_size);
72 return 0;
73}
74
75static int fioc_file_type(const char *path)
76{
77 if (strcmp(path, "/") == 0)
78 return FIOC_ROOT;
79 if (strcmp(path, "/" FIOC_NAME) == 0)
80 return FIOC_FILE;
81 return FIOC_NONE;
82}
83
84static int fioc_getattr(const char *path, struct stat *stbuf,
85 struct fuse_file_info *fi)
86{
87 (void) fi;
88 stbuf->st_uid = getuid();
89 stbuf->st_gid = getgid();
90 stbuf->st_atime = stbuf->st_mtime = time(NULL);
91
92 switch (fioc_file_type(path)) {
93 case FIOC_ROOT:
94 stbuf->st_mode = S_IFDIR | 0755;
95 stbuf->st_nlink = 2;
96 break;
97 case FIOC_FILE:
98 stbuf->st_mode = S_IFREG | 0644;
99 stbuf->st_nlink = 1;
100 stbuf->st_size = fioc_size;
101 break;
102 case FIOC_NONE:
103 return -ENOENT;
104 }
105
106 return 0;
107}
108
109static int fioc_open(const char *path, struct fuse_file_info *fi)
110{
111 (void) fi;
112
113 if (fioc_file_type(path) != FIOC_NONE)
114 return 0;
115 return -ENOENT;
116}
117
118static int fioc_do_read(char *buf, size_t size, off_t offset)
119{
120 if (offset >= fioc_size)
121 return 0;
122
123 if (size > fioc_size - offset)
124 size = fioc_size - offset;
125
126 memcpy(buf, fioc_buf + offset, size);
127
128 return size;
129}
130
131static int fioc_read(const char *path, char *buf, size_t size,
132 off_t offset, struct fuse_file_info *fi)
133{
134 (void) fi;
135
136 if (fioc_file_type(path) != FIOC_FILE)
137 return -EINVAL;
138
139 return fioc_do_read(buf, size, offset);
140}
141
142static int fioc_do_write(const char *buf, size_t size, off_t offset)
143{
144 if (fioc_expand(offset + size))
145 return -ENOMEM;
146
147 memcpy(fioc_buf + offset, buf, size);
148
149 return size;
150}
151
152static int fioc_write(const char *path, const char *buf, size_t size,
153 off_t offset, struct fuse_file_info *fi)
154{
155 (void) fi;
156
157 if (fioc_file_type(path) != FIOC_FILE)
158 return -EINVAL;
159
160 return fioc_do_write(buf, size, offset);
161}
162
163static int fioc_truncate(const char *path, off_t size,
164 struct fuse_file_info *fi)
165{
166 (void) fi;
167 if (fioc_file_type(path) != FIOC_FILE)
168 return -EINVAL;
169
170 return fioc_resize(size);
171}
172
173static int fioc_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
174 off_t offset, struct fuse_file_info *fi,
175 enum fuse_readdir_flags flags)
176{
177 (void) fi;
178 (void) offset;
179 (void) flags;
180
181 if (fioc_file_type(path) != FIOC_ROOT)
182 return -ENOENT;
183
184 filler(buf, ".", NULL, 0, 0);
185 filler(buf, "..", NULL, 0, 0);
186 filler(buf, FIOC_NAME, NULL, 0, 0);
187
188 return 0;
189}
190
191static int fioc_ioctl(const char *path, unsigned int cmd, void *arg,
192 struct fuse_file_info *fi, unsigned int flags, void *data)
193{
194 (void) arg;
195 (void) fi;
196 (void) flags;
197
198 if (fioc_file_type(path) != FIOC_FILE)
199 return -EINVAL;
200
201 if (flags & FUSE_IOCTL_COMPAT)
202 return -ENOSYS;
203
204 switch (cmd) {
205 case FIOC_GET_SIZE:
206 *(size_t *)data = fioc_size;
207 return 0;
208
209 case FIOC_SET_SIZE:
210 fioc_resize(*(size_t *)data);
211 return 0;
212 }
213
214 return -EINVAL;
215}
216
217static const struct fuse_operations fioc_oper = {
218 .getattr = fioc_getattr,
219 .readdir = fioc_readdir,
220 .truncate = fioc_truncate,
221 .open = fioc_open,
222 .read = fioc_read,
223 .write = fioc_write,
224 .ioctl = fioc_ioctl,
225};
226
227int main(int argc, char *argv[])
228{
229 return fuse_main(argc, argv, &fioc_oper, NULL);
230}
int(* fuse_fill_dir_t)(void *buf, const char *name, const struct stat *stbuf, off_t off, enum fuse_fill_dir_flags flags)
Definition: fuse.h:85
#define fuse_main(argc, argv, op, private_data)
Definition: fuse.h:913
fuse_readdir_flags
Definition: fuse.h:42
#define FUSE_IOCTL_COMPAT
Definition: fuse_common.h:453
int(* getattr)(const char *, struct stat *, struct fuse_file_info *fi)
Definition: fuse.h:336