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
This commit is contained in:
Doug Zongker 2010-02-01 14:40:12 -08:00
parent aa062531aa
commit 6aece33b3f
3 changed files with 114 additions and 25 deletions

View File

@ -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 {

View File

@ -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.

View File

@ -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);
}
char* zip_path;
char* dest_path;
if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
bool success = false;
if (argc == 2) {
// The two-argument version extracts to a file.
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;
char* zip_path;
char* dest_path;
if (ReadArgs(state, argv, 2, &zip_path, &dest_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 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 done2;
}
success = mzExtractZipEntryToFile(za, entry, fileno(f));
fclose(f);
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;
}
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;
}
success = mzExtractZipEntryToFile(za, entry, fileno(f));
fclose(f);
done:
free(zip_path);
free(dest_path);
return strdup(success ? "t" : "");
}