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>
27e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts#include <stdbool.h>
2803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <stdio.h>
2903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <stdlib.h>
3003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <string.h>
3160281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes#include <sys/inotify.h>
3203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <sys/mount.h>
33ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris#include <sys/param.h>
3460281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes#include <sys/resource.h>
3503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <sys/stat.h>
364553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood#include <sys/statfs.h>
372fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall#include <sys/time.h>
38e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts#include <sys/types.h>
3960281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes#include <sys/uio.h>
4060281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes#include <unistd.h>
41dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
4244d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey#include <cutils/fs.h>
43dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey#include <cutils/hashmap.h>
44300d5649800744b3f5eab478f2bd7921f584b07dElliott Hughes#include <cutils/log.h>
45dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey#include <cutils/multiuser.h>
4620ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey#include <cutils/properties.h>
47e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts#include <packagelistparser/packagelistparser.h>
4803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
49b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland#include <private/android_filesystem_config.h>
50b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland
512abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg/* FUSE_CANONICAL_PATH is not currently upstreamed */
522abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg#define FUSE_CANONICAL_PATH 2016
532abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg
5403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland/* README
5503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
5603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * What is this?
5760281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes *
5803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
5960281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes * directory permissions (all files are given fixed owner, group, and
6060281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes * permissions at creation, owner, group, and permissions are not
6103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * changeable, symlinks and hardlinks are not createable, etc.
6203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
63e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey * See usage() for command line options.
6403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
65e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey * It must be run as root, but will drop to requested UID/GID as soon as it
66e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey * mounts a filesystem.  It will refuse to run if requested UID/GID are zero.
6703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
6803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * Things I believe to be true:
6903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
7003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK,
7103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * CREAT) must bump that node's refcount
7203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - don't forget that FORGET can forget multiple references (req->nlookup)
7303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - if an op that returns a fuse_entry fails writing the reply to the
7403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * kernel, you must rollback the refcount to reflect the reference the
7503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * kernel did not actually acquire
76dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey *
77dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey * This daemon can also derive custom filesystem permissions based on directory
78dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey * structure when requested. These custom permissions support several features:
79dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey *
80dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey * - Apps can access their own files in /Android/data/com.example/ without
81dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey * requiring any additional GIDs.
82dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey * - Separate permissions for protecting directories like Pictures and Music.
83dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey * - Multi-user separation on the same physical device.
8403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland */
8503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
8603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define FUSE_TRACE 0
8703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
8803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#if FUSE_TRACE
89300d5649800744b3f5eab478f2bd7921f584b07dElliott Hughes#define TRACE(x...) ALOGD(x)
9003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#else
9103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define TRACE(x...) do {} while (0)
9203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#endif
9303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
94300d5649800744b3f5eab478f2bd7921f584b07dElliott Hughes#define ERROR(x...) ALOGE(x)
9503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
9620ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey#define PROP_SDCARDFS_DEVICE "ro.sys.sdcardfs"
9720ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey#define PROP_SDCARDFS_USER "persist.sys.sdcardfs"
9820ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey
9903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define FUSE_UNKNOWN_INO 0xffffffff
10003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
101847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Maximum number of bytes to write in one request. */
102847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_WRITE (256 * 1024)
103847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
104847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Maximum number of bytes to read in one request. */
105847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_READ (128 * 1024)
106847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
107847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Largest possible request.
108847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown * The request size is bounded by the maximum size of a FUSE_WRITE request because it has
109847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown * the largest possible data payload. */
110847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_REQUEST_SIZE (sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE)
111847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Pseudo-error constant used to indicate that no fuse status is needed
1136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or that a reply has already been written. */
1146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown#define NO_STATUS 1
1156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
116dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey/* Supplementary groups to execute with */
117dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkeystatic const gid_t kGroups[1] = { AID_PACKAGE_INFO };
118dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
119dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey/* Permission mode for a specific node. Controls how file permissions
120dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey * are derived for children nodes. */
121dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkeytypedef enum {
122977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* Nothing special; this node should just inherit from its parent. */
123dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    PERM_INHERIT,
124977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* This node is one level above a normal root; used for legacy layouts
125977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey     * which use the first level to represent user_id. */
126f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    PERM_PRE_ROOT,
127977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* This node is "/" */
128dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    PERM_ROOT,
129977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* This node is "/Android" */
130dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    PERM_ANDROID,
131977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* This node is "/Android/data" */
132dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    PERM_ANDROID_DATA,
133977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* This node is "/Android/obb" */
134dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    PERM_ANDROID_OBB,
1352e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey    /* This node is "/Android/media" */
1362e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey    PERM_ANDROID_MEDIA,
137dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey} perm_t;
138dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
13903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct handle {
14003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int fd;
14103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
14203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
14303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct dirhandle {
14403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    DIR *d;
14503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
14603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
14703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct node {
1486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    __u32 refcount;
14903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    __u64 nid;
15003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    __u64 gen;
151faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    /*
152faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * The inode number for this FUSE node. Note that this isn't stable across
153faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * multiple invocations of the FUSE daemon.
154faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     */
155faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    __u32 ino;
15603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
157dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    /* State derived based on current position in hierarchy. */
158dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    perm_t perm;
159dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    userid_t userid;
160dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    uid_t uid;
16110a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey    bool under_android;
162dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
16311ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    struct node *next;          /* per-dir sibling list */
16411ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    struct node *child;         /* first contained file by this dir */
16511ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    struct node *parent;        /* containing directory */
16603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen;
16811ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    char *name;
169575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood    /* If non-null, this is the real name of the file in the underlying storage.
170575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     * This may differ from the field "name" only by case.
171575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     * strlen(actual_name) will always equal strlen(name), so it is safe to use
172575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     * namelen for both fields.
173575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     */
174575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood    char *actual_name;
175977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
176977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* If non-null, an exact underlying path that should be grafted into this
177977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey     * position. Used to support things like OBB. */
178977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    char* graft_path;
179977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    size_t graft_pathlen;
180c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski
181c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    bool deleted;
18203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
18303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
184dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkeystatic int str_hash(void *key) {
185dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    return hashmapHash(key, strlen(key));
186dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey}
187dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
18844d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey/** Test if two string keys are equal ignoring case */
18944d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkeystatic bool str_icase_equals(void *keyA, void *keyB) {
19044d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    return strcasecmp(keyA, keyB) == 0;
191dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey}
192dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
193f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey/* Global data for all FUSE mounts */
194f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkeystruct fuse_global {
1956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_t lock;
19603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
197f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    uid_t uid;
198f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    gid_t gid;
199f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    bool multi_user;
200f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
201f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    char source_path[PATH_MAX];
202f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    char obb_path[PATH_MAX];
203f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
204ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    Hashmap* package_to_appid;
205ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
2066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    __u64 next_generation;
20703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct node root;
208dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
209faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    /* Used to allocate unique inode numbers for fuse nodes. We use
210faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * a simple counter based scheme where inode numbers from deleted
211faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * nodes aren't reused. Note that inode allocations are not stable
212faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * across multiple invocation of the sdcard daemon, but that shouldn't
213faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * be a huge problem in practice.
214faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     *
215faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * Note that we restrict inodes to 32 bit unsigned integers to prevent
216faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * truncation on 32 bit processes when unsigned long long stat.st_ino is
217faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * assigned to an unsigned long ino_t type in an LP32 process.
218faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     *
219faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * Also note that fuse_attr and fuse_dirent inode values are 64 bits wide
220faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * on both LP32 and LP64, but the fuse kernel code doesn't squash 64 bit
221faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * inode numbers into 32 bit values on 64 bit kernels (see fuse_squash_ino
222faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * in fs/fuse/inode.c).
223faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     *
224faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     * Accesses must be guarded by |lock|.
225faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath     */
226faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    __u32 inode_ctr;
227ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
228ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    struct fuse* fuse_default;
229ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    struct fuse* fuse_read;
230ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    struct fuse* fuse_write;
231ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey};
232ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
233ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey/* Single FUSE mount */
234ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkeystruct fuse {
235ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    struct fuse_global* global;
236ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
237ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    char dest_path[PATH_MAX];
238ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
239ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    int fd;
240ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
241ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    gid_t gid;
242ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    mode_t mask;
24303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
24403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
245f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey/* Private data used by a single FUSE handler */
2467729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brownstruct fuse_handler {
2476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse* fuse;
2486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int token;
2496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2507729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    /* To save memory, we never use the contents of the request buffer and the read
2517729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown     * buffer at the same time.  This allows us to share the underlying storage. */
2527729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    union {
2537729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        __u8 request_buffer[MAX_REQUEST_SIZE];
254e24e9a5091221f09526c083520367820810a7c98Elliott Hughes        __u8 read_buffer[MAX_READ + PAGE_SIZE];
2557729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    };
2567729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown};
25703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
2586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic inline void *id_to_ptr(__u64 nid)
2596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
2606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return (void *) (uintptr_t) nid;
2616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
262b94d320b1e7e2a3493147f6763cd2825b111a4d8Mike Lockwood
2636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic inline __u64 ptr_to_id(void *ptr)
2646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
2656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return (__u64) (uintptr_t) ptr;
2666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
2676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void acquire_node_locked(struct node* node)
2696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
2706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->refcount++;
2716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount);
2726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
2736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void remove_node_from_parent_locked(struct node* node);
2756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void release_node_locked(struct node* node)
2776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
2786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount);
2796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node->refcount > 0) {
2806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->refcount--;
2816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->refcount) {
2826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            TRACE("DESTROY %p (%s)\n", node, node->name);
2836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            remove_node_from_parent_locked(node);
2846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                /* TODO: remove debugging - poison memory */
2866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            memset(node->name, 0xef, node->namelen);
2876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->name);
2886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->actual_name);
2896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            memset(node, 0xfc, sizeof(*node));
2906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node);
2916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
2926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
2936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        ERROR("Zero refcnt %p\n", node);
2946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
2956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
2966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void add_node_to_parent_locked(struct node *node, struct node *parent) {
2986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->parent = parent;
2996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->next = parent->child;
3006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent->child = node;
3016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(parent);
3026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
3036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void remove_node_from_parent_locked(struct node* node)
3056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
3066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node->parent) {
3076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (node->parent->child == node) {
3086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->parent->child = node->parent->child->next;
3096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        } else {
3106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            struct node *node2;
3116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node2 = node->parent->child;
3126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            while (node2->next != node)
3136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                node2 = node2->next;
3146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node2->next = node->next;
3156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
3166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        release_node_locked(node->parent);
3176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->parent = NULL;
3186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->next = NULL;
3196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
3206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
3216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Gets the absolute path to a node into the provided buffer.
3236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown *
3246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Populates 'buf' with the path and returns the length of the path on success,
3256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or returns -1 if the path is too long for the provided buffer.
326f43219e0b1022b257499289ceb951f6a1a44bf9cPaul Eastham */
327977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize) {
328977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    const char* name;
329977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    size_t namelen;
330977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    if (node->graft_path) {
331977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        name = node->graft_path;
332977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        namelen = node->graft_pathlen;
333977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    } else if (node->actual_name) {
334977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        name = node->actual_name;
335977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        namelen = node->namelen;
336977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    } else {
337977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        name = node->name;
338977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        namelen = node->namelen;
339977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
340977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
3416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (bufsize < namelen + 1) {
3426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -1;
3436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
3446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    ssize_t pathlen = 0;
346977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    if (node->parent && node->graft_path == NULL) {
347db4638ee3044dff2c211f89ac5a19a9734c6b62dDaniel Rosenberg        pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 1);
3486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (pathlen < 0) {
3496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -1;
350575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
3516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        buf[pathlen++] = '/';
35203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
35303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
3556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return pathlen + namelen;
3566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
3576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Finds the absolute path of a file within a given directory.
3596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Performs a case-insensitive search for the file and sets the buffer to the path
3606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * of the first matching file.  If 'search' is zero or if no match is found, sets
3616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * the buffer to the path that the file would have, assuming the name were case-sensitive.
3626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown *
3636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Populates 'buf' with the path and returns the actual name (within 'buf') on success,
3646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or returns NULL if the path is too long for the provided buffer.
3656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown */
3666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic char* find_file_within(const char* path, const char* name,
3676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* buf, size_t bufsize, int search)
3686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
3696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t pathlen = strlen(path);
3706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
3716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t childlen = pathlen + namelen + 1;
3726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char* actual;
3736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (bufsize <= childlen) {
3756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
3766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
3776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(buf, path, pathlen);
3796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    buf[pathlen] = '/';
3806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    actual = buf + pathlen + 1;
3816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(actual, name, namelen + 1);
3826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (search && access(buf, F_OK)) {
384575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        struct dirent* entry;
3856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        DIR* dir = opendir(path);
386575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        if (!dir) {
387dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            ERROR("opendir %s failed: %s\n", path, strerror(errno));
3886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return actual;
389575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
390575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        while ((entry = readdir(dir))) {
3916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!strcasecmp(entry->d_name, name)) {
3926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                /* we have a match - replace the name, don't need to copy the null again */
3936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                memcpy(actual, entry->d_name, namelen);
394575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood                break;
395575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            }
396575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
397575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        closedir(dir);
398575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood    }
3996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return actual;
400575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood}
401575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood
402ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkeystatic void attr_from_stat(struct fuse* fuse, struct fuse_attr *attr,
403ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        const struct stat *s, const struct node* node) {
404faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    attr->ino = node->ino;
40503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->size = s->st_size;
40603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->blocks = s->st_blocks;
407f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->atime = s->st_atim.tv_sec;
408f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->mtime = s->st_mtim.tv_sec;
409f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->ctime = s->st_ctim.tv_sec;
410f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->atimensec = s->st_atim.tv_nsec;
411f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->mtimensec = s->st_mtim.tv_nsec;
412f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->ctimensec = s->st_ctim.tv_nsec;
41303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->mode = s->st_mode;
41403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->nlink = s->st_nlink;
41503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
416dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    attr->uid = node->uid;
417ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
418ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    if (fuse->gid == AID_SDCARD_RW) {
419ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        /* As an optimization, certain trusted system components only run
420ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey         * as owner but operate across all users. Since we're now handing
421ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey         * out the sdcard_rw GID only to trusted apps, we're okay relaxing
422ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey         * the user boundary enforcement for the default view. The UIDs
423ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey         * assigned to app directories are still multiuser aware. */
424ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        attr->gid = AID_SDCARD_RW;
425ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    } else {
426ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        attr->gid = multiuser_get_uid(node->userid, fuse->gid);
427ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    }
428b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland
42910a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey    int visible_mode = 0775 & ~fuse->mask;
43010a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey    if (node->perm == PERM_PRE_ROOT) {
43110a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        /* Top of multi-user view should always be visible to ensure
43210a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey         * secondary users can traverse inside. */
43310a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        visible_mode = 0711;
43410a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey    } else if (node->under_android) {
43510a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        /* Block "other" access to Android directories, since only apps
43610a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey         * belonging to a specific user should be in there; we still
43710a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey         * leave +x open for the default view. */
43810a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        if (fuse->gid == AID_SDCARD_RW) {
43910a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey            visible_mode = visible_mode & ~0006;
44010a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        } else {
44110a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey            visible_mode = visible_mode & ~0007;
44210a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        }
443ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    }
444dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    int owner_mode = s->st_mode & 0700;
445ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    int filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
446dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    attr->mode = (attr->mode & S_IFMT) | filtered_mode;
447dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey}
448dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
44944d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkeystatic int touch(char* path, mode_t mode) {
45044d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    int fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, mode);
45144d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    if (fd == -1) {
45244d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (errno == EEXIST) {
45344d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            return 0;
45444d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        } else {
45544d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            ERROR("Failed to open(%s): %s\n", path, strerror(errno));
45644d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            return -1;
45744d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        }
45844d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    }
45944d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    close(fd);
46044d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    return 0;
46144d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey}
46244d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey
463dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkeystatic void derive_permissions_locked(struct fuse* fuse, struct node *parent,
464dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        struct node *node) {
465977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    appid_t appid;
466dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
467dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    /* By default, each node inherits from its parent */
468dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    node->perm = PERM_INHERIT;
469dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    node->userid = parent->userid;
470dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    node->uid = parent->uid;
47110a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey    node->under_android = parent->under_android;
472dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
473dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    /* Derive custom permissions based on parent and current node */
474dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    switch (parent->perm) {
475dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    case PERM_INHERIT:
476dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        /* Already inherited above */
477dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        break;
478f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    case PERM_PRE_ROOT:
479977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        /* Legacy internal layout places users at top level */
480977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        node->perm = PERM_ROOT;
481977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        node->userid = strtoul(node->name, NULL, 10);
482977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        break;
483dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    case PERM_ROOT:
484977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        /* Assume masked off by default. */
48544d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (!strcasecmp(node->name, "Android")) {
486dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            /* App-specific directories inside; let anyone traverse */
487dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            node->perm = PERM_ANDROID;
48810a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey            node->under_android = true;
489dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
490dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        break;
491dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    case PERM_ANDROID:
49244d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (!strcasecmp(node->name, "data")) {
493dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            /* App-specific directories inside; let anyone traverse */
494dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            node->perm = PERM_ANDROID_DATA;
49544d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        } else if (!strcasecmp(node->name, "obb")) {
496dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            /* App-specific directories inside; let anyone traverse */
497dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            node->perm = PERM_ANDROID_OBB;
498977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey            /* Single OBB directory is always shared */
499ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey            node->graft_path = fuse->global->obb_path;
500ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey            node->graft_pathlen = strlen(fuse->global->obb_path);
5012e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey        } else if (!strcasecmp(node->name, "media")) {
5022e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey            /* App-specific directories inside; let anyone traverse */
5032e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey            node->perm = PERM_ANDROID_MEDIA;
504dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
505dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        break;
506dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    case PERM_ANDROID_DATA:
507dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    case PERM_ANDROID_OBB:
5082e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey    case PERM_ANDROID_MEDIA:
509f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        appid = (appid_t) (uintptr_t) hashmapGet(fuse->global->package_to_appid, node->name);
510977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        if (appid != 0) {
511977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey            node->uid = multiuser_get_uid(parent->userid, appid);
512dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
513dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        break;
514dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    }
515aa04e818a4904b193e00d603785c93e888eab174Jeff Sharkey}
516aa04e818a4904b193e00d603785c93e888eab174Jeff Sharkey
517fe7646194425cbae816936f996993bc146814d18Jeff Sharkeystatic void derive_permissions_recursive_locked(struct fuse* fuse, struct node *parent) {
518fe7646194425cbae816936f996993bc146814d18Jeff Sharkey    struct node *node;
519fe7646194425cbae816936f996993bc146814d18Jeff Sharkey    for (node = parent->child; node; node = node->next) {
520fe7646194425cbae816936f996993bc146814d18Jeff Sharkey        derive_permissions_locked(fuse, parent, node);
521fe7646194425cbae816936f996993bc146814d18Jeff Sharkey        if (node->child) {
522fe7646194425cbae816936f996993bc146814d18Jeff Sharkey            derive_permissions_recursive_locked(fuse, node);
523fe7646194425cbae816936f996993bc146814d18Jeff Sharkey        }
524fe7646194425cbae816936f996993bc146814d18Jeff Sharkey    }
525fe7646194425cbae816936f996993bc146814d18Jeff Sharkey}
526fe7646194425cbae816936f996993bc146814d18Jeff Sharkey
527977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey/* Kernel has already enforced everything we returned through
528977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey * derive_permissions_locked(), so this is used to lock down access
529977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey * even further, such as enforcing that apps hold sdcard_rw. */
530977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic bool check_caller_access_to_name(struct fuse* fuse,
531977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        const struct fuse_in_header *hdr, const struct node* parent_node,
532f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        const char* name, int mode) {
533977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* Always block security-sensitive files at root */
534977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    if (parent_node && parent_node->perm == PERM_ROOT) {
53544d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (!strcasecmp(name, "autorun.inf")
53644d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey                || !strcasecmp(name, ".android_secure")
53744d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey                || !strcasecmp(name, "android_secure")) {
538977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey            return false;
539977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        }
540977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
541977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
54244d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    /* Root always has access; access for any other UIDs should always
54344d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey     * be controlled through packages.list. */
54444d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    if (hdr->uid == 0) {
545977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return true;
546977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
547977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
548977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* No extra permissions to enforce */
549977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    return true;
550977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey}
551977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
552977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic bool check_caller_access_to_node(struct fuse* fuse,
553f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        const struct fuse_in_header *hdr, const struct node* node, int mode) {
554f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    return check_caller_access_to_name(fuse, hdr, node->parent, node->name, mode);
555977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey}
556977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
5576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstruct node *create_node_locked(struct fuse* fuse,
5586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct node *parent, const char *name, const char* actual_name)
55903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
56003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct node *node;
5616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
56203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
563faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    // Detect overflows in the inode counter. "4 billion nodes should be enough
564faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    // for everybody".
565ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    if (fuse->global->inode_ctr == 0) {
566faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath        ERROR("No more inode numbers available");
567faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath        return NULL;
568faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    }
569faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath
57011ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    node = calloc(1, sizeof(struct node));
5716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node) {
5726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
57303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
57411ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    node->name = malloc(namelen + 1);
5756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node->name) {
57611ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham        free(node);
5776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
57811ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    }
57903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    memcpy(node->name, name, namelen + 1);
5806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (strcmp(name, actual_name)) {
5816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->actual_name = malloc(namelen + 1);
5826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->actual_name) {
5836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->name);
5846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node);
5856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return NULL;
5866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
5876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        memcpy(node->actual_name, actual_name, namelen + 1);
5886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
58903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    node->namelen = namelen;
5906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->nid = ptr_to_id(node);
591ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    node->ino = fuse->global->inode_ctr++;
592ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    node->gen = fuse->global->next_generation++;
593dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
594c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    node->deleted = false;
595c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski
596dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    derive_permissions_locked(fuse, parent, node);
5976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(node);
5986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    add_node_to_parent_locked(node, parent);
59903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    return node;
60003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
60103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int rename_node_locked(struct node *node, const char *name,
6036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* actual_name)
60411ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham{
6056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
6066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int need_actual_name = strcmp(name, actual_name);
6076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
6086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* make the storage bigger without actually changing the name
6096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * in case an error occurs part way */
6106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (namelen > node->namelen) {
6116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* new_name = realloc(node->name, namelen + 1);
6126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!new_name) {
6136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -ENOMEM;
6146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
6156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->name = new_name;
6166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (need_actual_name && node->actual_name) {
6176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            char* new_actual_name = realloc(node->actual_name, namelen + 1);
6186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!new_actual_name) {
6196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                return -ENOMEM;
6206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
6216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->actual_name = new_actual_name;
6226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
6236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
62403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* update the name, taking care to allocate storage before overwriting the old name */
6266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (need_actual_name) {
6276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->actual_name) {
6286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->actual_name = malloc(namelen + 1);
6296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!node->actual_name) {
6306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                return -ENOMEM;
6316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
6326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
6336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        memcpy(node->actual_name, actual_name, namelen + 1);
6346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
6356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        free(node->actual_name);
6366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->actual_name = NULL;
6376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
6386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(node->name, name, namelen + 1);
6396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->namelen = namelen;
6406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
64103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
64203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
64403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
6456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (nid == FUSE_ROOT_ID) {
646ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        return &fuse->global->root;
64703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    } else {
64803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        return id_to_ptr(nid);
64903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
65003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
65103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node* lookup_node_and_path_by_id_locked(struct fuse* fuse, __u64 nid,
6536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* buf, size_t bufsize)
65403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
6556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node = lookup_node_by_id_locked(fuse, nid);
6566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node && get_node_path_locked(node, buf, bufsize) < 0) {
6576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node = NULL;
65803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
6596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return node;
66003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
66103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node *lookup_child_by_name_locked(struct node *node, const char *name)
66303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
66403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    for (node = node->child; node; node = node->next) {
6656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        /* use exact string comparison, nodes that differ by case
6666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * must be considered distinct even if they refer to the same
6676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * underlying file as otherwise operations such as "mv x x"
6686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * will not work because the source and target nodes are the same. */
669c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski        if (!strcmp(name, node->name) && !node->deleted) {
67011ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham            return node;
67111ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham        }
67211ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    }
67311ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    return 0;
67411ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham}
67511ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham
6766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node* acquire_or_create_child_locked(
6776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct fuse* fuse, struct node* parent,
6786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* name, const char* actual_name)
67903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
6806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* child = lookup_child_by_name_locked(parent, name);
6816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (child) {
6826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        acquire_node_locked(child);
6836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
6846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        child = create_node_locked(fuse, parent, name, actual_name);
68503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
6866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return child;
68703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
68803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void fuse_status(struct fuse *fuse, __u64 unique, int err)
69003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
69103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct fuse_out_header hdr;
69203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.len = sizeof(hdr);
69303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.error = err;
69403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.unique = unique;
69503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    write(fuse->fd, &hdr, sizeof(hdr));
69603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
69703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
69903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
70003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct fuse_out_header hdr;
70103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct iovec vec[2];
70203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int res;
70303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
70403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.len = len + sizeof(hdr);
70503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.error = 0;
70603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.unique = unique;
70703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
70803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[0].iov_base = &hdr;
70903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[0].iov_len = sizeof(hdr);
71003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[1].iov_base = data;
71103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[1].iov_len = len;
71203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
71303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    res = writev(fuse->fd, vec, 2);
71403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    if (res < 0) {
71503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        ERROR("*** REPLY FAILED *** %d\n", errno);
71603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
71703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
71803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
7196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int fuse_reply_entry(struct fuse* fuse, __u64 unique,
7206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct node* parent, const char* name, const char* actual_name,
7216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* path)
72203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
723fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct node* node;
7246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_entry_out out;
7256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct stat s;
72603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
7276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (lstat(path, &s) < 0) {
72844d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        return -errno;
72903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
730fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
731f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
7326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
7336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node) {
734f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        pthread_mutex_unlock(&fuse->global->lock);
7356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
7366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memset(&out, 0, sizeof(out));
738ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    attr_from_stat(fuse, &out.attr, &s, node);
7396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.attr_valid = 10;
7406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.entry_valid = 10;
74103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    out.nodeid = node->nid;
74203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    out.generation = node->gen;
743f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
74403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    fuse_reply(fuse, unique, &out, sizeof(out));
7456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
74603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
74703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
748dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkeystatic int fuse_reply_attr(struct fuse* fuse, __u64 unique, const struct node* node,
7496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* path)
75003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
7516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_attr_out out;
7526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct stat s;
753fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (lstat(path, &s) < 0) {
7556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
756fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
7576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memset(&out, 0, sizeof(out));
758ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    attr_from_stat(fuse, &out.attr, &s, node);
7596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.attr_valid = 10;
7606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse_reply(fuse, unique, &out, sizeof(out));
7616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
7626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
763fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
764ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkeystatic void fuse_notify_delete(struct fuse* fuse, const __u64 parent,
765ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        const __u64 child, const char* name) {
766ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    struct fuse_out_header hdr;
767ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    struct fuse_notify_delete_out data;
768ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    struct iovec vec[3];
769ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    size_t namelen = strlen(name);
770ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    int res;
771ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
772ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    hdr.len = sizeof(hdr) + sizeof(data) + namelen + 1;
773ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    hdr.error = FUSE_NOTIFY_DELETE;
774ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    hdr.unique = 0;
775ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
776ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    data.parent = parent;
777ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    data.child = child;
778ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    data.namelen = namelen;
779ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    data.padding = 0;
780ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
781ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    vec[0].iov_base = &hdr;
782ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    vec[0].iov_len = sizeof(hdr);
783ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    vec[1].iov_base = &data;
784ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    vec[1].iov_len = sizeof(data);
785ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    vec[2].iov_base = (void*) name;
786ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    vec[2].iov_len = namelen + 1;
787ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
788ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    res = writev(fuse->fd, vec, 3);
789ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    /* Ignore ENOENT, since other views may not have seen the entry */
790ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    if (res < 0 && errno != ENOENT) {
791ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        ERROR("*** NOTIFY FAILED *** %d\n", errno);
792ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    }
793ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey}
794ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
7956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
7966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const struct fuse_in_header *hdr, const char* name)
7976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
7986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
7996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
8006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
8016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
8026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
803f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
8046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
8056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
806e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] LOOKUP %s @ %"PRIx64" (%s)\n", handler->token, name, hdr->nodeid,
8076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        parent_node ? parent_node->name : "?");
808f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
8096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
8106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
8116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
8126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
8136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
814f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, R_OK)) {
815977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
816977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
817977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
8186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
819fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
820fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_forget(struct fuse* fuse, struct fuse_handler* handler,
822fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_forget_in *req)
823fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
8246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
825fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
826f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
8276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_by_id_locked(fuse, hdr->nodeid);
828e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] FORGET #%"PRIu64" @ %"PRIx64" (%s)\n", handler->token, req->nlookup,
8296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            hdr->nodeid, node ? node->name : "?");
8306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node) {
8316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        __u64 n = req->nlookup;
8326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        while (n--) {
8336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            release_node_locked(node);
8346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
835fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
836f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
8376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS; /* no reply */
838fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
839fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_getattr(struct fuse* fuse, struct fuse_handler* handler,
841fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_getattr_in *req)
842fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
8436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
8446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
8456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
846f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
8476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
848e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] GETATTR flags=%x fh=%"PRIx64" @ %"PRIx64" (%s)\n", handler->token,
8496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->getattr_flags, req->fh, hdr->nodeid, node ? node->name : "?");
850f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
851fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
852fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
8536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
854fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
855f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
856977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
857977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
858977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
859dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    return fuse_reply_attr(fuse, hdr->unique, node, path);
860fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
861fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
863fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
864fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
8656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
8666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
867fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct timespec times[2];
868fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
869f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
8706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
871e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] SETATTR fh=%"PRIx64" valid=%x @ %"PRIx64" (%s)\n", handler->token,
8726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
873f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
8746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
875fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
8766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
877fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
878a80f0986bb39ae03ba9014bf4974fc26ae48da70Marco Nelissen
879a80f0986bb39ae03ba9014bf4974fc26ae48da70Marco Nelissen    if (!(req->valid & FATTR_FH) &&
880f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            !check_caller_access_to_node(fuse, hdr, node, W_OK)) {
881977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
882977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
883fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* XXX: incomplete implementation on purpose.
8856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * chmod/chown should NEVER be implemented.*/
886fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
887853574ddc766da725dd114fe1d1102c59f713f3bElliott Hughes    if ((req->valid & FATTR_SIZE) && truncate64(path, req->size) < 0) {
8886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
889fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
890fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
891fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* Handle changing atime and mtime.  If FATTR_ATIME_and FATTR_ATIME_NOW
892fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * are both set, then set it to the current time.  Else, set it to the
893fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * time specified in the request.  Same goes for mtime.  Use utimensat(2)
894fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * as it allows ATIME and MTIME to be changed independently, and has
895fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * nanosecond resolution which fuse also has.
896fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     */
897fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
898fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        times[0].tv_nsec = UTIME_OMIT;
899fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        times[1].tv_nsec = UTIME_OMIT;
900fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        if (req->valid & FATTR_ATIME) {
901fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            if (req->valid & FATTR_ATIME_NOW) {
902fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_nsec = UTIME_NOW;
903fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            } else {
904fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_sec = req->atime;
905fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_nsec = req->atimensec;
906fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            }
907fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        }
908fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        if (req->valid & FATTR_MTIME) {
909fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            if (req->valid & FATTR_MTIME_NOW) {
910fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_nsec = UTIME_NOW;
911fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            } else {
912fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_sec = req->mtime;
913fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_nsec = req->mtimensec;
914fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            }
915fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        }
9166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        TRACE("[%d] Calling utimensat on %s with atime %ld, mtime=%ld\n",
9176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                handler->token, path, times[0].tv_sec, times[1].tv_sec);
9186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (utimensat(-1, path, times, 0) < 0) {
9196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -errno;
92003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        }
921fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
922dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    return fuse_reply_attr(fuse, hdr->unique, node, path);
923fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
924fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
926fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
927fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
9286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
9296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
9306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
9316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
9326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
933f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
9346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
9356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
936e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] MKNOD %s 0%o @ %"PRIx64" (%s)\n", handler->token,
9376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
938f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
9396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
9406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
9416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
9426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
943fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
944f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
945977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
946977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
947fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 mode = (req->mode & (~0777)) | 0664;
9486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (mknod(child_path, mode, req->rdev) < 0) {
9496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
950fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
9516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
952fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
953fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
955fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
956fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
9576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
9586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
9596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
9606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
9616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
962f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
9636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
9646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
965e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] MKDIR %s 0%o @ %"PRIx64" (%s)\n", handler->token,
9666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
967f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
9686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
9696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
9706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
9716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
972fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
973f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
974977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
975977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
976fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 mode = (req->mode & (~0777)) | 0775;
9776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (mkdir(child_path, mode) < 0) {
9786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
979fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
98044d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey
98144d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    /* When creating /Android/data and /Android/obb, mark them as .nomedia */
98244d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "data")) {
98344d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        char nomedia[PATH_MAX];
98444d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        snprintf(nomedia, PATH_MAX, "%s/.nomedia", child_path);
98544d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (touch(nomedia, 0664) != 0) {
98644d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
98744d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            return -ENOENT;
98844d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        }
98944d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    }
99044d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "obb")) {
99144d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        char nomedia[PATH_MAX];
992ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->global->obb_path);
99344d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (touch(nomedia, 0664) != 0) {
99444d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
99544d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            return -ENOENT;
99644d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        }
99744d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    }
99844d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey
9996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
1000fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1001fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
1003fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const char* name)
1004fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
10056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
1006c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    struct node* child_node;
10076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
10086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
1009fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1010f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
10116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
10126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
1013e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] UNLINK %s @ %"PRIx64" (%s)\n", handler->token,
10146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, hdr->nodeid, parent_node ? parent_node->name : "?");
1015f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
1016fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !find_file_within(parent_path, name,
10186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1)) {
10196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
10206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
1021f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
1022977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
1023977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
10246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (unlink(child_path) < 0) {
10256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
10266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
1027f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
1028c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    child_node = lookup_child_by_name_locked(parent_node, name);
1029c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    if (child_node) {
1030c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski        child_node->deleted = true;
1031c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    }
1032f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
1033ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    if (parent_node && child_node) {
1034ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        /* Tell all other views that node is gone */
1035ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        TRACE("[%d] fuse_notify_delete parent=%"PRIx64", child=%"PRIx64", name=%s\n",
1036ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey                handler->token, (uint64_t) parent_node->nid, (uint64_t) child_node->nid, name);
1037ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        if (fuse != fuse->global->fuse_default) {
1038ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey            fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
1039ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        }
1040ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        if (fuse != fuse->global->fuse_read) {
1041ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey            fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
1042ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        }
1043ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        if (fuse != fuse->global->fuse_write) {
1044ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey            fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
1045ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        }
1046ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    }
10476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1048fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1049fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
1051fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const char* name)
1052fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1053c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    struct node* child_node;
10546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
10556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
10566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
1057fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1058f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
10596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
10606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
1061e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] RMDIR %s @ %"PRIx64" (%s)\n", handler->token,
10626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, hdr->nodeid, parent_node ? parent_node->name : "?");
1063f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
1064fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !find_file_within(parent_path, name,
10666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1)) {
10676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
10686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
1069f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
1070977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
1071977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
10726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (rmdir(child_path) < 0) {
10736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
10746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
1075f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
1076c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    child_node = lookup_child_by_name_locked(parent_node, name);
1077c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    if (child_node) {
1078c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski        child_node->deleted = true;
1079c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    }
1080f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
1081ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    if (parent_node && child_node) {
1082ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        /* Tell all other views that node is gone */
1083ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        TRACE("[%d] fuse_notify_delete parent=%"PRIx64", child=%"PRIx64", name=%s\n",
1084ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey                handler->token, (uint64_t) parent_node->nid, (uint64_t) child_node->nid, name);
1085ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        if (fuse != fuse->global->fuse_default) {
1086ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey            fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
1087ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        }
1088ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        if (fuse != fuse->global->fuse_read) {
1089ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey            fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
1090ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        }
1091ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        if (fuse != fuse->global->fuse_write) {
1092ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey            fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
1093ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        }
1094ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    }
10956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1096fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1097fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_rename(struct fuse* fuse, struct fuse_handler* handler,
1099fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
11006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* old_name, const char* new_name)
1101fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
11026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* old_parent_node;
11036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* new_parent_node;
11046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* child_node;
11056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char old_parent_path[PATH_MAX];
11066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char new_parent_path[PATH_MAX];
11076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char old_child_path[PATH_MAX];
11086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char new_child_path[PATH_MAX];
11096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* new_actual_name;
1110fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
1111fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1112f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
11136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
11146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_parent_path, sizeof(old_parent_path));
11156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
11166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            new_parent_path, sizeof(new_parent_path));
1117e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] RENAME %s->%s @ %"PRIx64" (%s) -> %"PRIx64" (%s)\n", handler->token,
11186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_name, new_name,
11196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            hdr->nodeid, old_parent_node ? old_parent_node->name : "?",
11206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->newdir, new_parent_node ? new_parent_node->name : "?");
11216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!old_parent_node || !new_parent_node) {
11226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
11236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto lookup_error;
11246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
1125f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, old_parent_node, old_name, W_OK)) {
1126977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        res = -EACCES;
1127977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        goto lookup_error;
1128977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
1129f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, new_parent_node, new_name, W_OK)) {
1130977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        res = -EACCES;
1131977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        goto lookup_error;
1132977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
11336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    child_node = lookup_child_by_name_locked(old_parent_node, old_name);
11346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!child_node || get_node_path_locked(child_node,
11356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_child_path, sizeof(old_child_path)) < 0) {
11366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
11376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto lookup_error;
11386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
11396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(child_node);
1140f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
11416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
11426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* Special case for renaming a file where destination is same path
11436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * differing only by case.  In this case we don't want to look for a case
11446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * insensitive match.  This allows commands like "mv foo FOO" to work as expected.
11456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     */
11466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int search = old_parent_node != new_parent_node
11476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            || strcasecmp(old_name, new_name);
11486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!(new_actual_name = find_file_within(new_parent_path, new_name,
11496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            new_child_path, sizeof(new_child_path), search))) {
11506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
11516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto io_error;
1152fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1153fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
11546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RENAME %s->%s\n", handler->token, old_child_path, new_child_path);
11556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = rename(old_child_path, new_child_path);
11566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (res < 0) {
11576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -errno;
11586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto io_error;
1159fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1160fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1161f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
11626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = rename_node_locked(child_node, new_name, new_actual_name);
11636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!res) {
11646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        remove_node_from_parent_locked(child_node);
1165fe7646194425cbae816936f996993bc146814d18Jeff Sharkey        derive_permissions_locked(fuse, new_parent_node, child_node);
1166fe7646194425cbae816936f996993bc146814d18Jeff Sharkey        derive_permissions_recursive_locked(fuse, child_node);
11676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        add_node_to_parent_locked(child_node, new_parent_node);
1168fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
11696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    goto done;
1170fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
11716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownio_error:
1172f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
11736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Browndone:
11746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    release_node_locked(child_node);
11756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownlookup_error:
1176f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
11776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return res;
1178fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1179fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1180977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic int open_flags_to_access_mode(int open_flags) {
1181977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    if ((open_flags & O_ACCMODE) == O_RDONLY) {
1182977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return R_OK;
1183977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    } else if ((open_flags & O_ACCMODE) == O_WRONLY) {
1184977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return W_OK;
1185977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    } else {
1186977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        /* Probably O_RDRW, but treat as default to be safe */
1187977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return R_OK | W_OK;
1188977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
1189977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey}
1190977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
11916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_open(struct fuse* fuse, struct fuse_handler* handler,
1192fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_open_in* req)
1193fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
11946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
11956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
1196fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_open_out out;
1197fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h;
119803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1199f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
12006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
1201e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] OPEN 0%o @ %"PRIx64" (%s)\n", handler->token,
12026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->flags, hdr->nodeid, node ? node->name : "?");
1203f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
1204fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1205fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
12066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
1207fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1208aa04e818a4904b193e00d603785c93e888eab174Jeff Sharkey    if (!check_caller_access_to_node(fuse, hdr, node,
1209f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            open_flags_to_access_mode(req->flags))) {
1210977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
1211977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
12126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    h = malloc(sizeof(*h));
12136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!h) {
12146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
12156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
12166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] OPEN %s\n", handler->token, path);
1217fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    h->fd = open(path, req->flags);
1218fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (h->fd < 0) {
1219fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        free(h);
12206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1221fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1222fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.fh = ptr_to_id(h);
1223fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.open_flags = 0;
1224738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel
1225738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel#ifdef FUSE_SHORTCIRCUIT
1226738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel    out.lower_fd = h->fd;
1227738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel#else
1228fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.padding = 0;
1229738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel#endif
1230738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel
1231fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
12326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1233fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1234fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
12356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_read(struct fuse* fuse, struct fuse_handler* handler,
1236fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_read_in* req)
1237fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1238fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
1239fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u64 unique = hdr->unique;
1240fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 size = req->size;
1241fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u64 offset = req->offset;
12426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int res;
1243e24e9a5091221f09526c083520367820810a7c98Elliott Hughes    __u8 *read_buffer = (__u8 *) ((uintptr_t)(handler->read_buffer + PAGE_SIZE) & ~((uintptr_t)PAGE_SIZE-1));
12446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1245fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* Don't access any other fields of hdr or req beyond this point, the read buffer
1246fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * overlaps the request buffer and will clobber data in the request.  This
1247fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * saves us 128KB per request handler thread at the cost of this scary comment. */
12486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1249e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] READ %p(%d) %u@%"PRIu64"\n", handler->token,
1250e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland            h, h->fd, size, (uint64_t) offset);
125180b435a3f35795600654e9705f4b3fbbcc427a9dArpad Horvath    if (size > MAX_READ) {
12526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -EINVAL;
1253fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
125480b435a3f35795600654e9705f4b3fbbcc427a9dArpad Horvath    res = pread64(h->fd, read_buffer, size, offset);
1255fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (res < 0) {
12566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1257fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
125880b435a3f35795600654e9705f4b3fbbcc427a9dArpad Horvath    fuse_reply(fuse, unique, read_buffer, res);
12596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1260fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1261fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
12626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_write(struct fuse* fuse, struct fuse_handler* handler,
1263fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_write_in* req,
1264fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const void* buffer)
1265fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1266fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_write_out out;
1267fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
1268fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
1269e24e9a5091221f09526c083520367820810a7c98Elliott Hughes    __u8 aligned_buffer[req->size] __attribute__((__aligned__(PAGE_SIZE)));
127060281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes
127149e9344bddca3699c04f3da8c689d0f2b1a338b6Arpad Horvath    if (req->flags & O_DIRECT) {
127249e9344bddca3699c04f3da8c689d0f2b1a338b6Arpad Horvath        memcpy(aligned_buffer, buffer, req->size);
127349e9344bddca3699c04f3da8c689d0f2b1a338b6Arpad Horvath        buffer = (const __u8*) aligned_buffer;
127449e9344bddca3699c04f3da8c689d0f2b1a338b6Arpad Horvath    }
12756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1276e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] WRITE %p(%d) %u@%"PRIu64"\n", handler->token,
12776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            h, h->fd, req->size, req->offset);
1278fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    res = pwrite64(h->fd, buffer, req->size, req->offset);
1279fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (res < 0) {
12806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1281fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1282fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.size = res;
128319ec8860c1d80836b176dbf3dc434a94182094b7Daisuke Okitsu    out.padding = 0;
1284fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
12856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1286fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1287fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
12886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_statfs(struct fuse* fuse, struct fuse_handler* handler,
1289fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr)
1290fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
12916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
1292fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct statfs stat;
1293fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_statfs_out out;
1294fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
1295fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1296f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
12976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] STATFS\n", handler->token);
1298ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    res = get_node_path_locked(&fuse->global->root, path, sizeof(path));
1299f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
13006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (res < 0) {
13016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
13026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
1303ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    if (statfs(fuse->global->root.name, &stat) < 0) {
13046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1305fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1306fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    memset(&out, 0, sizeof(out));
1307fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.blocks = stat.f_blocks;
1308fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bfree = stat.f_bfree;
1309fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bavail = stat.f_bavail;
1310fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.files = stat.f_files;
1311fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.ffree = stat.f_ffree;
1312fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bsize = stat.f_bsize;
1313fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.namelen = stat.f_namelen;
1314fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.frsize = stat.f_frsize;
1315fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
13166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1317fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1318fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
13196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_release(struct fuse* fuse, struct fuse_handler* handler,
1320fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_release_in* req)
1321fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1322fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
13236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
13246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RELEASE %p(%d)\n", handler->token, h, h->fd);
1325fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    close(h->fd);
1326fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    free(h);
13276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1328fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1329fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
13306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
1331fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
1332fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1333f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    bool is_dir = (hdr->opcode == FUSE_FSYNCDIR);
1334f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    bool is_data_sync = req->fsync_flags & 1;
13356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1336f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    int fd = -1;
1337f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    if (is_dir) {
1338f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes      struct dirhandle *dh = id_to_ptr(req->fh);
1339f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes      fd = dirfd(dh->d);
1340f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    } else {
1341f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes      struct handle *h = id_to_ptr(req->fh);
1342f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes      fd = h->fd;
1343f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    }
1344f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes
1345f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    TRACE("[%d] %s %p(%d) is_data_sync=%d\n", handler->token,
1346f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes            is_dir ? "FSYNCDIR" : "FSYNC",
1347f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes            id_to_ptr(req->fh), fd, is_data_sync);
1348f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    int res = is_data_sync ? fdatasync(fd) : fsync(fd);
1349f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    if (res == -1) {
13506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1351fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
13526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1353fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1354fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
13556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_flush(struct fuse* fuse, struct fuse_handler* handler,
1356fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr)
1357fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
13586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] FLUSH\n", handler->token);
13596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1360fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1361fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
13626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
1363fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_open_in* req)
1364fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
13656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
13666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
1367fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_open_out out;
1368fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirhandle *h;
1369fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1370f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
13716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
1372e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland    TRACE("[%d] OPENDIR @ %"PRIx64" (%s)\n", handler->token,
13736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            hdr->nodeid, node ? node->name : "?");
1374f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
13756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1376fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
13776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
1378fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1379f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
1380977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
1381977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
1382fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    h = malloc(sizeof(*h));
1383fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!h) {
13846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
1385fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
13866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] OPENDIR %s\n", handler->token, path);
1387fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    h->d = opendir(path);
13886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!h->d) {
1389fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        free(h);
13906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1391fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1392fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.fh = ptr_to_id(h);
13933a8768804ce4b4797359d5df03ec8897fe43de90Ken Sumrall    out.open_flags = 0;
1394738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel
1395738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel#ifdef FUSE_SHORTCIRCUIT
1396738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel    out.lower_fd = -1;
1397738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel#else
13983a8768804ce4b4797359d5df03ec8897fe43de90Ken Sumrall    out.padding = 0;
1399738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel#endif
1400738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel
1401fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
14026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1403fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1404fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
14056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_readdir(struct fuse* fuse, struct fuse_handler* handler,
1406fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_read_in* req)
1407fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1408fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    char buffer[8192];
1409fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
1410fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirent *de;
1411fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirhandle *h = id_to_ptr(req->fh);
14126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
14136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] READDIR %p\n", handler->token, h);
1414fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (req->offset == 0) {
1415fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        /* rewinddir() might have been called above us, so rewind here too */
14166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        TRACE("[%d] calling rewinddir()\n", handler->token);
1417fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        rewinddir(h->d);
1418fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1419fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    de = readdir(h->d);
1420fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!de) {
14216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return 0;
1422fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1423fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->ino = FUSE_UNKNOWN_INO;
1424fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
1425fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->off = req->offset + 1;
1426fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->type = de->d_type;
1427fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->namelen = strlen(de->d_name);
1428fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    memcpy(fde->name, de->d_name, fde->namelen + 1);
1429fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, fde,
14306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
14316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1432fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1433fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
14346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_releasedir(struct fuse* fuse, struct fuse_handler* handler,
1435fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_release_in* req)
1436fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1437fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirhandle *h = id_to_ptr(req->fh);
14386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
14396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RELEASEDIR %p\n", handler->token, h);
1440fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    closedir(h->d);
1441fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    free(h);
14426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1443fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1444fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
14456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_init(struct fuse* fuse, struct fuse_handler* handler,
1446fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_init_in* req)
1447fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1448fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_init_out out;
1449ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    size_t fuse_struct_size;
1450fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
14516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] INIT ver=%d.%d maxread=%d flags=%x\n",
14526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            handler->token, req->major, req->minor, req->max_readahead, req->flags);
1453ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris
1454ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    /* Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
1455ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris     * defined (fuse version 7.6). The structure is the same from 7.6 through
1456ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris     * 7.22. Beginning with 7.23, the structure increased in size and added
1457ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris     * new parameters.
1458ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris     */
1459ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) {
1460ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris        ERROR("Fuse kernel version mismatch: Kernel version %d.%d, Expected at least %d.6",
1461ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris              req->major, req->minor, FUSE_KERNEL_VERSION);
1462ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris        return -1;
1463ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    }
1464ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris
1465f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    /* We limit ourselves to 15 because we don't handle BATCH_FORGET yet */
1466f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    out.minor = MIN(req->minor, 15);
1467ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    fuse_struct_size = sizeof(out);
1468ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
1469ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    /* FUSE_KERNEL_VERSION >= 23. */
1470ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris
1471ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    /* If the kernel only works on minor revs older than or equal to 22,
1472ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris     * then use the older structure size since this code only uses the 7.22
1473ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris     * version of the structure. */
1474ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    if (req->minor <= 22) {
1475ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris        fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
1476ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    }
1477ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris#endif
1478ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris
1479fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.major = FUSE_KERNEL_VERSION;
1480fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_readahead = req->max_readahead;
1481fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
1482738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel
1483738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel#ifdef FUSE_SHORTCIRCUIT
1484738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel    out.flags |= FUSE_SHORTCIRCUIT;
1485738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel#endif
1486738e0dcf0a09fa7659a7efa79de9482f7cf54e4fThierry Strudel
1487fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_background = 32;
1488fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.congestion_threshold = 32;
1489fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_write = MAX_WRITE;
1490ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    fuse_reply(fuse, hdr->unique, &out, fuse_struct_size);
14916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1492fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1493fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
14942abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenbergstatic int handle_canonical_path(struct fuse* fuse, struct fuse_handler* handler,
14952abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg        const struct fuse_in_header *hdr)
14962abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg{
14972abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    struct node* node;
14982abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    char path[PATH_MAX];
14992abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    int len;
15002abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg
15012abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    pthread_mutex_lock(&fuse->global->lock);
15022abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
15032abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg            path, sizeof(path));
15042abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    TRACE("[%d] CANONICAL_PATH @ %" PRIx64 " (%s)\n", handler->token, hdr->nodeid,
15052abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg        node ? node->name : "?");
15062abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    pthread_mutex_unlock(&fuse->global->lock);
15072abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg
15082abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    if (!node) {
15092abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg        return -ENOENT;
15102abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    }
15112abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
15122abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg        return -EACCES;
15132abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    }
15142abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    len = strlen(path);
15152abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    if (len + 1 > PATH_MAX)
15162abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg        len = PATH_MAX - 1;
15172abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    path[PATH_MAX - 1] = 0;
15182abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    fuse_reply(fuse, hdr->unique, path, len + 1);
15192abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    return NO_STATUS;
15202abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg}
15212abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg
15222abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg
15236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
1524fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const void *data, size_t data_len)
1525fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
152603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    switch (hdr->opcode) {
152703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_LOOKUP: { /* bytez[] -> entry_out */
1528847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char* name = data;
15296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_lookup(fuse, handler, hdr, name);
153003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1531847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
153203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_FORGET: {
1533847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_forget_in *req = data;
15346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_forget(fuse, handler, hdr, req);
153503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1536847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
153703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_GETATTR: { /* getattr_in -> attr_out */
1538847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_getattr_in *req = data;
15396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_getattr(fuse, handler, hdr, req);
154003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1541847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
154203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_SETATTR: { /* setattr_in -> attr_out */
1543847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_setattr_in *req = data;
15446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_setattr(fuse, handler, hdr, req);
154503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1546847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
154703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_READLINK:
154803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_SYMLINK:
154903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
1550847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_mknod_in *req = data;
1551847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char *name = ((const char*) data) + sizeof(*req);
15526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_mknod(fuse, handler, hdr, req, name);
155303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1554847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
155503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
1556847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_mkdir_in *req = data;
1557847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char *name = ((const char*) data) + sizeof(*req);
15586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_mkdir(fuse, handler, hdr, req, name);
155903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1560847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
156103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_UNLINK: { /* bytez[] -> */
1562847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char* name = data;
15636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_unlink(fuse, handler, hdr, name);
156403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1565847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
156603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RMDIR: { /* bytez[] -> */
1567847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char* name = data;
15686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_rmdir(fuse, handler, hdr, name);
156903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1570847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
157103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RENAME: { /* rename_in, oldname, newname ->  */
1572847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_rename_in *req = data;
15736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char *old_name = ((const char*) data) + sizeof(*req);
15746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char *new_name = old_name + strlen(old_name) + 1;
15756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_rename(fuse, handler, hdr, req, old_name, new_name);
157603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1577847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1578fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown//    case FUSE_LINK:
157903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_OPEN: { /* open_in -> open_out */
1580847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_open_in *req = data;
15816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_open(fuse, handler, hdr, req);
158203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1583847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
158403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_READ: { /* read_in -> byte[] */
1585847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_read_in *req = data;
15866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_read(fuse, handler, hdr, req);
158703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1588847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
158903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
1590847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_write_in *req = data;
1591847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const void* buffer = (const __u8*)data + sizeof(*req);
15926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_write(fuse, handler, hdr, req, buffer);
159303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1594847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
15954553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    case FUSE_STATFS: { /* getattr_in -> attr_out */
15966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_statfs(fuse, handler, hdr);
15974553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    }
1598847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
159903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RELEASE: { /* release_in -> */
1600847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_release_in *req = data;
16016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_release(fuse, handler, hdr, req);
160203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1603847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1604b2831a2db9e0370c5f797c037c135108025f2522Daisuke Okitsu    case FUSE_FSYNC:
1605b2831a2db9e0370c5f797c037c135108025f2522Daisuke Okitsu    case FUSE_FSYNCDIR: {
16066fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown        const struct fuse_fsync_in *req = data;
16076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_fsync(fuse, handler, hdr, req);
16086fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown    }
16096fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown
161003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_SETXATTR:
161103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_GETXATTR:
161203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_LISTXATTR:
161303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_REMOVEXATTR:
1614847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    case FUSE_FLUSH: {
16156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_flush(fuse, handler, hdr);
1616847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    }
1617847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
161803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_OPENDIR: { /* open_in -> open_out */
1619847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_open_in *req = data;
16206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_opendir(fuse, handler, hdr, req);
162103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1622847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
162303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_READDIR: {
1624847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_read_in *req = data;
16256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_readdir(fuse, handler, hdr, req);
162603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1627847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
162803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RELEASEDIR: { /* release_in -> */
1629847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_release_in *req = data;
16306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_releasedir(fuse, handler, hdr, req);
163103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1632847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
163303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_INIT: { /* init_in -> init_out */
1634847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_init_in *req = data;
16356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_init(fuse, handler, hdr, req);
163603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1637847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
16382abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    case FUSE_CANONICAL_PATH: { /* nodeid -> bytez[] */
16392abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg        return handle_canonical_path(fuse, handler, hdr);
16402abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    }
16412abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg
164203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    default: {
1643e43b99a0741dd481aacf76c3dc0f5102864a6857Marcus Oakland        TRACE("[%d] NOTIMPL op=%d uniq=%"PRIx64" nid=%"PRIx64"\n",
16446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                handler->token, hdr->opcode, hdr->unique, hdr->nodeid);
16456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOSYS;
164603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1647847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    }
164803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
164903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
16506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void handle_fuse_requests(struct fuse_handler* handler)
165103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
16526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse* fuse = handler->fuse;
165303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    for (;;) {
16546b6c1bd996be7b7b640ef9b074435620f73eecacMark Salyzyn        ssize_t len = TEMP_FAILURE_RETRY(read(fuse->fd,
16556b6c1bd996be7b7b640ef9b074435620f73eecacMark Salyzyn                handler->request_buffer, sizeof(handler->request_buffer)));
165603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        if (len < 0) {
16574a4858185177616707dda7ab562f45a0a8494e3fJeff Sharkey            if (errno == ENODEV) {
16584a4858185177616707dda7ab562f45a0a8494e3fJeff Sharkey                ERROR("[%d] someone stole our marbles!\n", handler->token);
16594a4858185177616707dda7ab562f45a0a8494e3fJeff Sharkey                exit(2);
16604a4858185177616707dda7ab562f45a0a8494e3fJeff Sharkey            }
16616b6c1bd996be7b7b640ef9b074435620f73eecacMark Salyzyn            ERROR("[%d] handle_fuse_requests: errno=%d\n", handler->token, errno);
16626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
166303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        }
1664847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1665847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        if ((size_t)len < sizeof(struct fuse_in_header)) {
16666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            ERROR("[%d] request too short: len=%zu\n", handler->token, (size_t)len);
16676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
1668847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        }
1669847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
16707729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        const struct fuse_in_header *hdr = (void*)handler->request_buffer;
1671847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        if (hdr->len != (size_t)len) {
16726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            ERROR("[%d] malformed header: len=%zu, hdr->len=%u\n",
16736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                    handler->token, (size_t)len, hdr->len);
16746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
1675847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        }
1676847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
16777729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        const void *data = handler->request_buffer + sizeof(struct fuse_in_header);
1678847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        size_t data_len = len - sizeof(struct fuse_in_header);
16796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        __u64 unique = hdr->unique;
16806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        int res = handle_fuse_request(fuse, handler, hdr, data, data_len);
16817729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown
16827729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        /* We do not access the request again after this point because the underlying
16837729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown         * buffer storage may have been reused while processing the request. */
16846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
16856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (res != NO_STATUS) {
16866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (res) {
16876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                TRACE("[%d] ERROR %d\n", handler->token, res);
16886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
16896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            fuse_status(fuse, unique, res);
16906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
169103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
169203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
169303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
16946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void* start_handler(void* data)
16957729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown{
16966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_handler* handler = data;
16976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    handle_fuse_requests(handler);
16986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NULL;
16996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
17006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1701977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic bool remove_str_to_int(void *key, void *value, void *context) {
1702dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    Hashmap* map = context;
1703dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    hashmapRemove(map, key);
1704dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    free(key);
1705977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    return true;
1706977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey}
1707977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
1708e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Robertsstatic bool package_parse_callback(pkg_info *info, void *userdata) {
1709e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts    struct fuse_global *global = (struct fuse_global *)userdata;
1710dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1711e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts    char* name = strdup(info->name);
1712e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts    hashmapPut(global->package_to_appid, name, (void*) (uintptr_t) info->uid);
1713e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts    packagelist_free(info);
1714e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts    return true;
1715e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts}
1716dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1717e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Robertsstatic bool read_package_list(struct fuse_global* global) {
1718e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts    pthread_mutex_lock(&global->lock);
1719977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
1720e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts    hashmapForEach(global->package_to_appid, remove_str_to_int, global->package_to_appid);
1721dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1722e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts    bool rc = packagelist_parse(package_parse_callback, global);
1723f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    TRACE("read_package_list: found %zu packages\n",
1724f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            hashmapSize(global->package_to_appid));
1725e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts
1726fe7646194425cbae816936f996993bc146814d18Jeff Sharkey    /* Regenerate ownership details using newly loaded mapping */
1727fe7646194425cbae816936f996993bc146814d18Jeff Sharkey    derive_permissions_recursive_locked(global->fuse_default, &global->root);
1728fe7646194425cbae816936f996993bc146814d18Jeff Sharkey
1729f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&global->lock);
1730e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts
1731e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts    return rc;
1732dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey}
1733dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1734f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkeystatic void watch_package_list(struct fuse_global* global) {
1735dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    struct inotify_event *event;
1736dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    char event_buf[512];
1737dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1738dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    int nfd = inotify_init();
1739dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    if (nfd < 0) {
1740dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        ERROR("inotify_init failed: %s\n", strerror(errno));
1741dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        return;
1742dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    }
1743dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1744dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    bool active = false;
1745dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    while (1) {
1746dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        if (!active) {
1747e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts            int res = inotify_add_watch(nfd, PACKAGES_LIST_FILE, IN_DELETE_SELF);
1748dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            if (res == -1) {
1749dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                if (errno == ENOENT || errno == EACCES) {
1750dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                    /* Framework may not have created yet, sleep and retry */
1751e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts                    ERROR("missing \"%s\"; retrying\n", PACKAGES_LIST_FILE);
1752dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                    sleep(3);
1753dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                    continue;
1754dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                } else {
1755dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                    ERROR("inotify_add_watch failed: %s\n", strerror(errno));
1756dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                    return;
1757dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                }
1758dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            }
1759dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1760dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            /* Watch above will tell us about any future changes, so
1761dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey             * read the current state. */
1762e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts            if (read_package_list(global) == false) {
1763e509980542f36dd1ecbbcc4afb6e9e7d2d536c12William Roberts                ERROR("read_package_list failed\n");
1764dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                return;
1765dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            }
1766dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            active = true;
1767dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
1768dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1769dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        int event_pos = 0;
1770dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        int res = read(nfd, event_buf, sizeof(event_buf));
1771dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        if (res < (int) sizeof(*event)) {
1772dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            if (errno == EINTR)
1773dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                continue;
1774dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            ERROR("failed to read inotify event: %s\n", strerror(errno));
1775dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            return;
1776dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
1777dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1778dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        while (res >= (int) sizeof(*event)) {
1779dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            int event_size;
1780dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            event = (struct inotify_event *) (event_buf + event_pos);
1781dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1782dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            TRACE("inotify event: %08x\n", event->mask);
1783dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            if ((event->mask & IN_IGNORED) == IN_IGNORED) {
1784dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                /* Previously watched file was deleted, probably due to move
1785dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                 * that swapped in new data; re-arm the watch and read. */
1786dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                active = false;
1787dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            }
1788dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1789dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            event_size = sizeof(*event) + event->len;
1790dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            res -= event_size;
1791dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            event_pos += event_size;
1792dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
1793dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    }
1794dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey}
1795dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
1796f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkeystatic int usage() {
1797f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    ERROR("usage: sdcard [OPTIONS] <source_path> <label>\n"
1798dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            "    -u: specify UID to run as\n"
1799dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            "    -g: specify GID to run as\n"
180010a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey            "    -U: specify user ID that owns device\n"
1801f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            "    -m: source_path is multi-user\n"
1802b9f438ff841f87c8ffbca85b13a533718a18e15fJeff Sharkey            "    -w: runtime write mount has full write access\n"
1803f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            "\n");
18042656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    return 1;
18054f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood}
18064f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood
1807f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkeystatic int fuse_setup(struct fuse* fuse, gid_t gid, mode_t mask) {
180803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    char opts[256];
18092656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1810f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse->fd = open("/dev/fuse", O_RDWR);
1811f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (fuse->fd == -1) {
1812f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        ERROR("failed to open fuse device: %s\n", strerror(errno));
18132656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        return -1;
18142656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
18152656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1816f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    umount2(fuse->dest_path, MNT_DETACH);
1817f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
18182656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    snprintf(opts, sizeof(opts),
18192656735f515a41cf131c87be5f40550b6538ce80Jeff Brown            "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
1820f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            fuse->fd, fuse->global->uid, fuse->global->gid);
1821f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (mount("/dev/fuse", fuse->dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC |
1822f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            MS_NOATIME, opts) != 0) {
1823f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        ERROR("failed to mount fuse filesystem: %s\n", strerror(errno));
1824f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        return -1;
1825f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    }
18262656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1827f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse->gid = gid;
1828f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse->mask = mask;
1829f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1830f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    return 0;
1831f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey}
1832f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1833f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkeystatic void run(const char* source_path, const char* label, uid_t uid,
183410a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        gid_t gid, userid_t userid, bool multi_user, bool full_write) {
1835f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    struct fuse_global global;
1836f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    struct fuse fuse_default;
1837f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    struct fuse fuse_read;
1838f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    struct fuse fuse_write;
1839f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    struct fuse_handler handler_default;
1840f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    struct fuse_handler handler_read;
1841f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    struct fuse_handler handler_write;
1842f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_t thread_default;
1843f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_t thread_read;
1844f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_t thread_write;
1845f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1846f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    memset(&global, 0, sizeof(global));
1847f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    memset(&fuse_default, 0, sizeof(fuse_default));
1848f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    memset(&fuse_read, 0, sizeof(fuse_read));
1849f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    memset(&fuse_write, 0, sizeof(fuse_write));
1850f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    memset(&handler_default, 0, sizeof(handler_default));
1851f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    memset(&handler_read, 0, sizeof(handler_read));
1852f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    memset(&handler_write, 0, sizeof(handler_write));
1853f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1854f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_init(&global.lock, NULL);
1855f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    global.package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
1856f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    global.uid = uid;
1857f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    global.gid = gid;
1858f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    global.multi_user = multi_user;
1859ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    global.next_generation = 0;
1860ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    global.inode_ctr = 1;
1861f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1862ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    memset(&global.root, 0, sizeof(global.root));
1863ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    global.root.nid = FUSE_ROOT_ID; /* 1 */
1864ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    global.root.refcount = 2;
1865ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    global.root.namelen = strlen(source_path);
1866ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    global.root.name = strdup(source_path);
186710a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey    global.root.userid = userid;
1868ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    global.root.uid = AID_ROOT;
186910a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey    global.root.under_android = false;
1870f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1871ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    strcpy(global.source_path, source_path);
1872ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
1873ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    if (multi_user) {
1874ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        global.root.perm = PERM_PRE_ROOT;
1875ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        snprintf(global.obb_path, sizeof(global.obb_path), "%s/obb", source_path);
1876ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    } else {
1877ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        global.root.perm = PERM_ROOT;
1878ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        snprintf(global.obb_path, sizeof(global.obb_path), "%s/Android/obb", source_path);
1879ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    }
1880f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1881ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    fuse_default.global = &global;
1882ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    fuse_read.global = &global;
1883f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    fuse_write.global = &global;
1884ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
1885ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    global.fuse_default = &fuse_default;
1886ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    global.fuse_read = &fuse_read;
1887ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    global.fuse_write = &fuse_write;
1888ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
1889b9f438ff841f87c8ffbca85b13a533718a18e15fJeff Sharkey    snprintf(fuse_default.dest_path, PATH_MAX, "/mnt/runtime/default/%s", label);
1890b9f438ff841f87c8ffbca85b13a533718a18e15fJeff Sharkey    snprintf(fuse_read.dest_path, PATH_MAX, "/mnt/runtime/read/%s", label);
1891b9f438ff841f87c8ffbca85b13a533718a18e15fJeff Sharkey    snprintf(fuse_write.dest_path, PATH_MAX, "/mnt/runtime/write/%s", label);
1892f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1893f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    handler_default.fuse = &fuse_default;
1894f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    handler_read.fuse = &fuse_read;
1895f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    handler_write.fuse = &fuse_write;
1896f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
1897ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    handler_default.token = 0;
1898ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    handler_read.token = 1;
1899ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    handler_write.token = 2;
1900ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
1901f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    umask(0);
1902f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey
190310a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey    if (multi_user) {
190410a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        /* Multi-user storage is fully isolated per user, so "other"
190510a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey         * permissions are completely masked off. */
190610a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
190710a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey                || fuse_setup(&fuse_read, AID_EVERYBODY, 0027)
190810a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey                || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027)) {
190910a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey            ERROR("failed to fuse_setup\n");
191010a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey            exit(1);
191110a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        }
191210a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey    } else {
191310a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        /* Physical storage is readable by all users on device, but
191410a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey         * the Android directories are masked off to a single user
191510a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey         * deep inside attr_from_stat(). */
191610a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
191710a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey                || fuse_setup(&fuse_read, AID_EVERYBODY, full_write ? 0027 : 0022)
191810a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey                || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0022)) {
191910a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey            ERROR("failed to fuse_setup\n");
192010a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey            exit(1);
192110a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        }
19222656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
19232656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1924f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    /* Drop privs */
1925f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (setgroups(sizeof(kGroups) / sizeof(kGroups[0]), kGroups) < 0) {
1926f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        ERROR("cannot setgroups: %s\n", strerror(errno));
1927f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        exit(1);
1928f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    }
1929f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (setgid(gid) < 0) {
1930dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        ERROR("cannot setgid: %s\n", strerror(errno));
1931f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        exit(1);
19322656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
1933f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (setuid(uid) < 0) {
1934dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        ERROR("cannot setuid: %s\n", strerror(errno));
1935f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        exit(1);
19362656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
19372656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1938f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (multi_user) {
1939ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        fs_prepare_dir(global.obb_path, 0775, uid, gid);
1940f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    }
19412656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1942f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (pthread_create(&thread_default, NULL, start_handler, &handler_default)
1943f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            || pthread_create(&thread_read, NULL, start_handler, &handler_read)
1944f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            || pthread_create(&thread_write, NULL, start_handler, &handler_write)) {
1945f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        ERROR("failed to pthread_create\n");
1946f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        exit(1);
1947f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    }
19482656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1949f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    watch_package_list(&global);
1950f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    ERROR("terminated prematurely\n");
1951f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    exit(1);
19522656735f515a41cf131c87be5f40550b6538ce80Jeff Brown}
19532656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
19543aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenbergstatic int sdcardfs_setup(const char *source_path, const char *dest_path, uid_t fsuid,
19553aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg                        gid_t fsgid, bool multi_user, userid_t userid, gid_t gid, mode_t mask) {
19563aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    char opts[256];
19573aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg
19583aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    snprintf(opts, sizeof(opts),
19593aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg            "fsuid=%d,fsgid=%d,%smask=%d,userid=%d,gid=%d",
19603aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg            fsuid, fsgid, multi_user?"multiuser,":"", mask, userid, gid);
19613aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg
19623aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    if (mount(source_path, dest_path, "sdcardfs",
19633aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg                        MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts) != 0) {
19643aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        ERROR("failed to mount sdcardfs filesystem: %s\n", strerror(errno));
19653aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        return -1;
19663aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    }
19673aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg
19683aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    return 0;
19693aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg}
19703aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg
19713aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenbergstatic void run_sdcardfs(const char* source_path, const char* label, uid_t uid,
19723aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        gid_t gid, userid_t userid, bool multi_user, bool full_write) {
19733aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    char dest_path_default[PATH_MAX];
19743aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    char dest_path_read[PATH_MAX];
19753aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    char dest_path_write[PATH_MAX];
19763aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    char obb_path[PATH_MAX];
19773aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    snprintf(dest_path_default, PATH_MAX, "/mnt/runtime/default/%s", label);
19783aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    snprintf(dest_path_read, PATH_MAX, "/mnt/runtime/read/%s", label);
19793aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    snprintf(dest_path_write, PATH_MAX, "/mnt/runtime/write/%s", label);
19803aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg
19813aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    umask(0);
19823aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    if (multi_user) {
19833aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        /* Multi-user storage is fully isolated per user, so "other"
19843aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg         * permissions are completely masked off. */
19853aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        if (sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
19863aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg                                                      AID_SDCARD_RW, 0006)
19873aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg                || sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
19883aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg                                                      AID_EVERYBODY, 0027)
19893aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg                || sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
19903aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg                                                      AID_EVERYBODY, full_write ? 0007 : 0027)) {
19913aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg            ERROR("failed to fuse_setup\n");
19923aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg            exit(1);
19933aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        }
19943aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    } else {
19953aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        /* Physical storage is readable by all users on device, but
19963aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg         * the Android directories are masked off to a single user
19973aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg         * deep inside attr_from_stat(). */
19983aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        if (sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
19993aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg                                                      AID_SDCARD_RW, 0006)
20003aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg                || sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
20013aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg                                                      AID_EVERYBODY, full_write ? 0027 : 0022)
20023aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg                || sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
20033aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg                                                      AID_EVERYBODY, full_write ? 0007 : 0022)) {
20043aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg            ERROR("failed to fuse_setup\n");
20053aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg            exit(1);
20063aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        }
20073aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    }
20083aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg
20093aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    /* Drop privs */
20103aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    if (setgroups(sizeof(kGroups) / sizeof(kGroups[0]), kGroups) < 0) {
20113aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        ERROR("cannot setgroups: %s\n", strerror(errno));
20123aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        exit(1);
20133aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    }
20143aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    if (setgid(gid) < 0) {
20153aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        ERROR("cannot setgid: %s\n", strerror(errno));
20163aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        exit(1);
20173aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    }
20183aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    if (setuid(uid) < 0) {
20193aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        ERROR("cannot setuid: %s\n", strerror(errno));
20203aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        exit(1);
20213aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    }
20223aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg
20233aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    if (multi_user) {
20243aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        snprintf(obb_path, sizeof(obb_path), "%s/obb", source_path);
20253aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        fs_prepare_dir(&obb_path[0], 0775, uid, gid);
20263aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    }
20273aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg
20283aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    exit(0);
20293aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg}
20303aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg
20313aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenbergstatic bool supports_sdcardfs(void) {
20323aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    FILE *fp;
20333aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    char *buf = NULL;
20343aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    size_t buflen = 0;
20353aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg
20363aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    fp = fopen("/proc/filesystems", "r");
20373aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    if (!fp) {
20383aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        ERROR("Could not read /proc/filesystems, error: %s\n", strerror(errno));
20393aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        return false;
20403aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    }
20413aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    while ((getline(&buf, &buflen, fp)) > 0) {
20423aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        if (strstr(buf, "sdcardfs\n")) {
20433aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg            free(buf);
20443aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg            fclose(fp);
20453aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg            return true;
20463aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        }
20473aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    }
20483aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    free(buf);
20493aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    fclose(fp);
20503aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    return false;
20513aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg}
20523aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg
205320ca9836b9a780c41a22850f478a29f29677553eJeff Sharkeystatic bool should_use_sdcardfs(void) {
205420ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey    char property[PROPERTY_VALUE_MAX];
205520ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey
205620ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey    // Allow user to have a strong opinion about state
205720ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey    property_get(PROP_SDCARDFS_USER, property, "");
205820ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey    if (!strcmp(property, "force_on")) {
205920ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey        ALOGW("User explicitly enabled sdcardfs");
206020ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey        return supports_sdcardfs();
206120ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey    } else if (!strcmp(property, "force_off")) {
206220ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey        ALOGW("User explicitly disabled sdcardfs");
206320ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey        return false;
206420ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey    }
206520ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey
206620ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey    // Fall back to device opinion about state
206720ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey    if (property_get_bool(PROP_SDCARDFS_DEVICE, false)) {
206820ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey        ALOGW("Device explicitly enabled sdcardfs");
206920ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey        return supports_sdcardfs();
207020ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey    } else {
207120ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey        ALOGW("Device explicitly disabled sdcardfs");
207220ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey        return false;
207320ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey    }
207420ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey}
207520ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey
2076f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkeyint main(int argc, char **argv) {
2077e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    const char *source_path = NULL;
2078f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    const char *label = NULL;
20792656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    uid_t uid = 0;
20802656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    gid_t gid = 0;
208110a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey    userid_t userid = 0;
2082f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    bool multi_user = false;
2083f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    bool full_write = false;
20844f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood    int i;
20852fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall    struct rlimit rlim;
20868d28fa71fce6a5623488614250970ce78551a924Nick Kralevich    int fs_version;
20874f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood
2088dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    int opt;
208910a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey    while ((opt = getopt(argc, argv, "u:g:U:mw")) != -1) {
2090dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        switch (opt) {
2091dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            case 'u':
2092dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                uid = strtoul(optarg, NULL, 10);
2093dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                break;
2094dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            case 'g':
2095dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                gid = strtoul(optarg, NULL, 10);
2096dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                break;
209710a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey            case 'U':
209810a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey                userid = strtoul(optarg, NULL, 10);
209910a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey                break;
2100f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            case 'm':
2101f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey                multi_user = true;
2102dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                break;
2103f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            case 'w':
2104f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey                full_write = true;
2105dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                break;
2106dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            case '?':
2107dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            default:
2108dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey                return usage();
2109dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
2110dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    }
2111dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
2112dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    for (i = optind; i < argc; i++) {
21134f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        char* arg = argv[i];
2114dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        if (!source_path) {
2115e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey            source_path = arg;
2116f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        } else if (!label) {
2117f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            label = arg;
2118e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru        } else {
2119575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            ERROR("too many arguments\n");
2120575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            return usage();
21214f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        }
212203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
212303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
2124e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    if (!source_path) {
2125e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey        ERROR("no source path specified\n");
2126e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey        return usage();
2127e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    }
2128f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!label) {
2129f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        ERROR("no label specified\n");
21304f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        return usage();
21314f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood    }
21322656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (!uid || !gid) {
213303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        ERROR("uid and gid must be nonzero\n");
21344f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        return usage();
213503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
213603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
21372fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall    rlim.rlim_cur = 8192;
21382fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall    rlim.rlim_max = 8192;
21392fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall    if (setrlimit(RLIMIT_NOFILE, &rlim)) {
21402fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall        ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno);
21412fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall    }
21422fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall
21438d28fa71fce6a5623488614250970ce78551a924Nick Kralevich    while ((fs_read_atomic_int("/data/.layout_version", &fs_version) == -1) || (fs_version < 3)) {
21448d28fa71fce6a5623488614250970ce78551a924Nick Kralevich        ERROR("installd fs upgrade not yet complete. Waiting...\n");
21458d28fa71fce6a5623488614250970ce78551a924Nick Kralevich        sleep(1);
21468d28fa71fce6a5623488614250970ce78551a924Nick Kralevich    }
21478d28fa71fce6a5623488614250970ce78551a924Nick Kralevich
214820ca9836b9a780c41a22850f478a29f29677553eJeff Sharkey    if (should_use_sdcardfs()) {
21493aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        run_sdcardfs(source_path, label, uid, gid, userid, multi_user, full_write);
21503aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    } else {
21513aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg        run(source_path, label, uid, gid, userid, multi_user, full_write);
21523aa261c05af3ff943543af74fd9e92210c3f758bDaniel Rosenberg    }
2153f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    return 1;
215403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
2155