libfuse: example/passthrough.c Source File

libfuse

passthrough.c
Go to the documentation of this file.
1 /*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 Copyright (C) 2011 Sebastian Pipping <sebastian@pipping.org>
5
6 This program can be distributed under the terms of the GNU GPL.
7 See the file COPYING.
8 */
9
26 #define FUSE_USE_VERSION 31
27
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31
32 #define _GNU_SOURCE
33
34 #ifdef linux
35 /* For pread()/pwrite()/utimensat() */
36 #define _XOPEN_SOURCE 700
37 #endif
38
39 #include <fuse.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <fcntl.h>
44 #include <sys/stat.h>
45 #include <dirent.h>
46 #include <errno.h>
47 #include <sys/time.h>
48 #ifdef HAVE_SETXATTR
49 #include <sys/xattr.h>
50 #endif
51
52 static void *xmp_init(struct fuse_conn_info *conn,
53 struct fuse_config *cfg)
54 {
55 (void) conn;
56 cfg->use_ino = 1;
57
58 /* Pick up changes from lower filesystem right away. This is
59 also necessary for better hardlink support. When the kernel
60 calls the unlink() handler, it does not know the inode of
61 the to-be-removed entry and can therefore not invalidate
62 the cache of the associated inode - resulting in an
63 incorrect st_nlink value being reported for any remaining
64 hardlinks to this inode. */
65 cfg->entry_timeout = 0;
66 cfg->attr_timeout = 0;
67 cfg->negative_timeout = 0;
68
69 return NULL;
70 }
71
72 static int xmp_getattr(const char *path, struct stat *stbuf,
73 struct fuse_file_info *fi)
74 {
75 (void) fi;
76 int res;
77
78 res = lstat(path, stbuf);
79 if (res == -1)
80 return -errno;
81
82 return 0;
83 }
84
85 static int xmp_access(const char *path, int mask)
86 {
87 int res;
88
89 res = access(path, mask);
90 if (res == -1)
91 return -errno;
92
93 return 0;
94 }
95
96 static int xmp_readlink(const char *path, char *buf, size_t size)
97 {
98 int res;
99
100 res = readlink(path, buf, size - 1);
101 if (res == -1)
102 return -errno;
103
104 buf[res] = '\0';
105 return 0;
106 }
107
108
109 static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
110 off_t offset, struct fuse_file_info *fi,
111 enum fuse_readdir_flags flags)
112 {
113 DIR *dp;
114 struct dirent *de;
115
116 (void) offset;
117 (void) fi;
118 (void) flags;
119
120 dp = opendir(path);
121 if (dp == NULL)
122 return -errno;
123
124 while ((de = readdir(dp)) != NULL) {
125 struct stat st;
126 memset(&st, 0, sizeof(st));
127 st.st_ino = de->d_ino;
128 st.st_mode = de->d_type << 12;
129 if (filler(buf, de->d_name, &st, 0, 0))
130 break;
131 }
132
133 closedir(dp);
134 return 0;
135 }
136
137 static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
138 {
139 int res;
140
141 /* On Linux this could just be 'mknod(path, mode, rdev)' but this
142 is more portable */
143 if (S_ISREG(mode)) {
144 res = open(path, O_CREAT | O_EXCL | O_WRONLY, mode);
145 if (res >= 0)
146 res = close(res);
147 } else if (S_ISFIFO(mode))
148 res = mkfifo(path, mode);
149 else
150 res = mknod(path, mode, rdev);
151 if (res == -1)
152 return -errno;
153
154 return 0;
155 }
156
157 static int xmp_mkdir(const char *path, mode_t mode)
158 {
159 int res;
160
161 res = mkdir(path, mode);
162 if (res == -1)
163 return -errno;
164
165 return 0;
166 }
167
168 static int xmp_unlink(const char *path)
169 {
170 int res;
171
172 res = unlink(path);
173 if (res == -1)
174 return -errno;
175
176 return 0;
177 }
178
179 static int xmp_rmdir(const char *path)
180 {
181 int res;
182
183 res = rmdir(path);
184 if (res == -1)
185 return -errno;
186
187 return 0;
188 }
189
190 static int xmp_symlink(const char *from, const char *to)
191 {
192 int res;
193
194 res = symlink(from, to);
195 if (res == -1)
196 return -errno;
197
198 return 0;
199 }
200
201 static int xmp_rename(const char *from, const char *to, unsigned int flags)
202 {
203 int res;
204
205 if (flags)
206 return -EINVAL;
207
208 res = rename(from, to);
209 if (res == -1)
210 return -errno;
211
212 return 0;
213 }
214
215 static int xmp_link(const char *from, const char *to)
216 {
217 int res;
218
219 res = link(from, to);
220 if (res == -1)
221 return -errno;
222
223 return 0;
224 }
225
226 static int xmp_chmod(const char *path, mode_t mode,
227 struct fuse_file_info *fi)
228 {
229 (void) fi;
230 int res;
231
232 res = chmod(path, mode);
233 if (res == -1)
234 return -errno;
235
236 return 0;
237 }
238
239 static int xmp_chown(const char *path, uid_t uid, gid_t gid,
240 struct fuse_file_info *fi)
241 {
242 (void) fi;
243 int res;
244
245 res = lchown(path, uid, gid);
246 if (res == -1)
247 return -errno;
248
249 return 0;
250 }
251
252 static int xmp_truncate(const char *path, off_t size,
253 struct fuse_file_info *fi)
254 {
255 int res;
256
257 if (fi != NULL)
258 res = ftruncate(fi->fh, size);
259 else
260 res = truncate(path, size);
261 if (res == -1)
262 return -errno;
263
264 return 0;
265 }
266
267 #ifdef HAVE_UTIMENSAT
268 static int xmp_utimens(const char *path, const struct timespec ts[2],
269 struct fuse_file_info *fi)
270 {
271 (void) fi;
272 int res;
273
274 /* don't use utime/utimes since they follow symlinks */
275 res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW);
276 if (res == -1)
277 return -errno;
278
279 return 0;
280 }
281 #endif
282
283 static int xmp_create(const char *path, mode_t mode,
284 struct fuse_file_info *fi)
285 {
286 int res;
287
288 res = open(path, fi->flags, mode);
289 if (res == -1)
290 return -errno;
291
292 fi->fh = res;
293 return 0;
294 }
295
296 static int xmp_open(const char *path, struct fuse_file_info *fi)
297 {
298 int res;
299
300 res = open(path, fi->flags);
301 if (res == -1)
302 return -errno;
303
304 fi->fh = res;
305 return 0;
306 }
307
308 static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
309 struct fuse_file_info *fi)
310 {
311 int fd;
312 int res;
313
314 if(fi == NULL)
315 fd = open(path, O_RDONLY);
316 else
317 fd = fi->fh;
318
319 if (fd == -1)
320 return -errno;
321
322 res = pread(fd, buf, size, offset);
323 if (res == -1)
324 res = -errno;
325
326 if(fi == NULL)
327 close(fd);
328 return res;
329 }
330
331 static int xmp_write(const char *path, const char *buf, size_t size,
332 off_t offset, struct fuse_file_info *fi)
333 {
334 int fd;
335 int res;
336
337 (void) fi;
338 if(fi == NULL)
339 fd = open(path, O_WRONLY);
340 else
341 fd = fi->fh;
342
343 if (fd == -1)
344 return -errno;
345
346 res = pwrite(fd, buf, size, offset);
347 if (res == -1)
348 res = -errno;
349
350 if(fi == NULL)
351 close(fd);
352 return res;
353 }
354
355 static int xmp_statfs(const char *path, struct statvfs *stbuf)
356 {
357 int res;
358
359 res = statvfs(path, stbuf);
360 if (res == -1)
361 return -errno;
362
363 return 0;
364 }
365
366 static int xmp_release(const char *path, struct fuse_file_info *fi)
367 {
368 (void) path;
369 close(fi->fh);
370 return 0;
371 }
372
373 static int xmp_fsync(const char *path, int isdatasync,
374 struct fuse_file_info *fi)
375 {
376 /* Just a stub. This method is optional and can safely be left
377 unimplemented */
378
379 (void) path;
380 (void) isdatasync;
381 (void) fi;
382 return 0;
383 }
384
385 #ifdef HAVE_POSIX_FALLOCATE
386 static int xmp_fallocate(const char *path, int mode,
387 off_t offset, off_t length, struct fuse_file_info *fi)
388 {
389 int fd;
390 int res;
391
392 (void) fi;
393
394 if (mode)
395 return -EOPNOTSUPP;
396
397 if(fi == NULL)
398 fd = open(path, O_WRONLY);
399 else
400 fd = fi->fh;
401
402 if (fd == -1)
403 return -errno;
404
405 res = -posix_fallocate(fd, offset, length);
406
407 if(fi == NULL)
408 close(fd);
409 return res;
410 }
411 #endif
412
413 #ifdef HAVE_SETXATTR
414 /* xattr operations are optional and can safely be left unimplemented */
415 static int xmp_setxattr(const char *path, const char *name, const char *value,
416 size_t size, int flags)
417 {
418 int res = lsetxattr(path, name, value, size, flags);
419 if (res == -1)
420 return -errno;
421 return 0;
422 }
423
424 static int xmp_getxattr(const char *path, const char *name, char *value,
425 size_t size)
426 {
427 int res = lgetxattr(path, name, value, size);
428 if (res == -1)
429 return -errno;
430 return res;
431 }
432
433 static int xmp_listxattr(const char *path, char *list, size_t size)
434 {
435 int res = llistxattr(path, list, size);
436 if (res == -1)
437 return -errno;
438 return res;
439 }
440
441 static int xmp_removexattr(const char *path, const char *name)
442 {
443 int res = lremovexattr(path, name);
444 if (res == -1)
445 return -errno;
446 return 0;
447 }
448 #endif /* HAVE_SETXATTR */
449
450 #ifdef HAVE_COPY_FILE_RANGE
451 static ssize_t xmp_copy_file_range(const char *path_in,
452 struct fuse_file_info *fi_in,
453 off_t offset_in, const char *path_out,
454 struct fuse_file_info *fi_out,
455 off_t offset_out, size_t len, int flags)
456 {
457 int fd_in, fd_out;
458 ssize_t res;
459
460 if(fi_in == NULL)
461 fd_in = open(path_in, O_RDONLY);
462 else
463 fd_in = fi_in->fh;
464
465 if (fd_in == -1)
466 return -errno;
467
468 if(fi_out == NULL)
469 fd_out = open(path_out, O_WRONLY);
470 else
471 fd_out = fi_out->fh;
472
473 if (fd_out == -1) {
474 close(fd_in);
475 return -errno;
476 }
477
478 res = copy_file_range(fd_in, &offset_in, fd_out, &offset_out, len,
479 flags);
480 if (res == -1)
481 res = -errno;
482
483 close(fd_in);
484 close(fd_out);
485
486 return res;
487 }
488 #endif
489
490 static struct fuse_operations xmp_oper = {
491 .init = xmp_init,
492 .getattr = xmp_getattr,
493 .access = xmp_access,
494 .readlink = xmp_readlink,
495 .readdir = xmp_readdir,
496 .mknod = xmp_mknod,
497 .mkdir = xmp_mkdir,
498 .symlink = xmp_symlink,
499 .unlink = xmp_unlink,
500 .rmdir = xmp_rmdir,
501 .rename = xmp_rename,
502 .link = xmp_link,
503 .chmod = xmp_chmod,
504 .chown = xmp_chown,
505 .truncate = xmp_truncate,
506 #ifdef HAVE_UTIMENSAT
507 .utimens = xmp_utimens,
508 #endif
509 .open = xmp_open,
510 .create = xmp_create,
511 .read = xmp_read,
512 .write = xmp_write,
513 .statfs = xmp_statfs,
514 .release = xmp_release,
515 .fsync = xmp_fsync,
516 #ifdef HAVE_POSIX_FALLOCATE
517 .fallocate = xmp_fallocate,
518 #endif
519 #ifdef HAVE_SETXATTR
520 .setxattr = xmp_setxattr,
521 .getxattr = xmp_getxattr,
522 .listxattr = xmp_listxattr,
523 .removexattr = xmp_removexattr,
524 #endif
525 #ifdef HAVE_COPY_FILE_RANGE
526 .copy_file_range = xmp_copy_file_range,
527 #endif
528 };
529
530 int main(int argc, char *argv[])
531 {
532 umask(0);
533 return fuse_main(argc, argv, &xmp_oper, NULL);
534 }
fuse_file_info::fh
uint64_t fh
Definition: fuse_common.h:72
fuse_conn_info
Definition: fuse_common.h:343
fuse_readdir_flags
fuse_readdir_flags
Definition: fuse.h:42
fuse_config::negative_timeout
double negative_timeout
Definition: fuse.h:129
fuse_file_info
Definition: fuse_common.h:37
fuse_operations::init
void *(* init)(struct fuse_conn_info *conn, struct fuse_config *cfg)
Definition: fuse.h:572
fuse_config::use_ino
int use_ino
Definition: fuse.h:190
fuse_operations
Definition: fuse.h:299
fuse_file_info::flags
int flags
Definition: fuse_common.h:39
fuse_config::attr_timeout
double attr_timeout
Definition: fuse.h:135
fuse.h
fuse_fill_dir_t
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:82
fuse_config
Definition: fuse.h:93
fuse_config::entry_timeout
double entry_timeout
Definition: fuse.h:119
fuse_main
#define fuse_main(argc, argv, op, private_data)
Definition: fuse.h:855