Home | History | Annotate | Download | only in sdcard
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <stdio.h>
     18 #include <stdlib.h>
     19 #include <string.h>
     20 #include <unistd.h>
     21 #include <errno.h>
     22 #include <fcntl.h>
     23 #include <sys/mount.h>
     24 #include <sys/stat.h>
     25 #include <sys/statfs.h>
     26 #include <sys/uio.h>
     27 #include <dirent.h>
     28 #include <limits.h>
     29 #include <ctype.h>
     30 #include <pthread.h>
     31 #include <sys/time.h>
     32 #include <sys/resource.h>
     33 
     34 #include <private/android_filesystem_config.h>
     35 
     36 #include "fuse.h"
     37 
     38 /* README
     39  *
     40  * What is this?
     41  *
     42  * sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
     43  * directory permissions (all files are given fixed owner, group, and
     44  * permissions at creation, owner, group, and permissions are not
     45  * changeable, symlinks and hardlinks are not createable, etc.
     46  *
     47  * See usage() for command line options.
     48  *
     49  * It must be run as root, but will drop to requested UID/GID as soon as it
     50  * mounts a filesystem.  It will refuse to run if requested UID/GID are zero.
     51  *
     52  * Things I believe to be true:
     53  *
     54  * - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK,
     55  * CREAT) must bump that node's refcount
     56  * - don't forget that FORGET can forget multiple references (req->nlookup)
     57  * - if an op that returns a fuse_entry fails writing the reply to the
     58  * kernel, you must rollback the refcount to reflect the reference the
     59  * kernel did not actually acquire
     60  */
     61 
     62 #define FUSE_TRACE 0
     63 
     64 #if FUSE_TRACE
     65 #define TRACE(x...) fprintf(stderr,x)
     66 #else
     67 #define TRACE(x...) do {} while (0)
     68 #endif
     69 
     70 #define ERROR(x...) fprintf(stderr,x)
     71 
     72 #define FUSE_UNKNOWN_INO 0xffffffff
     73 
     74 /* Maximum number of bytes to write in one request. */
     75 #define MAX_WRITE (256 * 1024)
     76 
     77 /* Maximum number of bytes to read in one request. */
     78 #define MAX_READ (128 * 1024)
     79 
     80 /* Largest possible request.
     81  * The request size is bounded by the maximum size of a FUSE_WRITE request because it has
     82  * the largest possible data payload. */
     83 #define MAX_REQUEST_SIZE (sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE)
     84 
     85 /* Default number of threads. */
     86 #define DEFAULT_NUM_THREADS 2
     87 
     88 /* Pseudo-error constant used to indicate that no fuse status is needed
     89  * or that a reply has already been written. */
     90 #define NO_STATUS 1
     91 
     92 struct handle {
     93     int fd;
     94 };
     95 
     96 struct dirhandle {
     97     DIR *d;
     98 };
     99 
    100 struct node {
    101     __u32 refcount;
    102     __u64 nid;
    103     __u64 gen;
    104 
    105     struct node *next;          /* per-dir sibling list */
    106     struct node *child;         /* first contained file by this dir */
    107     struct node *parent;        /* containing directory */
    108 
    109     size_t namelen;
    110     char *name;
    111     /* If non-null, this is the real name of the file in the underlying storage.
    112      * This may differ from the field "name" only by case.
    113      * strlen(actual_name) will always equal strlen(name), so it is safe to use
    114      * namelen for both fields.
    115      */
    116     char *actual_name;
    117 };
    118 
    119 /* Global data structure shared by all fuse handlers. */
    120 struct fuse {
    121     pthread_mutex_t lock;
    122 
    123     __u64 next_generation;
    124     int fd;
    125     struct node root;
    126     char rootpath[PATH_MAX];
    127 };
    128 
    129 /* Private data used by a single fuse handler. */
    130 struct fuse_handler {
    131     struct fuse* fuse;
    132     int token;
    133 
    134     /* To save memory, we never use the contents of the request buffer and the read
    135      * buffer at the same time.  This allows us to share the underlying storage. */
    136     union {
    137         __u8 request_buffer[MAX_REQUEST_SIZE];
    138         __u8 read_buffer[MAX_READ];
    139     };
    140 };
    141 
    142 static inline void *id_to_ptr(__u64 nid)
    143 {
    144     return (void *) (uintptr_t) nid;
    145 }
    146 
    147 static inline __u64 ptr_to_id(void *ptr)
    148 {
    149     return (__u64) (uintptr_t) ptr;
    150 }
    151 
    152 static void acquire_node_locked(struct node* node)
    153 {
    154     node->refcount++;
    155     TRACE("ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount);
    156 }
    157 
    158 static void remove_node_from_parent_locked(struct node* node);
    159 
    160 static void release_node_locked(struct node* node)
    161 {
    162     TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount);
    163     if (node->refcount > 0) {
    164         node->refcount--;
    165         if (!node->refcount) {
    166             TRACE("DESTROY %p (%s)\n", node, node->name);
    167             remove_node_from_parent_locked(node);
    168 
    169                 /* TODO: remove debugging - poison memory */
    170             memset(node->name, 0xef, node->namelen);
    171             free(node->name);
    172             free(node->actual_name);
    173             memset(node, 0xfc, sizeof(*node));
    174             free(node);
    175         }
    176     } else {
    177         ERROR("Zero refcnt %p\n", node);
    178     }
    179 }
    180 
    181 static void add_node_to_parent_locked(struct node *node, struct node *parent) {
    182     node->parent = parent;
    183     node->next = parent->child;
    184     parent->child = node;
    185     acquire_node_locked(parent);
    186 }
    187 
    188 static void remove_node_from_parent_locked(struct node* node)
    189 {
    190     if (node->parent) {
    191         if (node->parent->child == node) {
    192             node->parent->child = node->parent->child->next;
    193         } else {
    194             struct node *node2;
    195             node2 = node->parent->child;
    196             while (node2->next != node)
    197                 node2 = node2->next;
    198             node2->next = node->next;
    199         }
    200         release_node_locked(node->parent);
    201         node->parent = NULL;
    202         node->next = NULL;
    203     }
    204 }
    205 
    206 /* Gets the absolute path to a node into the provided buffer.
    207  *
    208  * Populates 'buf' with the path and returns the length of the path on success,
    209  * or returns -1 if the path is too long for the provided buffer.
    210  */
    211 static ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize)
    212 {
    213     size_t namelen = node->namelen;
    214     if (bufsize < namelen + 1) {
    215         return -1;
    216     }
    217 
    218     ssize_t pathlen = 0;
    219     if (node->parent) {
    220         pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 2);
    221         if (pathlen < 0) {
    222             return -1;
    223         }
    224         buf[pathlen++] = '/';
    225     }
    226 
    227     const char* name = node->actual_name ? node->actual_name : node->name;
    228     memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
    229     return pathlen + namelen;
    230 }
    231 
    232 /* Finds the absolute path of a file within a given directory.
    233  * Performs a case-insensitive search for the file and sets the buffer to the path
    234  * of the first matching file.  If 'search' is zero or if no match is found, sets
    235  * the buffer to the path that the file would have, assuming the name were case-sensitive.
    236  *
    237  * Populates 'buf' with the path and returns the actual name (within 'buf') on success,
    238  * or returns NULL if the path is too long for the provided buffer.
    239  */
    240 static char* find_file_within(const char* path, const char* name,
    241         char* buf, size_t bufsize, int search)
    242 {
    243     size_t pathlen = strlen(path);
    244     size_t namelen = strlen(name);
    245     size_t childlen = pathlen + namelen + 1;
    246     char* actual;
    247 
    248     if (bufsize <= childlen) {
    249         return NULL;
    250     }
    251 
    252     memcpy(buf, path, pathlen);
    253     buf[pathlen] = '/';
    254     actual = buf + pathlen + 1;
    255     memcpy(actual, name, namelen + 1);
    256 
    257     if (search && access(buf, F_OK)) {
    258         struct dirent* entry;
    259         DIR* dir = opendir(path);
    260         if (!dir) {
    261             ERROR("opendir %s failed: %s", path, strerror(errno));
    262             return actual;
    263         }
    264         while ((entry = readdir(dir))) {
    265             if (!strcasecmp(entry->d_name, name)) {
    266                 /* we have a match - replace the name, don't need to copy the null again */
    267                 memcpy(actual, entry->d_name, namelen);
    268                 break;
    269             }
    270         }
    271         closedir(dir);
    272     }
    273     return actual;
    274 }
    275 
    276 static void attr_from_stat(struct fuse_attr *attr, const struct stat *s, __u64 nid)
    277 {
    278     attr->ino = nid;
    279     attr->size = s->st_size;
    280     attr->blocks = s->st_blocks;
    281     attr->atime = s->st_atime;
    282     attr->mtime = s->st_mtime;
    283     attr->ctime = s->st_ctime;
    284     attr->atimensec = s->st_atime_nsec;
    285     attr->mtimensec = s->st_mtime_nsec;
    286     attr->ctimensec = s->st_ctime_nsec;
    287     attr->mode = s->st_mode;
    288     attr->nlink = s->st_nlink;
    289 
    290         /* force permissions to something reasonable:
    291          * world readable
    292          * writable by the sdcard group
    293          */
    294     if (attr->mode & 0100) {
    295         attr->mode = (attr->mode & (~0777)) | 0775;
    296     } else {
    297         attr->mode = (attr->mode & (~0777)) | 0664;
    298     }
    299 
    300         /* all files owned by root.sdcard */
    301     attr->uid = 0;
    302     attr->gid = AID_SDCARD_RW;
    303 }
    304 
    305 struct node *create_node_locked(struct fuse* fuse,
    306         struct node *parent, const char *name, const char* actual_name)
    307 {
    308     struct node *node;
    309     size_t namelen = strlen(name);
    310 
    311     node = calloc(1, sizeof(struct node));
    312     if (!node) {
    313         return NULL;
    314     }
    315     node->name = malloc(namelen + 1);
    316     if (!node->name) {
    317         free(node);
    318         return NULL;
    319     }
    320     memcpy(node->name, name, namelen + 1);
    321     if (strcmp(name, actual_name)) {
    322         node->actual_name = malloc(namelen + 1);
    323         if (!node->actual_name) {
    324             free(node->name);
    325             free(node);
    326             return NULL;
    327         }
    328         memcpy(node->actual_name, actual_name, namelen + 1);
    329     }
    330     node->namelen = namelen;
    331     node->nid = ptr_to_id(node);
    332     node->gen = fuse->next_generation++;
    333     acquire_node_locked(node);
    334     add_node_to_parent_locked(node, parent);
    335     return node;
    336 }
    337 
    338 static int rename_node_locked(struct node *node, const char *name,
    339         const char* actual_name)
    340 {
    341     size_t namelen = strlen(name);
    342     int need_actual_name = strcmp(name, actual_name);
    343 
    344     /* make the storage bigger without actually changing the name
    345      * in case an error occurs part way */
    346     if (namelen > node->namelen) {
    347         char* new_name = realloc(node->name, namelen + 1);
    348         if (!new_name) {
    349             return -ENOMEM;
    350         }
    351         node->name = new_name;
    352         if (need_actual_name && node->actual_name) {
    353             char* new_actual_name = realloc(node->actual_name, namelen + 1);
    354             if (!new_actual_name) {
    355                 return -ENOMEM;
    356             }
    357             node->actual_name = new_actual_name;
    358         }
    359     }
    360 
    361     /* update the name, taking care to allocate storage before overwriting the old name */
    362     if (need_actual_name) {
    363         if (!node->actual_name) {
    364             node->actual_name = malloc(namelen + 1);
    365             if (!node->actual_name) {
    366                 return -ENOMEM;
    367             }
    368         }
    369         memcpy(node->actual_name, actual_name, namelen + 1);
    370     } else {
    371         free(node->actual_name);
    372         node->actual_name = NULL;
    373     }
    374     memcpy(node->name, name, namelen + 1);
    375     node->namelen = namelen;
    376     return 0;
    377 }
    378 
    379 static struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
    380 {
    381     if (nid == FUSE_ROOT_ID) {
    382         return &fuse->root;
    383     } else {
    384         return id_to_ptr(nid);
    385     }
    386 }
    387 
    388 static struct node* lookup_node_and_path_by_id_locked(struct fuse* fuse, __u64 nid,
    389         char* buf, size_t bufsize)
    390 {
    391     struct node* node = lookup_node_by_id_locked(fuse, nid);
    392     if (node && get_node_path_locked(node, buf, bufsize) < 0) {
    393         node = NULL;
    394     }
    395     return node;
    396 }
    397 
    398 static struct node *lookup_child_by_name_locked(struct node *node, const char *name)
    399 {
    400     for (node = node->child; node; node = node->next) {
    401         /* use exact string comparison, nodes that differ by case
    402          * must be considered distinct even if they refer to the same
    403          * underlying file as otherwise operations such as "mv x x"
    404          * will not work because the source and target nodes are the same. */
    405         if (!strcmp(name, node->name)) {
    406             return node;
    407         }
    408     }
    409     return 0;
    410 }
    411 
    412 static struct node* acquire_or_create_child_locked(
    413         struct fuse* fuse, struct node* parent,
    414         const char* name, const char* actual_name)
    415 {
    416     struct node* child = lookup_child_by_name_locked(parent, name);
    417     if (child) {
    418         acquire_node_locked(child);
    419     } else {
    420         child = create_node_locked(fuse, parent, name, actual_name);
    421     }
    422     return child;
    423 }
    424 
    425 static void fuse_init(struct fuse *fuse, int fd, const char *source_path)
    426 {
    427     pthread_mutex_init(&fuse->lock, NULL);
    428 
    429     fuse->fd = fd;
    430     fuse->next_generation = 0;
    431 
    432     memset(&fuse->root, 0, sizeof(fuse->root));
    433     fuse->root.nid = FUSE_ROOT_ID; /* 1 */
    434     fuse->root.refcount = 2;
    435     fuse->root.namelen = strlen(source_path);
    436     fuse->root.name = strdup(source_path);
    437 }
    438 
    439 static void fuse_status(struct fuse *fuse, __u64 unique, int err)
    440 {
    441     struct fuse_out_header hdr;
    442     hdr.len = sizeof(hdr);
    443     hdr.error = err;
    444     hdr.unique = unique;
    445     write(fuse->fd, &hdr, sizeof(hdr));
    446 }
    447 
    448 static void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
    449 {
    450     struct fuse_out_header hdr;
    451     struct iovec vec[2];
    452     int res;
    453 
    454     hdr.len = len + sizeof(hdr);
    455     hdr.error = 0;
    456     hdr.unique = unique;
    457 
    458     vec[0].iov_base = &hdr;
    459     vec[0].iov_len = sizeof(hdr);
    460     vec[1].iov_base = data;
    461     vec[1].iov_len = len;
    462 
    463     res = writev(fuse->fd, vec, 2);
    464     if (res < 0) {
    465         ERROR("*** REPLY FAILED *** %d\n", errno);
    466     }
    467 }
    468 
    469 static int fuse_reply_entry(struct fuse* fuse, __u64 unique,
    470         struct node* parent, const char* name, const char* actual_name,
    471         const char* path)
    472 {
    473     struct node* node;
    474     struct fuse_entry_out out;
    475     struct stat s;
    476 
    477     if (lstat(path, &s) < 0) {
    478         return -errno;
    479     }
    480 
    481     pthread_mutex_lock(&fuse->lock);
    482     node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
    483     if (!node) {
    484         pthread_mutex_unlock(&fuse->lock);
    485         return -ENOMEM;
    486     }
    487     memset(&out, 0, sizeof(out));
    488     attr_from_stat(&out.attr, &s, node->nid);
    489     out.attr_valid = 10;
    490     out.entry_valid = 10;
    491     out.nodeid = node->nid;
    492     out.generation = node->gen;
    493     pthread_mutex_unlock(&fuse->lock);
    494     fuse_reply(fuse, unique, &out, sizeof(out));
    495     return NO_STATUS;
    496 }
    497 
    498 static int fuse_reply_attr(struct fuse* fuse, __u64 unique, __u64 nid,
    499         const char* path)
    500 {
    501     struct fuse_attr_out out;
    502     struct stat s;
    503 
    504     if (lstat(path, &s) < 0) {
    505         return -errno;
    506     }
    507     memset(&out, 0, sizeof(out));
    508     attr_from_stat(&out.attr, &s, nid);
    509     out.attr_valid = 10;
    510     fuse_reply(fuse, unique, &out, sizeof(out));
    511     return NO_STATUS;
    512 }
    513 
    514 static int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
    515         const struct fuse_in_header *hdr, const char* name)
    516 {
    517     struct node* parent_node;
    518     char parent_path[PATH_MAX];
    519     char child_path[PATH_MAX];
    520     const char* actual_name;
    521 
    522     pthread_mutex_lock(&fuse->lock);
    523     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
    524             parent_path, sizeof(parent_path));
    525     TRACE("[%d] LOOKUP %s @ %llx (%s)\n", handler->token, name, hdr->nodeid,
    526         parent_node ? parent_node->name : "?");
    527     pthread_mutex_unlock(&fuse->lock);
    528 
    529     if (!parent_node || !(actual_name = find_file_within(parent_path, name,
    530             child_path, sizeof(child_path), 1))) {
    531         return -ENOENT;
    532     }
    533     return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
    534 }
    535 
    536 static int handle_forget(struct fuse* fuse, struct fuse_handler* handler,
    537         const struct fuse_in_header *hdr, const struct fuse_forget_in *req)
    538 {
    539     struct node* node;
    540 
    541     pthread_mutex_lock(&fuse->lock);
    542     node = lookup_node_by_id_locked(fuse, hdr->nodeid);
    543     TRACE("[%d] FORGET #%lld @ %llx (%s)\n", handler->token, req->nlookup,
    544             hdr->nodeid, node ? node->name : "?");
    545     if (node) {
    546         __u64 n = req->nlookup;
    547         while (n--) {
    548             release_node_locked(node);
    549         }
    550     }
    551     pthread_mutex_unlock(&fuse->lock);
    552     return NO_STATUS; /* no reply */
    553 }
    554 
    555 static int handle_getattr(struct fuse* fuse, struct fuse_handler* handler,
    556         const struct fuse_in_header *hdr, const struct fuse_getattr_in *req)
    557 {
    558     struct node* node;
    559     char path[PATH_MAX];
    560 
    561     pthread_mutex_lock(&fuse->lock);
    562     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
    563     TRACE("[%d] GETATTR flags=%x fh=%llx @ %llx (%s)\n", handler->token,
    564             req->getattr_flags, req->fh, hdr->nodeid, node ? node->name : "?");
    565     pthread_mutex_unlock(&fuse->lock);
    566 
    567     if (!node) {
    568         return -ENOENT;
    569     }
    570     return fuse_reply_attr(fuse, hdr->unique, hdr->nodeid, path);
    571 }
    572 
    573 static int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
    574         const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
    575 {
    576     struct node* node;
    577     char path[PATH_MAX];
    578     struct timespec times[2];
    579 
    580     pthread_mutex_lock(&fuse->lock);
    581     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
    582     TRACE("[%d] SETATTR fh=%llx valid=%x @ %llx (%s)\n", handler->token,
    583             req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
    584     pthread_mutex_unlock(&fuse->lock);
    585 
    586     if (!node) {
    587         return -ENOENT;
    588     }
    589 
    590     /* XXX: incomplete implementation on purpose.
    591      * chmod/chown should NEVER be implemented.*/
    592 
    593     if ((req->valid & FATTR_SIZE) && truncate(path, req->size) < 0) {
    594         return -errno;
    595     }
    596 
    597     /* Handle changing atime and mtime.  If FATTR_ATIME_and FATTR_ATIME_NOW
    598      * are both set, then set it to the current time.  Else, set it to the
    599      * time specified in the request.  Same goes for mtime.  Use utimensat(2)
    600      * as it allows ATIME and MTIME to be changed independently, and has
    601      * nanosecond resolution which fuse also has.
    602      */
    603     if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
    604         times[0].tv_nsec = UTIME_OMIT;
    605         times[1].tv_nsec = UTIME_OMIT;
    606         if (req->valid & FATTR_ATIME) {
    607             if (req->valid & FATTR_ATIME_NOW) {
    608               times[0].tv_nsec = UTIME_NOW;
    609             } else {
    610               times[0].tv_sec = req->atime;
    611               times[0].tv_nsec = req->atimensec;
    612             }
    613         }
    614         if (req->valid & FATTR_MTIME) {
    615             if (req->valid & FATTR_MTIME_NOW) {
    616               times[1].tv_nsec = UTIME_NOW;
    617             } else {
    618               times[1].tv_sec = req->mtime;
    619               times[1].tv_nsec = req->mtimensec;
    620             }
    621         }
    622         TRACE("[%d] Calling utimensat on %s with atime %ld, mtime=%ld\n",
    623                 handler->token, path, times[0].tv_sec, times[1].tv_sec);
    624         if (utimensat(-1, path, times, 0) < 0) {
    625             return -errno;
    626         }
    627     }
    628     return fuse_reply_attr(fuse, hdr->unique, hdr->nodeid, path);
    629 }
    630 
    631 static int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
    632         const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
    633 {
    634     struct node* parent_node;
    635     char parent_path[PATH_MAX];
    636     char child_path[PATH_MAX];
    637     const char* actual_name;
    638 
    639     pthread_mutex_lock(&fuse->lock);
    640     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
    641             parent_path, sizeof(parent_path));
    642     TRACE("[%d] MKNOD %s 0%o @ %llx (%s)\n", handler->token,
    643             name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
    644     pthread_mutex_unlock(&fuse->lock);
    645 
    646     if (!parent_node || !(actual_name = find_file_within(parent_path, name,
    647             child_path, sizeof(child_path), 1))) {
    648         return -ENOENT;
    649     }
    650     __u32 mode = (req->mode & (~0777)) | 0664;
    651     if (mknod(child_path, mode, req->rdev) < 0) {
    652         return -errno;
    653     }
    654     return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
    655 }
    656 
    657 static int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
    658         const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
    659 {
    660     struct node* parent_node;
    661     char parent_path[PATH_MAX];
    662     char child_path[PATH_MAX];
    663     const char* actual_name;
    664 
    665     pthread_mutex_lock(&fuse->lock);
    666     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
    667             parent_path, sizeof(parent_path));
    668     TRACE("[%d] MKDIR %s 0%o @ %llx (%s)\n", handler->token,
    669             name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
    670     pthread_mutex_unlock(&fuse->lock);
    671 
    672     if (!parent_node || !(actual_name = find_file_within(parent_path, name,
    673             child_path, sizeof(child_path), 1))) {
    674         return -ENOENT;
    675     }
    676     __u32 mode = (req->mode & (~0777)) | 0775;
    677     if (mkdir(child_path, mode) < 0) {
    678         return -errno;
    679     }
    680     return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
    681 }
    682 
    683 static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
    684         const struct fuse_in_header* hdr, const char* name)
    685 {
    686     struct node* parent_node;
    687     char parent_path[PATH_MAX];
    688     char child_path[PATH_MAX];
    689 
    690     pthread_mutex_lock(&fuse->lock);
    691     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
    692             parent_path, sizeof(parent_path));
    693     TRACE("[%d] UNLINK %s @ %llx (%s)\n", handler->token,
    694             name, hdr->nodeid, parent_node ? parent_node->name : "?");
    695     pthread_mutex_unlock(&fuse->lock);
    696 
    697     if (!parent_node || !find_file_within(parent_path, name,
    698             child_path, sizeof(child_path), 1)) {
    699         return -ENOENT;
    700     }
    701     if (unlink(child_path) < 0) {
    702         return -errno;
    703     }
    704     return 0;
    705 }
    706 
    707 static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
    708         const struct fuse_in_header* hdr, const char* name)
    709 {
    710     struct node* parent_node;
    711     char parent_path[PATH_MAX];
    712     char child_path[PATH_MAX];
    713 
    714     pthread_mutex_lock(&fuse->lock);
    715     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
    716             parent_path, sizeof(parent_path));
    717     TRACE("[%d] RMDIR %s @ %llx (%s)\n", handler->token,
    718             name, hdr->nodeid, parent_node ? parent_node->name : "?");
    719     pthread_mutex_unlock(&fuse->lock);
    720 
    721     if (!parent_node || !find_file_within(parent_path, name,
    722             child_path, sizeof(child_path), 1)) {
    723         return -ENOENT;
    724     }
    725     if (rmdir(child_path) < 0) {
    726         return -errno;
    727     }
    728     return 0;
    729 }
    730 
    731 static int handle_rename(struct fuse* fuse, struct fuse_handler* handler,
    732         const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
    733         const char* old_name, const char* new_name)
    734 {
    735     struct node* old_parent_node;
    736     struct node* new_parent_node;
    737     struct node* child_node;
    738     char old_parent_path[PATH_MAX];
    739     char new_parent_path[PATH_MAX];
    740     char old_child_path[PATH_MAX];
    741     char new_child_path[PATH_MAX];
    742     const char* new_actual_name;
    743     int res;
    744 
    745     pthread_mutex_lock(&fuse->lock);
    746     old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
    747             old_parent_path, sizeof(old_parent_path));
    748     new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
    749             new_parent_path, sizeof(new_parent_path));
    750     TRACE("[%d] RENAME %s->%s @ %llx (%s) -> %llx (%s)\n", handler->token,
    751             old_name, new_name,
    752             hdr->nodeid, old_parent_node ? old_parent_node->name : "?",
    753             req->newdir, new_parent_node ? new_parent_node->name : "?");
    754     if (!old_parent_node || !new_parent_node) {
    755         res = -ENOENT;
    756         goto lookup_error;
    757     }
    758     child_node = lookup_child_by_name_locked(old_parent_node, old_name);
    759     if (!child_node || get_node_path_locked(child_node,
    760             old_child_path, sizeof(old_child_path)) < 0) {
    761         res = -ENOENT;
    762         goto lookup_error;
    763     }
    764     acquire_node_locked(child_node);
    765     pthread_mutex_unlock(&fuse->lock);
    766 
    767     /* Special case for renaming a file where destination is same path
    768      * differing only by case.  In this case we don't want to look for a case
    769      * insensitive match.  This allows commands like "mv foo FOO" to work as expected.
    770      */
    771     int search = old_parent_node != new_parent_node
    772             || strcasecmp(old_name, new_name);
    773     if (!(new_actual_name = find_file_within(new_parent_path, new_name,
    774             new_child_path, sizeof(new_child_path), search))) {
    775         res = -ENOENT;
    776         goto io_error;
    777     }
    778 
    779     TRACE("[%d] RENAME %s->%s\n", handler->token, old_child_path, new_child_path);
    780     res = rename(old_child_path, new_child_path);
    781     if (res < 0) {
    782         res = -errno;
    783         goto io_error;
    784     }
    785 
    786     pthread_mutex_lock(&fuse->lock);
    787     res = rename_node_locked(child_node, new_name, new_actual_name);
    788     if (!res) {
    789         remove_node_from_parent_locked(child_node);
    790         add_node_to_parent_locked(child_node, new_parent_node);
    791     }
    792     goto done;
    793 
    794 io_error:
    795     pthread_mutex_lock(&fuse->lock);
    796 done:
    797     release_node_locked(child_node);
    798 lookup_error:
    799     pthread_mutex_unlock(&fuse->lock);
    800     return res;
    801 }
    802 
    803 static int handle_open(struct fuse* fuse, struct fuse_handler* handler,
    804         const struct fuse_in_header* hdr, const struct fuse_open_in* req)
    805 {
    806     struct node* node;
    807     char path[PATH_MAX];
    808     struct fuse_open_out out;
    809     struct handle *h;
    810 
    811     pthread_mutex_lock(&fuse->lock);
    812     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
    813     TRACE("[%d] OPEN 0%o @ %llx (%s)\n", handler->token,
    814             req->flags, hdr->nodeid, node ? node->name : "?");
    815     pthread_mutex_unlock(&fuse->lock);
    816 
    817     if (!node) {
    818         return -ENOENT;
    819     }
    820     h = malloc(sizeof(*h));
    821     if (!h) {
    822         return -ENOMEM;
    823     }
    824     TRACE("[%d] OPEN %s\n", handler->token, path);
    825     h->fd = open(path, req->flags);
    826     if (h->fd < 0) {
    827         free(h);
    828         return -errno;
    829     }
    830     out.fh = ptr_to_id(h);
    831     out.open_flags = 0;
    832     out.padding = 0;
    833     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
    834     return NO_STATUS;
    835 }
    836 
    837 static int handle_read(struct fuse* fuse, struct fuse_handler* handler,
    838         const struct fuse_in_header* hdr, const struct fuse_read_in* req)
    839 {
    840     struct handle *h = id_to_ptr(req->fh);
    841     __u64 unique = hdr->unique;
    842     __u32 size = req->size;
    843     __u64 offset = req->offset;
    844     int res;
    845 
    846     /* Don't access any other fields of hdr or req beyond this point, the read buffer
    847      * overlaps the request buffer and will clobber data in the request.  This
    848      * saves us 128KB per request handler thread at the cost of this scary comment. */
    849 
    850     TRACE("[%d] READ %p(%d) %u@%llu\n", handler->token,
    851             h, h->fd, size, offset);
    852     if (size > sizeof(handler->read_buffer)) {
    853         return -EINVAL;
    854     }
    855     res = pread64(h->fd, handler->read_buffer, size, offset);
    856     if (res < 0) {
    857         return -errno;
    858     }
    859     fuse_reply(fuse, unique, handler->read_buffer, res);
    860     return NO_STATUS;
    861 }
    862 
    863 static int handle_write(struct fuse* fuse, struct fuse_handler* handler,
    864         const struct fuse_in_header* hdr, const struct fuse_write_in* req,
    865         const void* buffer)
    866 {
    867     struct fuse_write_out out;
    868     struct handle *h = id_to_ptr(req->fh);
    869     int res;
    870 
    871     TRACE("[%d] WRITE %p(%d) %u@%llu\n", handler->token,
    872             h, h->fd, req->size, req->offset);
    873     res = pwrite64(h->fd, buffer, req->size, req->offset);
    874     if (res < 0) {
    875         return -errno;
    876     }
    877     out.size = res;
    878     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
    879     return NO_STATUS;
    880 }
    881 
    882 static int handle_statfs(struct fuse* fuse, struct fuse_handler* handler,
    883         const struct fuse_in_header* hdr)
    884 {
    885     char path[PATH_MAX];
    886     struct statfs stat;
    887     struct fuse_statfs_out out;
    888     int res;
    889 
    890     pthread_mutex_lock(&fuse->lock);
    891     TRACE("[%d] STATFS\n", handler->token);
    892     res = get_node_path_locked(&fuse->root, path, sizeof(path));
    893     pthread_mutex_unlock(&fuse->lock);
    894     if (res < 0) {
    895         return -ENOENT;
    896     }
    897     if (statfs(fuse->root.name, &stat) < 0) {
    898         return -errno;
    899     }
    900     memset(&out, 0, sizeof(out));
    901     out.st.blocks = stat.f_blocks;
    902     out.st.bfree = stat.f_bfree;
    903     out.st.bavail = stat.f_bavail;
    904     out.st.files = stat.f_files;
    905     out.st.ffree = stat.f_ffree;
    906     out.st.bsize = stat.f_bsize;
    907     out.st.namelen = stat.f_namelen;
    908     out.st.frsize = stat.f_frsize;
    909     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
    910     return NO_STATUS;
    911 }
    912 
    913 static int handle_release(struct fuse* fuse, struct fuse_handler* handler,
    914         const struct fuse_in_header* hdr, const struct fuse_release_in* req)
    915 {
    916     struct handle *h = id_to_ptr(req->fh);
    917 
    918     TRACE("[%d] RELEASE %p(%d)\n", handler->token, h, h->fd);
    919     close(h->fd);
    920     free(h);
    921     return 0;
    922 }
    923 
    924 static int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
    925         const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
    926 {
    927     int is_data_sync = req->fsync_flags & 1;
    928     struct handle *h = id_to_ptr(req->fh);
    929     int res;
    930 
    931     TRACE("[%d] FSYNC %p(%d) is_data_sync=%d\n", handler->token,
    932             h, h->fd, is_data_sync);
    933     res = is_data_sync ? fdatasync(h->fd) : fsync(h->fd);
    934     if (res < 0) {
    935         return -errno;
    936     }
    937     return 0;
    938 }
    939 
    940 static int handle_flush(struct fuse* fuse, struct fuse_handler* handler,
    941         const struct fuse_in_header* hdr)
    942 {
    943     TRACE("[%d] FLUSH\n", handler->token);
    944     return 0;
    945 }
    946 
    947 static int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
    948         const struct fuse_in_header* hdr, const struct fuse_open_in* req)
    949 {
    950     struct node* node;
    951     char path[PATH_MAX];
    952     struct fuse_open_out out;
    953     struct dirhandle *h;
    954 
    955     pthread_mutex_lock(&fuse->lock);
    956     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
    957     TRACE("[%d] OPENDIR @ %llx (%s)\n", handler->token,
    958             hdr->nodeid, node ? node->name : "?");
    959     pthread_mutex_unlock(&fuse->lock);
    960 
    961     if (!node) {
    962         return -ENOENT;
    963     }
    964     h = malloc(sizeof(*h));
    965     if (!h) {
    966         return -ENOMEM;
    967     }
    968     TRACE("[%d] OPENDIR %s\n", handler->token, path);
    969     h->d = opendir(path);
    970     if (!h->d) {
    971         free(h);
    972         return -errno;
    973     }
    974     out.fh = ptr_to_id(h);
    975     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
    976     return NO_STATUS;
    977 }
    978 
    979 static int handle_readdir(struct fuse* fuse, struct fuse_handler* handler,
    980         const struct fuse_in_header* hdr, const struct fuse_read_in* req)
    981 {
    982     char buffer[8192];
    983     struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
    984     struct dirent *de;
    985     struct dirhandle *h = id_to_ptr(req->fh);
    986 
    987     TRACE("[%d] READDIR %p\n", handler->token, h);
    988     if (req->offset == 0) {
    989         /* rewinddir() might have been called above us, so rewind here too */
    990         TRACE("[%d] calling rewinddir()\n", handler->token);
    991         rewinddir(h->d);
    992     }
    993     de = readdir(h->d);
    994     if (!de) {
    995         return 0;
    996     }
    997     fde->ino = FUSE_UNKNOWN_INO;
    998     /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
    999     fde->off = req->offset + 1;
   1000     fde->type = de->d_type;
   1001     fde->namelen = strlen(de->d_name);
   1002     memcpy(fde->name, de->d_name, fde->namelen + 1);
   1003     fuse_reply(fuse, hdr->unique, fde,
   1004             FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
   1005     return NO_STATUS;
   1006 }
   1007 
   1008 static int handle_releasedir(struct fuse* fuse, struct fuse_handler* handler,
   1009         const struct fuse_in_header* hdr, const struct fuse_release_in* req)
   1010 {
   1011     struct dirhandle *h = id_to_ptr(req->fh);
   1012 
   1013     TRACE("[%d] RELEASEDIR %p\n", handler->token, h);
   1014     closedir(h->d);
   1015     free(h);
   1016     return 0;
   1017 }
   1018 
   1019 static int handle_init(struct fuse* fuse, struct fuse_handler* handler,
   1020         const struct fuse_in_header* hdr, const struct fuse_init_in* req)
   1021 {
   1022     struct fuse_init_out out;
   1023 
   1024     TRACE("[%d] INIT ver=%d.%d maxread=%d flags=%x\n",
   1025             handler->token, req->major, req->minor, req->max_readahead, req->flags);
   1026     out.major = FUSE_KERNEL_VERSION;
   1027     out.minor = FUSE_KERNEL_MINOR_VERSION;
   1028     out.max_readahead = req->max_readahead;
   1029     out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
   1030     out.max_background = 32;
   1031     out.congestion_threshold = 32;
   1032     out.max_write = MAX_WRITE;
   1033     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
   1034     return NO_STATUS;
   1035 }
   1036 
   1037 static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
   1038         const struct fuse_in_header *hdr, const void *data, size_t data_len)
   1039 {
   1040     switch (hdr->opcode) {
   1041     case FUSE_LOOKUP: { /* bytez[] -> entry_out */
   1042         const char* name = data;
   1043         return handle_lookup(fuse, handler, hdr, name);
   1044     }
   1045 
   1046     case FUSE_FORGET: {
   1047         const struct fuse_forget_in *req = data;
   1048         return handle_forget(fuse, handler, hdr, req);
   1049     }
   1050 
   1051     case FUSE_GETATTR: { /* getattr_in -> attr_out */
   1052         const struct fuse_getattr_in *req = data;
   1053         return handle_getattr(fuse, handler, hdr, req);
   1054     }
   1055 
   1056     case FUSE_SETATTR: { /* setattr_in -> attr_out */
   1057         const struct fuse_setattr_in *req = data;
   1058         return handle_setattr(fuse, handler, hdr, req);
   1059     }
   1060 
   1061 //    case FUSE_READLINK:
   1062 //    case FUSE_SYMLINK:
   1063     case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
   1064         const struct fuse_mknod_in *req = data;
   1065         const char *name = ((const char*) data) + sizeof(*req);
   1066         return handle_mknod(fuse, handler, hdr, req, name);
   1067     }
   1068 
   1069     case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
   1070         const struct fuse_mkdir_in *req = data;
   1071         const char *name = ((const char*) data) + sizeof(*req);
   1072         return handle_mkdir(fuse, handler, hdr, req, name);
   1073     }
   1074 
   1075     case FUSE_UNLINK: { /* bytez[] -> */
   1076         const char* name = data;
   1077         return handle_unlink(fuse, handler, hdr, name);
   1078     }
   1079 
   1080     case FUSE_RMDIR: { /* bytez[] -> */
   1081         const char* name = data;
   1082         return handle_rmdir(fuse, handler, hdr, name);
   1083     }
   1084 
   1085     case FUSE_RENAME: { /* rename_in, oldname, newname ->  */
   1086         const struct fuse_rename_in *req = data;
   1087         const char *old_name = ((const char*) data) + sizeof(*req);
   1088         const char *new_name = old_name + strlen(old_name) + 1;
   1089         return handle_rename(fuse, handler, hdr, req, old_name, new_name);
   1090     }
   1091 
   1092 //    case FUSE_LINK:
   1093     case FUSE_OPEN: { /* open_in -> open_out */
   1094         const struct fuse_open_in *req = data;
   1095         return handle_open(fuse, handler, hdr, req);
   1096     }
   1097 
   1098     case FUSE_READ: { /* read_in -> byte[] */
   1099         const struct fuse_read_in *req = data;
   1100         return handle_read(fuse, handler, hdr, req);
   1101     }
   1102 
   1103     case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
   1104         const struct fuse_write_in *req = data;
   1105         const void* buffer = (const __u8*)data + sizeof(*req);
   1106         return handle_write(fuse, handler, hdr, req, buffer);
   1107     }
   1108 
   1109     case FUSE_STATFS: { /* getattr_in -> attr_out */
   1110         return handle_statfs(fuse, handler, hdr);
   1111     }
   1112 
   1113     case FUSE_RELEASE: { /* release_in -> */
   1114         const struct fuse_release_in *req = data;
   1115         return handle_release(fuse, handler, hdr, req);
   1116     }
   1117 
   1118     case FUSE_FSYNC: {
   1119         const struct fuse_fsync_in *req = data;
   1120         return handle_fsync(fuse, handler, hdr, req);
   1121     }
   1122 
   1123 //    case FUSE_SETXATTR:
   1124 //    case FUSE_GETXATTR:
   1125 //    case FUSE_LISTXATTR:
   1126 //    case FUSE_REMOVEXATTR:
   1127     case FUSE_FLUSH: {
   1128         return handle_flush(fuse, handler, hdr);
   1129     }
   1130 
   1131     case FUSE_OPENDIR: { /* open_in -> open_out */
   1132         const struct fuse_open_in *req = data;
   1133         return handle_opendir(fuse, handler, hdr, req);
   1134     }
   1135 
   1136     case FUSE_READDIR: {
   1137         const struct fuse_read_in *req = data;
   1138         return handle_readdir(fuse, handler, hdr, req);
   1139     }
   1140 
   1141     case FUSE_RELEASEDIR: { /* release_in -> */
   1142         const struct fuse_release_in *req = data;
   1143         return handle_releasedir(fuse, handler, hdr, req);
   1144     }
   1145 
   1146 //    case FUSE_FSYNCDIR:
   1147     case FUSE_INIT: { /* init_in -> init_out */
   1148         const struct fuse_init_in *req = data;
   1149         return handle_init(fuse, handler, hdr, req);
   1150     }
   1151 
   1152     default: {
   1153         TRACE("[%d] NOTIMPL op=%d uniq=%llx nid=%llx\n",
   1154                 handler->token, hdr->opcode, hdr->unique, hdr->nodeid);
   1155         return -ENOSYS;
   1156     }
   1157     }
   1158 }
   1159 
   1160 static void handle_fuse_requests(struct fuse_handler* handler)
   1161 {
   1162     struct fuse* fuse = handler->fuse;
   1163     for (;;) {
   1164         ssize_t len = read(fuse->fd,
   1165                 handler->request_buffer, sizeof(handler->request_buffer));
   1166         if (len < 0) {
   1167             if (errno != EINTR) {
   1168                 ERROR("[%d] handle_fuse_requests: errno=%d\n", handler->token, errno);
   1169             }
   1170             continue;
   1171         }
   1172 
   1173         if ((size_t)len < sizeof(struct fuse_in_header)) {
   1174             ERROR("[%d] request too short: len=%zu\n", handler->token, (size_t)len);
   1175             continue;
   1176         }
   1177 
   1178         const struct fuse_in_header *hdr = (void*)handler->request_buffer;
   1179         if (hdr->len != (size_t)len) {
   1180             ERROR("[%d] malformed header: len=%zu, hdr->len=%u\n",
   1181                     handler->token, (size_t)len, hdr->len);
   1182             continue;
   1183         }
   1184 
   1185         const void *data = handler->request_buffer + sizeof(struct fuse_in_header);
   1186         size_t data_len = len - sizeof(struct fuse_in_header);
   1187         __u64 unique = hdr->unique;
   1188         int res = handle_fuse_request(fuse, handler, hdr, data, data_len);
   1189 
   1190         /* We do not access the request again after this point because the underlying
   1191          * buffer storage may have been reused while processing the request. */
   1192 
   1193         if (res != NO_STATUS) {
   1194             if (res) {
   1195                 TRACE("[%d] ERROR %d\n", handler->token, res);
   1196             }
   1197             fuse_status(fuse, unique, res);
   1198         }
   1199     }
   1200 }
   1201 
   1202 static void* start_handler(void* data)
   1203 {
   1204     struct fuse_handler* handler = data;
   1205     handle_fuse_requests(handler);
   1206     return NULL;
   1207 }
   1208 
   1209 static int ignite_fuse(struct fuse* fuse, int num_threads)
   1210 {
   1211     struct fuse_handler* handlers;
   1212     int i;
   1213 
   1214     handlers = malloc(num_threads * sizeof(struct fuse_handler));
   1215     if (!handlers) {
   1216         ERROR("cannot allocate storage for threads");
   1217         return -ENOMEM;
   1218     }
   1219 
   1220     for (i = 0; i < num_threads; i++) {
   1221         handlers[i].fuse = fuse;
   1222         handlers[i].token = i;
   1223     }
   1224 
   1225     for (i = 1; i < num_threads; i++) {
   1226         pthread_t thread;
   1227         int res = pthread_create(&thread, NULL, start_handler, &handlers[i]);
   1228         if (res) {
   1229             ERROR("failed to start thread #%d, error=%d", i, res);
   1230             goto quit;
   1231         }
   1232     }
   1233     handle_fuse_requests(&handlers[0]);
   1234     ERROR("terminated prematurely");
   1235 
   1236     /* don't bother killing all of the other threads or freeing anything,
   1237      * should never get here anyhow */
   1238 quit:
   1239     exit(1);
   1240 }
   1241 
   1242 static int usage()
   1243 {
   1244     ERROR("usage: sdcard [-t<threads>] <source_path> <dest_path> <uid> <gid>\n"
   1245             "    -t<threads>: specify number of threads to use, default -t%d\n"
   1246             "\n", DEFAULT_NUM_THREADS);
   1247     return 1;
   1248 }
   1249 
   1250 static int run(const char* source_path, const char* dest_path, uid_t uid, gid_t gid,
   1251         int num_threads) {
   1252     int fd;
   1253     char opts[256];
   1254     int res;
   1255     struct fuse fuse;
   1256 
   1257     /* cleanup from previous instance, if necessary */
   1258     umount2(dest_path, 2);
   1259 
   1260     fd = open("/dev/fuse", O_RDWR);
   1261     if (fd < 0){
   1262         ERROR("cannot open fuse device (error %d)\n", errno);
   1263         return -1;
   1264     }
   1265 
   1266     snprintf(opts, sizeof(opts),
   1267             "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
   1268             fd, uid, gid);
   1269 
   1270     res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV, opts);
   1271     if (res < 0) {
   1272         ERROR("cannot mount fuse filesystem (error %d)\n", errno);
   1273         goto error;
   1274     }
   1275 
   1276     res = setgid(gid);
   1277     if (res < 0) {
   1278         ERROR("cannot setgid (error %d)\n", errno);
   1279         goto error;
   1280     }
   1281 
   1282     res = setuid(uid);
   1283     if (res < 0) {
   1284         ERROR("cannot setuid (error %d)\n", errno);
   1285         goto error;
   1286     }
   1287 
   1288     fuse_init(&fuse, fd, source_path);
   1289 
   1290     umask(0);
   1291     res = ignite_fuse(&fuse, num_threads);
   1292 
   1293     /* we do not attempt to umount the file system here because we are no longer
   1294      * running as the root user */
   1295 
   1296 error:
   1297     close(fd);
   1298     return res;
   1299 }
   1300 
   1301 int main(int argc, char **argv)
   1302 {
   1303     int res;
   1304     const char *source_path = NULL;
   1305     const char *dest_path = NULL;
   1306     uid_t uid = 0;
   1307     gid_t gid = 0;
   1308     int num_threads = DEFAULT_NUM_THREADS;
   1309     int i;
   1310     struct rlimit rlim;
   1311 
   1312     for (i = 1; i < argc; i++) {
   1313         char* arg = argv[i];
   1314         if (!strncmp(arg, "-t", 2))
   1315             num_threads = strtoul(arg + 2, 0, 10);
   1316         else if (!source_path)
   1317             source_path = arg;
   1318         else if (!dest_path)
   1319             dest_path = arg;
   1320         else if (!uid) {
   1321             char* endptr = NULL;
   1322             errno = 0;
   1323             uid = strtoul(arg, &endptr, 10);
   1324             if (*endptr != '\0' || errno != 0) {
   1325                 ERROR("Invalid uid");
   1326                 return usage();
   1327             }
   1328         } else if (!gid) {
   1329             char* endptr = NULL;
   1330             errno = 0;
   1331             gid = strtoul(arg, &endptr, 10);
   1332             if (*endptr != '\0' || errno != 0) {
   1333                 ERROR("Invalid gid");
   1334                 return usage();
   1335             }
   1336         } else {
   1337             ERROR("too many arguments\n");
   1338             return usage();
   1339         }
   1340     }
   1341 
   1342     if (!source_path) {
   1343         ERROR("no source path specified\n");
   1344         return usage();
   1345     }
   1346     if (!dest_path) {
   1347         ERROR("no dest path specified\n");
   1348         return usage();
   1349     }
   1350     if (!uid || !gid) {
   1351         ERROR("uid and gid must be nonzero\n");
   1352         return usage();
   1353     }
   1354     if (num_threads < 1) {
   1355         ERROR("number of threads must be at least 1\n");
   1356         return usage();
   1357     }
   1358 
   1359     rlim.rlim_cur = 8192;
   1360     rlim.rlim_max = 8192;
   1361     if (setrlimit(RLIMIT_NOFILE, &rlim)) {
   1362         ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno);
   1363     }
   1364 
   1365     res = run(source_path, dest_path, uid, gid, num_threads);
   1366     return res < 0 ? 1 : 0;
   1367 }
   1368