refactor fuse sideloading code

Split the adb-specific portions (fetching a block from the adb host
and closing the connections) out from the rest of the FUSE filesystem
code, so that we can reuse the fuse stuff for installing off sdcards
as well.

Change-Id: I0ba385fd35999c5f5cad27842bc82024a264dd14
diff --git a/Android.mk b/Android.mk
index 1165acb..f469182 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,6 +17,18 @@
 
 include $(CLEAR_VARS)
 
+LOCAL_SRC_FILES := fuse_sideload.c
+
+LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
+LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
+
+LOCAL_MODULE := libfusesideload
+
+LOCAL_STATIC_LIBRARIES := libcutils libc libmincrypt
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
 LOCAL_SRC_FILES := \
     recovery.cpp \
     bootloader.cpp \
@@ -49,6 +61,7 @@
     libmtdutils \
     libmincrypt \
     libminadbd \
+    libfusesideload \
     libminui \
     libpng \
     libfs_mgr \
diff --git a/adb_install.cpp b/adb_install.cpp
index fb7860c..be3b9a0 100644
--- a/adb_install.cpp
+++ b/adb_install.cpp
@@ -31,7 +31,8 @@
 #include "common.h"
 #include "adb_install.h"
 extern "C" {
-#include "minadbd/adb.h"
+#include "minadbd/fuse_adb_provider.h"
+#include "fuse_sideload.h"
 }
 
 static RecoveryUI* ui = NULL;
@@ -89,7 +90,7 @@
         _exit(-1);
     }
 
-    // ADB_SIDELOAD_HOST_PATHNAME will start to exist once the host
+    // FUSE_SIDELOAD_HOST_PATHNAME will start to exist once the host
     // connects and starts serving a package.  Poll for its
     // appearance.  (Note that inotify doesn't work with FUSE.)
     int result;
@@ -103,7 +104,7 @@
             break;
         }
 
-        if (stat(ADB_SIDELOAD_HOST_PATHNAME, &st) != 0) {
+        if (stat(FUSE_SIDELOAD_HOST_PATHNAME, &st) != 0) {
             if (errno == ENOENT && i < ADB_INSTALL_TIMEOUT-1) {
                 sleep(1);
                 continue;
@@ -114,14 +115,14 @@
                 break;
             }
         }
-        result = install_package(ADB_SIDELOAD_HOST_PATHNAME, wipe_cache, install_file, false);
+        result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache, install_file, false);
         break;
     }
 
     if (!waited) {
         // Calling stat() on this magic filename signals the minadbd
         // subprocess to shut down.
-        stat(ADB_SIDELOAD_HOST_EXIT_PATHNAME, &st);
+        stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st);
 
         // TODO(dougz): there should be a way to cancel waiting for a
         // package (by pushing some button combo on the device).  For now
diff --git a/minadbd/fuse_sideload.c b/fuse_sideload.c
similarity index 93%
rename from minadbd/fuse_sideload.c
rename to fuse_sideload.c
index def068e..ab91def 100644
--- a/minadbd/fuse_sideload.c
+++ b/fuse_sideload.c
@@ -60,9 +60,8 @@
 #include <sys/uio.h>
 #include <unistd.h>
 
-#include "transport.h"
-#include "adb.h"
 #include "mincrypt/sha256.h"
+#include "fuse_sideload.h"
 
 #define PACKAGE_FILE_ID   (FUSE_ROOT_ID+1)
 #define EXIT_FLAG_ID      (FUSE_ROOT_ID+2)
