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 }
uint64_t fh
Definition: fuse_common.h:93
void *(* init)(struct fuse_conn_info *conn, struct fuse_config *cfg)
Definition: fuse.h:578
double negative_timeout
Definition: fuse.h:129
int(* readlink)(const char *, char *, size_t)
Definition: fuse.h:321
int use_ino
Definition: fuse.h:190
double attr_timeout
Definition: fuse.h:135
#define fuse_main(argc, argv, op, private_data)
Definition: fuse.h:869
fuse_readdir_flags
Definition: fuse.h:42
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
int(* access)(const char *, int)
Definition: fuse.h:597
double entry_timeout
Definition: fuse.h:119