sdcard.c revision f38f29c87d97cea45d04b783bddbd969234b1030
103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland/*
203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * Copyright (C) 2010 The Android Open Source Project
303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * Licensed under the Apache License, Version 2.0 (the "License");
503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * you may not use this file except in compliance with the License.
603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * You may obtain a copy of the License at
703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *      http://www.apache.org/licenses/LICENSE-2.0
903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
1003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * Unless required by applicable law or agreed to in writing, software
1103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * distributed under the License is distributed on an "AS IS" BASIS,
1203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * See the License for the specific language governing permissions and
1403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * limitations under the License.
1503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland */
1603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
17300d5649800744b3f5eab478f2bd7921f584b07dElliott Hughes#define LOG_TAG "sdcard"
18300d5649800744b3f5eab478f2bd7921f584b07dElliott Hughes
1960281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes#include <ctype.h>
2060281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes#include <dirent.h>
2160281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes#include <errno.h>
2260281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes#include <fcntl.h>
23e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland#include <inttypes.h>
2460281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes#include <limits.h>
2560281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes#include <linux/fuse.h>
2660281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes#include <pthread.h>
2703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <stdio.h>
2803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <stdlib.h>
2903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <string.h>
3060281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes#include <sys/inotify.h>
3103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <sys/mount.h>
32ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris#include <sys/param.h>
3360281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes#include <sys/resource.h>
3403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <sys/stat.h>
354553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood#include <sys/statfs.h>
362fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall#include <sys/time.h>
3760281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes#include <sys/uio.h>
3860281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes#include <unistd.h>
39dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
4044d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey#include <cutils/fs.h>
41dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey#include <cutils/hashmap.h>
42300d5649800744b3f5eab478f2bd7921f584b07dElliott Hughes#include <cutils/log.h>
43dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey#include <cutils/multiuser.h>
4403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
45b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland#include <private/android_filesystem_config.h>
46b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland
4703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland/* README
4803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
4903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * What is this?
5060281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes *
5103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
5260281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes * directory permissions (all files are given fixed owner, group, and
5360281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes * permissions at creation, owner, group, and permissions are not
5403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * changeable, symlinks and hardlinks are not createable, etc.
5503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
56e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey * See usage() for command line options.
5703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
58e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey * It must be run as root, but will drop to requested UID/GID as soon as it
59e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey * mounts a filesystem.  It will refuse to run if requested UID/GID are zero.
6003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
6103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * Things I believe to be true:
6203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
6303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK,
6403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * CREAT) must bump that node's refcount
6503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - don't forget that FORGET can forget multiple references (req->nlookup)
6603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - if an op that returns a fuse_entry fails writing the reply to the
6703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * kernel, you must rollback the refcount to reflect the reference the
6803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * kernel did not actually acquire
69dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey *
70dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey * This daemon can also derive custom filesystem permissions based on directory
71dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey * structure when requested. These custom permissions support several features:
72dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey *
73dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey * - Apps can access their own files in /Android/data/com.example/ without
74dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey * requiring any additional GIDs.
75dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey * - Separate permissions for protecting directories like Pictures and Music.
76dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey * - Multi-user separation on the same physical device.
7703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland */
7803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
7903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define FUSE_TRACE 0
8003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
8103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#if FUSE_TRACE
82300d5649800744b3f5eab478f2bd7921f584b07dElliott Hughes#define TRACE(x...) ALOGD(x)
8303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#else
8403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define TRACE(x...) do {} while (0)
8503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#endif
8603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
87300d5649800744b3f5eab478f2bd7921f584b07dElliott Hughes#define ERROR(x...) ALOGE(x)
8803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
8903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define FUSE_UNKNOWN_INO 0xffffffff
9003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
91847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Maximum number of bytes to write in one request. */
92847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_WRITE (256 * 1024)
93847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
94847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Maximum number of bytes to read in one request. */
95847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_READ (128 * 1024)
96847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
97847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Largest possible request.
98847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown * The request size is bounded by the maximum size of a FUSE_WRITE request because it has
99847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown * the largest possible data payload. */
100847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_REQUEST_SIZE (sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE)
101847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Pseudo-error constant used to indicate that no fuse status is needed
1036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or that a reply has already been written. */
1046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown#define NO_STATUS 1
1056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
106dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey/* Path to system-provided mapping of package name to appIds */
107dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkeystatic const char* const kPackagesListFile = "/data/system/packages.list";
108dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
109dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey/* Supplementary groups to execute with */
110dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkeystatic const gid_t kGroups[1] = { AID_PACKAGE_INFO };
111dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
112dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey/* Permission mode for a specific node. Controls how file permissions
113dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey * are derived for children nodes. */
114dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkeytypedef enum {
115977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* Nothing special; this node should just inherit from its parent. */
116dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    PERM_INHERIT,
117977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* This node is one level above a normal root; used for legacy layouts
118977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey     * which use the first level to represent user_id. */
119f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    PERM_PRE_ROOT,
120977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* This node is "/" */
121dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    PERM_ROOT,
122977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* This node is "/Android" */
123dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    PERM_ANDROID,
124977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* This node is "/Android/data" */
125dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    PERM_ANDROID_DATA,
126977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* This node is "/Android/obb" */
127dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    PERM_ANDROID_OBB,
1282e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey    /* This node is "/Android/media" */
1292e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey    PERM_ANDROID_MEDIA,
130dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey} perm_t;
131dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
13203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct handle {
13303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int fd;
13403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
13503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
13603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct dirhandle {
13703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    DIR *d;
13803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
13903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
14003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct node {
1416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    __u32 refcount;
14203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    __u64 nid;
14303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    __u64 gen;
144faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    /*
145faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * The inode number for this FUSE node. Note that this isn't stable across
146faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * multiple invocations of the FUSE daemon.
147faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     */
148faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    __u32 ino;
14903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
150dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    /* State derived based on current position in hierarchy. */
151dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    perm_t perm;
152dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    userid_t userid;
153dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    uid_t uid;
154dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    gid_t gid;
155dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    mode_t mode;
156dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
15711ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    struct node *next;          /* per-dir sibling list */
15811ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    struct node *child;         /* first contained file by this dir */
15911ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    struct node *parent;        /* containing directory */
16003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen;
16211ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    char *name;
163575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood    /* If non-null, this is the real name of the file in the underlying storage.
164575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     * This may differ from the field "name" only by case.
165575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     * strlen(actual_name) will always equal strlen(name), so it is safe to use
166575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     * namelen for both fields.
167575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     */
168575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood    char *actual_name;
169977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
170977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* If non-null, an exact underlying path that should be grafted into this
171977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey     * position. Used to support things like OBB. */
172977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    char* graft_path;
173977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    size_t graft_pathlen;
174c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski
175c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    bool deleted;
17603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
17703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
178dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkeystatic int str_hash(void *key) {
179dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    return hashmapHash(key, strlen(key));
180dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey}
181dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
18244d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey/** Test if two string keys are equal ignoring case */
18344d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkeystatic bool str_icase_equals(void *keyA, void *keyB) {
18444d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    return strcasecmp(keyA, keyB) == 0;
185dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey}
186dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
187977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic int int_hash(void *key) {
1885d9fe779c8ec2705865a23061834ad8cdbee5b82Elliott Hughes    return (int) (uintptr_t) key;
189977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey}
190977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
191977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic bool int_equals(void *keyA, void *keyB) {
192977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    return keyA == keyB;
193977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey}
194977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
195f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey/* Global data for all FUSE mounts */
196f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkeystruct fuse_global {
1976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_t lock;
19803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
199f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    uid_t uid;
200f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    gid_t gid;
201f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    bool multi_user;
202f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
203f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    Hashmap* package_to_appid;
204f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey};
205f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
206f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey/* Single FUSE mount */
207f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkeystruct fuse {
208f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    struct fuse_global* global;
209f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
210f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    char source_path[PATH_MAX];
211f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    char dest_path[PATH_MAX];
212f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    char obb_path[PATH_MAX];
213f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
2146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    __u64 next_generation;
21503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int fd;
21603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct node root;
217f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    gid_t gid;
218f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    mode_t mask;
219dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
220faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    /* Used to allocate unique inode numbers for fuse nodes. We use
221faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * a simple counter based scheme where inode numbers from deleted
222faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * nodes aren't reused. Note that inode allocations are not stable
223faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * across multiple invocation of the sdcard daemon, but that shouldn't
224faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * be a huge problem in practice.
225faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     *
226faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * Note that we restrict inodes to 32 bit unsigned integers to prevent
227faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * truncation on 32 bit processes when unsigned long long stat.st_ino is
228faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * assigned to an unsigned long ino_t type in an LP32 process.
229faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     *
230faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * Also note that fuse_attr and fuse_dirent inode values are 64 bits wide
231faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * on both LP32 and LP64, but the fuse kernel code doesn't squash 64 bit
232faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * inode numbers into 32 bit values on 64 bit kernels (see fuse_squash_ino
233faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * in fs/fuse/inode.c).
234faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     *
235faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * Accesses must be guarded by |lock|.
236faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     */
237faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    __u32 inode_ctr;
23803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
23903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
240f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey/* Private data used by a single FUSE handler */
2417729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brownstruct fuse_handler {
2426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse* fuse;
2436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int token;
2446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2457729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    /* To save memory, we never use the contents of the request buffer and the read
2467729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown     * buffer at the same time.  This allows us to share the underlying storage. */
2477729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    union {
2487729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        __u8 request_buffer[MAX_REQUEST_SIZE];
24980b435a3f35795600654e9705f4b3fbbcc427a9dArpad Horvath        __u8 read_buffer[MAX_READ + PAGESIZE];
2507729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    };
2517729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown};
25203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
2536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic inline void *id_to_ptr(__u64 nid)
2546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
2556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return (void *) (uintptr_t) nid;
2566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
257b94d320b1e7e2a3493147f6763cd2825b111a4d8Mike Lockwood
2586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic inline __u64 ptr_to_id(void *ptr)
2596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
2606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return (__u64) (uintptr_t) ptr;
2616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
2626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void acquire_node_locked(struct node* node)
2646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
2656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->refcount++;
2666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount);
2676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
2686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void remove_node_from_parent_locked(struct node* node);
2706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void release_node_locked(struct node* node)
2726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
2736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount);
2746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node->refcount > 0) {
2756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->refcount--;
2766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->refcount) {
2776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            TRACE("DESTROY %p (%s)\n", node, node->name);
2786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            remove_node_from_parent_locked(node);
2796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                /* TODO: remove debugging - poison memory */
2816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            memset(node->name, 0xef, node->namelen);
2826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->name);
2836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->actual_name);
2846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            memset(node, 0xfc, sizeof(*node));
2856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node);
2866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
2876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
2886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        ERROR("Zero refcnt %p\n", node);
2896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
2906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
2916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void add_node_to_parent_locked(struct node *node, struct node *parent) {
2936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->parent = parent;
2946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->next = parent->child;
2956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent->child = node;
2966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(parent);
2976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
2986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void remove_node_from_parent_locked(struct node* node)
3006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
3016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node->parent) {
3026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (node->parent->child == node) {
3036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->parent->child = node->parent->child->next;
3046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        } else {
3056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            struct node *node2;
3066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node2 = node->parent->child;
3076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            while (node2->next != node)
3086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                node2 = node2->next;
3096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node2->next = node->next;
3106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
3116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        release_node_locked(node->parent);
3126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->parent = NULL;
3136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->next = NULL;
3146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
3156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
3166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Gets the absolute path to a node into the provided buffer.
3186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown *
3196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Populates 'buf' with the path and returns the length of the path on success,
3206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or returns -1 if the path is too long for the provided buffer.
321f43219e0b1022b257499289ceb951f6a1a44bf9cPaul Eastham */
322977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize) {
323977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    const char* name;
324977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    size_t namelen;
325977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    if (node->graft_path) {
326977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        name = node->graft_path;
327977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        namelen = node->graft_pathlen;
328977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    } else if (node->actual_name) {
329977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        name = node->actual_name;
330977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        namelen = node->namelen;
331977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    } else {
332977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        name = node->name;
333977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        namelen = node->namelen;
334977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
335977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
3366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (bufsize < namelen + 1) {
3376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -1;
3386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
3396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    ssize_t pathlen = 0;
341977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    if (node->parent && node->graft_path == NULL) {
3426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 2);
3436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (pathlen < 0) {
3446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -1;
345575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
3466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        buf[pathlen++] = '/';
34703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
34803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
3506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return pathlen + namelen;
3516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
3526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Finds the absolute path of a file within a given directory.
3546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Performs a case-insensitive search for the file and sets the buffer to the path
3556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * of the first matching file.  If 'search' is zero or if no match is found, sets
3566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * the buffer to the path that the file would have, assuming the name were case-sensitive.
3576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown *
3586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Populates 'buf' with the path and returns the actual name (within 'buf') on success,
3596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or returns NULL if the path is too long for the provided buffer.
3606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown */
3616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic char* find_file_within(const char* path, const char* name,
3626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* buf, size_t bufsize, int search)
3636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
3646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t pathlen = strlen(path);
3656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
3666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t childlen = pathlen + namelen + 1;
3676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char* actual;
3686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (bufsize <= childlen) {
3706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
3716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
3726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(buf, path, pathlen);
3746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    buf[pathlen] = '/';
3756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    actual = buf + pathlen + 1;
3766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(actual, name, namelen + 1);
3776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (search && access(buf, F_OK)) {
379575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        struct dirent* entry;
3806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        DIR* dir = opendir(path);
381575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        if (!dir) {
382dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            ERROR("opendir %s failed: %s\n", path, strerror(errno));
3836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return actual;
384575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
385575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        while ((entry = readdir(dir))) {
3866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!strcasecmp(entry->d_name, name)) {
3876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                /* we have a match - replace the name, don't need to copy the null again */
3886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                memcpy(actual, entry->d_name, namelen);
389575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood                break;
390575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            }
391575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
392575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        closedir(dir);
393575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood    }
3946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return actual;
395575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood}
396575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood
397dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkeystatic void attr_from_stat(struct fuse_attr *attr, const struct stat *s, const struct node* node)
398575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood{
399faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    attr->ino = node->ino;
40003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->size = s->st_size;
40103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->blocks = s->st_blocks;
402f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->atime = s->st_atim.tv_sec;
403f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->mtime = s->st_mtim.tv_sec;
404f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->ctime = s->st_ctim.tv_sec;
405f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->atimensec = s->st_atim.tv_nsec;
406f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->mtimensec = s->st_mtim.tv_nsec;
407f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->ctimensec = s->st_ctim.tv_nsec;
40803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->mode = s->st_mode;
40903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->nlink = s->st_nlink;
41003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
411dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    attr->uid = node->uid;
412dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    attr->gid = node->gid;
413b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland
414dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    /* Filter requested mode based on underlying file, and
415dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey     * pass through file type. */
416dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    int owner_mode = s->st_mode & 0700;
417dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    int filtered_mode = node->mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
418dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    attr->mode = (attr->mode & S_IFMT) | filtered_mode;
419dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey}
420dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
42144d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkeystatic int touch(char* path, mode_t mode) {
42244d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    int fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, mode);
42344d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    if (fd == -1) {
42444d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (errno == EEXIST) {
42544d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            return 0;
42644d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        } else {
42744d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            ERROR("Failed to open(%s): %s\n", path, strerror(errno));
42844d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            return -1;
42944d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        }
43044d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    }
43144d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    close(fd);
43244d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    return 0;
43344d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey}
43444d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey
435dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkeystatic void derive_permissions_locked(struct fuse* fuse, struct node *parent,
436dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        struct node *node) {
437977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    appid_t appid;
438dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
439dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    /* By default, each node inherits from its parent */
440dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    node->perm = PERM_INHERIT;
441dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    node->userid = parent->userid;
442dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    node->uid = parent->uid;
443dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    node->gid = parent->gid;
444dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    node->mode = parent->mode;
445dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
446dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    /* Derive custom permissions based on parent and current node */
447dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    switch (parent->perm) {
448dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    case PERM_INHERIT:
449dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        /* Already inherited above */
450dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        break;
451f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    case PERM_PRE_ROOT:
452977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        /* Legacy internal layout places users at top level */
453977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        node->perm = PERM_ROOT;
454977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        node->userid = strtoul(node->name, NULL, 10);
455f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        node->gid = multiuser_get_uid(node->userid, fuse->gid);
456fc0004894a3ff93382493688bb9ab9af83b74ea4Jeff Sharkey        node->mode = 0771;
457977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        break;
458dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    case PERM_ROOT:
459977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        /* Assume masked off by default. */
460977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        node->mode = 0770;
46144d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (!strcasecmp(node->name, "Android")) {
462dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            /* App-specific directories inside; let anyone traverse */
463dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            node->perm = PERM_ANDROID;
464dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            node->mode = 0771;
465dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
466dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        break;
467dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    case PERM_ANDROID:
46844d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (!strcasecmp(node->name, "data")) {
469dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            /* App-specific directories inside; let anyone traverse */
470dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            node->perm = PERM_ANDROID_DATA;
471dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            node->mode = 0771;
47244d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        } else if (!strcasecmp(node->name, "obb")) {
473dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            /* App-specific directories inside; let anyone traverse */
474dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            node->perm = PERM_ANDROID_OBB;
475dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            node->mode = 0771;
476977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey            /* Single OBB directory is always shared */
477f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            node->graft_path = fuse->obb_path;
478f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            node->graft_pathlen = strlen(fuse->obb_path);
4792e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey        } else if (!strcasecmp(node->name, "media")) {
4802e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey            /* App-specific directories inside; let anyone traverse */
4812e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey            node->perm = PERM_ANDROID_MEDIA;
4822e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey            node->mode = 0771;
483dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
484dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        break;
485dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    case PERM_ANDROID_DATA:
486dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    case PERM_ANDROID_OBB:
4872e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey    case PERM_ANDROID_MEDIA:
488f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        appid = (appid_t) (uintptr_t) hashmapGet(fuse->global->package_to_appid, node->name);
489977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        if (appid != 0) {
490977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey            node->uid = multiuser_get_uid(parent->userid, appid);
491dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
492dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        node->mode = 0770;
493dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        break;
494dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    }
49539ff0ae0f66d7bc1499b30c9f75e187d329382ecJeff Sharkey
496f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    node->mode = node->mode & ~fuse->mask;
497aa04e818a4904b193e00d603785c93e888eab174Jeff Sharkey}
498aa04e818a4904b193e00d603785c93e888eab174Jeff Sharkey
499977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey/* Kernel has already enforced everything we returned through
500977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey * derive_permissions_locked(), so this is used to lock down access
501977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey * even further, such as enforcing that apps hold sdcard_rw. */
502977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic bool check_caller_access_to_name(struct fuse* fuse,
503977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        const struct fuse_in_header *hdr, const struct node* parent_node,
504f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        const char* name, int mode) {
505977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* Always block security-sensitive files at root */
506977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    if (parent_node && parent_node->perm == PERM_ROOT) {
50744d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (!strcasecmp(name, "autorun.inf")
50844d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey                || !strcasecmp(name, ".android_secure")
50944d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey                || !strcasecmp(name, "android_secure")) {
510977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey            return false;
511977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        }
512977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
513977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
51444d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    /* Root always has access; access for any other UIDs should always
51544d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey     * be controlled through packages.list. */
51644d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    if (hdr->uid == 0) {
517977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return true;
518977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
519977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
520977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* No extra permissions to enforce */
521977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    return true;
522977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey}
523977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
524977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic bool check_caller_access_to_node(struct fuse* fuse,
525f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        const struct fuse_in_header *hdr, const struct node* node, int mode) {
526f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    return check_caller_access_to_name(fuse, hdr, node->parent, node->name, mode);
527977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey}
528977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
5296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstruct node *create_node_locked(struct fuse* fuse,
5306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct node *parent, const char *name, const char* actual_name)
53103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
53203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct node *node;
5336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
53403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
535faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    // Detect overflows in the inode counter. "4 billion nodes should be enough
536faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    // for everybody".
537faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    if (fuse->inode_ctr == 0) {
538faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath        ERROR("No more inode numbers available");
539faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath        return NULL;
540faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    }
541faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath
54211ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    node = calloc(1, sizeof(struct node));
5436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node) {
5446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
54503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
54611ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    node->name = malloc(namelen + 1);
5476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node->name) {
54811ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham        free(node);
5496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
55011ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    }
55103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    memcpy(node->name, name, namelen + 1);
5526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (strcmp(name, actual_name)) {
5536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->actual_name = malloc(namelen + 1);
5546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->actual_name) {
5556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->name);
5566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node);
5576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return NULL;
5586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
5596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        memcpy(node->actual_name, actual_name, namelen + 1);
5606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
56103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    node->namelen = namelen;
5626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->nid = ptr_to_id(node);
563faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    node->ino = fuse->inode_ctr++;
5646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->gen = fuse->next_generation++;
565dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
566c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    node->deleted = false;
567c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski
568dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    derive_permissions_locked(fuse, parent, node);
5696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(node);
5706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    add_node_to_parent_locked(node, parent);
57103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    return node;
57203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
57303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
5746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int rename_node_locked(struct node *node, const char *name,
5756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* actual_name)
57611ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham{
5776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
5786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int need_actual_name = strcmp(name, actual_name);
5796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
5806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* make the storage bigger without actually changing the name
5816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * in case an error occurs part way */
5826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (namelen > node->namelen) {
5836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* new_name = realloc(node->name, namelen + 1);
5846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!new_name) {
5856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -ENOMEM;
5866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
5876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->name = new_name;
5886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (need_actual_name && node->actual_name) {
5896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            char* new_actual_name = realloc(node->actual_name, namelen + 1);
5906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!new_actual_name) {
5916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                return -ENOMEM;
5926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
5936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->actual_name = new_actual_name;
5946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
5956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
59603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
5976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* update the name, taking care to allocate storage before overwriting the old name */
5986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (need_actual_name) {
5996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->actual_name) {
6006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->actual_name = malloc(namelen + 1);
6016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!node->actual_name) {
6026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                return -ENOMEM;
6036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
6046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
6056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        memcpy(node->actual_name, actual_name, namelen + 1);
6066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
6076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        free(node->actual_name);
6086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->actual_name = NULL;
6096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
6106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(node->name, name, namelen + 1);
6116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->namelen = namelen;
6126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
61303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
61403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
61603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
6176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (nid == FUSE_ROOT_ID) {
61803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        return &fuse->root;
61903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    } else {
62003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        return id_to_ptr(nid);
62103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
62203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
62303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node* lookup_node_and_path_by_id_locked(struct fuse* fuse, __u64 nid,
6256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* buf, size_t bufsize)
62603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
6276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node = lookup_node_by_id_locked(fuse, nid);
6286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node && get_node_path_locked(node, buf, bufsize) < 0) {
6296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node = NULL;
63003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
6316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return node;
63203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
63303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node *lookup_child_by_name_locked(struct node *node, const char *name)
63503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
63603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    for (node = node->child; node; node = node->next) {
6376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        /* use exact string comparison, nodes that differ by case
6386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * must be considered distinct even if they refer to the same
6396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * underlying file as otherwise operations such as "mv x x"
6406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * will not work because the source and target nodes are the same. */
641c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski        if (!strcmp(name, node->name) && !node->deleted) {
64211ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham            return node;
64311ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham        }
64411ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    }
64511ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    return 0;
64611ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham}
64711ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham
6486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node* acquire_or_create_child_locked(
6496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct fuse* fuse, struct node* parent,
6506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* name, const char* actual_name)
65103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
6526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* child = lookup_child_by_name_locked(parent, name);
6536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (child) {
6546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        acquire_node_locked(child);
6556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
6566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        child = create_node_locked(fuse, parent, name, actual_name);
65703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
6586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return child;
65903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
66003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void fuse_status(struct fuse *fuse, __u64 unique, int err)
66203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
66303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct fuse_out_header hdr;
66403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.len = sizeof(hdr);
66503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.error = err;
66603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.unique = unique;
66703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    write(fuse->fd, &hdr, sizeof(hdr));
66803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
66903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
67103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
67203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct fuse_out_header hdr;
67303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct iovec vec[2];
67403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int res;
67503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
67603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.len = len + sizeof(hdr);
67703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.error = 0;
67803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.unique = unique;
67903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
68003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[0].iov_base = &hdr;
68103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[0].iov_len = sizeof(hdr);
68203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[1].iov_base = data;
68303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[1].iov_len = len;
68403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
68503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    res = writev(fuse->fd, vec, 2);
68603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    if (res < 0) {
68703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        ERROR("*** REPLY FAILED *** %d\n", errno);
68803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
68903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
69003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int fuse_reply_entry(struct fuse* fuse, __u64 unique,
6926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct node* parent, const char* name, const char* actual_name,
6936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* path)
69403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
695fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct node* node;
6966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_entry_out out;
6976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct stat s;
69803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (lstat(path, &s) < 0) {
70044d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        return -errno;
70103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
702fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
703f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
7046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
7056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node) {
706f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        pthread_mutex_unlock(&fuse->global->lock);
7076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
7086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memset(&out, 0, sizeof(out));
710dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    attr_from_stat(&out.attr, &s, node);
7116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.attr_valid = 10;
7126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.entry_valid = 10;
71303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    out.nodeid = node->nid;
71403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    out.generation = node->gen;
715f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
71603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    fuse_reply(fuse, unique, &out, sizeof(out));
7176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
71803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
71903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
720dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkeystatic int fuse_reply_attr(struct fuse* fuse, __u64 unique, const struct node* node,
7216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* path)
72203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
7236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_attr_out out;
7246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct stat s;
725fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (lstat(path, &s) < 0) {
7276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
728fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
7296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memset(&out, 0, sizeof(out));
730dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    attr_from_stat(&out.attr, &s, node);
7316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.attr_valid = 10;
7326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse_reply(fuse, unique, &out, sizeof(out));
7336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
7346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
735fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
7376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const struct fuse_in_header *hdr, const char* name)
7386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
7396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
7406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
7416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
7426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
7436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
744f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
7456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
7466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
747e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] LOOKUP %s @ %"PRIx64" (%s)\n", handler->token, name, hdr->nodeid,
7486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        parent_node ? parent_node->name : "?");
749f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
7506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
7516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
7526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
7536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
7546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
755f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, R_OK)) {
756977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
757977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
758977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
7596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
760fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
761fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_forget(struct fuse* fuse, struct fuse_handler* handler,
763fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_forget_in *req)
764fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
7656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
766fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
767f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
7686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_by_id_locked(fuse, hdr->nodeid);
769e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] FORGET #%"PRIu64" @ %"PRIx64" (%s)\n", handler->token, req->nlookup,
7706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            hdr->nodeid, node ? node->name : "?");
7716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node) {
7726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        __u64 n = req->nlookup;
7736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        while (n--) {
7746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            release_node_locked(node);
7756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
776fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
777f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
7786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS; /* no reply */
779fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
780fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_getattr(struct fuse* fuse, struct fuse_handler* handler,
782fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_getattr_in *req)
783fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
7846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
7856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
7866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
787f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
7886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
789e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] GETATTR flags=%x fh=%"PRIx64" @ %"PRIx64" (%s)\n", handler->token,
7906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->getattr_flags, req->fh, hdr->nodeid, node ? node->name : "?");
791f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
792fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
793fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
7946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
795fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
796f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
797977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
798977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
799977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
800dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    return fuse_reply_attr(fuse, hdr->unique, node, path);
801fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
802fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
804fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
805fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
8066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
8076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
808fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct timespec times[2];
809fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
810f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
8116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
812e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] SETATTR fh=%"PRIx64" valid=%x @ %"PRIx64" (%s)\n", handler->token,
8136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
814f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
8156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
816fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
8176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
818fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
819a80f0986bb39ae03ba9014bf4974fc26ae48da70Marco Nelissen
820a80f0986bb39ae03ba9014bf4974fc26ae48da70Marco Nelissen    if (!(req->valid & FATTR_FH) &&
821f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            !check_caller_access_to_node(fuse, hdr, node, W_OK)) {
822977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
823977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
824fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* XXX: incomplete implementation on purpose.
8266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * chmod/chown should NEVER be implemented.*/
827fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
828853574ddc766da725dd114fe1d1102c59f713f3bElliott Hughes    if ((req->valid & FATTR_SIZE) && truncate64(path, req->size) < 0) {
8296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
830fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
831fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
832fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* Handle changing atime and mtime.  If FATTR_ATIME_and FATTR_ATIME_NOW
833fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * are both set, then set it to the current time.  Else, set it to the
834fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * time specified in the request.  Same goes for mtime.  Use utimensat(2)
835fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * as it allows ATIME and MTIME to be changed independently, and has
836fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * nanosecond resolution which fuse also has.
837fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     */
838fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
839fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        times[0].tv_nsec = UTIME_OMIT;
840fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        times[1].tv_nsec = UTIME_OMIT;
841fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        if (req->valid & FATTR_ATIME) {
842fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            if (req->valid & FATTR_ATIME_NOW) {
843fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_nsec = UTIME_NOW;
844fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            } else {
845fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_sec = req->atime;
846fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_nsec = req->atimensec;
847fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            }
848fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        }
849fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        if (req->valid & FATTR_MTIME) {
850fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            if (req->valid & FATTR_MTIME_NOW) {
851fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_nsec = UTIME_NOW;
852fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            } else {
853fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_sec = req->mtime;
854fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_nsec = req->mtimensec;
855fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            }
856fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        }
8576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        TRACE("[%d] Calling utimensat on %s with atime %ld, mtime=%ld\n",
8586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                handler->token, path, times[0].tv_sec, times[1].tv_sec);
8596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (utimensat(-1, path, times, 0) < 0) {
8606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -errno;
86103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        }
862fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
863dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    return fuse_reply_attr(fuse, hdr->unique, node, path);
864fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
865fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
867fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
868fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
8696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
8706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
8716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
8726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
8736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
874f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
8756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
8766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
877e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] MKNOD %s 0%o @ %"PRIx64" (%s)\n", handler->token,
8786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
879f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
8806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
8816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
8826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
8836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
884fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
885f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
886977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
887977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
888fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 mode = (req->mode & (~0777)) | 0664;
8896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (mknod(child_path, mode, req->rdev) < 0) {
8906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
891fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
8926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
893fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
894fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
896fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
897fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
8986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
8996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
9006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
9016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
9026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
903f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
9046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
9056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
906e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] MKDIR %s 0%o @ %"PRIx64" (%s)\n", handler->token,
9076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
908f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
9096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
9106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
9116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
9126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
913fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
914f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
915977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
916977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
917fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 mode = (req->mode & (~0777)) | 0775;
9186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (mkdir(child_path, mode) < 0) {
9196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
920fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
92144d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey
92244d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    /* When creating /Android/data and /Android/obb, mark them as .nomedia */
92344d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "data")) {
92444d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        char nomedia[PATH_MAX];
92544d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        snprintf(nomedia, PATH_MAX, "%s/.nomedia", child_path);
92644d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (touch(nomedia, 0664) != 0) {
92744d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
92844d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            return -ENOENT;
92944d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        }
93044d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    }
93144d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "obb")) {
93244d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        char nomedia[PATH_MAX];
933f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->obb_path);
93444d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (touch(nomedia, 0664) != 0) {
93544d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
93644d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            return -ENOENT;
93744d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        }
93844d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    }
93944d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey
9406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
941fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
942fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
944fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const char* name)
945fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
9466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
947c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    struct node* child_node;
9486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
9496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
950fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
951f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
9526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
9536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
954e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] UNLINK %s @ %"PRIx64" (%s)\n", handler->token,
9556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, hdr->nodeid, parent_node ? parent_node->name : "?");
956f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
957fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !find_file_within(parent_path, name,
9596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1)) {
9606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
9616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
962f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
963977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
964977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
9656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (unlink(child_path) < 0) {
9666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
9676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
968f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
969c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    child_node = lookup_child_by_name_locked(parent_node, name);
970c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    if (child_node) {
971c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski        child_node->deleted = true;
972c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    }
973f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
9746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
975fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
976fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
978fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const char* name)
979fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
980c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    struct node* child_node;
9816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
9826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
9836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
984fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
985f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
9866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
9876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
988e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] RMDIR %s @ %"PRIx64" (%s)\n", handler->token,
9896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, hdr->nodeid, parent_node ? parent_node->name : "?");
990f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
991fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !find_file_within(parent_path, name,
9936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1)) {
9946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
9956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
996f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
997977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
998977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
9996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (rmdir(child_path) < 0) {
10006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
10016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
1002f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
1003c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    child_node = lookup_child_by_name_locked(parent_node, name);
1004c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    if (child_node) {
1005c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski        child_node->deleted = true;
1006c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    }
1007f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
10086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1009fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1010fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_rename(struct fuse* fuse, struct fuse_handler* handler,
1012fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
10136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* old_name, const char* new_name)
1014fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
10156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* old_parent_node;
10166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* new_parent_node;
10176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* child_node;
10186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char old_parent_path[PATH_MAX];
10196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char new_parent_path[PATH_MAX];
10206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char old_child_path[PATH_MAX];
10216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char new_child_path[PATH_MAX];
10226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* new_actual_name;
1023fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
1024fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1025f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
10266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
10276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_parent_path, sizeof(old_parent_path));
10286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
10296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            new_parent_path, sizeof(new_parent_path));
1030e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] RENAME %s->%s @ %"PRIx64" (%s) -> %"PRIx64" (%s)\n", handler->token,
10316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_name, new_name,
10326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            hdr->nodeid, old_parent_node ? old_parent_node->name : "?",
10336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->newdir, new_parent_node ? new_parent_node->name : "?");
10346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!old_parent_node || !new_parent_node) {
10356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
10366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto lookup_error;
10376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
1038f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, old_parent_node, old_name, W_OK)) {
1039977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        res = -EACCES;
1040977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        goto lookup_error;
1041977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
1042f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, new_parent_node, new_name, W_OK)) {
1043977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        res = -EACCES;
1044977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        goto lookup_error;
1045977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
10466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    child_node = lookup_child_by_name_locked(old_parent_node, old_name);
10476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!child_node || get_node_path_locked(child_node,
10486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_child_path, sizeof(old_child_path)) < 0) {
10496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
10506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto lookup_error;
10516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
10526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(child_node);
1053f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
10546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
10556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* Special case for renaming a file where destination is same path
10566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * differing only by case.  In this case we don't want to look for a case
10576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * insensitive match.  This allows commands like "mv foo FOO" to work as expected.
10586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     */
10596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int search = old_parent_node != new_parent_node
10606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            || strcasecmp(old_name, new_name);
10616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!(new_actual_name = find_file_within(new_parent_path, new_name,
10626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            new_child_path, sizeof(new_child_path), search))) {
10636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
10646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto io_error;
1065fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1066fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RENAME %s->%s\n", handler->token, old_child_path, new_child_path);
10686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = rename(old_child_path, new_child_path);
10696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (res < 0) {
10706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -errno;
10716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto io_error;
1072fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1073fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1074f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
10756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = rename_node_locked(child_node, new_name, new_actual_name);
10766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!res) {
10776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        remove_node_from_parent_locked(child_node);
10786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        add_node_to_parent_locked(child_node, new_parent_node);
1079fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
10806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    goto done;
1081fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownio_error:
1083f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
10846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Browndone:
10856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    release_node_locked(child_node);
10866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownlookup_error:
1087f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
10886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return res;
1089fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1090fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1091977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic int open_flags_to_access_mode(int open_flags) {
1092977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    if ((open_flags & O_ACCMODE) == O_RDONLY) {
1093977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return R_OK;
1094977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    } else if ((open_flags & O_ACCMODE) == O_WRONLY) {
1095977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return W_OK;
1096977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    } else {
1097977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        /* Probably O_RDRW, but treat as default to be safe */
1098977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return R_OK | W_OK;
1099977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
1100977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey}
1101977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
11026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_open(struct fuse* fuse, struct fuse_handler* handler,
1103fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_open_in* req)
1104fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
11056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
11066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
1107fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_open_out out;
1108fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h;
110903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1110f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
11116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
1112e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] OPEN 0%o @ %"PRIx64" (%s)\n", handler->token,
11136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->flags, hdr->nodeid, node ? node->name : "?");
1114f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
1115fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1116fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
11176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
1118fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1119aa04e818a4904b193e00d603785c93e888eab174Jeff Sharkey    if (!check_caller_access_to_node(fuse, hdr, node,
1120f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            open_flags_to_access_mode(req->flags))) {
1121977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
1122977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
11236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    h = malloc(sizeof(*h));
11246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!h) {
11256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
11266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
11276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] OPEN %s\n", handler->token, path);
1128fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    h->fd = open(path, req->flags);
1129fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (h->fd < 0) {
1130fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        free(h);
11316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1132fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1133fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.fh = ptr_to_id(h);
1134fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.open_flags = 0;
1135fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.padding = 0;
1136fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
11376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1138fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1139fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
11406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_read(struct fuse* fuse, struct fuse_handler* handler,
1141fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_read_in* req)
1142fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1143fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
1144fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u64 unique = hdr->unique;
1145fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 size = req->size;
1146fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u64 offset = req->offset;
11476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int res;
114880b435a3f35795600654e9705f4b3fbbcc427a9dArpad Horvath    __u8 *read_buffer = (__u8 *) ((uintptr_t)(handler->read_buffer + PAGESIZE) & ~((uintptr_t)PAGESIZE-1));
11496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1150fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* Don't access any other fields of hdr or req beyond this point, the read buffer
1151fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * overlaps the request buffer and will clobber data in the request.  This
1152fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * saves us 128KB per request handler thread at the cost of this scary comment. */
11536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1154e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] READ %p(%d) %u@%"PRIu64"\n", handler->token,
1155e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland            h, h->fd, size, (uint64_t) offset);
115680b435a3f35795600654e9705f4b3fbbcc427a9dArpad Horvath    if (size > MAX_READ) {
11576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -EINVAL;
1158fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
115980b435a3f35795600654e9705f4b3fbbcc427a9dArpad Horvath    res = pread64(h->fd, read_buffer, size, offset);
1160fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (res < 0) {
11616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1162fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
116380b435a3f35795600654e9705f4b3fbbcc427a9dArpad Horvath    fuse_reply(fuse, unique, read_buffer, res);
11646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1165fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1166fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
11676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_write(struct fuse* fuse, struct fuse_handler* handler,
1168fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_write_in* req,
1169fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const void* buffer)
1170fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1171fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_write_out out;
1172fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
1173fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
117449e9344bddca3699c04f3da8c689d0f2b1a338b6Arpad Horvath    __u8 aligned_buffer[req->size] __attribute__((__aligned__(PAGESIZE)));
117560281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes
117649e9344bddca3699c04f3da8c689d0f2b1a338b6Arpad Horvath    if (req->flags & O_DIRECT) {
117749e9344bddca3699c04f3da8c689d0f2b1a338b6Arpad Horvath        memcpy(aligned_buffer, buffer, req->size);
117849e9344bddca3699c04f3da8c689d0f2b1a338b6Arpad Horvath        buffer = (const __u8*) aligned_buffer;
117949e9344bddca3699c04f3da8c689d0f2b1a338b6Arpad Horvath    }
11806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1181e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] WRITE %p(%d) %u@%"PRIu64"\n", handler->token,
11826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            h, h->fd, req->size, req->offset);
1183fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    res = pwrite64(h->fd, buffer, req->size, req->offset);
1184fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (res < 0) {
11856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1186fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1187fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.size = res;
118819ec8860c1d80836b176dbf3dc434a94182094b7Daisuke Okitsu    out.padding = 0;
1189fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
11906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1191fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1192fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
11936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_statfs(struct fuse* fuse, struct fuse_handler* handler,
1194fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr)
1195fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
11966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
1197fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct statfs stat;
1198fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_statfs_out out;
1199fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
1200fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1201f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
12026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] STATFS\n", handler->token);
12036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = get_node_path_locked(&fuse->root, path, sizeof(path));
1204f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
12056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (res < 0) {
12066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
12076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
12086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (statfs(fuse->root.name, &stat) < 0) {
12096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1210fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1211fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    memset(&out, 0, sizeof(out));
1212fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.blocks = stat.f_blocks;
1213fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bfree = stat.f_bfree;
1214fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bavail = stat.f_bavail;
1215fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.files = stat.f_files;
1216fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.ffree = stat.f_ffree;
1217fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bsize = stat.f_bsize;
1218fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.namelen = stat.f_namelen;
1219fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.frsize = stat.f_frsize;
1220fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
12216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1222fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1223fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
12246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_release(struct fuse* fuse, struct fuse_handler* handler,
1225fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_release_in* req)
1226fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1227fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
12286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
12296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RELEASE %p(%d)\n", handler->token, h, h->fd);
1230fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    close(h->fd);
1231fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    free(h);
12326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1233fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1234fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
12356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
1236fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
1237fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1238f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    bool is_dir = (hdr->opcode == FUSE_FSYNCDIR);
1239f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    bool is_data_sync = req->fsync_flags & 1;
12406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1241f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    int fd = -1;
1242f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    if (is_dir) {
1243f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes      struct dirhandle *dh = id_to_ptr(req->fh);
1244f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes      fd = dirfd(dh->d);
1245f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    } else {
1246f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes      struct handle *h = id_to_ptr(req->fh);
1247f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes      fd = h->fd;
1248f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    }
1249f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes
1250f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    TRACE("[%d] %s %p(%d) is_data_sync=%d\n", handler->token,
1251f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes            is_dir ? "FSYNCDIR" : "FSYNC",
1252f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes            id_to_ptr(req->fh), fd, is_data_sync);
1253f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    int res = is_data_sync ? fdatasync(fd) : fsync(fd);
1254f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    if (res == -1) {
12556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1256fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
12576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1258fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1259fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
12606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_flush(struct fuse* fuse, struct fuse_handler* handler,
1261fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr)
1262fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
12636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] FLUSH\n", handler->token);
12646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1265fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1266fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
12676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
1268fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_open_in* req)
1269fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
12706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
12716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
1272fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_open_out out;
1273fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirhandle *h;
1274fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1275f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
12766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
1277e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] OPENDIR @ %"PRIx64" (%s)\n", handler->token,
12786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            hdr->nodeid, node ? node->name : "?");
1279f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
12806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1281fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
12826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
1283fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1284f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
1285977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
1286977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
1287fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    h = malloc(sizeof(*h));
1288fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!h) {
12896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
1290fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
12916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] OPENDIR %s\n", handler->token, path);
1292fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    h->d = opendir(path);
12936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!h->d) {
1294fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        free(h);
12956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1296fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1297fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.fh = ptr_to_id(h);
12983a8768804ce4b4797359d5df03ec8897fe43de90Ken Sumrall    out.open_flags = 0;
12993a8768804ce4b4797359d5df03ec8897fe43de90Ken Sumrall    out.padding = 0;
1300fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
13016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1302fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1303fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
13046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_readdir(struct fuse* fuse, struct fuse_handler* handler,
1305fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_read_in* req)
1306fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1307fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    char buffer[8192];
1308fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
1309fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirent *de;
1310fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirhandle *h = id_to_ptr(req->fh);
13116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
13126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] READDIR %p\n", handler->token, h);
1313fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (req->offset == 0) {
1314fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        /* rewinddir() might have been called above us, so rewind here too */
13156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        TRACE("[%d] calling rewinddir()\n", handler->token);
1316fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        rewinddir(h->d);
1317fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1318fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    de = readdir(h->d);
1319fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!de) {
13206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return 0;
1321fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1322fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->ino = FUSE_UNKNOWN_INO;
1323fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
1324fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->off = req->offset + 1;
1325fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->type = de->d_type;
1326fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->namelen = strlen(de->d_name);
1327fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    memcpy(fde->name, de->d_name, fde->namelen + 1);
1328fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, fde,
13296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
13306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1331fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1332fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
13336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_releasedir(struct fuse* fuse, struct fuse_handler* handler,
1334fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_release_in* req)
1335fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1336fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirhandle *h = id_to_ptr(req->fh);
13376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
13386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RELEASEDIR %p\n", handler->token, h);
1339fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    closedir(h->d);
1340fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    free(h);
13416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1342fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1343fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
13446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_init(struct fuse* fuse, struct fuse_handler* handler,
1345fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_init_in* req)
1346fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1347fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_init_out out;
1348ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    size_t fuse_struct_size;
1349fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
13506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] INIT ver=%d.%d maxread=%d flags=%x\n",
13516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            handler->token, req->major, req->minor, req->max_readahead, req->flags);
1352ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris
1353ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    /* Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
1354ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris     * defined (fuse version 7.6). The structure is the same from 7.6 through
1355ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris     * 7.22. Beginning with 7.23, the structure increased in size and added
1356ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris     * new parameters.
1357ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris     */
1358ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) {
1359ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris        ERROR("Fuse kernel version mismatch: Kernel version %d.%d, Expected at least %d.6",
1360ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris              req->major, req->minor, FUSE_KERNEL_VERSION);
1361ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris        return -1;
1362ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    }
1363ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris
1364f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    /* We limit ourselves to 15 because we don't handle BATCH_FORGET yet */
1365f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    out.minor = MIN(req->minor, 15);
1366ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    fuse_struct_size = sizeof(out);
1367ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
1368ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    /* FUSE_KERNEL_VERSION >= 23. */
1369ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris
1370ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    /* If the kernel only works on minor revs older than or equal to 22,
1371ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris     * then use the older structure size since this code only uses the 7.22
1372ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris     * version of the structure. */
1373ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    if (req->minor <= 22) {
1374ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris        fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
1375ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    }
1376ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris#endif
1377ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris
1378fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.major = FUSE_KERNEL_VERSION;
1379fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_readahead = req->max_readahead;
1380fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
1381fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_background = 32;
1382fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.congestion_threshold = 32;
1383fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_write = MAX_WRITE;
1384ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    fuse_reply(fuse, hdr->unique, &out, fuse_struct_size);
13856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1386fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1387fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
13886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
1389fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const void *data, size_t data_len)
1390fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
139103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    switch (hdr->opcode) {
139203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_LOOKUP: { /* bytez[] -> entry_out */
1393847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char* name = data;
13946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_lookup(fuse, handler, hdr, name);
139503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1396847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
139703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_FORGET: {
1398847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_forget_in *req = data;
13996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_forget(fuse, handler, hdr, req);
140003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1401847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
140203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_GETATTR: { /* getattr_in -> attr_out */
1403847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_getattr_in *req = data;
14046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_getattr(fuse, handler, hdr, req);
140503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1406847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
140703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_SETATTR: { /* setattr_in -> attr_out */
1408847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_setattr_in *req = data;
14096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_setattr(fuse, handler, hdr, req);
141003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1411847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
141203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_READLINK:
141303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_SYMLINK:
141403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
1415847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_mknod_in *req = data;
1416847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char *name = ((const char*) data) + sizeof(*req);
14176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_mknod(fuse, handler, hdr, req, name);
141803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1419847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
142003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
1421847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_mkdir_in *req = data;
1422847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char *name = ((const char*) data) + sizeof(*req);
14236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_mkdir(fuse, handler, hdr, req, name);
142403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1425847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
142603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_UNLINK: { /* bytez[] -> */
1427847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char* name = data;
14286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_unlink(fuse, handler, hdr, name);
142903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1430847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
143103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RMDIR: { /* bytez[] -> */
1432847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char* name = data;
14336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_rmdir(fuse, handler, hdr, name);
143403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1435847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
143603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RENAME: { /* rename_in, oldname, newname ->  */
1437847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_rename_in *req = data;
14386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char *old_name = ((const char*) data) + sizeof(*req);
14396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char *new_name = old_name + strlen(old_name) + 1;
14406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_rename(fuse, handler, hdr, req, old_name, new_name);
144103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1442847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1443fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown//    case FUSE_LINK:
144403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_OPEN: { /* open_in -> open_out */
1445847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_open_in *req = data;
14466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_open(fuse, handler, hdr, req);
144703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1448847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
144903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_READ: { /* read_in -> byte[] */
1450847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_read_in *req = data;
14516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_read(fuse, handler, hdr, req);
145203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1453847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
145403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
1455847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_write_in *req = data;
1456847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const void* buffer = (const __u8*)data + sizeof(*req);
14576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_write(fuse, handler, hdr, req, buffer);
145803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1459847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
14604553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    case FUSE_STATFS: { /* getattr_in -> attr_out */
14616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_statfs(fuse, handler, hdr);
14624553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    }
1463847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
146403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RELEASE: { /* release_in -> */
1465847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_release_in *req = data;
14666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_release(fuse, handler, hdr, req);
146703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1468847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1469b2831a2db9e0370c5f797c037c135108025f2522Daisuke Okitsu    case FUSE_FSYNC:
1470b2831a2db9e0370c5f797c037c135108025f2522Daisuke Okitsu    case FUSE_FSYNCDIR: {
14716fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown        const struct fuse_fsync_in *req = data;
14726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_fsync(fuse, handler, hdr, req);
14736fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown    }
14746fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown
147503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_SETXATTR:
147603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_GETXATTR:
147703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_LISTXATTR:
147803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_REMOVEXATTR:
1479847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    case FUSE_FLUSH: {
14806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_flush(fuse, handler, hdr);
1481847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    }
1482847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
148303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_OPENDIR: { /* open_in -> open_out */
1484847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_open_in *req = data;
14856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_opendir(fuse, handler, hdr, req);
148603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1487847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
148803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_READDIR: {
1489847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_read_in *req = data;
14906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_readdir(fuse, handler, hdr, req);
149103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1492847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
149303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RELEASEDIR: { /* release_in -> */
1494847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_release_in *req = data;
14956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_releasedir(fuse, handler, hdr, req);
149603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1497847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
149803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_INIT: { /* init_in -> init_out */
1499847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_init_in *req = data;
15006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_init(fuse, handler, hdr, req);
150103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1502847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
150303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    default: {
1504e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland        TRACE("[%d] NOTIMPL op=%d uniq=%"PRIx64" nid=%"PRIx64"\n",
15056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                handler->token, hdr->opcode, hdr->unique, hdr->nodeid);
15066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOSYS;
150703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1508847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    }
150903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
151003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
15116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void handle_fuse_requests(struct fuse_handler* handler)
151203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
15136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse* fuse = handler->fuse;
151403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    for (;;) {
15156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        ssize_t len = read(fuse->fd,
15166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                handler->request_buffer, sizeof(handler->request_buffer));
151703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        if (len < 0) {
15186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (errno != EINTR) {
15196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                ERROR("[%d] handle_fuse_requests: errno=%d\n", handler->token, errno);
15206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
15216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
152203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        }
1523847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1524847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        if ((size_t)len < sizeof(struct fuse_in_header)) {
15256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            ERROR("[%d] request too short: len=%zu\n", handler->token, (size_t)len);
15266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
1527847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        }
1528847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
15297729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        const struct fuse_in_header *hdr = (void*)handler->request_buffer;
1530847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        if (hdr->len != (size_t)len) {
15316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            ERROR("[%d] malformed header: len=%zu, hdr->len=%u\n",
15326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                    handler->token, (size_t)len, hdr->len);
15336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
1534847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        }
1535847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
15367729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        const void *data = handler->request_buffer + sizeof(struct fuse_in_header);
1537847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        size_t data_len = len - sizeof(struct fuse_in_header);
15386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        __u64 unique = hdr->unique;
15396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        int res = handle_fuse_request(fuse, handler, hdr, data, data_len);
15407729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown
15417729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        /* We do not access the request again after this point because the underlying
15427729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown         * buffer storage may have been reused while processing the request. */
15436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
15446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (res != NO_STATUS) {
15456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (res) {
15466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                TRACE("[%d] ERROR %d\n", handler->token, res);
15476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
15486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            fuse_status(fuse, unique, res);
15496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
155003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
155103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
155203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
15536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void* start_handler(void* data)
15547729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown{
15556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_handler* handler = data;
15566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    handle_fuse_requests(handler);
15576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NULL;
15586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
15596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1560977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic bool remove_str_to_int(void *key, void *value, void *context) {
1561dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    Hashmap* map = context;
1562dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    hashmapRemove(map, key);
1563dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    free(key);
1564977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    return true;
1565977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey}
1566977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
1567977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic bool remove_int_to_null(void *key, void *value, void *context) {
1568977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    Hashmap* map = context;
1569977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    hashmapRemove(map, key);
1570dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    return true;
1571dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey}
1572dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1573f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkeystatic int read_package_list(struct fuse_global* global) {
1574f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&global->lock);
1575dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1576f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    hashmapForEach(global->package_to_appid, remove_str_to_int, global->package_to_appid);
1577dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1578dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    FILE* file = fopen(kPackagesListFile, "r");
1579dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    if (!file) {
1580dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        ERROR("failed to open package list: %s\n", strerror(errno));
1581f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        pthread_mutex_unlock(&global->lock);
1582dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        return -1;
1583dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    }
1584dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1585dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    char buf[512];
1586dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    while (fgets(buf, sizeof(buf), file) != NULL) {
1587dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        char package_name[512];
1588dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        int appid;
1589977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        char gids[512];
1590977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
1591977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        if (sscanf(buf, "%s %d %*d %*s %*s %s", package_name, &appid, gids) == 3) {
1592dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            char* package_name_dup = strdup(package_name);
1593f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            hashmapPut(global->package_to_appid, package_name_dup, (void*) (uintptr_t) appid);
1594dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
1595dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    }
1596dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1597f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    TRACE("read_package_list: found %zu packages\n",
1598f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            hashmapSize(global->package_to_appid));
1599dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    fclose(file);
1600f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&global->lock);
1601dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    return 0;
1602dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey}
1603dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1604f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkeystatic void watch_package_list(struct fuse_global* global) {
1605dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    struct inotify_event *event;
1606dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    char event_buf[512];
1607dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1608dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    int nfd = inotify_init();
1609dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    if (nfd < 0) {
1610dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        ERROR("inotify_init failed: %s\n", strerror(errno));
1611dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        return;
1612dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    }
1613dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1614dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    bool active = false;
1615dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    while (1) {
1616dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        if (!active) {
1617dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            int res = inotify_add_watch(nfd, kPackagesListFile, IN_DELETE_SELF);
1618dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            if (res == -1) {
1619dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                if (errno == ENOENT || errno == EACCES) {
1620dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                    /* Framework may not have created yet, sleep and retry */
1621dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                    ERROR("missing packages.list; retrying\n");
1622dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                    sleep(3);
1623dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                    continue;
1624dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                } else {
1625dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                    ERROR("inotify_add_watch failed: %s\n", strerror(errno));
1626dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                    return;
1627dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                }
1628dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            }
1629dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1630dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            /* Watch above will tell us about any future changes, so
1631dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey             * read the current state. */
1632f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            if (read_package_list(global) == -1) {
1633dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                ERROR("read_package_list failed: %s\n", strerror(errno));
1634dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                return;
1635dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            }
1636dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            active = true;
1637dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
1638dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1639dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        int event_pos = 0;
1640dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        int res = read(nfd, event_buf, sizeof(event_buf));
1641dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        if (res < (int) sizeof(*event)) {
1642dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            if (errno == EINTR)
1643dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                continue;
1644dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            ERROR("failed to read inotify event: %s\n", strerror(errno));
1645dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            return;
1646dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
1647dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1648dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        while (res >= (int) sizeof(*event)) {
1649dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            int event_size;
1650dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            event = (struct inotify_event *) (event_buf + event_pos);
1651dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1652dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            TRACE("inotify event: %08x\n", event->mask);
1653dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            if ((event->mask & IN_IGNORED) == IN_IGNORED) {
1654dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                /* Previously watched file was deleted, probably due to move
1655dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                 * that swapped in new data; re-arm the watch and read. */
1656dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                active = false;
1657dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            }
1658dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1659dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            event_size = sizeof(*event) + event->len;
1660dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            res -= event_size;
1661dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            event_pos += event_size;
1662dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
1663dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    }
1664dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey}
1665dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1666f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkeystatic int usage() {
1667f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    ERROR("usage: sdcard [OPTIONS] <source_path> <label>\n"
1668dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            "    -u: specify UID to run as\n"
1669dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            "    -g: specify GID to run as\n"
1670f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            "    -m: source_path is multi-user\n"
1671f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            "    -w: runtime_write mount has full write access\n"
1672f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            "\n");
16732656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    return 1;
16744f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood}
16754f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood
1676f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkeystatic int fuse_setup(struct fuse* fuse, gid_t gid, mode_t mask) {
167703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    char opts[256];
16782656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1679f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse->fd = open("/dev/fuse", O_RDWR);
1680f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (fuse->fd == -1) {
1681f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        ERROR("failed to open fuse device: %s\n", strerror(errno));
16822656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        return -1;
16832656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
16842656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1685f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    umount2(fuse->dest_path, MNT_DETACH);
1686f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
16872656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    snprintf(opts, sizeof(opts),
16882656735f515a41cf131c87be5f40550b6538ce80Jeff Brown            "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
1689f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            fuse->fd, fuse->global->uid, fuse->global->gid);
1690f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (mount("/dev/fuse", fuse->dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC |
1691f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            MS_NOATIME, opts) != 0) {
1692f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        ERROR("failed to mount fuse filesystem: %s\n", strerror(errno));
1693f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        return -1;
1694f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    }
16952656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1696f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse->next_generation = 0;
1697f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse->inode_ctr = 1;
1698f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse->gid = gid;
1699f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse->mask = mask;
1700f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1701f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    memset(&fuse->root, 0, sizeof(fuse->root));
1702f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse->root.nid = FUSE_ROOT_ID; /* 1 */
1703f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse->root.refcount = 2;
1704f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse->root.namelen = strlen(fuse->source_path);
1705f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse->root.name = strdup(fuse->source_path);
1706f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse->root.userid = 0;
1707f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse->root.uid = AID_ROOT;
1708f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse->root.gid = fuse->gid;
1709f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1710f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (fuse->global->multi_user) {
1711f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        fuse->root.perm = PERM_PRE_ROOT;
1712f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        fuse->root.mode = 0711;
1713f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        snprintf(fuse->obb_path, sizeof(fuse->obb_path), "%s/obb", fuse->source_path);
1714f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    } else {
1715f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        fuse->root.perm = PERM_ROOT;
1716f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        fuse->root.mode = 0771 & ~mask;
1717f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        snprintf(fuse->obb_path, sizeof(fuse->obb_path), "%s/Android/obb", fuse->source_path);
1718dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    }
1719dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1720f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    return 0;
1721f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey}
1722f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1723f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkeystatic void run(const char* source_path, const char* label, uid_t uid,
1724f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        gid_t gid, bool multi_user, bool full_write) {
1725f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    struct fuse_global global;
1726f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    struct fuse fuse_default;
1727f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    struct fuse fuse_read;
1728f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    struct fuse fuse_write;
1729f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    struct fuse_handler handler_default;
1730f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    struct fuse_handler handler_read;
1731f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    struct fuse_handler handler_write;
1732f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_t thread_default;
1733f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_t thread_read;
1734f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_t thread_write;
1735f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1736f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    memset(&global, 0, sizeof(global));
1737f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    memset(&fuse_default, 0, sizeof(fuse_default));
1738f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    memset(&fuse_read, 0, sizeof(fuse_read));
1739f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    memset(&fuse_write, 0, sizeof(fuse_write));
1740f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    memset(&handler_default, 0, sizeof(handler_default));
1741f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    memset(&handler_read, 0, sizeof(handler_read));
1742f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    memset(&handler_write, 0, sizeof(handler_write));
1743f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1744f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_init(&global.lock, NULL);
1745f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    global.package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
1746f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    global.uid = uid;
1747f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    global.gid = gid;
1748f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    global.multi_user = multi_user;
1749f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1750f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse_default.global = &global;
1751f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    strcpy(fuse_default.source_path, source_path);
1752f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    snprintf(fuse_default.dest_path, PATH_MAX, "/mnt/runtime_default/%s", label);
1753f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1754f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse_read.global = &global;
1755f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    strcpy(fuse_read.source_path, source_path);
1756f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    snprintf(fuse_read.dest_path, PATH_MAX, "/mnt/runtime_read/%s", label);
1757f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1758f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse_write.global = &global;
1759f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    strcpy(fuse_write.source_path, source_path);
1760f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    snprintf(fuse_write.dest_path, PATH_MAX, "/mnt/runtime_write/%s", label);
1761f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1762f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    handler_default.fuse = &fuse_default;
1763f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    handler_read.fuse = &fuse_read;
1764f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    handler_write.fuse = &fuse_write;
1765f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1766f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    umask(0);
1767f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1768f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
1769f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            || fuse_setup(&fuse_read, AID_EVERYBODY, 0027)
1770f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027)) {
1771f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        ERROR("failed to fuse_setup\n");
1772f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        exit(1);
17732656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
17742656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1775f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    /* Drop privs */
1776f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (setgroups(sizeof(kGroups) / sizeof(kGroups[0]), kGroups) < 0) {
1777f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        ERROR("cannot setgroups: %s\n", strerror(errno));
1778f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        exit(1);
1779f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    }
1780f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (setgid(gid) < 0) {
1781dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        ERROR("cannot setgid: %s\n", strerror(errno));
1782f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        exit(1);
17832656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
1784f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (setuid(uid) < 0) {
1785dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        ERROR("cannot setuid: %s\n", strerror(errno));
1786f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        exit(1);
17872656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
17882656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1789f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (multi_user) {
1790f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        fs_prepare_dir(fuse_default.obb_path, 0775, uid, gid);
1791f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        fs_prepare_dir(fuse_read.obb_path, 0775, uid, gid);
1792f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        fs_prepare_dir(fuse_write.obb_path, 0775, uid, gid);
1793f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    }
17942656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1795f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (pthread_create(&thread_default, NULL, start_handler, &handler_default)
1796f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            || pthread_create(&thread_read, NULL, start_handler, &handler_read)
1797f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            || pthread_create(&thread_write, NULL, start_handler, &handler_write)) {
1798f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        ERROR("failed to pthread_create\n");
1799f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        exit(1);
1800f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    }
18012656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1802f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    watch_package_list(&global);
1803f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    ERROR("terminated prematurely\n");
1804f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    exit(1);
18052656735f515a41cf131c87be5f40550b6538ce80Jeff Brown}
18062656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1807f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkeyint main(int argc, char **argv) {
1808e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    const char *source_path = NULL;
1809f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    const char *label = NULL;
18102656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    uid_t uid = 0;
18112656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    gid_t gid = 0;
1812f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    bool multi_user = false;
1813f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    bool full_write = false;
18144f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood    int i;
18152fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall    struct rlimit rlim;
18168d28fa71fce6a5623488614250970ce78551a924Nick Kralevich    int fs_version;
18174f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood
1818dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    int opt;
1819f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    while ((opt = getopt(argc, argv, "u:g:mw")) != -1) {
1820dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        switch (opt) {
1821dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            case 'u':
1822dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                uid = strtoul(optarg, NULL, 10);
1823dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                break;
1824dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            case 'g':
1825dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                gid = strtoul(optarg, NULL, 10);
1826dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                break;
1827f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            case 'm':
1828f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey                multi_user = true;
1829dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                break;
1830f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            case 'w':
1831f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey                full_write = true;
1832dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                break;
1833dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            case '?':
1834dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            default:
1835dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                return usage();
1836dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
1837dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    }
1838dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1839dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    for (i = optind; i < argc; i++) {
18404f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        char* arg = argv[i];
1841dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        if (!source_path) {
1842e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey            source_path = arg;
1843f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        } else if (!label) {
1844f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            label = arg;
1845e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru        } else {
1846575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            ERROR("too many arguments\n");
1847575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            return usage();
18484f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        }
184903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
185003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1851e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    if (!source_path) {
1852e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey        ERROR("no source path specified\n");
1853e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey        return usage();
1854e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    }
1855f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!label) {
1856f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        ERROR("no label specified\n");
18574f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        return usage();
18584f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood    }
18592656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (!uid || !gid) {
186003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        ERROR("uid and gid must be nonzero\n");
18614f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        return usage();
186203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
186303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
18642fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall    rlim.rlim_cur = 8192;
18652fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall    rlim.rlim_max = 8192;
18662fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall    if (setrlimit(RLIMIT_NOFILE, &rlim)) {
18672fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall        ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno);
18682fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall    }
18692fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall
18708d28fa71fce6a5623488614250970ce78551a924Nick Kralevich    while ((fs_read_atomic_int("/data/.layout_version", &fs_version) == -1) || (fs_version < 3)) {
18718d28fa71fce6a5623488614250970ce78551a924Nick Kralevich        ERROR("installd fs upgrade not yet complete. Waiting...\n");
18728d28fa71fce6a5623488614250970ce78551a924Nick Kralevich        sleep(1);
18738d28fa71fce6a5623488614250970ce78551a924Nick Kralevich    }
18748d28fa71fce6a5623488614250970ce78551a924Nick Kralevich
1875f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    run(source_path, label, uid, gid, multi_user, full_write);
1876f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    return 1;
187703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
1878