Skip to content
This repository has been archived by the owner on Aug 11, 2022. It is now read-only.

Commit

Permalink
Stronger protection around parallel installs
Browse files Browse the repository at this point in the history
Now all tarball pack/unpack operations are wrapped in a lock
  • Loading branch information
isaacs committed Jun 29, 2012
1 parent ccc775c commit d517f42
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 35 deletions.
27 changes: 21 additions & 6 deletions lib/cache.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ exports = module.exports = cache
exports.read = read exports.read = read
exports.clean = clean exports.clean = clean
exports.unpack = unpack exports.unpack = unpack
exports.lock = lock
exports.unlock = unlock


var mkdir = require("mkdirp") var mkdir = require("mkdirp")
, exec = require("./utils/exec.js") , exec = require("./utils/exec.js")
Expand Down Expand Up @@ -788,11 +790,24 @@ function addPlacedTarball_ (p, name, uid, gid, cb) {
var target = path.dirname(p) var target = path.dirname(p)
, folder = path.join(target, "package") , folder = path.join(target, "package")


rm(folder, function (er) { lock(folder, function (er) {
if (er) { if (er) return cb(er)
log.error("addPlacedTarball", "Could not remove %j", folder) rmUnpack()
return cb(er) })
}
function rmUnpack () {
rm(folder, function (er) {
unlock(folder, function () {
if (er) {
log.error("addPlacedTarball", "Could not remove %j", folder)
return cb(er)
}
thenUnpack()
})
})
}

function thenUnpack () {
tar.unpack(p, folder, null, null, uid, gid, function (er) { tar.unpack(p, folder, null, null, uid, gid, function (er) {
if (er) { if (er) {
log.error("addPlacedTarball", "Could not unpack %j to %j", p, target) log.error("addPlacedTarball", "Could not unpack %j to %j", p, target)
Expand Down Expand Up @@ -837,7 +852,7 @@ function addPlacedTarball_ (p, name, uid, gid, cb) {
}) })
}) })
}) })
}) }
} }


function addLocalDirectory (p, name, cb) { function addLocalDirectory (p, name, cb) {
Expand Down
85 changes: 56 additions & 29 deletions lib/utils/tar.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ var npm = require("../npm.js")
, rm = require("rimraf") , rm = require("rimraf")
, readJson = require("read-package-json") , readJson = require("read-package-json")
, cache = require("../cache.js") , cache = require("../cache.js")
, lock = cache.lock
, unlock = cache.unlock
, myUid = process.getuid && process.getuid() , myUid = process.getuid && process.getuid()
, myGid = process.getgid && process.getgid() , myGid = process.getgid && process.getgid()
, tar = require("tar") , tar = require("tar")
Expand Down Expand Up @@ -43,34 +45,43 @@ function pack (targetTarball, folder, pkg, dfc, cb) {
} }
} }


function pack_ (targetTarball, folder, pkg, cb) { function pack_ (targetTarball, folder, pkg, cb_) {
new Packer({ path: folder, type: "Directory", isDirectory: true }) function cb (er) {
.on("error", function (er) { unlock(targetTarball, function () {
if (er) log.error("tar pack", "Error reading " + folder) return cb_(er)
return cb(er)
}) })
}
lock(targetTarball, function (er) {
if (er) return cb(er)


// By default, npm includes some proprietary attributes in the new Packer({ path: folder, type: "Directory", isDirectory: true })
// package tarball. This is sane, and allowed by the spec. .on("error", function (er) {
// However, npm *itself* excludes these from its own package, if (er) log.error("tar pack", "Error reading " + folder)
// so that it can be more easily bootstrapped using old and return cb(er)
// non-compliant tar implementations. })
.pipe(tar.Pack({ noProprietary: !npm.config.get("proprietary-attribs") }))
.on("error", function (er) { // By default, npm includes some proprietary attributes in the
if (er) log.error("tar.pack", "tar creation error", targetTarball) // package tarball. This is sane, and allowed by the spec.
cb(er) // However, npm *itself* excludes these from its own package,
}) // so that it can be more easily bootstrapped using old and
.pipe(zlib.Gzip()) // non-compliant tar implementations.
.on("error", function (er) { .pipe(tar.Pack({ noProprietary: !npm.config.get("proprietary-attribs") }))
if (er) log.error("tar.pack", "gzip error "+targetTarball) .on("error", function (er) {
cb(er) if (er) log.error("tar.pack", "tar creation error", targetTarball)
}) cb(er)
.pipe(fstream.Writer({ type: "File", path: targetTarball })) })
.on("error", function (er) { .pipe(zlib.Gzip())
if (er) log.error("tar.pack", "Could not write "+targetTarball) .on("error", function (er) {
cb(er) if (er) log.error("tar.pack", "gzip error "+targetTarball)
}) cb(er)
.on("close", cb) })
.pipe(fstream.Writer({ type: "File", path: targetTarball }))
.on("error", function (er) {
if (er) log.error("tar.pack", "Could not write "+targetTarball)
cb(er)
})
.on("close", cb)
})
} }




Expand All @@ -87,13 +98,29 @@ function unpack (tarball, unpackTarget, dMode, fMode, uid, gid, cb) {
}) })
} }


function unpack_ ( tarball, unpackTarget, dMode, fMode, uid, gid, cb ) { function unpack_ ( tarball, unpackTarget, dMode, fMode, uid, gid, cb_ ) {
var parent = path.dirname(unpackTarget) var parent = path.dirname(unpackTarget)
, base = path.basename(unpackTarget) , base = path.basename(unpackTarget)


rm(unpackTarget, function (er) { function cb (er) {
unlock(unpackTarget, function () {
return cb_(er)
})
}

lock(unpackTarget, function (er) {
if (er) return cb(er) if (er) return cb(er)
rmGunz()
})


function rmGunz () {
rm(unpackTarget, function (er) {
if (er) return cb(er)
gtp()
})
}

function gtp () {
// gzip {tarball} --decompress --stdout \ // gzip {tarball} --decompress --stdout \
// | tar -mvxpf - --strip-components=1 -C {unpackTarget} // | tar -mvxpf - --strip-components=1 -C {unpackTarget}
gunzTarPerm( tarball, unpackTarget gunzTarPerm( tarball, unpackTarget
Expand All @@ -103,7 +130,7 @@ function unpack_ ( tarball, unpackTarget, dMode, fMode, uid, gid, cb ) {
if (er) return cb(er) if (er) return cb(er)
readJson(path.resolve(folder, "package.json"), cb) readJson(path.resolve(folder, "package.json"), cb)
}) })
}) }
} }




Expand Down

0 comments on commit d517f42

Please sign in to comment.