summaryrefslogtreecommitdiffstats
path: root/fastboot/engine.c
diff options
context:
space:
mode:
Diffstat (limited to 'fastboot/engine.c')
-rw-r--r--fastboot/engine.c132
1 files changed, 86 insertions, 46 deletions
diff --git a/fastboot/engine.c b/fastboot/engine.c
index 89cff3f..a1b6539 100644
--- a/fastboot/engine.c
+++ b/fastboot/engine.c
@@ -9,7 +9,7 @@
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
+ * the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
@@ -19,7 +19,7 @@
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
@@ -35,12 +35,17 @@
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
-#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
+#ifdef USE_MINGW
+#include <fcntl.h>
+#else
+#include <sys/mman.h>
+#endif
+
extern struct fs_info info;
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
@@ -61,7 +66,7 @@ char *mkmsg(const char *fmt, ...)
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
va_end(ap);
-
+
s = strdup(buf);
if (s == 0) die("out of memory");
return s;
@@ -77,7 +82,7 @@ typedef struct Action Action;
#define CMD_SIZE 64
-struct Action
+struct Action
{
unsigned op;
Action *next;
@@ -104,7 +109,7 @@ struct image_data {
};
void generate_ext4_image(struct image_data *image);
-void munmap_image(struct image_data *image);
+void cleanup_image(struct image_data *image);
struct generator {
char *fs_type;
@@ -122,7 +127,7 @@ struct generator {
*/
void (*cleanup)(struct image_data *image);
} generators[] = {
- { "ext4", generate_ext4_image, munmap_image }
+ { "ext4", generate_ext4_image, cleanup_image }
};
static int cb_default(Action *a, int status, char *resp)
@@ -176,9 +181,58 @@ void fb_queue_erase(const char *ptn)
a->msg = mkmsg("erasing '%s'", ptn);
}
-void munmap_image(struct image_data *image)
+/* Loads file content into buffer. Returns NULL on error. */
+static void *load_buffer(int fd, off_t size)
+{
+ void *buffer;
+
+#ifdef USE_MINGW
+ ssize_t count = 0;
+
+ // mmap is more efficient but mingw does not support it.
+ // In this case we read whole image into memory buffer.
+ buffer = malloc(size);
+ if (!buffer) {
+ perror("malloc");
+ return NULL;
+ }
+
+ lseek(fd, 0, SEEK_SET);
+ while(count < size) {
+ ssize_t actually_read = read(fd, (char*)buffer+count, size-count);
+
+ if (actually_read == 0) {
+ break;
+ }
+ if (actually_read < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ perror("read");
+ free(buffer);
+ return NULL;
+ }
+
+ count += actually_read;
+ }
+#else
+ buffer = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (buffer == MAP_FAILED) {
+ perror("mmap");
+ return NULL;
+ }
+#endif
+
+ return buffer;
+}
+
+void cleanup_image(struct image_data *image)
{
+#ifdef USE_MINGW
+ free(image->buffer);
+#else
munmap(image->buffer, image->image_size);
+#endif
}
void generate_ext4_image(struct image_data *image)
@@ -186,28 +240,35 @@ void generate_ext4_image(struct image_data *image)
int fd;
struct stat st;
+#ifdef USE_MINGW
+ /* Ideally we should use tmpfile() here, the same as with unix version.
+ * But unfortunately it is not portable as it is not clear whether this
+ * function opens file in TEXT or BINARY mode.
+ *
+ * There are also some reports it is buggy:
+ * http://pdplab.it.uom.gr/teaching/gcc_manuals/gnulib.html#tmpfile
+ * http://www.mega-nerd.com/erikd/Blog/Windiots/tmpfile.html
+ */
+ char *filename = tempnam(getenv("TEMP"), "fastboot-format.img");
+ fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
+ unlink(filename);
+#else
fd = fileno(tmpfile());
- /* reset ext4fs info so we can be called multiple times */
+#endif
reset_ext4fs_info();
info.len = image->partition_size;
- make_ext4fs_internal(fd, NULL, NULL, 0, 0, 1, 0, 0, 0);
+ make_ext4fs_internal(fd, NULL, NULL, NULL, 0, 1, 0, 0, 0, NULL);
fstat(fd, &st);
image->image_size = st.st_size;
-
- image->buffer = mmap(NULL, image->image_size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (image->buffer == MAP_FAILED) {
- perror("mmap");
- image->buffer = NULL;
- }
+ image->buffer = load_buffer(fd, st.st_size);
close(fd);
}
-int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported)
+int fb_format(Action *a, usb_handle *usb)
{
const char *partition = a->cmd;
- char query[256];
char response[FB_RESPONSE_SZ+1];
int status = 0;
struct image_data image;
@@ -217,16 +278,9 @@ int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported)
char cmd[CMD_SIZE];
response[FB_RESPONSE_SZ] = '\0';
- snprintf(query, sizeof(query), "getvar:partition-type:%s", partition);
- status = fb_command_response(usb, query, response);
+ snprintf(cmd, sizeof(cmd), "getvar:partition-type:%s", partition);
+ status = fb_command_response(usb, cmd, response);
if (status) {
- if (skip_if_not_supported) {
- fprintf(stderr,
- "Erase successful, but not automatically formatting.\n");
- fprintf(stderr,
- "Can't determine partition type.\n");
- return 0;
- }
fprintf(stderr,"FAILED (%s)\n", fb_get_error());
return status;
}
@@ -238,28 +292,15 @@ int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported)
}
}
if (!generator) {
- if (skip_if_not_supported) {
- fprintf(stderr,
- "Erase successful, but not automatically formatting.\n");
- fprintf(stderr,
- "File system type %s not supported.\n", response);
- return 0;
- }
fprintf(stderr,"Formatting is not supported for filesystem with type '%s'.\n",
response);
return -1;
}
response[FB_RESPONSE_SZ] = '\0';
- snprintf(query, sizeof(query), "getvar:partition-size:%s", partition);
- status = fb_command_response(usb, query, response);
+ snprintf(cmd, sizeof(cmd), "getvar:partition-size:%s", partition);
+ status = fb_command_response(usb, cmd, response);
if (status) {
- if (skip_if_not_supported) {
- fprintf(stderr,
- "Erase successful, but not automatically formatting.\n");
- fprintf(stderr, "Unable to get partition size\n.");
- return 0;
- }
fprintf(stderr,"FAILED (%s)\n", fb_get_error());
return status;
}
@@ -278,7 +319,7 @@ int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported)
if (status) goto cleanup;
fprintf(stderr, "writing '%s'...\n", partition);
- snprintf(cmd, CMD_SIZE, "flash:%s", partition);
+ snprintf(cmd, sizeof(cmd), "flash:%s", partition);
status = fb_command(usb, cmd);
if (status) goto cleanup;
@@ -288,12 +329,11 @@ cleanup:
return status;
}
-void fb_queue_format(const char *partition, int skip_if_not_supported)
+void fb_queue_format(const char *partition)
{
Action *a;
a = queue_action(OP_FORMAT, partition);
- a->data = (void*)skip_if_not_supported;
a->msg = mkmsg("formatting '%s' partition", partition);
}
@@ -507,7 +547,7 @@ int fb_execute_queue(usb_handle *usb)
} else if (a->op == OP_NOTICE) {
fprintf(stderr,"%s\n",(char*)a->data);
} else if (a->op == OP_FORMAT) {
- status = fb_format(a, usb, (int)a->data);
+ status = fb_format(a, usb);
status = a->func(a, status, status ? fb_get_error() : "");
if (status) break;
} else {