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