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
17d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris#include <errno.h>
18d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris#include <string.h>
19d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris#include <unistd.h>
20d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris
21300d5649800744b3f5eab478f2bd7921f584b07dElliott Hughes#define LOG_TAG "sdcard"
22300d5649800744b3f5eab478f2bd7921f584b07dElliott Hughes
23c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include "fuse.h"
24b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland
25714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes#include <android-base/logging.h>
26714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes
272abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg/* FUSE_CANONICAL_PATH is not currently upstreamed */
282abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg#define FUSE_CANONICAL_PATH 2016
292abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg
3003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define FUSE_UNKNOWN_INO 0xffffffff
3103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Pseudo-error constant used to indicate that no fuse status is needed
336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or that a reply has already been written. */
346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown#define NO_STATUS 1
356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic inline void *id_to_ptr(__u64 nid)
376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return (void *) (uintptr_t) nid;
396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
40b94d320b1e7e2a3493147f6763cd2825b111a4d8Mike Lockwood
416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic inline __u64 ptr_to_id(void *ptr)
426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return (__u64) (uintptr_t) ptr;
446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void acquire_node_locked(struct node* node)
476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->refcount++;
49e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes    DLOG(INFO) << "ACQUIRE " << std::hex << node << std::dec
50e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes               << " (" << node->name << ") rc=" << node->refcount;
516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void remove_node_from_parent_locked(struct node* node);
546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void release_node_locked(struct node* node)
566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
57e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes    DLOG(INFO) << "RELEASE " << std::hex << node << std::dec
58e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes               << " (" << node->name << ") rc=" << node->refcount;
596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node->refcount > 0) {
606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->refcount--;
616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->refcount) {
62e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes            DLOG(INFO) << "DESTROY " << std::hex << node << std::dec << " (" << node->name << ")";
636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            remove_node_from_parent_locked(node);
646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
65f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes            /* TODO: remove debugging - poison memory */
666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            memset(node->name, 0xef, node->namelen);
676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->name);
686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->actual_name);
696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            memset(node, 0xfc, sizeof(*node));
706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node);
716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
73e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes        LOG(ERROR) << std::hex << node << std::dec << " refcount=0";
746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void add_node_to_parent_locked(struct node *node, struct node *parent) {
786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->parent = parent;
796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->next = parent->child;
806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent->child = node;
816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(parent);
826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void remove_node_from_parent_locked(struct node* node)
856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node->parent) {
876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (node->parent->child == node) {
886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->parent->child = node->parent->child->next;
896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        } else {
906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            struct node *node2;
916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node2 = node->parent->child;
926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            while (node2->next != node)
936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                node2 = node2->next;
946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node2->next = node->next;
956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        release_node_locked(node->parent);
976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->parent = NULL;
986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->next = NULL;
996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
1006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
1016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Gets the absolute path to a node into the provided buffer.
1036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown *
1046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Populates 'buf' with the path and returns the length of the path on success,
1056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or returns -1 if the path is too long for the provided buffer.
106f43219e0b1022b257499289ceb951f6a1a44bf9cPaul Eastham */
107977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize) {
108977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    const char* name;
109977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    size_t namelen;
110977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    if (node->graft_path) {
111977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        name = node->graft_path;
112977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        namelen = node->graft_pathlen;
113977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    } else if (node->actual_name) {
114977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        name = node->actual_name;
115977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        namelen = node->namelen;
116977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    } else {
117977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        name = node->name;
118977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        namelen = node->namelen;
119977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
120977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
1216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (bufsize < namelen + 1) {
1226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -1;
1236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
1246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    ssize_t pathlen = 0;
126977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    if (node->parent && node->graft_path == NULL) {
127db4638ee3044dff2c211f89ac5a19a9734c6b62dDaniel Rosenberg        pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 1);
1286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (pathlen < 0) {
1296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -1;
130575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
1316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        buf[pathlen++] = '/';
13203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
13303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
1356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return pathlen + namelen;
1366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
1376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Finds the absolute path of a file within a given directory.
1396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Performs a case-insensitive search for the file and sets the buffer to the path
1406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * of the first matching file.  If 'search' is zero or if no match is found, sets
1416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * the buffer to the path that the file would have, assuming the name were case-sensitive.
1426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown *
1436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Populates 'buf' with the path and returns the actual name (within 'buf') on success,
1446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or returns NULL if the path is too long for the provided buffer.
1456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown */
1466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic char* find_file_within(const char* path, const char* name,
1476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* buf, size_t bufsize, int search)
1486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
1496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t pathlen = strlen(path);
1506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
1516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t childlen = pathlen + namelen + 1;
1526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char* actual;
1536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (bufsize <= childlen) {
1556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
1566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
1576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(buf, path, pathlen);
1596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    buf[pathlen] = '/';
1606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    actual = buf + pathlen + 1;
1616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(actual, name, namelen + 1);
1626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (search && access(buf, F_OK)) {
164575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        struct dirent* entry;
1656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        DIR* dir = opendir(path);
166575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        if (!dir) {
167e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes            PLOG(ERROR) << "opendir(" << path << ") failed";
1686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return actual;
169575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
170575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        while ((entry = readdir(dir))) {
1716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!strcasecmp(entry->d_name, name)) {
1726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                /* we have a match - replace the name, don't need to copy the null again */
1736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                memcpy(actual, entry->d_name, namelen);
174575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood                break;
175575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            }
176575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
177575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        closedir(dir);
178575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood    }
1796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return actual;
180575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood}
181575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood
182ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkeystatic void attr_from_stat(struct fuse* fuse, struct fuse_attr *attr,
183ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        const struct stat *s, const struct node* node) {
184faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    attr->ino = node->ino;
18503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->size = s->st_size;
18603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->blocks = s->st_blocks;
187f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->atime = s->st_atim.tv_sec;
188f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->mtime = s->st_mtim.tv_sec;
189f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->ctime = s->st_ctim.tv_sec;
190f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->atimensec = s->st_atim.tv_nsec;
191f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->mtimensec = s->st_mtim.tv_nsec;
192f1df854e5857f6dd8fa64b185f8b7cf007463f81Elliott Hughes    attr->ctimensec = s->st_ctim.tv_nsec;
19303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->mode = s->st_mode;
19403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->nlink = s->st_nlink;
19503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
196dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    attr->uid = node->uid;
197ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
198ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    if (fuse->gid == AID_SDCARD_RW) {
199ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        /* As an optimization, certain trusted system components only run
200ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey         * as owner but operate across all users. Since we're now handing
201ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey         * out the sdcard_rw GID only to trusted apps, we're okay relaxing
202ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey         * the user boundary enforcement for the default view. The UIDs
203ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey         * assigned to app directories are still multiuser aware. */
204ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        attr->gid = AID_SDCARD_RW;
205ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    } else {
206ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        attr->gid = multiuser_get_uid(node->userid, fuse->gid);
207ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    }
208b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland
20910a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey    int visible_mode = 0775 & ~fuse->mask;
21010a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey    if (node->perm == PERM_PRE_ROOT) {
21110a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        /* Top of multi-user view should always be visible to ensure
21210a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey         * secondary users can traverse inside. */
21310a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        visible_mode = 0711;
21410a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey    } else if (node->under_android) {
21510a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        /* Block "other" access to Android directories, since only apps
21610a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey         * belonging to a specific user should be in there; we still
21710a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey         * leave +x open for the default view. */
21810a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        if (fuse->gid == AID_SDCARD_RW) {
21910a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey            visible_mode = visible_mode & ~0006;
22010a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        } else {
22110a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey            visible_mode = visible_mode & ~0007;
22210a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey        }
223ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    }
224dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    int owner_mode = s->st_mode & 0700;
225ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    int filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
226dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    attr->mode = (attr->mode & S_IFMT) | filtered_mode;
227dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey}
228dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
22944d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkeystatic int touch(char* path, mode_t mode) {
230d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    int fd = TEMP_FAILURE_RETRY(open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC,
231d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris                                     mode));
23244d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    if (fd == -1) {
23344d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (errno == EEXIST) {
23444d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            return 0;
23544d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        } else {
236e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes            PLOG(ERROR) << "open(" << path << ") failed";
23744d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            return -1;
23844d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        }
23944d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    }
24044d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    close(fd);
24144d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    return 0;
24244d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey}
24344d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey
244dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkeystatic void derive_permissions_locked(struct fuse* fuse, struct node *parent,
245dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        struct node *node) {
246977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    appid_t appid;
247dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
248dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    /* By default, each node inherits from its parent */
249dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    node->perm = PERM_INHERIT;
250dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    node->userid = parent->userid;
251dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    node->uid = parent->uid;
25210a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey    node->under_android = parent->under_android;
253dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
254dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    /* Derive custom permissions based on parent and current node */
255dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    switch (parent->perm) {
256dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    case PERM_INHERIT:
257dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        /* Already inherited above */
258dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        break;
259f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    case PERM_PRE_ROOT:
260977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        /* Legacy internal layout places users at top level */
261977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        node->perm = PERM_ROOT;
262977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        node->userid = strtoul(node->name, NULL, 10);
263977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        break;
264dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    case PERM_ROOT:
265977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        /* Assume masked off by default. */
26644d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (!strcasecmp(node->name, "Android")) {
267dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            /* App-specific directories inside; let anyone traverse */
268dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            node->perm = PERM_ANDROID;
26910a239b971d737b15a5d0652a441994e5c02ad88Jeff Sharkey            node->under_android = true;
270dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
271dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        break;
272dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    case PERM_ANDROID:
27344d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (!strcasecmp(node->name, "data")) {
274dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            /* App-specific directories inside; let anyone traverse */
275dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            node->perm = PERM_ANDROID_DATA;
27644d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        } else if (!strcasecmp(node->name, "obb")) {
277dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            /* App-specific directories inside; let anyone traverse */
278dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey            node->perm = PERM_ANDROID_OBB;
279977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey            /* Single OBB directory is always shared */
280ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey            node->graft_path = fuse->global->obb_path;
281ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey            node->graft_pathlen = strlen(fuse->global->obb_path);
2822e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey        } else if (!strcasecmp(node->name, "media")) {
2832e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey            /* App-specific directories inside; let anyone traverse */
2842e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey            node->perm = PERM_ANDROID_MEDIA;
285dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
286dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        break;
287dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    case PERM_ANDROID_DATA:
288dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    case PERM_ANDROID_OBB:
2892e7d80d10acf95076dfb1f2727455432091de65fJeff Sharkey    case PERM_ANDROID_MEDIA:
290d6d8faa69068d92e0e4021fced181b448d4e8cbdJorge Lucangeli Obes        const auto& iter = fuse->global->package_to_appid->find(node->name);
291d6d8faa69068d92e0e4021fced181b448d4e8cbdJorge Lucangeli Obes        if (iter != fuse->global->package_to_appid->end()) {
292d6d8faa69068d92e0e4021fced181b448d4e8cbdJorge Lucangeli Obes            appid = iter->second;
293977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey            node->uid = multiuser_get_uid(parent->userid, appid);
294dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        }
295dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey        break;
296dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    }
297aa04e818a4904b193e00d603785c93e888eab174Jeff Sharkey}
298aa04e818a4904b193e00d603785c93e888eab174Jeff Sharkey
299c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obesvoid derive_permissions_recursive_locked(struct fuse* fuse, struct node *parent) {
300fe7646194425cbae816936f996993bc146814d18Jeff Sharkey    struct node *node;
301fe7646194425cbae816936f996993bc146814d18Jeff Sharkey    for (node = parent->child; node; node = node->next) {
302fe7646194425cbae816936f996993bc146814d18Jeff Sharkey        derive_permissions_locked(fuse, parent, node);
303fe7646194425cbae816936f996993bc146814d18Jeff Sharkey        if (node->child) {
304fe7646194425cbae816936f996993bc146814d18Jeff Sharkey            derive_permissions_recursive_locked(fuse, node);
305fe7646194425cbae816936f996993bc146814d18Jeff Sharkey        }
306fe7646194425cbae816936f996993bc146814d18Jeff Sharkey    }
307fe7646194425cbae816936f996993bc146814d18Jeff Sharkey}
308fe7646194425cbae816936f996993bc146814d18Jeff Sharkey
309977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey/* Kernel has already enforced everything we returned through
310977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey * derive_permissions_locked(), so this is used to lock down access
311977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey * even further, such as enforcing that apps hold sdcard_rw. */
312977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic bool check_caller_access_to_name(struct fuse* fuse,
313977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        const struct fuse_in_header *hdr, const struct node* parent_node,
314f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        const char* name, int mode) {
315977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* Always block security-sensitive files at root */
316977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    if (parent_node && parent_node->perm == PERM_ROOT) {
31744d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (!strcasecmp(name, "autorun.inf")
31844d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey                || !strcasecmp(name, ".android_secure")
31944d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey                || !strcasecmp(name, "android_secure")) {
320977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey            return false;
321977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        }
322977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
323977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
32444d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    /* Root always has access; access for any other UIDs should always
32544d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey     * be controlled through packages.list. */
32644d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    if (hdr->uid == 0) {
327977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return true;
328977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
329977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
330977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    /* No extra permissions to enforce */
331977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    return true;
332977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey}
333977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
334977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic bool check_caller_access_to_node(struct fuse* fuse,
335f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        const struct fuse_in_header *hdr, const struct node* node, int mode) {
336f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    return check_caller_access_to_name(fuse, hdr, node->parent, node->name, mode);
337977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey}
338977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
3396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstruct node *create_node_locked(struct fuse* fuse,
3406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct node *parent, const char *name, const char* actual_name)
34103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
34203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct node *node;
3436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
34403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
345faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    // Detect overflows in the inode counter. "4 billion nodes should be enough
346faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    // for everybody".
347ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    if (fuse->global->inode_ctr == 0) {
348e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes        LOG(ERROR) << "No more inode numbers available";
349faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath        return NULL;
350faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath    }
351faa0935ffb772759f795d6b29c6db6f83e8531c4Narayan Kamath
352f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes    node = static_cast<struct node*>(calloc(1, sizeof(struct node)));
3536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node) {
3546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
35503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
356f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes    node->name = static_cast<char*>(malloc(namelen + 1));
3576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node->name) {
35811ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham        free(node);
3596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
36011ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    }
36103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    memcpy(node->name, name, namelen + 1);
3626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (strcmp(name, actual_name)) {
363f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        node->actual_name = static_cast<char*>(malloc(namelen + 1));
3646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->actual_name) {
3656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->name);
3666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node);
3676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return NULL;
3686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
3696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        memcpy(node->actual_name, actual_name, namelen + 1);
3706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
37103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    node->namelen = namelen;
3726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->nid = ptr_to_id(node);
373ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    node->ino = fuse->global->inode_ctr++;
374ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    node->gen = fuse->global->next_generation++;
375dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey
376c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    node->deleted = false;
377c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski
378dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    derive_permissions_locked(fuse, parent, node);
3796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(node);
3806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    add_node_to_parent_locked(node, parent);
38103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    return node;
38203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
38303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int rename_node_locked(struct node *node, const char *name,
3856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* actual_name)
38611ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham{
3876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
3886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int need_actual_name = strcmp(name, actual_name);
3896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* make the storage bigger without actually changing the name
3916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * in case an error occurs part way */
3926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (namelen > node->namelen) {
393f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        char* new_name = static_cast<char*>(realloc(node->name, namelen + 1));
3946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!new_name) {
3956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -ENOMEM;
3966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
3976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->name = new_name;
3986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (need_actual_name && node->actual_name) {
399f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes            char* new_actual_name = static_cast<char*>(realloc(node->actual_name, namelen + 1));
4006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!new_actual_name) {
4016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                return -ENOMEM;
4026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
4036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->actual_name = new_actual_name;
4046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
4056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
40603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* update the name, taking care to allocate storage before overwriting the old name */
4086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (need_actual_name) {
4096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->actual_name) {
410f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes            node->actual_name = static_cast<char*>(malloc(namelen + 1));
4116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!node->actual_name) {
4126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                return -ENOMEM;
4136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
4146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
4156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        memcpy(node->actual_name, actual_name, namelen + 1);
4166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
4176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        free(node->actual_name);
4186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->actual_name = NULL;
4196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
4206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(node->name, name, namelen + 1);
4216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->namelen = namelen;
4226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
42303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
42403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
42603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
4276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (nid == FUSE_ROOT_ID) {
428ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        return &fuse->global->root;
42903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    } else {
430f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        return static_cast<struct node*>(id_to_ptr(nid));
43103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
43203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
43303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node* lookup_node_and_path_by_id_locked(struct fuse* fuse, __u64 nid,
4356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* buf, size_t bufsize)
43603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
4376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node = lookup_node_by_id_locked(fuse, nid);
4386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node && get_node_path_locked(node, buf, bufsize) < 0) {
4396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node = NULL;
44003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
4416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return node;
44203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
44303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node *lookup_child_by_name_locked(struct node *node, const char *name)
44503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
44603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    for (node = node->child; node; node = node->next) {
4476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        /* use exact string comparison, nodes that differ by case
4486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * must be considered distinct even if they refer to the same
4496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * underlying file as otherwise operations such as "mv x x"
4506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * will not work because the source and target nodes are the same. */
451c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski        if (!strcmp(name, node->name) && !node->deleted) {
45211ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham            return node;
45311ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham        }
45411ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    }
45511ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    return 0;
45611ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham}
45711ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham
4586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node* acquire_or_create_child_locked(
4596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct fuse* fuse, struct node* parent,
4606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* name, const char* actual_name)
46103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
4626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* child = lookup_child_by_name_locked(parent, name);
4636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (child) {
4646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        acquire_node_locked(child);
4656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
4666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        child = create_node_locked(fuse, parent, name, actual_name);
46703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
4686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return child;
46903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
47003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void fuse_status(struct fuse *fuse, __u64 unique, int err)
47203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
47303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct fuse_out_header hdr;
47403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.len = sizeof(hdr);
47503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.error = err;
47603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.unique = unique;
477d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    ssize_t ret = TEMP_FAILURE_RETRY(write(fuse->fd, &hdr, sizeof(hdr)));
478d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    if (ret == -1) {
479d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris        PLOG(ERROR) << "*** STATUS FAILED ***";
480d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    } else if (static_cast<size_t>(ret) != sizeof(hdr)) {
481d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris        LOG(ERROR) << "*** STATUS FAILED: written " << ret << " expected "
482d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris                   << sizeof(hdr) << " ***";
483d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    }
48403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
48503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
48703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
48803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct fuse_out_header hdr;
48903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.len = len + sizeof(hdr);
49003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.error = 0;
49103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.unique = unique;
49203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
493d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    struct iovec vec[2];
49403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[0].iov_base = &hdr;
49503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[0].iov_len = sizeof(hdr);
49603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[1].iov_base = data;
49703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[1].iov_len = len;
49803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
499d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    ssize_t ret = TEMP_FAILURE_RETRY(writev(fuse->fd, vec, 2));
500d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    if (ret == -1) {
501e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes        PLOG(ERROR) << "*** REPLY FAILED ***";
502d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    } else if (static_cast<size_t>(ret) != sizeof(hdr) + len) {
503d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris        LOG(ERROR) << "*** REPLY FAILED: written " << ret << " expected "
504d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris                   << sizeof(hdr) + len << " ***";
50503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
50603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
50703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
5086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int fuse_reply_entry(struct fuse* fuse, __u64 unique,
5096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct node* parent, const char* name, const char* actual_name,
5106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* path)
51103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
512fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct node* node;
5136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_entry_out out;
5146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct stat s;
51503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
516d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    if (lstat(path, &s) == -1) {
51744d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        return -errno;
51803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
519fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
520f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
5216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
5226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node) {
523f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey        pthread_mutex_unlock(&fuse->global->lock);
5246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
5256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
5266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memset(&out, 0, sizeof(out));
527ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    attr_from_stat(fuse, &out.attr, &s, node);
5286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.attr_valid = 10;
5296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.entry_valid = 10;
53003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    out.nodeid = node->nid;
53103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    out.generation = node->gen;
532f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
53303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    fuse_reply(fuse, unique, &out, sizeof(out));
5346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
53503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
53603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
537dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkeystatic int fuse_reply_attr(struct fuse* fuse, __u64 unique, const struct node* node,
5386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* path)
53903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
5406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_attr_out out;
5416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct stat s;
542fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
543d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    if (lstat(path, &s) == -1) {
5446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
545fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
5466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memset(&out, 0, sizeof(out));
547ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    attr_from_stat(fuse, &out.attr, &s, node);
5486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.attr_valid = 10;
5496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse_reply(fuse, unique, &out, sizeof(out));
5506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
5516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
552fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
553ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkeystatic void fuse_notify_delete(struct fuse* fuse, const __u64 parent,
554ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        const __u64 child, const char* name) {
555ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    struct fuse_out_header hdr;
556ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    struct fuse_notify_delete_out data;
557ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    size_t namelen = strlen(name);
558ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    hdr.len = sizeof(hdr) + sizeof(data) + namelen + 1;
559ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    hdr.error = FUSE_NOTIFY_DELETE;
560ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    hdr.unique = 0;
561ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
562ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    data.parent = parent;
563ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    data.child = child;
564ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    data.namelen = namelen;
565ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    data.padding = 0;
566ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
567d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    struct iovec vec[3];
568ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    vec[0].iov_base = &hdr;
569ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    vec[0].iov_len = sizeof(hdr);
570ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    vec[1].iov_base = &data;
571ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    vec[1].iov_len = sizeof(data);
572ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    vec[2].iov_base = (void*) name;
573ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    vec[2].iov_len = namelen + 1;
574ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
575d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    ssize_t ret = TEMP_FAILURE_RETRY(writev(fuse->fd, vec, 3));
576ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    /* Ignore ENOENT, since other views may not have seen the entry */
577d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    if (ret == -1) {
578d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris        if (errno != ENOENT) {
579d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris            PLOG(ERROR) << "*** NOTIFY FAILED ***";
580d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris        }
581d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    } else if (static_cast<size_t>(ret) != sizeof(hdr) + sizeof(data) + namelen + 1) {
582d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris        LOG(ERROR) << "*** NOTIFY FAILED: written " << ret << " expected "
583d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris                   << sizeof(hdr) + sizeof(data) + namelen + 1 << " ***";
584ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    }
585ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey}
586ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey
5876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
5886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const struct fuse_in_header *hdr, const char* name)
5896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
5906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
5916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
5926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
5936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
5946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
595f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
5966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
5976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
598714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] LOOKUP " << name << " @ " << hdr->nodeid
599714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes               << " (" << (parent_node ? parent_node->name : "?") << ")";
600f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
6016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
6026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
6036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
6046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
6056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
606f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, R_OK)) {
607977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
608977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
609977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
6106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
611fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
612fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_forget(struct fuse* fuse, struct fuse_handler* handler,
614fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_forget_in *req)
615fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
6166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
617fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
618f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
6196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_by_id_locked(fuse, hdr->nodeid);
620714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] FORGET #" << req->nlookup
621714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes               << " @ " << std::hex << hdr->nodeid
622714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes               << " (" << (node ? node->name : "?") << ")";
6236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node) {
6246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        __u64 n = req->nlookup;
625df9c4a0166b351c20d8c89850880eee76fdecadfDaniel Micay        while (n) {
626df9c4a0166b351c20d8c89850880eee76fdecadfDaniel Micay            n--;
6276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            release_node_locked(node);
6286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
629fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
630f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
6316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS; /* no reply */
632fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
633fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_getattr(struct fuse* fuse, struct fuse_handler* handler,
635fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_getattr_in *req)
636fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
6376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
6386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
6396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
640f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
6416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
642714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] GETATTR flags=" << req->getattr_flags
643e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes               << " fh=" << std::hex << req->fh << " @ " << hdr->nodeid << std::dec
644714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes               << " (" << (node ? node->name : "?") << ")";
645f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
646fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
647fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
6486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
649fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
650f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
651977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
652977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
653977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
654dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    return fuse_reply_attr(fuse, hdr->unique, node, path);
655fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
656fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
658fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
659fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
6606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
6616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
662fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct timespec times[2];
663fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
664f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
6656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
666714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] SETATTR fh=" << std::hex << req->fh
667e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes               << " valid=" << std::hex << req->valid << " @ " << hdr->nodeid << std::dec
668714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes               << " (" << (node ? node->name : "?") << ")";
669f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
6706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
671fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
6726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
673fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
674a80f0986bb39ae03ba9014bf4974fc26ae48da70Marco Nelissen
675a80f0986bb39ae03ba9014bf4974fc26ae48da70Marco Nelissen    if (!(req->valid & FATTR_FH) &&
676f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            !check_caller_access_to_node(fuse, hdr, node, W_OK)) {
677977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
678977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
679fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* XXX: incomplete implementation on purpose.
6816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * chmod/chown should NEVER be implemented.*/
682fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
683d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    if ((req->valid & FATTR_SIZE) && TEMP_FAILURE_RETRY(truncate64(path, req->size)) == -1) {
6846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
685fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
686fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
687fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* Handle changing atime and mtime.  If FATTR_ATIME_and FATTR_ATIME_NOW
688fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * are both set, then set it to the current time.  Else, set it to the
689fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * time specified in the request.  Same goes for mtime.  Use utimensat(2)
690fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * as it allows ATIME and MTIME to be changed independently, and has
691fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * nanosecond resolution which fuse also has.
692fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     */
693fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
694fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        times[0].tv_nsec = UTIME_OMIT;
695fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        times[1].tv_nsec = UTIME_OMIT;
696fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        if (req->valid & FATTR_ATIME) {
697fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            if (req->valid & FATTR_ATIME_NOW) {
698fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_nsec = UTIME_NOW;
699fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            } else {
700fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_sec = req->atime;
701fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_nsec = req->atimensec;
702fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            }
703fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        }
704fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        if (req->valid & FATTR_MTIME) {
705fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            if (req->valid & FATTR_MTIME_NOW) {
706fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_nsec = UTIME_NOW;
707fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            } else {
708fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_sec = req->mtime;
709fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_nsec = req->mtimensec;
710fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            }
711fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        }
712e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes        DLOG(INFO) << "[" << handler->token << "] Calling utimensat on " << path
713e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes                   << " with atime " << times[0].tv_sec << ", mtime=" << times[1].tv_sec;
7146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (utimensat(-1, path, times, 0) < 0) {
7156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -errno;
71603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        }
717fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
718dfe0cbab3f9039f34af1dc9e31faf8155737ec2dJeff Sharkey    return fuse_reply_attr(fuse, hdr->unique, node, path);
719fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
720fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
722fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
723fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
7246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
7256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
7266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
7276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
7286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
729f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
7306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
7316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
732714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] MKNOD " << name << " 0" << std::oct << req->mode
733714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes               << " @ " << std::hex << hdr->nodeid
734714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes               << " (" << (parent_node ? parent_node->name : "?") << ")";
735f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
7366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
7376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
7386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
7396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
740fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
741f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
742977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
743977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
744fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 mode = (req->mode & (~0777)) | 0664;
745d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    if (mknod(child_path, mode, req->rdev) == -1) {
7466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
747fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
7486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
749fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
750fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
752fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
753fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
7546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
7556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
7566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
7576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
7586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
759f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
7606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
7616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
762714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] MKDIR " << name << " 0" << std::oct << req->mode
763714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes               << " @ " << std::hex << hdr->nodeid
764714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes               << " (" << (parent_node ? parent_node->name : "?") << ")";
765f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
7666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
7676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
7686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
7696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
770fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
771f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
772977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
773977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
774fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 mode = (req->mode & (~0777)) | 0775;
775d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    if (mkdir(child_path, mode) == -1) {
7766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
777fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
77844d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey
77944d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    /* When creating /Android/data and /Android/obb, mark them as .nomedia */
78044d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "data")) {
78144d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        char nomedia[PATH_MAX];
78244d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        snprintf(nomedia, PATH_MAX, "%s/.nomedia", child_path);
78344d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (touch(nomedia, 0664) != 0) {
784e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes            PLOG(ERROR) << "touch(" << nomedia << ") failed";
78544d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            return -ENOENT;
78644d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        }
78744d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    }
78844d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "obb")) {
78944d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        char nomedia[PATH_MAX];
790ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->global->obb_path);
79144d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        if (touch(nomedia, 0664) != 0) {
792e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes            PLOG(ERROR) << "touch(" << nomedia << ") failed";
79344d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey            return -ENOENT;
79444d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey        }
79544d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey    }
79644d6342caa0db1f613809e9ba1ea8d9af0183b74Jeff Sharkey
7976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
798fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
799fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
801fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const char* name)
802fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
8036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
804c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    struct node* child_node;
8056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
8066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
807fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
808f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
8096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
8106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
811714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] UNLINK " << name << " @ " << std::hex << hdr->nodeid
812714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes               << " (" << (parent_node ? parent_node->name : "?") << ")";
813f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
814fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !find_file_within(parent_path, name,
8166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1)) {
8176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
8186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
819f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
820977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
821977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
822d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    if (unlink(child_path) == -1) {
8236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
8246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
825f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
826c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    child_node = lookup_child_by_name_locked(parent_node, name);
827c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    if (child_node) {
828c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski        child_node->deleted = true;
829c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    }
830f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
831ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    if (parent_node && child_node) {
832ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        /* Tell all other views that node is gone */
833714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes        DLOG(INFO) << "[" << handler->token << "] fuse_notify_delete"
834714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes                   << " parent=" << std::hex << parent_node->nid
835e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes                   << ", child=" << std::hex << child_node->nid << std::dec
836e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes                   << ", name=" << name;
837ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        if (fuse != fuse->global->fuse_default) {
838ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey            fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
839ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        }
840ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        if (fuse != fuse->global->fuse_read) {
841ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey            fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
842ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        }
843ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        if (fuse != fuse->global->fuse_write) {
844ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey            fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
845ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        }
846ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    }
8476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
848fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
849fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
851fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const char* name)
852fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
853c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    struct node* child_node;
8546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
8556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
8566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
857fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
858f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
8596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
8606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
861714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] UNLINK " << name << " @ " << std::hex << hdr->nodeid
862714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes               << " (" << (parent_node ? parent_node->name : "?") << ")";
863f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
864fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !find_file_within(parent_path, name,
8666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1)) {
8676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
8686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
869f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
870977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
871977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
872d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    if (rmdir(child_path) == -1) {
8736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
8746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
875f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
876c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    child_node = lookup_child_by_name_locked(parent_node, name);
877c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    if (child_node) {
878c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski        child_node->deleted = true;
879c5353126bec17f8c43f2c4ca5b5e55cd6b3ed41cKrzysztof Adamski    }
880f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
881ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    if (parent_node && child_node) {
882ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        /* Tell all other views that node is gone */
883714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes        DLOG(INFO) << "[" << handler->token << "] fuse_notify_delete"
884714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes                   << " parent=" << std::hex << parent_node->nid
885e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes                   << ", child=" << std::hex << child_node->nid << std::dec
886e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes                   << ", name=" << name;
887ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        if (fuse != fuse->global->fuse_default) {
888ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey            fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
889ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        }
890ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        if (fuse != fuse->global->fuse_read) {
891ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey            fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
892ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        }
893ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        if (fuse != fuse->global->fuse_write) {
894ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey            fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
895ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey        }
896ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    }
8976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
898fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
899fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_rename(struct fuse* fuse, struct fuse_handler* handler,
901fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
9026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* old_name, const char* new_name)
903fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
9046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* old_parent_node;
9056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* new_parent_node;
9066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* child_node;
9076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char old_parent_path[PATH_MAX];
9086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char new_parent_path[PATH_MAX];
9096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char old_child_path[PATH_MAX];
9106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char new_child_path[PATH_MAX];
9116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* new_actual_name;
912f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes    int search;
913fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
914fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
915f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
9166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
9176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_parent_path, sizeof(old_parent_path));
9186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
9196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            new_parent_path, sizeof(new_parent_path));
920714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] RENAME " << old_name << "->" << new_name
921714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes               << " @ " << std::hex << hdr->nodeid
922714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes               << " (" << (old_parent_node ? old_parent_node->name : "?") << ") -> "
923714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes               << std::hex << req->newdir
924714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes               << " (" << (new_parent_node ? new_parent_node->name : "?") << ")";
9256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!old_parent_node || !new_parent_node) {
9266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
9276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto lookup_error;
9286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
929f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, old_parent_node, old_name, W_OK)) {
930977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        res = -EACCES;
931977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        goto lookup_error;
932977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
933f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_name(fuse, hdr, new_parent_node, new_name, W_OK)) {
934977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        res = -EACCES;
935977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        goto lookup_error;
936977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
9376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    child_node = lookup_child_by_name_locked(old_parent_node, old_name);
9386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!child_node || get_node_path_locked(child_node,
9396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_child_path, sizeof(old_child_path)) < 0) {
9406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
9416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto lookup_error;
9426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
9436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(child_node);
944f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
9456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
9466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* Special case for renaming a file where destination is same path
9476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * differing only by case.  In this case we don't want to look for a case
9486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * insensitive match.  This allows commands like "mv foo FOO" to work as expected.
9496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     */
950f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes    search = old_parent_node != new_parent_node
9516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            || strcasecmp(old_name, new_name);
9526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!(new_actual_name = find_file_within(new_parent_path, new_name,
9536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            new_child_path, sizeof(new_child_path), search))) {
9546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
9556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto io_error;
956fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
957fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
958e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] RENAME " << old_child_path << "->" << new_child_path;
9596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = rename(old_child_path, new_child_path);
960d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    if (res == -1) {
9616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -errno;
9626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto io_error;
963fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
964fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
965f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
9666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = rename_node_locked(child_node, new_name, new_actual_name);
9676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!res) {
9686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        remove_node_from_parent_locked(child_node);
969fe7646194425cbae816936f996993bc146814d18Jeff Sharkey        derive_permissions_locked(fuse, new_parent_node, child_node);
970fe7646194425cbae816936f996993bc146814d18Jeff Sharkey        derive_permissions_recursive_locked(fuse, child_node);
9716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        add_node_to_parent_locked(child_node, new_parent_node);
972fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
9736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    goto done;
974fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownio_error:
976f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
9776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Browndone:
9786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    release_node_locked(child_node);
9796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownlookup_error:
980f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
9816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return res;
982fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
983fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
984977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkeystatic int open_flags_to_access_mode(int open_flags) {
985977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    if ((open_flags & O_ACCMODE) == O_RDONLY) {
986977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return R_OK;
987977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    } else if ((open_flags & O_ACCMODE) == O_WRONLY) {
988977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return W_OK;
989977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    } else {
990977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        /* Probably O_RDRW, but treat as default to be safe */
991977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return R_OK | W_OK;
992977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
993977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey}
994977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey
9956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_open(struct fuse* fuse, struct fuse_handler* handler,
996fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_open_in* req)
997fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
9986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
9996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
1000f1e65b449ec802863f0e7fcbe211fc67bf0a65f3Andreas Gampe    struct fuse_open_out out = {};
1001fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h;
100203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1003f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
10046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
1005714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] OPEN 0" << std::oct << req->flags
1006e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes               << " @ " << std::hex << hdr->nodeid << std::dec
1007e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes               << " (" << (node ? node->name : "?") << ")";
1008f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
1009fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1010fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
10116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
1012fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1013aa04e818a4904b193e00d603785c93e888eab174Jeff Sharkey    if (!check_caller_access_to_node(fuse, hdr, node,
1014f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey            open_flags_to_access_mode(req->flags))) {
1015977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
1016977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
1017f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes    h = static_cast<struct handle*>(malloc(sizeof(*h)));
10186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!h) {
10196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
10206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
1021e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] OPEN " << path;
1022d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    h->fd = TEMP_FAILURE_RETRY(open(path, req->flags));
1023d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    if (h->fd == -1) {
1024fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        free(h);
10256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1026fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1027fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.fh = ptr_to_id(h);
1028fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.open_flags = 0;
1029fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
10306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1031fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1032fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_read(struct fuse* fuse, struct fuse_handler* handler,
1034fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_read_in* req)
1035fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1036f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes    struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
1037fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u64 unique = hdr->unique;
1038fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 size = req->size;
1039fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u64 offset = req->offset;
10406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int res;
1041e24e9a5091221f09526c083520367820810a7c98Elliott Hughes    __u8 *read_buffer = (__u8 *) ((uintptr_t)(handler->read_buffer + PAGE_SIZE) & ~((uintptr_t)PAGE_SIZE-1));
10426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1043fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* Don't access any other fields of hdr or req beyond this point, the read buffer
1044fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * overlaps the request buffer and will clobber data in the request.  This
1045fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * saves us 128KB per request handler thread at the cost of this scary comment. */
10466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1047e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] READ " << std::hex << h << std::dec
1048e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes               << "(" << h->fd << ") " << size << "@" << offset;
104980b435a3f35795600654e9705f4b3fbbcc427a9dArpad Horvath    if (size > MAX_READ) {
10506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -EINVAL;
1051fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1052d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    res = TEMP_FAILURE_RETRY(pread64(h->fd, read_buffer, size, offset));
1053d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    if (res == -1) {
10546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1055fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
105680b435a3f35795600654e9705f4b3fbbcc427a9dArpad Horvath    fuse_reply(fuse, unique, read_buffer, res);
10576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1058fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1059fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_write(struct fuse* fuse, struct fuse_handler* handler,
1061fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_write_in* req,
1062fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const void* buffer)
1063fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1064fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_write_out out;
1065f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes    struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
1066fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
1067e24e9a5091221f09526c083520367820810a7c98Elliott Hughes    __u8 aligned_buffer[req->size] __attribute__((__aligned__(PAGE_SIZE)));
106860281d556ded9fed3df770befb58990f7ae2e04fElliott Hughes
106949e9344bddca3699c04f3da8c689d0f2b1a338b6Arpad Horvath    if (req->flags & O_DIRECT) {
107049e9344bddca3699c04f3da8c689d0f2b1a338b6Arpad Horvath        memcpy(aligned_buffer, buffer, req->size);
107149e9344bddca3699c04f3da8c689d0f2b1a338b6Arpad Horvath        buffer = (const __u8*) aligned_buffer;
107249e9344bddca3699c04f3da8c689d0f2b1a338b6Arpad Horvath    }
10736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1074e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] WRITE " << std::hex << h << std::dec
1075e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes               << "(" << h->fd << ") " << req->size << "@" << req->offset;
1076d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    res = TEMP_FAILURE_RETRY(pwrite64(h->fd, buffer, req->size, req->offset));
1077d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    if (res == -1) {
10786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1079fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1080fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.size = res;
108119ec8860c1d80836b176dbf3dc434a94182094b7Daisuke Okitsu    out.padding = 0;
1082fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
10836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1084fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1085fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_statfs(struct fuse* fuse, struct fuse_handler* handler,
1087fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr)
1088fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
10896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
1090fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct statfs stat;
1091fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_statfs_out out;
1092fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
1093fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1094f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
1095e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] STATFS";
1096ed2fe57c2509d0d784ba7dbce1deef21afb2a612Jeff Sharkey    res = get_node_path_locked(&fuse->global->root, path, sizeof(path));
1097f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
10986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (res < 0) {
10996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
11006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
1101d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris    if (TEMP_FAILURE_RETRY(statfs(fuse->global->root.name, &stat)) == -1) {
11026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1103fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1104fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    memset(&out, 0, sizeof(out));
1105fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.blocks = stat.f_blocks;
1106fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bfree = stat.f_bfree;
1107fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bavail = stat.f_bavail;
1108fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.files = stat.f_files;
1109fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.ffree = stat.f_ffree;
1110fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bsize = stat.f_bsize;
1111fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.namelen = stat.f_namelen;
1112fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.frsize = stat.f_frsize;
1113fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
11146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1115fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1116fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
11176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_release(struct fuse* fuse, struct fuse_handler* handler,
1118fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_release_in* req)
1119fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1120f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes    struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
11216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1122e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] RELEASE " << std::hex << h << std::dec
1123e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes               << "(" << h->fd << ")";
1124fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    close(h->fd);
1125fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    free(h);
11266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1127fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1128fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
11296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
1130fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
1131fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1132f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    bool is_dir = (hdr->opcode == FUSE_FSYNCDIR);
1133f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    bool is_data_sync = req->fsync_flags & 1;
11346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1135f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    int fd = -1;
1136f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    if (is_dir) {
1137f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes      struct dirhandle *dh = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
1138f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes      fd = dirfd(dh->d);
1139f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    } else {
1140f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes      struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
1141f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes      fd = h->fd;
1142f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    }
1143f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes
1144e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] " << (is_dir ? "FSYNCDIR" : "FSYNC") << " "
1145e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes               << std::hex << req->fh << std::dec << "(" << fd << ") is_data_sync=" << is_data_sync;
1146f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    int res = is_data_sync ? fdatasync(fd) : fsync(fd);
1147f6d6737529ea164fd2ea79f02cc78a46bb9260f5Elliott Hughes    if (res == -1) {
11486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1149fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
11506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1151fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1152fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
11536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_flush(struct fuse* fuse, struct fuse_handler* handler,
1154fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr)
1155fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1156e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] FLUSH";
11576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1158fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1159fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
11606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
1161fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_open_in* req)
1162fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
11636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
11646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
1165f1e65b449ec802863f0e7fcbe211fc67bf0a65f3Andreas Gampe    struct fuse_open_out out = {};
1166fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirhandle *h;
1167fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1168f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_lock(&fuse->global->lock);
11696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
1170714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] OPENDIR @ " << std::hex << hdr->nodeid
1171714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes               << " (" << (node ? node->name : "?") << ")";
1172f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    pthread_mutex_unlock(&fuse->global->lock);
11736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1174fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
11756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
1176fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1177f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
1178977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey        return -EACCES;
1179977a9f3b1a05e6168e8245a1e2061225b68b2b41Jeff Sharkey    }
1180f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes    h = static_cast<struct dirhandle*>(malloc(sizeof(*h)));
1181fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!h) {
11826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
1183fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1184e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] OPENDIR " << path;
1185fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    h->d = opendir(path);
11866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!h->d) {
1187fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        free(h);
11886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
1189fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1190fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.fh = ptr_to_id(h);
11913a8768804ce4b4797359d5df03ec8897fe43de90Ken Sumrall    out.open_flags = 0;
1192fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
11936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1194fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1195fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
11966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_readdir(struct fuse* fuse, struct fuse_handler* handler,
1197fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_read_in* req)
1198fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1199fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    char buffer[8192];
1200fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
1201fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirent *de;
1202f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes    struct dirhandle *h = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
12036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1204e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] READDIR " << h;
1205fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (req->offset == 0) {
1206fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        /* rewinddir() might have been called above us, so rewind here too */
1207e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes        DLOG(INFO) << "[" << handler->token << "] calling rewinddir()";
1208fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        rewinddir(h->d);
1209fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1210fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    de = readdir(h->d);
1211fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!de) {
12126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return 0;
1213fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1214fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->ino = FUSE_UNKNOWN_INO;
1215fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
1216fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->off = req->offset + 1;
1217fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->type = de->d_type;
1218fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->namelen = strlen(de->d_name);
1219fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    memcpy(fde->name, de->d_name, fde->namelen + 1);
1220fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, fde,
12216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
12226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1223fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1224fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
12256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_releasedir(struct fuse* fuse, struct fuse_handler* handler,
1226fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_release_in* req)
1227fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1228f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes    struct dirhandle *h = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
12296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1230e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] RELEASEDIR " << h;
1231fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    closedir(h->d);
1232fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    free(h);
12336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1234fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1235fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
12366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_init(struct fuse* fuse, struct fuse_handler* handler,
1237fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_init_in* req)
1238fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1239fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_init_out out;
1240ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    size_t fuse_struct_size;
1241fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
1242e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] INIT ver=" << req->major << "." << req->minor
1243e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes               << " maxread=" << req->max_readahead << " flags=" << std::hex << req->flags;
1244ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris
1245ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    /* Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
1246ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris     * defined (fuse version 7.6). The structure is the same from 7.6 through
1247ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris     * 7.22. Beginning with 7.23, the structure increased in size and added
1248ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris     * new parameters.
1249ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris     */
1250ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) {
1251e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes        LOG(ERROR) << "Fuse kernel version mismatch: Kernel version "
1252e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes                   << req->major << "." << req->minor
1253e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes                   << ", Expected at least " << FUSE_KERNEL_VERSION << ".6";
1254ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris        return -1;
1255ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    }
1256ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris
1257f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    /* We limit ourselves to 15 because we don't handle BATCH_FORGET yet */
1258f38f29c87d97cea45d04b783bddbd969234b1030Jeff Sharkey    out.minor = MIN(req->minor, 15);
1259ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    fuse_struct_size = sizeof(out);
1260ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
1261ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    /* FUSE_KERNEL_VERSION >= 23. */
1262ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris
126316d0b426a32f9611278466ee4bb369241f55d74aDaichi Hirono    /* Since we return minor version 15, the kernel does not accept the latest
126416d0b426a32f9611278466ee4bb369241f55d74aDaichi Hirono     * fuse_init_out size. We need to use FUSE_COMPAT_22_INIT_OUT_SIZE always.*/
126516d0b426a32f9611278466ee4bb369241f55d74aDaichi Hirono    fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
1266ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris#endif
1267ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris
1268fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.major = FUSE_KERNEL_VERSION;
1269fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_readahead = req->max_readahead;
1270fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
1271fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_background = 32;
1272fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.congestion_threshold = 32;
1273fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_write = MAX_WRITE;
1274ff649ea5ab6a83910e414841fd02997cf9d54e60Christopher Ferris    fuse_reply(fuse, hdr->unique, &out, fuse_struct_size);
12756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1276fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1277fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
12782abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenbergstatic int handle_canonical_path(struct fuse* fuse, struct fuse_handler* handler,
12792abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg        const struct fuse_in_header *hdr)
12802abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg{
12812abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    struct node* node;
12822abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    char path[PATH_MAX];
12832abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    int len;
12842abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg
12852abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    pthread_mutex_lock(&fuse->global->lock);
12862abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
12872abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg            path, sizeof(path));
12888df46540b4d0af156583eecaea79c1e131c76f8aJorge Lucangeli Obes    DLOG(INFO) << "[" << handler->token << "] CANONICAL_PATH @ " << std::hex << hdr->nodeid
12898df46540b4d0af156583eecaea79c1e131c76f8aJorge Lucangeli Obes               << std::dec << " (" << (node ? node->name : "?") << ")";
12902abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    pthread_mutex_unlock(&fuse->global->lock);
12912abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg
12922abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    if (!node) {
12932abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg        return -ENOENT;
12942abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    }
12952abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
12962abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg        return -EACCES;
12972abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    }
12982abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    len = strlen(path);
12992abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    if (len + 1 > PATH_MAX)
13002abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg        len = PATH_MAX - 1;
13012abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    path[PATH_MAX - 1] = 0;
13022abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    fuse_reply(fuse, hdr->unique, path, len + 1);
13032abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    return NO_STATUS;
13042abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg}
13052abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg
13066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
1307fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const void *data, size_t data_len)
1308fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
130903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    switch (hdr->opcode) {
131003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_LOOKUP: { /* bytez[] -> entry_out */
1311f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const char *name = static_cast<const char*>(data);
13126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_lookup(fuse, handler, hdr, name);
131303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1314847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
131503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_FORGET: {
1316f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const struct fuse_forget_in *req = static_cast<const struct fuse_forget_in*>(data);
13176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_forget(fuse, handler, hdr, req);
131803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1319847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
132003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_GETATTR: { /* getattr_in -> attr_out */
1321f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const struct fuse_getattr_in *req = static_cast<const struct fuse_getattr_in*>(data);
13226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_getattr(fuse, handler, hdr, req);
132303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1324847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
132503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_SETATTR: { /* setattr_in -> attr_out */
1326f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const struct fuse_setattr_in *req = static_cast<const struct fuse_setattr_in*>(data);
13276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_setattr(fuse, handler, hdr, req);
132803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1329847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
133003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_READLINK:
133103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_SYMLINK:
133203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
1333f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const struct fuse_mknod_in *req = static_cast<const struct fuse_mknod_in*>(data);
1334847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char *name = ((const char*) data) + sizeof(*req);
13356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_mknod(fuse, handler, hdr, req, name);
133603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1337847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
133803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
1339f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const struct fuse_mkdir_in *req = static_cast<const struct fuse_mkdir_in*>(data);
1340847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char *name = ((const char*) data) + sizeof(*req);
13416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_mkdir(fuse, handler, hdr, req, name);
134203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1343847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
134403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_UNLINK: { /* bytez[] -> */
1345f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const char *name = static_cast<const char*>(data);
13466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_unlink(fuse, handler, hdr, name);
134703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1348847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
134903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RMDIR: { /* bytez[] -> */
1350f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const char *name = static_cast<const char*>(data);
13516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_rmdir(fuse, handler, hdr, name);
135203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1353847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
135403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RENAME: { /* rename_in, oldname, newname ->  */
1355f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const struct fuse_rename_in *req = static_cast<const struct fuse_rename_in*>(data);
13566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char *old_name = ((const char*) data) + sizeof(*req);
13576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char *new_name = old_name + strlen(old_name) + 1;
13586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_rename(fuse, handler, hdr, req, old_name, new_name);
135903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1360847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1361fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown//    case FUSE_LINK:
136203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_OPEN: { /* open_in -> open_out */
1363f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const struct fuse_open_in *req = static_cast<const struct fuse_open_in*>(data);
13646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_open(fuse, handler, hdr, req);
136503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1366847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
136703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_READ: { /* read_in -> byte[] */
1368f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const struct fuse_read_in *req = static_cast<const struct fuse_read_in*>(data);
13696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_read(fuse, handler, hdr, req);
137003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1371847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
137203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
1373f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const struct fuse_write_in *req = static_cast<const struct fuse_write_in*>(data);
1374847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const void* buffer = (const __u8*)data + sizeof(*req);
13756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_write(fuse, handler, hdr, req, buffer);
137603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1377847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
13784553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    case FUSE_STATFS: { /* getattr_in -> attr_out */
13796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_statfs(fuse, handler, hdr);
13804553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    }
1381847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
138203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RELEASE: { /* release_in -> */
1383f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const struct fuse_release_in *req = static_cast<const struct fuse_release_in*>(data);
13846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_release(fuse, handler, hdr, req);
138503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1386847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1387b2831a2db9e0370c5f797c037c135108025f2522Daisuke Okitsu    case FUSE_FSYNC:
1388b2831a2db9e0370c5f797c037c135108025f2522Daisuke Okitsu    case FUSE_FSYNCDIR: {
1389f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const struct fuse_fsync_in *req = static_cast<const struct fuse_fsync_in*>(data);
13906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_fsync(fuse, handler, hdr, req);
13916fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown    }
13926fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown
139303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_SETXATTR:
139403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_GETXATTR:
139503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_LISTXATTR:
139603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_REMOVEXATTR:
1397847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    case FUSE_FLUSH: {
13986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_flush(fuse, handler, hdr);
1399847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    }
1400847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
140103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_OPENDIR: { /* open_in -> open_out */
1402f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const struct fuse_open_in *req = static_cast<const struct fuse_open_in*>(data);
14036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_opendir(fuse, handler, hdr, req);
140403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1405847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
140603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_READDIR: {
1407f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const struct fuse_read_in *req = static_cast<const struct fuse_read_in*>(data);
14086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_readdir(fuse, handler, hdr, req);
140903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1410847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
141103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RELEASEDIR: { /* release_in -> */
1412f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const struct fuse_release_in *req = static_cast<const struct fuse_release_in*>(data);
14136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_releasedir(fuse, handler, hdr, req);
141403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1415847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
141603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_INIT: { /* init_in -> init_out */
1417f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const struct fuse_init_in *req = static_cast<const struct fuse_init_in*>(data);
14186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_init(fuse, handler, hdr, req);
141903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1420847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
14212abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    case FUSE_CANONICAL_PATH: { /* nodeid -> bytez[] */
14222abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg        return handle_canonical_path(fuse, handler, hdr);
14232abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg    }
14242abee9e063d1549fb006853b27f378c7d22192afDaniel Rosenberg
142503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    default: {
1426714ec9d1de9a8687be9203dee9c1f9cb13a9d73dJorge Lucangeli Obes        DLOG(INFO) << "[" << handler->token << "] NOTIMPL op=" << hdr->opcode
1427e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes                   << "uniq=" << std::hex << hdr->unique << "nid=" << hdr->nodeid << std::dec;
14286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOSYS;
142903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1430847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    }
143103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
143203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1433c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obesvoid handle_fuse_requests(struct fuse_handler* handler)
143403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
14356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse* fuse = handler->fuse;
143603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    for (;;) {
14376b6c1bd996be7b7b640ef9b074435620f73eecacMark Salyzyn        ssize_t len = TEMP_FAILURE_RETRY(read(fuse->fd,
14386b6c1bd996be7b7b640ef9b074435620f73eecacMark Salyzyn                handler->request_buffer, sizeof(handler->request_buffer)));
1439d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris        if (len == -1) {
14404a4858185177616707dda7ab562f45a0a8494e3fJeff Sharkey            if (errno == ENODEV) {
1441e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes                LOG(ERROR) << "[" << handler->token << "] someone stole our marbles!";
14424a4858185177616707dda7ab562f45a0a8494e3fJeff Sharkey                exit(2);
14434a4858185177616707dda7ab562f45a0a8494e3fJeff Sharkey            }
1444e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes            PLOG(ERROR) << "[" << handler->token << "] handle_fuse_requests";
14456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
144603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        }
1447847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1448d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris        if (static_cast<size_t>(len) < sizeof(struct fuse_in_header)) {
1449e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes            LOG(ERROR) << "[" << handler->token << "] request too short: len=" << len;
14506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
1451847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        }
1452847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1453f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes        const struct fuse_in_header* hdr =
1454f08ba055819cbdb24e55dba5de1ed502fc4bdd4eJorge Lucangeli Obes            reinterpret_cast<const struct fuse_in_header*>(handler->request_buffer);
1455d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris        if (hdr->len != static_cast<size_t>(len)) {
1456e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes            LOG(ERROR) << "[" << handler->token << "] malformed header: len=" << len
1457e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes                       << ", hdr->len=" << hdr->len;
14586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
1459847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        }
1460847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
14617729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        const void *data = handler->request_buffer + sizeof(struct fuse_in_header);
1462847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        size_t data_len = len - sizeof(struct fuse_in_header);
14636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        __u64 unique = hdr->unique;
14646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        int res = handle_fuse_request(fuse, handler, hdr, data, data_len);
14657729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown
14667729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        /* We do not access the request again after this point because the underlying
14677729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown         * buffer storage may have been reused while processing the request. */
14686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
14696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (res != NO_STATUS) {
14706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (res) {
1471e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes                DLOG(INFO) << "[" << handler->token << "] ERROR " << res;
14726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
14736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            fuse_status(fuse, unique, res);
14746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
147503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
147603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
1477