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