PageRenderTime 25ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/node_modules/hook.io/node_modules/npm/node_modules/tar/lib/entry.js

https://bitbucket.org/baldpenguin/af-node-calipso
JavaScript | 212 lines | 148 code | 36 blank | 28 comment | 23 complexity | 5b5d7afd4a28a70769cb09d26b5a3ac7 MD5 | raw file
Possible License(s): MIT, WTFPL, BSD-3-Clause, Apache-2.0, 0BSD
  1. // A passthrough read/write stream that sets its properties
  2. // based on a header, extendedHeader, and globalHeader
  3. //
  4. // Can be either a file system object of some sort, or
  5. // a pax/ustar metadata entry.
  6. module.exports = Entry
  7. var TarHeader = require("./header.js")
  8. , tar = require("../tar")
  9. , assert = require("assert").ok
  10. , Stream = require("stream").Stream
  11. , inherits = require("inherits")
  12. , fstream = require("fstream").Abstract
  13. function Entry (header, extended, global) {
  14. Stream.call(this)
  15. this.readable = true
  16. this.writable = true
  17. this._needDrain = false
  18. this._paused = false
  19. this._reading = false
  20. this._ending = false
  21. this._ended = false
  22. this._remaining = 0
  23. this._queue = []
  24. this._index = 0
  25. this._queueLen = 0
  26. this._read = this._read.bind(this)
  27. this.props = {}
  28. this._header = header
  29. this._extended = extended || {}
  30. // globals can change throughout the course of
  31. // a file parse operation. Freeze it at its current state.
  32. this._global = {}
  33. var me = this
  34. Object.keys(global || {}).forEach(function (g) {
  35. me._global[g] = global[g]
  36. })
  37. this._setProps()
  38. }
  39. inherits(Entry, Stream,
  40. { write: function (c) {
  41. if (this._ending) this.error("write() after end()", null, true)
  42. if (this._remaining === 0) {
  43. this.error("invalid bytes past eof")
  44. }
  45. // often we'll get a bunch of \0 at the end of the last write,
  46. // since chunks will always be 512 bytes when reading a tarball.
  47. if (c.length > this._remaining) {
  48. c = c.slice(0, this._remaining)
  49. }
  50. this._remaining -= c.length
  51. // put it on the stack.
  52. var ql = this._queueLen
  53. this._queue.push(c)
  54. this._queueLen ++
  55. this._read()
  56. // either paused, or buffered
  57. if (this._paused || ql > 0) {
  58. this._needDrain = true
  59. return false
  60. }
  61. return true
  62. }
  63. , end: function (c) {
  64. if (c) this.write(c)
  65. this._ending = true
  66. this._read()
  67. }
  68. , pause: function () {
  69. this._paused = true
  70. this.emit("pause")
  71. }
  72. , resume: function () {
  73. // console.error(" Tar Entry resume", this.path)
  74. this.emit("resume")
  75. this._paused = false
  76. this._read()
  77. return this._queueLen - this._index > 1
  78. }
  79. // This is bound to the instance
  80. , _read: function () {
  81. // console.error(" Tar Entry _read", this.path)
  82. if (this._paused || this._reading || this._ended) return
  83. // set this flag so that event handlers don't inadvertently
  84. // get multiple _read() calls running.
  85. this._reading = true
  86. // have any data to emit?
  87. if (this._index < this._queueLen) {
  88. var chunk = this._queue[this._index ++]
  89. this.emit("data", chunk)
  90. }
  91. // check if we're drained
  92. if (this._index >= this._queueLen) {
  93. this._queue.length = this._queueLen = this._index = 0
  94. if (this._needDrain) {
  95. this._needDrain = false
  96. this.emit("drain")
  97. }
  98. if (this._ending) {
  99. this._ended = true
  100. this.emit("end")
  101. }
  102. }
  103. // if the queue gets too big, then pluck off whatever we can.
  104. // this should be fairly rare.
  105. var mql = this._maxQueueLen
  106. if (this._queueLen > mql && this._index > 0) {
  107. mql = Math.min(this._index, mql)
  108. this._index -= mql
  109. this._queueLen -= mql
  110. this._queue = this._queue.slice(mql)
  111. }
  112. this._reading = false
  113. }
  114. , _setProps: function () {
  115. // props = extended->global->header->{}
  116. var header = this._header
  117. , extended = this._extended
  118. , global = this._global
  119. , props = this.props
  120. // first get the values from the normal header.
  121. var fields = tar.fields
  122. for (var f = 0; fields[f] !== null; f ++) {
  123. var field = fields[f]
  124. , val = header[field]
  125. if (typeof val !== "undefined") props[field] = val
  126. }
  127. // next, the global header for this file.
  128. // numeric values, etc, will have already been parsed.
  129. ;[global, extended].forEach(function (p) {
  130. Object.keys(p).forEach(function (f) {
  131. if (typeof p[f] !== "undefined") props[f] = p[f]
  132. })
  133. })
  134. // no nulls allowed in path or linkpath
  135. ;["path", "linkpath"].forEach(function (p) {
  136. if (props.hasOwnProperty(p)) {
  137. props[p] = props[p].split("\0")[0]
  138. }
  139. })
  140. // set date fields to be a proper date
  141. ;["mtime", "ctime", "atime"].forEach(function (p) {
  142. if (props.hasOwnProperty(p)) {
  143. props[p] = new Date(props[p] * 1000)
  144. }
  145. })
  146. // set the type so that we know what kind of file to create
  147. var type
  148. switch (tar.types[props.type]) {
  149. case "OldFile":
  150. case "ContiguousFile":
  151. type = "File"
  152. break
  153. case "GNUDumpDir":
  154. type = "Directory"
  155. break
  156. case undefined:
  157. type = "Unknown"
  158. break
  159. case "Link":
  160. case "SymbolicLink":
  161. case "CharacterDevice":
  162. case "BlockDevice":
  163. case "Directory":
  164. case "FIFO":
  165. default:
  166. type = tar.types[props.type]
  167. }
  168. this.type = type
  169. this.path = props.path
  170. this.size = props.size
  171. // size is special, since it signals when the file needs to end.
  172. this._remaining = props.size
  173. }
  174. , warn: fstream.warn
  175. , error: fstream.error
  176. })