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 
39 enum {
40  FIOC_NONE,
41  FIOC_ROOT,
42  FIOC_FILE,
43 };
44 
45 static void *fioc_buf;
46 static size_t fioc_size;
47 
48 static 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 
68 static 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 
75 static 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 
84 static 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 
109 static 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 
118 static 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 
131 static 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 
142 static 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 
152 static 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 
163 static 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 
173 static 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 
191 static 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 
217 static 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 
227 int 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:446
int(* getattr)(const char *, struct stat *, struct fuse_file_info *fi)
Definition: fuse.h:336