sdcard.c revision 6249b9009f44f2127670eda4d5aa6d5fd3e26e02
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
1703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <stdio.h>
1803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <stdlib.h>
1903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <string.h>
2003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <unistd.h>
2103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <errno.h>
2203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <fcntl.h>
2303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <sys/mount.h>
2403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <sys/stat.h>
254553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood#include <sys/statfs.h>
2603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <sys/uio.h>
2703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include <dirent.h>
287729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown#include <limits.h>
291bedb73f9fc239b69d958cbabc50c7ba382bacbcMike Lockwood#include <ctype.h>
306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown#include <pthread.h>
3103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
32b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland#include <private/android_filesystem_config.h>
33b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland
3403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include "fuse.h"
3503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland/* README
3703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
3803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * What is this?
3903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
4003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
4103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * directory permissions (all files are given fixed owner, group, and
4203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * permissions at creation, owner, group, and permissions are not
4303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * changeable, symlinks and hardlinks are not createable, etc.
4403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
4503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * usage:  sdcard <path> <uid> <gid>
4603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
4703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * It must be run as root, but will change to uid/gid as soon as it
48cfa9f650266621fee963fe18084a39602aa8fcc6Jeff Sharkey * mounts a filesystem on /storage/sdcard.  It will refuse to run if uid or
4903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * gid are zero.
5003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
5103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
5203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * Things I believe to be true:
5303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
5403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK,
5503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * CREAT) must bump that node's refcount
5603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - don't forget that FORGET can forget multiple references (req->nlookup)
5703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - if an op that returns a fuse_entry fails writing the reply to the
5803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * kernel, you must rollback the refcount to reflect the reference the
5903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * kernel did not actually acquire
6003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
6103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland */
6203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define FUSE_TRACE 0
6403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#if FUSE_TRACE
6603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define TRACE(x...) fprintf(stderr,x)
6703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#else
6803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define TRACE(x...) do {} while (0)
6903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#endif
7003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
7103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define ERROR(x...) fprintf(stderr,x)
7203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
7303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define FUSE_UNKNOWN_INO 0xffffffff
7403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
75cfa9f650266621fee963fe18084a39602aa8fcc6Jeff Sharkey#define MOUNT_POINT "/storage/sdcard0"
764553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood
77847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Maximum number of bytes to write in one request. */
78847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_WRITE (256 * 1024)
79847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
80847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Maximum number of bytes to read in one request. */
81847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_READ (128 * 1024)
82847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
83847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Largest possible request.
84847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown * The request size is bounded by the maximum size of a FUSE_WRITE request because it has
85847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown * the largest possible data payload. */
86847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_REQUEST_SIZE (sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE)
87847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Default number of threads. */
896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown#define DEFAULT_NUM_THREADS 2
906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Pseudo-error constant used to indicate that no fuse status is needed
926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or that a reply has already been written. */
936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown#define NO_STATUS 1
946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
9503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct handle {
9603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int fd;
9703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
9803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
9903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct dirhandle {
10003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    DIR *d;
10103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
10203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
10303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct node {
1046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    __u32 refcount;
10503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    __u64 nid;
10603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    __u64 gen;
10703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
10811ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    struct node *next;          /* per-dir sibling list */
10911ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    struct node *child;         /* first contained file by this dir */
11011ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    struct node *parent;        /* containing directory */
11103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen;
11311ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    char *name;
114575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood    /* If non-null, this is the real name of the file in the underlying storage.
115575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     * This may differ from the field "name" only by case.
116575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     * strlen(actual_name) will always equal strlen(name), so it is safe to use
117575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     * namelen for both fields.
118575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     */
119575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood    char *actual_name;
12003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
12103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1227729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown/* Global data structure shared by all fuse handlers. */
12303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct fuse {
1246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_t lock;
12503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    __u64 next_generation;
12703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int fd;
12803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct node root;
1297729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    char rootpath[PATH_MAX];
13003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
13103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1327729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown/* Private data used by a single fuse handler. */
1337729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brownstruct fuse_handler {
1346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse* fuse;
1356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int token;
1366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1377729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    /* To save memory, we never use the contents of the request buffer and the read
1387729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown     * buffer at the same time.  This allows us to share the underlying storage. */
1397729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    union {
1407729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        __u8 request_buffer[MAX_REQUEST_SIZE];
1417729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        __u8 read_buffer[MAX_READ];
1427729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    };
1437729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown};
14403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic inline void *id_to_ptr(__u64 nid)
1466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
1476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return (void *) (uintptr_t) nid;
1486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
149b94d320b1e7e2a3493147f6763cd2825b111a4d8Mike Lockwood
1506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic inline __u64 ptr_to_id(void *ptr)
1516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
1526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return (__u64) (uintptr_t) ptr;
1536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
1546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void acquire_node_locked(struct node* node)
1566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
1576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->refcount++;
1586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount);
1596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
1606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void remove_node_from_parent_locked(struct node* node);
1626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void release_node_locked(struct node* node)
1646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
1656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount);
1666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node->refcount > 0) {
1676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->refcount--;
1686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->refcount) {
1696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            TRACE("DESTROY %p (%s)\n", node, node->name);
1706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            remove_node_from_parent_locked(node);
1716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                /* TODO: remove debugging - poison memory */
1736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            memset(node->name, 0xef, node->namelen);
1746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->name);
1756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->actual_name);
1766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            memset(node, 0xfc, sizeof(*node));
1776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node);
1786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
1796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
1806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        ERROR("Zero refcnt %p\n", node);
1816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
1826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
1836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void add_node_to_parent_locked(struct node *node, struct node *parent) {
1856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->parent = parent;
1866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->next = parent->child;
1876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent->child = node;
1886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(parent);
1896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
1906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void remove_node_from_parent_locked(struct node* node)
1926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
1936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node->parent) {
1946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (node->parent->child == node) {
1956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->parent->child = node->parent->child->next;
1966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        } else {
1976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            struct node *node2;
1986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node2 = node->parent->child;
1996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            while (node2->next != node)
2006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                node2 = node2->next;
2016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node2->next = node->next;
2026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
2036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        release_node_locked(node->parent);
2046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->parent = NULL;
2056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->next = NULL;
2066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
2076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
2086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Gets the absolute path to a node into the provided buffer.
2106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown *
2116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Populates 'buf' with the path and returns the length of the path on success,
2126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or returns -1 if the path is too long for the provided buffer.
213f43219e0b1022b257499289ceb951f6a1a44bf9cPaul Eastham */
2146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize)
21503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
2166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = node->namelen;
2176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (bufsize < namelen + 1) {
2186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -1;
2196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
2206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    ssize_t pathlen = 0;
2226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node->parent) {
2236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 2);
2246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (pathlen < 0) {
2256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -1;
226575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
2276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        buf[pathlen++] = '/';
22803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
22903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
2306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* name = node->actual_name ? node->actual_name : node->name;
2316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
2326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return pathlen + namelen;
2336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
2346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Finds the absolute path of a file within a given directory.
2366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Performs a case-insensitive search for the file and sets the buffer to the path
2376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * of the first matching file.  If 'search' is zero or if no match is found, sets
2386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * the buffer to the path that the file would have, assuming the name were case-sensitive.
2396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown *
2406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Populates 'buf' with the path and returns the actual name (within 'buf') on success,
2416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or returns NULL if the path is too long for the provided buffer.
2426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown */
2436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic char* find_file_within(const char* path, const char* name,
2446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* buf, size_t bufsize, int search)
2456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
2466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t pathlen = strlen(path);
2476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
2486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t childlen = pathlen + namelen + 1;
2496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char* actual;
2506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (bufsize <= childlen) {
2526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
2536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
2546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(buf, path, pathlen);
2566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    buf[pathlen] = '/';
2576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    actual = buf + pathlen + 1;
2586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(actual, name, namelen + 1);
2596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (search && access(buf, F_OK)) {
261575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        struct dirent* entry;
2626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        DIR* dir = opendir(path);
263575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        if (!dir) {
264575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            ERROR("opendir %s failed: %s", path, strerror(errno));
2656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return actual;
266575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
267575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        while ((entry = readdir(dir))) {
2686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!strcasecmp(entry->d_name, name)) {
2696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                /* we have a match - replace the name, don't need to copy the null again */
2706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                memcpy(actual, entry->d_name, namelen);
271575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood                break;
272575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            }
273575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
274575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        closedir(dir);
275575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood    }
2766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return actual;
277575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood}
278575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood
2796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void attr_from_stat(struct fuse_attr *attr, const struct stat *s, __u64 nid)
280575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood{
2816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    attr->ino = nid;
28203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->size = s->st_size;
28303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->blocks = s->st_blocks;
2844553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->atime = s->st_atime;
2854553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->mtime = s->st_mtime;
2864553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->ctime = s->st_ctime;
2874553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->atimensec = s->st_atime_nsec;
2884553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->mtimensec = s->st_mtime_nsec;
2894553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->ctimensec = s->st_ctime_nsec;
29003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->mode = s->st_mode;
29103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->nlink = s->st_nlink;
29203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
293b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland        /* force permissions to something reasonable:
294b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland         * world readable
295b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland         * writable by the sdcard group
296b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland         */
297b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland    if (attr->mode & 0100) {
298b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland        attr->mode = (attr->mode & (~0777)) | 0775;
299b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland    } else {
300b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland        attr->mode = (attr->mode & (~0777)) | 0664;
301b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland    }
302b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland
303b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland        /* all files owned by root.sdcard */
304b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland    attr->uid = 0;
305b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland    attr->gid = AID_SDCARD_RW;
30603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
30703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstruct node *create_node_locked(struct fuse* fuse,
3096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct node *parent, const char *name, const char* actual_name)
31003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
31103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct node *node;
3126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
31303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
31411ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    node = calloc(1, sizeof(struct node));
3156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node) {
3166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
31703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
31811ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    node->name = malloc(namelen + 1);
3196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node->name) {
32011ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham        free(node);
3216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
32211ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    }
32303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    memcpy(node->name, name, namelen + 1);
3246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (strcmp(name, actual_name)) {
3256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->actual_name = malloc(namelen + 1);
3266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->actual_name) {
3276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->name);
3286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node);
3296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return NULL;
3306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
3316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        memcpy(node->actual_name, actual_name, namelen + 1);
3326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
33303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    node->namelen = namelen;
3346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->nid = ptr_to_id(node);
3356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->gen = fuse->next_generation++;
3366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(node);
3376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    add_node_to_parent_locked(node, parent);
33803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    return node;
33903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
34003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int rename_node_locked(struct node *node, const char *name,
3426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* actual_name)
34311ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham{
3446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
3456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int need_actual_name = strcmp(name, actual_name);
3466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* make the storage bigger without actually changing the name
3486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * in case an error occurs part way */
3496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (namelen > node->namelen) {
3506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* new_name = realloc(node->name, namelen + 1);
3516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!new_name) {
3526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -ENOMEM;
3536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
3546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->name = new_name;
3556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (need_actual_name && node->actual_name) {
3566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            char* new_actual_name = realloc(node->actual_name, namelen + 1);
3576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!new_actual_name) {
3586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                return -ENOMEM;
3596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
3606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->actual_name = new_actual_name;
3616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
3626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
36303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* update the name, taking care to allocate storage before overwriting the old name */
3656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (need_actual_name) {
3666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->actual_name) {
3676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->actual_name = malloc(namelen + 1);
3686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!node->actual_name) {
3696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                return -ENOMEM;
3706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
3716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
3726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        memcpy(node->actual_name, actual_name, namelen + 1);
3736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
3746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        free(node->actual_name);
3756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->actual_name = NULL;
3766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
3776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(node->name, name, namelen + 1);
3786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->namelen = namelen;
3796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
38003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
38103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
38303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
3846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (nid == FUSE_ROOT_ID) {
38503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        return &fuse->root;
38603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    } else {
38703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        return id_to_ptr(nid);
38803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
38903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
39003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node* lookup_node_and_path_by_id_locked(struct fuse* fuse, __u64 nid,
3926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* buf, size_t bufsize)
39303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
3946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node = lookup_node_by_id_locked(fuse, nid);
3956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node && get_node_path_locked(node, buf, bufsize) < 0) {
3966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node = NULL;
39703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
3986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return node;
39903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
40003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node *lookup_child_by_name_locked(struct node *node, const char *name)
40203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
40303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    for (node = node->child; node; node = node->next) {
4046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        /* use exact string comparison, nodes that differ by case
4056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * must be considered distinct even if they refer to the same
4066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * underlying file as otherwise operations such as "mv x x"
4076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * will not work because the source and target nodes are the same. */
4086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!strcmp(name, node->name)) {
40911ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham            return node;
41011ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham        }
41111ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    }
41211ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    return 0;
41311ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham}
41411ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham
4156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node* acquire_or_create_child_locked(
4166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct fuse* fuse, struct node* parent,
4176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* name, const char* actual_name)
41803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
4196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* child = lookup_child_by_name_locked(parent, name);
4206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (child) {
4216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        acquire_node_locked(child);
4226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
4236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        child = create_node_locked(fuse, parent, name, actual_name);
42403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
4256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return child;
42603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
42703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void fuse_init(struct fuse *fuse, int fd, const char *path)
42903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
4306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_init(&fuse->lock, NULL);
43103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse->fd = fd;
4336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse->next_generation = 0;
43403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memset(&fuse->root, 0, sizeof(fuse->root));
4366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse->root.nid = FUSE_ROOT_ID; /* 1 */
4376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse->root.refcount = 2;
4386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse->root.namelen = strlen(path);
4396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse->root.name = strdup(path);
44003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
44103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void fuse_status(struct fuse *fuse, __u64 unique, int err)
44303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
44403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct fuse_out_header hdr;
44503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.len = sizeof(hdr);
44603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.error = err;
44703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.unique = unique;
44803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    write(fuse->fd, &hdr, sizeof(hdr));
44903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
45003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
45203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
45303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct fuse_out_header hdr;
45403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct iovec vec[2];
45503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int res;
45603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
45703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.len = len + sizeof(hdr);
45803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.error = 0;
45903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.unique = unique;
46003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
46103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[0].iov_base = &hdr;
46203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[0].iov_len = sizeof(hdr);
46303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[1].iov_base = data;
46403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[1].iov_len = len;
46503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
46603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    res = writev(fuse->fd, vec, 2);
46703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    if (res < 0) {
46803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        ERROR("*** REPLY FAILED *** %d\n", errno);
46903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
47003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
47103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int fuse_reply_entry(struct fuse* fuse, __u64 unique,
4736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct node* parent, const char* name, const char* actual_name,
4746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* path)
47503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
476fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct node* node;
4776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_entry_out out;
4786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct stat s;
47903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (lstat(path, &s) < 0) {
4816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
48203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
483fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
4846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
4856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
4866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node) {
4876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        pthread_mutex_unlock(&fuse->lock);
4886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
4896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
4906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memset(&out, 0, sizeof(out));
4916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    attr_from_stat(&out.attr, &s, node->nid);
4926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.attr_valid = 10;
4936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.entry_valid = 10;
49403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    out.nodeid = node->nid;
49503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    out.generation = node->gen;
4966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
49703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    fuse_reply(fuse, unique, &out, sizeof(out));
4986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
49903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
50003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
5016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int fuse_reply_attr(struct fuse* fuse, __u64 unique, __u64 nid,
5026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* path)
50303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
5046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_attr_out out;
5056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct stat s;
506fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (lstat(path, &s) < 0) {
5086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
509fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
5106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memset(&out, 0, sizeof(out));
5116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    attr_from_stat(&out.attr, &s, nid);
5126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.attr_valid = 10;
5136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse_reply(fuse, unique, &out, sizeof(out));
5146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
5156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
516fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
5186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const struct fuse_in_header *hdr, const char* name)
5196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
5206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
5216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
5226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
5236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
5246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
5256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
5266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
5276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
5286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] LOOKUP %s @ %llx (%s)\n", handler->token, name, hdr->nodeid,
5296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        parent_node ? parent_node->name : "?");
5306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
5316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
5326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
5336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
5346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
5356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
5366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
537fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
538fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_forget(struct fuse* fuse, struct fuse_handler* handler,
540fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_forget_in *req)
541fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
5426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
543fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
5456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_by_id_locked(fuse, hdr->nodeid);
5466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] FORGET #%lld @ %llx (%s)\n", handler->token, req->nlookup,
5476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            hdr->nodeid, node ? node->name : "?");
5486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node) {
5496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        __u64 n = req->nlookup;
5506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        while (n--) {
5516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            release_node_locked(node);
5526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
553fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
5546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
5556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS; /* no reply */
556fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
557fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_getattr(struct fuse* fuse, struct fuse_handler* handler,
559fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_getattr_in *req)
560fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
5616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
5626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
5636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
5646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
5656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
5666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] GETATTR flags=%x fh=%llx @ %llx (%s)\n", handler->token,
5676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->getattr_flags, req->fh, hdr->nodeid, node ? node->name : "?");
5686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
569fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
570fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
5716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
572fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
5736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_attr(fuse, hdr->unique, hdr->nodeid, path);
574fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
575fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
577fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
578fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
5796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
5806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
581fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct timespec times[2];
582fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
5846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
5856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] SETATTR fh=%llx valid=%x @ %llx (%s)\n", handler->token,
5866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
5876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
5886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
589fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
5906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
591fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
592fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* XXX: incomplete implementation on purpose.
5946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * chmod/chown should NEVER be implemented.*/
595fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if ((req->valid & FATTR_SIZE) && truncate(path, req->size) < 0) {
5976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
598fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
599fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
600fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* Handle changing atime and mtime.  If FATTR_ATIME_and FATTR_ATIME_NOW
601fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * are both set, then set it to the current time.  Else, set it to the
602fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * time specified in the request.  Same goes for mtime.  Use utimensat(2)
603fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * as it allows ATIME and MTIME to be changed independently, and has
604fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * nanosecond resolution which fuse also has.
605fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     */
606fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
607fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        times[0].tv_nsec = UTIME_OMIT;
608fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        times[1].tv_nsec = UTIME_OMIT;
609fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        if (req->valid & FATTR_ATIME) {
610fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            if (req->valid & FATTR_ATIME_NOW) {
611fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_nsec = UTIME_NOW;
612fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            } else {
613fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_sec = req->atime;
614fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_nsec = req->atimensec;
615fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            }
616fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        }
617fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        if (req->valid & FATTR_MTIME) {
618fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            if (req->valid & FATTR_MTIME_NOW) {
619fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_nsec = UTIME_NOW;
620fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            } else {
621fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_sec = req->mtime;
622fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_nsec = req->mtimensec;
623fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            }
624fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        }
6256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        TRACE("[%d] Calling utimensat on %s with atime %ld, mtime=%ld\n",
6266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                handler->token, path, times[0].tv_sec, times[1].tv_sec);
6276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (utimensat(-1, path, times, 0) < 0) {
6286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -errno;
62903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        }
630fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
6316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_attr(fuse, hdr->unique, hdr->nodeid, path);
632fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
633fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
635fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
636fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
6376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
6386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
6396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
6406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
6416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
6426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
6436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
6446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
6456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] MKNOD %s 0%o @ %llx (%s)\n", handler->token,
6466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
6476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
6486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
6496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
6506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
6516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
652fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
653fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 mode = (req->mode & (~0777)) | 0664;
6546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (mknod(child_path, mode, req->rdev) < 0) {
6556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
656fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
6576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
658fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
659fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
661fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
662fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
6636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
6646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
6656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
6666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
6676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
6686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
6696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
6706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
6716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] MKDIR %s 0%o @ %llx (%s)\n", handler->token,
6726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
6736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
6746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
6756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
6766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
6776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
678fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
679fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 mode = (req->mode & (~0777)) | 0775;
6806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (mkdir(child_path, mode) < 0) {
6816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
682fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
6836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
684fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
685fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
687fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const char* name)
688fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
6896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
6906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
6916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
692fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
6946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
6956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
6966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] UNLINK %s @ %llx (%s)\n", handler->token,
6976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, hdr->nodeid, parent_node ? parent_node->name : "?");
6986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
699fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !find_file_within(parent_path, name,
7016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1)) {
7026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
7036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (unlink(child_path) < 0) {
7056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
7066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
708fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
709fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
711fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const char* name)
712fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
7136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
7146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
7156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
716fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
7186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
7196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
7206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RMDIR %s @ %llx (%s)\n", handler->token,
7216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, hdr->nodeid, parent_node ? parent_node->name : "?");
7226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
723fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !find_file_within(parent_path, name,
7256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1)) {
7266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
7276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (rmdir(child_path) < 0) {
7296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
7306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
732fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
733fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_rename(struct fuse* fuse, struct fuse_handler* handler,
735fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
7366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* old_name, const char* new_name)
737fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
7386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* old_parent_node;
7396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* new_parent_node;
7406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* child_node;
7416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char old_parent_path[PATH_MAX];
7426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char new_parent_path[PATH_MAX];
7436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char old_child_path[PATH_MAX];
7446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char new_child_path[PATH_MAX];
7456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* new_actual_name;
746fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
747fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
7496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
7506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_parent_path, sizeof(old_parent_path));
7516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
7526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            new_parent_path, sizeof(new_parent_path));
7536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RENAME %s->%s @ %llx (%s) -> %llx (%s)\n", handler->token,
7546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_name, new_name,
7556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            hdr->nodeid, old_parent_node ? old_parent_node->name : "?",
7566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->newdir, new_parent_node ? new_parent_node->name : "?");
7576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!old_parent_node || !new_parent_node) {
7586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
7596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto lookup_error;
7606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    child_node = lookup_child_by_name_locked(old_parent_node, old_name);
7626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!child_node || get_node_path_locked(child_node,
7636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_child_path, sizeof(old_child_path)) < 0) {
7646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
7656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto lookup_error;
7666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(child_node);
7686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
7696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
7706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* Special case for renaming a file where destination is same path
7716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * differing only by case.  In this case we don't want to look for a case
7726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * insensitive match.  This allows commands like "mv foo FOO" to work as expected.
7736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     */
7746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int search = old_parent_node != new_parent_node
7756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            || strcasecmp(old_name, new_name);
7766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!(new_actual_name = find_file_within(new_parent_path, new_name,
7776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            new_child_path, sizeof(new_child_path), search))) {
7786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
7796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto io_error;
780fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
781fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RENAME %s->%s\n", handler->token, old_child_path, new_child_path);
7836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = rename(old_child_path, new_child_path);
7846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (res < 0) {
7856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -errno;
7866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto io_error;
787fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
788fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
7906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = rename_node_locked(child_node, new_name, new_actual_name);
7916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!res) {
7926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        remove_node_from_parent_locked(child_node);
7936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        add_node_to_parent_locked(child_node, new_parent_node);
794fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
7956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    goto done;
796fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownio_error:
7986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
7996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Browndone:
8006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    release_node_locked(child_node);
8016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownlookup_error:
8026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
8036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return res;
804fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
805fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_open(struct fuse* fuse, struct fuse_handler* handler,
807fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_open_in* req)
808fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
8096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
8106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
811fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_open_out out;
812fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h;
81303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
8146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
8156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
8166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] OPEN 0%o @ %llx (%s)\n", handler->token,
8176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->flags, hdr->nodeid, node ? node->name : "?");
8186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
819fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
820fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
8216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
822fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
8236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    h = malloc(sizeof(*h));
8246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!h) {
8256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
8266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
8276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] OPEN %s\n", handler->token, path);
828fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    h->fd = open(path, req->flags);
829fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (h->fd < 0) {
830fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        free(h);
8316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
832fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
833fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.fh = ptr_to_id(h);
834fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.open_flags = 0;
835fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.padding = 0;
836fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
8376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
838fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
839fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_read(struct fuse* fuse, struct fuse_handler* handler,
841fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_read_in* req)
842fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
843fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
844fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u64 unique = hdr->unique;
845fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 size = req->size;
846fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u64 offset = req->offset;
8476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int res;
8486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
849fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* Don't access any other fields of hdr or req beyond this point, the read buffer
850fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * overlaps the request buffer and will clobber data in the request.  This
851fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * saves us 128KB per request handler thread at the cost of this scary comment. */
8526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
8536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] READ %p(%d) %u@%llu\n", handler->token,
8546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            h, h->fd, size, offset);
855fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (size > sizeof(handler->read_buffer)) {
8566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -EINVAL;
857fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
858fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    res = pread64(h->fd, handler->read_buffer, size, offset);
859fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (res < 0) {
8606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
861fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
862fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, unique, handler->read_buffer, res);
8636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
864fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
865fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_write(struct fuse* fuse, struct fuse_handler* handler,
867fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_write_in* req,
868fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const void* buffer)
869fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
870fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_write_out out;
871fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
872fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
8736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
8746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] WRITE %p(%d) %u@%llu\n", handler->token,
8756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            h, h->fd, req->size, req->offset);
876fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    res = pwrite64(h->fd, buffer, req->size, req->offset);
877fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (res < 0) {
8786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
879fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
880fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.size = res;
881fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
8826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
883fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
884fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_statfs(struct fuse* fuse, struct fuse_handler* handler,
886fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr)
887fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
8886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
889fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct statfs stat;
890fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_statfs_out out;
891fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
892fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
8946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] STATFS\n", handler->token);
8956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = get_node_path_locked(&fuse->root, path, sizeof(path));
8966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
8976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (res < 0) {
8986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
8996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
9006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (statfs(fuse->root.name, &stat) < 0) {
9016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
902fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
903fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    memset(&out, 0, sizeof(out));
904fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.blocks = stat.f_blocks;
905fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bfree = stat.f_bfree;
906fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bavail = stat.f_bavail;
907fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.files = stat.f_files;
908fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.ffree = stat.f_ffree;
909fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bsize = stat.f_bsize;
910fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.namelen = stat.f_namelen;
911fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.frsize = stat.f_frsize;
912fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
9136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
914fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
915fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_release(struct fuse* fuse, struct fuse_handler* handler,
917fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_release_in* req)
918fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
919fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
9206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
9216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RELEASE %p(%d)\n", handler->token, h, h->fd);
922fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    close(h->fd);
923fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    free(h);
9246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
925fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
926fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
928fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
929fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
930fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int is_data_sync = req->fsync_flags & 1;
931fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
932fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
9336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
9346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] FSYNC %p(%d) is_data_sync=%d\n", handler->token,
9356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            h, h->fd, is_data_sync);
936fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    res = is_data_sync ? fdatasync(h->fd) : fsync(h->fd);
937fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (res < 0) {
9386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
939fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
9406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
941fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
942fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_flush(struct fuse* fuse, struct fuse_handler* handler,
944fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr)
945fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
9466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] FLUSH\n", handler->token);
9476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
948fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
949fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
951fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_open_in* req)
952fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
9536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
9546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
955fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_open_out out;
956fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirhandle *h;
957fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
9596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
9606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] OPENDIR @ %llx (%s)\n", handler->token,
9616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            hdr->nodeid, node ? node->name : "?");
9626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
9636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
964fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
9656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
966fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
967fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    h = malloc(sizeof(*h));
968fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!h) {
9696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
970fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
9716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] OPENDIR %s\n", handler->token, path);
972fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    h->d = opendir(path);
9736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!h->d) {
974fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        free(h);
9756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
976fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
977fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.fh = ptr_to_id(h);
978fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
9796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
980fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
981fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_readdir(struct fuse* fuse, struct fuse_handler* handler,
983fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_read_in* req)
984fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
985fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    char buffer[8192];
986fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
987fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirent *de;
988fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirhandle *h = id_to_ptr(req->fh);
9896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
9906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] READDIR %p\n", handler->token, h);
991fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (req->offset == 0) {
992fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        /* rewinddir() might have been called above us, so rewind here too */
9936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        TRACE("[%d] calling rewinddir()\n", handler->token);
994fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        rewinddir(h->d);
995fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
996fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    de = readdir(h->d);
997fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!de) {
9986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return 0;
999fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
1000fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->ino = FUSE_UNKNOWN_INO;
1001fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
1002fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->off = req->offset + 1;
1003fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->type = de->d_type;
1004fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->namelen = strlen(de->d_name);
1005fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    memcpy(fde->name, de->d_name, fde->namelen + 1);
1006fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, fde,
10076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
10086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1009fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1010fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_releasedir(struct fuse* fuse, struct fuse_handler* handler,
1012fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_release_in* req)
1013fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1014fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirhandle *h = id_to_ptr(req->fh);
10156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
10166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RELEASEDIR %p\n", handler->token, h);
1017fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    closedir(h->d);
1018fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    free(h);
10196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1020fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1021fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_init(struct fuse* fuse, struct fuse_handler* handler,
1023fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_init_in* req)
1024fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1025fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_init_out out;
1026fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] INIT ver=%d.%d maxread=%d flags=%x\n",
10286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            handler->token, req->major, req->minor, req->max_readahead, req->flags);
1029fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.major = FUSE_KERNEL_VERSION;
1030fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.minor = FUSE_KERNEL_MINOR_VERSION;
1031fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_readahead = req->max_readahead;
1032fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
1033fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_background = 32;
1034fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.congestion_threshold = 32;
1035fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_write = MAX_WRITE;
1036fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
10376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1038fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1039fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
1041fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const void *data, size_t data_len)
1042fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
104303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    switch (hdr->opcode) {
104403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_LOOKUP: { /* bytez[] -> entry_out */
1045847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char* name = data;
10466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_lookup(fuse, handler, hdr, name);
104703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1048847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
104903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_FORGET: {
1050847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_forget_in *req = data;
10516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_forget(fuse, handler, hdr, req);
105203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1053847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
105403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_GETATTR: { /* getattr_in -> attr_out */
1055847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_getattr_in *req = data;
10566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_getattr(fuse, handler, hdr, req);
105703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1058847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
105903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_SETATTR: { /* setattr_in -> attr_out */
1060847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_setattr_in *req = data;
10616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_setattr(fuse, handler, hdr, req);
106203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1063847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
106403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_READLINK:
106503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_SYMLINK:
106603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
1067847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_mknod_in *req = data;
1068847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char *name = ((const char*) data) + sizeof(*req);
10696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_mknod(fuse, handler, hdr, req, name);
107003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1071847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
107203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
1073847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_mkdir_in *req = data;
1074847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char *name = ((const char*) data) + sizeof(*req);
10756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_mkdir(fuse, handler, hdr, req, name);
107603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1077847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
107803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_UNLINK: { /* bytez[] -> */
1079847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char* name = data;
10806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_unlink(fuse, handler, hdr, name);
108103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1082847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
108303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RMDIR: { /* bytez[] -> */
1084847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char* name = data;
10856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_rmdir(fuse, handler, hdr, name);
108603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1087847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
108803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RENAME: { /* rename_in, oldname, newname ->  */
1089847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_rename_in *req = data;
10906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char *old_name = ((const char*) data) + sizeof(*req);
10916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char *new_name = old_name + strlen(old_name) + 1;
10926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_rename(fuse, handler, hdr, req, old_name, new_name);
109303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1094847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1095fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown//    case FUSE_LINK:
109603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_OPEN: { /* open_in -> open_out */
1097847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_open_in *req = data;
10986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_open(fuse, handler, hdr, req);
109903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1100847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
110103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_READ: { /* read_in -> byte[] */
1102847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_read_in *req = data;
11036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_read(fuse, handler, hdr, req);
110403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1105847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
110603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
1107847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_write_in *req = data;
1108847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const void* buffer = (const __u8*)data + sizeof(*req);
11096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_write(fuse, handler, hdr, req, buffer);
111003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1111847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
11124553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    case FUSE_STATFS: { /* getattr_in -> attr_out */
11136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_statfs(fuse, handler, hdr);
11144553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    }
1115847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
111603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RELEASE: { /* release_in -> */
1117847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_release_in *req = data;
11186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_release(fuse, handler, hdr, req);
111903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1120847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
11216fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown    case FUSE_FSYNC: {
11226fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown        const struct fuse_fsync_in *req = data;
11236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_fsync(fuse, handler, hdr, req);
11246fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown    }
11256fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown
112603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_SETXATTR:
112703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_GETXATTR:
112803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_LISTXATTR:
112903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_REMOVEXATTR:
1130847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    case FUSE_FLUSH: {
11316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_flush(fuse, handler, hdr);
1132847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    }
1133847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
113403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_OPENDIR: { /* open_in -> open_out */
1135847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_open_in *req = data;
11366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_opendir(fuse, handler, hdr, req);
113703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1138847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
113903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_READDIR: {
1140847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_read_in *req = data;
11416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_readdir(fuse, handler, hdr, req);
114203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1143847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
114403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RELEASEDIR: { /* release_in -> */
1145847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_release_in *req = data;
11466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_releasedir(fuse, handler, hdr, req);
114703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1148847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
114903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_FSYNCDIR:
115003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_INIT: { /* init_in -> init_out */
1151847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_init_in *req = data;
11526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_init(fuse, handler, hdr, req);
115303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1154847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
115503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    default: {
11566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        TRACE("[%d] NOTIMPL op=%d uniq=%llx nid=%llx\n",
11576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                handler->token, hdr->opcode, hdr->unique, hdr->nodeid);
11586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOSYS;
115903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1160847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    }
116103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
116203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
11636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void handle_fuse_requests(struct fuse_handler* handler)
116403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
11656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse* fuse = handler->fuse;
116603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    for (;;) {
11676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        ssize_t len = read(fuse->fd,
11686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                handler->request_buffer, sizeof(handler->request_buffer));
116903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        if (len < 0) {
11706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (errno != EINTR) {
11716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                ERROR("[%d] handle_fuse_requests: errno=%d\n", handler->token, errno);
11726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
11736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
117403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        }
1175847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1176847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        if ((size_t)len < sizeof(struct fuse_in_header)) {
11776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            ERROR("[%d] request too short: len=%zu\n", handler->token, (size_t)len);
11786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
1179847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        }
1180847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
11817729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        const struct fuse_in_header *hdr = (void*)handler->request_buffer;
1182847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        if (hdr->len != (size_t)len) {
11836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            ERROR("[%d] malformed header: len=%zu, hdr->len=%u\n",
11846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                    handler->token, (size_t)len, hdr->len);
11856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
1186847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        }
1187847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
11887729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        const void *data = handler->request_buffer + sizeof(struct fuse_in_header);
1189847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        size_t data_len = len - sizeof(struct fuse_in_header);
11906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        __u64 unique = hdr->unique;
11916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        int res = handle_fuse_request(fuse, handler, hdr, data, data_len);
11927729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown
11937729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        /* We do not access the request again after this point because the underlying
11947729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown         * buffer storage may have been reused while processing the request. */
11956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
11966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (res != NO_STATUS) {
11976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (res) {
11986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                TRACE("[%d] ERROR %d\n", handler->token, res);
11996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
12006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            fuse_status(fuse, unique, res);
12016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
120203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
120303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
120403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
12056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void* start_handler(void* data)
12067729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown{
12076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_handler* handler = data;
12086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    handle_fuse_requests(handler);
12096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NULL;
12106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
12116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
12126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int ignite_fuse(struct fuse* fuse, int num_threads)
12136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
12146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_handler* handlers;
12156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int i;
12166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
12176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    handlers = malloc(num_threads * sizeof(struct fuse_handler));
12186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!handlers) {
12196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        ERROR("cannot allocate storage for threads");
12206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
12216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
12226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
12236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    for (i = 0; i < num_threads; i++) {
12246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        handlers[i].fuse = fuse;
12256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        handlers[i].token = i;
12266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
12276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
12286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    for (i = 1; i < num_threads; i++) {
12296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        pthread_t thread;
12306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        int res = pthread_create(&thread, NULL, start_handler, &handlers[i]);
12316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (res) {
12326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            ERROR("failed to start thread #%d, error=%d", i, res);
12336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            goto quit;
12346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
12356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
12366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    handle_fuse_requests(&handlers[0]);
12376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    ERROR("terminated prematurely");
12386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
12396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* don't bother killing all of the other threads or freeing anything,
12406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * should never get here anyhow */
12416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownquit:
12426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    exit(1);
12437729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown}
12447729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown
12454f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwoodstatic int usage()
12464f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood{
12476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    ERROR("usage: sdcard [-t<threads>] <path> <uid> <gid>\n"
12486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            "    -t<threads>: specify number of threads to use, default -t%d\n"
12496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            "\n", DEFAULT_NUM_THREADS);
12502656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    return 1;
12514f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood}
12524f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood
12536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int run(const char* path, uid_t uid, gid_t gid, int num_threads)
125403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
12552656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    int fd;
125603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    char opts[256];
12572656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    int res;
12582656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    struct fuse fuse;
12592656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12602656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    /* cleanup from previous instance, if necessary */
12612656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    umount2(MOUNT_POINT, 2);
12622656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12632656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    fd = open("/dev/fuse", O_RDWR);
12642656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (fd < 0){
12652656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        ERROR("cannot open fuse device (error %d)\n", errno);
12662656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        return -1;
12672656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
12682656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12692656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    snprintf(opts, sizeof(opts),
12702656735f515a41cf131c87be5f40550b6538ce80Jeff Brown            "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
12712656735f515a41cf131c87be5f40550b6538ce80Jeff Brown            fd, uid, gid);
12722656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12732656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    res = mount("/dev/fuse", MOUNT_POINT, "fuse", MS_NOSUID | MS_NODEV, opts);
12742656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (res < 0) {
12752656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        ERROR("cannot mount fuse filesystem (error %d)\n", errno);
12762656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        goto error;
12772656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
12782656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12792656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    res = setgid(gid);
12802656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (res < 0) {
12812656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        ERROR("cannot setgid (error %d)\n", errno);
12822656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        goto error;
12832656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
12842656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12852656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    res = setuid(uid);
12862656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (res < 0) {
12872656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        ERROR("cannot setuid (error %d)\n", errno);
12882656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        goto error;
12892656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
12902656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12912656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    fuse_init(&fuse, fd, path);
12922656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12932656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    umask(0);
12946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = ignite_fuse(&fuse, num_threads);
12952656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12962656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    /* we do not attempt to umount the file system here because we are no longer
12972656735f515a41cf131c87be5f40550b6538ce80Jeff Brown     * running as the root user */
12982656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12992656735f515a41cf131c87be5f40550b6538ce80Jeff Brownerror:
13002656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    close(fd);
13012656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    return res;
13022656735f515a41cf131c87be5f40550b6538ce80Jeff Brown}
13032656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
13042656735f515a41cf131c87be5f40550b6538ce80Jeff Brownint main(int argc, char **argv)
13052656735f515a41cf131c87be5f40550b6538ce80Jeff Brown{
130603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int res;
13074f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood    const char *path = NULL;
13082656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    uid_t uid = 0;
13092656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    gid_t gid = 0;
13106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int num_threads = DEFAULT_NUM_THREADS;
13114f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood    int i;
13124f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood
13134f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood    for (i = 1; i < argc; i++) {
13144f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        char* arg = argv[i];
13156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!strncmp(arg, "-t", 2))
13166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            num_threads = strtoul(arg + 2, 0, 10);
13176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        else if (!path)
1318575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            path = arg;
13192656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        else if (!uid)
1320575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            uid = strtoul(arg, 0, 10);
13212656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        else if (!gid)
1322575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            gid = strtoul(arg, 0, 10);
1323575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        else {
1324575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            ERROR("too many arguments\n");
1325575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            return usage();
13264f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        }
132703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
132803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
13294f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood    if (!path) {
13304f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        ERROR("no path specified\n");
13314f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        return usage();
13324f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood    }
13332656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (!uid || !gid) {
133403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        ERROR("uid and gid must be nonzero\n");
13354f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        return usage();
133603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
13376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (num_threads < 1) {
13386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        ERROR("number of threads must be at least 1\n");
13396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return usage();
13406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
134103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
13426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = run(path, uid, gid, num_threads);
13432656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    return res < 0 ? 1 : 0;
134403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
1345