"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/tar/lib/parse.js" (11 Apr 2017, 6954 Bytes) of package /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 
    2 // A writable stream.
    3 // It emits "entry" events, which provide a readable stream that has
    4 // header info attached.
    5 
    6 module.exports = Parse.create = Parse
    7 
    8 var stream = require("stream")
    9   , Stream = stream.Stream
   10   , BlockStream = require("block-stream")
   11   , tar = require("../tar.js")
   12   , TarHeader = require("./header.js")
   13   , Entry = require("./entry.js")
   14   , BufferEntry = require("./buffer-entry.js")
   15   , ExtendedHeader = require("./extended-header.js")
   16   , assert = require("assert").ok
   17   , inherits = require("inherits")
   18   , fstream = require("fstream")
   19 
   20 // reading a tar is a lot like reading a directory
   21 // However, we're actually not going to run the ctor,
   22 // since it does a stat and various other stuff.
   23 // This inheritance gives us the pause/resume/pipe
   24 // behavior that is desired.
   25 inherits(Parse, fstream.Reader)
   26 
   27 function Parse () {
   28   var me = this
   29   if (!(me instanceof Parse)) return new Parse()
   30 
   31   // doesn't apply fstream.Reader ctor?
   32   // no, becasue we don't want to stat/etc, we just
   33   // want to get the entry/add logic from .pipe()
   34   Stream.apply(me)
   35 
   36   me.writable = true
   37   me.readable = true
   38   me._stream = new BlockStream(512)
   39   me.position = 0
   40   me._ended = false
   41 
   42   me._stream.on("error", function (e) {
   43     me.emit("error", e)
   44   })
   45 
   46   me._stream.on("data", function (c) {
   47     me._process(c)
   48   })
   49 
   50   me._stream.on("end", function () {
   51     me._streamEnd()
   52   })
   53 
   54   me._stream.on("drain", function () {
   55     me.emit("drain")
   56   })
   57 }
   58 
   59 // overridden in Extract class, since it needs to
   60 // wait for its DirWriter part to finish before
   61 // emitting "end"
   62 Parse.prototype._streamEnd = function () {
   63   var me = this
   64   if (!me._ended || me._entry) me.error("unexpected eof")
   65   me.emit("end")
   66 }
   67 
   68 // a tar reader is actually a filter, not just a readable stream.
   69 // So, you should pipe a tarball stream into it, and it needs these
   70 // write/end methods to do that.
   71 Parse.prototype.write = function (c) {
   72   if (this._ended) {
   73     // gnutar puts a LOT of nulls at the end.
   74     // you can keep writing these things forever.
   75     // Just ignore them.
   76     for (var i = 0, l = c.length; i > l; i ++) {
   77       if (c[i] !== 0) return this.error("write() after end()")
   78     }
   79     return
   80   }
   81   return this._stream.write(c)
   82 }
   83 
   84 Parse.prototype.end = function (c) {
   85   this._ended = true
   86   return this._stream.end(c)
   87 }
   88 
   89 // don't need to do anything, since we're just
   90 // proxying the data up from the _stream.
   91 // Just need to override the parent's "Not Implemented"
   92 // error-thrower.
   93 Parse.prototype._read = function () {}
   94 
   95 Parse.prototype._process = function (c) {
   96   assert(c && c.length === 512, "block size should be 512")
   97 
   98   // one of three cases.
   99   // 1. A new header
  100   // 2. A part of a file/extended header
  101   // 3. One of two or more EOF null blocks
  102 
  103   if (this._entry) {
  104     var entry = this._entry
  105     if(!entry._abort) entry.write(c)
  106     else {
  107       entry._remaining -= c.length
  108       if(entry._remaining < 0) entry._remaining = 0
  109     }
  110     if (entry._remaining === 0) {
  111       entry.end()
  112       this._entry = null
  113     }
  114   } else {
  115     // either zeroes or a header
  116     var zero = true
  117     for (var i = 0; i < 512 && zero; i ++) {
  118       zero = c[i] === 0
  119     }
  120 
  121     // eof is *at least* 2 blocks of nulls, and then the end of the
  122     // file.  you can put blocks of nulls between entries anywhere,
  123     // so appending one tarball to another is technically valid.
  124     // ending without the eof null blocks is not allowed, however.
  125     if (zero) {
  126       if (this._eofStarted)
  127         this._ended = true
  128       this._eofStarted = true
  129     } else {
  130       this._eofStarted = false
  131       this._startEntry(c)
  132     }
  133   }
  134 
  135   this.position += 512
  136 }
  137 
  138 // take a header chunk, start the right kind of entry.
  139 Parse.prototype._startEntry = function (c) {
  140   var header = new TarHeader(c)
  141     , self = this
  142     , entry
  143     , ev
  144     , EntryType
  145     , onend
  146     , meta = false
  147 
  148   if (null === header.size || !header.cksumValid) {
  149     var e = new Error("invalid tar file")
  150     e.header = header
  151     e.tar_file_offset = this.position
  152     e.tar_block = this.position / 512
  153     return this.emit("error", e)
  154   }
  155 
  156   switch (tar.types[header.type]) {
  157     case "File":
  158     case "OldFile":
  159     case "Link":
  160     case "SymbolicLink":
  161     case "CharacterDevice":
  162     case "BlockDevice":
  163     case "Directory":
  164     case "FIFO":
  165     case "ContiguousFile":
  166     case "GNUDumpDir":
  167       // start a file.
  168       // pass in any extended headers
  169       // These ones consumers are typically most interested in.
  170       EntryType = Entry
  171       ev = "entry"
  172       break
  173 
  174     case "GlobalExtendedHeader":
  175       // extended headers that apply to the rest of the tarball
  176       EntryType = ExtendedHeader
  177       onend = function () {
  178         self._global = self._global || {}
  179         Object.keys(entry.fields).forEach(function (k) {
  180           self._global[k] = entry.fields[k]
  181         })
  182       }
  183       ev = "globalExtendedHeader"
  184       meta = true
  185       break
  186 
  187     case "ExtendedHeader":
  188     case "OldExtendedHeader":
  189       // extended headers that apply to the next entry
  190       EntryType = ExtendedHeader
  191       onend = function () {
  192         self._extended = entry.fields
  193       }
  194       ev = "extendedHeader"
  195       meta = true
  196       break
  197 
  198     case "NextFileHasLongLinkpath":
  199       // set linkpath=<contents> in extended header
  200       EntryType = BufferEntry
  201       onend = function () {
  202         self._extended = self._extended || {}
  203         self._extended.linkpath = entry.body
  204       }
  205       ev = "longLinkpath"
  206       meta = true
  207       break
  208 
  209     case "NextFileHasLongPath":
  210     case "OldGnuLongPath":
  211       // set path=<contents> in file-extended header
  212       EntryType = BufferEntry
  213       onend = function () {
  214         self._extended = self._extended || {}
  215         self._extended.path = entry.body
  216       }
  217       ev = "longPath"
  218       meta = true
  219       break
  220 
  221     default:
  222       // all the rest we skip, but still set the _entry
  223       // member, so that we can skip over their data appropriately.
  224       // emit an event to say that this is an ignored entry type?
  225       EntryType = Entry
  226       ev = "ignoredEntry"
  227       break
  228   }
  229 
  230   var global, extended
  231   if (meta) {
  232     global = extended = null
  233   } else {
  234     var global = this._global
  235     var extended = this._extended
  236 
  237     // extendedHeader only applies to one entry, so once we start
  238     // an entry, it's over.
  239     this._extended = null
  240   }
  241   entry = new EntryType(header, extended, global)
  242   entry.meta = meta
  243 
  244   // only proxy data events of normal files.
  245   if (!meta) {
  246     entry.on("data", function (c) {
  247       me.emit("data", c)
  248     })
  249   }
  250 
  251   if (onend) entry.on("end", onend)
  252 
  253   this._entry = entry
  254   var me = this
  255 
  256   entry.on("pause", function () {
  257     me.pause()
  258   })
  259 
  260   entry.on("resume", function () {
  261     me.resume()
  262   })
  263 
  264   if (this.listeners("*").length) {
  265     this.emit("*", ev, entry)
  266   }
  267 
  268   this.emit(ev, entry)
  269 
  270   // Zero-byte entry.  End immediately.
  271   if (entry.props.size === 0) {
  272     entry.end()
  273     this._entry = null
  274   }
  275 }