@@ -72,7 +71,9 @@
 
 struct fuse_data {
     int ffd;   // file descriptor for the fuse socket
-    int sfd;   // file descriptor for the adb channel
+
+    struct provider_vtab* vtab;
+    void* cookie;
 
     uint64_t file_size;     // bytes
 
@@ -170,13 +171,13 @@
     out.entry_valid = 10;
     out.attr_valid = 10;
 
-    if (strncmp(ADB_SIDELOAD_HOST_FILENAME, data,
-                sizeof(ADB_SIDELOAD_HOST_FILENAME)) == 0) {
+    if (strncmp(FUSE_SIDELOAD_HOST_FILENAME, data,
+                sizeof(FUSE_SIDELOAD_HOST_FILENAME)) == 0) {
         out.nodeid = PACKAGE_FILE_ID;
         out.generation = PACKAGE_FILE_ID;
         fill_attr(&(out.attr), fd, PACKAGE_FILE_ID, fd->file_size, S_IFREG | 0444);
-    } else if (strncmp(ADB_SIDELOAD_HOST_EXIT_FLAG, data,
-                       sizeof(ADB_SIDELOAD_HOST_EXIT_FLAG)) == 0) {
+    } else if (strncmp(FUSE_SIDELOAD_HOST_EXIT_FLAG, data,
+                       sizeof(FUSE_SIDELOAD_HOST_EXIT_FLAG)) == 0) {
         out.nodeid = EXIT_FLAG_ID;
         out.generation = EXIT_FLAG_ID;
         fill_attr(&(out.attr), fd, EXIT_FLAG_ID, 0, S_IFREG | 0);
@@ -231,17 +232,8 @@
         memset(fd->block_data + fetch_size, 0, fd->block_size - fetch_size);
     }
 
-    char buf[10];
-    snprintf(buf, sizeof(buf), "%08u", block);
-    if (writex(fd->sfd, buf, 8) < 0) {
-        fprintf(stderr, "failed to write to adb host: %s\n", strerror(errno));
-        return -EIO;
-    }
-
-    if (readx(fd->sfd, fd->block_data, fetch_size) < 0) {
-        fprintf(stderr, "failed to read from adb host: %s\n", strerror(errno));
-        return -EIO;
-    }
+    int result = fd->vtab->read_block(fd->cookie, block, fd->block_data, fetch_size);
+    if (result < 0) return result;
 
     fd->curr_block = block;
 
@@ -346,13 +338,14 @@
     return NO_STATUS;
 }
 
-int run_fuse(int sfd, uint64_t file_size, uint32_t block_size)
+int run_fuse_sideload(struct provider_vtab* vtab, void* cookie,
+                      uint64_t file_size, uint32_t block_size)
 {
     int result;
 
     // If something's already mounted on our mountpoint, try to remove
     // it.  (Mostly in case of a previous abnormal exit.)
-    umount2(ADB_SIDELOAD_HOST_MOUNTPOINT, MNT_FORCE);
+    umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_FORCE);
 
     if (block_size < 1024) {
         fprintf(stderr, "block size (%u) is too small\n", block_size);
@@ -365,7 +358,8 @@
 
     struct fuse_data fd;
     memset(&fd, 0, sizeof(fd));
-    fd.sfd = sfd;
+    fd.vtab = vtab;
+    fd.cookie = cookie;
     fd.file_size = file_size;
     fd.block_size = block_size;
     fd.file_blocks = (file_size == 0) ? 0 : (((file_size-1) / block_size) + 1);
@@ -414,7 +408,7 @@
               "allow_other,rootmode=040000"),
              fd.ffd, fd.uid, fd.gid, block_size);
 
-    result = mount("/dev/fuse", ADB_SIDELOAD_HOST_MOUNTPOINT,
+    result = mount("/dev/fuse", FUSE_SIDELOAD_HOST_MOUNTPOINT,
                    "fuse", MS_NOSUID | MS_NODEV | MS_RDONLY | MS_NOEXEC, opts);
     if (result < 0) {
         perror("mount");
@@ -493,8 +487,9 @@
     }
 
   done:
-    writex(sfd, "DONEDONE", 8);
-    result = umount2(ADB_SIDELOAD_HOST_MOUNTPOINT, MNT_DETACH);
+    fd.vtab->close(fd.cookie);
+
+    result = umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_DETACH);
     if (result < 0) {
         printf("fuse_sideload umount failed: %s\n", strerror(errno));
     }
diff --git a/fuse_sideload.h b/fuse_sideload.h
new file mode 100644
index 0000000..c0b16ef
--- /dev/null
+++ b/fuse_sideload.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#ifndef __FUSE_SIDELOAD_H
+#define __FUSE_SIDELOAD_H
+
+// define the filenames created by the sideload FUSE filesystem
+#define FUSE_SIDELOAD_HOST_MOUNTPOINT "/sideload"
+#define FUSE_SIDELOAD_HOST_FILENAME "package.zip"
+#define FUSE_SIDELOAD_HOST_PATHNAME (FUSE_SIDELOAD_HOST_MOUNTPOINT "/" FUSE_SIDELOAD_HOST_FILENAME)
+#define FUSE_SIDELOAD_HOST_EXIT_FLAG "exit"
+#define FUSE_SIDELOAD_HOST_EXIT_PATHNAME (FUSE_SIDELOAD_HOST_MOUNTPOINT "/" FUSE_SIDELOAD_HOST_EXIT_FLAG)
+
+struct provider_vtab {
+    // read a block
+    int (*read_block)(void* cookie, uint32_t block, uint8_t* buffer, uint32_t fetch_size);
+
+    // close down
+    void (*close)(void* cookie);
+};
+
+int run_fuse_sideload(struct provider_vtab* vtab, void* cookie,
+                      uint64_t file_size, uint32_t block_size);
+
+#endif
diff --git a/minadbd/Android.mk b/minadbd/Android.mk
index b5fb844..04956d8 100644
--- a/minadbd/Android.mk
+++ b/minadbd/Android.mk
@@ -13,7 +13,7 @@
 LOCAL_SRC_FILES := \
 	adb.c \
 	fdevent.c \
