sdcard.c revision 3a8768804ce4b4797359d5df03ec8897fe43de90
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>
312fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall#include <sys/time.h>
322fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall#include <sys/resource.h>
3303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
34b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland#include <private/android_filesystem_config.h>
35b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland
3603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include "fuse.h"
3703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland/* README
3903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
4003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * What is this?
4103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
4203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
4303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * directory permissions (all files are given fixed owner, group, and
4403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * permissions at creation, owner, group, and permissions are not
4503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * changeable, symlinks and hardlinks are not createable, etc.
4603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
47e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey * See usage() for command line options.
4803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
49e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey * It must be run as root, but will drop to requested UID/GID as soon as it
50e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey * mounts a filesystem.  It will refuse to run if requested UID/GID are zero.
5103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
5203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * Things I believe to be true:
5303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland *
5403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK,
5503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * CREAT) must bump that node's refcount
5603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - don't forget that FORGET can forget multiple references (req->nlookup)
5703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - if an op that returns a fuse_entry fails writing the reply to the
5803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * kernel, you must rollback the refcount to reflect the reference the
5903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * kernel did not actually acquire
6003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland */
6103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define FUSE_TRACE 0
6303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
6403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#if FUSE_TRACE
6503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define TRACE(x...) fprintf(stderr,x)
6603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#else
6703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define TRACE(x...) do {} while (0)
6803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#endif
6903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
7003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define ERROR(x...) fprintf(stderr,x)
7103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
7203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define FUSE_UNKNOWN_INO 0xffffffff
7303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
74847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Maximum number of bytes to write in one request. */
75847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_WRITE (256 * 1024)
76847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
77847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Maximum number of bytes to read in one request. */
78847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_READ (128 * 1024)
79847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
80847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Largest possible request.
81847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown * The request size is bounded by the maximum size of a FUSE_WRITE request because it has
82847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown * the largest possible data payload. */
83847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_REQUEST_SIZE (sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE)
84847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Default number of threads. */
866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown#define DEFAULT_NUM_THREADS 2
876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Pseudo-error constant used to indicate that no fuse status is needed
896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or that a reply has already been written. */
906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown#define NO_STATUS 1
916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
9203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct handle {
9303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int fd;
9403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
9503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
9603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct dirhandle {
9703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    DIR *d;
9803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
9903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
10003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct node {
1016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    __u32 refcount;
10203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    __u64 nid;
10303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    __u64 gen;
10403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
10511ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    struct node *next;          /* per-dir sibling list */
10611ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    struct node *child;         /* first contained file by this dir */
10711ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    struct node *parent;        /* containing directory */
10803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen;
11011ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    char *name;
111575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood    /* If non-null, this is the real name of the file in the underlying storage.
112575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     * This may differ from the field "name" only by case.
113575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     * strlen(actual_name) will always equal strlen(name), so it is safe to use
114575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     * namelen for both fields.
115575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood     */
116575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood    char *actual_name;
11703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
11803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1197729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown/* Global data structure shared by all fuse handlers. */
12003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct fuse {
1216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_t lock;
12203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    __u64 next_generation;
12403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int fd;
12503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct node root;
1267729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    char rootpath[PATH_MAX];
12703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland};
12803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1297729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown/* Private data used by a single fuse handler. */
1307729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brownstruct fuse_handler {
1316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse* fuse;
1326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int token;
1336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1347729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    /* To save memory, we never use the contents of the request buffer and the read
1357729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown     * buffer at the same time.  This allows us to share the underlying storage. */
1367729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    union {
1377729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        __u8 request_buffer[MAX_REQUEST_SIZE];
1387729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        __u8 read_buffer[MAX_READ];
1397729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown    };
1407729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown};
14103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic inline void *id_to_ptr(__u64 nid)
1436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
1446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return (void *) (uintptr_t) nid;
1456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
146b94d320b1e7e2a3493147f6763cd2825b111a4d8Mike Lockwood
1476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic inline __u64 ptr_to_id(void *ptr)
1486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
1496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return (__u64) (uintptr_t) ptr;
1506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
1516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void acquire_node_locked(struct node* node)
1536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
1546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->refcount++;
1556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount);
1566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
1576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void remove_node_from_parent_locked(struct node* node);
1596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void release_node_locked(struct node* node)
1616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
1626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount);
1636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node->refcount > 0) {
1646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->refcount--;
1656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->refcount) {
1666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            TRACE("DESTROY %p (%s)\n", node, node->name);
1676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            remove_node_from_parent_locked(node);
1686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                /* TODO: remove debugging - poison memory */
1706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            memset(node->name, 0xef, node->namelen);
1716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->name);
1726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->actual_name);
1736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            memset(node, 0xfc, sizeof(*node));
1746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node);
1756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
1766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
1776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        ERROR("Zero refcnt %p\n", node);
1786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
1796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
1806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void add_node_to_parent_locked(struct node *node, struct node *parent) {
1826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->parent = parent;
1836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->next = parent->child;
1846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent->child = node;
1856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(parent);
1866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
1876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
1886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void remove_node_from_parent_locked(struct node* node)
1896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
1906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node->parent) {
1916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (node->parent->child == node) {
1926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->parent->child = node->parent->child->next;
1936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        } else {
1946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            struct node *node2;
1956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node2 = node->parent->child;
1966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            while (node2->next != node)
1976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                node2 = node2->next;
1986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node2->next = node->next;
1996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
2006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        release_node_locked(node->parent);
2016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->parent = NULL;
2026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->next = NULL;
2036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
2046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
2056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Gets the absolute path to a node into the provided buffer.
2076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown *
2086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Populates 'buf' with the path and returns the length of the path on success,
2096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or returns -1 if the path is too long for the provided buffer.
210f43219e0b1022b257499289ceb951f6a1a44bf9cPaul Eastham */
2116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize)
21203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
2136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = node->namelen;
2146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (bufsize < namelen + 1) {
2156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -1;
2166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
2176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    ssize_t pathlen = 0;
2196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node->parent) {
2206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 2);
2216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (pathlen < 0) {
2226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -1;
223575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
2246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        buf[pathlen++] = '/';
22503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
22603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
2276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* name = node->actual_name ? node->actual_name : node->name;
2286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
2296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return pathlen + namelen;
2306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
2316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown/* Finds the absolute path of a file within a given directory.
2336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Performs a case-insensitive search for the file and sets the buffer to the path
2346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * of the first matching file.  If 'search' is zero or if no match is found, sets
2356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * the buffer to the path that the file would have, assuming the name were case-sensitive.
2366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown *
2376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * Populates 'buf' with the path and returns the actual name (within 'buf') on success,
2386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown * or returns NULL if the path is too long for the provided buffer.
2396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown */
2406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic char* find_file_within(const char* path, const char* name,
2416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* buf, size_t bufsize, int search)
2426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
2436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t pathlen = strlen(path);
2446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
2456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t childlen = pathlen + namelen + 1;
2466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char* actual;
2476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (bufsize <= childlen) {
2496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
2506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
2516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(buf, path, pathlen);
2536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    buf[pathlen] = '/';
2546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    actual = buf + pathlen + 1;
2556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(actual, name, namelen + 1);
2566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
2576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (search && access(buf, F_OK)) {
258575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        struct dirent* entry;
2596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        DIR* dir = opendir(path);
260575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        if (!dir) {
261575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            ERROR("opendir %s failed: %s", path, strerror(errno));
2626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return actual;
263575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
264575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        while ((entry = readdir(dir))) {
2656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!strcasecmp(entry->d_name, name)) {
2666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                /* we have a match - replace the name, don't need to copy the null again */
2676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                memcpy(actual, entry->d_name, namelen);
268575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood                break;
269575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            }
270575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        }
271575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood        closedir(dir);
272575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood    }
2736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return actual;
274575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood}
275575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood
2766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void attr_from_stat(struct fuse_attr *attr, const struct stat *s, __u64 nid)
277575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood{
2786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    attr->ino = nid;
27903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->size = s->st_size;
28003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->blocks = s->st_blocks;
2814553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->atime = s->st_atime;
2824553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->mtime = s->st_mtime;
2834553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->ctime = s->st_ctime;
2844553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->atimensec = s->st_atime_nsec;
2854553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->mtimensec = s->st_mtime_nsec;
2864553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    attr->ctimensec = s->st_ctime_nsec;
28703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->mode = s->st_mode;
28803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    attr->nlink = s->st_nlink;
28903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
290b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland        /* force permissions to something reasonable:
291b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland         * world readable
292b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland         * writable by the sdcard group
293b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland         */
294b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland    if (attr->mode & 0100) {
295b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland        attr->mode = (attr->mode & (~0777)) | 0775;
296b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland    } else {
297b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland        attr->mode = (attr->mode & (~0777)) | 0664;
298b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland    }
299b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland
300b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland        /* all files owned by root.sdcard */
301b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland    attr->uid = 0;
302b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland    attr->gid = AID_SDCARD_RW;
30303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
30403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstruct node *create_node_locked(struct fuse* fuse,
3066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct node *parent, const char *name, const char* actual_name)
30703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
30803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct node *node;
3096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
31003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
31111ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    node = calloc(1, sizeof(struct node));
3126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node) {
3136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
31403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
31511ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    node->name = malloc(namelen + 1);
3166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node->name) {
31711ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham        free(node);
3186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return NULL;
31911ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    }
32003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    memcpy(node->name, name, namelen + 1);
3216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (strcmp(name, actual_name)) {
3226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->actual_name = malloc(namelen + 1);
3236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->actual_name) {
3246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node->name);
3256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            free(node);
3266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return NULL;
3276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
3286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        memcpy(node->actual_name, actual_name, namelen + 1);
3296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
33003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    node->namelen = namelen;
3316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->nid = ptr_to_id(node);
3326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->gen = fuse->next_generation++;
3336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(node);
3346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    add_node_to_parent_locked(node, parent);
33503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    return node;
33603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
33703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int rename_node_locked(struct node *node, const char *name,
3396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* actual_name)
34011ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham{
3416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    size_t namelen = strlen(name);
3426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int need_actual_name = strcmp(name, actual_name);
3436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
3446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* make the storage bigger without actually changing the name
3456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * in case an error occurs part way */
3466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (namelen > node->namelen) {
3476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* new_name = realloc(node->name, namelen + 1);
3486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!new_name) {
3496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -ENOMEM;
3506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
3516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->name = new_name;
3526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (need_actual_name && node->actual_name) {
3536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            char* new_actual_name = realloc(node->actual_name, namelen + 1);
3546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!new_actual_name) {
3556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                return -ENOMEM;
3566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
3576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->actual_name = new_actual_name;
3586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
3596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
36003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* update the name, taking care to allocate storage before overwriting the old name */
3626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (need_actual_name) {
3636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!node->actual_name) {
3646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            node->actual_name = malloc(namelen + 1);
3656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (!node->actual_name) {
3666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                return -ENOMEM;
3676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
3686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
3696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        memcpy(node->actual_name, actual_name, namelen + 1);
3706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
3716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        free(node->actual_name);
3726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node->actual_name = NULL;
3736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
3746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memcpy(node->name, name, namelen + 1);
3756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node->namelen = namelen;
3766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
37703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
37803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
38003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
3816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (nid == FUSE_ROOT_ID) {
38203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        return &fuse->root;
38303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    } else {
38403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        return id_to_ptr(nid);
38503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
38603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
38703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node* lookup_node_and_path_by_id_locked(struct fuse* fuse, __u64 nid,
3896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        char* buf, size_t bufsize)
39003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
3916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node = lookup_node_by_id_locked(fuse, nid);
3926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node && get_node_path_locked(node, buf, bufsize) < 0) {
3936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        node = NULL;
39403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
3956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return node;
39603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
39703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
3986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node *lookup_child_by_name_locked(struct node *node, const char *name)
39903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
40003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    for (node = node->child; node; node = node->next) {
4016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        /* use exact string comparison, nodes that differ by case
4026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * must be considered distinct even if they refer to the same
4036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * underlying file as otherwise operations such as "mv x x"
4046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown         * will not work because the source and target nodes are the same. */
4056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!strcmp(name, node->name)) {
40611ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham            return node;
40711ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham        }
40811ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    }
40911ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham    return 0;
41011ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham}
41111ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham
4126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic struct node* acquire_or_create_child_locked(
4136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct fuse* fuse, struct node* parent,
4146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* name, const char* actual_name)
41503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
4166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* child = lookup_child_by_name_locked(parent, name);
4176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (child) {
4186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        acquire_node_locked(child);
4196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    } else {
4206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        child = create_node_locked(fuse, parent, name, actual_name);
42103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
4226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return child;
42303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
42403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
425e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkeystatic void fuse_init(struct fuse *fuse, int fd, const char *source_path)
42603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
4276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_init(&fuse->lock, NULL);
42803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse->fd = fd;
4306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse->next_generation = 0;
43103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memset(&fuse->root, 0, sizeof(fuse->root));
4336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse->root.nid = FUSE_ROOT_ID; /* 1 */
4346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse->root.refcount = 2;
435e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    fuse->root.namelen = strlen(source_path);
436e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    fuse->root.name = strdup(source_path);
43703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
43803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void fuse_status(struct fuse *fuse, __u64 unique, int err)
44003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
44103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct fuse_out_header hdr;
44203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.len = sizeof(hdr);
44303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.error = err;
44403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.unique = unique;
44503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    write(fuse->fd, &hdr, sizeof(hdr));
44603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
44703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
44903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
45003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct fuse_out_header hdr;
45103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    struct iovec vec[2];
45203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int res;
45303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
45403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.len = len + sizeof(hdr);
45503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.error = 0;
45603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    hdr.unique = unique;
45703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
45803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[0].iov_base = &hdr;
45903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[0].iov_len = sizeof(hdr);
46003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[1].iov_base = data;
46103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    vec[1].iov_len = len;
46203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
46303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    res = writev(fuse->fd, vec, 2);
46403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    if (res < 0) {
46503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        ERROR("*** REPLY FAILED *** %d\n", errno);
46603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
46703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
46803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int fuse_reply_entry(struct fuse* fuse, __u64 unique,
4706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        struct node* parent, const char* name, const char* actual_name,
4716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* path)
47203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
473fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct node* node;
4746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_entry_out out;
4756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct stat s;
47603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (lstat(path, &s) < 0) {
4786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
47903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
480fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
4816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
4826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
4836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!node) {
4846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        pthread_mutex_unlock(&fuse->lock);
4856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
4866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
4876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memset(&out, 0, sizeof(out));
4886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    attr_from_stat(&out.attr, &s, node->nid);
4896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.attr_valid = 10;
4906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.entry_valid = 10;
49103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    out.nodeid = node->nid;
49203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    out.generation = node->gen;
4936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
49403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    fuse_reply(fuse, unique, &out, sizeof(out));
4956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
49603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
49703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
4986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int fuse_reply_attr(struct fuse* fuse, __u64 unique, __u64 nid,
4996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* path)
50003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
5016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_attr_out out;
5026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct stat s;
503fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (lstat(path, &s) < 0) {
5056249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
506fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
5076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    memset(&out, 0, sizeof(out));
5086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    attr_from_stat(&out.attr, &s, nid);
5096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    out.attr_valid = 10;
5106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    fuse_reply(fuse, unique, &out, sizeof(out));
5116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
5126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
513fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
5156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const struct fuse_in_header *hdr, const char* name)
5166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
5176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
5186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
5196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
5206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
5216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
5226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
5236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
5246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
5256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] LOOKUP %s @ %llx (%s)\n", handler->token, name, hdr->nodeid,
5266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        parent_node ? parent_node->name : "?");
5276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
5286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
5296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
5306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
5316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
5326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
5336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
534fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
535fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_forget(struct fuse* fuse, struct fuse_handler* handler,
537fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_forget_in *req)
538fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
5396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
540fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
5426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_by_id_locked(fuse, hdr->nodeid);
5436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] FORGET #%lld @ %llx (%s)\n", handler->token, req->nlookup,
5446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            hdr->nodeid, node ? node->name : "?");
5456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (node) {
5466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        __u64 n = req->nlookup;
5476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        while (n--) {
5486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            release_node_locked(node);
5496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
550fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
5516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
5526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS; /* no reply */
553fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
554fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_getattr(struct fuse* fuse, struct fuse_handler* handler,
556fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_getattr_in *req)
557fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
5586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
5596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
5606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
5616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
5626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
5636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] GETATTR flags=%x fh=%llx @ %llx (%s)\n", handler->token,
5646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->getattr_flags, req->fh, hdr->nodeid, node ? node->name : "?");
5656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
566fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
567fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
5686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
569fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
5706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_attr(fuse, hdr->unique, hdr->nodeid, path);
571fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
572fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
574fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
575fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
5766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
5776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
578fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct timespec times[2];
579fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
5816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
5826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] SETATTR fh=%llx valid=%x @ %llx (%s)\n", handler->token,
5836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
5846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
5856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
586fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
5876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
588fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
589fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* XXX: incomplete implementation on purpose.
5916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * chmod/chown should NEVER be implemented.*/
592fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
5936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if ((req->valid & FATTR_SIZE) && truncate(path, req->size) < 0) {
5946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
595fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
596fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
597fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* Handle changing atime and mtime.  If FATTR_ATIME_and FATTR_ATIME_NOW
598fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * are both set, then set it to the current time.  Else, set it to the
599fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * time specified in the request.  Same goes for mtime.  Use utimensat(2)
600fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * as it allows ATIME and MTIME to be changed independently, and has
601fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * nanosecond resolution which fuse also has.
602fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     */
603fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
604fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        times[0].tv_nsec = UTIME_OMIT;
605fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        times[1].tv_nsec = UTIME_OMIT;
606fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        if (req->valid & FATTR_ATIME) {
607fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            if (req->valid & FATTR_ATIME_NOW) {
608fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_nsec = UTIME_NOW;
609fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            } else {
610fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_sec = req->atime;
611fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[0].tv_nsec = req->atimensec;
612fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            }
613fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        }
614fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        if (req->valid & FATTR_MTIME) {
615fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            if (req->valid & FATTR_MTIME_NOW) {
616fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_nsec = UTIME_NOW;
617fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            } else {
618fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_sec = req->mtime;
619fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown              times[1].tv_nsec = req->mtimensec;
620fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown            }
621fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        }
6226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        TRACE("[%d] Calling utimensat on %s with atime %ld, mtime=%ld\n",
6236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                handler->token, path, times[0].tv_sec, times[1].tv_sec);
6246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (utimensat(-1, path, times, 0) < 0) {
6256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            return -errno;
62603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        }
627fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
6286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_attr(fuse, hdr->unique, hdr->nodeid, path);
629fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
630fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
632fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
633fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
6346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
6356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
6366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
6376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
6386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
6396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
6406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
6416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
6426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] MKNOD %s 0%o @ %llx (%s)\n", handler->token,
6436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
6446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
6456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
6466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
6476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
6486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
649fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
650fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 mode = (req->mode & (~0777)) | 0664;
6516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (mknod(child_path, mode, req->rdev) < 0) {
6526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
653fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
6546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
655fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
656fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
658fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
659fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
6606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
6616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
6626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
6636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* actual_name;
6646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
6656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
6666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
6676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
6686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] MKDIR %s 0%o @ %llx (%s)\n", handler->token,
6696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
6706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
6716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
6726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
6736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1))) {
6746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
675fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
676fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 mode = (req->mode & (~0777)) | 0775;
6776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (mkdir(child_path, mode) < 0) {
6786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
679fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
6806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
681fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
682fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
684fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const char* name)
685fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
6866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
6876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
6886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
689fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
6916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
6926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
6936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] UNLINK %s @ %llx (%s)\n", handler->token,
6946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, hdr->nodeid, parent_node ? parent_node->name : "?");
6956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
696fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
6976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !find_file_within(parent_path, name,
6986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1)) {
6996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
7006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7016249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (unlink(child_path) < 0) {
7026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
7036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
705fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
706fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
708fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const char* name)
709fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
7106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* parent_node;
7116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char parent_path[PATH_MAX];
7126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char child_path[PATH_MAX];
713fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
7156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
7166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            parent_path, sizeof(parent_path));
7176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RMDIR %s @ %llx (%s)\n", handler->token,
7186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            name, hdr->nodeid, parent_node ? parent_node->name : "?");
7196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
720fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!parent_node || !find_file_within(parent_path, name,
7226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            child_path, sizeof(child_path), 1)) {
7236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
7246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (rmdir(child_path) < 0) {
7266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
7276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
729fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
730fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_rename(struct fuse* fuse, struct fuse_handler* handler,
732fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
7336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char* old_name, const char* new_name)
734fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
7356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* old_parent_node;
7366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* new_parent_node;
7376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* child_node;
7386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char old_parent_path[PATH_MAX];
7396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char new_parent_path[PATH_MAX];
7406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char old_child_path[PATH_MAX];
7416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char new_child_path[PATH_MAX];
7426249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    const char* new_actual_name;
743fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
744fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
7466249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
7476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_parent_path, sizeof(old_parent_path));
7486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
7496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            new_parent_path, sizeof(new_parent_path));
7506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RENAME %s->%s @ %llx (%s) -> %llx (%s)\n", handler->token,
7516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_name, new_name,
7526249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            hdr->nodeid, old_parent_node ? old_parent_node->name : "?",
7536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->newdir, new_parent_node ? new_parent_node->name : "?");
7546249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!old_parent_node || !new_parent_node) {
7556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
7566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto lookup_error;
7576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    child_node = lookup_child_by_name_locked(old_parent_node, old_name);
7596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!child_node || get_node_path_locked(child_node,
7606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            old_child_path, sizeof(old_child_path)) < 0) {
7616249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
7626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto lookup_error;
7636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
7646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    acquire_node_locked(child_node);
7656249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
7666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
7676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* Special case for renaming a file where destination is same path
7686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * differing only by case.  In this case we don't want to look for a case
7696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * insensitive match.  This allows commands like "mv foo FOO" to work as expected.
7706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     */
7716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int search = old_parent_node != new_parent_node
7726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            || strcasecmp(old_name, new_name);
7736249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!(new_actual_name = find_file_within(new_parent_path, new_name,
7746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            new_child_path, sizeof(new_child_path), search))) {
7756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -ENOENT;
7766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto io_error;
777fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
778fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RENAME %s->%s\n", handler->token, old_child_path, new_child_path);
7806249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = rename(old_child_path, new_child_path);
7816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (res < 0) {
7826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        res = -errno;
7836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        goto io_error;
784fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
785fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7866249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
7876249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = rename_node_locked(child_node, new_name, new_actual_name);
7886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!res) {
7896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        remove_node_from_parent_locked(child_node);
7906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        add_node_to_parent_locked(child_node, new_parent_node);
791fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
7926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    goto done;
793fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
7946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownio_error:
7956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
7966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Browndone:
7976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    release_node_locked(child_node);
7986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownlookup_error:
7996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
8006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return res;
801fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
802fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8036249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_open(struct fuse* fuse, struct fuse_handler* handler,
804fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_open_in* req)
805fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
8066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
8076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
808fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_open_out out;
809fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h;
81003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
8116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
8126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
8136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] OPEN 0%o @ %llx (%s)\n", handler->token,
8146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            req->flags, hdr->nodeid, node ? node->name : "?");
8156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
816fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
817fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
8186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
819fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
8206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    h = malloc(sizeof(*h));
8216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!h) {
8226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
8236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
8246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] OPEN %s\n", handler->token, path);
825fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    h->fd = open(path, req->flags);
826fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (h->fd < 0) {
827fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        free(h);
8286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
829fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
830fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.fh = ptr_to_id(h);
831fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.open_flags = 0;
832fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.padding = 0;
833fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
8346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
835fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
836fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_read(struct fuse* fuse, struct fuse_handler* handler,
838fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_read_in* req)
839fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
840fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
841fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u64 unique = hdr->unique;
842fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u32 size = req->size;
843fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    __u64 offset = req->offset;
8446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int res;
8456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
846fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* Don't access any other fields of hdr or req beyond this point, the read buffer
847fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * overlaps the request buffer and will clobber data in the request.  This
848fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown     * saves us 128KB per request handler thread at the cost of this scary comment. */
8496249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
8506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] READ %p(%d) %u@%llu\n", handler->token,
8516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            h, h->fd, size, offset);
852fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (size > sizeof(handler->read_buffer)) {
8536249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -EINVAL;
854fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
855fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    res = pread64(h->fd, handler->read_buffer, size, offset);
856fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (res < 0) {
8576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
858fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
859fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, unique, handler->read_buffer, res);
8606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
861fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
862fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8636249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_write(struct fuse* fuse, struct fuse_handler* handler,
864fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_write_in* req,
865fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const void* buffer)
866fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
867fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_write_out out;
868fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
869fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
8706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
8716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] WRITE %p(%d) %u@%llu\n", handler->token,
8726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            h, h->fd, req->size, req->offset);
873fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    res = pwrite64(h->fd, buffer, req->size, req->offset);
874fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (res < 0) {
8756249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
876fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
877fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.size = res;
878fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
8796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
880fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
881fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_statfs(struct fuse* fuse, struct fuse_handler* handler,
883fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr)
884fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
8856249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
886fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct statfs stat;
887fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_statfs_out out;
888fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
889fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
8906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
8916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] STATFS\n", handler->token);
8926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = get_node_path_locked(&fuse->root, path, sizeof(path));
8936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
8946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (res < 0) {
8956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
8966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
8976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (statfs(fuse->root.name, &stat) < 0) {
8986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
899fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
900fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    memset(&out, 0, sizeof(out));
901fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.blocks = stat.f_blocks;
902fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bfree = stat.f_bfree;
903fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bavail = stat.f_bavail;
904fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.files = stat.f_files;
905fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.ffree = stat.f_ffree;
906fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.bsize = stat.f_bsize;
907fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.namelen = stat.f_namelen;
908fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.st.frsize = stat.f_frsize;
909fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
9106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
911fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
912fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_release(struct fuse* fuse, struct fuse_handler* handler,
914fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_release_in* req)
915fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
916fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
9176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
9186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RELEASE %p(%d)\n", handler->token, h, h->fd);
919fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    close(h->fd);
920fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    free(h);
9216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
922fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
923fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
925fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
926fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
927fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int is_data_sync = req->fsync_flags & 1;
928fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct handle *h = id_to_ptr(req->fh);
929fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    int res;
9306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
9316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] FSYNC %p(%d) is_data_sync=%d\n", handler->token,
9326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            h, h->fd, is_data_sync);
933fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    res = is_data_sync ? fdatasync(h->fd) : fsync(h->fd);
934fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (res < 0) {
9356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
936fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
9376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
938fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
939fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_flush(struct fuse* fuse, struct fuse_handler* handler,
941fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr)
942fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
9436249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] FLUSH\n", handler->token);
9446249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
945fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
946fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
948fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_open_in* req)
949fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
9506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct node* node;
9516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    char path[PATH_MAX];
952fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_open_out out;
953fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirhandle *h;
954fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_lock(&fuse->lock);
9566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
9576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] OPENDIR @ %llx (%s)\n", handler->token,
9586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            hdr->nodeid, node ? node->name : "?");
9596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    pthread_mutex_unlock(&fuse->lock);
9606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
961fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!node) {
9626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOENT;
963fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
964fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    h = malloc(sizeof(*h));
965fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!h) {
9666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
967fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
9686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] OPENDIR %s\n", handler->token, path);
969fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    h->d = opendir(path);
9706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!h->d) {
971fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        free(h);
9726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -errno;
973fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
974fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.fh = ptr_to_id(h);
9753a8768804ce4b4797359d5df03ec8897fe43de90Ken Sumrall    out.open_flags = 0;
9763a8768804ce4b4797359d5df03ec8897fe43de90Ken Sumrall    out.padding = 0;
977fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
9786249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
979fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
980fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
9816249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_readdir(struct fuse* fuse, struct fuse_handler* handler,
982fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_read_in* req)
983fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
984fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    char buffer[8192];
985fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
986fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirent *de;
987fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirhandle *h = id_to_ptr(req->fh);
9886249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
9896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] READDIR %p\n", handler->token, h);
990fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (req->offset == 0) {
991fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        /* rewinddir() might have been called above us, so rewind here too */
9926249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        TRACE("[%d] calling rewinddir()\n", handler->token);
993fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        rewinddir(h->d);
994fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
995fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    de = readdir(h->d);
996fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    if (!de) {
9976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return 0;
998fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    }
999fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->ino = FUSE_UNKNOWN_INO;
1000fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
1001fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->off = req->offset + 1;
1002fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->type = de->d_type;
1003fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fde->namelen = strlen(de->d_name);
1004fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    memcpy(fde->name, de->d_name, fde->namelen + 1);
1005fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, fde,
10066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
10076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1008fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1009fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_releasedir(struct fuse* fuse, struct fuse_handler* handler,
1011fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_release_in* req)
1012fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1013fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct dirhandle *h = id_to_ptr(req->fh);
10146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
10156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] RELEASEDIR %p\n", handler->token, h);
1016fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    closedir(h->d);
1017fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    free(h);
10186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return 0;
1019fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1020fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_init(struct fuse* fuse, struct fuse_handler* handler,
1022fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header* hdr, const struct fuse_init_in* req)
1023fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
1024fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    struct fuse_init_out out;
1025fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    TRACE("[%d] INIT ver=%d.%d maxread=%d flags=%x\n",
10276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            handler->token, req->major, req->minor, req->max_readahead, req->flags);
1028fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.major = FUSE_KERNEL_VERSION;
1029fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.minor = FUSE_KERNEL_MINOR_VERSION;
1030fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_readahead = req->max_readahead;
1031fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
1032fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_background = 32;
1033fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.congestion_threshold = 32;
1034fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    out.max_write = MAX_WRITE;
1035fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
10366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NO_STATUS;
1037fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown}
1038fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown
10396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
1040fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown        const struct fuse_in_header *hdr, const void *data, size_t data_len)
1041fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{
104203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    switch (hdr->opcode) {
104303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_LOOKUP: { /* bytez[] -> entry_out */
1044847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char* name = data;
10456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_lookup(fuse, handler, hdr, name);
104603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1047847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
104803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_FORGET: {
1049847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_forget_in *req = data;
10506249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_forget(fuse, handler, hdr, req);
105103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1052847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
105303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_GETATTR: { /* getattr_in -> attr_out */
1054847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_getattr_in *req = data;
10556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_getattr(fuse, handler, hdr, req);
105603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1057847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
105803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_SETATTR: { /* setattr_in -> attr_out */
1059847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_setattr_in *req = data;
10606249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_setattr(fuse, handler, hdr, req);
106103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1062847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
106303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_READLINK:
106403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_SYMLINK:
106503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
1066847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_mknod_in *req = data;
1067847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char *name = ((const char*) data) + sizeof(*req);
10686249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_mknod(fuse, handler, hdr, req, name);
106903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1070847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
107103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
1072847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_mkdir_in *req = data;
1073847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char *name = ((const char*) data) + sizeof(*req);
10746249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_mkdir(fuse, handler, hdr, req, name);
107503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1076847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
107703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_UNLINK: { /* bytez[] -> */
1078847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char* name = data;
10796249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_unlink(fuse, handler, hdr, name);
108003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1081847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
108203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RMDIR: { /* bytez[] -> */
1083847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const char* name = data;
10846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_rmdir(fuse, handler, hdr, name);
108503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1086847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
108703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RENAME: { /* rename_in, oldname, newname ->  */
1088847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_rename_in *req = data;
10896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char *old_name = ((const char*) data) + sizeof(*req);
10906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        const char *new_name = old_name + strlen(old_name) + 1;
10916249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_rename(fuse, handler, hdr, req, old_name, new_name);
109203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1093847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1094fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown//    case FUSE_LINK:
109503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_OPEN: { /* open_in -> open_out */
1096847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_open_in *req = data;
10976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_open(fuse, handler, hdr, req);
109803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1099847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
110003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_READ: { /* read_in -> byte[] */
1101847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_read_in *req = data;
11026249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_read(fuse, handler, hdr, req);
110303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1104847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
110503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
1106847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_write_in *req = data;
1107847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const void* buffer = (const __u8*)data + sizeof(*req);
11086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_write(fuse, handler, hdr, req, buffer);
110903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1110847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
11114553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    case FUSE_STATFS: { /* getattr_in -> attr_out */
11126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_statfs(fuse, handler, hdr);
11134553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood    }
1114847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
111503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RELEASE: { /* release_in -> */
1116847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_release_in *req = data;
11176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_release(fuse, handler, hdr, req);
111803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1119847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
11206fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown    case FUSE_FSYNC: {
11216fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown        const struct fuse_fsync_in *req = data;
11226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_fsync(fuse, handler, hdr, req);
11236fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown    }
11246fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown
112503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_SETXATTR:
112603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_GETXATTR:
112703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_LISTXATTR:
112803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_REMOVEXATTR:
1129847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    case FUSE_FLUSH: {
11306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_flush(fuse, handler, hdr);
1131847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    }
1132847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
113303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_OPENDIR: { /* open_in -> open_out */
1134847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_open_in *req = data;
11356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_opendir(fuse, handler, hdr, req);
113603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1137847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
113803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_READDIR: {
1139847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_read_in *req = data;
11406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_readdir(fuse, handler, hdr, req);
114103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1142847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
114303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_RELEASEDIR: { /* release_in -> */
1144847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_release_in *req = data;
11456249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_releasedir(fuse, handler, hdr, req);
114603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1147847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
114803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland//    case FUSE_FSYNCDIR:
114903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    case FUSE_INIT: { /* init_in -> init_out */
1150847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        const struct fuse_init_in *req = data;
11516249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return handle_init(fuse, handler, hdr, req);
115203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1153847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
115403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    default: {
11556249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        TRACE("[%d] NOTIMPL op=%d uniq=%llx nid=%llx\n",
11566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                handler->token, hdr->opcode, hdr->unique, hdr->nodeid);
11576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOSYS;
115803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
1159847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown    }
116003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
116103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
11626249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void handle_fuse_requests(struct fuse_handler* handler)
116303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{
11646249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse* fuse = handler->fuse;
116503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    for (;;) {
11666249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        ssize_t len = read(fuse->fd,
11676249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                handler->request_buffer, sizeof(handler->request_buffer));
116803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        if (len < 0) {
11696249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (errno != EINTR) {
11706249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                ERROR("[%d] handle_fuse_requests: errno=%d\n", handler->token, errno);
11716249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
11726249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
117303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        }
1174847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
1175847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        if ((size_t)len < sizeof(struct fuse_in_header)) {
11766249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            ERROR("[%d] request too short: len=%zu\n", handler->token, (size_t)len);
11776249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
1178847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        }
1179847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
11807729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        const struct fuse_in_header *hdr = (void*)handler->request_buffer;
1181847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        if (hdr->len != (size_t)len) {
11826249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            ERROR("[%d] malformed header: len=%zu, hdr->len=%u\n",
11836249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                    handler->token, (size_t)len, hdr->len);
11846249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            continue;
1185847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        }
1186847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown
11877729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        const void *data = handler->request_buffer + sizeof(struct fuse_in_header);
1188847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown        size_t data_len = len - sizeof(struct fuse_in_header);
11896249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        __u64 unique = hdr->unique;
11906249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        int res = handle_fuse_request(fuse, handler, hdr, data, data_len);
11917729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown
11927729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown        /* We do not access the request again after this point because the underlying
11937729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown         * buffer storage may have been reused while processing the request. */
11946249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
11956249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (res != NO_STATUS) {
11966249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            if (res) {
11976249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown                TRACE("[%d] ERROR %d\n", handler->token, res);
11986249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            }
11996249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            fuse_status(fuse, unique, res);
12006249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
120103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
120203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
120303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
12046249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic void* start_handler(void* data)
12057729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown{
12066249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_handler* handler = data;
12076249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    handle_fuse_requests(handler);
12086249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    return NULL;
12096249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown}
12106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
12116249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownstatic int ignite_fuse(struct fuse* fuse, int num_threads)
12126249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown{
12136249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    struct fuse_handler* handlers;
12146249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int i;
12156249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
12166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    handlers = malloc(num_threads * sizeof(struct fuse_handler));
12176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (!handlers) {
12186249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        ERROR("cannot allocate storage for threads");
12196249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return -ENOMEM;
12206249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
12216249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
12226249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    for (i = 0; i < num_threads; i++) {
12236249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        handlers[i].fuse = fuse;
12246249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        handlers[i].token = i;
12256249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
12266249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
12276249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    for (i = 1; i < num_threads; i++) {
12286249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        pthread_t thread;
12296249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        int res = pthread_create(&thread, NULL, start_handler, &handlers[i]);
12306249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (res) {
12316249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            ERROR("failed to start thread #%d, error=%d", i, res);
12326249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            goto quit;
12336249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        }
12346249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
12356249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    handle_fuse_requests(&handlers[0]);
12366249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    ERROR("terminated prematurely");
12376249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown
12386249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    /* don't bother killing all of the other threads or freeing anything,
12396249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown     * should never get here anyhow */
12406249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brownquit:
12416249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    exit(1);
12427729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown}
12437729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown
12444f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwoodstatic int usage()
12454f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood{
1246e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    ERROR("usage: sdcard [-t<threads>] <source_path> <dest_path> <uid> <gid>\n"
12476249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            "    -t<threads>: specify number of threads to use, default -t%d\n"
12486249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            "\n", DEFAULT_NUM_THREADS);
12492656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    return 1;
12504f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood}
12514f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood
1252e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkeystatic int run(const char* source_path, const char* dest_path, uid_t uid, gid_t gid,
1253e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey        int num_threads) {
12542656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    int fd;
125503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    char opts[256];
12562656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    int res;
12572656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    struct fuse fuse;
12582656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12592656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    /* cleanup from previous instance, if necessary */
1260e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    umount2(dest_path, 2);
12612656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12622656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    fd = open("/dev/fuse", O_RDWR);
12632656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (fd < 0){
12642656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        ERROR("cannot open fuse device (error %d)\n", errno);
12652656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        return -1;
12662656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
12672656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12682656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    snprintf(opts, sizeof(opts),
12692656735f515a41cf131c87be5f40550b6538ce80Jeff Brown            "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
12702656735f515a41cf131c87be5f40550b6538ce80Jeff Brown            fd, uid, gid);
12712656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1272e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV, opts);
12732656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (res < 0) {
12742656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        ERROR("cannot mount fuse filesystem (error %d)\n", errno);
12752656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        goto error;
12762656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
12772656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12782656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    res = setgid(gid);
12792656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (res < 0) {
12802656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        ERROR("cannot setgid (error %d)\n", errno);
12812656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        goto error;
12822656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
12832656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12842656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    res = setuid(uid);
12852656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (res < 0) {
12862656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        ERROR("cannot setuid (error %d)\n", errno);
12872656735f515a41cf131c87be5f40550b6538ce80Jeff Brown        goto error;
12882656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    }
12892656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
1290e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    fuse_init(&fuse, fd, source_path);
12912656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12922656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    umask(0);
12936249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    res = ignite_fuse(&fuse, num_threads);
12942656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12952656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    /* we do not attempt to umount the file system here because we are no longer
12962656735f515a41cf131c87be5f40550b6538ce80Jeff Brown     * running as the root user */
12972656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
12982656735f515a41cf131c87be5f40550b6538ce80Jeff Brownerror:
12992656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    close(fd);
13002656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    return res;
13012656735f515a41cf131c87be5f40550b6538ce80Jeff Brown}
13022656735f515a41cf131c87be5f40550b6538ce80Jeff Brown
13032656735f515a41cf131c87be5f40550b6538ce80Jeff Brownint main(int argc, char **argv)
13042656735f515a41cf131c87be5f40550b6538ce80Jeff Brown{
130503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    int res;
1306e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    const char *source_path = NULL;
1307e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    const char *dest_path = NULL;
13082656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    uid_t uid = 0;
13092656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    gid_t gid = 0;
13106249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    int num_threads = DEFAULT_NUM_THREADS;
13114f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood    int i;
13122fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall    struct rlimit rlim;
13134f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood
13144f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood    for (i = 1; i < argc; i++) {
13154f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        char* arg = argv[i];
13166249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        if (!strncmp(arg, "-t", 2))
13176249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown            num_threads = strtoul(arg + 2, 0, 10);
1318e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey        else if (!source_path)
1319e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey            source_path = arg;
1320e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey        else if (!dest_path)
1321e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey            dest_path = arg;
1322e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru        else if (!uid) {
1323e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru            char* endptr = NULL;
1324e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru            errno = 0;
1325e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru            uid = strtoul(arg, &endptr, 10);
1326e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru            if (*endptr != '\0' || errno != 0) {
1327e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru                ERROR("Invalid uid");
1328e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru                return usage();
1329e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru            }
1330e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru        } else if (!gid) {
1331e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru            char* endptr = NULL;
1332e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru            errno = 0;
1333e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru            gid = strtoul(arg, &endptr, 10);
1334e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru            if (*endptr != '\0' || errno != 0) {
1335e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru                ERROR("Invalid gid");
1336e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru                return usage();
1337e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru            }
1338e92372ba9eaa04eb4ed7eb9417ee2be3515bd972Jean-Baptiste Queru        } else {
1339575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            ERROR("too many arguments\n");
1340575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood            return usage();
13414f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        }
134203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
134303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
1344e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    if (!source_path) {
1345e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey        ERROR("no source path specified\n");
1346e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey        return usage();
1347e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    }
1348e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    if (!dest_path) {
1349e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey        ERROR("no dest path specified\n");
13504f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        return usage();
13514f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood    }
13522656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    if (!uid || !gid) {
135303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland        ERROR("uid and gid must be nonzero\n");
13544f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood        return usage();
135503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland    }
13566249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    if (num_threads < 1) {
13576249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        ERROR("number of threads must be at least 1\n");
13586249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown        return usage();
13596249b9009f44f2127670eda4d5aa6d5fd3e26e02Jeff Brown    }
136003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland
13612fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall    rlim.rlim_cur = 8192;
13622fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall    rlim.rlim_max = 8192;
13632fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall    if (setrlimit(RLIMIT_NOFILE, &rlim)) {
13642fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall        ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno);
13652fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall    }
13662fd72cc22171cc23e67206db795fc5025d4f7ac6Ken Sumrall
1367e169bd05ec70f68c0db5e61c93b71e1746eb6c56Jeff Sharkey    res = run(source_path, dest_path, uid, gid, num_threads);
13682656735f515a41cf131c87be5f40550b6538ce80Jeff Brown    return res < 0 ? 1 : 0;
136903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}
1370