diff options
Diffstat (limited to 'deps/npm/lib/utils/tar.js')
-rw-r--r-- | deps/npm/lib/utils/tar.js | 294 |
1 files changed, 111 insertions, 183 deletions
diff --git a/deps/npm/lib/utils/tar.js b/deps/npm/lib/utils/tar.js index 192de7a26a..ede49a121e 100644 --- a/deps/npm/lib/utils/tar.js +++ b/deps/npm/lib/utils/tar.js @@ -3,6 +3,7 @@ var npm = require("../npm.js") , fs = require("graceful-fs") + , writeFileAtomic = require("write-file-atomic") , path = require("path") , log = require("npmlog") , uidNumber = require("uid-number") @@ -15,15 +16,6 @@ var npm = require("../npm.js") , fstream = require("fstream") , Packer = require("fstream-npm") , lifecycle = require("./lifecycle.js") - , locker = require("./locker.js") - -function lock(path, cb) { - return locker.lock('tar://' + path, cb) -} - -function unlock(path, cb) { - return locker.unlock('tar://' + path, cb) -} if (process.env.SUDO_UID && myUid === 0) { if (!isNaN(process.env.SUDO_UID)) myUid = +process.env.SUDO_UID @@ -51,73 +43,40 @@ function pack (tarball, folder, pkg, dfc, cb) { } } -function pack_ (tarball, folder, pkg, cb_) { - var tarballLock = false - , folderLock = false - - function cb (er) { - if (folderLock) - unlock(folder, function() { - folderLock = false - cb(er) - }) - else if (tarballLock) - unlock(tarball, function() { - tarballLock = false - cb(er) - }) - else - cb_(er) - } - - lock(folder, function(er) { - if (er) return cb(er) - folderLock = true - next() - }) - - lock(tarball, function (er) { - if (er) return cb(er) - tarballLock = true - next() - }) - - function next () { - if (!tarballLock || !folderLock) return - - new Packer({ path: folder, type: "Directory", isDirectory: true }) - .on("error", function (er) { - if (er) log.error("tar pack", "Error reading " + folder) - return cb(er) - }) +function pack_ (tarball, folder, pkg, cb) { + new Packer({ path: folder, type: "Directory", isDirectory: true }) + .on("error", function (er) { + if (er) log.error("tar pack", "Error reading " + folder) + return cb(er) + }) - // By default, npm includes some proprietary attributes in the - // package tarball. This is sane, and allowed by the spec. - // However, npm *itself* excludes these from its own package, - // so that it can be more easily bootstrapped using old and - // non-compliant tar implementations. - .pipe(tar.Pack({ noProprietary: !npm.config.get("proprietary-attribs") })) - .on("error", function (er) { - if (er) log.error("tar.pack", "tar creation error", tarball) - cb(er) - }) - .pipe(zlib.Gzip()) - .on("error", function (er) { - if (er) log.error("tar.pack", "gzip error "+tarball) - cb(er) - }) - .pipe(fstream.Writer({ type: "File", path: tarball })) - .on("error", function (er) { - if (er) log.error("tar.pack", "Could not write "+tarball) - cb(er) - }) - .on("close", cb) - } + // By default, npm includes some proprietary attributes in the + // package tarball. This is sane, and allowed by the spec. + // However, npm *itself* excludes these from its own package, + // so that it can be more easily bootstrapped using old and + // non-compliant tar implementations. + .pipe(tar.Pack({ noProprietary: !npm.config.get("proprietary-attribs") })) + .on("error", function (er) { + if (er) log.error("tar.pack", "tar creation error", tarball) + cb(er) + }) + .pipe(zlib.Gzip()) + .on("error", function (er) { + if (er) log.error("tar.pack", "gzip error "+tarball) + cb(er) + }) + .pipe(fstream.Writer({ type: "File", path: tarball })) + .on("error", function (er) { + if (er) log.error("tar.pack", "Could not write "+tarball) + cb(er) + }) + .on("close", cb) } function unpack (tarball, unpackTarget, dMode, fMode, uid, gid, cb) { - log.verbose("tar unpack", tarball) + log.verbose("tar", "unpack", tarball) + log.verbose("tar", "unpacking to", unpackTarget) if (typeof cb !== "function") cb = gid, gid = null if (typeof cb !== "function") cb = uid, uid = null if (typeof cb !== "function") cb = fMode, fMode = npm.modes.file @@ -129,52 +88,9 @@ function unpack (tarball, unpackTarget, dMode, fMode, uid, gid, cb) { }) } -function unpack_ ( tarball, unpackTarget, dMode, fMode, uid, gid, cb_ ) { - var parent = path.dirname(unpackTarget) - , base = path.basename(unpackTarget) - , folderLock - , tarballLock - - function cb (er) { - if (folderLock) - unlock(unpackTarget, function() { - folderLock = false - cb(er) - }) - else if (tarballLock) - unlock(tarball, function() { - tarballLock = false - cb(er) - }) - else - cb_(er) - } - - lock(unpackTarget, function (er) { - if (er) return cb(er) - folderLock = true - next() - }) - - lock(tarball, function (er) { +function unpack_ ( tarball, unpackTarget, dMode, fMode, uid, gid, cb ) { + rm(unpackTarget, function (er) { if (er) return cb(er) - tarballLock = true - next() - }) - - function next() { - if (!tarballLock || !folderLock) return - rmGunz() - } - - function rmGunz () { - rm(unpackTarget, function (er) { - if (er) return cb(er) - gtp() - }) - } - - function gtp () { // gzip {tarball} --decompress --stdout \ // | tar -mvxpf - --strip-components=1 -C {unpackTarget} gunzTarPerm( tarball, unpackTarget @@ -184,7 +100,7 @@ function unpack_ ( tarball, unpackTarget, dMode, fMode, uid, gid, cb_ ) { if (er) return cb(er) readJson(path.resolve(folder, "package.json"), cb) }) - } + }) } @@ -202,6 +118,17 @@ function gunzTarPerm (tarball, target, dMode, fMode, uid, gid, cb_) { var fst = fs.createReadStream(tarball) + fst.on("open", function (fd) { + fs.fstat(fd, function (er, st) { + if (er) return fst.emit("error", er) + if (st.size === 0) { + er = new Error("0-byte tarball\n" + + "Please run `npm cache clean`") + fst.emit("error", er) + } + }) + }) + // figure out who we're supposed to be, if we're not pretending // to be a specific user. if (npm.config.get("unsafe-perm") && process.platform !== "win32") { @@ -275,73 +202,74 @@ function gunzTarPerm (tarball, target, dMode, fMode, uid, gid, cb_) { } - fst.on("error", function (er) { - if (er) log.error("tar.unpack", "error reading "+tarball) - cb(er) - }) - fst.on("data", function OD (c) { - // detect what it is. - // Then, depending on that, we'll figure out whether it's - // a single-file module, gzipped tarball, or naked tarball. - // gzipped files all start with 1f8b08 - if (c[0] === 0x1F && - c[1] === 0x8B && - c[2] === 0x08) { - fst - .pipe(zlib.Unzip()) - .on("error", function (er) { - if (er) log.error("tar.unpack", "unzip error "+tarball) - cb(er) - }) - .pipe(tar.Extract(extractOpts)) - .on("entry", extractEntry) - .on("error", function (er) { - if (er) log.error("tar.unpack", "untar error "+tarball) - cb(er) - }) - .on("close", cb) - } else if (c.toString().match(/^package\//) || - c.toString().match(/^pax_global_header/)) { - // naked tar - fst - .pipe(tar.Extract(extractOpts)) - .on("entry", extractEntry) - .on("error", function (er) { - if (er) log.error("tar.unpack", "untar error "+tarball) - cb(er) - }) - .on("close", cb) - } else { - // naked js file - var jsOpts = { path: path.resolve(target, "index.js") } - - if (process.platform !== "win32" && - typeof uid === "number" && - typeof gid === "number") { - jsOpts.uid = uid - jsOpts.gid = gid - } + fst + .on("error", function (er) { + if (er) log.error("tar.unpack", "error reading "+tarball) + cb(er) + }) + .on("data", function OD (c) { + // detect what it is. + // Then, depending on that, we'll figure out whether it's + // a single-file module, gzipped tarball, or naked tarball. + // gzipped files all start with 1f8b08 + if (c[0] === 0x1F && + c[1] === 0x8B && + c[2] === 0x08) { + fst + .pipe(zlib.Unzip()) + .on("error", function (er) { + if (er) log.error("tar.unpack", "unzip error "+tarball) + cb(er) + }) + .pipe(tar.Extract(extractOpts)) + .on("entry", extractEntry) + .on("error", function (er) { + if (er) log.error("tar.unpack", "untar error "+tarball) + cb(er) + }) + .on("close", cb) + } else if (c.toString().match(/^package\//) || + c.toString().match(/^pax_global_header/)) { + // naked tar + fst + .pipe(tar.Extract(extractOpts)) + .on("entry", extractEntry) + .on("error", function (er) { + if (er) log.error("tar.unpack", "untar error "+tarball) + cb(er) + }) + .on("close", cb) + } else { + // naked js file + var jsOpts = { path: path.resolve(target, "index.js") } + + if (process.platform !== "win32" && + typeof uid === "number" && + typeof gid === "number") { + jsOpts.uid = uid + jsOpts.gid = gid + } - fst - .pipe(fstream.Writer(jsOpts)) - .on("error", function (er) { - if (er) log.error("tar.unpack", "copy error "+tarball) - cb(er) - }) - .on("close", function () { - var j = path.resolve(target, "package.json") - readJson(j, function (er, d) { - if (er) { - log.error("not a package", tarball) - return cb(er) - } - fs.writeFile(j, JSON.stringify(d) + "\n", cb) + fst + .pipe(fstream.Writer(jsOpts)) + .on("error", function (er) { + if (er) log.error("tar.unpack", "copy error "+tarball) + cb(er) }) - }) - } + .on("close", function () { + var j = path.resolve(target, "package.json") + readJson(j, function (er, d) { + if (er) { + log.error("not a package", tarball) + return cb(er) + } + writeFileAtomic(j, JSON.stringify(d) + "\n", cb) + }) + }) + } - // now un-hook, and re-emit the chunk - fst.removeListener("data", OD) - fst.emit("data", c) - }) + // now un-hook, and re-emit the chunk + fst.removeListener("data", OD) + fst.emit("data", c) + }) } |