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 }
uint64_t fh
Definition: fuse_common.h:72
fuse_readdir_flags
Definition: fuse.h:42
double negative_timeout
Definition: fuse.h:129
void *(* init)(struct fuse_conn_info *conn, struct fuse_config *cfg)
Definition: fuse.h:572
int use_ino
Definition: fuse.h:190
double attr_timeout
Definition: fuse.h:135
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
double entry_timeout
Definition: fuse.h:119
#define fuse_main(argc, argv, op, private_data)
Definition: fuse.h:855