95058833a371376d61204cd234965f87c3a8d5cd
[rrq/fuse_xattrs.git] / passthrough.c
1 /*
2   fuse_xattrs - Add xattrs support using sidecar files
3
4   Copyright (C) 2016  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 "fuse_xattrs_config.h"
26 #include "utils.h"
27
28 int xmp_getattr(const char *path, struct stat *stbuf) {
29     int res;
30
31     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
32     res = lstat(_path, stbuf);
33     free(_path);
34
35     if (res == -1)
36         return -errno;
37
38     return 0;
39 }
40
41 int xmp_access(const char *path, int mask) {
42     int res;
43
44     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
45     res = access(_path, mask);
46     free(_path);
47
48     if (res == -1)
49         return -errno;
50
51     return 0;
52 }
53
54 int xmp_readlink(const char *path, char *buf, size_t size) {
55     int res;
56
57     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
58     res = readlink(_path, buf, size - 1);
59     free(_path);
60
61     if (res == -1)
62         return -errno;
63
64     buf[res] = '\0';
65     return 0;
66 }
67
68 int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
69                 off_t offset, struct fuse_file_info *fi)
70 {
71     DIR *dp;
72     struct dirent *de;
73
74     (void) offset;
75     (void) fi;
76
77     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
78     dp = opendir(_path);
79     free(_path);
80
81     if (dp == NULL)
82         return -errno;
83
84     while ((de = readdir(dp)) != NULL) {
85         struct stat st;
86         memset(&st, 0, sizeof(st));
87         st.st_ino = de->d_ino;
88         st.st_mode = de->d_type << 12;
89         if (filler(buf, de->d_name, &st, 0))
90             break;
91     }
92
93     closedir(dp);
94     return 0;
95 }
96
97 int xmp_mknod(const char *path, mode_t mode, dev_t rdev) {
98     int res;
99     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
100
101     /* On Linux this could just be 'mknod(path, mode, rdev)' but this
102        is more portable */
103     if (S_ISREG(mode)) {
104         res = open(_path, O_CREAT | O_EXCL | O_WRONLY, mode);
105         if (res >= 0)
106             res = close(res);
107     } else if (S_ISFIFO(mode))
108         res = mkfifo(_path, mode);
109     else
110         res = mknod(_path, mode, rdev);
111
112     free(_path);
113     if (res == -1)
114         return -errno;
115
116     return 0;
117 }
118
119 int xmp_mkdir(const char *path, mode_t mode) {
120     int res;
121
122     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
123     res = mkdir(_path, mode);
124     free(_path);
125
126     if (res == -1)
127         return -errno;
128
129     return 0;
130 }
131
132 int xmp_unlink(const char *path) {
133     int res;
134
135     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
136     res = unlink(_path);
137     free(_path);
138
139     if (res == -1)
140         return -errno;
141
142     return 0;
143 }
144
145 int xmp_rmdir(const char *path) {
146     int res;
147
148     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
149     res = rmdir(_path);
150     free(_path);
151
152     if (res == -1)
153         return -errno;
154
155     return 0;
156 }
157
158 int xmp_symlink(const char *from, const char *to) {
159     int res;
160
161     char *_to = prepend_source_directory(xattrs_config.source_dir, to);
162     res = symlink(from, _to);
163     free(_to);
164
165     if (res == -1)
166         return -errno;
167
168     return 0;
169 }
170
171 int xmp_rename(const char *from, const char *to) {
172     int res;
173
174     char *_from = prepend_source_directory(xattrs_config.source_dir, from);
175     char *_to = prepend_source_directory(xattrs_config.source_dir, to);
176     res = rename(_from, _to);
177     free(_from);
178     free(_to);
179
180     if (res == -1)
181         return -errno;
182
183     return 0;
184 }
185
186 int xmp_link(const char *from, const char *to) {
187     int res;
188
189     char *_from = prepend_source_directory(xattrs_config.source_dir, from);
190     char *_to = prepend_source_directory(xattrs_config.source_dir, to);
191     res = link(_from, _to);
192     free(_from);
193     free(_to);
194
195     if (res == -1)
196         return -errno;
197
198     return 0;
199 }
200
201 int xmp_chmod(const char *path, mode_t mode) {
202     int res;
203
204     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
205     res = chmod(_path, mode);
206     free(_path);
207
208     if (res == -1)
209         return -errno;
210
211     return 0;
212 }
213
214 int xmp_chown(const char *path, uid_t uid, gid_t gid) {
215     int res;
216
217     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
218     res = lchown(_path, uid, gid);
219     free(_path);
220
221     if (res == -1)
222         return -errno;
223
224     return 0;
225 }
226
227 int xmp_truncate(const char *path, off_t size) {
228     int res;
229
230     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
231     res = truncate(_path, size);
232     free(_path);
233
234     if (res == -1)
235         return -errno;
236
237     return 0;
238 }
239
240 #ifdef HAVE_UTIMENSAT
241 int xmp_utimens(const char *path, const struct timespec ts[2],
242 struct fuse_file_info *fi)
243 {
244     (void) fi;
245     int res;
246
247     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
248     /* don't use utime/utimes since they follow symlinks */
249     res = utimensat(0, _path, ts, AT_SYMLINK_NOFOLLOW);
250     free(_path);
251     if (res == -1)
252         return -errno;
253
254     return 0;
255 }
256 #endif
257
258 int xmp_open(const char *path, struct fuse_file_info *fi) {
259     int res;
260
261     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
262     res = open(_path, fi->flags);
263     free(_path);
264
265     if (res == -1)
266         return -errno;
267
268     close(res);
269     return 0;
270 }
271
272 int xmp_read(const char *path, char *buf, size_t size, off_t offset,
273              struct fuse_file_info *fi) {
274     int fd;
275     int res;
276
277     (void) fi;
278     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
279     fd = open(_path, O_RDONLY);
280     free(_path);
281
282     if (fd == -1)
283         return -errno;
284
285     res = pread(fd, buf, size, offset);
286     if (res == -1)
287         res = -errno;
288
289     close(fd);
290     return res;
291 }
292
293 int xmp_write(const char *path, const char *buf, size_t size,
294               off_t offset, struct fuse_file_info *fi) {
295     int fd;
296     int res;
297
298     (void) fi;
299     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
300     fd = open(_path, O_WRONLY);
301     free(_path);
302
303     if (fd == -1)
304         return -errno;
305
306     res = pwrite(fd, buf, size, offset);
307     if (res == -1)
308         res = -errno;
309
310     close(fd);
311     return res;
312 }
313
314 int xmp_statfs(const char *path, struct statvfs *stbuf) {
315     int res;
316
317     char *_path = prepend_source_directory(xattrs_config.source_dir, path);
318     res = statvfs(_path, stbuf);
319     free(_path);
320
321     if (res == -1)
322         return -errno;
323
324     return 0;
325 }
326
327 int xmp_release(const char *path, struct fuse_file_info *fi) {
328     /* Just a stub.      This method is optional and can safely be left
329        unimplemented */
330
331     (void) path;
332     (void) fi;
333     return 0;
334 }
335
336 int xmp_fsync(const char *path, int isdatasync,
337               struct fuse_file_info *fi) {
338     /* Just a stub.      This method is optional and can safely be left
339        unimplemented */
340
341     (void) path;
342     (void) isdatasync;
343     (void) fi;
344     return 0;
345 }
346
347 #ifdef HAVE_POSIX_FALLOCATE
348 int xmp_fallocate(const char *path, int mode,
349                   off_t offset, off_t length, struct fuse_file_info *fi)
350 {
351     int fd;
352     int res;
353
354     (void) fi;
355
356     if (mode)
357         return -EOPNOTSUPP;
358
359     char *_path = concat(xattrs_config.source_dir, path);
360     fd = open(_path, O_WRONLY);
361     free(_path);
362
363     if (fd == -1)
364         return -errno;
365
366     res = -posix_fallocate(fd, offset, length);
367
368     close(fd);
369     return res;
370 }
371 #endif
372