mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
b503616295
# ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D36056 --HG-- extra : source : 2616392f26053ee376b9126fbca696de5d4bb15b
222 lines
6.2 KiB
JavaScript
222 lines
6.2 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
var EXPORTED_SYMBOLS = ["ZipUtils"];
|
|
|
|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|
|
|
ChromeUtils.defineModuleGetter(
|
|
this,
|
|
"FileUtils",
|
|
"resource://gre/modules/FileUtils.jsm"
|
|
);
|
|
ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
|
|
|
|
// The maximum amount of file data to buffer at a time during file extraction
|
|
const EXTRACTION_BUFFER = 1024 * 512;
|
|
|
|
/**
|
|
* Asynchronously writes data from an nsIInputStream to an OS.File instance.
|
|
* The source stream and OS.File are closed regardless of whether the operation
|
|
* succeeds or fails.
|
|
* Returns a promise that will be resolved when complete.
|
|
*
|
|
* @param aPath
|
|
* The name of the file being extracted for logging purposes.
|
|
* @param aStream
|
|
* The source nsIInputStream.
|
|
* @param aFile
|
|
* The open OS.File instance to write to.
|
|
*/
|
|
function saveStreamAsync(aPath, aStream, aFile) {
|
|
return new Promise((resolve, reject) => {
|
|
// Read the input stream on a background thread
|
|
let sts = Cc["@mozilla.org/network/stream-transport-service;1"].getService(
|
|
Ci.nsIStreamTransportService
|
|
);
|
|
let transport = sts.createInputTransport(aStream, true);
|
|
let input = transport
|
|
.openInputStream(0, 0, 0)
|
|
.QueryInterface(Ci.nsIAsyncInputStream);
|
|
let source = Cc["@mozilla.org/binaryinputstream;1"].createInstance(
|
|
Ci.nsIBinaryInputStream
|
|
);
|
|
source.setInputStream(input);
|
|
|
|
function readFailed(error) {
|
|
try {
|
|
aStream.close();
|
|
} catch (e) {
|
|
Cu.reportError("Failed to close JAR stream for " + aPath);
|
|
}
|
|
|
|
aFile.close().then(
|
|
function() {
|
|
reject(error);
|
|
},
|
|
function(e) {
|
|
Cu.reportError("Failed to close file for " + aPath);
|
|
reject(error);
|
|
}
|
|
);
|
|
}
|
|
|
|
function readData() {
|
|
try {
|
|
let count = Math.min(source.available(), EXTRACTION_BUFFER);
|
|
let data = new Uint8Array(count);
|
|
source.readArrayBuffer(count, data.buffer);
|
|
|
|
aFile.write(data, { bytes: count }).then(function() {
|
|
input.asyncWait(readData, 0, 0, Services.tm.currentThread);
|
|
}, readFailed);
|
|
} catch (e) {
|
|
if (e.result == Cr.NS_BASE_STREAM_CLOSED) {
|
|
resolve(aFile.close());
|
|
} else {
|
|
readFailed(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
input.asyncWait(readData, 0, 0, Services.tm.currentThread);
|
|
});
|
|
}
|
|
|
|
var ZipUtils = {
|
|
/**
|
|
* Asynchronously extracts files from a ZIP file into a directory.
|
|
* Returns a promise that will be resolved when the extraction is complete.
|
|
*
|
|
* @param aZipFile
|
|
* The source ZIP file that contains the add-on.
|
|
* @param aDir
|
|
* The nsIFile to extract to.
|
|
*/
|
|
extractFilesAsync: function ZipUtils_extractFilesAsync(aZipFile, aDir) {
|
|
let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].createInstance(
|
|
Ci.nsIZipReader
|
|
);
|
|
|
|
try {
|
|
zipReader.open(aZipFile);
|
|
} catch (e) {
|
|
return Promise.reject(e);
|
|
}
|
|
|
|
return (async function() {
|
|
// Get all of the entries in the zip and sort them so we create directories
|
|
// before files
|
|
let names = Array.from(zipReader.findEntries(null));
|
|
names.sort();
|
|
|
|
for (let name of names) {
|
|
let entryName = name;
|
|
let zipentry = zipReader.getEntry(name);
|
|
let path = OS.Path.join(aDir.path, ...name.split("/"));
|
|
|
|
if (zipentry.isDirectory) {
|
|
try {
|
|
await OS.File.makeDir(path);
|
|
} catch (e) {
|
|
dump(
|
|
"extractFilesAsync: failed to create directory " + path + "\n"
|
|
);
|
|
throw e;
|
|
}
|
|
} else {
|
|
let options = {
|
|
unixMode: zipentry.permissions | FileUtils.PERMS_FILE,
|
|
};
|
|
try {
|
|
let file = await OS.File.open(path, { truncate: true }, options);
|
|
if (zipentry.realSize == 0) {
|
|
await file.close();
|
|
} else {
|
|
await saveStreamAsync(
|
|
path,
|
|
zipReader.getInputStream(entryName),
|
|
file
|
|
);
|
|
}
|
|
} catch (e) {
|
|
dump("extractFilesAsync: failed to extract file " + path + "\n");
|
|
throw e;
|
|
}
|
|
}
|
|
}
|
|
|
|
zipReader.close();
|
|
})().catch(e => {
|
|
zipReader.close();
|
|
throw e;
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Extracts files from a ZIP file into a directory.
|
|
*
|
|
* @param aZipFile
|
|
* The source ZIP file that contains the add-on.
|
|
* @param aDir
|
|
* The nsIFile to extract to.
|
|
*/
|
|
extractFiles: function ZipUtils_extractFiles(aZipFile, aDir) {
|
|
function getTargetFile(aDir, entry) {
|
|
let target = aDir.clone();
|
|
entry.split("/").forEach(function(aPart) {
|
|
target.append(aPart);
|
|
});
|
|
return target;
|
|
}
|
|
|
|
let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].createInstance(
|
|
Ci.nsIZipReader
|
|
);
|
|
zipReader.open(aZipFile);
|
|
|
|
try {
|
|
// create directories first
|
|
for (let entryName of zipReader.findEntries("*/")) {
|
|
let target = getTargetFile(aDir, entryName);
|
|
if (!target.exists()) {
|
|
try {
|
|
target.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
|
|
} catch (e) {
|
|
dump(
|
|
"extractFiles: failed to create target directory for extraction file = " +
|
|
target.path +
|
|
"\n"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (let entryName of zipReader.findEntries(null)) {
|
|
let target = getTargetFile(aDir, entryName);
|
|
if (target.exists()) {
|
|
continue;
|
|
}
|
|
|
|
zipReader.extract(entryName, target);
|
|
try {
|
|
target.permissions |= FileUtils.PERMS_FILE;
|
|
} catch (e) {
|
|
dump(
|
|
"Failed to set permissions " +
|
|
FileUtils.PERMS_FILE.toString(8) +
|
|
" on " +
|
|
target.path +
|
|
" " +
|
|
e +
|
|
"\n"
|
|
);
|
|
}
|
|
}
|
|
} finally {
|
|
zipReader.close();
|
|
}
|
|
},
|
|
};
|