1075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker/* 2075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker * Copyright (C) 2014 The Android Open Source Project 3075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker * 4075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker * Licensed under the Apache License, Version 2.0 (the "License"); 5075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker * you may not use this file except in compliance with the License. 6075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker * You may obtain a copy of the License at 7075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker * 8075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker * http://www.apache.org/licenses/LICENSE-2.0 9075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker * 10075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker * Unless required by applicable law or agreed to in writing, software 11075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker * distributed under the License is distributed on an "AS IS" BASIS, 12075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker * See the License for the specific language governing permissions and 14075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker * limitations under the License. 15075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker */ 16075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 17075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// This module creates a special filesystem containing two files. 18075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// 19075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// "/sideload/package.zip" appears to be a normal file, but reading 20075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// from it causes data to be fetched from the adb host. We can use 21075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// this to sideload packages over an adb connection without having to 22075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// store the entire package in RAM on the device. 23075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// 24075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// Because we may not trust the adb host, this filesystem maintains 25075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// the following invariant: each read of a given position returns the 26075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// same data as the first read at that position. That is, once a 27075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// section of the file is read, future reads of that section return 28075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// the same data. (Otherwise, a malicious adb host process could 29075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// return one set of bits when the package is read for signature 30075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// verification, and then different bits for when the package is 31075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// accessed by the installer.) If the adb host returns something 32075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// different than it did on the first read, the reader of the file 33075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// will see their read fail with EINVAL. 34075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// 35075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// The other file, "/sideload/exit", is used to control the subprocess 36075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// that creates this filesystem. Calling stat() on the exit file 37075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// causes the filesystem to be unmounted and the adb process on the 38075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// device shut down. 39075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// 40075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// Note that only the minimal set of file operations needed for these 41075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// two files is implemented. In particular, you can't opendir() or 42075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// readdir() on the "/sideload" directory; ls on it won't work. 43075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 44075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <ctype.h> 45075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <dirent.h> 46075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <errno.h> 47075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <fcntl.h> 48075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <limits.h> 49075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <linux/fuse.h> 50075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <pthread.h> 51075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <stdio.h> 52075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <stdlib.h> 53075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <string.h> 54075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <sys/inotify.h> 55075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <sys/mount.h> 56075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <sys/resource.h> 57075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <sys/stat.h> 58075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <sys/statfs.h> 59075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <sys/time.h> 60075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <sys/uio.h> 61075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include <unistd.h> 62075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 63075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#include "mincrypt/sha256.h" 6418a78e0a162c35756628610307f41179816d3333Doug Zongker#include "fuse_sideload.h" 65075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 66075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#define PACKAGE_FILE_ID (FUSE_ROOT_ID+1) 67075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#define EXIT_FLAG_ID (FUSE_ROOT_ID+2) 68075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 69075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#define NO_STATUS 1 70075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker#define NO_STATUS_EXIT 2 71075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 72075ad800c539503d0515e5e0b4af160eccedead9Doug Zongkerstruct fuse_data { 73075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker int ffd; // file descriptor for the fuse socket 7418a78e0a162c35756628610307f41179816d3333Doug Zongker 7518a78e0a162c35756628610307f41179816d3333Doug Zongker struct provider_vtab* vtab; 7618a78e0a162c35756628610307f41179816d3333Doug Zongker void* cookie; 77075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 78075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker uint64_t file_size; // bytes 79075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 80075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker uint32_t block_size; // block size that the adb host is using to send the file to us 81075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker uint32_t file_blocks; // file size in block_size blocks 82075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 83075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker uid_t uid; 84075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker gid_t gid; 85075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 86075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker uint32_t curr_block; // cache the block most recently read from the host 87075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker uint8_t* block_data; 88075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 89075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker uint8_t* extra_block; // another block of storage for reads that 90075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // span two blocks 91075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 92075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker uint8_t* hashes; // SHA-256 hash of each block (all zeros 93075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // if block hasn't been read yet) 94075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker}; 95075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 96075ad800c539503d0515e5e0b4af160eccedead9Doug Zongkerstatic void fuse_reply(struct fuse_data* fd, __u64 unique, const void *data, size_t len) 97075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker{ 98075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker struct fuse_out_header hdr; 99075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker struct iovec vec[2]; 100075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker int res; 101075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 102075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker hdr.len = len + sizeof(hdr); 103075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker hdr.error = 0; 104075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker hdr.unique = unique; 105075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 106075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker vec[0].iov_base = &hdr; 107075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker vec[0].iov_len = sizeof(hdr); 108075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker vec[1].iov_base = data; 109075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker vec[1].iov_len = len; 110075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 111075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker res = writev(fd->ffd, vec, 2); 112075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (res < 0) { 113075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker printf("*** REPLY FAILED *** %d\n", errno); 114075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 115075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker} 116075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 117075ad800c539503d0515e5e0b4af160eccedead9Doug Zongkerstatic int handle_init(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) { 118075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker const struct fuse_init_in* req = data; 119075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker struct fuse_init_out out; 120075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 121075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker out.major = FUSE_KERNEL_VERSION; 122075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker out.minor = FUSE_KERNEL_MINOR_VERSION; 123075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker out.max_readahead = req->max_readahead; 124075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker out.flags = 0; 125075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker out.max_background = 32; 126075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker out.congestion_threshold = 32; 127075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker out.max_write = 4096; 128075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fuse_reply(fd, hdr->unique, &out, sizeof(out)); 129075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 130075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return NO_STATUS; 131075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker} 132075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 133075ad800c539503d0515e5e0b4af160eccedead9Doug Zongkerstatic void fill_attr(struct fuse_attr* attr, struct fuse_data* fd, 134075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker uint64_t nodeid, uint64_t size, uint32_t mode) { 135075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker memset(attr, 0, sizeof(*attr)); 136075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker attr->nlink = 1; 137075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker attr->uid = fd->uid; 138075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker attr->gid = fd->gid; 139075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker attr->blksize = 4096; 140075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 141075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker attr->ino = nodeid; 142075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker attr->size = size; 143075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker attr->blocks = (size == 0) ? 0 : (((size-1) / attr->blksize) + 1); 144075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker attr->mode = mode; 145075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker} 146075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 147075ad800c539503d0515e5e0b4af160eccedead9Doug Zongkerstatic int handle_getattr(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) { 148075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker const struct fuse_getattr_in* req = data; 149075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker struct fuse_attr_out out; 150075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker memset(&out, 0, sizeof(out)); 151075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker out.attr_valid = 10; 152075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 153075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (hdr->nodeid == FUSE_ROOT_ID) { 154075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fill_attr(&(out.attr), fd, hdr->nodeid, 4096, S_IFDIR | 0555); 155075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } else if (hdr->nodeid == PACKAGE_FILE_ID) { 156075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fill_attr(&(out.attr), fd, PACKAGE_FILE_ID, fd->file_size, S_IFREG | 0444); 157075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } else if (hdr->nodeid == EXIT_FLAG_ID) { 158075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fill_attr(&(out.attr), fd, EXIT_FLAG_ID, 0, S_IFREG | 0); 159075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } else { 160075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return -ENOENT; 161075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 162075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 163075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fuse_reply(fd, hdr->unique, &out, sizeof(out)); 164075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return (hdr->nodeid == EXIT_FLAG_ID) ? NO_STATUS_EXIT : NO_STATUS; 165075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker} 166075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 167075ad800c539503d0515e5e0b4af160eccedead9Doug Zongkerstatic int handle_lookup(void* data, struct fuse_data* fd, 168075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker const struct fuse_in_header* hdr) { 169075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker struct fuse_entry_out out; 170075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker memset(&out, 0, sizeof(out)); 171075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker out.entry_valid = 10; 172075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker out.attr_valid = 10; 173075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 17418a78e0a162c35756628610307f41179816d3333Doug Zongker if (strncmp(FUSE_SIDELOAD_HOST_FILENAME, data, 17518a78e0a162c35756628610307f41179816d3333Doug Zongker sizeof(FUSE_SIDELOAD_HOST_FILENAME)) == 0) { 176075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker out.nodeid = PACKAGE_FILE_ID; 177075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker out.generation = PACKAGE_FILE_ID; 178075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fill_attr(&(out.attr), fd, PACKAGE_FILE_ID, fd->file_size, S_IFREG | 0444); 17918a78e0a162c35756628610307f41179816d3333Doug Zongker } else if (strncmp(FUSE_SIDELOAD_HOST_EXIT_FLAG, data, 18018a78e0a162c35756628610307f41179816d3333Doug Zongker sizeof(FUSE_SIDELOAD_HOST_EXIT_FLAG)) == 0) { 181075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker out.nodeid = EXIT_FLAG_ID; 182075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker out.generation = EXIT_FLAG_ID; 183075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fill_attr(&(out.attr), fd, EXIT_FLAG_ID, 0, S_IFREG | 0); 184075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } else { 185075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return -ENOENT; 186075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 187075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 188075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fuse_reply(fd, hdr->unique, &out, sizeof(out)); 189075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return (out.nodeid == EXIT_FLAG_ID) ? NO_STATUS_EXIT : NO_STATUS; 190075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker} 191075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 192075ad800c539503d0515e5e0b4af160eccedead9Doug Zongkerstatic int handle_open(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) { 193075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker const struct fuse_open_in* req = data; 194075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 195075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (hdr->nodeid == EXIT_FLAG_ID) return -EPERM; 196075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (hdr->nodeid != PACKAGE_FILE_ID) return -ENOENT; 197075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 198075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker struct fuse_open_out out; 199075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker memset(&out, 0, sizeof(out)); 200075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker out.fh = 10; // an arbitrary number; we always use the same handle 201075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fuse_reply(fd, hdr->unique, &out, sizeof(out)); 202075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return NO_STATUS; 203075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker} 204075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 205075ad800c539503d0515e5e0b4af160eccedead9Doug Zongkerstatic int handle_flush(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) { 206075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return 0; 207075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker} 208075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 209075ad800c539503d0515e5e0b4af160eccedead9Doug Zongkerstatic int handle_release(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) { 210075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return 0; 211075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker} 212075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 213075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// Fetch a block from the host into fd->curr_block and fd->block_data. 214075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker// Returns 0 on successful fetch, negative otherwise. 215075ad800c539503d0515e5e0b4af160eccedead9Doug Zongkerstatic int fetch_block(struct fuse_data* fd, uint32_t block) { 216075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (block == fd->curr_block) { 217075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return 0; 218075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 219075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 220075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (block >= fd->file_blocks) { 221075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker memset(fd->block_data, 0, fd->block_size); 222075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fd->curr_block = block; 223075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return 0; 224075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 225075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 226075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker size_t fetch_size = fd->block_size; 227075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (block * fd->block_size + fetch_size > fd->file_size) { 228075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // If we're reading the last (partial) block of the file, 229075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // expect a shorter response from the host, and pad the rest 230075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // of the block with zeroes. 231075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fetch_size = fd->file_size - (block * fd->block_size); 232075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker memset(fd->block_data + fetch_size, 0, fd->block_size - fetch_size); 233075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 234075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 23518a78e0a162c35756628610307f41179816d3333Doug Zongker int result = fd->vtab->read_block(fd->cookie, block, fd->block_data, fetch_size); 23618a78e0a162c35756628610307f41179816d3333Doug Zongker if (result < 0) return result; 237075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 238075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fd->curr_block = block; 239075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 240075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // Verify the hash of the block we just got from the host. 241075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // 242075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // - If the hash of the just-received data matches the stored hash 243075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // for the block, accept it. 244075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // - If the stored hash is all zeroes, store the new hash and 245075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // accept the block (this is the first time we've read this 246075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // block). 247075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // - Otherwise, return -EINVAL for the read. 248075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 249075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker uint8_t hash[SHA256_DIGEST_SIZE]; 250075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker SHA256_hash(fd->block_data, fd->block_size, hash); 251075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker uint8_t* blockhash = fd->hashes + block * SHA256_DIGEST_SIZE; 252075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (memcmp(hash, blockhash, SHA256_DIGEST_SIZE) == 0) { 253075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return 0; 254075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 255075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 256075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker int i; 257075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker for (i = 0; i < SHA256_DIGEST_SIZE; ++i) { 258075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (blockhash[i] != 0) { 259075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fd->curr_block = -1; 260075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return -EIO; 261075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 262075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 263075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 264075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker memcpy(blockhash, hash, SHA256_DIGEST_SIZE); 265075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return 0; 266075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker} 267075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 268075ad800c539503d0515e5e0b4af160eccedead9Doug Zongkerstatic int handle_read(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) { 269075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker const struct fuse_read_in* req = data; 270075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker struct fuse_out_header outhdr; 271075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker struct iovec vec[3]; 272075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker int vec_used; 273075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker int result; 274075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 275075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (hdr->nodeid != PACKAGE_FILE_ID) return -ENOENT; 276075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 277075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker uint64_t offset = req->offset; 278075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker uint32_t size = req->size; 279075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 280075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // The docs on the fuse kernel interface are vague about what to 281075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // do when a read request extends past the end of the file. We 282075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // can return a short read -- the return structure does include a 283075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // length field -- but in testing that caused the program using 284075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // the file to segfault. (I speculate that this is due to the 285075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // reading program accessing it via mmap; maybe mmap dislikes when 286075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // you return something short of a whole page?) To fix this we 287075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // zero-pad reads that extend past the end of the file so we're 288075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // always returning exactly as many bytes as were requested. 289075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // (Users of the mapped file have to know its real length anyway.) 290075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 291075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker outhdr.len = sizeof(outhdr) + size; 292075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker outhdr.error = 0; 293075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker outhdr.unique = hdr->unique; 294075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker vec[0].iov_base = &outhdr; 295075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker vec[0].iov_len = sizeof(outhdr); 296075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 297075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker uint32_t block = offset / fd->block_size; 298075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = fetch_block(fd, block); 299075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (result != 0) return result; 300075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 301075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // Two cases: 302075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // 303075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // - the read request is entirely within this block. In this 304075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // case we can reply immediately. 305075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // 306075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // - the read request goes over into the next block. Note that 307075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // since we mount the filesystem with max_read=block_size, a 308075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // read can never span more than two blocks. In this case we 309075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // copy the block to extra_block and issue a fetch for the 310075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // following block. 311075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 312075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker uint32_t block_offset = offset - (block * fd->block_size); 313075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 314075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (size + block_offset <= fd->block_size) { 315075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // First case: the read fits entirely in the first block. 316075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 317075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker vec[1].iov_base = fd->block_data + block_offset; 318075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker vec[1].iov_len = size; 319075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker vec_used = 2; 320075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } else { 321075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // Second case: the read spills over into the next block. 322075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 323075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker memcpy(fd->extra_block, fd->block_data + block_offset, 324075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fd->block_size - block_offset); 325075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker vec[1].iov_base = fd->extra_block; 326075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker vec[1].iov_len = fd->block_size - block_offset; 327075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 328075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = fetch_block(fd, block+1); 329075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (result != 0) return result; 330075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker vec[2].iov_base = fd->block_data; 331075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker vec[2].iov_len = size - vec[1].iov_len; 332075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker vec_used = 3; 333075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 334075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 335075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (writev(fd->ffd, vec, vec_used) < 0) { 336075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker printf("*** READ REPLY FAILED: %s ***\n", strerror(errno)); 337075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 338075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return NO_STATUS; 339075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker} 340075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 34118a78e0a162c35756628610307f41179816d3333Doug Zongkerint run_fuse_sideload(struct provider_vtab* vtab, void* cookie, 34218a78e0a162c35756628610307f41179816d3333Doug Zongker uint64_t file_size, uint32_t block_size) 343075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker{ 344075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker int result; 345075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 346075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // If something's already mounted on our mountpoint, try to remove 347075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker // it. (Mostly in case of a previous abnormal exit.) 34818a78e0a162c35756628610307f41179816d3333Doug Zongker umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_FORCE); 349075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 350075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (block_size < 1024) { 351075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fprintf(stderr, "block size (%u) is too small\n", block_size); 352075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return -1; 353075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 354075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (block_size > (1<<22)) { // 4 MiB 355075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fprintf(stderr, "block size (%u) is too large\n", block_size); 356075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return -1; 357075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 358075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 359075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker struct fuse_data fd; 360075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker memset(&fd, 0, sizeof(fd)); 36118a78e0a162c35756628610307f41179816d3333Doug Zongker fd.vtab = vtab; 36218a78e0a162c35756628610307f41179816d3333Doug Zongker fd.cookie = cookie; 363075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fd.file_size = file_size; 364075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fd.block_size = block_size; 365075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fd.file_blocks = (file_size == 0) ? 0 : (((file_size-1) / block_size) + 1); 366075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 367075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (fd.file_blocks > (1<<18)) { 368075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fprintf(stderr, "file has too many blocks (%u)\n", fd.file_blocks); 369075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = -1; 370075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker goto done; 371075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 372075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 373075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fd.hashes = (uint8_t*)calloc(fd.file_blocks, SHA256_DIGEST_SIZE); 374075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (fd.hashes == NULL) { 375075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fprintf(stderr, "failed to allocate %d bites for hashes\n", 376075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fd.file_blocks * SHA256_DIGEST_SIZE); 377075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = -1; 378075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker goto done; 379075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 380075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 381075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fd.uid = getuid(); 382075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fd.gid = getgid(); 383075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 384075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fd.curr_block = -1; 385075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fd.block_data = (uint8_t*)malloc(block_size); 386075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (fd.block_data == NULL) { 387075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fprintf(stderr, "failed to allocate %d bites for block_data\n", block_size); 388075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = -1; 389075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker goto done; 390075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 391075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fd.extra_block = (uint8_t*)malloc(block_size); 392075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (fd.extra_block == NULL) { 393075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fprintf(stderr, "failed to allocate %d bites for extra_block\n", block_size); 394075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = -1; 395075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker goto done; 396075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 397075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 398075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fd.ffd = open("/dev/fuse", O_RDWR); 399075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (fd.ffd < 0) { 400075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker perror("open /dev/fuse"); 401075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = -1; 402075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker goto done; 403075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 404075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 405075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker char opts[256]; 406075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker snprintf(opts, sizeof(opts), 407075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker ("fd=%d,user_id=%d,group_id=%d,max_read=%zu," 408075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker "allow_other,rootmode=040000"), 409075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fd.ffd, fd.uid, fd.gid, block_size); 410075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 41118a78e0a162c35756628610307f41179816d3333Doug Zongker result = mount("/dev/fuse", FUSE_SIDELOAD_HOST_MOUNTPOINT, 412075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker "fuse", MS_NOSUID | MS_NODEV | MS_RDONLY | MS_NOEXEC, opts); 413075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (result < 0) { 414075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker perror("mount"); 415075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker goto done; 416075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 417075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker uint8_t request_buffer[sizeof(struct fuse_in_header) + PATH_MAX*8]; 418075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker for (;;) { 419075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker ssize_t len = read(fd.ffd, request_buffer, sizeof(request_buffer)); 420075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (len < 0) { 421075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (errno != EINTR) { 422075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker perror("read request"); 423075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (errno == ENODEV) { 424075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = -1; 425075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker break; 426075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 427075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 428075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker continue; 429075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 430075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 431075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if ((size_t)len < sizeof(struct fuse_in_header)) { 432075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fprintf(stderr, "request too short: len=%zu\n", (size_t)len); 433075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker continue; 434075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 435075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 436075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker struct fuse_in_header* hdr = (struct fuse_in_header*) request_buffer; 437075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker void* data = request_buffer + sizeof(struct fuse_in_header); 438075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 439075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = -ENOSYS; 440075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 441075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker switch (hdr->opcode) { 442075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker case FUSE_INIT: 443075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = handle_init(data, &fd, hdr); 444075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker break; 445075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 446075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker case FUSE_LOOKUP: 447075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = handle_lookup(data, &fd, hdr); 448075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker break; 449075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 450075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker case FUSE_GETATTR: 451075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = handle_getattr(data, &fd, hdr); 452075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker break; 453075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 454075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker case FUSE_OPEN: 455075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = handle_open(data, &fd, hdr); 456075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker break; 457075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 458075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker case FUSE_READ: 459075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = handle_read(data, &fd, hdr); 460075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker break; 461075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 462075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker case FUSE_FLUSH: 463075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = handle_flush(data, &fd, hdr); 464075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker break; 465075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 466075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker case FUSE_RELEASE: 467075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = handle_release(data, &fd, hdr); 468075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker break; 469075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 470075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker default: 471075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker fprintf(stderr, "unknown fuse request opcode %d\n", hdr->opcode); 472075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker break; 473075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 474075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 475075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (result == NO_STATUS_EXIT) { 476075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker result = 0; 477075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker break; 478075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 479075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 480075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (result != NO_STATUS) { 481075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker struct fuse_out_header outhdr; 482075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker outhdr.len = sizeof(outhdr); 483075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker outhdr.error = result; 484075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker outhdr.unique = hdr->unique; 485075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker write(fd.ffd, &outhdr, sizeof(outhdr)); 486075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 487075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 488075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 489075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker done: 49018a78e0a162c35756628610307f41179816d3333Doug Zongker fd.vtab->close(fd.cookie); 49118a78e0a162c35756628610307f41179816d3333Doug Zongker 49218a78e0a162c35756628610307f41179816d3333Doug Zongker result = umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_DETACH); 493075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (result < 0) { 494075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker printf("fuse_sideload umount failed: %s\n", strerror(errno)); 495075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker } 496075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 497075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker if (fd.ffd) close(fd.ffd); 498075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker free(fd.hashes); 499075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker free(fd.block_data); 500075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker free(fd.extra_block); 501075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker 502075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker return result; 503075ad800c539503d0515e5e0b4af160eccedead9Doug Zongker} 504