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.

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

mercurial