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 <ctype.h>
     29 
     30 #include <private/android_filesystem_config.h>
     31 
     32 #include "fuse.h"
     33 
     34 /* README
     35  *
     36  * What is this?
     37  *
     38  * sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
     39  * directory permissions (all files are given fixed owner, group, and
     40  * permissions at creation, owner, group, and permissions are not
     41  * changeable, symlinks and hardlinks are not createable, etc.
     42  *
     43  * usage:  sdcard <path> <uid> <gid>
     44  *
     45  * It must be run as root, but will change to uid/gid as soon as it
     46  * mounts a filesystem on /mnt/sdcard.  It will refuse to run if uid or
     47  * gid are zero.
     48  *
     49  *
     50  * Things I believe to be true:
     51  *
     52  * - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK,
     53  * CREAT) must bump that node's refcount
     54  * - don't forget that FORGET can forget multiple references (req->nlookup)
     55  * - if an op that returns a fuse_entry fails writing the reply to the
     56  * kernel, you must rollback the refcount to reflect the reference the
     57  * kernel did not actually acquire
     58  *
     59  */
     60 
     61 #define FUSE_TRACE 0
     62 
     63 #if FUSE_TRACE
     64 #define TRACE(x...) fprintf(stderr,x)
     65 #else
     66 #define TRACE(x...) do {} while (0)
     67 #endif
     68 
     69 #define ERROR(x...) fprintf(stderr,x)
     70 
     71 #define FUSE_UNKNOWN_INO 0xffffffff
     72 
     73 #define MOUNT_POINT "/mnt/sdcard"
     74 
     75 struct handle {
     76     struct node *node;
     77     int fd;
     78 };
     79 
     80 struct dirhandle {
     81     struct node *node;
     82     DIR *d;
     83 };
     84 
     85 struct node {
     86     __u64 nid;
     87     __u64 gen;
     88 
     89     struct node *next;          /* per-dir sibling list */
     90     struct node *child;         /* first contained file by this dir */
     91     struct node *all;           /* global node list */
     92     struct node *parent;        /* containing directory */
     93 
     94     __u32 refcount;
     95     __u32 namelen;
     96 
     97     char *name;
     98     /* If non-null, this is the real name of the file in the underlying storage.
     99      * This may differ from the field "name" only by case.
    100      * strlen(actual_name) will always equal strlen(name), so it is safe to use
    101      * namelen for both fields.
    102      */
    103     char *actual_name;
    104 };
    105 
    106 struct fuse {
    107     __u64 next_generation;
    108     __u64 next_node_id;
    109 
    110     int fd;
    111 
    112     struct node *all;
    113 
    114     struct node root;
    115     char rootpath[1024];
    116 };
    117 
    118 static unsigned uid = -1;
    119 static unsigned gid = -1;
    120 
    121 #define PATH_BUFFER_SIZE 1024
    122 
    123 #define NO_CASE_SENSITIVE_MATCH 0
    124 #define CASE_SENSITIVE_MATCH 1
    125 
    126 /*
    127  * Get the real-life absolute path to a node.
    128  *   node: start at this node
    129  *   buf: storage for returned string
    130  *   name: append this string to path if set
    131  */
    132 char *do_node_get_path(struct node *node, char *buf, const char *name, int match_case_insensitive)
    133 {
    134     struct node *in_node = node;
    135     const char *in_name = name;
    136     char *out = buf + PATH_BUFFER_SIZE - 1;
    137     int len;
    138     out[0] = 0;
    139 
    140     if (name) {
    141         len = strlen(name);
    142         goto start;
    143     }
    144 
    145     while (node) {
    146         name = (node->actual_name ? node->actual_name : node->name);
    147         len = node->namelen;
    148         node = node->parent;
    149     start:
    150         if ((len + 1) > (out - buf))
    151             return 0;
    152         out -= len;
    153         memcpy(out, name, len);
    154         /* avoid double slash at beginning of path */
    155         if (out[0] != '/') {
    156             out --;
    157             out[0] = '/';
    158         }
    159     }
    160 
    161     /* If we are searching for a file within node (rather than computing node's path)
    162      * and fail, then we need to look for a case insensitive match.
    163      */
    164     if (in_name && match_case_insensitive && access(out, F_OK) != 0) {
    165         char *path, buffer[PATH_BUFFER_SIZE];
    166         DIR* dir;
    167         struct dirent* entry;
    168         path = do_node_get_path(in_node, buffer, NULL, NO_CASE_SENSITIVE_MATCH);
    169         dir = opendir(path);
    170         if (!dir) {
    171             ERROR("opendir %s failed: %s", path, strerror(errno));
    172             return out;
    173         }
    174 
    175         while ((entry = readdir(dir))) {
    176             if (!strcasecmp(entry->d_name, in_name)) {
    177                 /* we have a match - replace the name */
    178                 len = strlen(in_name);
    179                 memcpy(buf + PATH_BUFFER_SIZE - len - 1, entry->d_name, len);
    180                 break;
    181             }
    182         }
    183         closedir(dir);
    184     }
    185 
    186    return out;
    187 }
    188 
    189 char *node_get_path(struct node *node, char *buf, const char *name)
    190 {
    191     /* We look for case insensitive matches by default */
    192     return do_node_get_path(node, buf, name, CASE_SENSITIVE_MATCH);
    193 }
    194 
    195 void attr_from_stat(struct fuse_attr *attr, struct stat *s)
    196 {
    197     attr->ino = s->st_ino;
    198     attr->size = s->st_size;
    199     attr->blocks = s->st_blocks;
    200     attr->atime = s->st_atime;
    201     attr->mtime = s->st_mtime;
    202     attr->ctime = s->st_ctime;
    203     attr->atimensec = s->st_atime_nsec;
    204     attr->mtimensec = s->st_mtime_nsec;
    205     attr->ctimensec = s->st_ctime_nsec;
    206     attr->mode = s->st_mode;
    207     attr->nlink = s->st_nlink;
    208 
    209         /* force permissions to something reasonable:
    210          * world readable
    211          * writable by the sdcard group
    212          */
    213     if (attr->mode & 0100) {
    214         attr->mode = (attr->mode & (~0777)) | 0775;
    215     } else {
    216         attr->mode = (attr->mode & (~0777)) | 0664;
    217     }
    218 
    219         /* all files owned by root.sdcard */
    220     attr->uid = 0;
    221     attr->gid = AID_SDCARD_RW;
    222 }
    223 
    224 int node_get_attr(struct node *node, struct fuse_attr *attr)
    225 {
    226     int res;
    227     struct stat s;
    228     char *path, buffer[PATH_BUFFER_SIZE];
    229 
    230     path = node_get_path(node, buffer, 0);
    231     res = lstat(path, &s);
    232     if (res < 0) {
    233         ERROR("lstat('%s') errno %d\n", path, errno);
    234         return -1;
    235     }
    236 
    237     attr_from_stat(attr, &s);
    238     attr->ino = node->nid;
    239 
    240     return 0;
    241 }
    242 
    243 static void add_node_to_parent(struct node *node, struct node *parent) {
    244     node->parent = parent;
    245     node->next = parent->child;
    246     parent->child = node;
    247     parent->refcount++;
    248 }
    249 
    250 /* Check to see if our parent directory already has a file with a name
    251  * that differs only by case.  If we find one, store it in the actual_name
    252  * field so node_get_path will map it to this file in the underlying storage.
    253  */
    254 static void node_find_actual_name(struct node *node)
    255 {
    256     char *path, buffer[PATH_BUFFER_SIZE];
    257     const char *node_name = node->name;
    258     DIR* dir;
    259     struct dirent* entry;
    260 
    261     if (!node->parent) return;
    262 
    263     path = node_get_path(node->parent, buffer, 0);
    264     dir = opendir(path);
    265     if (!dir) {
    266         ERROR("opendir %s failed: %s", path, strerror(errno));
    267         return;
    268     }
    269 
    270     while ((entry = readdir(dir))) {
    271         const char *test_name = entry->d_name;
    272         if (strcmp(test_name, node_name) && !strcasecmp(test_name, node_name)) {
    273             /* we have a match - differs but only by case */
    274             node->actual_name = strdup(test_name);
    275             if (!node->actual_name) {
    276                 ERROR("strdup failed - out of memory\n");
    277                 exit(1);
    278             }
    279             break;
    280         }
    281     }
    282     closedir(dir);
    283 }
    284 
    285 struct node *node_create(struct node *parent, const char *name, __u64 nid, __u64 gen)
    286 {
    287     struct node *node;
    288     int namelen = strlen(name);
    289 
    290     node = calloc(1, sizeof(struct node));
    291     if (node == 0) {
    292         return 0;
    293     }
    294     node->name = malloc(namelen + 1);
    295     if (node->name == 0) {
    296         free(node);
    297         return 0;
    298     }
    299 
    300     node->nid = nid;
    301     node->gen = gen;
    302     add_node_to_parent(node, parent);
    303     memcpy(node->name, name, namelen + 1);
    304     node->namelen = namelen;
    305     node_find_actual_name(node);
    306     return node;
    307 }
    308 
    309 static char *rename_node(struct node *node, const char *name)
    310 {
    311     node->namelen = strlen(name);
    312     char *newname = realloc(node->name, node->namelen + 1);
    313     if (newname == 0)
    314         return 0;
    315     node->name = newname;
    316     memcpy(node->name, name, node->namelen + 1);
    317     node_find_actual_name(node);
    318     return node->name;
    319 }
    320 
    321 void fuse_init(struct fuse *fuse, int fd, const char *path)
    322 {
    323     fuse->fd = fd;
    324     fuse->next_node_id = 2;
    325     fuse->next_generation = 0;
    326 
    327     fuse->all = &fuse->root;
    328 
    329     memset(&fuse->root, 0, sizeof(fuse->root));
    330     fuse->root.nid = FUSE_ROOT_ID; /* 1 */
    331     fuse->root.refcount = 2;
    332     rename_node(&fuse->root, path);
    333 }
    334 
    335 static inline void *id_to_ptr(__u64 nid)
    336 {
    337     return (void *) nid;
    338 }
    339 
    340 static inline __u64 ptr_to_id(void *ptr)
    341 {
    342     return (__u64) ptr;
    343 }
    344 
    345 
    346 struct node *lookup_by_inode(struct fuse *fuse, __u64 nid)
    347 {
    348     if (nid == FUSE_ROOT_ID) {
    349         return &fuse->root;
    350     } else {
    351         return id_to_ptr(nid);
    352     }
    353 }
    354 
    355 struct node *lookup_child_by_name(struct node *node, const char *name)
    356 {
    357     for (node = node->child; node; node = node->next) {
    358         if (!strcmp(name, node->name)) {
    359             return node;
    360         }
    361     }
    362     return 0;
    363 }
    364 
    365 struct node *lookup_child_by_inode(struct node *node, __u64 nid)
    366 {
    367     for (node = node->child; node; node = node->next) {
    368         if (node->nid == nid) {
    369             return node;
    370         }
    371     }
    372     return 0;
    373 }
    374 
    375 static void dec_refcount(struct node *node) {
    376     if (node->refcount > 0) {
    377         node->refcount--;
    378         TRACE("dec_refcount %p(%s) -> %d\n", node, node->name, node->refcount);
    379     } else {
    380         ERROR("Zero refcnt %p\n", node);
    381     }
    382  }
    383 
    384 static struct node *remove_child(struct node *parent, __u64 nid)
    385 {
    386     struct node *prev = 0;
    387     struct node *node;
    388 
    389     for (node = parent->child; node; node = node->next) {
    390         if (node->nid == nid) {
    391             if (prev) {
    392                 prev->next = node->next;
    393             } else {
    394                 parent->child = node->next;
    395             }
    396             node->next = 0;
    397             node->parent = 0;
    398             dec_refcount(parent);
    399             return node;
    400         }
    401         prev = node;
    402     }
    403     return 0;
    404 }
    405 
    406 struct node *node_lookup(struct fuse *fuse, struct node *parent, const char *name,
    407                          struct fuse_attr *attr)
    408 {
    409     int res;
    410     struct stat s;
    411     char *path, buffer[PATH_BUFFER_SIZE];
    412     struct node *node;
    413 
    414     path = node_get_path(parent, buffer, name);
    415         /* XXX error? */
    416 
    417     res = lstat(path, &s);
    418     if (res < 0)
    419         return 0;
    420 
    421     node = lookup_child_by_name(parent, name);
    422     if (!node) {
    423         node = node_create(parent, name, fuse->next_node_id++, fuse->next_generation++);
    424         if (!node)
    425             return 0;
    426         node->nid = ptr_to_id(node);
    427         node->all = fuse->all;
    428         fuse->all = node;
    429     }
    430 
    431     attr_from_stat(attr, &s);
    432     attr->ino = node->nid;
    433 
    434     return node;
    435 }
    436 
    437 void node_release(struct node *node)
    438 {
    439     TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount);
    440     dec_refcount(node);
    441     if (node->refcount == 0) {
    442         if (node->parent->child == node) {
    443             node->parent->child = node->parent->child->next;
    444         } else {
    445             struct node *node2;
    446 
    447             node2 = node->parent->child;
    448             while (node2->next != node)
    449                 node2 = node2->next;
    450             node2->next = node->next;
    451         }
    452 
    453         TRACE("DESTROY %p (%s)\n", node, node->name);
    454 
    455         node_release(node->parent);
    456 
    457         node->parent = 0;
    458         node->next = 0;
    459 
    460             /* TODO: remove debugging - poison memory */
    461         memset(node->name, 0xef, node->namelen);
    462         free(node->name);
    463         free(node->actual_name);
    464         memset(node, 0xfc, sizeof(*node));
    465         free(node);
    466     }
    467 }
    468 
    469 void fuse_status(struct fuse *fuse, __u64 unique, int err)
    470 {
    471     struct fuse_out_header hdr;
    472     hdr.len = sizeof(hdr);
    473     hdr.error = err;
    474     hdr.unique = unique;
    475     if (err) {
    476 //        ERROR("*** %d ***\n", err);
    477     }
    478     write(fuse->fd, &hdr, sizeof(hdr));
    479 }
    480 
    481 void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
    482 {
    483     struct fuse_out_header hdr;
    484     struct iovec vec[2];
    485     int res;
    486 
    487     hdr.len = len + sizeof(hdr);
    488     hdr.error = 0;
    489     hdr.unique = unique;
    490 
    491     vec[0].iov_base = &hdr;
    492     vec[0].iov_len = sizeof(hdr);
    493     vec[1].iov_base = data;
    494     vec[1].iov_len = len;
    495 
    496     res = writev(fuse->fd, vec, 2);
    497     if (res < 0) {
    498         ERROR("*** REPLY FAILED *** %d\n", errno);
    499     }
    500 }
    501 
    502 void lookup_entry(struct fuse *fuse, struct node *node,
    503                   const char *name, __u64 unique)
    504 {
    505     struct fuse_entry_out out;
    506 
    507     memset(&out, 0, sizeof(out));
    508 
    509     node = node_lookup(fuse, node, name, &out.attr);
    510     if (!node) {
    511         fuse_status(fuse, unique, -ENOENT);
    512         return;
    513     }
    514 
    515     node->refcount++;
    516 //    fprintf(stderr,"ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount);
    517     out.nodeid = node->nid;
    518     out.generation = node->gen;
    519     out.entry_valid = 10;
    520     out.attr_valid = 10;
    521 
    522     fuse_reply(fuse, unique, &out, sizeof(out));
    523 }
    524 
    525 void handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *data, unsigned len)
    526 {
    527     struct node *node;
    528 
    529     if ((len < sizeof(*hdr)) || (hdr->len != len)) {
    530         ERROR("malformed header\n");
    531         return;
    532     }
    533 
    534     len -= hdr->len;
    535 
    536     if (hdr->nodeid) {
    537         node = lookup_by_inode(fuse, hdr->nodeid);
    538         if (!node) {
    539             fuse_status(fuse, hdr->unique, -ENOENT);
    540             return;
    541         }
    542     } else {
    543         node = 0;
    544     }
    545 
    546     switch (hdr->opcode) {
    547     case FUSE_LOOKUP: { /* bytez[] -> entry_out */
    548         TRACE("LOOKUP %llx %s\n", hdr->nodeid, (char*) data);
    549         lookup_entry(fuse, node, (char*) data, hdr->unique);
    550         return;
    551     }
    552     case FUSE_FORGET: {
    553         struct fuse_forget_in *req = data;
    554         TRACE("FORGET %llx (%s) #%lld\n", hdr->nodeid, node->name, req->nlookup);
    555             /* no reply */
    556         while (req->nlookup--)
    557             node_release(node);
    558         return;
    559     }
    560     case FUSE_GETATTR: { /* getattr_in -> attr_out */
    561         struct fuse_getattr_in *req = data;
    562         struct fuse_attr_out out;
    563 
    564         TRACE("GETATTR flags=%x fh=%llx\n", req->getattr_flags, req->fh);
    565 
    566         memset(&out, 0, sizeof(out));
    567         node_get_attr(node, &out.attr);
    568         out.attr_valid = 10;
    569 
    570         fuse_reply(fuse, hdr->unique, &out, sizeof(out));
    571         return;
    572     }
    573     case FUSE_SETATTR: { /* setattr_in -> attr_out */
    574         struct fuse_setattr_in *req = data;
    575         struct fuse_attr_out out;
    576         char *path, buffer[PATH_BUFFER_SIZE];
    577         int res = 0;
    578         struct timespec times[2];
    579 
    580         TRACE("SETATTR fh=%llx id=%llx valid=%x\n",
    581               req->fh, hdr->nodeid, req->valid);
    582 
    583         /* XXX: incomplete implementation on purpose.   chmod/chown
    584          * should NEVER be implemented.*/
    585 
    586         path = node_get_path(node, buffer, 0);
    587         if (req->valid & FATTR_SIZE)
    588             res = truncate(path, req->size);
    589         if (res)
    590             goto getout;
    591 
    592         /* Handle changing atime and mtime.  If FATTR_ATIME_and FATTR_ATIME_NOW
    593          * are both set, then set it to the current time.  Else, set it to the
    594          * time specified in the request.  Same goes for mtime.  Use utimensat(2)
    595          * as it allows ATIME and MTIME to be changed independently, and has
    596          * nanosecond resolution which fuse also has.
    597          */
    598         if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
    599             times[0].tv_nsec = UTIME_OMIT;
    600             times[1].tv_nsec = UTIME_OMIT;
    601             if (req->valid & FATTR_ATIME) {
    602                 if (req->valid & FATTR_ATIME_NOW) {
    603                   times[0].tv_nsec = UTIME_NOW;
    604                 } else {
    605                   times[0].tv_sec = req->atime;
    606                   times[0].tv_nsec = req->atimensec;
    607                 }
    608             }
    609             if (req->valid & FATTR_MTIME) {
    610                 if (req->valid & FATTR_MTIME_NOW) {
    611                   times[1].tv_nsec = UTIME_NOW;
    612                 } else {
    613                   times[1].tv_sec = req->mtime;
    614                   times[1].tv_nsec = req->mtimensec;
    615                 }
    616             }
    617             TRACE("Calling utimensat on %s with atime %ld, mtime=%ld\n", path, times[0].tv_sec, times[1].tv_sec);
    618             res = utimensat(-1, path, times, 0);
    619         }
    620 
    621         getout:
    622         memset(&out, 0, sizeof(out));
    623         node_get_attr(node, &out.attr);
    624         out.attr_valid = 10;
    625 
    626         if (res)
    627             fuse_status(fuse, hdr->unique, -errno);
    628         else
    629             fuse_reply(fuse, hdr->unique, &out, sizeof(out));
    630         return;
    631     }
    632 //    case FUSE_READLINK:
    633 //    case FUSE_SYMLINK:
    634     case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
    635         struct fuse_mknod_in *req = data;
    636         char *path, buffer[PATH_BUFFER_SIZE];
    637         char *name = ((char*) data) + sizeof(*req);
    638         int res;
    639 
    640         TRACE("MKNOD %s @ %llx\n", name, hdr->nodeid);
    641         path = node_get_path(node, buffer, name);
    642 
    643         req->mode = (req->mode & (~0777)) | 0664;
    644         res = mknod(path, req->mode, req->rdev); /* XXX perm?*/
    645         if (res < 0) {
    646             fuse_status(fuse, hdr->unique, -errno);
    647         } else {
    648             lookup_entry(fuse, node, name, hdr->unique);
    649         }
    650         return;
    651     }
    652     case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
    653         struct fuse_mkdir_in *req = data;
    654         struct fuse_entry_out out;
    655         char *path, buffer[PATH_BUFFER_SIZE];
    656         char *name = ((char*) data) + sizeof(*req);
    657         int res;
    658 
    659         TRACE("MKDIR %s @ %llx 0%o\n", name, hdr->nodeid, req->mode);
    660         path = node_get_path(node, buffer, name);
    661 
    662         req->mode = (req->mode & (~0777)) | 0775;
    663         res = mkdir(path, req->mode);
    664         if (res < 0) {
    665             fuse_status(fuse, hdr->unique, -errno);
    666         } else {
    667             lookup_entry(fuse, node, name, hdr->unique);
    668         }
    669         return;
    670     }
    671     case FUSE_UNLINK: { /* bytez[] -> */
    672         char *path, buffer[PATH_BUFFER_SIZE];
    673         int res;
    674         TRACE("UNLINK %s @ %llx\n", (char*) data, hdr->nodeid);
    675         path = node_get_path(node, buffer, (char*) data);
    676         res = unlink(path);
    677         fuse_status(fuse, hdr->unique, res ? -errno : 0);
    678         return;
    679     }
    680     case FUSE_RMDIR: { /* bytez[] -> */
    681         char *path, buffer[PATH_BUFFER_SIZE];
    682         int res;
    683         TRACE("RMDIR %s @ %llx\n", (char*) data, hdr->nodeid);
    684         path = node_get_path(node, buffer, (char*) data);
    685         res = rmdir(path);
    686         fuse_status(fuse, hdr->unique, res ? -errno : 0);
    687         return;
    688     }
    689     case FUSE_RENAME: { /* rename_in, oldname, newname ->  */
    690         struct fuse_rename_in *req = data;
    691         char *oldname = ((char*) data) + sizeof(*req);
    692         char *newname = oldname + strlen(oldname) + 1;
    693         char *oldpath, oldbuffer[PATH_BUFFER_SIZE];
    694         char *newpath, newbuffer[PATH_BUFFER_SIZE];
    695         struct node *target;
    696         struct node *newparent;
    697         int res;
    698 
    699         TRACE("RENAME %s->%s @ %llx\n", oldname, newname, hdr->nodeid);
    700 
    701         target = lookup_child_by_name(node, oldname);
    702         if (!target) {
    703             fuse_status(fuse, hdr->unique, -ENOENT);
    704             return;
    705         }
    706         oldpath = node_get_path(node, oldbuffer, oldname);
    707 
    708         newparent = lookup_by_inode(fuse, req->newdir);
    709         if (!newparent) {
    710             fuse_status(fuse, hdr->unique, -ENOENT);
    711             return;
    712         }
    713         if (newparent == node) {
    714             /* Special case for renaming a file where destination
    715              * is same path differing only by case.
    716              * In this case we don't want to look for a case insensitive match.
    717              * This allows commands like "mv foo FOO" to work as expected.
    718              */
    719             newpath = do_node_get_path(newparent, newbuffer, newname, NO_CASE_SENSITIVE_MATCH);
    720         } else {
    721             newpath = node_get_path(newparent, newbuffer, newname);
    722         }
    723 
    724         if (!remove_child(node, target->nid)) {
    725             ERROR("RENAME remove_child not found");
    726             fuse_status(fuse, hdr->unique, -ENOENT);
    727             return;
    728         }
    729         if (!rename_node(target, newname)) {
    730             fuse_status(fuse, hdr->unique, -ENOMEM);
    731             return;
    732         }
    733         add_node_to_parent(target, newparent);
    734 
    735         res = rename(oldpath, newpath);
    736         TRACE("RENAME result %d\n", res);
    737 
    738         fuse_status(fuse, hdr->unique, res ? -errno : 0);
    739         return;
    740     }
    741 //    case FUSE_LINK:
    742     case FUSE_OPEN: { /* open_in -> open_out */
    743         struct fuse_open_in *req = data;
    744         struct fuse_open_out out;
    745         char *path, buffer[PATH_BUFFER_SIZE];
    746         struct handle *h;
    747 
    748         h = malloc(sizeof(*h));
    749         if (!h) {
    750             fuse_status(fuse, hdr->unique, -ENOMEM);
    751             return;
    752         }
    753 
    754         path = node_get_path(node, buffer, 0);
    755         TRACE("OPEN %llx '%s' 0%o fh=%p\n", hdr->nodeid, path, req->flags, h);
    756         h->fd = open(path, req->flags);
    757         if (h->fd < 0) {
    758             ERROR("ERROR\n");
    759             fuse_status(fuse, hdr->unique, -errno);
    760             free(h);
    761             return;
    762         }
    763         out.fh = ptr_to_id(h);
    764         out.open_flags = 0;
    765         out.padding = 0;
    766         fuse_reply(fuse, hdr->unique, &out, sizeof(out));
    767         return;
    768     }
    769     case FUSE_READ: { /* read_in -> byte[] */
    770         char buffer[128 * 1024];
    771         struct fuse_read_in *req = data;
    772         struct handle *h = id_to_ptr(req->fh);
    773         int res;
    774         TRACE("READ %p(%d) %u@%llu\n", h, h->fd, req->size, req->offset);
    775         if (req->size > sizeof(buffer)) {
    776             fuse_status(fuse, hdr->unique, -EINVAL);
    777             return;
    778         }
    779         res = pread64(h->fd, buffer, req->size, req->offset);
    780         if (res < 0) {
    781             fuse_status(fuse, hdr->unique, -errno);
    782             return;
    783         }
    784         fuse_reply(fuse, hdr->unique, buffer, res);
    785         return;
    786     }
    787     case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
    788         struct fuse_write_in *req = data;
    789         struct fuse_write_out out;
    790         struct handle *h = id_to_ptr(req->fh);
    791         int res;
    792         TRACE("WRITE %p(%d) %u@%llu\n", h, h->fd, req->size, req->offset);
    793         res = pwrite64(h->fd, ((char*) data) + sizeof(*req), req->size, req->offset);
    794         if (res < 0) {
    795             fuse_status(fuse, hdr->unique, -errno);
    796             return;
    797         }
    798         out.size = res;
    799         fuse_reply(fuse, hdr->unique, &out, sizeof(out));
    800         goto oops;
    801     }
    802     case FUSE_STATFS: { /* getattr_in -> attr_out */
    803         struct statfs stat;
    804         struct fuse_statfs_out out;
    805         int res;
    806 
    807         TRACE("STATFS\n");
    808 
    809         if (statfs(fuse->root.name, &stat)) {
    810             fuse_status(fuse, hdr->unique, -errno);
    811             return;
    812         }
    813 
    814         memset(&out, 0, sizeof(out));
    815         out.st.blocks = stat.f_blocks;
    816         out.st.bfree = stat.f_bfree;
    817         out.st.bavail = stat.f_bavail;
    818         out.st.files = stat.f_files;
    819         out.st.ffree = stat.f_ffree;
    820         out.st.bsize = stat.f_bsize;
    821         out.st.namelen = stat.f_namelen;
    822         out.st.frsize = stat.f_frsize;
    823         fuse_reply(fuse, hdr->unique, &out, sizeof(out));
    824         return;
    825     }
    826     case FUSE_RELEASE: { /* release_in -> */
    827         struct fuse_release_in *req = data;
    828         struct handle *h = id_to_ptr(req->fh);
    829         TRACE("RELEASE %p(%d)\n", h, h->fd);
    830         close(h->fd);
    831         free(h);
    832         fuse_status(fuse, hdr->unique, 0);
    833         return;
    834     }
    835 //    case FUSE_FSYNC:
    836 //    case FUSE_SETXATTR:
    837 //    case FUSE_GETXATTR:
    838 //    case FUSE_LISTXATTR:
    839 //    case FUSE_REMOVEXATTR:
    840     case FUSE_FLUSH:
    841         fuse_status(fuse, hdr->unique, 0);
    842         return;
    843     case FUSE_OPENDIR: { /* open_in -> open_out */
    844         struct fuse_open_in *req = data;
    845         struct fuse_open_out out;
    846         char *path, buffer[PATH_BUFFER_SIZE];
    847         struct dirhandle *h;
    848 
    849         h = malloc(sizeof(*h));
    850         if (!h) {
    851             fuse_status(fuse, hdr->unique, -ENOMEM);
    852             return;
    853         }
    854 
    855         path = node_get_path(node, buffer, 0);
    856         TRACE("OPENDIR %llx '%s'\n", hdr->nodeid, path);
    857         h->d = opendir(path);
    858         if (h->d == 0) {
    859             ERROR("ERROR\n");
    860             fuse_status(fuse, hdr->unique, -errno);
    861             free(h);
    862             return;
    863         }
    864         out.fh = ptr_to_id(h);
    865         fuse_reply(fuse, hdr->unique, &out, sizeof(out));
    866         return;
    867     }
    868     case FUSE_READDIR: {
    869         struct fuse_read_in *req = data;
    870         char buffer[8192];
    871         struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
    872         struct dirent *de;
    873         struct dirhandle *h = id_to_ptr(req->fh);
    874         TRACE("READDIR %p\n", h);
    875         if (req->offset == 0) {
    876             /* rewinddir() might have been called above us, so rewind here too */
    877             TRACE("calling rewinddir()\n");
    878             rewinddir(h->d);
    879         }
    880         de = readdir(h->d);
    881         if (!de) {
    882             fuse_status(fuse, hdr->unique, 0);
    883             return;
    884         }
    885         fde->ino = FUSE_UNKNOWN_INO;
    886         /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
    887         fde->off = req->offset + 1;
    888         fde->type = de->d_type;
    889         fde->namelen = strlen(de->d_name);
    890         memcpy(fde->name, de->d_name, fde->namelen + 1);
    891         fuse_reply(fuse, hdr->unique, fde,
    892                    FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
    893         return;
    894     }
    895     case FUSE_RELEASEDIR: { /* release_in -> */
    896         struct fuse_release_in *req = data;
    897         struct dirhandle *h = id_to_ptr(req->fh);
    898         TRACE("RELEASEDIR %p\n",h);
    899         closedir(h->d);
    900         free(h);
    901         fuse_status(fuse, hdr->unique, 0);
    902         return;
    903     }
    904 //    case FUSE_FSYNCDIR:
    905     case FUSE_INIT: { /* init_in -> init_out */
    906         struct fuse_init_in *req = data;
    907         struct fuse_init_out out;
    908 
    909         TRACE("INIT ver=%d.%d maxread=%d flags=%x\n",
    910                 req->major, req->minor, req->max_readahead, req->flags);
    911 
    912         out.major = FUSE_KERNEL_VERSION;
    913         out.minor = FUSE_KERNEL_MINOR_VERSION;
    914         out.max_readahead = req->max_readahead;
    915         out.flags = FUSE_ATOMIC_O_TRUNC;
    916         out.max_background = 32;
    917         out.congestion_threshold = 32;
    918         out.max_write = 256 * 1024;
    919 
    920         fuse_reply(fuse, hdr->unique, &out, sizeof(out));
    921         return;
    922     }
    923     default: {
    924         struct fuse_out_header h;
    925         ERROR("NOTIMPL op=%d uniq=%llx nid=%llx\n",
    926                 hdr->opcode, hdr->unique, hdr->nodeid);
    927 
    928         oops:
    929         h.len = sizeof(h);
    930         h.error = -ENOSYS;
    931         h.unique = hdr->unique;
    932         write(fuse->fd, &h, sizeof(h));
    933         break;
    934     }
    935     }
    936 }
    937 
    938 void handle_fuse_requests(struct fuse *fuse)
    939 {
    940     unsigned char req[256 * 1024 + 128];
    941     int len;
    942 
    943     for (;;) {
    944         len = read(fuse->fd, req, 8192);
    945         if (len < 0) {
    946             if (errno == EINTR)
    947                 continue;
    948             ERROR("handle_fuse_requests: errno=%d\n", errno);
    949             return;
    950         }
    951         handle_fuse_request(fuse, (void*) req, (void*) (req + sizeof(struct fuse_in_header)), len);
    952     }
    953 }
    954 
    955 static int usage()
    956 {
    957     ERROR("usage: sdcard [-l -f] <path> <uid> <gid>\n\n\t-l force file names to lower case when creating new files\n\t-f fix up file system before starting (repairs bad file name case and group ownership)\n");
    958     return -1;
    959 }
    960 
    961 int main(int argc, char **argv)
    962 {
    963     struct fuse fuse;
    964     char opts[256];
    965     int fd;
    966     int res;
    967     const char *path = NULL;
    968     int i;
    969 
    970     for (i = 1; i < argc; i++) {
    971         char* arg = argv[i];
    972         if (!path)
    973             path = arg;
    974         else if (uid == -1)
    975             uid = strtoul(arg, 0, 10);
    976         else if (gid == -1)
    977             gid = strtoul(arg, 0, 10);
    978         else {
    979             ERROR("too many arguments\n");
    980             return usage();
    981         }
    982     }
    983 
    984     if (!path) {
    985         ERROR("no path specified\n");
    986         return usage();
    987     }
    988     if (uid <= 0 || gid <= 0) {
    989         ERROR("uid and gid must be nonzero\n");
    990         return usage();
    991     }
    992 
    993         /* cleanup from previous instance, if necessary */
    994     umount2(MOUNT_POINT, 2);
    995 
    996     fd = open("/dev/fuse", O_RDWR);
    997     if (fd < 0){
    998         ERROR("cannot open fuse device (%d)\n", errno);
    999         return -1;
   1000     }
   1001 
   1002     sprintf(opts, "fd=%i,rootmode=40000,default_permissions,allow_other,"
   1003             "user_id=%d,group_id=%d", fd, uid, gid);
   1004 
   1005     res = mount("/dev/fuse", MOUNT_POINT, "fuse", MS_NOSUID | MS_NODEV, opts);
   1006     if (res < 0) {
   1007         ERROR("cannot mount fuse filesystem (%d)\n", errno);
   1008         return -1;
   1009     }
   1010 
   1011     if (setgid(gid) < 0) {
   1012         ERROR("cannot setgid!\n");
   1013         return -1;
   1014     }
   1015     if (setuid(uid) < 0) {
   1016         ERROR("cannot setuid!\n");
   1017         return -1;
   1018     }
   1019 
   1020     fuse_init(&fuse, fd, path);
   1021 
   1022     umask(0);
   1023     handle_fuse_requests(&fuse);
   1024 
   1025     return 0;
   1026 }
   1027