PageRenderTime 72ms CodeModel.GetById 26ms app.highlight 41ms RepoModel.GetById 1ms app.codeStats 0ms

/filesystems/loopback/loopback.c

http://macfuse.googlecode.com/
C | 756 lines | 576 code | 158 blank | 22 comment | 110 complexity | 017ce370291472d6f69b51ececc259da MD5 | raw file
  1/*
  2  FUSE: Filesystem in Userspace
  3  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
  4
  5  This program can be distributed under the terms of the GNU GPL.
  6  See the file COPYING.
  7
  8*/
  9
 10/*
 11 * Loopback MacFUSE file system in C. Uses the high-level FUSE API.
 12 * Based on the fusexmp_fh.c example from the Linux FUSE distribution.
 13 * Amit Singh <http://osxbook.com>
 14 */
 15
 16#include <AvailabilityMacros.h>
 17
 18#if !defined(AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER)
 19#error "This file system requires Leopard and above."
 20#endif
 21
 22#define FUSE_USE_VERSION 26
 23
 24#define _GNU_SOURCE
 25
 26#include <fuse.h>
 27#include <stdio.h>
 28#include <stdlib.h>
 29#include <string.h>
 30#include <unistd.h>
 31#include <fcntl.h>
 32#include <dirent.h>
 33#include <errno.h>
 34#include <sys/time.h>
 35#include <sys/xattr.h>
 36#include <sys/attr.h>
 37#include <sys/param.h>
 38
 39#if defined(_POSIX_C_SOURCE)
 40typedef unsigned char  u_char;
 41typedef unsigned short u_short;
 42typedef unsigned int   u_int;
 43typedef unsigned long  u_long;
 44#endif
 45
 46#define G_PREFIX                       "org"
 47#define G_KAUTH_FILESEC_XATTR G_PREFIX ".apple.system.Security"
 48#define A_PREFIX                       "com"
 49#define A_KAUTH_FILESEC_XATTR A_PREFIX ".apple.system.Security"
 50#define XATTR_APPLE_PREFIX             "com.apple."
 51
 52static int
 53loopback_getattr(const char *path, struct stat *stbuf)
 54{
 55    int res;
 56
 57    res = lstat(path, stbuf);
 58    if (res == -1) {
 59        return -errno;
 60    }
 61
 62    return 0;
 63}
 64
 65static int
 66loopback_fgetattr(const char *path, struct stat *stbuf,
 67                  struct fuse_file_info *fi)
 68{
 69    int res;
 70
 71    (void)path;
 72
 73    res = fstat(fi->fh, stbuf);
 74    if (res == -1) {
 75        return -errno;
 76    }
 77
 78    return 0;
 79}
 80
 81static int
 82loopback_readlink(const char *path, char *buf, size_t size)
 83{
 84    int res;
 85
 86    res = readlink(path, buf, size - 1);
 87    if (res == -1) {
 88        return -errno;
 89    }
 90
 91    buf[res] = '\0';
 92
 93    return 0;
 94}
 95
 96struct loopback_dirp {
 97    DIR *dp;
 98    struct dirent *entry;
 99    off_t offset;
100};
101
102static int
103loopback_opendir(const char *path, struct fuse_file_info *fi)
104{
105    int res;
106
107    struct loopback_dirp *d = malloc(sizeof(struct loopback_dirp));
108    if (d == NULL) {
109        return -ENOMEM;
110    }
111
112    d->dp = opendir(path);
113    if (d->dp == NULL) {
114        res = -errno;
115        free(d);
116        return res;
117    }
118
119    d->offset = 0;
120    d->entry = NULL;
121
122    fi->fh = (unsigned long)d;
123
124    return 0;
125}
126
127static inline struct loopback_dirp *
128get_dirp(struct fuse_file_info *fi)
129{
130    return (struct loopback_dirp *)(uintptr_t)fi->fh;
131}
132
133static int
134loopback_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
135                 off_t offset, struct fuse_file_info *fi)
136{
137    struct loopback_dirp *d = get_dirp(fi);
138
139    (void)path;
140
141    if (offset != d->offset) {
142        seekdir(d->dp, offset);
143        d->entry = NULL;
144        d->offset = offset;
145    }
146
147    while (1) {
148        struct stat st;
149        off_t nextoff;
150
151        if (!d->entry) {
152            d->entry = readdir(d->dp);
153            if (!d->entry) {
154                break;
155            }
156        }
157
158        memset(&st, 0, sizeof(st));
159        st.st_ino = d->entry->d_ino;
160        st.st_mode = d->entry->d_type << 12;
161        nextoff = telldir(d->dp);
162        if (filler(buf, d->entry->d_name, &st, nextoff)) {
163            break;
164        }
165
166        d->entry = NULL;
167        d->offset = nextoff;
168    }
169
170    return 0;
171}
172
173static int
174loopback_releasedir(const char *path, struct fuse_file_info *fi)
175{
176    struct loopback_dirp *d = get_dirp(fi);
177
178    (void)path;
179
180    closedir(d->dp);
181    free(d);
182
183    return 0;
184}
185
186static int
187loopback_mknod(const char *path, mode_t mode, dev_t rdev)
188{
189    int res;
190
191    if (S_ISFIFO(mode)) {
192        res = mkfifo(path, mode);
193    } else {
194        res = mknod(path, mode, rdev);
195    }
196
197    if (res == -1) {
198        return -errno;
199    }
200
201    return 0;
202}
203
204static int
205loopback_mkdir(const char *path, mode_t mode)
206{
207    int res;
208
209    res = mkdir(path, mode);
210    if (res == -1) {
211        return -errno;
212    }
213
214    return 0;
215}
216
217static int
218loopback_unlink(const char *path)
219{
220    int res;
221
222    res = unlink(path);
223    if (res == -1) {
224        return -errno;
225    }
226
227    return 0;
228}
229
230static int
231loopback_rmdir(const char *path)
232{
233    int res;
234
235    res = rmdir(path);
236    if (res == -1) {
237        return -errno;
238    }
239
240    return 0;
241}
242
243static int
244loopback_symlink(const char *from, const char *to)
245{
246    int res;
247
248    res = symlink(from, to);
249    if (res == -1) {
250        return -errno;
251    }
252
253    return 0;
254}
255
256static int
257loopback_rename(const char *from, const char *to)
258{
259    int res;
260
261    res = rename(from, to);
262    if (res == -1) {
263        return -errno;
264    }
265
266    return 0;
267}
268
269static int
270loopback_exchange(const char *path1, const char *path2, unsigned long options)
271{
272    int res;
273
274    res = exchangedata(path1, path2, options);
275    if (res == -1) {
276        return -errno;
277    }
278
279    return 0;
280}
281
282static int
283loopback_link(const char *from, const char *to)
284{
285    int res;
286
287    res = link(from, to);
288    if (res == -1) {
289        return -errno;
290    }
291
292    return 0;
293}
294
295static int
296loopback_fsetattr_x(const char *path, struct setattr_x *attr,
297                    struct fuse_file_info *fi)
298{
299    int res;
300    uid_t uid = -1;
301    gid_t gid = -1;
302
303    if (SETATTR_WANTS_MODE(attr)) {
304        res = lchmod(path, attr->mode);
305        if (res == -1) {
306            return -errno;
307        }
308    }
309
310    if (SETATTR_WANTS_UID(attr)) {
311        uid = attr->uid;
312    }
313
314    if (SETATTR_WANTS_GID(attr)) {
315        gid = attr->gid;
316    }
317
318    if ((uid != -1) || (gid != -1)) {
319        res = lchown(path, uid, gid);
320        if (res == -1) {
321            return -errno;
322        }
323    }
324
325    if (SETATTR_WANTS_SIZE(attr)) {
326        if (fi) {
327            res = ftruncate(fi->fh, attr->size);
328        } else {
329            res = truncate(path, attr->size);
330        }
331        if (res == -1) {
332            return -errno;
333        }
334    }
335
336    if (SETATTR_WANTS_MODTIME(attr)) {
337        struct timeval tv[2];
338        if (!SETATTR_WANTS_ACCTIME(attr)) {
339            gettimeofday(&tv[0], NULL);
340        } else {
341            tv[0].tv_sec = attr->acctime.tv_sec;
342            tv[0].tv_usec = attr->acctime.tv_nsec / 1000;
343        }
344        tv[1].tv_sec = attr->modtime.tv_sec;
345        tv[1].tv_usec = attr->modtime.tv_nsec / 1000;
346        res = utimes(path, tv);
347        if (res == -1) {
348            return -errno;
349        }
350    }
351
352    if (SETATTR_WANTS_CRTIME(attr)) {
353        struct attrlist attributes;
354
355        attributes.bitmapcount = ATTR_BIT_MAP_COUNT;
356        attributes.reserved = 0;
357        attributes.commonattr = ATTR_CMN_CRTIME;
358        attributes.dirattr = 0;
359        attributes.fileattr = 0;
360        attributes.forkattr = 0;
361        attributes.volattr = 0;
362
363        res = setattrlist(path, &attributes, &attr->crtime,
364                  sizeof(struct timespec), FSOPT_NOFOLLOW);
365
366        if (res == -1) {
367            return -errno;
368        }
369    }
370
371    if (SETATTR_WANTS_CHGTIME(attr)) {
372        struct attrlist attributes;
373
374        attributes.bitmapcount = ATTR_BIT_MAP_COUNT;
375        attributes.reserved = 0;
376        attributes.commonattr = ATTR_CMN_CHGTIME;
377        attributes.dirattr = 0;
378        attributes.fileattr = 0;
379        attributes.forkattr = 0;
380        attributes.volattr = 0;
381
382        res = setattrlist(path, &attributes, &attr->chgtime,
383                  sizeof(struct timespec), FSOPT_NOFOLLOW);
384
385        if (res == -1) {
386            return -errno;
387        }
388    }
389
390    if (SETATTR_WANTS_BKUPTIME(attr)) {
391        struct attrlist attributes;
392
393        attributes.bitmapcount = ATTR_BIT_MAP_COUNT;
394        attributes.reserved = 0;
395        attributes.commonattr = ATTR_CMN_BKUPTIME;
396        attributes.dirattr = 0;
397        attributes.fileattr = 0;
398        attributes.forkattr = 0;
399        attributes.volattr = 0;
400
401        res = setattrlist(path, &attributes, &attr->bkuptime,
402                  sizeof(struct timespec), FSOPT_NOFOLLOW);
403
404        if (res == -1) {
405            return -errno;
406        }
407    }
408
409    if (SETATTR_WANTS_FLAGS(attr)) {
410        res = lchflags(path, attr->flags);
411        if (res == -1) {
412            return -errno;
413        }
414    }
415
416    return 0;
417}
418
419static int
420loopback_setattr_x(const char *path, struct setattr_x *attr)
421{
422    return loopback_fsetattr_x(path, attr, (struct fuse_file_info *)0);
423}
424
425static int
426loopback_getxtimes(const char *path, struct timespec *bkuptime,
427                   struct timespec *crtime)
428{
429    int res = 0;
430    struct attrlist attributes;
431
432    attributes.bitmapcount = ATTR_BIT_MAP_COUNT;
433    attributes.reserved    = 0;
434    attributes.commonattr  = 0;
435    attributes.dirattr     = 0;
436    attributes.fileattr    = 0;
437    attributes.forkattr    = 0;
438    attributes.volattr     = 0;
439
440
441
442    struct xtimeattrbuf {
443        uint32_t size;
444        struct timespec xtime;
445    } __attribute__ ((packed));
446
447
448    struct xtimeattrbuf buf;
449
450    attributes.commonattr = ATTR_CMN_BKUPTIME;
451    res = getattrlist(path, &attributes, &buf, sizeof(buf), FSOPT_NOFOLLOW);
452    if (res == 0) {
453        (void)memcpy(bkuptime, &(buf.xtime), sizeof(struct timespec));
454    } else {
455        (void)memset(bkuptime, 0, sizeof(struct timespec));
456    }
457
458    attributes.commonattr = ATTR_CMN_CRTIME;
459    res = getattrlist(path, &attributes, &buf, sizeof(buf), FSOPT_NOFOLLOW);
460    if (res == 0) {
461        (void)memcpy(crtime, &(buf.xtime), sizeof(struct timespec));
462    } else {
463        (void)memset(crtime, 0, sizeof(struct timespec));
464    }
465
466    return 0;
467}
468
469static int
470loopback_create(const char *path, mode_t mode, struct fuse_file_info *fi)
471{
472    int fd;
473
474    fd = open(path, fi->flags, mode);
475    if (fd == -1) {
476        return -errno;
477    }
478
479    fi->fh = fd;
480    return 0;
481}
482
483static int
484loopback_open(const char *path, struct fuse_file_info *fi)
485{
486    int fd;
487
488    fd = open(path, fi->flags);
489    if (fd == -1) {
490        return -errno;
491    }
492
493    fi->fh = fd;
494    return 0;
495}
496
497static int
498loopback_read(const char *path, char *buf, size_t size, off_t offset,
499              struct fuse_file_info *fi)
500{
501    int res;
502
503    (void)path;
504    res = pread(fi->fh, buf, size, offset);
505    if (res == -1) {
506        res = -errno;
507    }
508
509    return res;
510}
511
512static int
513loopback_write(const char *path, const char *buf, size_t size,
514               off_t offset, struct fuse_file_info *fi)
515{
516    int res;
517
518    (void)path;
519
520    res = pwrite(fi->fh, buf, size, offset);
521    if (res == -1) {
522        res = -errno;
523    }
524
525    return res;
526}
527
528static int
529loopback_statfs(const char *path, struct statvfs *stbuf)
530{
531    int res;
532
533    res = statvfs(path, stbuf);
534    if (res == -1) {
535        return -errno;
536    }
537
538    return 0;
539}
540
541static int
542loopback_flush(const char *path, struct fuse_file_info *fi)
543{
544    int res;
545
546    (void)path;
547
548    res = close(dup(fi->fh));
549    if (res == -1) {
550        return -errno;
551    }
552
553    return 0;
554}
555
556static int
557loopback_release(const char *path, struct fuse_file_info *fi)
558{
559    (void)path;
560
561    close(fi->fh);
562
563    return 0;
564}
565
566static int
567loopback_fsync(const char *path, int isdatasync, struct fuse_file_info *fi)
568{
569    int res;
570
571    (void)path;
572
573    (void)isdatasync;
574
575    res = fsync(fi->fh);
576    if (res == -1) {
577        return -errno;
578    }
579
580    return 0;
581}
582
583static int
584loopback_setxattr(const char *path, const char *name, const char *value,
585                  size_t size, int flags, uint32_t position)
586{
587    int res;
588
589    if (!strncmp(name, XATTR_APPLE_PREFIX, sizeof(XATTR_APPLE_PREFIX) - 1)) {
590        flags &= ~(XATTR_NOSECURITY);
591    }
592
593    if (!strcmp(name, A_KAUTH_FILESEC_XATTR)) {
594
595        char new_name[MAXPATHLEN];
596
597        memcpy(new_name, A_KAUTH_FILESEC_XATTR, sizeof(A_KAUTH_FILESEC_XATTR));
598        memcpy(new_name, G_PREFIX, sizeof(G_PREFIX) - 1);
599
600        res = setxattr(path, new_name, value, size, position, flags);
601
602    } else {
603        res = setxattr(path, name, value, size, position, flags);
604    }
605
606    if (res == -1) {
607        return -errno;
608    }
609
610    return 0;
611}
612
613static int
614loopback_getxattr(const char *path, const char *name, char *value, size_t size,
615                  uint32_t position)
616{
617    int res;
618
619    if (strcmp(name, A_KAUTH_FILESEC_XATTR) == 0) {
620
621        char new_name[MAXPATHLEN];
622
623        memcpy(new_name, A_KAUTH_FILESEC_XATTR, sizeof(A_KAUTH_FILESEC_XATTR));
624        memcpy(new_name, G_PREFIX, sizeof(G_PREFIX) - 1);
625
626        res = getxattr(path, new_name, value, size, position, XATTR_NOFOLLOW);
627
628    } else {
629        res = getxattr(path, name, value, size, position, XATTR_NOFOLLOW);
630    }
631
632    if (res == -1) {
633        return -errno;
634    }
635
636    return res;
637}
638
639static int
640loopback_listxattr(const char *path, char *list, size_t size)
641{
642    ssize_t res = listxattr(path, list, size, XATTR_NOFOLLOW);
643    if (res > 0) {
644        if (list) {
645            size_t len = 0;
646            char *curr = list;
647            do { 
648                size_t thislen = strlen(curr) + 1;
649                if (strcmp(curr, G_KAUTH_FILESEC_XATTR) == 0) {
650                    memmove(curr, curr + thislen, res - len - thislen);
651                    res -= thislen;
652                    break;
653                }
654                curr += thislen;
655                len += thislen;
656            } while (len < res);
657        } else {
658            /*
659            ssize_t res2 = getxattr(path, G_KAUTH_FILESEC_XATTR, NULL, 0, 0,
660                                    XATTR_NOFOLLOW);
661            if (res2 >= 0) {
662                res -= sizeof(G_KAUTH_FILESEC_XATTR);
663            }
664            */
665        }
666    }
667
668    if (res == -1) {
669        return -errno;
670    }
671
672    return res;
673}
674
675static int
676loopback_removexattr(const char *path, const char *name)
677{
678    int res;
679
680    if (strcmp(name, A_KAUTH_FILESEC_XATTR) == 0) {
681
682        char new_name[MAXPATHLEN];
683
684        memcpy(new_name, A_KAUTH_FILESEC_XATTR, sizeof(A_KAUTH_FILESEC_XATTR));
685        memcpy(new_name, G_PREFIX, sizeof(G_PREFIX) - 1);
686
687        res = removexattr(path, new_name, XATTR_NOFOLLOW);
688
689    } else {
690        res = removexattr(path, name, XATTR_NOFOLLOW);
691    }
692
693    if (res == -1) {
694        return -errno;
695    }
696
697    return 0;
698}
699
700void *
701loopback_init(struct fuse_conn_info *conn)
702{
703    FUSE_ENABLE_SETVOLNAME(conn);
704    FUSE_ENABLE_XTIMES(conn);
705
706    return NULL;
707}
708
709void
710loopback_destroy(void *userdata)
711{
712    /* nothing */
713}
714
715static struct fuse_operations loopback_oper = {
716    .init        = loopback_init,
717    .destroy     = loopback_destroy,
718    .getattr     = loopback_getattr,
719    .fgetattr    = loopback_fgetattr,
720/*  .access      = loopback_access, */
721    .readlink    = loopback_readlink,
722    .opendir     = loopback_opendir,
723    .readdir     = loopback_readdir,
724    .releasedir  = loopback_releasedir,
725    .mknod       = loopback_mknod,
726    .mkdir       = loopback_mkdir,
727    .symlink     = loopback_symlink,
728    .unlink      = loopback_unlink,
729    .rmdir       = loopback_rmdir,
730    .rename      = loopback_rename,
731    .link        = loopback_link,
732    .create      = loopback_create,
733    .open        = loopback_open,
734    .read        = loopback_read,
735    .write       = loopback_write,
736    .statfs      = loopback_statfs,
737    .flush       = loopback_flush,
738    .release     = loopback_release,
739    .fsync       = loopback_fsync,
740    .setxattr    = loopback_setxattr,
741    .getxattr    = loopback_getxattr,
742    .listxattr   = loopback_listxattr,
743    .removexattr = loopback_removexattr,
744    .exchange    = loopback_exchange,
745    .getxtimes   = loopback_getxtimes,
746    .setattr_x   = loopback_setattr_x,
747    .fsetattr_x  = loopback_fsetattr_x,
748};
749
750int
751main(int argc, char *argv[])
752{
753    umask(0);
754
755    return fuse_main(argc, argv, &loopback_oper, NULL);
756}