entry-writer.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. module.exports = EntryWriter
  2. var tar = require("../tar.js")
  3. , TarHeader = require("./header.js")
  4. , Entry = require("./entry.js")
  5. , inherits = require("inherits")
  6. , BlockStream = require("block-stream")
  7. , ExtendedHeaderWriter
  8. , Stream = require("stream").Stream
  9. , EOF = {}
  10. inherits(EntryWriter, Stream)
  11. function EntryWriter (props) {
  12. var me = this
  13. if (!(me instanceof EntryWriter)) {
  14. return new EntryWriter(props)
  15. }
  16. Stream.apply(this)
  17. me.writable = true
  18. me.readable = true
  19. me._stream = new BlockStream(512)
  20. me._stream.on("data", function (c) {
  21. me.emit("data", c)
  22. })
  23. me._stream.on("drain", function () {
  24. me.emit("drain")
  25. })
  26. me._stream.on("end", function () {
  27. me.emit("end")
  28. me.emit("close")
  29. })
  30. me.props = props
  31. if (props.type === "Directory") {
  32. props.size = 0
  33. }
  34. props.ustar = "ustar\0"
  35. props.ustarver = "00"
  36. me.path = props.path
  37. me._buffer = []
  38. me._didHeader = false
  39. me._meta = false
  40. me.on("pipe", function () {
  41. me._process()
  42. })
  43. }
  44. EntryWriter.prototype.write = function (c) {
  45. // console.error(".. ew write")
  46. if (this._ended) return this.emit("error", new Error("write after end"))
  47. this._buffer.push(c)
  48. this._process()
  49. this._needDrain = this._buffer.length > 0
  50. return !this._needDrain
  51. }
  52. EntryWriter.prototype.end = function (c) {
  53. // console.error(".. ew end")
  54. if (c) this._buffer.push(c)
  55. this._buffer.push(EOF)
  56. this._ended = true
  57. this._process()
  58. this._needDrain = this._buffer.length > 0
  59. }
  60. EntryWriter.prototype.pause = function () {
  61. // console.error(".. ew pause")
  62. this._paused = true
  63. this.emit("pause")
  64. }
  65. EntryWriter.prototype.resume = function () {
  66. // console.error(".. ew resume")
  67. this._paused = false
  68. this.emit("resume")
  69. this._process()
  70. }
  71. EntryWriter.prototype.add = function (entry) {
  72. // console.error(".. ew add")
  73. if (!this.parent) return this.emit("error", new Error("no parent"))
  74. // make sure that the _header and such is emitted, and clear out
  75. // the _currentEntry link on the parent.
  76. if (!this._ended) this.end()
  77. return this.parent.add(entry)
  78. }
  79. EntryWriter.prototype._header = function () {
  80. // console.error(".. ew header")
  81. if (this._didHeader) return
  82. this._didHeader = true
  83. var headerBlock = TarHeader.encode(this.props)
  84. if (this.props.needExtended && !this._meta) {
  85. var me = this
  86. ExtendedHeaderWriter = ExtendedHeaderWriter ||
  87. require("./extended-header-writer.js")
  88. ExtendedHeaderWriter(this.props)
  89. .on("data", function (c) {
  90. me.emit("data", c)
  91. })
  92. .on("error", function (er) {
  93. me.emit("error", er)
  94. })
  95. .end()
  96. }
  97. // console.error(".. .. ew headerBlock emitting")
  98. this.emit("data", headerBlock)
  99. this.emit("header")
  100. }
  101. EntryWriter.prototype._process = function () {
  102. // console.error(".. .. ew process")
  103. if (!this._didHeader && !this._meta) {
  104. this._header()
  105. }
  106. if (this._paused || this._processing) {
  107. // console.error(".. .. .. paused=%j, processing=%j", this._paused, this._processing)
  108. return
  109. }
  110. this._processing = true
  111. var buf = this._buffer
  112. for (var i = 0; i < buf.length; i ++) {
  113. // console.error(".. .. .. i=%d", i)
  114. var c = buf[i]
  115. if (c === EOF) this._stream.end()
  116. else this._stream.write(c)
  117. if (this._paused) {
  118. // console.error(".. .. .. paused mid-emission")
  119. this._processing = false
  120. if (i < buf.length) {
  121. this._needDrain = true
  122. this._buffer = buf.slice(i + 1)
  123. }
  124. return
  125. }
  126. }
  127. // console.error(".. .. .. emitted")
  128. this._buffer.length = 0
  129. this._processing = false
  130. // console.error(".. .. .. emitting drain")
  131. this.emit("drain")
  132. }
  133. EntryWriter.prototype.destroy = function () {}