Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6aece33b authored by Doug Zongker's avatar Doug Zongker
Browse files

add a one-argument version of package_extract_file

Add a version of package_extract_file that returns the file data as
its return value (to be consumed by some other edify function that
expects to receive a bunch of binary data as an argument).  Lets us
avoid having two copies of a big file in memory (extracting it into
/tmp, which is a ramdisk, and then having something load it into
memory) when doing things like radio updates.

Change-Id: Ie26ece5fbae457eb0ddcd8a13d74d78a769fbc70
parent aa062531
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -810,6 +810,43 @@ bool mzExtractZipEntryToFile(const ZipArchive *pArchive,
    return true;
}

typedef struct {
    unsigned char* buffer;
    long len;
} BufferExtractCookie;

static bool bufferProcessFunction(const unsigned char *data, int dataLen,
    void *cookie) {
    BufferExtractCookie *bec = (BufferExtractCookie*)cookie;

    memmove(bec->buffer, data, dataLen);
    bec->buffer += dataLen;
    bec->len -= dataLen;

    return true;
}

/*
 * Uncompress "pEntry" in "pArchive" to buffer, which must be large
 * enough to hold mzGetZipEntryUncomplen(pEntry) bytes.
 */
bool mzExtractZipEntryToBuffer(const ZipArchive *pArchive,
    const ZipEntry *pEntry, unsigned char *buffer)
{
    BufferExtractCookie bec;
    bec.buffer = buffer;
    bec.len = mzGetZipEntryUncompLen(pEntry);

    bool ret = mzProcessZipEntryContents(pArchive, pEntry,
        bufferProcessFunction, (void*)&bec);
    if (!ret || bec.len != 0) {
        LOGE("Can't extract entry to memory buffer.\n");
        return false;
    }
    return true;
}


/* Helper state to make path translation easier and less malloc-happy.
 */
typedef struct {
+7 −0
Original line number Diff line number Diff line
@@ -168,6 +168,13 @@ bool mzIsZipEntryIntact(const ZipArchive *pArchive, const ZipEntry *pEntry);
bool mzExtractZipEntryToFile(const ZipArchive *pArchive,
    const ZipEntry *pEntry, int fd);

/*
 * Inflate and write an entry to a memory buffer, which must be long
 * enough to hold mzGetZipEntryUncomplen(pEntry) bytes.
 */
bool mzExtractZipEntryToBuffer(const ZipArchive *pArchive,
    const ZipEntry *pEntry, unsigned char* buffer);

/*
 * Inflate all entries under zipDir to the directory specified by
 * targetDir, which must exist and be a writable directory.
+69 −24
Original line number Diff line number Diff line
@@ -315,37 +315,82 @@ char* PackageExtractDirFn(const char* name, State* state,


// package_extract_file(package_path, destination_path)
//   or
// package_extract_file(package_path)
//   to return the entire contents of the file as the result of this
//   function (the char* returned points to a long giving the length
//   followed by that many bytes of data).
char* PackageExtractFileFn(const char* name, State* state,
                           int argc, Expr* argv[]) {
    if (argc != 2) {
        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
    if (argc != 1 && argc != 2) {
        return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
                          name, argc);
    }
    bool success = false;
    if (argc == 2) {
        // The two-argument version extracts to a file.

        char* zip_path;
        char* dest_path;
        if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;

    bool success = false;

        ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
        const ZipEntry* entry = mzFindZipEntry(za, zip_path);
        if (entry == NULL) {
            fprintf(stderr, "%s: no %s in package\n", name, zip_path);
        goto done;
            goto done2;
        }

        FILE* f = fopen(dest_path, "wb");
        if (f == NULL) {
            fprintf(stderr, "%s: can't open %s for write: %s\n",
                    name, dest_path, strerror(errno));
        goto done;
            goto done2;
        }
        success = mzExtractZipEntryToFile(za, entry, fileno(f));
        fclose(f);

  done:
      done2:
        free(zip_path);
        free(dest_path);
        return strdup(success ? "t" : "");
    } else {
        // The one-argument version returns the contents of the file
        // as the result.

        char* zip_path;
        char* buffer = NULL;

        if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL;

        ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
        const ZipEntry* entry = mzFindZipEntry(za, zip_path);
        if (entry == NULL) {
            fprintf(stderr, "%s: no %s in package\n", name, zip_path);
            goto done1;
        }

        long size = mzGetZipEntryUncompLen(entry);
        buffer = malloc(size + sizeof(long));
        if (buffer == NULL) {
            fprintf(stderr, "%s: failed to allocate %ld bytes for %s\n",
                    name, size+sizeof(long), zip_path);
            goto done1;
        }

        *(long *)buffer = size;
        success = mzExtractZipEntryToBuffer(
            za, entry, (unsigned char *)(buffer + sizeof(long)));

      done1:
        free(zip_path);
        if (!success) {
            free(buffer);
            buffer = malloc(sizeof(long));
            *(long *)buffer = -1L;
        }
        return buffer;
    }
}