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