sdcard.c revision f43219e0b1022b257499289ceb951f6a1a44bf9c
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2010 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdio.h> 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdlib.h> 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <string.h> 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <unistd.h> 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <errno.h> 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <fcntl.h> 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/mount.h> 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/stat.h> 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/statfs.h> 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/uio.h> 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <dirent.h> 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <private/android_filesystem_config.h> 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "fuse.h" 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* README 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * What is this? 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * sdcard is a program that uses FUSE to emulate FAT-on-sdcard style 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * directory permissions (all files are given fixed owner, group, and 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * permissions at creation, owner, group, and permissions are not 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * changeable, symlinks and hardlinks are not createable, etc. 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * usage: sdcard <path> <uid> <gid> 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 44a833cbbed087bf6869905a43166757a6436ad34fDave Bort * It must be run as root, but will change to uid/gid as soon as it 45a833cbbed087bf6869905a43166757a6436ad34fDave Bort * mounts a filesystem on /mnt/sdcard. It will refuse to run if uid or 46a833cbbed087bf6869905a43166757a6436ad34fDave Bort * gid are zero. 47a833cbbed087bf6869905a43166757a6436ad34fDave Bort * 48a833cbbed087bf6869905a43166757a6436ad34fDave Bort * 49a833cbbed087bf6869905a43166757a6436ad34fDave Bort * Things I believe to be true: 50a833cbbed087bf6869905a43166757a6436ad34fDave Bort * 51a833cbbed087bf6869905a43166757a6436ad34fDave Bort * - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK, 52a833cbbed087bf6869905a43166757a6436ad34fDave Bort * CREAT) must bump that node's refcount 53a833cbbed087bf6869905a43166757a6436ad34fDave Bort * - don't forget that FORGET can forget multiple references (req->nlookup) 54a833cbbed087bf6869905a43166757a6436ad34fDave Bort * - if an op that returns a fuse_entry fails writing the reply to the 55a833cbbed087bf6869905a43166757a6436ad34fDave Bort * kernel, you must rollback the refcount to reflect the reference the 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * kernel did not actually acquire 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 58c1e8aa4c448807fc3ee9d21e8b67bb886fa065aaMike Lockwood * 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Bugs: 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * - need to move/rename node on RENAME 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define FUSE_TRACE 0 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#if FUSE_TRACE 6775986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov#define TRACE(x...) fprintf(stderr,x) 68dace230043314d6fab1c5ced4b031eaccd814c25Dianne Hackborn#else 69603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana#define TRACE(x...) do {} while (0) 70603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana#endif 71603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 72603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana#define ERROR(x...) fprintf(stderr,x) 73b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define FUSE_UNKNOWN_INO 0xffffffff 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define MOUNT_POINT "/mnt/sdcard" 77b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct handle { 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct node *node; 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fd; 818d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert}; 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct dirhandle { 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct node *node; 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DIR *d; 868cc6a5026aeb5cf9cc36529426fe0cc66714f5fbDianne Hackborn}; 878cc6a5026aeb5cf9cc36529426fe0cc66714f5fbDianne Hackborn 88487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tatestruct node { 897d562ec393d54dd9ef387c49d1283243bfdbd2b1Christopher Tate __u64 nid; 908c850b792f2d371fd8a4aff146d9d757ee982539Christopher Tate __u64 gen; 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct node *next; 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct node *child; 943f41673265dcaaef058703311c5481e8a51fd8beJiafa Liu struct node *all; 95b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn struct node *parent; 961ccac75e1f1b97eccb916a8de04fc1012b30f6e5Suchi Amalapurapu 971ccac75e1f1b97eccb916a8de04fc1012b30f6e5Suchi Amalapurapu __u32 refcount; 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project __u32 namelen; 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 100b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn char name[1]; 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct fuse { 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project __u64 next_generation; 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project __u64 next_node_id; 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fd; 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct node *all; 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct node root; 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char rootpath[1024]; 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define PATH_BUFFER_SIZE 1024 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1178cc6a5026aeb5cf9cc36529426fe0cc66714f5fbDianne Hackborn/* 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the real-life absolute path to a node. 11975986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov * node: start at this node 12075986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov * buf: storage for returned string 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * name: append this string to path if set 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectchar *node_get_path(struct node *node, char *buf, const char *name) 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char *out = buf + PATH_BUFFER_SIZE - 1; 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len; 127f1bb004cda115fff322e7f5126797343236b5c0eBrandon Ballinger out[0] = 0; 128f1bb004cda115fff322e7f5126797343236b5c0eBrandon Ballinger 129f85aa5a4d4e6f1ef7e07638568e27d709b8085c6Charles Chen if (name) { 130f85aa5a4d4e6f1ef7e07638568e27d709b8085c6Charles Chen len = strlen(name); 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project goto start; 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 133c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 134c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project while (node) { 135487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate name = node->name; 136c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project len = node->namelen; 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node = node->parent; 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project start: 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((len + 1) > (out - buf)) 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out -= len; 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project memcpy(out, name, len); 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out --; 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out[0] = '/'; 145a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood } 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14715e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood return out; 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 150c1e8aa4c448807fc3ee9d21e8b67bb886fa065aaMike Lockwoodvoid attr_from_stat(struct fuse_attr *attr, struct stat *s) 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attr->ino = s->st_ino; 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attr->size = s->st_size; 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attr->blocks = s->st_blocks; 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attr->atime = s->st_atime; 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attr->mtime = s->st_mtime; 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attr->ctime = s->st_ctime; 15804e71b3db84fd5f7fc4eefb49a33154ea91ec9fcWink Saville attr->atimensec = s->st_atime_nsec; 15904e71b3db84fd5f7fc4eefb49a33154ea91ec9fcWink Saville attr->mtimensec = s->st_mtime_nsec; 160e91bc680b731a5d97f066b2e6c9c99b3c7dd5c58John Wang attr->ctimensec = s->st_ctime_nsec; 1619207b1e7c8ad4bbef3530d2b047bf6587f2988c4Raphael attr->mode = s->st_mode; 16255567efca99de7242b118cf7bf13cc773b01941cHung-ying Tyan attr->nlink = s->st_nlink; 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* force permissions to something reasonable: 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * world readable 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * writable by the sdcard group 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (attr->mode & 0100) { 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attr->mode = (attr->mode & (~0777)) | 0775; 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attr->mode = (attr->mode & (~0777)) | 0664; 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* all files owned by root.sdcard */ 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attr->uid = 0; 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attr->gid = AID_SDCARD_RW; 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint node_get_attr(struct node *node, struct fuse_attr *attr) 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int res; 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct stat s; 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char *path, buffer[PATH_BUFFER_SIZE]; 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project path = node_get_path(node, buffer, 0); 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project res = lstat(path, &s); 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (res < 0) { 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ERROR("lstat('%s') errno %d\n", path, errno); 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attr_from_stat(attr, &s); 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attr->ino = node->nid; 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct node *node_create(struct node *parent, const char *name, __u64 nid, __u64 gen) 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct node *node; 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int namelen = strlen(name); 202603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 203603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana node = calloc(1, sizeof(struct node) + namelen); 204603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana if (node == 0) { 205603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana return 0; 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node->nid = nid; 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node->gen = gen; 2101ccac75e1f1b97eccb916a8de04fc1012b30f6e5Suchi Amalapurapu node->parent = parent; 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node->next = parent->child; 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parent->child = node; 213c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project memcpy(node->name, name, namelen + 1); 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node->namelen = namelen; 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parent->refcount++; 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return node; 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid fuse_init(struct fuse *fuse, int fd, const char *path) 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse->fd = fd; 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse->next_node_id = 2; 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse->next_generation = 0; 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse->all = &fuse->root; 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse->root.nid = FUSE_ROOT_ID; /* 1 */ 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse->root.next = 0; 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse->root.child = 0; 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse->root.parent = 0; 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse->root.all = 0; 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse->root.refcount = 2; 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 236d8b51a2ba8ee82be81414c0e80158e82b2c361d9Raphael strcpy(fuse->root.name, path); 23755567efca99de7242b118cf7bf13cc773b01941cHung-ying Tyan fuse->root.namelen = strlen(fuse->root.name); 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic inline void *id_to_ptr(__u64 nid) 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (void *) nid; 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic inline __u64 ptr_to_id(void *ptr) 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (__u64) ptr; 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct node *lookup_by_inode(struct fuse *fuse, __u64 nid) 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (nid == FUSE_ROOT_ID) { 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return &fuse->root; 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return id_to_ptr(nid); 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct node *lookup_child_by_name(struct node *node, const char *name) 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (node = node->child; node; node = node->next) { 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!strcmp(name, node->name)) { 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return node; 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 266a833cbbed087bf6869905a43166757a6436ad34fDave Bort } 267a833cbbed087bf6869905a43166757a6436ad34fDave Bort return 0; 268a833cbbed087bf6869905a43166757a6436ad34fDave Bort} 269a833cbbed087bf6869905a43166757a6436ad34fDave Bort 270a833cbbed087bf6869905a43166757a6436ad34fDave Bortstruct node *lookup_child_by_inode(struct node *node, __u64 nid) 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (node = node->child; node; node = node->next) { 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (node->nid == nid) { 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return node; 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct node *node_lookup(struct fuse *fuse, struct node *parent, const char *name, 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct fuse_attr *attr) 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int res; 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct stat s; 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char *path, buffer[PATH_BUFFER_SIZE]; 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct node *node; 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project path = node_get_path(parent, buffer, name); 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* XXX error? */ 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project res = lstat(path, &s); 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (res < 0) 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node = lookup_child_by_name(parent, name); 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!node) { 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node = node_create(parent, name, fuse->next_node_id++, fuse->next_generation++); 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!node) 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node->nid = ptr_to_id(node); 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node->all = fuse->all; 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse->all = node; 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attr_from_stat(attr, &s); 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attr->ino = node->nid; 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return node; 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid node_release(struct node *node) 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount); 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node->refcount--; 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (node->refcount == 0) { 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (node->parent->child == node) { 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node->parent->child = node->parent->child->next; 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct node *node2; 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node2 = node->parent->child; 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (node2->next != node) 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node2 = node2->next; 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node2->next = node->next; 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TRACE("DESTROY %p (%s)\n", node, node->name); 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node_release(node->parent); 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node->parent = 0; 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node->next = 0; 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* TODO: remove debugging - poison memory */ 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project memset(node, 0xef, sizeof(*node) + strlen(node->name)); 3366dceb76b3e02cd2e0f08105f54d942e6ad8c4456Scott Main 3376dceb76b3e02cd2e0f08105f54d942e6ad8c4456Scott Main free(node); 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3396dceb76b3e02cd2e0f08105f54d942e6ad8c4456Scott Main} 3406dceb76b3e02cd2e0f08105f54d942e6ad8c4456Scott Main 3416dceb76b3e02cd2e0f08105f54d942e6ad8c4456Scott Mainvoid fuse_status(struct fuse *fuse, __u64 unique, int err) 3426dceb76b3e02cd2e0f08105f54d942e6ad8c4456Scott Main{ 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct fuse_out_header hdr; 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hdr.len = sizeof(hdr); 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hdr.error = err; 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hdr.unique = unique; 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (err) { 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ERROR("*** %d ***\n", err); 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project write(fuse->fd, &hdr, sizeof(hdr)); 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len) 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct fuse_out_header hdr; 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct iovec vec[2]; 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int res; 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3592e2c9104b78c4e817db992cb121742ae2e52ba26Dirk Dougherty hdr.len = len + sizeof(hdr); 3602e2c9104b78c4e817db992cb121742ae2e52ba26Dirk Dougherty hdr.error = 0; 3612e2c9104b78c4e817db992cb121742ae2e52ba26Dirk Dougherty hdr.unique = unique; 3622e2c9104b78c4e817db992cb121742ae2e52ba26Dirk Dougherty 3632e2c9104b78c4e817db992cb121742ae2e52ba26Dirk Dougherty vec[0].iov_base = &hdr; 3642e2c9104b78c4e817db992cb121742ae2e52ba26Dirk Dougherty vec[0].iov_len = sizeof(hdr); 3654b508759dcf02b5b11e3d28ae63864fafd410644Dirk Dougherty vec[1].iov_base = data; 3662e2c9104b78c4e817db992cb121742ae2e52ba26Dirk Dougherty vec[1].iov_len = len; 3672e2c9104b78c4e817db992cb121742ae2e52ba26Dirk Dougherty 3682e2c9104b78c4e817db992cb121742ae2e52ba26Dirk Dougherty res = writev(fuse->fd, vec, 2); 3692e2c9104b78c4e817db992cb121742ae2e52ba26Dirk Dougherty if (res < 0) { 3702e2c9104b78c4e817db992cb121742ae2e52ba26Dirk Dougherty ERROR("*** REPLY FAILED *** %d\n", errno); 3712e2c9104b78c4e817db992cb121742ae2e52ba26Dirk Dougherty } 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 373ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato 374ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onoratovoid lookup_entry(struct fuse *fuse, struct node *node, 375ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato const char *name, __u64 unique) 376ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato{ 377ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato struct fuse_entry_out out; 378ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato 379ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato memset(&out, 0, sizeof(out)); 380ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato 381ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato node = node_lookup(fuse, node, name, &out.attr); 382ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato if (!node) { 383ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato fuse_status(fuse, unique, -ENOENT); 384ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato return; 385ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato } 386ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato 387ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato node->refcount++; 388ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato// fprintf(stderr,"ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount); 389ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato out.nodeid = node->nid; 390ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato out.generation = node->gen; 391ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato out.entry_valid = 10; 392ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato out.attr_valid = 10; 393ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato 394ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato fuse_reply(fuse, unique, &out, sizeof(out)); 395ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato} 396ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato 397ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onoratovoid handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *data, unsigned len) 398ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato{ 399ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato struct node *node; 400ccfca2ee9ebe6d3de861f6f001bd4810c863cab1Joe Onorato 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((len < sizeof(*hdr)) || (hdr->len != len)) { 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ERROR("malformed header\n"); 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project len -= hdr->len; 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (hdr->nodeid) { 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node = lookup_by_inode(fuse, hdr->nodeid); 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!node) { 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse_status(fuse, hdr->unique, -ENOENT); 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node = 0; 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (hdr->opcode) { 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case FUSE_LOOKUP: { /* bytez[] -> entry_out */ 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TRACE("LOOKUP %llx %s\n", hdr->nodeid, (char*) data); 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lookup_entry(fuse, node, (char*) data, hdr->unique); 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case FUSE_FORGET: { 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct fuse_forget_in *req = data; 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TRACE("FORGET %llx (%s) #%lld\n", hdr->nodeid, node->name, req->nlookup); 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* no reply */ 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (req->nlookup--) 4292e2c9104b78c4e817db992cb121742ae2e52ba26Dirk Dougherty node_release(node); 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case FUSE_GETATTR: { /* getattr_in -> attr_out */ 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct fuse_getattr_in *req = data; 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct fuse_attr_out out; 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TRACE("GETATTR flags=%x fh=%llx\n",req->getattr_flags, req->fh); 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project memset(&out, 0, sizeof(out)); 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node_get_attr(node, &out.attr); 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.attr_valid = 10; 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse_reply(fuse, hdr->unique, &out, sizeof(out)); 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case FUSE_SETATTR: { /* setattr_in -> attr_out */ 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct fuse_setattr_in *req = data; 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct fuse_attr_out out; 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char *path, buffer[PATH_BUFFER_SIZE]; 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int res = 0; 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TRACE("SETATTR fh=%llx id=%llx valid=%x\n", 4522e2c9104b78c4e817db992cb121742ae2e52ba26Dirk Dougherty req->fh, hdr->nodeid, req->valid); 4532e2c9104b78c4e817db992cb121742ae2e52ba26Dirk Dougherty 4542e2c9104b78c4e817db992cb121742ae2e52ba26Dirk Dougherty /* XXX: incomplete implementation -- truncate only. chmod/chown 45513d30dc375de954ea70bbab2c89ce7e1e58fcf8cDirk Dougherty * should NEVER be implemented. */ 45613d30dc375de954ea70bbab2c89ce7e1e58fcf8cDirk Dougherty 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project path = node_get_path(node, buffer, 0); 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (req->valid & FATTR_SIZE) 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project res = truncate(path, req->size); 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project memset(&out, 0, sizeof(out)); 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project node_get_attr(node, &out.attr); 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.attr_valid = 10; 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (res) 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse_status(fuse, hdr->unique, -errno); 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse_reply(fuse, hdr->unique, &out, sizeof(out)); 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// case FUSE_READLINK: 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// case FUSE_SYMLINK: 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */ 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct fuse_mknod_in *req = data; 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char *path, buffer[PATH_BUFFER_SIZE]; 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char *name = ((char*) data) + sizeof(*req); 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int res; 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TRACE("MKNOD %s @ %llx\n", name, hdr->nodeid); 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project path = node_get_path(node, buffer, name); 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project req->mode = (req->mode & (~0777)) | 0664; 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project res = mknod(path, req->mode, req->rdev); /* XXX perm?*/ 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (res < 0) { 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse_status(fuse, hdr->unique, -errno); 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lookup_entry(fuse, node, name, hdr->unique); 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */ 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct fuse_mkdir_in *req = data; 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project struct fuse_entry_out out; 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char *path, buffer[PATH_BUFFER_SIZE]; 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char *name = ((char*) data) + sizeof(*req); 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int res; 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TRACE("MKDIR %s @ %llx 0%o\n", name, hdr->nodeid, req->mode); 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project path = node_get_path(node, buffer, name); 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project req->mode = (req->mode & (~0777)) | 0775; 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project res = mkdir(path, req->mode); 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (res < 0) { 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse_status(fuse, hdr->unique, -errno); 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lookup_entry(fuse, node, name, hdr->unique); 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case FUSE_UNLINK: { /* bytez[] -> */ 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char *path, buffer[PATH_BUFFER_SIZE]; 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int res; 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TRACE("UNLINK %s @ %llx\n", (char*) data, hdr->nodeid); 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project path = node_get_path(node, buffer, (char*) data); 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project res = unlink(path); 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fuse_status(fuse, hdr->unique, res ? -errno : 0); 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case FUSE_RMDIR: { /* bytez[] -> */ 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char *path, buffer[PATH_BUFFER_SIZE]; 519 int res; 520 TRACE("RMDIR %s @ %llx\n", (char*) data, hdr->nodeid); 521 path = node_get_path(node, buffer, (char*) data); 522 res = rmdir(path); 523 fuse_status(fuse, hdr->unique, res ? -errno : 0); 524 return; 525 } 526 case FUSE_RENAME: { /* rename_in, oldname, newname -> */ 527 struct fuse_rename_in *req = data; 528 char *oldname = ((char*) data) + sizeof(*req); 529 char *newname = oldname + strlen(oldname) + 1; 530 char *oldpath, oldbuffer[PATH_BUFFER_SIZE]; 531 char *newpath, newbuffer[PATH_BUFFER_SIZE]; 532 struct node *newnode; 533 int res; 534 535 newnode = lookup_by_inode(fuse, req->newdir); 536 if (!newnode) { 537 fuse_status(fuse, hdr->unique, -ENOENT); 538 return; 539 } 540 541 oldpath = node_get_path(node, oldbuffer, oldname); 542 newpath = node_get_path(newnode, newbuffer, newname); 543 544 res = rename(oldpath, newpath); 545 fuse_status(fuse, hdr->unique, res ? -errno : 0); 546 return; 547 } 548// case FUSE_LINK: 549 case FUSE_OPEN: { /* open_in -> open_out */ 550 struct fuse_open_in *req = data; 551 struct fuse_open_out out; 552 char *path, buffer[PATH_BUFFER_SIZE]; 553 struct handle *h; 554 555 h = malloc(sizeof(*h)); 556 if (!h) { 557 fuse_status(fuse, hdr->unique, -ENOMEM); 558 return; 559 } 560 561 path = node_get_path(node, buffer, 0); 562 TRACE("OPEN %llx '%s' 0%o fh=%p\n", hdr->nodeid, path, req->flags, h); 563 h->fd = open(path, req->flags); 564 if (h->fd < 0) { 565 ERROR("ERROR\n"); 566 fuse_status(fuse, hdr->unique, errno); 567 free(h); 568 return; 569 } 570 out.fh = ptr_to_id(h); 571 out.open_flags = 0; 572 out.padding = 0; 573 fuse_reply(fuse, hdr->unique, &out, sizeof(out)); 574 return; 575 } 576 case FUSE_READ: { /* read_in -> byte[] */ 577 char buffer[128 * 1024]; 578 struct fuse_read_in *req = data; 579 struct handle *h = id_to_ptr(req->fh); 580 int res; 581 TRACE("READ %p(%d) %u@%llu\n", h, h->fd, req->size, req->offset); 582 if (req->size > sizeof(buffer)) { 583 fuse_status(fuse, hdr->unique, -EINVAL); 584 return; 585 } 586 res = pread(h->fd, buffer, req->size, req->offset); 587 if (res < 0) { 588 fuse_status(fuse, hdr->unique, errno); 589 return; 590 } 591 fuse_reply(fuse, hdr->unique, buffer, res); 592 return; 593 } 594 case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */ 595 struct fuse_write_in *req = data; 596 struct fuse_write_out out; 597 struct handle *h = id_to_ptr(req->fh); 598 int res; 599 TRACE("WRITE %p(%d) %u@%llu\n", h, h->fd, req->size, req->offset); 600 res = pwrite(h->fd, ((char*) data) + sizeof(*req), req->size, req->offset); 601 if (res < 0) { 602 fuse_status(fuse, hdr->unique, errno); 603 return; 604 } 605 out.size = res; 606 fuse_reply(fuse, hdr->unique, &out, sizeof(out)); 607 goto oops; 608 } 609 case FUSE_STATFS: { /* getattr_in -> attr_out */ 610 struct statfs stat; 611 struct fuse_statfs_out out; 612 int res; 613 614 TRACE("STATFS\n"); 615 616 if (statfs(fuse->root.name, &stat)) { 617 fuse_status(fuse, hdr->unique, -errno); 618 return; 619 } 620 621 memset(&out, 0, sizeof(out)); 622 out.st.blocks = stat.f_blocks; 623 out.st.bfree = stat.f_bfree; 624 out.st.bavail = stat.f_bavail; 625 out.st.files = stat.f_files; 626 out.st.ffree = stat.f_ffree; 627 out.st.bsize = stat.f_bsize; 628 out.st.namelen = stat.f_namelen; 629 out.st.frsize = stat.f_frsize; 630 fuse_reply(fuse, hdr->unique, &out, sizeof(out)); 631 return; 632 } 633 case FUSE_RELEASE: { /* release_in -> */ 634 struct fuse_release_in *req = data; 635 struct handle *h = id_to_ptr(req->fh); 636 TRACE("RELEASE %p(%d)\n", h, h->fd); 637 close(h->fd); 638 free(h); 639 fuse_status(fuse, hdr->unique, 0); 640 return; 641 } 642// case FUSE_FSYNC: 643// case FUSE_SETXATTR: 644// case FUSE_GETXATTR: 645// case FUSE_LISTXATTR: 646// case FUSE_REMOVEXATTR: 647 case FUSE_FLUSH: 648 fuse_status(fuse, hdr->unique, 0); 649 return; 650 case FUSE_OPENDIR: { /* open_in -> open_out */ 651 struct fuse_open_in *req = data; 652 struct fuse_open_out out; 653 char *path, buffer[PATH_BUFFER_SIZE]; 654 struct dirhandle *h; 655 656 h = malloc(sizeof(*h)); 657 if (!h) { 658 fuse_status(fuse, hdr->unique, -ENOMEM); 659 return; 660 } 661 662 path = node_get_path(node, buffer, 0); 663 TRACE("OPENDIR %llx '%s'\n", hdr->nodeid, path); 664 h->d = opendir(path); 665 if (h->d == 0) { 666 ERROR("ERROR\n"); 667 fuse_status(fuse, hdr->unique, -errno); 668 free(h); 669 return; 670 } 671 out.fh = ptr_to_id(h); 672 fuse_reply(fuse, hdr->unique, &out, sizeof(out)); 673 return; 674 } 675 case FUSE_READDIR: { 676 struct fuse_read_in *req = data; 677 char buffer[8192]; 678 struct fuse_dirent *fde = (struct fuse_dirent*) buffer; 679 struct dirent *de; 680 struct dirhandle *h = id_to_ptr(req->fh); 681 TRACE("READDIR %p\n", h); 682 de = readdir(h->d); 683 if (!de) { 684 fuse_status(fuse, hdr->unique, 0); 685 return; 686 } 687 fde->ino = FUSE_UNKNOWN_INO; 688 fde->off = 0; 689 fde->type = de->d_type; 690 fde->namelen = strlen(de->d_name); 691 memcpy(fde->name, de->d_name, fde->namelen + 1); 692 fuse_reply(fuse, hdr->unique, fde, 693 FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen)); 694 return; 695 } 696 case FUSE_RELEASEDIR: { /* release_in -> */ 697 struct fuse_release_in *req = data; 698 struct dirhandle *h = id_to_ptr(req->fh); 699 TRACE("RELEASEDIR %p\n",h); 700 closedir(h->d); 701 free(h); 702 fuse_status(fuse, hdr->unique, 0); 703 return; 704 } 705// case FUSE_FSYNCDIR: 706 case FUSE_INIT: { /* init_in -> init_out */ 707 struct fuse_init_in *req = data; 708 struct fuse_init_out out; 709 710 TRACE("INIT ver=%d.%d maxread=%d flags=%x\n", 711 req->major, req->minor, req->max_readahead, req->flags); 712 713 out.major = FUSE_KERNEL_VERSION; 714 out.minor = FUSE_KERNEL_MINOR_VERSION; 715 out.max_readahead = req->max_readahead; 716 out.flags = FUSE_ATOMIC_O_TRUNC; 717 out.max_background = 32; 718 out.congestion_threshold = 32; 719 out.max_write = 256 * 1024; 720 721 fuse_reply(fuse, hdr->unique, &out, sizeof(out)); 722 return; 723 } 724 default: { 725 struct fuse_out_header h; 726 ERROR("NOTIMPL op=%d uniq=%llx nid=%llx\n", 727 hdr->opcode, hdr->unique, hdr->nodeid); 728 729 oops: 730 h.len = sizeof(h); 731 h.error = -ENOSYS; 732 h.unique = hdr->unique; 733 write(fuse->fd, &h, sizeof(h)); 734 break; 735 } 736 } 737} 738 739void handle_fuse_requests(struct fuse *fuse) 740{ 741 unsigned char req[256 * 1024 + 128]; 742 int len; 743 744 for (;;) { 745 len = read(fuse->fd, req, 8192); 746 if (len < 0) { 747 if (errno == EINTR) 748 continue; 749 ERROR("handle_fuse_requests: errno=%d\n", errno); 750 return; 751 } 752 handle_fuse_request(fuse, (void*) req, (void*) (req + sizeof(struct fuse_in_header)), len); 753 } 754} 755 756int main(int argc, char **argv) 757{ 758 struct fuse fuse; 759 char opts[256]; 760 int fd; 761 int res; 762 unsigned uid; 763 unsigned gid; 764 const char *path; 765 766 if (argc != 4) { 767 ERROR("usage: sdcard <path> <uid> <gid>\n"); 768 return -1; 769 } 770 771 uid = strtoul(argv[2], 0, 10); 772 gid = strtoul(argv[3], 0, 10); 773 if (!uid || !gid) { 774 ERROR("uid and gid must be nonzero\n"); 775 return -1; 776 } 777 778 path = argv[1]; 779 780 /* cleanup from previous instance, if necessary */ 781 umount2(MOUNT_POINT, 2); 782 783 fd = open("/dev/fuse", O_RDWR); 784 if (fd < 0){ 785 ERROR("cannot open fuse device (%d)\n", errno); 786 return -1; 787 } 788 789 sprintf(opts, "fd=%i,rootmode=40000,default_permissions,allow_other," 790 "user_id=%d,group_id=%d", fd, uid, gid); 791 792 res = mount("/dev/fuse", MOUNT_POINT, "fuse", MS_NOSUID | MS_NODEV, opts); 793 if (res < 0) { 794 ERROR("cannot mount fuse filesystem (%d)\n", errno); 795 return -1; 796 } 797 798 if (setgid(gid) < 0) { 799 ERROR("cannot setgid!\n"); 800 return -1; 801 } 802 if (setuid(uid) < 0) { 803 ERROR("cannot setuid!\n"); 804 return -1; 805 } 806 807 fuse_init(&fuse, fd, path); 808 809 umask(0); 810 handle_fuse_requests(&fuse); 811 812 return 0; 813} 814