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