From 41a859d9062c7877789089eaaa866090feda70f9 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Sun, 19 Jul 2015 08:40:37 -0700 Subject: recovery: Switch fuse_* to C++. Change-Id: Id50c3e6febd0ab61f10a654b9b265cf21a2d1701 (cherry picked from commit 71dc365f25676cfb3f62dbb7163697a8c3c5243d) --- fuse_sdcard_provider.cpp | 140 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 fuse_sdcard_provider.cpp (limited to 'fuse_sdcard_provider.cpp') diff --git a/fuse_sdcard_provider.cpp b/fuse_sdcard_provider.cpp new file mode 100644 index 0000000..eb6454f --- /dev/null +++ b/fuse_sdcard_provider.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fuse_sideload.h" + +struct file_data { + int fd; // the underlying sdcard file + + uint64_t file_size; + uint32_t block_size; +}; + +static int read_block_file(void* cookie, uint32_t block, uint8_t* buffer, uint32_t fetch_size) { + file_data* fd = reinterpret_cast(cookie); + + off64_t offset = ((off64_t) block) * fd->block_size; + if (TEMP_FAILURE_RETRY(lseek64(fd->fd, offset, SEEK_SET)) == -1) { + fprintf(stderr, "seek on sdcard failed: %s\n", strerror(errno)); + return -EIO; + } + + while (fetch_size > 0) { + ssize_t r = TEMP_FAILURE_RETRY(read(fd->fd, buffer, fetch_size)); + if (r == -1) { + fprintf(stderr, "read on sdcard failed: %s\n", strerror(errno)); + return -EIO; + } + fetch_size -= r; + buffer += r; + } + + return 0; +} + +static void close_file(void* cookie) { + file_data* fd = reinterpret_cast(cookie); + close(fd->fd); +} + +struct token { + pthread_t th; + const char* path; + int result; +}; + +static void* run_sdcard_fuse(void* cookie) { + token* t = reinterpret_cast(cookie); + + struct stat sb; + if (stat(t->path, &sb) < 0) { + fprintf(stderr, "failed to stat %s: %s\n", t->path, strerror(errno)); + t->result = -1; + return NULL; + } + + struct file_data fd; + struct provider_vtab vtab; + + fd.fd = open(t->path, O_RDONLY); + if (fd.fd < 0) { + fprintf(stderr, "failed to open %s: %s\n", t->path, strerror(errno)); + t->result = -1; + return NULL; + } + fd.file_size = sb.st_size; + fd.block_size = 65536; + + vtab.read_block = read_block_file; + vtab.close = close_file; + + t->result = run_fuse_sideload(&vtab, &fd, fd.file_size, fd.block_size); + return NULL; +} + +// How long (in seconds) we wait for the fuse-provided package file to +// appear, before timing out. +#define SDCARD_INSTALL_TIMEOUT 10 + +void* start_sdcard_fuse(const char* path) { + token* t = new token; + + t->path = path; + pthread_create(&(t->th), NULL, run_sdcard_fuse, t); + + struct stat st; + int i; + for (i = 0; i < SDCARD_INSTALL_TIMEOUT; ++i) { + if (stat(FUSE_SIDELOAD_HOST_PATHNAME, &st) != 0) { + if (errno == ENOENT && i < SDCARD_INSTALL_TIMEOUT-1) { + sleep(1); + continue; + } else { + return NULL; + } + } + } + + // The installation process expects to find the sdcard unmounted. + // Unmount it with MNT_DETACH so that our open file continues to + // work but new references see it as unmounted. + umount2("/sdcard", MNT_DETACH); + + return t; +} + +void finish_sdcard_fuse(void* cookie) { + if (cookie == NULL) return; + token* t = reinterpret_cast(cookie); + + // Calling stat() on this magic filename signals the fuse + // filesystem to shut down. + struct stat st; + stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st); + + pthread_join(t->th, NULL); + delete t; +} -- cgit v1.1