toolkit/modules/ZipUtils.jsm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 this.EXPORTED_SYMBOLS = [ "ZipUtils" ];
michael@0 6
michael@0 7 const Cc = Components.classes;
michael@0 8 const Ci = Components.interfaces;
michael@0 9 const Cr = Components.results;
michael@0 10 const Cu = Components.utils;
michael@0 11
michael@0 12 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
michael@0 13 Cu.import("resource://gre/modules/Services.jsm");
michael@0 14
michael@0 15 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
michael@0 16 "resource://gre/modules/FileUtils.jsm");
michael@0 17 XPCOMUtils.defineLazyModuleGetter(this, "OS",
michael@0 18 "resource://gre/modules/osfile.jsm");
michael@0 19 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
michael@0 20 "resource://gre/modules/Promise.jsm");
michael@0 21 XPCOMUtils.defineLazyModuleGetter(this, "Task",
michael@0 22 "resource://gre/modules/Task.jsm");
michael@0 23
michael@0 24
michael@0 25 // The maximum amount of file data to buffer at a time during file extraction
michael@0 26 const EXTRACTION_BUFFER = 1024 * 512;
michael@0 27
michael@0 28
michael@0 29 /**
michael@0 30 * Asynchronously writes data from an nsIInputStream to an OS.File instance.
michael@0 31 * The source stream and OS.File are closed regardless of whether the operation
michael@0 32 * succeeds or fails.
michael@0 33 * Returns a promise that will be resolved when complete.
michael@0 34 *
michael@0 35 * @param aPath
michael@0 36 * The name of the file being extracted for logging purposes.
michael@0 37 * @param aStream
michael@0 38 * The source nsIInputStream.
michael@0 39 * @param aFile
michael@0 40 * The open OS.File instance to write to.
michael@0 41 */
michael@0 42 function saveStreamAsync(aPath, aStream, aFile) {
michael@0 43 let deferred = Promise.defer();
michael@0 44
michael@0 45 // Read the input stream on a background thread
michael@0 46 let sts = Cc["@mozilla.org/network/stream-transport-service;1"].
michael@0 47 getService(Ci.nsIStreamTransportService);
michael@0 48 let transport = sts.createInputTransport(aStream, -1, -1, true);
michael@0 49 let input = transport.openInputStream(0, 0, 0)
michael@0 50 .QueryInterface(Ci.nsIAsyncInputStream);
michael@0 51 let source = Cc["@mozilla.org/binaryinputstream;1"].
michael@0 52 createInstance(Ci.nsIBinaryInputStream);
michael@0 53 source.setInputStream(input);
michael@0 54
michael@0 55 let data = new Uint8Array(EXTRACTION_BUFFER);
michael@0 56
michael@0 57 function readFailed(error) {
michael@0 58 try {
michael@0 59 aStream.close();
michael@0 60 }
michael@0 61 catch (e) {
michael@0 62 logger.error("Failed to close JAR stream for " + aPath);
michael@0 63 }
michael@0 64
michael@0 65 aFile.close().then(function() {
michael@0 66 deferred.reject(error);
michael@0 67 }, function(e) {
michael@0 68 logger.error("Failed to close file for " + aPath);
michael@0 69 deferred.reject(error);
michael@0 70 });
michael@0 71 }
michael@0 72
michael@0 73 function readData() {
michael@0 74 try {
michael@0 75 let count = Math.min(source.available(), data.byteLength);
michael@0 76 source.readArrayBuffer(count, data.buffer);
michael@0 77
michael@0 78 aFile.write(data, { bytes: count }).then(function() {
michael@0 79 input.asyncWait(readData, 0, 0, Services.tm.currentThread);
michael@0 80 }, readFailed);
michael@0 81 }
michael@0 82 catch (e if e.result == Cr.NS_BASE_STREAM_CLOSED) {
michael@0 83 deferred.resolve(aFile.close());
michael@0 84 }
michael@0 85 catch (e) {
michael@0 86 readFailed(e);
michael@0 87 }
michael@0 88 }
michael@0 89
michael@0 90 input.asyncWait(readData, 0, 0, Services.tm.currentThread);
michael@0 91
michael@0 92 return deferred.promise;
michael@0 93 }
michael@0 94
michael@0 95
michael@0 96 this.ZipUtils = {
michael@0 97
michael@0 98 /**
michael@0 99 * Asynchronously extracts files from a ZIP file into a directory.
michael@0 100 * Returns a promise that will be resolved when the extraction is complete.
michael@0 101 *
michael@0 102 * @param aZipFile
michael@0 103 * The source ZIP file that contains the add-on.
michael@0 104 * @param aDir
michael@0 105 * The nsIFile to extract to.
michael@0 106 */
michael@0 107 extractFilesAsync: function ZipUtils_extractFilesAsync(aZipFile, aDir) {
michael@0 108 let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].
michael@0 109 createInstance(Ci.nsIZipReader);
michael@0 110
michael@0 111 try {
michael@0 112 zipReader.open(aZipFile);
michael@0 113 }
michael@0 114 catch (e) {
michael@0 115 return Promise.reject(e);
michael@0 116 }
michael@0 117
michael@0 118 return Task.spawn(function() {
michael@0 119 // Get all of the entries in the zip and sort them so we create directories
michael@0 120 // before files
michael@0 121 let entries = zipReader.findEntries(null);
michael@0 122 let names = [];
michael@0 123 while (entries.hasMore())
michael@0 124 names.push(entries.getNext());
michael@0 125 names.sort();
michael@0 126
michael@0 127 for (let name of names) {
michael@0 128 let entryName = name;
michael@0 129 let zipentry = zipReader.getEntry(name);
michael@0 130 let path = OS.Path.join(aDir.path, ...name.split("/"));
michael@0 131
michael@0 132 if (zipentry.isDirectory) {
michael@0 133 try {
michael@0 134 yield OS.File.makeDir(path);
michael@0 135 }
michael@0 136 catch (e) {
michael@0 137 dump("extractFilesAsync: failed to create directory " + path + "\n");
michael@0 138 throw e;
michael@0 139 }
michael@0 140 }
michael@0 141 else {
michael@0 142 let options = { unixMode: zipentry.permissions | FileUtils.PERMS_FILE };
michael@0 143 try {
michael@0 144 let file = yield OS.File.open(path, { truncate: true }, options);
michael@0 145 if (zipentry.realSize == 0)
michael@0 146 yield file.close();
michael@0 147 else
michael@0 148 yield saveStreamAsync(path, zipReader.getInputStream(entryName), file);
michael@0 149 }
michael@0 150 catch (e) {
michael@0 151 dump("extractFilesAsync: failed to extract file " + path + "\n");
michael@0 152 throw e;
michael@0 153 }
michael@0 154 }
michael@0 155 }
michael@0 156
michael@0 157 zipReader.close();
michael@0 158 }).then(null, (e) => {
michael@0 159 zipReader.close();
michael@0 160 throw e;
michael@0 161 });
michael@0 162 },
michael@0 163
michael@0 164 /**
michael@0 165 * Extracts files from a ZIP file into a directory.
michael@0 166 *
michael@0 167 * @param aZipFile
michael@0 168 * The source ZIP file that contains the add-on.
michael@0 169 * @param aDir
michael@0 170 * The nsIFile to extract to.
michael@0 171 */
michael@0 172 extractFiles: function ZipUtils_extractFiles(aZipFile, aDir) {
michael@0 173 function getTargetFile(aDir, entry) {
michael@0 174 let target = aDir.clone();
michael@0 175 entry.split("/").forEach(function(aPart) {
michael@0 176 target.append(aPart);
michael@0 177 });
michael@0 178 return target;
michael@0 179 }
michael@0 180
michael@0 181 let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].
michael@0 182 createInstance(Ci.nsIZipReader);
michael@0 183 zipReader.open(aZipFile);
michael@0 184
michael@0 185 try {
michael@0 186 // create directories first
michael@0 187 let entries = zipReader.findEntries("*/");
michael@0 188 while (entries.hasMore()) {
michael@0 189 let entryName = entries.getNext();
michael@0 190 let target = getTargetFile(aDir, entryName);
michael@0 191 if (!target.exists()) {
michael@0 192 try {
michael@0 193 target.create(Ci.nsIFile.DIRECTORY_TYPE,
michael@0 194 FileUtils.PERMS_DIRECTORY);
michael@0 195 }
michael@0 196 catch (e) {
michael@0 197 dump("extractFiles: failed to create target directory for extraction file = " + target.path + "\n");
michael@0 198 }
michael@0 199 }
michael@0 200 }
michael@0 201
michael@0 202 entries = zipReader.findEntries(null);
michael@0 203 while (entries.hasMore()) {
michael@0 204 let entryName = entries.getNext();
michael@0 205 let target = getTargetFile(aDir, entryName);
michael@0 206 if (target.exists())
michael@0 207 continue;
michael@0 208
michael@0 209 zipReader.extract(entryName, target);
michael@0 210 try {
michael@0 211 target.permissions |= FileUtils.PERMS_FILE;
michael@0 212 }
michael@0 213 catch (e) {
michael@0 214 dump("Failed to set permissions " + aPermissions.toString(8) + " on " + target.path + "\n");
michael@0 215 }
michael@0 216 }
michael@0 217 }
michael@0 218 finally {
michael@0 219 zipReader.close();
michael@0 220 }
michael@0 221 }
michael@0 222
michael@0 223 };

mercurial