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