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