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:
parent
aa062531aa
commit
6aece33b3f
37
minzip/Zip.c
37
minzip/Zip.c
@ -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 {
|
||||
|
@ -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.
|
||||
|
@ -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" : "");
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user