sdcard.c revision fc1e1a0ab48a88dc7e9a93f65da5e6458de622af
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> 3003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 31b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland#include <private/android_filesystem_config.h> 32b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland 3303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#include "fuse.h" 3403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 3503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland/* README 3603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * 3703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * What is this? 3803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * 3903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * sdcard is a program that uses FUSE to emulate FAT-on-sdcard style 4003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * directory permissions (all files are given fixed owner, group, and 4103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * permissions at creation, owner, group, and permissions are not 4203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * changeable, symlinks and hardlinks are not createable, etc. 4303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * 4403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * usage: sdcard <path> <uid> <gid> 4503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * 4603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * It must be run as root, but will change to uid/gid as soon as it 47cfa9f650266621fee963fe18084a39602aa8fcc6Jeff Sharkey * mounts a filesystem on /storage/sdcard. It will refuse to run if uid or 4803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * gid are zero. 4903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * 5003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * 5103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * Things I believe to be true: 5203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * 5303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK, 5403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * CREAT) must bump that node's refcount 5503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - don't forget that FORGET can forget multiple references (req->nlookup) 5603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * - if an op that returns a fuse_entry fails writing the reply to the 5703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * kernel, you must rollback the refcount to reflect the reference the 5803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * kernel did not actually acquire 5903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland * 6003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland */ 6103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 6203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define FUSE_TRACE 0 6303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 6403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#if FUSE_TRACE 6503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define TRACE(x...) fprintf(stderr,x) 6603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#else 6703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define TRACE(x...) do {} while (0) 6803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#endif 6903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 7003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define ERROR(x...) fprintf(stderr,x) 7103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 7203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland#define FUSE_UNKNOWN_INO 0xffffffff 7303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 74cfa9f650266621fee963fe18084a39602aa8fcc6Jeff Sharkey#define MOUNT_POINT "/storage/sdcard0" 754553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood 76847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Maximum number of bytes to write in one request. */ 77847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_WRITE (256 * 1024) 78847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 79847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Maximum number of bytes to read in one request. */ 80847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_READ (128 * 1024) 81847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 82847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown/* Largest possible request. 83847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown * The request size is bounded by the maximum size of a FUSE_WRITE request because it has 84847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown * the largest possible data payload. */ 85847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown#define MAX_REQUEST_SIZE (sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE) 86847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 8703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct handle { 8803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland struct node *node; 8903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland int fd; 9003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}; 9103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 9203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct dirhandle { 9303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland struct node *node; 9403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland DIR *d; 9503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}; 9603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 9703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct node { 9803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland __u64 nid; 9903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland __u64 gen; 10003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 10111ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham struct node *next; /* per-dir sibling list */ 10211ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham struct node *child; /* first contained file by this dir */ 10311ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham struct node *all; /* global node list */ 10411ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham struct node *parent; /* containing directory */ 10503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 10603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland __u32 refcount; 10703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland __u32 namelen; 10803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 10911ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham char *name; 110575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood /* If non-null, this is the real name of the file in the underlying storage. 111575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood * This may differ from the field "name" only by case. 112575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood * strlen(actual_name) will always equal strlen(name), so it is safe to use 113575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood * namelen for both fields. 114575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood */ 115575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood char *actual_name; 11603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}; 11703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 1187729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown/* Global data structure shared by all fuse handlers. */ 11903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct fuse { 12003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland __u64 next_generation; 12103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland __u64 next_node_id; 12203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 12303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland int fd; 12403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 12503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland struct node *all; 12603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 12703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland struct node root; 1287729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown char rootpath[PATH_MAX]; 12903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland}; 13003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 1317729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown/* Private data used by a single fuse handler. */ 1327729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brownstruct fuse_handler { 1337729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown /* To save memory, we never use the contents of the request buffer and the read 1347729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown * buffer at the same time. This allows us to share the underlying storage. */ 1357729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown union { 1367729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown __u8 request_buffer[MAX_REQUEST_SIZE]; 1377729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown __u8 read_buffer[MAX_READ]; 1387729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown }; 1397729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown}; 14003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 141575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood#define NO_CASE_SENSITIVE_MATCH 0 142575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood#define CASE_SENSITIVE_MATCH 1 143b94d320b1e7e2a3493147f6763cd2825b111a4d8Mike Lockwood 144f43219e0b1022b257499289ceb951f6a1a44bf9cPaul Eastham/* 145f43219e0b1022b257499289ceb951f6a1a44bf9cPaul Eastham * Get the real-life absolute path to a node. 146f43219e0b1022b257499289ceb951f6a1a44bf9cPaul Eastham * node: start at this node 147f43219e0b1022b257499289ceb951f6a1a44bf9cPaul Eastham * buf: storage for returned string 148f43219e0b1022b257499289ceb951f6a1a44bf9cPaul Eastham * name: append this string to path if set 149f43219e0b1022b257499289ceb951f6a1a44bf9cPaul Eastham */ 150575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwoodchar *do_node_get_path(struct node *node, char *buf, const char *name, int match_case_insensitive) 15103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 152575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood struct node *in_node = node; 153575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood const char *in_name = name; 1547729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown char *out = buf + PATH_MAX - 1; 15503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland int len; 15603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland out[0] = 0; 15703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 15803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland if (name) { 15903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland len = strlen(name); 16003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland goto start; 16103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 16203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 16303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland while (node) { 164575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood name = (node->actual_name ? node->actual_name : node->name); 16503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland len = node->namelen; 16603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland node = node->parent; 16703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland start: 16803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland if ((len + 1) > (out - buf)) 16903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return 0; 17003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland out -= len; 17103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland memcpy(out, name, len); 172575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood /* avoid double slash at beginning of path */ 173575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood if (out[0] != '/') { 174575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood out --; 175575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood out[0] = '/'; 176575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood } 17703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 17803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 179575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood /* If we are searching for a file within node (rather than computing node's path) 180575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood * and fail, then we need to look for a case insensitive match. 181575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood */ 182575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood if (in_name && match_case_insensitive && access(out, F_OK) != 0) { 1837729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown char *path, buffer[PATH_MAX]; 184575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood DIR* dir; 185575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood struct dirent* entry; 186575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood path = do_node_get_path(in_node, buffer, NULL, NO_CASE_SENSITIVE_MATCH); 187575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood dir = opendir(path); 188575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood if (!dir) { 189575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood ERROR("opendir %s failed: %s", path, strerror(errno)); 190575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood return out; 191575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood } 192575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood 193575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood while ((entry = readdir(dir))) { 194575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood if (!strcasecmp(entry->d_name, in_name)) { 195575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood /* we have a match - replace the name */ 196575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood len = strlen(in_name); 1977729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown memcpy(buf + PATH_MAX - len - 1, entry->d_name, len); 198575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood break; 199575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood } 200575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood } 201575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood closedir(dir); 202575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood } 203575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood 204575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood return out; 205575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood} 206575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood 207575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwoodchar *node_get_path(struct node *node, char *buf, const char *name) 208575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood{ 209575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood /* We look for case insensitive matches by default */ 210575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood return do_node_get_path(node, buf, name, CASE_SENSITIVE_MATCH); 21103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 21203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 21303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandvoid attr_from_stat(struct fuse_attr *attr, struct stat *s) 21403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 21503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland attr->ino = s->st_ino; 21603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland attr->size = s->st_size; 21703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland attr->blocks = s->st_blocks; 2184553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood attr->atime = s->st_atime; 2194553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood attr->mtime = s->st_mtime; 2204553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood attr->ctime = s->st_ctime; 2214553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood attr->atimensec = s->st_atime_nsec; 2224553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood attr->mtimensec = s->st_mtime_nsec; 2234553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood attr->ctimensec = s->st_ctime_nsec; 22403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland attr->mode = s->st_mode; 22503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland attr->nlink = s->st_nlink; 22603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 227b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland /* force permissions to something reasonable: 228b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland * world readable 229b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland * writable by the sdcard group 230b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland */ 231b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland if (attr->mode & 0100) { 232b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland attr->mode = (attr->mode & (~0777)) | 0775; 233b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland } else { 234b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland attr->mode = (attr->mode & (~0777)) | 0664; 235b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland } 236b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland 237b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland /* all files owned by root.sdcard */ 238b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland attr->uid = 0; 239b14a2c6e34b197870433386fb809d34b58b30fc0Brian Swetland attr->gid = AID_SDCARD_RW; 24003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 24103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 24203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandint node_get_attr(struct node *node, struct fuse_attr *attr) 24303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 24403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland int res; 24503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland struct stat s; 2467729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown char *path, buffer[PATH_MAX]; 24703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 24803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland path = node_get_path(node, buffer, 0); 24903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland res = lstat(path, &s); 25003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland if (res < 0) { 25103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland ERROR("lstat('%s') errno %d\n", path, errno); 25203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return -1; 25303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 25403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 25503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland attr_from_stat(attr, &s); 25603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland attr->ino = node->nid; 25703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 25803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return 0; 25903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 26003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 26111ccdb3be67b22f677065715ace68aabf371acc7Paul Easthamstatic void add_node_to_parent(struct node *node, struct node *parent) { 26211ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham node->parent = parent; 26311ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham node->next = parent->child; 26411ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham parent->child = node; 26577085c570e7db2ea4a52e3a0fec5100687c31b46Paul Eastham parent->refcount++; 26611ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham} 26711ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham 268575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood/* Check to see if our parent directory already has a file with a name 269575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood * that differs only by case. If we find one, store it in the actual_name 270575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood * field so node_get_path will map it to this file in the underlying storage. 271575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood */ 272575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwoodstatic void node_find_actual_name(struct node *node) 273575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood{ 2747729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown char *path, buffer[PATH_MAX]; 275575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood const char *node_name = node->name; 276575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood DIR* dir; 277575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood struct dirent* entry; 278575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood 279575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood if (!node->parent) return; 280575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood 281575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood path = node_get_path(node->parent, buffer, 0); 282575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood dir = opendir(path); 283575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood if (!dir) { 284575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood ERROR("opendir %s failed: %s", path, strerror(errno)); 285575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood return; 286575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood } 287575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood 288575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood while ((entry = readdir(dir))) { 289575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood const char *test_name = entry->d_name; 290575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood if (strcmp(test_name, node_name) && !strcasecmp(test_name, node_name)) { 291575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood /* we have a match - differs but only by case */ 292575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood node->actual_name = strdup(test_name); 293575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood if (!node->actual_name) { 294575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood ERROR("strdup failed - out of memory\n"); 295575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood exit(1); 296575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood } 297575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood break; 298575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood } 299575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood } 300575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood closedir(dir); 301575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood} 302575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood 30303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct node *node_create(struct node *parent, const char *name, __u64 nid, __u64 gen) 30403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 30503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland struct node *node; 30603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland int namelen = strlen(name); 30703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 30811ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham node = calloc(1, sizeof(struct node)); 30903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland if (node == 0) { 31003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return 0; 31103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 31211ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham node->name = malloc(namelen + 1); 31311ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham if (node->name == 0) { 31411ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham free(node); 31511ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham return 0; 31611ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham } 31703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 31803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland node->nid = nid; 31903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland node->gen = gen; 32011ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham add_node_to_parent(node, parent); 32103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland memcpy(node->name, name, namelen + 1); 32203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland node->namelen = namelen; 323575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood node_find_actual_name(node); 32403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return node; 32503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 32603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 32711ccdb3be67b22f677065715ace68aabf371acc7Paul Easthamstatic char *rename_node(struct node *node, const char *name) 32811ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham{ 32911ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham node->namelen = strlen(name); 33011ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham char *newname = realloc(node->name, node->namelen + 1); 33111ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham if (newname == 0) 33211ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham return 0; 33311ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham node->name = newname; 33411ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham memcpy(node->name, name, node->namelen + 1); 335575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood node_find_actual_name(node); 33611ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham return node->name; 33711ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham} 33811ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham 33903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandvoid fuse_init(struct fuse *fuse, int fd, const char *path) 34003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 34103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland fuse->fd = fd; 34203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland fuse->next_node_id = 2; 34303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland fuse->next_generation = 0; 34403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 34503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland fuse->all = &fuse->root; 34603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 3478349cce829388503fae67d454aff6a544ccd36aaTerry Heo (Woncheol) memset(&fuse->root, 0, sizeof(fuse->root)); 34803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland fuse->root.nid = FUSE_ROOT_ID; /* 1 */ 34903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland fuse->root.refcount = 2; 35011ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham rename_node(&fuse->root, path); 35103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 35203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 35303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstatic inline void *id_to_ptr(__u64 nid) 35403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 3552656735f515a41cf131c87be5f40550b6538ce80Jeff Brown return (void *) (uintptr_t) nid; 35603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 35703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 35803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstatic inline __u64 ptr_to_id(void *ptr) 35903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 3602656735f515a41cf131c87be5f40550b6538ce80Jeff Brown return (__u64) (uintptr_t) ptr; 36103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 36203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 36303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 36403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct node *lookup_by_inode(struct fuse *fuse, __u64 nid) 36503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 366fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!nid) { 367fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return NULL; 368fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } else if (nid == FUSE_ROOT_ID) { 36903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return &fuse->root; 37003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } else { 37103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return id_to_ptr(nid); 37203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 37303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 37403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 37503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct node *lookup_child_by_name(struct node *node, const char *name) 37603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 37703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland for (node = node->child; node; node = node->next) { 37803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland if (!strcmp(name, node->name)) { 37903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return node; 38003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 38103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 38203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return 0; 38303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 38403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 38503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct node *lookup_child_by_inode(struct node *node, __u64 nid) 38603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 38703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland for (node = node->child; node; node = node->next) { 38803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland if (node->nid == nid) { 38903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return node; 39003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 39103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 39203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return 0; 39303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 39403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 39577085c570e7db2ea4a52e3a0fec5100687c31b46Paul Easthamstatic void dec_refcount(struct node *node) { 39677085c570e7db2ea4a52e3a0fec5100687c31b46Paul Eastham if (node->refcount > 0) { 39777085c570e7db2ea4a52e3a0fec5100687c31b46Paul Eastham node->refcount--; 39877085c570e7db2ea4a52e3a0fec5100687c31b46Paul Eastham TRACE("dec_refcount %p(%s) -> %d\n", node, node->name, node->refcount); 39977085c570e7db2ea4a52e3a0fec5100687c31b46Paul Eastham } else { 40077085c570e7db2ea4a52e3a0fec5100687c31b46Paul Eastham ERROR("Zero refcnt %p\n", node); 40177085c570e7db2ea4a52e3a0fec5100687c31b46Paul Eastham } 40277085c570e7db2ea4a52e3a0fec5100687c31b46Paul Eastham } 40377085c570e7db2ea4a52e3a0fec5100687c31b46Paul Eastham 40411ccdb3be67b22f677065715ace68aabf371acc7Paul Easthamstatic struct node *remove_child(struct node *parent, __u64 nid) 40511ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham{ 40611ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham struct node *prev = 0; 40711ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham struct node *node; 40811ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham 40911ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham for (node = parent->child; node; node = node->next) { 41011ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham if (node->nid == nid) { 41111ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham if (prev) { 41211ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham prev->next = node->next; 41311ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham } else { 41411ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham parent->child = node->next; 41511ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham } 41611ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham node->next = 0; 41711ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham node->parent = 0; 41877085c570e7db2ea4a52e3a0fec5100687c31b46Paul Eastham dec_refcount(parent); 41911ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham return node; 42011ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham } 42111ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham prev = node; 42211ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham } 42311ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham return 0; 42411ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham} 42511ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham 42603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandstruct node *node_lookup(struct fuse *fuse, struct node *parent, const char *name, 42703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland struct fuse_attr *attr) 42803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 42903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland int res; 43003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland struct stat s; 4317729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown char *path, buffer[PATH_MAX]; 43203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland struct node *node; 43303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 43403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland path = node_get_path(parent, buffer, name); 43503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland /* XXX error? */ 43603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 43703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland res = lstat(path, &s); 43803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland if (res < 0) 43903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return 0; 44003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 44103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland node = lookup_child_by_name(parent, name); 44203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland if (!node) { 44303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland node = node_create(parent, name, fuse->next_node_id++, fuse->next_generation++); 44403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland if (!node) 44503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return 0; 44603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland node->nid = ptr_to_id(node); 44703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland node->all = fuse->all; 44803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland fuse->all = node; 44903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 45003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 45103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland attr_from_stat(attr, &s); 45203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland attr->ino = node->nid; 45303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 45403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return node; 45503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 45603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 45703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandvoid node_release(struct node *node) 45803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 45903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount); 46077085c570e7db2ea4a52e3a0fec5100687c31b46Paul Eastham dec_refcount(node); 46103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland if (node->refcount == 0) { 46203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland if (node->parent->child == node) { 46303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland node->parent->child = node->parent->child->next; 46403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } else { 46503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland struct node *node2; 46603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 46703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland node2 = node->parent->child; 46803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland while (node2->next != node) 46903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland node2 = node2->next; 47003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland node2->next = node->next; 47103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 47203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 47303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland TRACE("DESTROY %p (%s)\n", node, node->name); 47403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 47503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland node_release(node->parent); 47603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 47703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland node->parent = 0; 47803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland node->next = 0; 47903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 48003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland /* TODO: remove debugging - poison memory */ 48111ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham memset(node->name, 0xef, node->namelen); 48211ccdb3be67b22f677065715ace68aabf371acc7Paul Eastham free(node->name); 483575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood free(node->actual_name); 48477085c570e7db2ea4a52e3a0fec5100687c31b46Paul Eastham memset(node, 0xfc, sizeof(*node)); 48503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland free(node); 48603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 48703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 48803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 48903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandvoid fuse_status(struct fuse *fuse, __u64 unique, int err) 49003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 49103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland struct fuse_out_header hdr; 49203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland hdr.len = sizeof(hdr); 49303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland hdr.error = err; 49403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland hdr.unique = unique; 49503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland if (err) { 49603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland// ERROR("*** %d ***\n", err); 49703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 49803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland write(fuse->fd, &hdr, sizeof(hdr)); 49903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 50003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 50103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetlandvoid fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len) 50203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 50303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland struct fuse_out_header hdr; 50403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland struct iovec vec[2]; 50503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland int res; 50603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 50703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland hdr.len = len + sizeof(hdr); 50803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland hdr.error = 0; 50903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland hdr.unique = unique; 51003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 51103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland vec[0].iov_base = &hdr; 51203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland vec[0].iov_len = sizeof(hdr); 51303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland vec[1].iov_base = data; 51403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland vec[1].iov_len = len; 51503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 51603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland res = writev(fuse->fd, vec, 2); 51703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland if (res < 0) { 51803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland ERROR("*** REPLY FAILED *** %d\n", errno); 51903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 52003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 52103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 522fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void lookup_entry(struct fuse* fuse, struct fuse_handler* handler, 523fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown __u64 unique, struct node* parent_node, const char* name) 52403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 52503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland struct fuse_entry_out out; 526fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct node* node; 52703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 528fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown memset(&out, 0, sizeof(out)); 529fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown node = node_lookup(fuse, parent_node, name, &out.attr); 53003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland if (!node) { 53103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland fuse_status(fuse, unique, -ENOENT); 53203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 53303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 534fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 53503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland node->refcount++; 536fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount); 53703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland out.nodeid = node->nid; 53803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland out.generation = node->gen; 53903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland out.entry_valid = 10; 54003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland out.attr_valid = 10; 541fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 54203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland fuse_reply(fuse, unique, &out, sizeof(out)); 54303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 54403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 545fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_lookup(struct fuse* fuse, struct fuse_handler* handler, 546fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header *hdr, const char* name) 54703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 548fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct node* node = lookup_by_inode(fuse, hdr->nodeid); 549fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 550fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("LOOKUP %s @ %llx (%s)\n", name, hdr->nodeid, node ? node->name : "?"); 551fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!node) { 552fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOENT); 553fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 554fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 555fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 556fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown lookup_entry(fuse, handler, hdr->unique, node, name); 557fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 558fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 559fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_forget(struct fuse* fuse, struct fuse_handler* handler, 560fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header *hdr, const struct fuse_forget_in *req) 561fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 562fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct node* node = lookup_by_inode(fuse, hdr->nodeid); 563fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown __u64 n = req->nlookup; 564fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 565fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("FORGET #%lld @ %llx (%s)\n", n, hdr->nodeid, node ? node->name : "?"); 566fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!node) { 567fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOENT); 568fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 569fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 570fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 571fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown while (n--) { 572fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown node_release(node); 573fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 574fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown /* no reply */ 575fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 576fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 577fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_getaddr(struct fuse* fuse, struct fuse_handler* handler, 578fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header *hdr, const struct fuse_getattr_in *req) 579fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 580fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct fuse_attr_out out; 581fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct node* node = lookup_by_inode(fuse, hdr->nodeid); 582fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 583fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("GETATTR flags=%x fh=%llx @ %llx (%s)\n", req->getattr_flags, req->fh, 584fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown hdr->nodeid, node ? node->name : "?"); 585fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!node) { 586fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOENT); 587fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 588fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 58903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 590fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown memset(&out, 0, sizeof(out)); 591fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown node_get_attr(node, &out.attr); 592fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.attr_valid = 10; 593fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 594fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_reply(fuse, hdr->unique, &out, sizeof(out)); 595fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 596fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 597fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_setattr(struct fuse* fuse, struct fuse_handler* handler, 598fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header *hdr, const struct fuse_setattr_in *req) 599fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 600fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct fuse_attr_out out; 601fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown char *path, buffer[PATH_MAX]; 602fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown int res = 0; 603fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct timespec times[2]; 604fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct node* node = lookup_by_inode(fuse, hdr->nodeid); 605fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 606fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("SETATTR fh=%llx valid=%x @ %llx (%s)\n", req->fh, req->valid, 607fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown hdr->nodeid, node ? node->name : "?"); 608fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!node) { 609fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOENT); 610fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 611fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 612fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 613fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown /* XXX: incomplete implementation on purpose. chmod/chown 614fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown * should NEVER be implemented.*/ 615fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 616fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown path = node_get_path(node, buffer, 0); 617fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (req->valid & FATTR_SIZE) 618fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown res = truncate(path, req->size); 619fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (res < 0) { 620fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -errno); 621fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 622fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 623fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 624fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown /* Handle changing atime and mtime. If FATTR_ATIME_and FATTR_ATIME_NOW 625fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown * are both set, then set it to the current time. Else, set it to the 626fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown * time specified in the request. Same goes for mtime. Use utimensat(2) 627fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown * as it allows ATIME and MTIME to be changed independently, and has 628fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown * nanosecond resolution which fuse also has. 629fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown */ 630fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (req->valid & (FATTR_ATIME | FATTR_MTIME)) { 631fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown times[0].tv_nsec = UTIME_OMIT; 632fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown times[1].tv_nsec = UTIME_OMIT; 633fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (req->valid & FATTR_ATIME) { 634fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (req->valid & FATTR_ATIME_NOW) { 635fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown times[0].tv_nsec = UTIME_NOW; 636fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } else { 637fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown times[0].tv_sec = req->atime; 638fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown times[0].tv_nsec = req->atimensec; 639fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 640fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 641fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (req->valid & FATTR_MTIME) { 642fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (req->valid & FATTR_MTIME_NOW) { 643fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown times[1].tv_nsec = UTIME_NOW; 644fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } else { 645fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown times[1].tv_sec = req->mtime; 646fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown times[1].tv_nsec = req->mtimensec; 647fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 648fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 649fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("Calling utimensat on %s with atime %ld, mtime=%ld\n", path, times[0].tv_sec, times[1].tv_sec); 650fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown res = utimensat(-1, path, times, 0); 651fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (res < 0) { 652fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -errno); 65303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 65403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 655fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 656fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 657fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown memset(&out, 0, sizeof(out)); 658fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown node_get_attr(node, &out.attr); 659fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.attr_valid = 10; 660fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_reply(fuse, hdr->unique, &out, sizeof(out)); 661fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 662fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 663fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_mknod(struct fuse* fuse, struct fuse_handler* handler, 664fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name) 665fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 666fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown char *path, buffer[PATH_MAX]; 667fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown int res; 668fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct node* node = lookup_by_inode(fuse, hdr->nodeid); 669fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 670fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("MKNOD %s @ %llx (%s)\n", name, hdr->nodeid, node ? node->name : "?"); 671fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!node) { 672fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOENT); 673fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 674fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 675fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 676fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown path = node_get_path(node, buffer, name); 677fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 678fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown __u32 mode = (req->mode & (~0777)) | 0664; 679fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown res = mknod(path, mode, req->rdev); /* XXX perm?*/ 680fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (res < 0) { 681fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -errno); 682fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 683fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 684fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 685fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown lookup_entry(fuse, handler, hdr->unique, node, name); 686fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 687fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 688fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_mkdir(struct fuse* fuse, struct fuse_handler* handler, 689fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name) 690fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 691fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct fuse_entry_out out; 692fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown char *path, buffer[PATH_MAX]; 693fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown int res; 694fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct node* node = lookup_by_inode(fuse, hdr->nodeid); 695fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 696fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("MKDIR %s 0%o @ %llx (%s)\n", name, req->mode, hdr->nodeid, node ? node->name : "?"); 697fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!node) { 698fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOENT); 699fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 700fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 701fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 702fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown path = node_get_path(node, buffer, name); 703fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 704fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown __u32 mode = (req->mode & (~0777)) | 0775; 705fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown res = mkdir(path, mode); 706fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (res < 0) { 707fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -errno); 708fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 709fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 710fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 711fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown lookup_entry(fuse, handler, hdr->unique, node, name); 712fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 713fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 714fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_unlink(struct fuse* fuse, struct fuse_handler* handler, 715fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header* hdr, const char* name) 716fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 717fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown char *path, buffer[PATH_MAX]; 718fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown int res; 719fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct node* node = lookup_by_inode(fuse, hdr->nodeid); 720fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 721fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("UNLINK %s @ %llx (%s)\n", name, hdr->nodeid, node ? node->name : "?"); 722fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!node) { 723fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOENT); 724fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 725fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 726fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 727fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown path = node_get_path(node, buffer, name); 728fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown res = unlink(path); 729fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, res ? -errno : 0); 730fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 731fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 732fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_rmdir(struct fuse* fuse, struct fuse_handler* handler, 733fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header* hdr, const char* name) 734fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 735fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown char *path, buffer[PATH_MAX]; 736fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown int res; 737fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct node* node = lookup_by_inode(fuse, hdr->nodeid); 738fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 739fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("RMDIR %s @ %llx (%s)\n", name, hdr->nodeid, node ? node->name : "?"); 740fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!node) { 741fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOENT); 742fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 743fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 744fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 745fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown path = node_get_path(node, buffer, name); 746fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown res = rmdir(path); 747fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, res ? -errno : 0); 748fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 749fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 750fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_rename(struct fuse* fuse, struct fuse_handler* handler, 751fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header* hdr, const struct fuse_rename_in* req, 752fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const char* oldname, const char* newname) 753fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 754fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown char *oldpath, oldbuffer[PATH_MAX]; 755fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown char *newpath, newbuffer[PATH_MAX]; 756fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct node *target; 757fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct node *newparent; 758fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown int res; 759fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct node* node = lookup_by_inode(fuse, hdr->nodeid); 760fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 761fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("RENAME %s->%s @ %llx (%s)\n", oldname, newname, hdr->nodeid, node ? node->name : "?"); 762fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!node) { 763fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOENT); 764fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 765fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 766fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 767fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown target = lookup_child_by_name(node, oldname); 768fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!target) { 769fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOENT); 770fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 771fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 772fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown oldpath = node_get_path(node, oldbuffer, oldname); 773fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 774fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown newparent = lookup_by_inode(fuse, req->newdir); 775fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!newparent) { 776fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOENT); 777fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 778fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 779fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (newparent == node) { 780fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown /* Special case for renaming a file where destination 781fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown * is same path differing only by case. 782fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown * In this case we don't want to look for a case insensitive match. 783fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown * This allows commands like "mv foo FOO" to work as expected. 784fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown */ 785fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown newpath = do_node_get_path(newparent, newbuffer, newname, NO_CASE_SENSITIVE_MATCH); 78603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } else { 787fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown newpath = node_get_path(newparent, newbuffer, newname); 788fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 789fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 790fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!remove_child(node, target->nid)) { 791fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown ERROR("RENAME remove_child not found"); 792fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOENT); 793fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 79403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 795fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!rename_node(target, newname)) { 796fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOMEM); 797fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 798fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 799fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown add_node_to_parent(target, newparent); 800fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 801fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown res = rename(oldpath, newpath); 802fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("RENAME result %d\n", res); 803fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 804fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, res ? -errno : 0); 805fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 806fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 807fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_open(struct fuse* fuse, struct fuse_handler* handler, 808fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header* hdr, const struct fuse_open_in* req) 809fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 810fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct fuse_open_out out; 811fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown char *path, buffer[PATH_MAX]; 812fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct handle *h; 813fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct node* node = lookup_by_inode(fuse, hdr->nodeid); 81403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 815fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown h = malloc(sizeof(*h)); 816fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!h) { 817fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOMEM); 818fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 819fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 820fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 821fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("OPEN 0%o fh=%p @ %llx (%s)\n", req->flags, h, hdr->nodeid, node ? node->name : "?"); 822fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!node) { 823fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOENT); 824fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 825fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 826fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 827fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown path = node_get_path(node, buffer, 0); 828fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown h->fd = open(path, req->flags); 829fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (h->fd < 0) { 830fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown ERROR("ERROR\n"); 831fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -errno); 832fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown free(h); 833fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 834fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 835fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.fh = ptr_to_id(h); 836fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.open_flags = 0; 837fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.padding = 0; 838fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_reply(fuse, hdr->unique, &out, sizeof(out)); 839fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 840fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 841fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_read(struct fuse* fuse, struct fuse_handler* handler, 842fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header* hdr, const struct fuse_read_in* req) 843fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 844fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct handle *h = id_to_ptr(req->fh); 845fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown __u64 unique = hdr->unique; 846fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown __u32 size = req->size; 847fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown __u64 offset = req->offset; 848fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown /* Don't access any other fields of hdr or req beyond this point, the read buffer 849fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown * overlaps the request buffer and will clobber data in the request. This 850fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown * saves us 128KB per request handler thread at the cost of this scary comment. */ 851fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown int res; 852fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("READ %p(%d) %u@%llu\n", h, h->fd, size, offset); 853fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (size > sizeof(handler->read_buffer)) { 854fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, unique, -EINVAL); 855fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 856fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 857fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown res = pread64(h->fd, handler->read_buffer, size, offset); 858fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (res < 0) { 859fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, unique, -errno); 860fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 861fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 862fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_reply(fuse, unique, handler->read_buffer, res); 863fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 864fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 865fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_write(struct fuse* fuse, struct fuse_handler* handler, 866fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header* hdr, const struct fuse_write_in* req, 867fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const void* buffer) 868fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 869fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct fuse_write_out out; 870fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct handle *h = id_to_ptr(req->fh); 871fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown int res; 872fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("WRITE %p(%d) %u@%llu\n", h, h->fd, req->size, req->offset); 873fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown res = pwrite64(h->fd, buffer, req->size, req->offset); 874fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (res < 0) { 875fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -errno); 876fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 877fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 878fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.size = res; 879fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_reply(fuse, hdr->unique, &out, sizeof(out)); 880fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 881fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 882fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_statfs(struct fuse* fuse, struct fuse_handler* handler, 883fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header* hdr) 884fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 885fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct statfs stat; 886fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct fuse_statfs_out out; 887fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown int res; 888fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 889fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("STATFS\n"); 890fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 891fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (statfs(fuse->root.name, &stat)) { 892fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -errno); 893fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 894fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 895fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 896fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown memset(&out, 0, sizeof(out)); 897fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.st.blocks = stat.f_blocks; 898fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.st.bfree = stat.f_bfree; 899fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.st.bavail = stat.f_bavail; 900fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.st.files = stat.f_files; 901fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.st.ffree = stat.f_ffree; 902fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.st.bsize = stat.f_bsize; 903fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.st.namelen = stat.f_namelen; 904fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.st.frsize = stat.f_frsize; 905fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_reply(fuse, hdr->unique, &out, sizeof(out)); 906fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 907fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 908fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_release(struct fuse* fuse, struct fuse_handler* handler, 909fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header* hdr, const struct fuse_release_in* req) 910fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 911fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct handle *h = id_to_ptr(req->fh); 912fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("RELEASE %p(%d)\n", h, h->fd); 913fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown close(h->fd); 914fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown free(h); 915fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, 0); 916fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 917fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 918fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_fsync(struct fuse* fuse, struct fuse_handler* handler, 919fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header* hdr, const struct fuse_fsync_in* req) 920fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 921fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown int is_data_sync = req->fsync_flags & 1; 922fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct handle *h = id_to_ptr(req->fh); 923fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown int res; 924fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("FSYNC %p(%d) is_data_sync=%d\n", h, h->fd, is_data_sync); 925fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown res = is_data_sync ? fdatasync(h->fd) : fsync(h->fd); 926fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (res < 0) { 927fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -errno); 928fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 929fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 930fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, 0); 931fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 932fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 933fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_flush(struct fuse* fuse, struct fuse_handler* handler, 934fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header* hdr) 935fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 936fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, 0); 937fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 938fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 939fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_opendir(struct fuse* fuse, struct fuse_handler* handler, 940fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header* hdr, const struct fuse_open_in* req) 941fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 942fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct fuse_open_out out; 943fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown char *path, buffer[PATH_MAX]; 944fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct dirhandle *h; 945fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct node* node = lookup_by_inode(fuse, hdr->nodeid); 946fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 947fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("OPENDIR @ %llx (%s)\n", hdr->nodeid, node ? node->name : "?"); 948fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!node) { 949fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOENT); 950fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 951fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 952fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 953fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown h = malloc(sizeof(*h)); 954fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!h) { 955fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -ENOMEM); 956fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 957fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 958fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 959fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown path = node_get_path(node, buffer, 0); 960fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown h->d = opendir(path); 961fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (h->d == 0) { 962fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown ERROR("ERROR\n"); 963fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, -errno); 964fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown free(h); 965fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 966fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 967fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.fh = ptr_to_id(h); 968fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_reply(fuse, hdr->unique, &out, sizeof(out)); 969fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 970fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 971fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_readdir(struct fuse* fuse, struct fuse_handler* handler, 972fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header* hdr, const struct fuse_read_in* req) 973fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 974fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown char buffer[8192]; 975fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct fuse_dirent *fde = (struct fuse_dirent*) buffer; 976fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct dirent *de; 977fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct dirhandle *h = id_to_ptr(req->fh); 978fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("READDIR %p\n", h); 979fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (req->offset == 0) { 980fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown /* rewinddir() might have been called above us, so rewind here too */ 981fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("calling rewinddir()\n"); 982fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown rewinddir(h->d); 983fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 984fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown de = readdir(h->d); 985fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown if (!de) { 986fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, 0); 987fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown return; 988fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown } 989fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fde->ino = FUSE_UNKNOWN_INO; 990fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown /* increment the offset so we can detect when rewinddir() seeks back to the beginning */ 991fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fde->off = req->offset + 1; 992fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fde->type = de->d_type; 993fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fde->namelen = strlen(de->d_name); 994fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown memcpy(fde->name, de->d_name, fde->namelen + 1); 995fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_reply(fuse, hdr->unique, fde, 996fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen)); 997fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 998fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 999fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_releasedir(struct fuse* fuse, struct fuse_handler* handler, 1000fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header* hdr, const struct fuse_release_in* req) 1001fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 1002fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct dirhandle *h = id_to_ptr(req->fh); 1003fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("RELEASEDIR %p\n",h); 1004fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown closedir(h->d); 1005fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown free(h); 1006fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_status(fuse, hdr->unique, 0); 1007fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 1008fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 1009fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_init(struct fuse* fuse, struct fuse_handler* handler, 1010fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header* hdr, const struct fuse_init_in* req) 1011fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 1012fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown struct fuse_init_out out; 1013fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 1014fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown TRACE("INIT ver=%d.%d maxread=%d flags=%x\n", 1015fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown req->major, req->minor, req->max_readahead, req->flags); 1016fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 1017fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.major = FUSE_KERNEL_VERSION; 1018fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.minor = FUSE_KERNEL_MINOR_VERSION; 1019fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.max_readahead = req->max_readahead; 1020fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES; 1021fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.max_background = 32; 1022fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.congestion_threshold = 32; 1023fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown out.max_write = MAX_WRITE; 1024fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 1025fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown fuse_reply(fuse, hdr->unique, &out, sizeof(out)); 1026fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown} 1027fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown 1028fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler, 1029fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown const struct fuse_in_header *hdr, const void *data, size_t data_len) 1030fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown{ 103103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland switch (hdr->opcode) { 103203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_LOOKUP: { /* bytez[] -> entry_out */ 1033847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const char* name = data; 1034fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_lookup(fuse, handler, hdr, name); 103503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 103603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1037847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 103803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_FORGET: { 1039847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const struct fuse_forget_in *req = data; 1040fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_forget(fuse, handler, hdr, req); 104103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 104203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1043847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 104403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_GETATTR: { /* getattr_in -> attr_out */ 1045847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const struct fuse_getattr_in *req = data; 1046fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_getaddr(fuse, handler, hdr, req); 104703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 104803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1049847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 105003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_SETATTR: { /* setattr_in -> attr_out */ 1051847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const struct fuse_setattr_in *req = data; 1052fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_setattr(fuse, handler, hdr, req); 105303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 105403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1055847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 105603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland// case FUSE_READLINK: 105703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland// case FUSE_SYMLINK: 105803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */ 1059847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const struct fuse_mknod_in *req = data; 1060847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const char *name = ((const char*) data) + sizeof(*req); 1061fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_mknod(fuse, handler, hdr, req, name); 106203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 106303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1064847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 106503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */ 1066847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const struct fuse_mkdir_in *req = data; 1067847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const char *name = ((const char*) data) + sizeof(*req); 1068fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_mkdir(fuse, handler, hdr, req, name); 106903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 107003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1071847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 107203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_UNLINK: { /* bytez[] -> */ 1073847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const char* name = data; 1074fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_unlink(fuse, handler, hdr, name); 107503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 107603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1077847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 107803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_RMDIR: { /* bytez[] -> */ 1079847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const char* name = data; 1080fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_rmdir(fuse, handler, hdr, name); 108103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 108203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1083847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 108403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_RENAME: { /* rename_in, oldname, newname -> */ 1085847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const struct fuse_rename_in *req = data; 1086847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const char *oldname = ((const char*) data) + sizeof(*req); 1087847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const char *newname = oldname + strlen(oldname) + 1; 1088fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_rename(fuse, handler, hdr, req, oldname, newname); 108903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 109003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1091847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 1092fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown// case FUSE_LINK: 109303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_OPEN: { /* open_in -> open_out */ 1094847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const struct fuse_open_in *req = data; 1095fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_open(fuse, handler, hdr, req); 109603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 109703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1098847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 109903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_READ: { /* read_in -> byte[] */ 1100847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const struct fuse_read_in *req = data; 1101fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_read(fuse, handler, hdr, req); 110203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 110303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1104847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 110503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */ 1106847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const struct fuse_write_in *req = data; 1107847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const void* buffer = (const __u8*)data + sizeof(*req); 1108fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_write(fuse, handler, hdr, req, buffer); 1109847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown return; 111003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1111847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 11124553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood case FUSE_STATFS: { /* getattr_in -> attr_out */ 1113fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_statfs(fuse, handler, hdr); 11144553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood return; 11154553b08d7555a103fdbe8623a9cbd826a7e413ffMike Lockwood } 1116847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 111703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_RELEASE: { /* release_in -> */ 1118847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const struct fuse_release_in *req = data; 1119fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_release(fuse, handler, hdr, req); 112003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 112103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1122847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 11236fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown case FUSE_FSYNC: { 11246fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown const struct fuse_fsync_in *req = data; 1125fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_fsync(fuse, handler, hdr, req); 11266fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown return; 11276fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown } 11286fd921ae03a0fa17acfe118753ecd76d25f02e10Jeff Brown 112903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland// case FUSE_SETXATTR: 113003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland// case FUSE_GETXATTR: 113103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland// case FUSE_LISTXATTR: 113203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland// case FUSE_REMOVEXATTR: 1133847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown case FUSE_FLUSH: { 1134fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_flush(fuse, handler, hdr); 113503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 1136847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown } 1137847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 113803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_OPENDIR: { /* open_in -> open_out */ 1139847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const struct fuse_open_in *req = data; 1140fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_opendir(fuse, handler, hdr, req); 114103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 114203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1143847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 114403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_READDIR: { 1145847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const struct fuse_read_in *req = data; 1146fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_readdir(fuse, handler, hdr, req); 114703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 114803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1149847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 115003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_RELEASEDIR: { /* release_in -> */ 1151847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const struct fuse_release_in *req = data; 1152fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_releasedir(fuse, handler, hdr, req); 115303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 115403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1155847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 115603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland// case FUSE_FSYNCDIR: 115703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland case FUSE_INIT: { /* init_in -> init_out */ 1158847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown const struct fuse_init_in *req = data; 1159fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brown handle_init(fuse, handler, hdr, req); 116003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 116103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1162847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 116303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland default: { 116403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland ERROR("NOTIMPL op=%d uniq=%llx nid=%llx\n", 116503ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland hdr->opcode, hdr->unique, hdr->nodeid); 1166847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown fuse_status(fuse, hdr->unique, -ENOSYS); 116703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland break; 116803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1169847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown } 117003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 117103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 1172fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic void handle_fuse_requests(struct fuse *fuse, struct fuse_handler* handler) 117303ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 117403ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland for (;;) { 11757729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown ssize_t len = read(fuse->fd, handler->request_buffer, sizeof(handler->request_buffer)); 117603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland if (len < 0) { 117703ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland if (errno == EINTR) 117803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland continue; 117903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland ERROR("handle_fuse_requests: errno=%d\n", errno); 118003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland return; 118103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 1182847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 1183847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown if ((size_t)len < sizeof(struct fuse_in_header)) { 1184847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown ERROR("request too short: len=%zu\n", (size_t)len); 1185847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown return; 1186847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown } 1187847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 11887729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown const struct fuse_in_header *hdr = (void*)handler->request_buffer; 1189847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown if (hdr->len != (size_t)len) { 1190847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown ERROR("malformed header: len=%zu, hdr->len=%u\n", (size_t)len, hdr->len); 1191847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown return; 1192847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown } 1193847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown 11947729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown const void *data = handler->request_buffer + sizeof(struct fuse_in_header); 1195847158476c1b7662eeec77808d8ecdbb329e6f28Jeff Brown size_t data_len = len - sizeof(struct fuse_in_header); 11967729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown handle_fuse_request(fuse, handler, hdr, data, data_len); 11977729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown 11987729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown /* We do not access the request again after this point because the underlying 11997729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown * buffer storage may have been reused while processing the request. */ 120003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 120103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 120203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 1203fc1e1a0ab48a88dc7e9a93f65da5e6458de622afJeff Brownstatic int ignite_fuse(struct fuse* fuse) 12047729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown{ 12057729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown /* use only one handler thread for now */ 12067729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown struct fuse_handler handler; 12077729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown handle_fuse_requests(fuse, &handler); 12087729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown return 0; 12097729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown} 12107729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown 12114f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwoodstatic int usage() 12124f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood{ 12132656735f515a41cf131c87be5f40550b6538ce80Jeff Brown ERROR("usage: sdcard <path> <uid> <gid>\n\n"); 12142656735f515a41cf131c87be5f40550b6538ce80Jeff Brown return 1; 12154f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood} 12164f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood 12172656735f515a41cf131c87be5f40550b6538ce80Jeff Brownstatic int run(const char* path, uid_t uid, gid_t gid) 121803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland{ 12192656735f515a41cf131c87be5f40550b6538ce80Jeff Brown int fd; 122003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland char opts[256]; 12212656735f515a41cf131c87be5f40550b6538ce80Jeff Brown int res; 12222656735f515a41cf131c87be5f40550b6538ce80Jeff Brown struct fuse fuse; 12232656735f515a41cf131c87be5f40550b6538ce80Jeff Brown 12242656735f515a41cf131c87be5f40550b6538ce80Jeff Brown /* cleanup from previous instance, if necessary */ 12252656735f515a41cf131c87be5f40550b6538ce80Jeff Brown umount2(MOUNT_POINT, 2); 12262656735f515a41cf131c87be5f40550b6538ce80Jeff Brown 12272656735f515a41cf131c87be5f40550b6538ce80Jeff Brown fd = open("/dev/fuse", O_RDWR); 12282656735f515a41cf131c87be5f40550b6538ce80Jeff Brown if (fd < 0){ 12292656735f515a41cf131c87be5f40550b6538ce80Jeff Brown ERROR("cannot open fuse device (error %d)\n", errno); 12302656735f515a41cf131c87be5f40550b6538ce80Jeff Brown return -1; 12312656735f515a41cf131c87be5f40550b6538ce80Jeff Brown } 12322656735f515a41cf131c87be5f40550b6538ce80Jeff Brown 12332656735f515a41cf131c87be5f40550b6538ce80Jeff Brown snprintf(opts, sizeof(opts), 12342656735f515a41cf131c87be5f40550b6538ce80Jeff Brown "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d", 12352656735f515a41cf131c87be5f40550b6538ce80Jeff Brown fd, uid, gid); 12362656735f515a41cf131c87be5f40550b6538ce80Jeff Brown 12372656735f515a41cf131c87be5f40550b6538ce80Jeff Brown res = mount("/dev/fuse", MOUNT_POINT, "fuse", MS_NOSUID | MS_NODEV, opts); 12382656735f515a41cf131c87be5f40550b6538ce80Jeff Brown if (res < 0) { 12392656735f515a41cf131c87be5f40550b6538ce80Jeff Brown ERROR("cannot mount fuse filesystem (error %d)\n", errno); 12402656735f515a41cf131c87be5f40550b6538ce80Jeff Brown goto error; 12412656735f515a41cf131c87be5f40550b6538ce80Jeff Brown } 12422656735f515a41cf131c87be5f40550b6538ce80Jeff Brown 12432656735f515a41cf131c87be5f40550b6538ce80Jeff Brown res = setgid(gid); 12442656735f515a41cf131c87be5f40550b6538ce80Jeff Brown if (res < 0) { 12452656735f515a41cf131c87be5f40550b6538ce80Jeff Brown ERROR("cannot setgid (error %d)\n", errno); 12462656735f515a41cf131c87be5f40550b6538ce80Jeff Brown goto error; 12472656735f515a41cf131c87be5f40550b6538ce80Jeff Brown } 12482656735f515a41cf131c87be5f40550b6538ce80Jeff Brown 12492656735f515a41cf131c87be5f40550b6538ce80Jeff Brown res = setuid(uid); 12502656735f515a41cf131c87be5f40550b6538ce80Jeff Brown if (res < 0) { 12512656735f515a41cf131c87be5f40550b6538ce80Jeff Brown ERROR("cannot setuid (error %d)\n", errno); 12522656735f515a41cf131c87be5f40550b6538ce80Jeff Brown goto error; 12532656735f515a41cf131c87be5f40550b6538ce80Jeff Brown } 12542656735f515a41cf131c87be5f40550b6538ce80Jeff Brown 12552656735f515a41cf131c87be5f40550b6538ce80Jeff Brown fuse_init(&fuse, fd, path); 12562656735f515a41cf131c87be5f40550b6538ce80Jeff Brown 12572656735f515a41cf131c87be5f40550b6538ce80Jeff Brown umask(0); 12587729d2450faeb1a02c72b29f48efc208de1cb444Jeff Brown res = ignite_fuse(&fuse); 12592656735f515a41cf131c87be5f40550b6538ce80Jeff Brown 12602656735f515a41cf131c87be5f40550b6538ce80Jeff Brown /* we do not attempt to umount the file system here because we are no longer 12612656735f515a41cf131c87be5f40550b6538ce80Jeff Brown * running as the root user */ 12622656735f515a41cf131c87be5f40550b6538ce80Jeff Brown 12632656735f515a41cf131c87be5f40550b6538ce80Jeff Brownerror: 12642656735f515a41cf131c87be5f40550b6538ce80Jeff Brown close(fd); 12652656735f515a41cf131c87be5f40550b6538ce80Jeff Brown return res; 12662656735f515a41cf131c87be5f40550b6538ce80Jeff Brown} 12672656735f515a41cf131c87be5f40550b6538ce80Jeff Brown 12682656735f515a41cf131c87be5f40550b6538ce80Jeff Brownint main(int argc, char **argv) 12692656735f515a41cf131c87be5f40550b6538ce80Jeff Brown{ 127003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland int fd; 127103ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland int res; 12724f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood const char *path = NULL; 12732656735f515a41cf131c87be5f40550b6538ce80Jeff Brown uid_t uid = 0; 12742656735f515a41cf131c87be5f40550b6538ce80Jeff Brown gid_t gid = 0; 12754f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood int i; 12764f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood 12774f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood for (i = 1; i < argc; i++) { 12784f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood char* arg = argv[i]; 1279575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood if (!path) 1280575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood path = arg; 12812656735f515a41cf131c87be5f40550b6538ce80Jeff Brown else if (!uid) 1282575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood uid = strtoul(arg, 0, 10); 12832656735f515a41cf131c87be5f40550b6538ce80Jeff Brown else if (!gid) 1284575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood gid = strtoul(arg, 0, 10); 1285575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood else { 1286575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood ERROR("too many arguments\n"); 1287575a2bbee30d70a1940077a5b699aaf93cb4e2cdMike Lockwood return usage(); 12884f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood } 128903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 129003ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 12914f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood if (!path) { 12924f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood ERROR("no path specified\n"); 12934f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood return usage(); 12944f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood } 12952656735f515a41cf131c87be5f40550b6538ce80Jeff Brown if (!uid || !gid) { 129603ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland ERROR("uid and gid must be nonzero\n"); 12974f35e623a2359789406772009078d1a6ca7af6b3Mike Lockwood return usage(); 129803ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland } 129903ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland 13002656735f515a41cf131c87be5f40550b6538ce80Jeff Brown res = run(path, uid, gid); 13012656735f515a41cf131c87be5f40550b6538ce80Jeff Brown return res < 0 ? 1 : 0; 130203ee9479a4ed67689b9bbccda20c60800a38b178Brian Swetland} 1303