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 #include <sys/inotify.h>
     34 
     35 #include <cutils/fs.h>
     36 #include <cutils/hashmap.h>
     37 #include <cutils/multiuser.h>
     38 
     39 #include <private/android_filesystem_config.h>
     40 
     41 #include "fuse.h"
     42 
     43 /* README
     44  *
     45  * What is this?
     46  *
     47  * sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
     48  * directory permissions (all files are given fixed owner, group, and
     49  * permissions at creation, owner, group, and permissions are not
     50  * changeable, symlinks and hardlinks are not createable, etc.
     51  *
     52  * See usage() for command line options.
     53  *
     54  * It must be run as root, but will drop to requested UID/GID as soon as it
     55  * mounts a filesystem.  It will refuse to run if requested UID/GID are zero.
     56  *
     57  * Things I believe to be true:
     58  *
     59  * - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK,
     60  * CREAT) must bump that node's refcount
     61  * - don't forget that FORGET can forget multiple references (req->nlookup)
     62  * - if an op that returns a fuse_entry fails writing the reply to the
     63  * kernel, you must rollback the refcount to reflect the reference the
     64  * kernel did not actually acquire
     65  *
     66  * This daemon can also derive custom filesystem permissions based on directory
     67  * structure when requested. These custom permissions support several features:
     68  *
     69  * - Apps can access their own files in /Android/data/com.example/ without
     70  * requiring any additional GIDs.
     71  * - Separate permissions for protecting directories like Pictures and Music.
     72  * - Multi-user separation on the same physical device.
     73  *
     74  * The derived permissions look like this:
     75  *
     76  * rwxrwx--x root:sdcard_rw     /
     77  * rwxrwx--- root:sdcard_pics   /Pictures
     78  * rwxrwx--- root:sdcard_av     /Music
     79  *
     80  * rwxrwx--x root:sdcard_rw     /Android
     81  * rwxrwx--x root:sdcard_rw     /Android/data
     82  * rwxrwx--- u0_a12:sdcard_rw   /Android/data/com.example
     83  * rwxrwx--x root:sdcard_rw     /Android/obb/
     84  * rwxrwx--- u0_a12:sdcard_rw   /Android/obb/com.example
     85  *
     86  * rwxrwx--- root:sdcard_all    /Android/user
     87  * rwxrwx--x root:sdcard_rw     /Android/user/10
     88  * rwxrwx--- u10_a12:sdcard_rw  /Android/user/10/Android/data/com.example
     89  */
     90 
     91 #define FUSE_TRACE 0
     92 
     93 #if FUSE_TRACE
     94 #define TRACE(x...) fprintf(stderr,x)
     95 #else
     96 #define TRACE(x...) do {} while (0)
     97 #endif
     98 
     99 #define ERROR(x...) fprintf(stderr,x)
    100 
    101 #define FUSE_UNKNOWN_INO 0xffffffff
    102 
    103 /* Maximum number of bytes to write in one request. */
    104 #define MAX_WRITE (256 * 1024)
    105 
    106 /* Maximum number of bytes to read in one request. */
    107 #define MAX_READ (128 * 1024)
    108 
    109 /* Largest possible request.
    110  * The request size is bounded by the maximum size of a FUSE_WRITE request because it has
    111  * the largest possible data payload. */
    112 #define MAX_REQUEST_SIZE (sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE)
    113 
    114 /* Default number of threads. */
    115 #define DEFAULT_NUM_THREADS 2
    116 
    117 /* Pseudo-error constant used to indicate that no fuse status is needed
    118  * or that a reply has already been written. */
    119 #define NO_STATUS 1
    120 
    121 /* Path to system-provided mapping of package name to appIds */
    122 static const char* const kPackagesListFile = "/data/system/packages.list";
    123 
    124 /* Supplementary groups to execute with */
    125 static const gid_t kGroups[1] = { AID_PACKAGE_INFO };
    126 
    127 /* Permission mode for a specific node. Controls how file permissions
    128  * are derived for children nodes. */
    129 typedef enum {
    130     /* Nothing special; this node should just inherit from its parent. */
    131     PERM_INHERIT,
    132     /* This node is one level above a normal root; used for legacy layouts
    133      * which use the first level to represent user_id. */
    134     PERM_LEGACY_PRE_ROOT,
    135     /* This node is "/" */
    136     PERM_ROOT,
    137     /* This node is "/Android" */
    138     PERM_ANDROID,
    139     /* This node is "/Android/data" */
    140     PERM_ANDROID_DATA,
    141     /* This node is "/Android/obb" */
    142     PERM_ANDROID_OBB,
    143     /* This node is "/Android/user" */
    144     PERM_ANDROID_USER,
    145 } perm_t;
    146 
    147 /* Permissions structure to derive */
    148 typedef enum {
    149     DERIVE_NONE,
    150     DERIVE_LEGACY,
    151     DERIVE_UNIFIED,
    152 } derive_t;
    153 
    154 struct handle {
    155     int fd;
    156 };
    157 
    158 struct dirhandle {
    159     DIR *d;
    160 };
    161 
    162 struct node {
    163     __u32 refcount;
    164     __u64 nid;
    165     __u64 gen;
    166 
    167     /* State derived based on current position in hierarchy. */
    168     perm_t perm;
    169     userid_t userid;
    170     uid_t uid;
    171     gid_t gid;
    172     mode_t mode;
    173 
    174     struct node *next;          /* per-dir sibling list */
    175     struct node *child;         /* first contained file by this dir */
    176     struct node *parent;        /* containing directory */
    177 
    178     size_t namelen;
    179     char *name;
    180     /* If non-null, this is the real name of the file in the underlying storage.
    181      * This may differ from the field "name" only by case.
    182      * strlen(actual_name) will always equal strlen(name), so it is safe to use
    183      * namelen for both fields.
    184      */
    185     char *actual_name;
    186 
    187     /* If non-null, an exact underlying path that should be grafted into this
    188      * position. Used to support things like OBB. */
    189     char* graft_path;
    190     size_t graft_pathlen;
    191 };
    192 
    193 static int str_hash(void *key) {
    194     return hashmapHash(key, strlen(key));
    195 }
    196 
    197 /** Test if two string keys are equal ignoring case */
    198 static bool str_icase_equals(void *keyA, void *keyB) {
    199     return strcasecmp(keyA, keyB) == 0;
    200 }
    201 
    202 static int int_hash(void *key) {
    203     return (int) key;
    204 }
    205 
    206 static bool int_equals(void *keyA, void *keyB) {
    207     return keyA == keyB;
    208 }
    209 
    210 /* Global data structure shared by all fuse handlers. */
    211 struct fuse {
    212     pthread_mutex_t lock;
    213 
    214     __u64 next_generation;
    215     int fd;
    216     derive_t derive;
    217     bool split_perms;
    218     gid_t write_gid;
    219     struct node root;
    220     char obbpath[PATH_MAX];
    221 
    222     Hashmap* package_to_appid;
    223     Hashmap* appid_with_rw;
    224 };
    225 
    226 /* Private data used by a single fuse handler. */
    227 struct fuse_handler {
    228     struct fuse* fuse;
    229     int token;
    230 
    231     /* To save memory, we never use the contents of the request buffer and the read
    232      * buffer at the same time.  This allows us to share the underlying storage. */
    233     union {
    234         __u8 request_buffer[MAX_REQUEST_SIZE];
    235         __u8 read_buffer[MAX_READ];
    236     };
    237 };
    238 
    239 static inline void *id_to_ptr(__u64 nid)
    240 {
    241     return (void *) (uintptr_t) nid;
    242 }
    243 
    244 static inline __u64 ptr_to_id(void *ptr)
    245 {
    246     return (__u64) (uintptr_t) ptr;
    247 }
    248 
    249 static void acquire_node_locked(struct node* node)
    250 {
    251     node->refcount++;
    252     TRACE("ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount);
    253 }
    254 
    255 static void remove_node_from_parent_locked(struct node* node);
    256 
    257 static void release_node_locked(struct node* node)
    258 {
    259     TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount);
    260     if (node->refcount > 0) {
    261         node->refcount--;
    262         if (!node->refcount) {
    263             TRACE("DESTROY %p (%s)\n", node, node->name);
    264             remove_node_from_parent_locked(node);
    265 
    266                 /* TODO: remove debugging - poison memory */
    267             memset(node->name, 0xef, node->namelen);
    268             free(node->name);
    269             free(node->actual_name);
    270             memset(node, 0xfc, sizeof(*node));
    271             free(node);
    272         }
    273     } else {
    274         ERROR("Zero refcnt %p\n", node);
    275     }
    276 }
    277 
    278 static void add_node_to_parent_locked(struct node *node, struct node *parent) {
    279     node->parent = parent;
    280     node->next = parent->child;
    281     parent->child = node;
    282     acquire_node_locked(parent);
    283 }
    284 
    285 static void remove_node_from_parent_locked(struct node* node)
    286 {
    287     if (node->parent) {
    288         if (node->parent->child == node) {
    289             node->parent->child = node->parent->child->next;
    290         } else {
    291             struct node *node2;
    292             node2 = node->parent->child;
    293             while (node2->next != node)
    294                 node2 = node2->next;
    295             node2->next = node->next;
    296         }
    297         release_node_locked(node->parent);
    298         node->parent = NULL;
    299         node->next = NULL;
    300     }
    301 }
    302 
    303 /* Gets the absolute path to a node into the provided buffer.
    304  *
    305  * Populates 'buf' with the path and returns the length of the path on success,
    306  * or returns -1 if the path is too long for the provided buffer.
    307  */
    308 static ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize) {
    309     const char* name;
    310     size_t namelen;
    311     if (node->graft_path) {
    312         name = node->graft_path;
    313         namelen = node->graft_pathlen;
    314     } else if (node->actual_name) {
    315         name = node->actual_name;
    316         namelen = node->namelen;
    317     } else {
    318         name = node->name;
    319         namelen = node->namelen;
    320     }
    321 
    322     if (bufsize < namelen + 1) {
    323         return -1;
    324     }
    325 
    326     ssize_t pathlen = 0;
    327     if (node->parent && node->graft_path == NULL) {
    328         pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 2);
    329         if (pathlen < 0) {
    330             return -1;
    331         }
    332         buf[pathlen++] = '/';
    333     }
    334 
    335     memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
    336     return pathlen + namelen;
    337 }
    338 
    339 /* Finds the absolute path of a file within a given directory.
    340  * Performs a case-insensitive search for the file and sets the buffer to the path
    341  * of the first matching file.  If 'search' is zero or if no match is found, sets
    342  * the buffer to the path that the file would have, assuming the name were case-sensitive.
    343  *
    344  * Populates 'buf' with the path and returns the actual name (within 'buf') on success,
    345  * or returns NULL if the path is too long for the provided buffer.
    346  */
    347 static char* find_file_within(const char* path, const char* name,
    348         char* buf, size_t bufsize, int search)
    349 {
    350     size_t pathlen = strlen(path);
    351     size_t namelen = strlen(name);
    352     size_t childlen = pathlen + namelen + 1;
    353     char* actual;
    354 
    355     if (bufsize <= childlen) {
    356         return NULL;
    357     }
    358 
    359     memcpy(buf, path, pathlen);
    360     buf[pathlen] = '/';
    361     actual = buf + pathlen + 1;
    362     memcpy(actual, name, namelen + 1);
    363 
    364     if (search && access(buf, F_OK)) {
    365         struct dirent* entry;
    366         DIR* dir = opendir(path);
    367         if (!dir) {
    368             ERROR("opendir %s failed: %s\n", path, strerror(errno));
    369             return actual;
    370         }
    371         while ((entry = readdir(dir))) {
    372             if (!strcasecmp(entry->d_name, name)) {
    373                 /* we have a match - replace the name, don't need to copy the null again */
    374                 memcpy(actual, entry->d_name, namelen);
    375                 break;
    376             }
    377         }
    378         closedir(dir);
    379     }
    380     return actual;
    381 }
    382 
    383 static void attr_from_stat(struct fuse_attr *attr, const struct stat *s, const struct node* node)
    384 {
    385     attr->ino = node->nid;
    386     attr->size = s->st_size;
    387     attr->blocks = s->st_blocks;
    388     attr->atime = s->st_atime;
    389     attr->mtime = s->st_mtime;
    390     attr->ctime = s->st_ctime;
    391     attr->atimensec = s->st_atime_nsec;
    392     attr->mtimensec = s->st_mtime_nsec;
    393     attr->ctimensec = s->st_ctime_nsec;
    394     attr->mode = s->st_mode;
    395     attr->nlink = s->st_nlink;
    396 
    397     attr->uid = node->uid;
    398     attr->gid = node->gid;
    399 
    400     /* Filter requested mode based on underlying file, and
    401      * pass through file type. */
    402     int owner_mode = s->st_mode & 0700;
    403     int filtered_mode = node->mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
    404     attr->mode = (attr->mode & S_IFMT) | filtered_mode;
    405 }
    406 
    407 static int touch(char* path, mode_t mode) {
    408     int fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, mode);
    409     if (fd == -1) {
    410         if (errno == EEXIST) {
    411             return 0;
    412         } else {
    413             ERROR("Failed to open(%s): %s\n", path, strerror(errno));
    414             return -1;
    415         }
    416     }
    417     close(fd);
    418     return 0;
    419 }
    420 
    421 static void derive_permissions_locked(struct fuse* fuse, struct node *parent,
    422         struct node *node) {
    423     appid_t appid;
    424 
    425     /* By default, each node inherits from its parent */
    426     node->perm = PERM_INHERIT;
    427     node->userid = parent->userid;
    428     node->uid = parent->uid;
    429     node->gid = parent->gid;
    430     node->mode = parent->mode;
    431 
    432     if (fuse->derive == DERIVE_NONE) {
    433         return;
    434     }
    435 
    436     /* Derive custom permissions based on parent and current node */
    437     switch (parent->perm) {
    438     case PERM_INHERIT:
    439         /* Already inherited above */
    440         break;
    441     case PERM_LEGACY_PRE_ROOT:
    442         /* Legacy internal layout places users at top level */
    443         node->perm = PERM_ROOT;
    444         node->userid = strtoul(node->name, NULL, 10);
    445         break;
    446     case PERM_ROOT:
    447         /* Assume masked off by default. */
    448         node->mode = 0770;
    449         if (!strcasecmp(node->name, "Android")) {
    450             /* App-specific directories inside; let anyone traverse */
    451             node->perm = PERM_ANDROID;
    452             node->mode = 0771;
    453         } else if (fuse->split_perms) {
    454             if (!strcasecmp(node->name, "DCIM")
    455                     || !strcasecmp(node->name, "Pictures")) {
    456                 node->gid = AID_SDCARD_PICS;
    457             } else if (!strcasecmp(node->name, "Alarms")
    458                     || !strcasecmp(node->name, "Movies")
    459                     || !strcasecmp(node->name, "Music")
    460                     || !strcasecmp(node->name, "Notifications")
    461                     || !strcasecmp(node->name, "Podcasts")
    462                     || !strcasecmp(node->name, "Ringtones")) {
    463                 node->gid = AID_SDCARD_AV;
    464             }
    465         }
    466         break;
    467     case PERM_ANDROID:
    468         if (!strcasecmp(node->name, "data")) {
    469             /* App-specific directories inside; let anyone traverse */
    470             node->perm = PERM_ANDROID_DATA;
    471             node->mode = 0771;
    472         } else if (!strcasecmp(node->name, "obb")) {
    473             /* App-specific directories inside; let anyone traverse */
    474             node->perm = PERM_ANDROID_OBB;
    475             node->mode = 0771;
    476             /* Single OBB directory is always shared */
    477             node->graft_path = fuse->obbpath;
    478             node->graft_pathlen = strlen(fuse->obbpath);
    479         } else if (!strcasecmp(node->name, "user")) {
    480             /* User directories must only be accessible to system, protected
    481              * by sdcard_all. Zygote will bind mount the appropriate user-
    482              * specific path. */
    483             node->perm = PERM_ANDROID_USER;
    484             node->gid = AID_SDCARD_ALL;
    485             node->mode = 0770;
    486         }
    487         break;
    488     case PERM_ANDROID_DATA:
    489     case PERM_ANDROID_OBB:
    490         appid = (appid_t) hashmapGet(fuse->package_to_appid, node->name);
    491         if (appid != 0) {
    492             node->uid = multiuser_get_uid(parent->userid, appid);
    493         }
    494         node->mode = 0770;
    495         break;
    496     case PERM_ANDROID_USER:
    497         /* Root of a secondary user */
    498         node->perm = PERM_ROOT;
    499         node->userid = strtoul(node->name, NULL, 10);
    500         node->gid = AID_SDCARD_R;
    501         node->mode = 0771;
    502         break;
    503     }
    504 }
    505 
    506 /* Return if the calling UID holds sdcard_rw. */
    507 static bool get_caller_has_rw_locked(struct fuse* fuse, const struct fuse_in_header *hdr) {
    508     /* No additional permissions enforcement */
    509     if (fuse->derive == DERIVE_NONE) {
    510         return true;
    511     }
    512 
    513     appid_t appid = multiuser_get_app_id(hdr->uid);
    514     return hashmapContainsKey(fuse->appid_with_rw, (void*) appid);
    515 }
    516 
    517 /* Kernel has already enforced everything we returned through
    518  * derive_permissions_locked(), so this is used to lock down access
    519  * even further, such as enforcing that apps hold sdcard_rw. */
    520 static bool check_caller_access_to_name(struct fuse* fuse,
    521         const struct fuse_in_header *hdr, const struct node* parent_node,
    522         const char* name, int mode, bool has_rw) {
    523     /* Always block security-sensitive files at root */
    524     if (parent_node && parent_node->perm == PERM_ROOT) {
    525         if (!strcasecmp(name, "autorun.inf")
    526                 || !strcasecmp(name, ".android_secure")
    527                 || !strcasecmp(name, "android_secure")) {
    528             return false;
    529         }
    530     }
    531 
    532     /* No additional permissions enforcement */
    533     if (fuse->derive == DERIVE_NONE) {
    534         return true;
    535     }
    536 
    537     /* Root always has access; access for any other UIDs should always
    538      * be controlled through packages.list. */
    539     if (hdr->uid == 0) {
    540         return true;
    541     }
    542 
    543     /* If asking to write, verify that caller either owns the
    544      * parent or holds sdcard_rw. */
    545     if (mode & W_OK) {
    546         if (parent_node && hdr->uid == parent_node->uid) {
    547             return true;
    548         }
    549 
    550         return has_rw;
    551     }
    552 
    553     /* No extra permissions to enforce */
    554     return true;
    555 }
    556 
    557 static bool check_caller_access_to_node(struct fuse* fuse,
    558         const struct fuse_in_header *hdr, const struct node* node, int mode, bool has_rw) {
    559     return check_caller_access_to_name(fuse, hdr, node->parent, node->name, mode, has_rw);
    560 }
    561 
    562 struct node *create_node_locked(struct fuse* fuse,
    563         struct node *parent, const char *name, const char* actual_name)
    564 {
    565     struct node *node;
    566     size_t namelen = strlen(name);
    567 
    568     node = calloc(1, sizeof(struct node));
    569     if (!node) {
    570         return NULL;
    571     }
    572     node->name = malloc(namelen + 1);
    573     if (!node->name) {
    574         free(node);
    575         return NULL;
    576     }
    577     memcpy(node->name, name, namelen + 1);
    578     if (strcmp(name, actual_name)) {
    579         node->actual_name = malloc(namelen + 1);
    580         if (!node->actual_name) {
    581             free(node->name);
    582             free(node);
    583             return NULL;
    584         }
    585         memcpy(node->actual_name, actual_name, namelen + 1);
    586     }
    587     node->namelen = namelen;
    588     node->nid = ptr_to_id(node);
    589     node->gen = fuse->next_generation++;
    590 
    591     derive_permissions_locked(fuse, parent, node);
    592     acquire_node_locked(node);
    593     add_node_to_parent_locked(node, parent);
    594     return node;
    595 }
    596 
    597 static int rename_node_locked(struct node *node, const char *name,
    598         const char* actual_name)
    599 {
    600     size_t namelen = strlen(name);
    601     int need_actual_name = strcmp(name, actual_name);
    602 
    603     /* make the storage bigger without actually changing the name
    604      * in case an error occurs part way */
    605     if (namelen > node->namelen) {
    606         char* new_name = realloc(node->name, namelen + 1);
    607         if (!new_name) {
    608             return -ENOMEM;
    609         }
    610         node->name = new_name;
    611         if (need_actual_name && node->actual_name) {
    612             char* new_actual_name = realloc(node->actual_name, namelen + 1);
    613             if (!new_actual_name) {
    614                 return -ENOMEM;
    615             }
    616             node->actual_name = new_actual_name;
    617         }
    618     }
    619 
    620     /* update the name, taking care to allocate storage before overwriting the old name */
    621     if (need_actual_name) {
    622         if (!node->actual_name) {
    623             node->actual_name = malloc(namelen + 1);
    624             if (!node->actual_name) {
    625                 return -ENOMEM;
    626             }
    627         }
    628         memcpy(node->actual_name, actual_name, namelen + 1);
    629     } else {
    630         free(node->actual_name);
    631         node->actual_name = NULL;
    632     }
    633     memcpy(node->name, name, namelen + 1);
    634     node->namelen = namelen;
    635     return 0;
    636 }
    637 
    638 static struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
    639 {
    640     if (nid == FUSE_ROOT_ID) {
    641         return &fuse->root;
    642     } else {
    643         return id_to_ptr(nid);
    644     }
    645 }
    646 
    647 static struct node* lookup_node_and_path_by_id_locked(struct fuse* fuse, __u64 nid,
    648         char* buf, size_t bufsize)
    649 {
    650     struct node* node = lookup_node_by_id_locked(fuse, nid);
    651     if (node && get_node_path_locked(node, buf, bufsize) < 0) {
    652         node = NULL;
    653     }
    654     return node;
    655 }
    656 
    657 static struct node *lookup_child_by_name_locked(struct node *node, const char *name)
    658 {
    659     for (node = node->child; node; node = node->next) {
    660         /* use exact string comparison, nodes that differ by case
    661          * must be considered distinct even if they refer to the same
    662          * underlying file as otherwise operations such as "mv x x"
    663          * will not work because the source and target nodes are the same. */
    664         if (!strcmp(name, node->name)) {
    665             return node;
    666         }
    667     }
    668     return 0;
    669 }
    670 
    671 static struct node* acquire_or_create_child_locked(
    672         struct fuse* fuse, struct node* parent,
    673         const char* name, const char* actual_name)
    674 {
    675     struct node* child = lookup_child_by_name_locked(parent, name);
    676     if (child) {
    677         acquire_node_locked(child);
    678     } else {
    679         child = create_node_locked(fuse, parent, name, actual_name);
    680     }
    681     return child;
    682 }
    683 
    684 static void fuse_init(struct fuse *fuse, int fd, const char *source_path,
    685         gid_t write_gid, derive_t derive, bool split_perms) {
    686     pthread_mutex_init(&fuse->lock, NULL);
    687 
    688     fuse->fd = fd;
    689     fuse->next_generation = 0;
    690     fuse->derive = derive;
    691     fuse->split_perms = split_perms;
    692     fuse->write_gid = write_gid;
    693 
    694     memset(&fuse->root, 0, sizeof(fuse->root));
    695     fuse->root.nid = FUSE_ROOT_ID; /* 1 */
    696     fuse->root.refcount = 2;
    697     fuse->root.namelen = strlen(source_path);
    698     fuse->root.name = strdup(source_path);
    699     fuse->root.userid = 0;
    700     fuse->root.uid = AID_ROOT;
    701 
    702     /* Set up root node for various modes of operation */
    703     switch (derive) {
    704     case DERIVE_NONE:
    705         /* Traditional behavior that treats entire device as being accessible
    706          * to sdcard_rw, and no permissions are derived. */
    707         fuse->root.perm = PERM_ROOT;
    708         fuse->root.mode = 0775;
    709         fuse->root.gid = AID_SDCARD_RW;
    710         break;
    711     case DERIVE_LEGACY:
    712         /* Legacy behavior used to support internal multiuser layout which
    713          * places user_id at the top directory level, with the actual roots
    714          * just below that. Shared OBB path is also at top level. */
    715         fuse->root.perm = PERM_LEGACY_PRE_ROOT;
    716         fuse->root.mode = 0771;
    717         fuse->root.gid = AID_SDCARD_R;
    718         fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
    719         fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);
    720         snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/obb", source_path);
    721         fs_prepare_dir(fuse->obbpath, 0775, getuid(), getgid());
    722         break;
    723     case DERIVE_UNIFIED:
    724         /* Unified multiuser layout which places secondary user_id under
    725          * /Android/user and shared OBB path under /Android/obb. */
    726         fuse->root.perm = PERM_ROOT;
    727         fuse->root.mode = 0771;
    728         fuse->root.gid = AID_SDCARD_R;
    729         fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
    730         fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);
    731         snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/Android/obb", source_path);
    732         break;
    733     }
    734 }
    735 
    736 static void fuse_status(struct fuse *fuse, __u64 unique, int err)
    737 {
    738     struct fuse_out_header hdr;
    739     hdr.len = sizeof(hdr);
    740     hdr.error = err;
    741     hdr.unique = unique;
    742     write(fuse->fd, &hdr, sizeof(hdr));
    743 }
    744 
    745 static void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
    746 {
    747     struct fuse_out_header hdr;
    748     struct iovec vec[2];
    749     int res;
    750 
    751     hdr.len = len + sizeof(hdr);
    752     hdr.error = 0;
    753     hdr.unique = unique;
    754 
    755     vec[0].iov_base = &hdr;
    756     vec[0].iov_len = sizeof(hdr);
    757     vec[1].iov_base = data;
    758     vec[1].iov_len = len;
    759 
    760     res = writev(fuse->fd, vec, 2);
    761     if (res < 0) {
    762         ERROR("*** REPLY FAILED *** %d\n", errno);
    763     }
    764 }
    765 
    766 static int fuse_reply_entry(struct fuse* fuse, __u64 unique,
    767         struct node* parent, const char* name, const char* actual_name,
    768         const char* path)
    769 {
    770     struct node* node;
    771     struct fuse_entry_out out;
    772     struct stat s;
    773 
    774     if (lstat(path, &s) < 0) {
    775         return -errno;
    776     }
    777 
    778     pthread_mutex_lock(&fuse->lock);
    779     node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
    780     if (!node) {
    781         pthread_mutex_unlock(&fuse->lock);
    782         return -ENOMEM;
    783     }
    784     memset(&out, 0, sizeof(out));
    785     attr_from_stat(&out.attr, &s, node);
    786     out.attr_valid = 10;
    787     out.entry_valid = 10;
    788     out.nodeid = node->nid;
    789     out.generation = node->gen;
    790     pthread_mutex_unlock(&fuse->lock);
    791     fuse_reply(fuse, unique, &out, sizeof(out));
    792     return NO_STATUS;
    793 }
    794 
    795 static int fuse_reply_attr(struct fuse* fuse, __u64 unique, const struct node* node,
    796         const char* path)
    797 {
    798     struct fuse_attr_out out;
    799     struct stat s;
    800 
    801     if (lstat(path, &s) < 0) {
    802         return -errno;
    803     }
    804     memset(&out, 0, sizeof(out));
    805     attr_from_stat(&out.attr, &s, node);
    806     out.attr_valid = 10;
    807     fuse_reply(fuse, unique, &out, sizeof(out));
    808     return NO_STATUS;
    809 }
    810 
    811 static int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
    812         const struct fuse_in_header *hdr, const char* name)
    813 {
    814     struct node* parent_node;
    815     char parent_path[PATH_MAX];
    816     char child_path[PATH_MAX];
    817     const char* actual_name;
    818 
    819     pthread_mutex_lock(&fuse->lock);
    820     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
    821             parent_path, sizeof(parent_path));
    822     TRACE("[%d] LOOKUP %s @ %llx (%s)\n", handler->token, name, hdr->nodeid,
    823         parent_node ? parent_node->name : "?");
    824     pthread_mutex_unlock(&fuse->lock);
    825 
    826     if (!parent_node || !(actual_name = find_file_within(parent_path, name,
    827             child_path, sizeof(child_path), 1))) {
    828         return -ENOENT;
    829     }
    830     if (!check_caller_access_to_name(fuse, hdr, parent_node, name, R_OK, false)) {
    831         return -EACCES;
    832     }
    833 
    834     return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
    835 }
    836 
    837 static int handle_forget(struct fuse* fuse, struct fuse_handler* handler,
    838         const struct fuse_in_header *hdr, const struct fuse_forget_in *req)
    839 {
    840     struct node* node;
    841 
    842     pthread_mutex_lock(&fuse->lock);
    843     node = lookup_node_by_id_locked(fuse, hdr->nodeid);
    844     TRACE("[%d] FORGET #%lld @ %llx (%s)\n", handler->token, req->nlookup,
    845             hdr->nodeid, node ? node->name : "?");
    846     if (node) {
    847         __u64 n = req->nlookup;
    848         while (n--) {
    849             release_node_locked(node);
    850         }
    851     }
    852     pthread_mutex_unlock(&fuse->lock);
    853     return NO_STATUS; /* no reply */
    854 }
    855 
    856 static int handle_getattr(struct fuse* fuse, struct fuse_handler* handler,
    857         const struct fuse_in_header *hdr, const struct fuse_getattr_in *req)
    858 {
    859     struct node* node;
    860     char path[PATH_MAX];
    861 
    862     pthread_mutex_lock(&fuse->lock);
    863     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
    864     TRACE("[%d] GETATTR flags=%x fh=%llx @ %llx (%s)\n", handler->token,
    865             req->getattr_flags, req->fh, hdr->nodeid, node ? node->name : "?");
    866     pthread_mutex_unlock(&fuse->lock);
    867 
    868     if (!node) {
    869         return -ENOENT;
    870     }
    871     if (!check_caller_access_to_node(fuse, hdr, node, R_OK, false)) {
    872         return -EACCES;
    873     }
    874 
    875     return fuse_reply_attr(fuse, hdr->unique, node, path);
    876 }
    877 
    878 static int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
    879         const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
    880 {
    881     bool has_rw;
    882     struct node* node;
    883     char path[PATH_MAX];
    884     struct timespec times[2];
    885 
    886     pthread_mutex_lock(&fuse->lock);
    887     has_rw = get_caller_has_rw_locked(fuse, hdr);
    888     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
    889     TRACE("[%d] SETATTR fh=%llx valid=%x @ %llx (%s)\n", handler->token,
    890             req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
    891     pthread_mutex_unlock(&fuse->lock);
    892 
    893     if (!node) {
    894         return -ENOENT;
    895     }
    896     if (!check_caller_access_to_node(fuse, hdr, node, W_OK, has_rw)) {
    897         return -EACCES;
    898     }
    899 
    900     /* XXX: incomplete implementation on purpose.
    901      * chmod/chown should NEVER be implemented.*/
    902 
    903     if ((req->valid & FATTR_SIZE) && truncate(path, req->size) < 0) {
    904         return -errno;
    905     }
    906 
    907     /* Handle changing atime and mtime.  If FATTR_ATIME_and FATTR_ATIME_NOW
    908      * are both set, then set it to the current time.  Else, set it to the
    909      * time specified in the request.  Same goes for mtime.  Use utimensat(2)
    910      * as it allows ATIME and MTIME to be changed independently, and has
    911      * nanosecond resolution which fuse also has.
    912      */
    913     if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
    914         times[0].tv_nsec = UTIME_OMIT;
    915         times[1].tv_nsec = UTIME_OMIT;
    916         if (req->valid & FATTR_ATIME) {
    917             if (req->valid & FATTR_ATIME_NOW) {
    918               times[0].tv_nsec = UTIME_NOW;
    919             } else {
    920               times[0].tv_sec = req->atime;
    921               times[0].tv_nsec = req->atimensec;
    922             }
    923         }
    924         if (req->valid & FATTR_MTIME) {
    925             if (req->valid & FATTR_MTIME_NOW) {
    926               times[1].tv_nsec = UTIME_NOW;
    927             } else {
    928               times[1].tv_sec = req->mtime;
    929               times[1].tv_nsec = req->mtimensec;
    930             }
    931         }
    932         TRACE("[%d] Calling utimensat on %s with atime %ld, mtime=%ld\n",
    933                 handler->token, path, times[0].tv_sec, times[1].tv_sec);
    934         if (utimensat(-1, path, times, 0) < 0) {
    935             return -errno;
    936         }
    937     }
    938     return fuse_reply_attr(fuse, hdr->unique, node, path);
    939 }
    940 
    941 static int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
    942         const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
    943 {
    944     bool has_rw;
    945     struct node* parent_node;
    946     char parent_path[PATH_MAX];
    947     char child_path[PATH_MAX];
    948     const char* actual_name;
    949 
    950     pthread_mutex_lock(&fuse->lock);
    951     has_rw = get_caller_has_rw_locked(fuse, hdr);
    952     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
    953             parent_path, sizeof(parent_path));
    954     TRACE("[%d] MKNOD %s 0%o @ %llx (%s)\n", handler->token,
    955             name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
    956     pthread_mutex_unlock(&fuse->lock);
    957 
    958     if (!parent_node || !(actual_name = find_file_within(parent_path, name,
    959             child_path, sizeof(child_path), 1))) {
    960         return -ENOENT;
    961     }
    962     if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK, has_rw)) {
    963         return -EACCES;
    964     }
    965     __u32 mode = (req->mode & (~0777)) | 0664;
    966     if (mknod(child_path, mode, req->rdev) < 0) {
    967         return -errno;
    968     }
    969     return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
    970 }
    971 
    972 static int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
    973         const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
    974 {
    975     bool has_rw;
    976     struct node* parent_node;
    977     char parent_path[PATH_MAX];
    978     char child_path[PATH_MAX];
    979     const char* actual_name;
    980 
    981     pthread_mutex_lock(&fuse->lock);
    982     has_rw = get_caller_has_rw_locked(fuse, hdr);
    983     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
    984             parent_path, sizeof(parent_path));
    985     TRACE("[%d] MKDIR %s 0%o @ %llx (%s)\n", handler->token,
    986             name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
    987     pthread_mutex_unlock(&fuse->lock);
    988 
    989     if (!parent_node || !(actual_name = find_file_within(parent_path, name,
    990             child_path, sizeof(child_path), 1))) {
    991         return -ENOENT;
    992     }
    993     if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK, has_rw)) {
    994         return -EACCES;
    995     }
    996     __u32 mode = (req->mode & (~0777)) | 0775;
    997     if (mkdir(child_path, mode) < 0) {
    998         return -errno;
    999     }
   1000 
   1001     /* When creating /Android/data and /Android/obb, mark them as .nomedia */
   1002     if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "data")) {
   1003         char nomedia[PATH_MAX];
   1004         snprintf(nomedia, PATH_MAX, "%s/.nomedia", child_path);
   1005         if (touch(nomedia, 0664) != 0) {
   1006             ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
   1007             return -ENOENT;
   1008         }
   1009     }
   1010     if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "obb")) {
   1011         char nomedia[PATH_MAX];
   1012         snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->obbpath);
   1013         if (touch(nomedia, 0664) != 0) {
   1014             ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
   1015             return -ENOENT;
   1016         }
   1017     }
   1018 
   1019     return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
   1020 }
   1021 
   1022 static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
   1023         const struct fuse_in_header* hdr, const char* name)
   1024 {
   1025     bool has_rw;
   1026     struct node* parent_node;
   1027     char parent_path[PATH_MAX];
   1028     char child_path[PATH_MAX];
   1029 
   1030     pthread_mutex_lock(&fuse->lock);
   1031     has_rw = get_caller_has_rw_locked(fuse, hdr);
   1032     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
   1033             parent_path, sizeof(parent_path));
   1034     TRACE("[%d] UNLINK %s @ %llx (%s)\n", handler->token,
   1035             name, hdr->nodeid, parent_node ? parent_node->name : "?");
   1036     pthread_mutex_unlock(&fuse->lock);
   1037 
   1038     if (!parent_node || !find_file_within(parent_path, name,
   1039             child_path, sizeof(child_path), 1)) {
   1040         return -ENOENT;
   1041     }
   1042     if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK, has_rw)) {
   1043         return -EACCES;
   1044     }
   1045     if (unlink(child_path) < 0) {
   1046         return -errno;
   1047     }
   1048     return 0;
   1049 }
   1050 
   1051 static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
   1052         const struct fuse_in_header* hdr, const char* name)
   1053 {
   1054     bool has_rw;
   1055     struct node* parent_node;
   1056     char parent_path[PATH_MAX];
   1057     char child_path[PATH_MAX];
   1058 
   1059     pthread_mutex_lock(&fuse->lock);
   1060     has_rw = get_caller_has_rw_locked(fuse, hdr);
   1061     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
   1062             parent_path, sizeof(parent_path));
   1063     TRACE("[%d] RMDIR %s @ %llx (%s)\n", handler->token,
   1064             name, hdr->nodeid, parent_node ? parent_node->name : "?");
   1065     pthread_mutex_unlock(&fuse->lock);
   1066 
   1067     if (!parent_node || !find_file_within(parent_path, name,
   1068             child_path, sizeof(child_path), 1)) {
   1069         return -ENOENT;
   1070     }
   1071     if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK, has_rw)) {
   1072         return -EACCES;
   1073     }
   1074     if (rmdir(child_path) < 0) {
   1075         return -errno;
   1076     }
   1077     return 0;
   1078 }
   1079 
   1080 static int handle_rename(struct fuse* fuse, struct fuse_handler* handler,
   1081         const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
   1082         const char* old_name, const char* new_name)
   1083 {
   1084     bool has_rw;
   1085     struct node* old_parent_node;
   1086     struct node* new_parent_node;
   1087     struct node* child_node;
   1088     char old_parent_path[PATH_MAX];
   1089     char new_parent_path[PATH_MAX];
   1090     char old_child_path[PATH_MAX];
   1091     char new_child_path[PATH_MAX];
   1092     const char* new_actual_name;
   1093     int res;
   1094 
   1095     pthread_mutex_lock(&fuse->lock);
   1096     has_rw = get_caller_has_rw_locked(fuse, hdr);
   1097     old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
   1098             old_parent_path, sizeof(old_parent_path));
   1099     new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
   1100             new_parent_path, sizeof(new_parent_path));
   1101     TRACE("[%d] RENAME %s->%s @ %llx (%s) -> %llx (%s)\n", handler->token,
   1102             old_name, new_name,
   1103             hdr->nodeid, old_parent_node ? old_parent_node->name : "?",
   1104             req->newdir, new_parent_node ? new_parent_node->name : "?");
   1105     if (!old_parent_node || !new_parent_node) {
   1106         res = -ENOENT;
   1107         goto lookup_error;
   1108     }
   1109     if (!check_caller_access_to_name(fuse, hdr, old_parent_node, old_name, W_OK, has_rw)) {
   1110         res = -EACCES;
   1111         goto lookup_error;
   1112     }
   1113     if (!check_caller_access_to_name(fuse, hdr, new_parent_node, new_name, W_OK, has_rw)) {
   1114         res = -EACCES;
   1115         goto lookup_error;
   1116     }
   1117     child_node = lookup_child_by_name_locked(old_parent_node, old_name);
   1118     if (!child_node || get_node_path_locked(child_node,
   1119             old_child_path, sizeof(old_child_path)) < 0) {
   1120         res = -ENOENT;
   1121         goto lookup_error;
   1122     }
   1123     acquire_node_locked(child_node);
   1124     pthread_mutex_unlock(&fuse->lock);
   1125 
   1126     /* Special case for renaming a file where destination is same path
   1127      * differing only by case.  In this case we don't want to look for a case
   1128      * insensitive match.  This allows commands like "mv foo FOO" to work as expected.
   1129      */
   1130     int search = old_parent_node != new_parent_node
   1131             || strcasecmp(old_name, new_name);
   1132     if (!(new_actual_name = find_file_within(new_parent_path, new_name,
   1133             new_child_path, sizeof(new_child_path), search))) {
   1134         res = -ENOENT;
   1135         goto io_error;
   1136     }
   1137 
   1138     TRACE("[%d] RENAME %s->%s\n", handler->token, old_child_path, new_child_path);
   1139     res = rename(old_child_path, new_child_path);
   1140     if (res < 0) {
   1141         res = -errno;
   1142         goto io_error;
   1143     }
   1144 
   1145     pthread_mutex_lock(&fuse->lock);
   1146     res = rename_node_locked(child_node, new_name, new_actual_name);
   1147     if (!res) {
   1148         remove_node_from_parent_locked(child_node);
   1149         add_node_to_parent_locked(child_node, new_parent_node);
   1150     }
   1151     goto done;
   1152 
   1153 io_error:
   1154     pthread_mutex_lock(&fuse->lock);
   1155 done:
   1156     release_node_locked(child_node);
   1157 lookup_error:
   1158     pthread_mutex_unlock(&fuse->lock);
   1159     return res;
   1160 }
   1161 
   1162 static int open_flags_to_access_mode(int open_flags) {
   1163     if ((open_flags & O_ACCMODE) == O_RDONLY) {
   1164         return R_OK;
   1165     } else if ((open_flags & O_ACCMODE) == O_WRONLY) {
   1166         return W_OK;
   1167     } else {
   1168         /* Probably O_RDRW, but treat as default to be safe */
   1169         return R_OK | W_OK;
   1170     }
   1171 }
   1172 
   1173 static int handle_open(struct fuse* fuse, struct fuse_handler* handler,
   1174         const struct fuse_in_header* hdr, const struct fuse_open_in* req)
   1175 {
   1176     bool has_rw;
   1177     struct node* node;
   1178     char path[PATH_MAX];
   1179     struct fuse_open_out out;
   1180     struct handle *h;
   1181 
   1182     pthread_mutex_lock(&fuse->lock);
   1183     has_rw = get_caller_has_rw_locked(fuse, hdr);
   1184     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
   1185     TRACE("[%d] OPEN 0%o @ %llx (%s)\n", handler->token,
   1186             req->flags, hdr->nodeid, node ? node->name : "?");
   1187     pthread_mutex_unlock(&fuse->lock);
   1188 
   1189     if (!node) {
   1190         return -ENOENT;
   1191     }
   1192     if (!check_caller_access_to_node(fuse, hdr, node,
   1193             open_flags_to_access_mode(req->flags), has_rw)) {
   1194         return -EACCES;
   1195     }
   1196     h = malloc(sizeof(*h));
   1197     if (!h) {
   1198         return -ENOMEM;
   1199     }
   1200     TRACE("[%d] OPEN %s\n", handler->token, path);
   1201     h->fd = open(path, req->flags);
   1202     if (h->fd < 0) {
   1203         free(h);
   1204         return -errno;
   1205     }
   1206     out.fh = ptr_to_id(h);
   1207     out.open_flags = 0;
   1208     out.padding = 0;
   1209     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
   1210     return NO_STATUS;
   1211 }
   1212 
   1213 static int handle_read(struct fuse* fuse, struct fuse_handler* handler,
   1214         const struct fuse_in_header* hdr, const struct fuse_read_in* req)
   1215 {
   1216     struct handle *h = id_to_ptr(req->fh);
   1217     __u64 unique = hdr->unique;
   1218     __u32 size = req->size;
   1219     __u64 offset = req->offset;
   1220     int res;
   1221 
   1222     /* Don't access any other fields of hdr or req beyond this point, the read buffer
   1223      * overlaps the request buffer and will clobber data in the request.  This
   1224      * saves us 128KB per request handler thread at the cost of this scary comment. */
   1225 
   1226     TRACE("[%d] READ %p(%d) %u@%llu\n", handler->token,
   1227             h, h->fd, size, offset);
   1228     if (size > sizeof(handler->read_buffer)) {
   1229         return -EINVAL;
   1230     }
   1231     res = pread64(h->fd, handler->read_buffer, size, offset);
   1232     if (res < 0) {
   1233         return -errno;
   1234     }
   1235     fuse_reply(fuse, unique, handler->read_buffer, res);
   1236     return NO_STATUS;
   1237 }
   1238 
   1239 static int handle_write(struct fuse* fuse, struct fuse_handler* handler,
   1240         const struct fuse_in_header* hdr, const struct fuse_write_in* req,
   1241         const void* buffer)
   1242 {
   1243     struct fuse_write_out out;
   1244     struct handle *h = id_to_ptr(req->fh);
   1245     int res;
   1246 
   1247     TRACE("[%d] WRITE %p(%d) %u@%llu\n", handler->token,
   1248             h, h->fd, req->size, req->offset);
   1249     res = pwrite64(h->fd, buffer, req->size, req->offset);
   1250     if (res < 0) {
   1251         return -errno;
   1252     }
   1253     out.size = res;
   1254     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
   1255     return NO_STATUS;
   1256 }
   1257 
   1258 static int handle_statfs(struct fuse* fuse, struct fuse_handler* handler,
   1259         const struct fuse_in_header* hdr)
   1260 {
   1261     char path[PATH_MAX];
   1262     struct statfs stat;
   1263     struct fuse_statfs_out out;
   1264     int res;
   1265 
   1266     pthread_mutex_lock(&fuse->lock);
   1267     TRACE("[%d] STATFS\n", handler->token);
   1268     res = get_node_path_locked(&fuse->root, path, sizeof(path));
   1269     pthread_mutex_unlock(&fuse->lock);
   1270     if (res < 0) {
   1271         return -ENOENT;
   1272     }
   1273     if (statfs(fuse->root.name, &stat) < 0) {
   1274         return -errno;
   1275     }
   1276     memset(&out, 0, sizeof(out));
   1277     out.st.blocks = stat.f_blocks;
   1278     out.st.bfree = stat.f_bfree;
   1279     out.st.bavail = stat.f_bavail;
   1280     out.st.files = stat.f_files;
   1281     out.st.ffree = stat.f_ffree;
   1282     out.st.bsize = stat.f_bsize;
   1283     out.st.namelen = stat.f_namelen;
   1284     out.st.frsize = stat.f_frsize;
   1285     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
   1286     return NO_STATUS;
   1287 }
   1288 
   1289 static int handle_release(struct fuse* fuse, struct fuse_handler* handler,
   1290         const struct fuse_in_header* hdr, const struct fuse_release_in* req)
   1291 {
   1292     struct handle *h = id_to_ptr(req->fh);
   1293 
   1294     TRACE("[%d] RELEASE %p(%d)\n", handler->token, h, h->fd);
   1295     close(h->fd);
   1296     free(h);
   1297     return 0;
   1298 }
   1299 
   1300 static int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
   1301         const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
   1302 {
   1303     int is_data_sync = req->fsync_flags & 1;
   1304     struct handle *h = id_to_ptr(req->fh);
   1305     int res;
   1306 
   1307     TRACE("[%d] FSYNC %p(%d) is_data_sync=%d\n", handler->token,
   1308             h, h->fd, is_data_sync);
   1309     res = is_data_sync ? fdatasync(h->fd) : fsync(h->fd);
   1310     if (res < 0) {
   1311         return -errno;
   1312     }
   1313     return 0;
   1314 }
   1315 
   1316 static int handle_flush(struct fuse* fuse, struct fuse_handler* handler,
   1317         const struct fuse_in_header* hdr)
   1318 {
   1319     TRACE("[%d] FLUSH\n", handler->token);
   1320     return 0;
   1321 }
   1322 
   1323 static int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
   1324         const struct fuse_in_header* hdr, const struct fuse_open_in* req)
   1325 {
   1326     struct node* node;
   1327     char path[PATH_MAX];
   1328     struct fuse_open_out out;
   1329     struct dirhandle *h;
   1330 
   1331     pthread_mutex_lock(&fuse->lock);
   1332     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
   1333     TRACE("[%d] OPENDIR @ %llx (%s)\n", handler->token,
   1334             hdr->nodeid, node ? node->name : "?");
   1335     pthread_mutex_unlock(&fuse->lock);
   1336 
   1337     if (!node) {
   1338         return -ENOENT;
   1339     }
   1340     if (!check_caller_access_to_node(fuse, hdr, node, R_OK, false)) {
   1341         return -EACCES;
   1342     }
   1343     h = malloc(sizeof(*h));
   1344     if (!h) {
   1345         return -ENOMEM;
   1346     }
   1347     TRACE("[%d] OPENDIR %s\n", handler->token, path);
   1348     h->d = opendir(path);
   1349     if (!h->d) {
   1350         free(h);
   1351         return -errno;
   1352     }
   1353     out.fh = ptr_to_id(h);
   1354     out.open_flags = 0;
   1355     out.padding = 0;
   1356     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
   1357     return NO_STATUS;
   1358 }
   1359 
   1360 static int handle_readdir(struct fuse* fuse, struct fuse_handler* handler,
   1361         const struct fuse_in_header* hdr, const struct fuse_read_in* req)
   1362 {
   1363     char buffer[8192];
   1364     struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
   1365     struct dirent *de;
   1366     struct dirhandle *h = id_to_ptr(req->fh);
   1367 
   1368     TRACE("[%d] READDIR %p\n", handler->token, h);
   1369     if (req->offset == 0) {
   1370         /* rewinddir() might have been called above us, so rewind here too */
   1371         TRACE("[%d] calling rewinddir()\n", handler->token);
   1372         rewinddir(h->d);
   1373     }
   1374     de = readdir(h->d);
   1375     if (!de) {
   1376         return 0;
   1377     }
   1378     fde->ino = FUSE_UNKNOWN_INO;
   1379     /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
   1380     fde->off = req->offset + 1;
   1381     fde->type = de->d_type;
   1382     fde->namelen = strlen(de->d_name);
   1383     memcpy(fde->name, de->d_name, fde->namelen + 1);
   1384     fuse_reply(fuse, hdr->unique, fde,
   1385             FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
   1386     return NO_STATUS;
   1387 }
   1388 
   1389 static int handle_releasedir(struct fuse* fuse, struct fuse_handler* handler,
   1390         const struct fuse_in_header* hdr, const struct fuse_release_in* req)
   1391 {
   1392     struct dirhandle *h = id_to_ptr(req->fh);
   1393 
   1394     TRACE("[%d] RELEASEDIR %p\n", handler->token, h);
   1395     closedir(h->d);
   1396     free(h);
   1397     return 0;
   1398 }
   1399 
   1400 static int handle_init(struct fuse* fuse, struct fuse_handler* handler,
   1401         const struct fuse_in_header* hdr, const struct fuse_init_in* req)
   1402 {
   1403     struct fuse_init_out out;
   1404 
   1405     TRACE("[%d] INIT ver=%d.%d maxread=%d flags=%x\n",
   1406             handler->token, req->major, req->minor, req->max_readahead, req->flags);
   1407     out.major = FUSE_KERNEL_VERSION;
   1408     out.minor = FUSE_KERNEL_MINOR_VERSION;
   1409     out.max_readahead = req->max_readahead;
   1410     out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
   1411     out.max_background = 32;
   1412     out.congestion_threshold = 32;
   1413     out.max_write = MAX_WRITE;
   1414     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
   1415     return NO_STATUS;
   1416 }
   1417 
   1418 static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
   1419         const struct fuse_in_header *hdr, const void *data, size_t data_len)
   1420 {
   1421     switch (hdr->opcode) {
   1422     case FUSE_LOOKUP: { /* bytez[] -> entry_out */
   1423         const char* name = data;
   1424         return handle_lookup(fuse, handler, hdr, name);
   1425     }
   1426 
   1427     case FUSE_FORGET: {
   1428         const struct fuse_forget_in *req = data;
   1429         return handle_forget(fuse, handler, hdr, req);
   1430     }
   1431 
   1432     case FUSE_GETATTR: { /* getattr_in -> attr_out */
   1433         const struct fuse_getattr_in *req = data;
   1434         return handle_getattr(fuse, handler, hdr, req);
   1435     }
   1436 
   1437     case FUSE_SETATTR: { /* setattr_in -> attr_out */
   1438         const struct fuse_setattr_in *req = data;
   1439         return handle_setattr(fuse, handler, hdr, req);
   1440     }
   1441 
   1442 //    case FUSE_READLINK:
   1443 //    case FUSE_SYMLINK:
   1444     case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
   1445         const struct fuse_mknod_in *req = data;
   1446         const char *name = ((const char*) data) + sizeof(*req);
   1447         return handle_mknod(fuse, handler, hdr, req, name);
   1448     }
   1449 
   1450     case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
   1451         const struct fuse_mkdir_in *req = data;
   1452         const char *name = ((const char*) data) + sizeof(*req);
   1453         return handle_mkdir(fuse, handler, hdr, req, name);
   1454     }
   1455 
   1456     case FUSE_UNLINK: { /* bytez[] -> */
   1457         const char* name = data;
   1458         return handle_unlink(fuse, handler, hdr, name);
   1459     }
   1460 
   1461     case FUSE_RMDIR: { /* bytez[] -> */
   1462         const char* name = data;
   1463         return handle_rmdir(fuse, handler, hdr, name);
   1464     }
   1465 
   1466     case FUSE_RENAME: { /* rename_in, oldname, newname ->  */
   1467         const struct fuse_rename_in *req = data;
   1468         const char *old_name = ((const char*) data) + sizeof(*req);
   1469         const char *new_name = old_name + strlen(old_name) + 1;
   1470         return handle_rename(fuse, handler, hdr, req, old_name, new_name);
   1471     }
   1472 
   1473 //    case FUSE_LINK:
   1474     case FUSE_OPEN: { /* open_in -> open_out */
   1475         const struct fuse_open_in *req = data;
   1476         return handle_open(fuse, handler, hdr, req);
   1477     }
   1478 
   1479     case FUSE_READ: { /* read_in -> byte[] */
   1480         const struct fuse_read_in *req = data;
   1481         return handle_read(fuse, handler, hdr, req);
   1482     }
   1483 
   1484     case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
   1485         const struct fuse_write_in *req = data;
   1486         const void* buffer = (const __u8*)data + sizeof(*req);
   1487         return handle_write(fuse, handler, hdr, req, buffer);
   1488     }
   1489 
   1490     case FUSE_STATFS: { /* getattr_in -> attr_out */
   1491         return handle_statfs(fuse, handler, hdr);
   1492     }
   1493 
   1494     case FUSE_RELEASE: { /* release_in -> */
   1495         const struct fuse_release_in *req = data;
   1496         return handle_release(fuse, handler, hdr, req);
   1497     }
   1498 
   1499     case FUSE_FSYNC: {
   1500         const struct fuse_fsync_in *req = data;
   1501         return handle_fsync(fuse, handler, hdr, req);
   1502     }
   1503 
   1504 //    case FUSE_SETXATTR:
   1505 //    case FUSE_GETXATTR:
   1506 //    case FUSE_LISTXATTR:
   1507 //    case FUSE_REMOVEXATTR:
   1508     case FUSE_FLUSH: {
   1509         return handle_flush(fuse, handler, hdr);
   1510     }
   1511 
   1512     case FUSE_OPENDIR: { /* open_in -> open_out */
   1513         const struct fuse_open_in *req = data;
   1514         return handle_opendir(fuse, handler, hdr, req);
   1515     }
   1516 
   1517     case FUSE_READDIR: {
   1518         const struct fuse_read_in *req = data;
   1519         return handle_readdir(fuse, handler, hdr, req);
   1520     }
   1521 
   1522     case FUSE_RELEASEDIR: { /* release_in -> */
   1523         const struct fuse_release_in *req = data;
   1524         return handle_releasedir(fuse, handler, hdr, req);
   1525     }
   1526 
   1527 //    case FUSE_FSYNCDIR:
   1528     case FUSE_INIT: { /* init_in -> init_out */
   1529         const struct fuse_init_in *req = data;
   1530         return handle_init(fuse, handler, hdr, req);
   1531     }
   1532 
   1533     default: {
   1534         TRACE("[%d] NOTIMPL op=%d uniq=%llx nid=%llx\n",
   1535                 handler->token, hdr->opcode, hdr->unique, hdr->nodeid);
   1536         return -ENOSYS;
   1537     }
   1538     }
   1539 }
   1540 
   1541 static void handle_fuse_requests(struct fuse_handler* handler)
   1542 {
   1543     struct fuse* fuse = handler->fuse;
   1544     for (;;) {
   1545         ssize_t len = read(fuse->fd,
   1546                 handler->request_buffer, sizeof(handler->request_buffer));
   1547         if (len < 0) {
   1548             if (errno != EINTR) {
   1549                 ERROR("[%d] handle_fuse_requests: errno=%d\n", handler->token, errno);
   1550             }
   1551             continue;
   1552         }
   1553 
   1554         if ((size_t)len < sizeof(struct fuse_in_header)) {
   1555             ERROR("[%d] request too short: len=%zu\n", handler->token, (size_t)len);
   1556             continue;
   1557         }
   1558 
   1559         const struct fuse_in_header *hdr = (void*)handler->request_buffer;
   1560         if (hdr->len != (size_t)len) {
   1561             ERROR("[%d] malformed header: len=%zu, hdr->len=%u\n",
   1562                     handler->token, (size_t)len, hdr->len);
   1563             continue;
   1564         }
   1565 
   1566         const void *data = handler->request_buffer + sizeof(struct fuse_in_header);
   1567         size_t data_len = len - sizeof(struct fuse_in_header);
   1568         __u64 unique = hdr->unique;
   1569         int res = handle_fuse_request(fuse, handler, hdr, data, data_len);
   1570 
   1571         /* We do not access the request again after this point because the underlying
   1572          * buffer storage may have been reused while processing the request. */
   1573 
   1574         if (res != NO_STATUS) {
   1575             if (res) {
   1576                 TRACE("[%d] ERROR %d\n", handler->token, res);
   1577             }
   1578             fuse_status(fuse, unique, res);
   1579         }
   1580     }
   1581 }
   1582 
   1583 static void* start_handler(void* data)
   1584 {
   1585     struct fuse_handler* handler = data;
   1586     handle_fuse_requests(handler);
   1587     return NULL;
   1588 }
   1589 
   1590 static bool remove_str_to_int(void *key, void *value, void *context) {
   1591     Hashmap* map = context;
   1592     hashmapRemove(map, key);
   1593     free(key);
   1594     return true;
   1595 }
   1596 
   1597 static bool remove_int_to_null(void *key, void *value, void *context) {
   1598     Hashmap* map = context;
   1599     hashmapRemove(map, key);
   1600     return true;
   1601 }
   1602 
   1603 static int read_package_list(struct fuse *fuse) {
   1604     pthread_mutex_lock(&fuse->lock);
   1605 
   1606     hashmapForEach(fuse->package_to_appid, remove_str_to_int, fuse->package_to_appid);
   1607     hashmapForEach(fuse->appid_with_rw, remove_int_to_null, fuse->appid_with_rw);
   1608 
   1609     FILE* file = fopen(kPackagesListFile, "r");
   1610     if (!file) {
   1611         ERROR("failed to open package list: %s\n", strerror(errno));
   1612         pthread_mutex_unlock(&fuse->lock);
   1613         return -1;
   1614     }
   1615 
   1616     char buf[512];
   1617     while (fgets(buf, sizeof(buf), file) != NULL) {
   1618         char package_name[512];
   1619         int appid;
   1620         char gids[512];
   1621 
   1622         if (sscanf(buf, "%s %d %*d %*s %*s %s", package_name, &appid, gids) == 3) {
   1623             char* package_name_dup = strdup(package_name);
   1624             hashmapPut(fuse->package_to_appid, package_name_dup, (void*) appid);
   1625 
   1626             char* token = strtok(gids, ",");
   1627             while (token != NULL) {
   1628                 if (strtoul(token, NULL, 10) == fuse->write_gid) {
   1629                     hashmapPut(fuse->appid_with_rw, (void*) appid, (void*) 1);
   1630                     break;
   1631                 }
   1632                 token = strtok(NULL, ",");
   1633             }
   1634         }
   1635     }
   1636 
   1637     TRACE("read_package_list: found %d packages, %d with write_gid\n",
   1638             hashmapSize(fuse->package_to_appid),
   1639             hashmapSize(fuse->appid_with_rw));
   1640     fclose(file);
   1641     pthread_mutex_unlock(&fuse->lock);
   1642     return 0;
   1643 }
   1644 
   1645 static void watch_package_list(struct fuse* fuse) {
   1646     struct inotify_event *event;
   1647     char event_buf[512];
   1648 
   1649     int nfd = inotify_init();
   1650     if (nfd < 0) {
   1651         ERROR("inotify_init failed: %s\n", strerror(errno));
   1652         return;
   1653     }
   1654 
   1655     bool active = false;
   1656     while (1) {
   1657         if (!active) {
   1658             int res = inotify_add_watch(nfd, kPackagesListFile, IN_DELETE_SELF);
   1659             if (res == -1) {
   1660                 if (errno == ENOENT || errno == EACCES) {
   1661                     /* Framework may not have created yet, sleep and retry */
   1662                     ERROR("missing packages.list; retrying\n");
   1663                     sleep(3);
   1664                     continue;
   1665                 } else {
   1666                     ERROR("inotify_add_watch failed: %s\n", strerror(errno));
   1667                     return;
   1668                 }
   1669             }
   1670 
   1671             /* Watch above will tell us about any future changes, so
   1672              * read the current state. */
   1673             if (read_package_list(fuse) == -1) {
   1674                 ERROR("read_package_list failed: %s\n", strerror(errno));
   1675                 return;
   1676             }
   1677             active = true;
   1678         }
   1679 
   1680         int event_pos = 0;
   1681         int res = read(nfd, event_buf, sizeof(event_buf));
   1682         if (res < (int) sizeof(*event)) {
   1683             if (errno == EINTR)
   1684                 continue;
   1685             ERROR("failed to read inotify event: %s\n", strerror(errno));
   1686             return;
   1687         }
   1688 
   1689         while (res >= (int) sizeof(*event)) {
   1690             int event_size;
   1691             event = (struct inotify_event *) (event_buf + event_pos);
   1692 
   1693             TRACE("inotify event: %08x\n", event->mask);
   1694             if ((event->mask & IN_IGNORED) == IN_IGNORED) {
   1695                 /* Previously watched file was deleted, probably due to move
   1696                  * that swapped in new data; re-arm the watch and read. */
   1697                 active = false;
   1698             }
   1699 
   1700             event_size = sizeof(*event) + event->len;
   1701             res -= event_size;
   1702             event_pos += event_size;
   1703         }
   1704     }
   1705 }
   1706 
   1707 static int ignite_fuse(struct fuse* fuse, int num_threads)
   1708 {
   1709     struct fuse_handler* handlers;
   1710     int i;
   1711 
   1712     handlers = malloc(num_threads * sizeof(struct fuse_handler));
   1713     if (!handlers) {
   1714         ERROR("cannot allocate storage for threads\n");
   1715         return -ENOMEM;
   1716     }
   1717 
   1718     for (i = 0; i < num_threads; i++) {
   1719         handlers[i].fuse = fuse;
   1720         handlers[i].token = i;
   1721     }
   1722 
   1723     /* When deriving permissions, this thread is used to process inotify events,
   1724      * otherwise it becomes one of the FUSE handlers. */
   1725     i = (fuse->derive == DERIVE_NONE) ? 1 : 0;
   1726     for (; i < num_threads; i++) {
   1727         pthread_t thread;
   1728         int res = pthread_create(&thread, NULL, start_handler, &handlers[i]);
   1729         if (res) {
   1730             ERROR("failed to start thread #%d, error=%d\n", i, res);
   1731             goto quit;
   1732         }
   1733     }
   1734 
   1735     if (fuse->derive == DERIVE_NONE) {
   1736         handle_fuse_requests(&handlers[0]);
   1737     } else {
   1738         watch_package_list(fuse);
   1739     }
   1740 
   1741     ERROR("terminated prematurely\n");
   1742 
   1743     /* don't bother killing all of the other threads or freeing anything,
   1744      * should never get here anyhow */
   1745 quit:
   1746     exit(1);
   1747 }
   1748 
   1749 static int usage()
   1750 {
   1751     ERROR("usage: sdcard [OPTIONS] <source_path> <dest_path>\n"
   1752             "    -u: specify UID to run as\n"
   1753             "    -g: specify GID to run as\n"
   1754             "    -w: specify GID required to write (default sdcard_rw, requires -d or -l)\n"
   1755             "    -t: specify number of threads to use (default %d)\n"
   1756             "    -d: derive file permissions based on path\n"
   1757             "    -l: derive file permissions based on legacy internal layout\n"
   1758             "    -s: split derived permissions for pics, av\n"
   1759             "\n", DEFAULT_NUM_THREADS);
   1760     return 1;
   1761 }
   1762 
   1763 static int run(const char* source_path, const char* dest_path, uid_t uid,
   1764         gid_t gid, gid_t write_gid, int num_threads, derive_t derive,
   1765         bool split_perms) {
   1766     int fd;
   1767     char opts[256];
   1768     int res;
   1769     struct fuse fuse;
   1770 
   1771     /* cleanup from previous instance, if necessary */
   1772     umount2(dest_path, 2);
   1773 
   1774     fd = open("/dev/fuse", O_RDWR);
   1775     if (fd < 0){
   1776         ERROR("cannot open fuse device: %s\n", strerror(errno));
   1777         return -1;
   1778     }
   1779 
   1780     snprintf(opts, sizeof(opts),
   1781             "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
   1782             fd, uid, gid);
   1783 
   1784     res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV, opts);
   1785     if (res < 0) {
   1786         ERROR("cannot mount fuse filesystem: %s\n", strerror(errno));
   1787         goto error;
   1788     }
   1789 
   1790     res = setgroups(sizeof(kGroups) / sizeof(kGroups[0]), kGroups);
   1791     if (res < 0) {
   1792         ERROR("cannot setgroups: %s\n", strerror(errno));
   1793         goto error;
   1794     }
   1795 
   1796     res = setgid(gid);
   1797     if (res < 0) {
   1798         ERROR("cannot setgid: %s\n", strerror(errno));
   1799         goto error;
   1800     }
   1801 
   1802     res = setuid(uid);
   1803     if (res < 0) {
   1804         ERROR("cannot setuid: %s\n", strerror(errno));
   1805         goto error;
   1806     }
   1807 
   1808     fuse_init(&fuse, fd, source_path, write_gid, derive, split_perms);
   1809 
   1810     umask(0);
   1811     res = ignite_fuse(&fuse, num_threads);
   1812 
   1813     /* we do not attempt to umount the file system here because we are no longer
   1814      * running as the root user */
   1815 
   1816 error:
   1817     close(fd);
   1818     return res;
   1819 }
   1820 
   1821 int main(int argc, char **argv)
   1822 {
   1823     int res;
   1824     const char *source_path = NULL;
   1825     const char *dest_path = NULL;
   1826     uid_t uid = 0;
   1827     gid_t gid = 0;
   1828     gid_t write_gid = AID_SDCARD_RW;
   1829     int num_threads = DEFAULT_NUM_THREADS;
   1830     derive_t derive = DERIVE_NONE;
   1831     bool split_perms = false;
   1832     int i;
   1833     struct rlimit rlim;
   1834 
   1835     int opt;
   1836     while ((opt = getopt(argc, argv, "u:g:w:t:dls")) != -1) {
   1837         switch (opt) {
   1838             case 'u':
   1839                 uid = strtoul(optarg, NULL, 10);
   1840                 break;
   1841             case 'g':
   1842                 gid = strtoul(optarg, NULL, 10);
   1843                 break;
   1844             case 'w':
   1845                 write_gid = strtoul(optarg, NULL, 10);
   1846                 break;
   1847             case 't':
   1848                 num_threads = strtoul(optarg, NULL, 10);
   1849                 break;
   1850             case 'd':
   1851                 derive = DERIVE_UNIFIED;
   1852                 break;
   1853             case 'l':
   1854                 derive = DERIVE_LEGACY;
   1855                 break;
   1856             case 's':
   1857                 split_perms = true;
   1858                 break;
   1859             case '?':
   1860             default:
   1861                 return usage();
   1862         }
   1863     }
   1864 
   1865     for (i = optind; i < argc; i++) {
   1866         char* arg = argv[i];
   1867         if (!source_path) {
   1868             source_path = arg;
   1869         } else if (!dest_path) {
   1870             dest_path = arg;
   1871         } else if (!uid) {
   1872             uid = strtoul(arg, NULL, 10);
   1873         } else if (!gid) {
   1874             gid = strtoul(arg, NULL, 10);
   1875         } else {
   1876             ERROR("too many arguments\n");
   1877             return usage();
   1878         }
   1879     }
   1880 
   1881     if (!source_path) {
   1882         ERROR("no source path specified\n");
   1883         return usage();
   1884     }
   1885     if (!dest_path) {
   1886         ERROR("no dest path specified\n");
   1887         return usage();
   1888     }
   1889     if (!uid || !gid) {
   1890         ERROR("uid and gid must be nonzero\n");
   1891         return usage();
   1892     }
   1893     if (num_threads < 1) {
   1894         ERROR("number of threads must be at least 1\n");
   1895         return usage();
   1896     }
   1897     if (split_perms && derive == DERIVE_NONE) {
   1898         ERROR("cannot split permissions without deriving\n");
   1899         return usage();
   1900     }
   1901 
   1902     rlim.rlim_cur = 8192;
   1903     rlim.rlim_max = 8192;
   1904     if (setrlimit(RLIMIT_NOFILE, &rlim)) {
   1905         ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno);
   1906     }
   1907 
   1908     res = run(source_path, dest_path, uid, gid, write_gid, num_threads, derive, split_perms);
   1909     return res < 0 ? 1 : 0;
   1910 }
   1911