b3827ccd91e51d99a09c3c2220157a5b5f87662b
[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(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(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(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
86     if (fi != NULL && fi->fh != 0) {
87         dp = fdopendir(fi->fh);
88     } else {
89         char *_path = prepend_source_directory(path);
90         dp = opendir(_path);
91         free(_path);
92     }
93
94     if (dp == NULL)
95         return -errno;
96
97     while ((de = readdir(dp)) != NULL) {
98         if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(de->d_name) == 1) {
99             continue;
100         }
101
102         struct stat st;
103         memset(&st, 0, sizeof(st));
104         st.st_ino = de->d_ino;
105         st.st_mode = de->d_type << 12;
106         if (filler(buf, de->d_name, &st, 0))
107             break;
108     }
109
110     closedir(dp);
111     return 0;
112 }
113
114 int xmp_mknod(const char *path, mode_t mode, dev_t rdev) {
115     int res;
116     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
117         return -ENOENT;
118     }
119
120     char *_path = prepend_source_directory(path);
121
122     /* On Linux this could just be 'mknod(path, mode, rdev)' but this
123        is more portable */
124     if (S_ISREG(mode)) {
125         res = open(_path, O_CREAT | O_EXCL | O_WRONLY, mode);
126         if (res >= 0)
127             res = close(res);
128     } else if (S_ISFIFO(mode))
129         res = mkfifo(_path, mode);
130     else
131         res = mknod(_path, mode, rdev);
132
133     free(_path);
134     if (res == -1)
135         return -errno;
136
137     return 0;
138 }
139
140 int xmp_mkdir(const char *path, mode_t mode) {
141     int res;
142     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
143         return -ENOENT;
144     }
145
146     char *_path = prepend_source_directory(path);
147     res = mkdir(_path, mode);
148     free(_path);
149
150     if (res == -1)
151         return -errno;
152
153     return 0;
154 }
155
156 int xmp_unlink(const char *path) {
157     int res;
158     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
159         return -ENOENT;
160     }
161
162     char *_path = prepend_source_directory(path);
163     res = unlink(_path);
164     free(_path);
165
166     if (res == -1)
167         return -errno;
168
169     return 0;
170 }
171
172 int xmp_rmdir(const char *path) {
173     int res;
174     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
175         return -ENOENT;
176     }
177
178     char *_path = prepend_source_directory(path);
179     res = rmdir(_path);
180     free(_path);
181
182     if (res == -1)
183         return -errno;
184
185     return 0;
186 }
187
188 int xmp_symlink(const char *from, const char *to) {
189     int res;
190     if (xattrs_config.show_sidecar == 0) {
191         if (filename_is_sidecar(from) == 1 || filename_is_sidecar(to)) {
192             return -ENOENT;
193         }
194     }
195
196     char *_to = prepend_source_directory(to);
197     res = symlink(from, _to);
198     free(_to);
199
200     if (res == -1)
201         return -errno;
202
203     return 0;
204 }
205
206 int xmp_rename(const char *from, const char *to) {
207     int res;
208     if (xattrs_config.show_sidecar == 0) {
209         if (filename_is_sidecar(from) == 1 || filename_is_sidecar(to)) {
210             return -ENOENT;
211         }
212     }
213
214     char *_from = prepend_source_directory(from);
215     char *_to = prepend_source_directory(to);
216     res = rename(_from, _to);
217     free(_from);
218     free(_to);
219
220     if (res == -1)
221         return -errno;
222
223     return 0;
224 }
225
226 int xmp_link(const char *from, const char *to) {
227     int res;
228     if (xattrs_config.show_sidecar == 0) {
229         if (filename_is_sidecar(from) == 1 || filename_is_sidecar(to)) {
230             return -ENOENT;
231         }
232     }
233
234     char *_from = prepend_source_directory(from);
235     char *_to = prepend_source_directory(to);
236     res = link(_from, _to);
237     free(_from);
238     free(_to);
239
240     if (res == -1)
241         return -errno;
242
243     return 0;
244 }
245
246 int xmp_chmod(const char *path, mode_t mode) {
247     int res;
248     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
249         return -ENOENT;
250     }
251
252     char *_path = prepend_source_directory(path);
253     res = chmod(_path, mode);
254     free(_path);
255
256     if (res == -1)
257         return -errno;
258
259     return 0;
260 }
261
262 int xmp_chown(const char *path, uid_t uid, gid_t gid) {
263     int res;
264     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
265         return -ENOENT;
266     }
267
268     char *_path = prepend_source_directory(path);
269     res = lchown(_path, uid, gid);
270     free(_path);
271
272     if (res == -1)
273         return -errno;
274
275     return 0;
276 }
277
278 int xmp_truncate(const char *path, off_t size) {
279     int res;
280     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
281         return -ENOENT;
282     }
283
284     char *_path = prepend_source_directory(path);
285     res = truncate(_path, size);
286     free(_path);
287
288     if (res == -1)
289         return -errno;
290
291     return 0;
292 }
293
294 #ifdef HAVE_UTIMENSAT
295 int xmp_utimens(const char *path, const struct timespec ts[2],
296 struct fuse_file_info *fi)
297 {
298     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
299         return -ENOENT;
300     }
301
302     (void) fi;
303     int res;
304
305     char *_path = prepend_source_directory(path);
306     /* don't use utime/utimes since they follow symlinks */
307     res = utimensat(0, _path, ts, AT_SYMLINK_NOFOLLOW);
308     free(_path);
309     if (res == -1)
310         return -errno;
311
312     return 0;
313 }
314 #endif
315
316 int xmp_open(const char *path, struct fuse_file_info *fi) {
317     int fd;
318     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
319         return -ENOENT;
320     }
321
322     char *_path = prepend_source_directory(path);
323     fd = open(_path, fi->flags);
324     free(_path);
325
326     if (fd == -1)
327         return -errno;
328
329     fi->fh = fd;
330     return 0;
331 }
332
333 int xmp_read(const char *path, char *buf, size_t size, off_t offset,
334              struct fuse_file_info *fi)
335 {
336     (void) path;
337     if (fi == NULL || fi->fh == 0) {
338         return -1;
339     }
340
341     int res = pread(fi->fh, buf, size, offset);
342     if (res == -1)
343         res = -errno;
344
345     return res;
346 }
347
348 int xmp_write(const char *path, const char *buf, size_t size,
349               off_t offset, struct fuse_file_info *fi)
350 {
351     (void) path;
352     if (fi == NULL || fi->fh == 0) {
353         return -1;
354     }
355
356     int res = pwrite(fi->fh, buf, size, offset);
357     if (res == -1)
358         res = -errno;
359
360     return res;
361 }
362
363 int xmp_statfs(const char *path, struct statvfs *stbuf) {
364     int res;
365     if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1)  {
366         return -ENOENT;
367     }
368
369     char *_path = prepend_source_directory(path);
370     res = statvfs(_path, stbuf);
371     free(_path);
372
373     if (res == -1)
374         return -errno;
375
376     return 0;
377 }
378
379 int xmp_release(const char *path, struct fuse_file_info *fi) {
380     (void) path;
381     return close(fi->fh);
382 }
383
384 int xmp_fsync(const char *path, int isdatasync,
385               struct fuse_file_info *fi) {
386     /* Just a stub.      This method is optional and can safely be left
387        unimplemented */
388
389     (void) path;
390     (void) isdatasync;
391     (void) fi;
392     return 0;
393 }
394
395 #ifdef HAVE_POSIX_FALLOCATE
396 int xmp_fallocate(const char *path, int mode,
397                   off_t offset, off_t length, struct fuse_file_info *fi)
398 {
399     (void) path;
400     if (fi == NULL || fi->fh == 0) {
401         return -1;
402     }
403
404     int res;
405     if (mode)
406         return -EOPNOTSUPP;
407
408     res = -posix_fallocate(fi->fh, offset, length);
409     return res;
410 }
411 #endif
412