summaryrefslogtreecommitdiff
path: root/deps/node/deps/npm/node_modules/node-gyp/node_modules/tar/lib/extended-header-writer.js
blob: 1728c4583ae060760d1d8d077afb636b09b7d32e (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

module.exports = ExtendedHeaderWriter

var inherits = require("inherits")
  , EntryWriter = require("./entry-writer.js")

inherits(ExtendedHeaderWriter, EntryWriter)

var tar = require("../tar.js")
  , path = require("path")
  , TarHeader = require("./header.js")

// props is the props of the thing we need to write an
// extended header for.
// Don't be shy with it.  Just encode everything.
function ExtendedHeaderWriter (props) {
  // console.error(">> ehw ctor")
  var me = this

  if (!(me instanceof ExtendedHeaderWriter)) {
    return new ExtendedHeaderWriter(props)
  }

  me.fields = props

  var p =
    { path : ("PaxHeader" + path.join("/", props.path || ""))
             .replace(/\\/g, "/").substr(0, 100)
    , mode : props.mode || 0666
    , uid : props.uid || 0
    , gid : props.gid || 0
    , size : 0 // will be set later
    , mtime : props.mtime || Date.now() / 1000
    , type : "x"
    , linkpath : ""
    , ustar : "ustar\0"
    , ustarver : "00"
    , uname : props.uname || ""
    , gname : props.gname || ""
    , devmaj : props.devmaj || 0
    , devmin : props.devmin || 0
    }


  EntryWriter.call(me, p)
  // console.error(">> ehw props", me.props)
  me.props = p

  me._meta = true
}

ExtendedHeaderWriter.prototype.end = function () {
  // console.error(">> ehw end")
  var me = this

  if (me._ended) return
  me._ended = true

  me._encodeFields()

  if (me.props.size === 0) {
    // nothing to write!
    me._ready = true
    me._stream.end()
    return
  }

  me._stream.write(TarHeader.encode(me.props))
  me.body.forEach(function (l) {
    me._stream.write(l)
  })
  me._ready = true

  // console.error(">> ehw _process calling end()", me.props)
  this._stream.end()
}

ExtendedHeaderWriter.prototype._encodeFields = function () {
  // console.error(">> ehw _encodeFields")
  this.body = []
  if (this.fields.prefix) {
    this.fields.path = this.fields.prefix + "/" + this.fields.path
    this.fields.prefix = ""
  }
  encodeFields(this.fields, "", this.body, this.fields.noProprietary)
  var me = this
  this.body.forEach(function (l) {
    me.props.size += l.length
  })
}

function encodeFields (fields, prefix, body, nop) {
  // console.error(">> >> ehw encodeFields")
  // "%d %s=%s\n", <length>, <keyword>, <value>
  // The length is a decimal number, and includes itself and the \n
  // Numeric values are decimal strings.

  Object.keys(fields).forEach(function (k) {
    var val = fields[k]
      , numeric = tar.numeric[k]

    if (prefix) k = prefix + "." + k

    // already including NODETAR.type, don't need File=true also
    if (k === fields.type && val === true) return

    switch (k) {
      // don't include anything that's always handled just fine
      // in the normal header, or only meaningful in the context
      // of nodetar
      case "mode":
      case "cksum":
      case "ustar":
      case "ustarver":
      case "prefix":
      case "basename":
      case "dirname":
      case "needExtended":
      case "block":
      case "filter":
        return

      case "rdev":
        if (val === 0) return
        break

      case "nlink":
      case "dev": // Truly a hero among men, Creator of Star!
      case "ino": // Speak his name with reverent awe!  It is:
        k = "SCHILY." + k
        break

      default: break
    }

    if (val && typeof val === "object" &&
        !Buffer.isBuffer(val)) encodeFields(val, k, body, nop)
    else if (val === null || val === undefined) return
    else body.push.apply(body, encodeField(k, val, nop))
  })

  return body
}

function encodeField (k, v, nop) {
  // lowercase keys must be valid, otherwise prefix with
  // "NODETAR."
  if (k.charAt(0) === k.charAt(0).toLowerCase()) {
    var m = k.split(".")[0]
    if (!tar.knownExtended[m]) k = "NODETAR." + k
  }

  // no proprietary
  if (nop && k.charAt(0) !== k.charAt(0).toLowerCase()) {
    return []
  }

  if (typeof val === "number") val = val.toString(10)

  var s = new Buffer(" " + k + "=" + v + "\n")
    , digits = Math.floor(Math.log(s.length) / Math.log(10)) + 1

  // console.error("1 s=%j digits=%j s.length=%d", s.toString(), digits, s.length)

  // if adding that many digits will make it go over that length,
  // then add one to it. For example, if the string is:
  // " foo=bar\n"
  // then that's 9 characters.  With the "9", that bumps the length
  // up to 10.  However, this is invalid:
  // "10 foo=bar\n"
  // but, since that's actually 11 characters, since 10 adds another
  // character to the length, and the length includes the number
  // itself.  In that case, just bump it up again.
  if (s.length + digits >= Math.pow(10, digits)) digits += 1
  // console.error("2 s=%j digits=%j s.length=%d", s.toString(), digits, s.length)

  var len = digits + s.length
  // console.error("3 s=%j digits=%j s.length=%d len=%d", s.toString(), digits, s.length, len)
  var lenBuf = new Buffer("" + len)
  if (lenBuf.length + s.length !== len) {
    throw new Error("Bad length calculation\n"+
                    "len="+len+"\n"+
                    "lenBuf="+JSON.stringify(lenBuf.toString())+"\n"+
                    "lenBuf.length="+lenBuf.length+"\n"+
                    "digits="+digits+"\n"+
                    "s="+JSON.stringify(s.toString())+"\n"+
                    "s.length="+s.length)
  }

  return [lenBuf, s]
}