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