2 fuse_xattrs - Add xattrs support using sidecar files
4 Copyright (C) 2016-2017 Felipe Barriga Richards <felipe {at} felipebarriga.cl>
6 Based on passthrough.c (libfuse example)
8 This program can be distributed under the terms of the GNU GPL.
12 #define FUSE_USE_VERSION 30
14 /* For pread()/pwrite()/utimensat() */
15 #define _XOPEN_SOURCE 700
18 #include <osxfuse/fuse.h>
30 #include "xattrs_config.h"
32 #include "stringmem.h"
34 int xmp_getattr(const char *path, struct stat *stbuf) {
37 if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1) {
41 char *_path = prepend_source_directory(path);
42 res = lstat(_path, stbuf);
51 int xmp_access(const char *path, int mask) {
53 if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1) {
57 char *_path = prepend_source_directory(path);
58 res = access(_path, mask);
67 int xmp_readlink(const char *path, char *buf, size_t size) {
69 if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1) {
73 char *_path = prepend_source_directory(path);
74 res = readlink(_path, buf, size - 1);
84 int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
85 off_t offset, struct fuse_file_info *fi)
92 if (fi != NULL && fi->fh != 0) {
93 dp = fdopendir(fi->fh);
95 char *_path = prepend_source_directory(path);
103 while ((de = readdir(dp)) != NULL) {
104 if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(de->d_name) == 1) {
109 memset(&st, 0, sizeof(st));
110 st.st_ino = de->d_ino;
111 st.st_mode = de->d_type << 12;
112 if (filler(buf, de->d_name, &st, 0))
120 int xmp_mknod(const char *path, mode_t mode, dev_t rdev) {
122 if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1) {
126 char *_path = prepend_source_directory(path);
128 /* On Linux this could just be 'mknod(path, mode, rdev)' but this
131 res = open(_path, O_CREAT | O_EXCL | O_WRONLY, mode);
134 } else if (S_ISFIFO(mode))
135 res = mkfifo(_path, mode);
137 res = mknod(_path, mode, rdev);
146 int xmp_mkdir(const char *path, mode_t mode) {
148 if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1) {
152 char *_path = prepend_source_directory(path);
153 res = mkdir(_path, mode);
162 int xmp_unlink(const char *path) {
164 if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1) {
168 char *_path = prepend_source_directory(path);
176 char *sidecar_path = get_sidecar_path(_path);
177 if (is_regular_file(sidecar_path)) {
178 if (unlink(sidecar_path) == -1) {
179 error_print("Error removing sidecar file: %s\n", sidecar_path);
182 strfree(sidecar_path);
188 // FIXME: remove sidecar
189 int xmp_rmdir(const char *path) {
191 if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1) {
195 char *_path = prepend_source_directory(path);
205 int xmp_symlink(const char *from, const char *to) {
207 if (xattrs_config.show_sidecar == 0) {
208 if (filename_is_sidecar(from) == 1 || filename_is_sidecar(to)) {
213 char *_to = prepend_source_directory(to);
214 res = symlink(from, _to);
223 int xmp_rename(const char *from, const char *to) {
225 if (xattrs_config.show_sidecar == 0) {
226 if (filename_is_sidecar(from) == 1 || filename_is_sidecar(to)) {
231 char *_from = prepend_source_directory(from);
232 char *_to = prepend_source_directory(to);
233 res = rename(_from, _to);
241 char *from_sidecar_path = get_sidecar_path(_from);
242 char *to_sidecar_path = get_sidecar_path(_to);
244 // FIXME: Remove to_sidecar_path if it exists ?
245 if (is_regular_file(from_sidecar_path)) {
246 if (rename(from_sidecar_path, to_sidecar_path) == -1) {
247 error_print("Error renaming sidecar. from: %s to: %s\n", from_sidecar_path, to_sidecar_path);
250 strfree(from_sidecar_path);
251 strfree(to_sidecar_path);
259 // TODO: handle sidecar file ?
260 int xmp_link(const char *from, const char *to) {
262 if (xattrs_config.show_sidecar == 0) {
263 if (filename_is_sidecar(from) == 1 || filename_is_sidecar(to)) {
268 char *_from = prepend_source_directory(from);
269 char *_to = prepend_source_directory(to);
270 res = link(_from, _to);
280 int xmp_chmod(const char *path, mode_t mode) {
282 if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1) {
286 char *_path = prepend_source_directory(path);
287 res = chmod(_path, mode);
296 int xmp_chown(const char *path, uid_t uid, gid_t gid) {
298 if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1) {
302 char *_path = prepend_source_directory(path);
303 res = lchown(_path, uid, gid);
312 int xmp_truncate(const char *path, off_t size) {
314 if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1) {
318 char *_path = prepend_source_directory(path);
319 res = truncate(_path, size);
328 #ifdef HAVE_UTIMENSAT
329 int xmp_utimens(const char *path, const struct timespec ts[2]) {
330 if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1) {
336 char *_path = prepend_source_directory(path);
337 /* don't use utime/utimes since they follow symlinks */
338 res = utimensat(0, _path, ts, AT_SYMLINK_NOFOLLOW);
347 int xmp_open(const char *path, struct fuse_file_info *fi) {
349 if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1) {
353 char *_path = prepend_source_directory(path);
354 fd = open(_path, fi->flags);
364 int xmp_read(const char *path, char *buf, size_t size, off_t offset,
365 struct fuse_file_info *fi)
368 if (fi == NULL || fi->fh == 0) {
372 int res = pread(fi->fh, buf, size, offset);
379 int xmp_write(const char *path, const char *buf, size_t size,
380 off_t offset, struct fuse_file_info *fi)
383 if (fi == NULL || fi->fh == 0) {
387 int res = pwrite(fi->fh, buf, size, offset);
394 int xmp_statfs(const char *path, struct statvfs *stbuf) {
396 if (xattrs_config.show_sidecar == 0 && filename_is_sidecar(path) == 1) {
400 char *_path = prepend_source_directory(path);
401 res = statvfs(_path, stbuf);
410 int xmp_release(const char *path, struct fuse_file_info *fi) {
412 return close(fi->fh);
415 int xmp_fsync(const char *path, int isdatasync,
416 struct fuse_file_info *fi) {
417 /* Just a stub. This method is optional and can safely be left
426 #ifdef HAVE_POSIX_FALLOCATE
427 int xmp_fallocate(const char *path, int mode,
428 off_t offset, off_t length, struct fuse_file_info *fi)
431 if (fi == NULL || fi->fh == 0) {
439 res = -posix_fallocate(fi->fh, offset, length);