]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/lib/utils/tar.js
Adding integrated tile server
[simantics/district.git] / org.simantics.maps.server / node / node-v4.8.0-win-x64 / node_modules / npm / lib / utils / tar.js
1 // commands for packing and unpacking tarballs
2 // this file is used by lib/cache.js
3
4 var npm = require("../npm.js")
5   , fs = require("graceful-fs")
6   , writeFileAtomic = require("write-file-atomic")
7   , writeStreamAtomic = require("fs-write-stream-atomic")
8   , path = require("path")
9   , log = require("npmlog")
10   , uidNumber = require("uid-number")
11   , rm = require("./gently-rm.js")
12   , readJson = require("read-package-json")
13   , myUid = process.getuid && process.getuid()
14   , myGid = process.getgid && process.getgid()
15   , tar = require("tar")
16   , zlib = require("zlib")
17   , fstream = require("fstream")
18   , Packer = require("fstream-npm")
19   , lifecycle = require("./lifecycle.js")
20
21 if (process.env.SUDO_UID && myUid === 0) {
22   if (!isNaN(process.env.SUDO_UID)) myUid = +process.env.SUDO_UID
23   if (!isNaN(process.env.SUDO_GID)) myGid = +process.env.SUDO_GID
24 }
25
26 exports.pack = pack
27 exports.unpack = unpack
28
29 function pack (tarball, folder, pkg, dfc, cb) {
30   log.verbose("tar pack", [tarball, folder])
31   if (typeof cb !== "function") cb = dfc, dfc = false
32
33   log.verbose("tarball", tarball)
34   log.verbose("folder", folder)
35
36   if (dfc) {
37     // do fancy crap
38     return lifecycle(pkg, "prepublish", folder, function (er) {
39       if (er) return cb(er)
40       pack_(tarball, folder, pkg, cb)
41     })
42   } else {
43     pack_(tarball, folder, pkg, cb)
44   }
45 }
46
47 function pack_ (tarball, folder, pkg, cb) {
48   new Packer({ path: folder, type: "Directory", isDirectory: true })
49     .on("error", function (er) {
50       if (er) log.error("tar pack", "Error reading " + folder)
51       return cb(er)
52     })
53
54     // By default, npm includes some proprietary attributes in the
55     // package tarball.  This is sane, and allowed by the spec.
56     // However, npm *itself* excludes these from its own package,
57     // so that it can be more easily bootstrapped using old and
58     // non-compliant tar implementations.
59     .pipe(tar.Pack({ noProprietary: !npm.config.get("proprietary-attribs") }))
60     .on("error", function (er) {
61       if (er) log.error("tar.pack", "tar creation error", tarball)
62       cb(er)
63     })
64     .pipe(zlib.Gzip())
65     .on("error", function (er) {
66       if (er) log.error("tar.pack", "gzip error "+tarball)
67       cb(er)
68     })
69     .pipe(writeStreamAtomic(tarball))
70     .on("error", function (er) {
71       if (er) log.error("tar.pack", "Could not write "+tarball)
72       cb(er)
73     })
74     .on("close", cb)
75 }
76
77
78 function unpack (tarball, unpackTarget, dMode, fMode, uid, gid, cb) {
79   log.verbose("tar", "unpack", tarball)
80   log.verbose("tar", "unpacking to", unpackTarget)
81   if (typeof cb !== "function") cb = gid, gid = null
82   if (typeof cb !== "function") cb = uid, uid = null
83   if (typeof cb !== "function") cb = fMode, fMode = npm.modes.file
84   if (typeof cb !== "function") cb = dMode, dMode = npm.modes.exec
85
86   uidNumber(uid, gid, function (er, uid, gid) {
87     if (er) return cb(er)
88     unpack_(tarball, unpackTarget, dMode, fMode, uid, gid, cb)
89   })
90 }
91
92 function unpack_ ( tarball, unpackTarget, dMode, fMode, uid, gid, cb ) {
93   rm(unpackTarget, function (er) {
94     if (er) return cb(er)
95     // gzip {tarball} --decompress --stdout \
96     //   | tar -mvxpf - --strip-components=1 -C {unpackTarget}
97     gunzTarPerm( tarball, unpackTarget
98                , dMode, fMode
99                , uid, gid
100                , function (er, folder) {
101       if (er) return cb(er)
102       readJson(path.resolve(folder, "package.json"), cb)
103     })
104   })
105 }
106
107
108 function gunzTarPerm (tarball, target, dMode, fMode, uid, gid, cb_) {
109   if (!dMode) dMode = npm.modes.exec
110   if (!fMode) fMode = npm.modes.file
111   log.silly("gunzTarPerm", "modes", [dMode.toString(8), fMode.toString(8)])
112
113   var cbCalled = false
114   function cb (er) {
115     if (cbCalled) return
116     cbCalled = true
117     cb_(er, target)
118   }
119
120   var fst = fs.createReadStream(tarball)
121
122   fst.on("open", function (fd) {
123     fs.fstat(fd, function (er, st) {
124       if (er) return fst.emit("error", er)
125       if (st.size === 0) {
126         er = new Error("0-byte tarball\n" +
127                        "Please run `npm cache clean`")
128         fst.emit("error", er)
129       }
130     })
131   })
132
133   // figure out who we're supposed to be, if we're not pretending
134   // to be a specific user.
135   if (npm.config.get("unsafe-perm") && process.platform !== "win32") {
136     uid = myUid
137     gid = myGid
138   }
139
140   function extractEntry (entry) {
141     log.silly("gunzTarPerm", "extractEntry", entry.path)
142     // never create things that are user-unreadable,
143     // or dirs that are user-un-listable. Only leads to headaches.
144     var originalMode = entry.mode = entry.mode || entry.props.mode
145     entry.mode = entry.mode | (entry.type === "Directory" ? dMode : fMode)
146     entry.mode = entry.mode & (~npm.modes.umask)
147     entry.props.mode = entry.mode
148     if (originalMode !== entry.mode) {
149       log.silly( "gunzTarPerm", "modified mode"
150                , [entry.path, originalMode, entry.mode])
151     }
152
153     // if there's a specific owner uid/gid that we want, then set that
154     if (process.platform !== "win32" &&
155         typeof uid === "number" &&
156         typeof gid === "number") {
157       entry.props.uid = entry.uid = uid
158       entry.props.gid = entry.gid = gid
159     }
160   }
161
162   var extractOpts = { type: "Directory", path: target, strip: 1 }
163
164   if (process.platform !== "win32" &&
165       typeof uid === "number" &&
166       typeof gid === "number") {
167     extractOpts.uid = uid
168     extractOpts.gid = gid
169   }
170
171   var sawIgnores = {}
172   extractOpts.filter = function () {
173     // symbolic links are not allowed in packages.
174     if (this.type.match(/^.*Link$/)) {
175       log.warn( "excluding symbolic link"
176               , this.path.substr(target.length + 1)
177               + " -> " + this.linkpath )
178       return false
179     }
180
181     // Note: This mirrors logic in the fs read operations that are
182     // employed during tarball creation, in the fstream-npm module.
183     // It is duplicated here to handle tarballs that are created
184     // using other means, such as system tar or git archive.
185     if (this.type === "File") {
186       var base = path.basename(this.path)
187       if (base === ".npmignore") {
188         sawIgnores[ this.path ] = true
189       } else if (base === ".gitignore") {
190         var npmignore = this.path.replace(/\.gitignore$/, ".npmignore")
191         if (sawIgnores[npmignore]) {
192           // Skip this one, already seen.
193           return false
194         } else {
195           // Rename, may be clobbered later.
196           this.path = npmignore
197           this._path = npmignore
198         }
199       }
200     }
201
202     return true
203   }
204
205
206   fst
207     .on("error", function (er) {
208       if (er) log.error("tar.unpack", "error reading "+tarball)
209       cb(er)
210     })
211     .on("data", function OD (c) {
212       // detect what it is.
213       // Then, depending on that, we'll figure out whether it's
214       // a single-file module, gzipped tarball, or naked tarball.
215       // gzipped files all start with 1f8b08
216       if (c[0] === 0x1F &&
217           c[1] === 0x8B &&
218           c[2] === 0x08) {
219         fst
220           .pipe(zlib.Unzip())
221           .on("error", function (er) {
222             if (er) log.error("tar.unpack", "unzip error "+tarball)
223             cb(er)
224           })
225           .pipe(tar.Extract(extractOpts))
226           .on("entry", extractEntry)
227           .on("error", function (er) {
228             if (er) log.error("tar.unpack", "untar error "+tarball)
229             cb(er)
230           })
231           .on("close", cb)
232       } else if (hasTarHeader(c)) {
233         // naked tar
234         fst
235           .pipe(tar.Extract(extractOpts))
236           .on("entry", extractEntry)
237           .on("error", function (er) {
238             if (er) log.error("tar.unpack", "untar error "+tarball)
239             cb(er)
240           })
241           .on("close", cb)
242       } else {
243         // naked js file
244         var jsOpts = { path: path.resolve(target, "index.js") }
245
246         if (process.platform !== "win32" &&
247             typeof uid === "number" &&
248             typeof gid === "number") {
249           jsOpts.uid = uid
250           jsOpts.gid = gid
251         }
252
253         fst
254           .pipe(fstream.Writer(jsOpts))
255           .on("error", function (er) {
256             if (er) log.error("tar.unpack", "copy error "+tarball)
257             cb(er)
258           })
259           .on("close", function () {
260             var j = path.resolve(target, "package.json")
261             readJson(j, function (er, d) {
262               if (er) {
263                 log.error("not a package", tarball)
264                 return cb(er)
265               }
266               writeFileAtomic(j, JSON.stringify(d) + "\n", cb)
267             })
268           })
269       }
270
271       // now un-hook, and re-emit the chunk
272       fst.removeListener("data", OD)
273       fst.emit("data", c)
274     })
275 }
276
277 function hasTarHeader (c) {
278   return c[257] === 0x75 && // tar archives have 7573746172 at position
279          c[258] === 0x73 && // 257 and 003030 or 202000 at position 262
280          c[259] === 0x74 &&
281          c[260] === 0x61 &&
282          c[261] === 0x72 &&
283
284        ((c[262] === 0x00 &&
285          c[263] === 0x30 &&
286          c[264] === 0x30) ||
287
288         (c[262] === 0x20 &&
289          c[263] === 0x20 &&
290          c[264] === 0x00))
291 }