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