sdcard.c revision e169bd05ec70f68c0db5e61c93b71e1746eb6c56
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 *
45e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey * See usage() for command line options.
4603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
47e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey * It must be run as root, but will drop to requested UID/GID as soon as it
48e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey * mounts a filesystem.  It will refuse to run if requested UID/GID are zero.
4903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
5003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * Things I believe to be true:
5103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
5203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK,
5303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * CREAT) must bump that node's refcount
5403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - don't forget that FORGET can forget multiple references (req->nlookup)
5503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - if an op that returns a fuse_entry fails writing the reply to the
5603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * kernel, you must rollback the refcount to reflect the reference the
5703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * kernel did not actually acquire
5803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland */
5903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define FUSE_TRACE 0
6103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#if FUSE_TRACE
6303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define TRACE(x...) fprintf(stderr,x)
6403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#else
6503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define TRACE(x...) do {} while (0)
6603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#endif
6703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define ERROR(x...) fprintf(stderr,x)
6903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
7003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define FUSE_UNKNOWN_INO 0xffffffff
7103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
72847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Maximum number of bytes to write in one request. */
73847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_WRITE (256 * 1024)
74847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
75847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Maximum number of bytes to read in one request. */
76847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_READ (128 * 1024)
77847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
78847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Largest possible request.
79847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown * The request size is bounded by the maximum size of a FUSE_WRITE request because it has
80847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown * the largest possible data payload. */
81847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_REQUEST_SIZE (sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE)
82847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Default number of threads. */
846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown#define DEFAULT_NUM_THREADS 2
856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Pseudo-error constant used to indicate that no fuse status is needed
876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or that a reply has already been written. */
886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown#define NO_STATUS 1
896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
9003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct handle {
9103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int fd;
9203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
9303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
9403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct dirhandle {
9503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    DIR *d;
9603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
9703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
9803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct node {
996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    __u32 refcount;
10003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    __u64 nid;
10103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    __u64 gen;
10203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
10311ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    struct node *next;          /* per-dir sibling list */
10411ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    struct node *child;         /* first contained file by this dir */
10511ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    struct node *parent;        /* containing directory */
10603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen;
10811ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    char *name;
109575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood    /* If non-null, this is the real name of the file in the underlying storage.
110575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     * This may differ from the field "name" only by case.
111575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     * strlen(actual_name) will always equal strlen(name), so it is safe to use
112575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     * namelen for both fields.
113575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     */
114575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood    char *actual_name;
11503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
11603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1177729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown/* Global data structure shared by all fuse handlers. */
11803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct fuse {
1196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_t lock;
12003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    __u64 next_generation;
12203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int fd;
12303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct node root;
1247729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    char rootpath[PATH_MAX];
12503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
12603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1277729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown/* Private data used by a single fuse handler. */
1287729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brownstruct fuse_handler {
1296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse* fuse;
1306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int token;
1316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1327729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    /* To save memory, we never use the contents of the request buffer and the read
1337729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown     * buffer at the same time.  This allows us to share the underlying storage. */
1347729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    union {
1357729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        __u8 request_buffer[MAX_REQUEST_SIZE];
1367729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        __u8 read_buffer[MAX_READ];
1377729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    };
1387729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown};
13903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic inline void *id_to_ptr(__u64 nid)
1416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
1426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return (void *) (uintptr_t) nid;
1436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
144b94d320b1e7e2a3493147f6763cd2825b111a4d8Mike Lockwood
1456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic inline __u64 ptr_to_id(void *ptr)
1466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
1476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return (__u64) (uintptr_t) ptr;
1486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
1496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void acquire_node_locked(struct node* node)
1516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
1526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->refcount++;
1536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount);
1546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
1556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void remove_node_from_parent_locked(struct node* node);
1576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void release_node_locked(struct node* node)
1596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
1606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount);
1616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node->refcount > 0) {
1626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->refcount--;
1636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->refcount) {
1646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            TRACE("DESTROY %p (%s)\n", node, node->name);
1656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            remove_node_from_parent_locked(node);
1666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                /* TODO: remove debugging - poison memory */
1686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            memset(node->name, 0xef, node->namelen);
1696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->name);
1706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->actual_name);
1716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            memset(node, 0xfc, sizeof(*node));
1726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node);
1736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
1746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
1756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        ERROR("Zero refcnt %p\n", node);
1766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
1776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
1786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void add_node_to_parent_locked(struct node *node, struct node *parent) {
1806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->parent = parent;
1816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->next = parent->child;
1826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent->child = node;
1836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(parent);
1846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
1856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void remove_node_from_parent_locked(struct node* node)
1876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
1886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node->parent) {
1896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (node->parent->child == node) {
1906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->parent->child = node->parent->child->next;
1916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        } else {
1926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            struct node *node2;
1936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node2 = node->parent->child;
1946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            while (node2->next != node)
1956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                node2 = node2->next;
1966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node2->next = node->next;
1976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
1986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        release_node_locked(node->parent);
1996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->parent = NULL;
2006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->next = NULL;
2016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
2026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
2036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Gets the absolute path to a node into the provided buffer.
2056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown *
2066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Populates 'buf' with the path and returns the length of the path on success,
2076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or returns -1 if the path is too long for the provided buffer.
208f43219e0b1022b257499289ceb951f6a1a44bf9cPaul Eastham */
2096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize)
21003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
2116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = node->namelen;
2126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (bufsize < namelen + 1) {
2136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -1;
2146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
2156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    ssize_t pathlen = 0;
2176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node->parent) {
2186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 2);
2196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (pathlen < 0) {
2206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -1;
221575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
2226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        buf[pathlen++] = '/';
22303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
22403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
2256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* name = node->actual_name ? node->actual_name : node->name;
2266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
2276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return pathlen + namelen;
2286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
2296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Finds the absolute path of a file within a given directory.
2316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Performs a case-insensitive search for the file and sets the buffer to the path
2326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * of the first matching file.  If 'search' is zero or if no match is found, sets
2336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * the buffer to the path that the file would have, assuming the name were case-sensitive.
2346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown *
2356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Populates 'buf' with the path and returns the actual name (within 'buf') on success,
2366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or returns NULL if the path is too long for the provided buffer.
2376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown */
2386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic char* find_file_within(const char* path, const char* name,
2396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* buf, size_t bufsize, int search)
2406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
2416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t pathlen = strlen(path);
2426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
2436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t childlen = pathlen + namelen + 1;
2446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char* actual;
2456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (bufsize <= childlen) {
2476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
2486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
2496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(buf, path, pathlen);
2516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    buf[pathlen] = '/';
2526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    actual = buf + pathlen + 1;
2536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(actual, name, namelen + 1);
2546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (search && access(buf, F_OK)) {
256575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        struct dirent* entry;
2576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        DIR* dir = opendir(path);
258575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        if (!dir) {
259575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            ERROR("opendir %s failed: %s", path, strerror(errno));
2606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return actual;
261575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
262575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        while ((entry = readdir(dir))) {
2636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!strcasecmp(entry->d_name, name)) {
2646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                /* we have a match - replace the name, don't need to copy the null again */
2656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                memcpy(actual, entry->d_name, namelen);
266575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood                break;
267575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            }
268575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
269575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        closedir(dir);
270575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood    }
2716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return actual;
272575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood}
273575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood
2746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void attr_from_stat(struct fuse_attr *attr, const struct stat *s, __u64 nid)
275575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood{
2766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    attr->ino = nid;
27703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->size = s->st_size;
27803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->blocks = s->st_blocks;
2794553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->atime = s->st_atime;
2804553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->mtime = s->st_mtime;
2814553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->ctime = s->st_ctime;
2824553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->atimensec = s->st_atime_nsec;
2834553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->mtimensec = s->st_mtime_nsec;
2844553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->ctimensec = s->st_ctime_nsec;
28503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->mode = s->st_mode;
28603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->nlink = s->st_nlink;
28703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
288b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland        /* force permissions to something reasonable:
289b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland         * world readable
290b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland         * writable by the sdcard group
291b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland         */
292b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland    if (attr->mode & 0100) {
293b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland        attr->mode = (attr->mode & (~0777)) | 0775;
294b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland    } else {
295b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland        attr->mode = (attr->mode & (~0777)) | 0664;
296b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland    }
297b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland
298b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland        /* all files owned by root.sdcard */
299b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland    attr->uid = 0;
300b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland    attr->gid = AID_SDCARD_RW;
30103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
30203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstruct node *create_node_locked(struct fuse* fuse,
3046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct node *parent, const char *name, const char* actual_name)
30503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
30603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct node *node;
3076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
30803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
30911ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    node = calloc(1, sizeof(struct node));
3106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node) {
3116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
31203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
31311ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    node->name = malloc(namelen + 1);
3146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node->name) {
31511ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham        free(node);
3166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
31711ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    }
31803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    memcpy(node->name, name, namelen + 1);
3196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (strcmp(name, actual_name)) {
3206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->actual_name = malloc(namelen + 1);
3216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->actual_name) {
3226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->name);
3236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node);
3246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return NULL;
3256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
3266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        memcpy(node->actual_name, actual_name, namelen + 1);
3276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
32803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    node->namelen = namelen;
3296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->nid = ptr_to_id(node);
3306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->gen = fuse->next_generation++;
3316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(node);
3326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    add_node_to_parent_locked(node, parent);
33303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    return node;
33403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
33503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int rename_node_locked(struct node *node, const char *name,
3376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* actual_name)
33811ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham{
3396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
3406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int need_actual_name = strcmp(name, actual_name);
3416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* make the storage bigger without actually changing the name
3436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * in case an error occurs part way */
3446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (namelen > node->namelen) {
3456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* new_name = realloc(node->name, namelen + 1);
3466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!new_name) {
3476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -ENOMEM;
3486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
3496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->name = new_name;
3506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (need_actual_name && node->actual_name) {
3516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            char* new_actual_name = realloc(node->actual_name, namelen + 1);
3526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!new_actual_name) {
3536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                return -ENOMEM;
3546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
3556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->actual_name = new_actual_name;
3566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
3576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
35803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* update the name, taking care to allocate storage before overwriting the old name */
3606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (need_actual_name) {
3616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->actual_name) {
3626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->actual_name = malloc(namelen + 1);
3636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!node->actual_name) {
3646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                return -ENOMEM;
3656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
3666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
3676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        memcpy(node->actual_name, actual_name, namelen + 1);
3686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
3696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        free(node->actual_name);
3706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->actual_name = NULL;
3716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
3726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(node->name, name, namelen + 1);
3736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->namelen = namelen;
3746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
37503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
37603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
37803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
3796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (nid == FUSE_ROOT_ID) {
38003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        return &fuse->root;
38103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    } else {
38203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        return id_to_ptr(nid);
38303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
38403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
38503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node* lookup_node_and_path_by_id_locked(struct fuse* fuse, __u64 nid,
3876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* buf, size_t bufsize)
38803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
3896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node = lookup_node_by_id_locked(fuse, nid);
3906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node && get_node_path_locked(node, buf, bufsize) < 0) {
3916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node = NULL;
39203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
3936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return node;
39403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
39503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node *lookup_child_by_name_locked(struct node *node, const char *name)
39703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
39803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    for (node = node->child; node; node = node->next) {
3996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        /* use exact string comparison, nodes that differ by case
4006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * must be considered distinct even if they refer to the same
4016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * underlying file as otherwise operations such as "mv x x"
4026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * will not work because the source and target nodes are the same. */
4036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!strcmp(name, node->name)) {
40411ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham            return node;
40511ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham        }
40611ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    }
40711ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    return 0;
40811ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham}
40911ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham
4106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node* acquire_or_create_child_locked(
4116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct fuse* fuse, struct node* parent,
4126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* name, const char* actual_name)
41303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
4146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* child = lookup_child_by_name_locked(parent, name);
4156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (child) {
4166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        acquire_node_locked(child);
4176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
4186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        child = create_node_locked(fuse, parent, name, actual_name);
41903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
4206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return child;
42103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
42203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
423e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkeystatic void fuse_init(struct fuse *fuse, int fd, const char *source_path)
42403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
4256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_init(&fuse->lock, NULL);
42603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse->fd = fd;
4286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse->next_generation = 0;
42903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memset(&fuse->root, 0, sizeof(fuse->root));
4316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse->root.nid = FUSE_ROOT_ID; /* 1 */
4326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse->root.refcount = 2;
433e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    fuse->root.namelen = strlen(source_path);
434e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    fuse->root.name = strdup(source_path);
43503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
43603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void fuse_status(struct fuse *fuse, __u64 unique, int err)
43803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
43903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct fuse_out_header hdr;
44003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.len = sizeof(hdr);
44103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.error = err;
44203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.unique = unique;
44303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    write(fuse->fd, &hdr, sizeof(hdr));
44403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
44503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
44703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
44803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct fuse_out_header hdr;
44903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct iovec vec[2];
45003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int res;
45103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
45203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.len = len + sizeof(hdr);
45303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.error = 0;
45403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.unique = unique;
45503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
45603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[0].iov_base = &hdr;
45703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[0].iov_len = sizeof(hdr);
45803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[1].iov_base = data;
45903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[1].iov_len = len;
46003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
46103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    res = writev(fuse->fd, vec, 2);
46203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    if (res < 0) {
46303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        ERROR("*** REPLY FAILED *** %d\n", errno);
46403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
46503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
46603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int fuse_reply_entry(struct fuse* fuse, __u64 unique,
4686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct node* parent, const char* name, const char* actual_name,
4696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* path)
47003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
471fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct node* node;
4726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_entry_out out;
4736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct stat s;
47403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (lstat(path, &s) < 0) {
4766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
47703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
478fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
4796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
4806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
4816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node) {
4826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        pthread_mutex_unlock(&fuse->lock);
4836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
4846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
4856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memset(&out, 0, sizeof(out));
4866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    attr_from_stat(&out.attr, &s, node->nid);
4876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.attr_valid = 10;
4886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.entry_valid = 10;
48903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    out.nodeid = node->nid;
49003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    out.generation = node->gen;
4916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
49203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    fuse_reply(fuse, unique, &out, sizeof(out));
4936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
49403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
49503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int fuse_reply_attr(struct fuse* fuse, __u64 unique, __u64 nid,
4976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* path)
49803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
4996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_attr_out out;
5006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct stat s;
501fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (lstat(path, &s) < 0) {
5036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
504fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
5056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memset(&out, 0, sizeof(out));
5066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    attr_from_stat(&out.attr, &s, nid);
5076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.attr_valid = 10;
5086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse_reply(fuse, unique, &out, sizeof(out));
5096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
5106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
511fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
5136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const struct fuse_in_header *hdr, const char* name)
5146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
5156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
5166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
5176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
5186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
5196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
5206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
5216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
5226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
5236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] LOOKUP %s @ %llx (%s)\n", handler->token, name, hdr->nodeid,
5246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        parent_node ? parent_node->name : "?");
5256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
5266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
5276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
5286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
5296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
5306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
5316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
532fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
533fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_forget(struct fuse* fuse, struct fuse_handler* handler,
535fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_forget_in *req)
536fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
5376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
538fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
5406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_by_id_locked(fuse, hdr->nodeid);
5416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] FORGET #%lld @ %llx (%s)\n", handler->token, req->nlookup,
5426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            hdr->nodeid, node ? node->name : "?");
5436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node) {
5446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        __u64 n = req->nlookup;
5456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        while (n--) {
5466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            release_node_locked(node);
5476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
548fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
5496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
5506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS; /* no reply */
551fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
552fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_getattr(struct fuse* fuse, struct fuse_handler* handler,
554fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_getattr_in *req)
555fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
5566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
5576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
5586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
5596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
5606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
5616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] GETATTR flags=%x fh=%llx @ %llx (%s)\n", handler->token,
5626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->getattr_flags, req->fh, hdr->nodeid, node ? node->name : "?");
5636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
564fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
565fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
5666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
567fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
5686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_attr(fuse, hdr->unique, hdr->nodeid, path);
569fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
570fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
572fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
573fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
5746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
5756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
576fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct timespec times[2];
577fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
5796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
5806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] SETATTR fh=%llx valid=%x @ %llx (%s)\n", handler->token,
5816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
5826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
5836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
584fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
5856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
586fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
587fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* XXX: incomplete implementation on purpose.
5896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * chmod/chown should NEVER be implemented.*/
590fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if ((req->valid & FATTR_SIZE) && truncate(path, req->size) < 0) {
5926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
593fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
594fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
595fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* Handle changing atime and mtime.  If FATTR_ATIME_and FATTR_ATIME_NOW
596fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * are both set, then set it to the current time.  Else, set it to the
597fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * time specified in the request.  Same goes for mtime.  Use utimensat(2)
598fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * as it allows ATIME and MTIME to be changed independently, and has
599fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * nanosecond resolution which fuse also has.
600fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     */
601fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
602fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        times[0].tv_nsec = UTIME_OMIT;
603fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        times[1].tv_nsec = UTIME_OMIT;
604fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        if (req->valid & FATTR_ATIME) {
605fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            if (req->valid & FATTR_ATIME_NOW) {
606fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_nsec = UTIME_NOW;
607fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            } else {
608fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_sec = req->atime;
609fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_nsec = req->atimensec;
610fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            }
611fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        }
612fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        if (req->valid & FATTR_MTIME) {
613fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            if (req->valid & FATTR_MTIME_NOW) {
614fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_nsec = UTIME_NOW;
615fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            } else {
616fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_sec = req->mtime;
617fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_nsec = req->mtimensec;
618fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            }
619fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        }
6206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        TRACE("[%d] Calling utimensat on %s with atime %ld, mtime=%ld\n",
6216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                handler->token, path, times[0].tv_sec, times[1].tv_sec);
6226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (utimensat(-1, path, times, 0) < 0) {
6236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -errno;
62403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        }
625fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
6266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_attr(fuse, hdr->unique, hdr->nodeid, path);
627fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
628fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
630fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
631fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
6326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
6336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
6346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
6356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
6366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
6376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
6386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
6396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
6406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] MKNOD %s 0%o @ %llx (%s)\n", handler->token,
6416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
6426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
6436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
6446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
6456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
6466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
647fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
648fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 mode = (req->mode & (~0777)) | 0664;
6496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (mknod(child_path, mode, req->rdev) < 0) {
6506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
651fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
6526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
653fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
654fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
656fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
657fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
6586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
6596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
6606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
6616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
6626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
6636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
6646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
6656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
6666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] MKDIR %s 0%o @ %llx (%s)\n", handler->token,
6676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
6686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
6696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
6706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
6716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
6726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
673fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
674fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 mode = (req->mode & (~0777)) | 0775;
6756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (mkdir(child_path, mode) < 0) {
6766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
677fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
6786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
679fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
680fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
682fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const char* name)
683fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
6846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
6856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
6866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
687fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
6896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
6906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
6916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] UNLINK %s @ %llx (%s)\n", handler->token,
6926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, hdr->nodeid, parent_node ? parent_node->name : "?");
6936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
694fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !find_file_within(parent_path, name,
6966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1)) {
6976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
6986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
6996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (unlink(child_path) < 0) {
7006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
7016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
703fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
704fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
706fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const char* name)
707fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
7086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
7096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
7106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
711fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
7136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
7146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
7156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RMDIR %s @ %llx (%s)\n", handler->token,
7166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, hdr->nodeid, parent_node ? parent_node->name : "?");
7176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
718fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !find_file_within(parent_path, name,
7206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1)) {
7216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
7226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (rmdir(child_path) < 0) {
7246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
7256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
727fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
728fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_rename(struct fuse* fuse, struct fuse_handler* handler,
730fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
7316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* old_name, const char* new_name)
732fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
7336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* old_parent_node;
7346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* new_parent_node;
7356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* child_node;
7366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char old_parent_path[PATH_MAX];
7376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char new_parent_path[PATH_MAX];
7386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char old_child_path[PATH_MAX];
7396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char new_child_path[PATH_MAX];
7406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* new_actual_name;
741fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
742fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
7446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
7456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_parent_path, sizeof(old_parent_path));
7466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
7476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            new_parent_path, sizeof(new_parent_path));
7486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RENAME %s->%s @ %llx (%s) -> %llx (%s)\n", handler->token,
7496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_name, new_name,
7506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            hdr->nodeid, old_parent_node ? old_parent_node->name : "?",
7516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->newdir, new_parent_node ? new_parent_node->name : "?");
7526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!old_parent_node || !new_parent_node) {
7536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
7546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto lookup_error;
7556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    child_node = lookup_child_by_name_locked(old_parent_node, old_name);
7576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!child_node || get_node_path_locked(child_node,
7586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_child_path, sizeof(old_child_path)) < 0) {
7596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
7606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto lookup_error;
7616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(child_node);
7636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
7646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
7656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* Special case for renaming a file where destination is same path
7666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * differing only by case.  In this case we don't want to look for a case
7676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * insensitive match.  This allows commands like "mv foo FOO" to work as expected.
7686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     */
7696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int search = old_parent_node != new_parent_node
7706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            || strcasecmp(old_name, new_name);
7716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!(new_actual_name = find_file_within(new_parent_path, new_name,
7726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            new_child_path, sizeof(new_child_path), search))) {
7736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
7746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto io_error;
775fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
776fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RENAME %s->%s\n", handler->token, old_child_path, new_child_path);
7786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = rename(old_child_path, new_child_path);
7796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (res < 0) {
7806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -errno;
7816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto io_error;
782fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
783fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
7856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = rename_node_locked(child_node, new_name, new_actual_name);
7866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!res) {
7876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        remove_node_from_parent_locked(child_node);
7886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        add_node_to_parent_locked(child_node, new_parent_node);
789fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
7906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    goto done;
791fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownio_error:
7936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
7946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Browndone:
7956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    release_node_locked(child_node);
7966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownlookup_error:
7976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
7986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return res;
799fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
800fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_open(struct fuse* fuse, struct fuse_handler* handler,
802fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_open_in* req)
803fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
8046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
8056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
806fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_open_out out;
807fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h;
80803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
8096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
8106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
8116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] OPEN 0%o @ %llx (%s)\n", handler->token,
8126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->flags, hdr->nodeid, node ? node->name : "?");
8136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
814fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
815fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
8166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
817fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
8186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    h = malloc(sizeof(*h));
8196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!h) {
8206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
8216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
8226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] OPEN %s\n", handler->token, path);
823fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    h->fd = open(path, req->flags);
824fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (h->fd < 0) {
825fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        free(h);
8266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
827fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
828fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.fh = ptr_to_id(h);
829fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.open_flags = 0;
830fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.padding = 0;
831fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
8326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
833fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
834fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_read(struct fuse* fuse, struct fuse_handler* handler,
836fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_read_in* req)
837fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
838fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
839fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u64 unique = hdr->unique;
840fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 size = req->size;
841fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u64 offset = req->offset;
8426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int res;
8436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
844fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* Don't access any other fields of hdr or req beyond this point, the read buffer
845fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * overlaps the request buffer and will clobber data in the request.  This
846fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * saves us 128KB per request handler thread at the cost of this scary comment. */
8476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
8486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] READ %p(%d) %u@%llu\n", handler->token,
8496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            h, h->fd, size, offset);
850fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (size > sizeof(handler->read_buffer)) {
8516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -EINVAL;
852fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
853fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    res = pread64(h->fd, handler->read_buffer, size, offset);
854fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (res < 0) {
8556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
856fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
857fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, unique, handler->read_buffer, res);
8586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
859fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
860fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_write(struct fuse* fuse, struct fuse_handler* handler,
862fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_write_in* req,
863fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const void* buffer)
864fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
865fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_write_out out;
866fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
867fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
8686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
8696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] WRITE %p(%d) %u@%llu\n", handler->token,
8706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            h, h->fd, req->size, req->offset);
871fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    res = pwrite64(h->fd, buffer, req->size, req->offset);
872fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (res < 0) {
8736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
874fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
875fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.size = res;
876fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
8776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
878fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
879fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_statfs(struct fuse* fuse, struct fuse_handler* handler,
881fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr)
882fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
8836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
884fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct statfs stat;
885fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_statfs_out out;
886fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
887fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
8896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] STATFS\n", handler->token);
8906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = get_node_path_locked(&fuse->root, path, sizeof(path));
8916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
8926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (res < 0) {
8936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
8946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
8956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (statfs(fuse->root.name, &stat) < 0) {
8966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
897fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
898fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    memset(&out, 0, sizeof(out));
899fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.blocks = stat.f_blocks;
900fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bfree = stat.f_bfree;
901fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bavail = stat.f_bavail;
902fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.files = stat.f_files;
903fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.ffree = stat.f_ffree;
904fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bsize = stat.f_bsize;
905fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.namelen = stat.f_namelen;
906fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.frsize = stat.f_frsize;
907fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
9086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
909fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
910fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_release(struct fuse* fuse, struct fuse_handler* handler,
912fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_release_in* req)
913fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
914fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
9156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
9166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RELEASE %p(%d)\n", handler->token, h, h->fd);
917fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    close(h->fd);
918fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    free(h);
9196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
920fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
921fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
923fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
924fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
925fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int is_data_sync = req->fsync_flags & 1;
926fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
927fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
9286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
9296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] FSYNC %p(%d) is_data_sync=%d\n", handler->token,
9306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            h, h->fd, is_data_sync);
931fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    res = is_data_sync ? fdatasync(h->fd) : fsync(h->fd);
932fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (res < 0) {
9336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
934fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
9356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
936fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
937fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_flush(struct fuse* fuse, struct fuse_handler* handler,
939fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr)
940fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
9416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] FLUSH\n", handler->token);
9426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
943fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
944fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
946fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_open_in* req)
947fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
9486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
9496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
950fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_open_out out;
951fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirhandle *h;
952fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
9546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
9556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] OPENDIR @ %llx (%s)\n", handler->token,
9566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            hdr->nodeid, node ? node->name : "?");
9576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
9586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
959fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
9606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
961fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
962fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    h = malloc(sizeof(*h));
963fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!h) {
9646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
965fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
9666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] OPENDIR %s\n", handler->token, path);
967fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    h->d = opendir(path);
9686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!h->d) {
969fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        free(h);
9706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
971fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
972fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.fh = ptr_to_id(h);
973fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
9746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
975fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
976fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_readdir(struct fuse* fuse, struct fuse_handler* handler,
978fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_read_in* req)
979fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
980fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    char buffer[8192];
981fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
982fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirent *de;
983fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirhandle *h = id_to_ptr(req->fh);
9846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
9856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] READDIR %p\n", handler->token, h);
986fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (req->offset == 0) {
987fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        /* rewinddir() might have been called above us, so rewind here too */
9886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        TRACE("[%d] calling rewinddir()\n", handler->token);
989fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        rewinddir(h->d);
990fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
991fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    de = readdir(h->d);
992fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!de) {
9936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return 0;
994fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
995fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->ino = FUSE_UNKNOWN_INO;
996fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
997fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->off = req->offset + 1;
998fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->type = de->d_type;
999fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->namelen = strlen(de->d_name);
1000fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    memcpy(fde->name, de->d_name, fde->namelen + 1);
1001fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, fde,
10026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
10036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1004fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1005fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_releasedir(struct fuse* fuse, struct fuse_handler* handler,
1007fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_release_in* req)
1008fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1009fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirhandle *h = id_to_ptr(req->fh);
10106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
10116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RELEASEDIR %p\n", handler->token, h);
1012fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    closedir(h->d);
1013fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    free(h);
10146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1015fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1016fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_init(struct fuse* fuse, struct fuse_handler* handler,
1018fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_init_in* req)
1019fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1020fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_init_out out;
1021fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] INIT ver=%d.%d maxread=%d flags=%x\n",
10236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            handler->token, req->major, req->minor, req->max_readahead, req->flags);
1024fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.major = FUSE_KERNEL_VERSION;
1025fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.minor = FUSE_KERNEL_MINOR_VERSION;
1026fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_readahead = req->max_readahead;
1027fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
1028fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_background = 32;
1029fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.congestion_threshold = 32;
1030fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_write = MAX_WRITE;
1031fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
10326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1033fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1034fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
1036fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const void *data, size_t data_len)
1037fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
103803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    switch (hdr->opcode) {
103903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_LOOKUP: { /* bytez[] -> entry_out */
1040847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char* name = data;
10416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_lookup(fuse, handler, hdr, name);
104203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1043847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
104403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_FORGET: {
1045847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_forget_in *req = data;
10466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_forget(fuse, handler, hdr, req);
104703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1048847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
104903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_GETATTR: { /* getattr_in -> attr_out */
1050847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_getattr_in *req = data;
10516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_getattr(fuse, handler, hdr, req);
105203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1053847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
105403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_SETATTR: { /* setattr_in -> attr_out */
1055847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_setattr_in *req = data;
10566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_setattr(fuse, handler, hdr, req);
105703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1058847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
105903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_READLINK:
106003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_SYMLINK:
106103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
1062847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_mknod_in *req = data;
1063847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char *name = ((const char*) data) + sizeof(*req);
10646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_mknod(fuse, handler, hdr, req, name);
106503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1066847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
106703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
1068847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_mkdir_in *req = data;
1069847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char *name = ((const char*) data) + sizeof(*req);
10706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_mkdir(fuse, handler, hdr, req, name);
107103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1072847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
107303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_UNLINK: { /* bytez[] -> */
1074847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char* name = data;
10756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_unlink(fuse, handler, hdr, name);
107603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1077847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
107803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RMDIR: { /* bytez[] -> */
1079847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char* name = data;
10806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_rmdir(fuse, handler, hdr, name);
108103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1082847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
108303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RENAME: { /* rename_in, oldname, newname ->  */
1084847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_rename_in *req = data;
10856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char *old_name = ((const char*) data) + sizeof(*req);
10866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char *new_name = old_name + strlen(old_name) + 1;
10876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_rename(fuse, handler, hdr, req, old_name, new_name);
108803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1089847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1090fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown//    case FUSE_LINK:
109103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_OPEN: { /* open_in -> open_out */
1092847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_open_in *req = data;
10936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_open(fuse, handler, hdr, req);
109403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1095847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
109603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_READ: { /* read_in -> byte[] */
1097847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_read_in *req = data;
10986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_read(fuse, handler, hdr, req);
109903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1100847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
110103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
1102847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_write_in *req = data;
1103847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const void* buffer = (const __u8*)data + sizeof(*req);
11046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_write(fuse, handler, hdr, req, buffer);
110503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1106847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
11074553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    case FUSE_STATFS: { /* getattr_in -> attr_out */
11086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_statfs(fuse, handler, hdr);
11094553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    }
1110847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
111103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RELEASE: { /* release_in -> */
1112847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_release_in *req = data;
11136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_release(fuse, handler, hdr, req);
111403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1115847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
11166fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown    case FUSE_FSYNC: {
11176fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown        const struct fuse_fsync_in *req = data;
11186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_fsync(fuse, handler, hdr, req);
11196fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown    }
11206fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown
112103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_SETXATTR:
112203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_GETXATTR:
112303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_LISTXATTR:
112403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_REMOVEXATTR:
1125847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    case FUSE_FLUSH: {
11266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_flush(fuse, handler, hdr);
1127847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    }
1128847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
112903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_OPENDIR: { /* open_in -> open_out */
1130847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_open_in *req = data;
11316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_opendir(fuse, handler, hdr, req);
113203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1133847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
113403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_READDIR: {
1135847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_read_in *req = data;
11366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_readdir(fuse, handler, hdr, req);
113703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1138847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
113903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RELEASEDIR: { /* release_in -> */
1140847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_release_in *req = data;
11416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_releasedir(fuse, handler, hdr, req);
114203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1143847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
114403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_FSYNCDIR:
114503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_INIT: { /* init_in -> init_out */
1146847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_init_in *req = data;
11476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_init(fuse, handler, hdr, req);
114803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1149847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
115003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    default: {
11516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        TRACE("[%d] NOTIMPL op=%d uniq=%llx nid=%llx\n",
11526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                handler->token, hdr->opcode, hdr->unique, hdr->nodeid);
11536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOSYS;
115403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1155847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    }
115603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
115703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
11586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void handle_fuse_requests(struct fuse_handler* handler)
115903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
11606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse* fuse = handler->fuse;
116103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    for (;;) {
11626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        ssize_t len = read(fuse->fd,
11636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                handler->request_buffer, sizeof(handler->request_buffer));
116403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        if (len < 0) {
11656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (errno != EINTR) {
11666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                ERROR("[%d] handle_fuse_requests: errno=%d\n", handler->token, errno);
11676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
11686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
116903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        }
1170847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1171847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        if ((size_t)len < sizeof(struct fuse_in_header)) {
11726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            ERROR("[%d] request too short: len=%zu\n", handler->token, (size_t)len);
11736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
1174847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        }
1175847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
11767729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        const struct fuse_in_header *hdr = (void*)handler->request_buffer;
1177847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        if (hdr->len != (size_t)len) {
11786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            ERROR("[%d] malformed header: len=%zu, hdr->len=%u\n",
11796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                    handler->token, (size_t)len, hdr->len);
11806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
1181847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        }
1182847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
11837729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        const void *data = handler->request_buffer + sizeof(struct fuse_in_header);
1184847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        size_t data_len = len - sizeof(struct fuse_in_header);
11856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        __u64 unique = hdr->unique;
11866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        int res = handle_fuse_request(fuse, handler, hdr, data, data_len);
11877729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown
11887729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        /* We do not access the request again after this point because the underlying
11897729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown         * buffer storage may have been reused while processing the request. */
11906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
11916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (res != NO_STATUS) {
11926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (res) {
11936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                TRACE("[%d] ERROR %d\n", handler->token, res);
11946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
11956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            fuse_status(fuse, unique, res);
11966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
119703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
119803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
119903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
12006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void* start_handler(void* data)
12017729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown{
12026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_handler* handler = data;
12036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    handle_fuse_requests(handler);
12046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NULL;
12056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
12066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
12076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int ignite_fuse(struct fuse* fuse, int num_threads)
12086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
12096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_handler* handlers;
12106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int i;
12116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
12126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    handlers = malloc(num_threads * sizeof(struct fuse_handler));
12136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!handlers) {
12146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        ERROR("cannot allocate storage for threads");
12156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
12166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
12176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
12186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    for (i = 0; i < num_threads; i++) {
12196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        handlers[i].fuse = fuse;
12206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        handlers[i].token = i;
12216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
12226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
12236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    for (i = 1; i < num_threads; i++) {
12246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        pthread_t thread;
12256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        int res = pthread_create(&thread, NULL, start_handler, &handlers[i]);
12266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (res) {
12276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            ERROR("failed to start thread #%d, error=%d", i, res);
12286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            goto quit;
12296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
12306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
12316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    handle_fuse_requests(&handlers[0]);
12326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    ERROR("terminated prematurely");
12336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
12346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* don't bother killing all of the other threads or freeing anything,
12356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * should never get here anyhow */
12366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownquit:
12376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    exit(1);
12387729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown}
12397729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown
12404f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwoodstatic int usage()
12414f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood{
1242e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    ERROR("usage: sdcard [-t<threads>] <source_path> <dest_path> <uid> <gid>\n"
12436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            "    -t<threads>: specify number of threads to use, default -t%d\n"
12446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            "\n", DEFAULT_NUM_THREADS);
12452656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    return 1;
12464f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood}
12474f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood
1248e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkeystatic int run(const char* source_path, const char* dest_path, uid_t uid, gid_t gid,
1249e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey        int num_threads) {
12502656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    int fd;
125103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    char opts[256];
12522656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    int res;
12532656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    struct fuse fuse;
12542656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12552656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    /* cleanup from previous instance, if necessary */
1256e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    umount2(dest_path, 2);
12572656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12582656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    fd = open("/dev/fuse", O_RDWR);
12592656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (fd < 0){
12602656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        ERROR("cannot open fuse device (error %d)\n", errno);
12612656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        return -1;
12622656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
12632656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12642656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    snprintf(opts, sizeof(opts),
12652656735f515a41cf131c87be5f40550b6538ce80Jeff Brown            "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
12662656735f515a41cf131c87be5f40550b6538ce80Jeff Brown            fd, uid, gid);
12672656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1268e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV, opts);
12692656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (res < 0) {
12702656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        ERROR("cannot mount fuse filesystem (error %d)\n", errno);
12712656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        goto error;
12722656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
12732656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12742656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    res = setgid(gid);
12752656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (res < 0) {
12762656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        ERROR("cannot setgid (error %d)\n", errno);
12772656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        goto error;
12782656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
12792656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12802656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    res = setuid(uid);
12812656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (res < 0) {
12822656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        ERROR("cannot setuid (error %d)\n", errno);
12832656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        goto error;
12842656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
12852656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1286e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    fuse_init(&fuse, fd, source_path);
12872656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12882656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    umask(0);
12896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = ignite_fuse(&fuse, num_threads);
12902656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12912656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    /* we do not attempt to umount the file system here because we are no longer
12922656735f515a41cf131c87be5f40550b6538ce80Jeff Brown     * running as the root user */
12932656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12942656735f515a41cf131c87be5f40550b6538ce80Jeff Brownerror:
12952656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    close(fd);
12962656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    return res;
12972656735f515a41cf131c87be5f40550b6538ce80Jeff Brown}
12982656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12992656735f515a41cf131c87be5f40550b6538ce80Jeff Brownint main(int argc, char **argv)
13002656735f515a41cf131c87be5f40550b6538ce80Jeff Brown{
130103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int res;
1302e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    const char *source_path = NULL;
1303e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    const char *dest_path = NULL;
13042656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    uid_t uid = 0;
13052656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    gid_t gid = 0;
13066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int num_threads = DEFAULT_NUM_THREADS;
13074f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood    int i;
13084f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood
13094f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood    for (i = 1; i < argc; i++) {
13104f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        char* arg = argv[i];
13116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!strncmp(arg, "-t", 2))
13126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            num_threads = strtoul(arg + 2, 0, 10);
1313e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey        else if (!source_path)
1314e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey            source_path = arg;
1315e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey        else if (!dest_path)
1316e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey            dest_path = arg;
13172656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        else if (!uid)
1318575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            uid = strtoul(arg, 0, 10);
13192656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        else if (!gid)
1320575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            gid = strtoul(arg, 0, 10);
1321575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        else {
1322575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            ERROR("too many arguments\n");
1323575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            return usage();
13244f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        }
132503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
132603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1327e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    if (!source_path) {
1328e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey        ERROR("no source path specified\n");
1329e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey        return usage();
1330e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    }
1331e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    if (!dest_path) {
1332e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey        ERROR("no dest path specified\n");
13334f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        return usage();
13344f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood    }
13352656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (!uid || !gid) {
133603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        ERROR("uid and gid must be nonzero\n");
13374f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        return usage();
133803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
13396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (num_threads < 1) {
13406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        ERROR("number of threads must be at least 1\n");
13416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return usage();
13426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
134303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1344e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    res = run(source_path, dest_path, uid, gid, num_threads);
13452656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    return res < 0 ? 1 : 0;
134603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
1347