support for hidding sidecar files.
[rrq/fuse_xattrs.git] / passthrough.c
1 /*
2   fuse_xattrs - Add xattrs support using sidecar files
3
4   Copyright (C) 2016-2017  Felipe Barriga Richards <felipe {at} felipebarriga.cl>
5
6   Based on passthrough.c (libfuse example)
7
8   This program can be distributed under the terms of the GNU GPL.
9   See the file COPYING.
10 */
11
12 #define FUSE_USE_VERSION 30
13
14 /* For pread()/pwrite()/utimensat() */
15 #define _XOPEN_SOURCE 700
16
17 #include <fuse.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <dirent.h>
23 #include <errno.h>
24
25 #include "xattrs_config.h"
26 #include "utils.h"
27
28 int xmp_getattr(const char *path, struct stat *stbuf) {
29     int res;
30
31     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
32         return -ENOENT;
33     }
34
35     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
36     res = lstat(_path, stbuf);
37     free(_path);
38
39     if (res == -1)
40         return -errno;
41
42     return 0;
43 }
44
45 int xmp_access(const char *path, int mask) {
46     int res;
47     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
48         return -ENOENT;
49     }
50
51     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
52     res = access(_path, mask);
53     free(_path);
54
55     if (res == -1)
56         return -errno;
57
58     return 0;
59 }
60
61 int xmp_readlink(const char *path, char *buf, size_t size) {
62     int res;
63     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
64         return -ENOENT;
65     }
66
67     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
68     res = readlink(_path, buf, size - 1);
69     free(_path);
70
71     if (res == -1)
72         return -errno;
73
74     buf[res] = '\0';
75     return 0;
76 }
77
78 int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
79                 off_t offset, struct fuse_file_info *fi)
80 {
81     DIR *dp;
82     struct dirent *de;
83
84     (void) offset;
85     (void) fi;
86
87     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
88     dp = opendir(_path);
89     free(_path);
90
91     if (dp == NULL)
92         return -errno;
93
94     while ((de = readdir(dp)) != NULL) {
95         if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(de->d_name) == 1) {
96             continue;
97         }
98
99         struct stat st;
100         memset(&st, 0, sizeof(st));
101         st.st_ino = de->d_ino;
102         st.st_mode = de->d_type << 12;
103         if (filler(buf, de->d_name, &st, 0))
104             break;
105     }
106
107     closedir(dp);
108     return 0;
109 }
110
111 int xmp_mknod(const char *path, mode_t mode, dev_t rdev) {
112     int res;
113     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
114         return -ENOENT;
115     }
116
117     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
118
119     /* On Linux this could just be 'mknod(path, mode, rdev)' but this
120        is more portable */
121     if (S_ISREG(mode)) {
122         res = open(_path, O_CREAT | O_EXCL | O_WRONLY, mode);
123         if (res >= 0)
124             res = close(res);
125     } else if (S_ISFIFO(mode))
126         res = mkfifo(_path, mode);
127     else
128         res = mknod(_path, mode, rdev);
129
130     free(_path);
131     if (res == -1)
132         return -errno;
133
134     return 0;
135 }
136
137 int xmp_mkdir(const char *path, mode_t mode) {
138     int res;
139     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
140         return -ENOENT;
141     }
142
143     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
144     res = mkdir(_path, mode);
145     free(_path);
146
147     if (res == -1)
148         return -errno;
149
150     return 0;
151 }
152
153 int xmp_unlink(const char *path) {
154     int res;
155     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
156         return -ENOENT;
157     }
158
159     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
160     res = unlink(_path);
161     free(_path);
162
163     if (res == -1)
164         return -errno;
165
166     return 0;
167 }
168
169 int xmp_rmdir(const char *path) {
170     int res;
171     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
172         return -ENOENT;
173     }
174
175     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
176     res = rmdir(_path);
177     free(_path);
178
179     if (res == -1)
180         return -errno;
181
182     return 0;
183 }
184
185 int xmp_symlink(const char *from, const char *to) {
186     int res;
187     if (xattrs_config.show_sidecar == 0) {
188         if (filename_is_sidecar(from) == 1 || filename_is_sidecar(to)) {
189             return -ENOENT;
190         }
191     }
192
193     char *_to = prepend_source_directory(xattrs_config.source_dir, to);
194     res = symlink(from, _to);
195     free(_to);
196
197     if (res == -1)
198         return -errno;
199
200     return 0;
201 }
202
203 int xmp_rename(const char *from, const char *to) {
204     int res;
205     if (xattrs_config.show_sidecar == 0) {
206         if (filename_is_sidecar(from) == 1 || filename_is_sidecar(to)) {
207             return -ENOENT;
208         }
209     }
210
211     char *_from = prepend_source_directory(xattrs_config.source_dir, from);
212     char *_to = prepend_source_directory(xattrs_config.source_dir, to);
213     res = rename(_from, _to);
214     free(_from);
215     free(_to);
216
217     if (res == -1)
218         return -errno;
219
220     return 0;
221 }
222
223 int xmp_link(const char *from, const char *to) {
224     int res;
225     if (xattrs_config.show_sidecar == 0) {
226         if (filename_is_sidecar(from) == 1 || filename_is_sidecar(to)) {
227             return -ENOENT;
228         }
229     }
230
231     char *_from = prepend_source_directory(xattrs_config.source_dir, from);
232     char *_to = prepend_source_directory(xattrs_config.source_dir, to);
233     res = link(_from, _to);
234     free(_from);
235     free(_to);
236
237     if (res == -1)
238         return -errno;
239
240     return 0;
241 }
242
243 int xmp_chmod(const char *path, mode_t mode) {
244     int res;
245     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
246         return -ENOENT;
247     }
248
249     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
250     res = chmod(_path, mode);
251     free(_path);
252
253     if (res == -1)
254         return -errno;
255
256     return 0;
257 }
258
259 int xmp_chown(const char *path, uid_t uid, gid_t gid) {
260     int res;
261     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
262         return -ENOENT;
263     }
264
265     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
266     res = lchown(_path, uid, gid);
267     free(_path);
268
269     if (res == -1)
270         return -errno;
271
272     return 0;
273 }
274
275 int xmp_truncate(const char *path, off_t size) {
276     int res;
277     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
278         return -ENOENT;
279     }
280
281     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
282     res = truncate(_path, size);
283     free(_path);
284
285     if (res == -1)
286         return -errno;
287
288     return 0;
289 }
290
291 #ifdef HAVE_UTIMENSAT
292 int xmp_utimens(const char *path, const struct timespec ts[2],
293 struct fuse_file_info *fi)
294 {
295     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
296         return -ENOENT;
297     }
298
299     (void) fi;
300     int res;
301
302     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
303     /* don't use utime/utimes since they follow symlinks */
304     res = utimensat(0, _path, ts, AT_SYMLINK_NOFOLLOW);
305     free(_path);
306     if (res == -1)
307         return -errno;
308
309     return 0;
310 }
311 #endif
312
313 int xmp_open(const char *path, struct fuse_file_info *fi) {
314     int res;
315     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
316         return -ENOENT;
317     }
318
319     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
320     res = open(_path, fi->flags);
321     free(_path);
322
323     if (res == -1)
324         return -errno;
325
326     close(res);
327     return 0;
328 }
329
330 int xmp_read(const char *path, char *buf, size_t size, off_t offset,
331              struct fuse_file_info *fi)
332 {
333     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
334         return -ENOENT;
335     }
336
337     int fd;
338     int res;
339
340     (void) fi;
341     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
342     fd = open(_path, O_RDONLY);
343     free(_path);
344
345     if (fd == -1)
346         return -errno;
347
348     res = pread(fd, buf, size, offset);
349     if (res == -1)
350         res = -errno;
351
352     close(fd);
353     return res;
354 }
355
356 int xmp_write(const char *path, const char *buf, size_t size,
357               off_t offset, struct fuse_file_info *fi)
358 {
359     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
360         return -ENOENT;
361     }
362
363     int fd;
364     int res;
365
366     (void) fi;
367     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
368     fd = open(_path, O_WRONLY);
369     free(_path);
370
371     if (fd == -1)
372         return -errno;
373
374     res = pwrite(fd, buf, size, offset);
375     if (res == -1)
376         res = -errno;
377
378     close(fd);
379     return res;
380 }
381
382 int xmp_statfs(const char *path, struct statvfs *stbuf) {
383     int res;
384     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
385         return -ENOENT;
386     }
387
388     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
389     res = statvfs(_path, stbuf);
390     free(_path);
391
392     if (res == -1)
393         return -errno;
394
395     return 0;
396 }
397
398 int xmp_release(const char *path, struct fuse_file_info *fi) {
399     /* Just a stub.      This method is optional and can safely be left
400        unimplemented */
401
402     (void) path;
403     (void) fi;
404     return 0;
405 }
406
407 int xmp_fsync(const char *path, int isdatasync,
408               struct fuse_file_info *fi) {
409     /* Just a stub.      This method is optional and can safely be left
410        unimplemented */
411
412     (void) path;
413     (void) isdatasync;
414     (void) fi;
415     return 0;
416 }
417
418 #ifdef HAVE_POSIX_FALLOCATE
419 int xmp_fallocate(const char *path, int mode,
420                   off_t offset, off_t length, struct fuse_file_info *fi)
421 {
422     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
423         return -ENOENT;
424     }
425
426     int fd;
427     int res;
428
429     (void) fi;
430
431     if (mode)
432         return -EOPNOTSUPP;
433
434     char *_path = concat(xattrs_config.source_dir, path);
435     fd = open(_path, O_WRONLY);
436     free(_path);
437
438     if (fd == -1)
439         return -errno;
440
441     res = -posix_fallocate(fd, offset, length);
442
443     close(fd);
444     return res;
445 }
446 #endif
447