aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDoug Zongker2014-07-10 12:50:39 -0500
committerDoug Zongker2014-07-10 12:58:35 -0500
commit945fc68c62692467ddb8b7d714bcf0bf01c783c2 (patch)
tree8fcb9d928f544a13a8085c47e13e6742a3675583 /fuse_sdcard_provider.c
parent18a78e0a162c35756628610307f41179816d3333 (diff)
downloadplatform-bootable-recovery-945fc68c62692467ddb8b7d714bcf0bf01c783c2.tar.gz
platform-bootable-recovery-945fc68c62692467ddb8b7d714bcf0bf01c783c2.tar.xz
platform-bootable-recovery-945fc68c62692467ddb8b7d714bcf0bf01c783c2.zip
do sdcard sideloading through the fuse filesystem
Make a fuse filesystem that sits on top of the selected package file on the sdcard, so we can verify that the file contents don't change while being read and avoid copying the file to /tmp (that is, RAM) before verifying and installing it. Change-Id: Ifd982aa68bfe469eda5f839042648654bf7386a1
Diffstat (limited to 'fuse_sdcard_provider.c')
-rw-r--r--fuse_sdcard_provider.c141
1 files changed, 141 insertions, 0 deletions
diff --git a/fuse_sdcard_provider.c b/fuse_sdcard_provider.c
new file mode 100644
index 00000000..19fb52df
--- /dev/null
+++ b/fuse_sdcard_provider.c
@@ -0,0 +1,141 @@
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18#include <stdio.h>
19#include <errno.h>
20#include <pthread.h>
21#include <sys/mount.h>
22#include <sys/stat.h>
23#include <unistd.h>
24#include <fcntl.h>
25
26#include "fuse_sideload.h"
27
28struct file_data {
29 int fd; // the underlying sdcard file
30
31 uint64_t file_size;
32 uint32_t block_size;
33};
34
35static int read_block_file(void* cookie, uint32_t block, uint8_t* buffer, uint32_t fetch_size) {
36 struct file_data* fd = (struct file_data*)cookie;
37
38 if (lseek(fd->fd, block * fd->block_size, SEEK_SET) < 0) {
39 printf("seek on sdcard failed: %s\n", strerror(errno));
40 return -EIO;
41 }
42
43 while (fetch_size > 0) {
44 ssize_t r = read(fd->fd, buffer, fetch_size);
45 if (r < 0) {
46 if (r != -EINTR) {
47 printf("read on sdcard failed: %s\n", strerror(errno));
48 return -EIO;
49 }
50 r = 0;
51 }
52 fetch_size -= r;
53 buffer += r;
54 }
55
56 return 0;
57}
58
59static void close_file(void* cookie) {
60 struct file_data* fd = (struct file_data*)cookie;
61 close(fd->fd);
62}
63
64struct token {
65 pthread_t th;
66 const char* path;
67 int result;
68};
69
70static void* run_sdcard_fuse(void* cookie) {
71 struct token* t = (struct token*)cookie;
72
73 struct stat sb;
74 if (stat(t->path, &sb) < 0) {
75 fprintf(stderr, "failed to stat %s: %s\n", t->path, strerror(errno));
76 t->result = -1;
77 return NULL;
78 }
79
80 struct file_data fd;
81 struct provider_vtab vtab;
82
83 fd.fd = open(t->path, O_RDONLY);
84 if (fd.fd < 0) {
85 fprintf(stderr, "failed to open %s: %s\n", t->path, strerror(errno));
86 t->result = -1;
87 return NULL;
88 }
89 fd.file_size = sb.st_size;
90 fd.block_size = 65536;
91
92 vtab.read_block = read_block_file;
93 vtab.close = close_file;
94
95 t->result = run_fuse_sideload(&vtab, &fd, fd.file_size, fd.block_size);
96 return NULL;
97}
98
99// How long (in seconds) we wait for the fuse-provided package file to
100// appear, before timing out.
101#define SDCARD_INSTALL_TIMEOUT 10
102
103void* start_sdcard_fuse(const char* path) {
104 struct token* t = malloc(sizeof(struct token));
105
106 t->path = path;
107 pthread_create(&(t->th), NULL, run_sdcard_fuse, t);
108
109 struct stat st;
110 int i;
111 for (i = 0; i < SDCARD_INSTALL_TIMEOUT; ++i) {
112 if (stat(FUSE_SIDELOAD_HOST_PATHNAME, &st) != 0) {
113 if (errno == ENOENT && i < SDCARD_INSTALL_TIMEOUT-1) {
114 sleep(1);
115 continue;
116 } else {
117 return NULL;
118 }
119 }
120 }
121
122 // The installation process expects to find the sdcard unmounted.
123 // Unmount it with MNT_DETACH so that our open file continues to
124 // work but new references see it as unmounted.
125 umount2("/sdcard", MNT_DETACH);
126
127 return t;
128}
129
130void finish_sdcard_fuse(void* cookie) {
131 if (cookie == NULL) return;
132 struct token* t = (struct token*)cookie;
133
134 // Calling stat() on this magic filename signals the fuse
135 // filesystem to shut down.
136 struct stat st;
137 stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st);
138
139 pthread_join(t->th, NULL);
140 free(t);
141}