Initial commit
[yaffs-website] / node_modules / tar / lib / extended-header-writer.js
1
2 module.exports = ExtendedHeaderWriter
3
4 var inherits = require("inherits")
5   , EntryWriter = require("./entry-writer.js")
6
7 inherits(ExtendedHeaderWriter, EntryWriter)
8
9 var tar = require("../tar.js")
10   , path = require("path")
11   , TarHeader = require("./header.js")
12
13 // props is the props of the thing we need to write an
14 // extended header for.
15 // Don't be shy with it.  Just encode everything.
16 function ExtendedHeaderWriter (props) {
17   // console.error(">> ehw ctor")
18   var me = this
19
20   if (!(me instanceof ExtendedHeaderWriter)) {
21     return new ExtendedHeaderWriter(props)
22   }
23
24   me.fields = props
25
26   var p =
27     { path : ("PaxHeader" + path.join("/", props.path || ""))
28              .replace(/\\/g, "/").substr(0, 100)
29     , mode : props.mode || 0666
30     , uid : props.uid || 0
31     , gid : props.gid || 0
32     , size : 0 // will be set later
33     , mtime : props.mtime || Date.now() / 1000
34     , type : "x"
35     , linkpath : ""
36     , ustar : "ustar\0"
37     , ustarver : "00"
38     , uname : props.uname || ""
39     , gname : props.gname || ""
40     , devmaj : props.devmaj || 0
41     , devmin : props.devmin || 0
42     }
43
44
45   EntryWriter.call(me, p)
46   // console.error(">> ehw props", me.props)
47   me.props = p
48
49   me._meta = true
50 }
51
52 ExtendedHeaderWriter.prototype.end = function () {
53   // console.error(">> ehw end")
54   var me = this
55
56   if (me._ended) return
57   me._ended = true
58
59   me._encodeFields()
60
61   if (me.props.size === 0) {
62     // nothing to write!
63     me._ready = true
64     me._stream.end()
65     return
66   }
67
68   me._stream.write(TarHeader.encode(me.props))
69   me.body.forEach(function (l) {
70     me._stream.write(l)
71   })
72   me._ready = true
73
74   // console.error(">> ehw _process calling end()", me.props)
75   this._stream.end()
76 }
77
78 ExtendedHeaderWriter.prototype._encodeFields = function () {
79   // console.error(">> ehw _encodeFields")
80   this.body = []
81   if (this.fields.prefix) {
82     this.fields.path = this.fields.prefix + "/" + this.fields.path
83     this.fields.prefix = ""
84   }
85   encodeFields(this.fields, "", this.body, this.fields.noProprietary)
86   var me = this
87   this.body.forEach(function (l) {
88     me.props.size += l.length
89   })
90 }
91
92 function encodeFields (fields, prefix, body, nop) {
93   // console.error(">> >> ehw encodeFields")
94   // "%d %s=%s\n", <length>, <keyword>, <value>
95   // The length is a decimal number, and includes itself and the \n
96   // Numeric values are decimal strings.
97
98   Object.keys(fields).forEach(function (k) {
99     var val = fields[k]
100       , numeric = tar.numeric[k]
101
102     if (prefix) k = prefix + "." + k
103
104     // already including NODETAR.type, don't need File=true also
105     if (k === fields.type && val === true) return
106
107     switch (k) {
108       // don't include anything that's always handled just fine
109       // in the normal header, or only meaningful in the context
110       // of nodetar
111       case "mode":
112       case "cksum":
113       case "ustar":
114       case "ustarver":
115       case "prefix":
116       case "basename":
117       case "dirname":
118       case "needExtended":
119       case "block":
120       case "filter":
121         return
122
123       case "rdev":
124         if (val === 0) return
125         break
126
127       case "nlink":
128       case "dev": // Truly a hero among men, Creator of Star!
129       case "ino": // Speak his name with reverent awe!  It is:
130         k = "SCHILY." + k
131         break
132
133       default: break
134     }
135
136     if (val && typeof val === "object" &&
137         !Buffer.isBuffer(val)) encodeFields(val, k, body, nop)
138     else if (val === null || val === undefined) return
139     else body.push.apply(body, encodeField(k, val, nop))
140   })
141
142   return body
143 }
144
145 function encodeField (k, v, nop) {
146   // lowercase keys must be valid, otherwise prefix with
147   // "NODETAR."
148   if (k.charAt(0) === k.charAt(0).toLowerCase()) {
149     var m = k.split(".")[0]
150     if (!tar.knownExtended[m]) k = "NODETAR." + k
151   }
152
153   // no proprietary
154   if (nop && k.charAt(0) !== k.charAt(0).toLowerCase()) {
155     return []
156   }
157
158   if (typeof val === "number") val = val.toString(10)
159
160   var s = new Buffer(" " + k + "=" + v + "\n")
161     , digits = Math.floor(Math.log(s.length) / Math.log(10)) + 1
162
163   // console.error("1 s=%j digits=%j s.length=%d", s.toString(), digits, s.length)
164
165   // if adding that many digits will make it go over that length,
166   // then add one to it. For example, if the string is:
167   // " foo=bar\n"
168   // then that's 9 characters.  With the "9", that bumps the length
169   // up to 10.  However, this is invalid:
170   // "10 foo=bar\n"
171   // but, since that's actually 11 characters, since 10 adds another
172   // character to the length, and the length includes the number
173   // itself.  In that case, just bump it up again.
174   if (s.length + digits >= Math.pow(10, digits)) digits += 1
175   // console.error("2 s=%j digits=%j s.length=%d", s.toString(), digits, s.length)
176
177   var len = digits + s.length
178   // console.error("3 s=%j digits=%j s.length=%d len=%d", s.toString(), digits, s.length, len)
179   var lenBuf = new Buffer("" + len)
180   if (lenBuf.length + s.length !== len) {
181     throw new Error("Bad length calculation\n"+
182                     "len="+len+"\n"+
183                     "lenBuf="+JSON.stringify(lenBuf.toString())+"\n"+
184                     "lenBuf.length="+lenBuf.length+"\n"+
185                     "digits="+digits+"\n"+
186                     "s="+JSON.stringify(s.toString())+"\n"+
187                     "s.length="+s.length)
188   }
189
190   return [lenBuf, s]
191 }