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