Welcome to mirror list, hosted at ThFree Co, Russian Federation.

entry.js « lib « tar « node_modules « npm « deps - github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 4fc331eb9422b12e1f52109764cae423ae2b45a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
// A passthrough read/write stream that sets its properties
// based on a header, extendedHeader, and globalHeader
//
// Can be either a file system object of some sort, or
// a pax/ustar metadata entry.

module.exports = Entry

var TarHeader = require("./header.js")
  , tar = require("../tar")
  , assert = require("assert").ok
  , Stream = require("stream").Stream
  , inherits = require("inherits")
  , fstream = require("fstream").Abstract

function Entry (header, extended, global) {
  Stream.call(this)
  this.readable = true
  this.writable = true

  this._needDrain = false
  this._paused = false
  this._reading = false
  this._ending = false
  this._ended = false
  this._remaining = 0
  this._queue = []
  this._index = 0
  this._queueLen = 0

  this._read = this._read.bind(this)

  this.props = {}
  this._header = header
  this._extended = extended || {}

  // globals can change throughout the course of
  // a file parse operation.  Freeze it at its current state.
  this._global = {}
  var me = this
  Object.keys(global || {}).forEach(function (g) {
    me._global[g] = global[g]
  })

  this._setProps()
}

inherits(Entry, Stream,
{ write: function (c) {
    if (this._ending) this.error("write() after end()", null, true)
    if (this._remaining === 0) {
      this.error("invalid bytes past eof")
    }

    // often we'll get a bunch of \0 at the end of the last write,
    // since chunks will always be 512 bytes when reading a tarball.
    if (c.length > this._remaining) {
      c = c.slice(0, this._remaining)
    }
    this._remaining -= c.length

    // put it on the stack.
    var ql = this._queueLen
    this._queue.push(c)
    this._queueLen ++

    this._read()

    // either paused, or buffered
    if (this._paused || ql > 0) {
      this._needDrain = true
      return false
    }

    return true
  }

, end: function (c) {
    if (c) this.write(c)
    this._ending = true
    this._read()
  }

, pause: function () {
    this._paused = true
    this.emit("pause")
  }

, resume: function () {
    // console.error("    Tar Entry resume", this.path)
    this.emit("resume")
    this._paused = false
    this._read()
    return this._queueLen - this._index > 1
  }

  // This is bound to the instance
, _read: function () {
    // console.error("    Tar Entry _read", this.path)

    if (this._paused || this._reading || this._ended) return

    // set this flag so that event handlers don't inadvertently
    // get multiple _read() calls running.
    this._reading = true

    // have any data to emit?
    if (this._index < this._queueLen) {
      var chunk = this._queue[this._index ++]
      this.emit("data", chunk)
    }

    // check if we're drained
    if (this._index >= this._queueLen) {
      this._queue.length = this._queueLen = this._index = 0
      if (this._needDrain) {
        this._needDrain = false
        this.emit("drain")
      }
      if (this._ending) {
        this._ended = true
        this.emit("end")
      }
    }

    // if the queue gets too big, then pluck off whatever we can.
    // this should be fairly rare.
    var mql = this._maxQueueLen
    if (this._queueLen > mql && this._index > 0) {
      mql = Math.min(this._index, mql)
      this._index -= mql
      this._queueLen -= mql
      this._queue = this._queue.slice(mql)
    }

    this._reading = false
  }

, _setProps: function () {
    // props = extended->global->header->{}
    var header = this._header
      , extended = this._extended
      , global = this._global
      , props = this.props

    // first get the values from the normal header.
    var fields = tar.fields
    for (var f = 0; fields[f] !== null; f ++) {
      var field = fields[f]
        , val = header[field]
      if (typeof val !== "undefined") props[field] = val
    }

    // next, the global header for this file.
    // numeric values, etc, will have already been parsed.
    ;[global, extended].forEach(function (p) {
      Object.keys(p).forEach(function (f) {
        if (typeof p[f] !== "undefined") props[f] = p[f]
      })
    })

    // no nulls allowed in path or linkpath
    ;["path", "linkpath"].forEach(function (p) {
      if (props.hasOwnProperty(p)) {
        props[p] = props[p].split("\0")[0]
      }
    })


    // set date fields to be a proper date
    ;["mtime", "ctime", "atime"].forEach(function (p) {
      if (props.hasOwnProperty(p)) {
        props[p] = new Date(props[p] * 1000)
      }
    })

    // set the type so that we know what kind of file to create
    var type
    switch (tar.types[props.type]) {
      case "OldFile":
      case "ContiguousFile":
        type = "File"
        break

      case "GNUDumpDir":
        type = "Directory"
        break

      case undefined:
        type = "Unknown"
        break

      case "Link":
      case "SymbolicLink":
      case "CharacterDevice":
      case "BlockDevice":
      case "Directory":
      case "FIFO":
      default:
        type = tar.types[props.type]
    }

    this.type = type
    this.path = props.path
    this.size = props.size

    // size is special, since it signals when the file needs to end.
    this._remaining = props.size
  }
, warn: fstream.warn
, error: fstream.error
})