Blame view

node_modules/tar/lib/extended-header-writer.js 5.2 KB
aaac7fed   liuqimichale   add
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]
  }