-	fuse_sideload.c \
+	fuse_adb_provider.c \
 	transport.c \
 	transport_usb.c \
 	sockets.c \
@@ -23,8 +23,10 @@
 
 LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
 LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
+LOCAL_C_INCLUDES += bootable/recovery
 
 LOCAL_MODULE := libminadbd
 
-LOCAL_STATIC_LIBRARIES := libcutils libc libmincrypt
+LOCAL_STATIC_LIBRARIES := libfusesideload libcutils libc
+
 include $(BUILD_STATIC_LIBRARY)
diff --git a/minadbd/adb.h b/minadbd/adb.h
index 770f34d..714868f 100644
--- a/minadbd/adb.h
+++ b/minadbd/adb.h
@@ -421,11 +421,4 @@
 int sendfailmsg(int fd, const char *reason);
 int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s);
 
-// define the filenames created by the sideload-host FUSE filesystem
-#define ADB_SIDELOAD_HOST_MOUNTPOINT "/sideload"
-#define ADB_SIDELOAD_HOST_FILENAME "package.zip"
-#define ADB_SIDELOAD_HOST_PATHNAME (ADB_SIDELOAD_HOST_MOUNTPOINT "/" ADB_SIDELOAD_HOST_FILENAME)
-#define ADB_SIDELOAD_HOST_EXIT_FLAG "exit"
-#define ADB_SIDELOAD_HOST_EXIT_PATHNAME (ADB_SIDELOAD_HOST_MOUNTPOINT "/" ADB_SIDELOAD_HOST_EXIT_FLAG)
-
 #endif
diff --git a/minadbd/fuse_adb_provider.c b/minadbd/fuse_adb_provider.c
new file mode 100644
index 0000000..f80533a
--- /dev/null
+++ b/minadbd/fuse_adb_provider.c
@@ -0,0 +1,67 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "adb.h"
+#include "fuse_sideload.h"
+
+struct adb_data {
+    int sfd;  // file descriptor for the adb channel
+
+    uint64_t file_size;
+    uint32_t block_size;
+};
+
+static int read_block_adb(void* cookie, uint32_t block, uint8_t* buffer, uint32_t fetch_size) {
+    struct adb_data* ad = (struct adb_data*)cookie;
+
+    char buf[10];
+    snprintf(buf, sizeof(buf), "%08u", block);
+    if (writex(ad->sfd, buf, 8) < 0) {
+        fprintf(stderr, "failed to write to adb host: %s\n", strerror(errno));
+        return -EIO;
+    }
+
+    if (readx(ad->sfd, buffer, fetch_size) < 0) {
+        fprintf(stderr, "failed to read from adb host: %s\n", strerror(errno));
+        return -EIO;
+    }
+
+    return 0;
+}
+
+static void close_adb(void* cookie) {
+    struct adb_data* ad = (struct adb_data*)cookie;
+
+    writex(ad->sfd, "DONEDONE", 8);
+}
+
+int run_adb_fuse(int sfd, uint64_t file_size, uint32_t block_size) {
+    struct adb_data ad;
+    struct provider_vtab vtab;
+
+    ad.sfd = sfd;
+    ad.file_size = file_size;
+    ad.block_size = block_size;
+
+    vtab.read_block = read_block_adb;
+    vtab.close = close_adb;
+
+    return run_fuse_sideload(&vtab, &ad, file_size, block_size);
+}
diff --git a/minadbd/fuse_sideload.h b/minadbd/fuse_adb_provider.h
similarity index 82%
rename from minadbd/fuse_sideload.h
rename to minadbd/fuse_adb_provider.h
index caeeec7..0eb1f79 100644
--- a/minadbd/fuse_sideload.h
+++ b/minadbd/fuse_adb_provider.h
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#ifndef __FUSE_SIDELOAD_H
-#define __FUSE_SIDELOAD_H
+#ifndef __FUSE_ADB_PROVIDER_H
+#define __FUSE_ADB_PROVIDER_H
 
-int run_fuse(int sfd, uint64_t file_size, uint32_t block_size);
+int run_adb_fuse(int sfd, uint64_t file_size, uint32_t block_size);
 
 #endif
diff --git a/minadbd/services.c b/minadbd/services.c
index bf57dc3..218b84a 100644
--- a/minadbd/services.c
+++ b/minadbd/services.c
@@ -22,7 +22,7 @@
 
 #include "sysdeps.h"
 #include "fdevent.h"
-#include "fuse_sideload.h"
+#include "fuse_adb_provider.h"
 
 #define  TRACE_TAG  TRACE_SERVICES
 #include "adb.h"
@@ -54,7 +54,7 @@
 
     printf("sideload-host file size %llu block size %lu\n", file_size, block_size);
 
-    int result = run_fuse(sfd, file_size, block_size);
+    int result = run_adb_fuse(sfd, file_size, block_size);
 
     printf("sideload_host finished\n");
     sleep(1);