Index: node_modules/cacache/lib/util/disposer.js
===================================================================
--- node_modules/cacache/lib/util/disposer.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/cacache/lib/util/disposer.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,30 @@
+'use strict'
+
+module.exports.disposer = disposer
+
+function disposer (creatorFn, disposerFn, fn) {
+  const runDisposer = (resource, result, shouldThrow = false) => {
+    return disposerFn(resource)
+      .then(
+        // disposer resolved, do something with original fn's promise
+        () => {
+          if (shouldThrow)
+            throw result
+
+          return result
+        },
+        // Disposer fn failed, crash process
+        (err) => {
+          throw err
+          // Or process.exit?
+        })
+  }
+
+  return creatorFn
+    .then((resource) => {
+      // fn(resource) can throw, so wrap in a promise here
+      return Promise.resolve().then(() => fn(resource))
+        .then((result) => runDisposer(resource, result))
+        .catch((err) => runDisposer(resource, err, true))
+    })
+}
Index: node_modules/cacache/lib/util/fix-owner.js
===================================================================
--- node_modules/cacache/lib/util/fix-owner.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/cacache/lib/util/fix-owner.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,142 @@
+'use strict'
+
+const util = require('util')
+
+const chownr = util.promisify(require('chownr'))
+const mkdirp = require('mkdirp')
+const inflight = require('promise-inflight')
+const inferOwner = require('infer-owner')
+
+// Memoize getuid()/getgid() calls.
+// patch process.setuid/setgid to invalidate cached value on change
+const self = { uid: null, gid: null }
+const getSelf = () => {
+  if (typeof self.uid !== 'number') {
+    self.uid = process.getuid()
+    const setuid = process.setuid
+    process.setuid = (uid) => {
+      self.uid = null
+      process.setuid = setuid
+      return process.setuid(uid)
+    }
+  }
+  if (typeof self.gid !== 'number') {
+    self.gid = process.getgid()
+    const setgid = process.setgid
+    process.setgid = (gid) => {
+      self.gid = null
+      process.setgid = setgid
+      return process.setgid(gid)
+    }
+  }
+}
+
+module.exports.chownr = fixOwner
+
+function fixOwner (cache, filepath) {
+  if (!process.getuid) {
+    // This platform doesn't need ownership fixing
+    return Promise.resolve()
+  }
+
+  getSelf()
+  if (self.uid !== 0) {
+    // almost certainly can't chown anyway
+    return Promise.resolve()
+  }
+
+  return Promise.resolve(inferOwner(cache)).then((owner) => {
+    const { uid, gid } = owner
+
+    // No need to override if it's already what we used.
+    if (self.uid === uid && self.gid === gid)
+      return
+
+    return inflight('fixOwner: fixing ownership on ' + filepath, () =>
+      chownr(
+        filepath,
+        typeof uid === 'number' ? uid : self.uid,
+        typeof gid === 'number' ? gid : self.gid
+      ).catch((err) => {
+        if (err.code === 'ENOENT')
+          return null
+
+        throw err
+      })
+    )
+  })
+}
+
+module.exports.chownr.sync = fixOwnerSync
+
+function fixOwnerSync (cache, filepath) {
+  if (!process.getuid) {
+    // This platform doesn't need ownership fixing
+    return
+  }
+  const { uid, gid } = inferOwner.sync(cache)
+  getSelf()
+  if (self.uid !== 0) {
+    // almost certainly can't chown anyway
+    return
+  }
+
+  if (self.uid === uid && self.gid === gid) {
+    // No need to override if it's already what we used.
+    return
+  }
+  try {
+    chownr.sync(
+      filepath,
+      typeof uid === 'number' ? uid : self.uid,
+      typeof gid === 'number' ? gid : self.gid
+    )
+  } catch (err) {
+    // only catch ENOENT, any other error is a problem.
+    if (err.code === 'ENOENT')
+      return null
+
+    throw err
+  }
+}
+
+module.exports.mkdirfix = mkdirfix
+
+function mkdirfix (cache, p, cb) {
+  // we have to infer the owner _before_ making the directory, even though
+  // we aren't going to use the results, since the cache itself might not
+  // exist yet.  If we mkdirp it, then our current uid/gid will be assumed
+  // to be correct if it creates the cache folder in the process.
+  return Promise.resolve(inferOwner(cache)).then(() => {
+    return mkdirp(p)
+      .then((made) => {
+        if (made)
+          return fixOwner(cache, made).then(() => made)
+      })
+      .catch((err) => {
+        if (err.code === 'EEXIST')
+          return fixOwner(cache, p).then(() => null)
+
+        throw err
+      })
+  })
+}
+
+module.exports.mkdirfix.sync = mkdirfixSync
+
+function mkdirfixSync (cache, p) {
+  try {
+    inferOwner.sync(cache)
+    const made = mkdirp.sync(p)
+    if (made) {
+      fixOwnerSync(cache, made)
+      return made
+    }
+  } catch (err) {
+    if (err.code === 'EEXIST') {
+      fixOwnerSync(cache, p)
+      return null
+    } else
+      throw err
+  }
+}
Index: node_modules/cacache/lib/util/hash-to-segments.js
===================================================================
--- node_modules/cacache/lib/util/hash-to-segments.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/cacache/lib/util/hash-to-segments.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,7 @@
+'use strict'
+
+module.exports = hashToSegments
+
+function hashToSegments (hash) {
+  return [hash.slice(0, 2), hash.slice(2, 4), hash.slice(4)]
+}
Index: node_modules/cacache/lib/util/move-file.js
===================================================================
--- node_modules/cacache/lib/util/move-file.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/cacache/lib/util/move-file.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,67 @@
+'use strict'
+
+const fs = require('fs')
+const util = require('util')
+const chmod = util.promisify(fs.chmod)
+const unlink = util.promisify(fs.unlink)
+const stat = util.promisify(fs.stat)
+const move = require('@npmcli/move-file')
+const pinflight = require('promise-inflight')
+
+module.exports = moveFile
+
+function moveFile (src, dest) {
+  const isWindows = global.__CACACHE_TEST_FAKE_WINDOWS__ ||
+    process.platform === 'win32'
+
+  // This isn't quite an fs.rename -- the assumption is that
+  // if `dest` already exists, and we get certain errors while
+  // trying to move it, we should just not bother.
+  //
+  // In the case of cache corruption, users will receive an
+  // EINTEGRITY error elsewhere, and can remove the offending
+  // content their own way.
+  //
+  // Note that, as the name suggests, this strictly only supports file moves.
+  return new Promise((resolve, reject) => {
+    fs.link(src, dest, (err) => {
+      if (err) {
+        if (isWindows && err.code === 'EPERM') {
+          // XXX This is a really weird way to handle this situation, as it
+          // results in the src file being deleted even though the dest
+          // might not exist.  Since we pretty much always write files to
+          // deterministic locations based on content hash, this is likely
+          // ok (or at worst, just ends in a future cache miss).  But it would
+          // be worth investigating at some time in the future if this is
+          // really what we want to do here.
+          return resolve()
+        } else if (err.code === 'EEXIST' || err.code === 'EBUSY') {
+          // file already exists, so whatever
+          return resolve()
+        } else
+          return reject(err)
+      } else
+        return resolve()
+    })
+  })
+    .then(() => {
+      // content should never change for any reason, so make it read-only
+      return Promise.all([
+        unlink(src),
+        !isWindows && chmod(dest, '0444'),
+      ])
+    })
+    .catch(() => {
+      return pinflight('cacache-move-file:' + dest, () => {
+        return stat(dest).catch((err) => {
+          if (err.code !== 'ENOENT') {
+            // Something else is wrong here. Bail bail bail
+            throw err
+          }
+          // file doesn't already exist! let's try a rename -> copy fallback
+          // only delete if it successfully copies
+          return move(src, dest)
+        })
+      })
+    })
+}
Index: node_modules/cacache/lib/util/tmp.js
===================================================================
--- node_modules/cacache/lib/util/tmp.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/cacache/lib/util/tmp.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,35 @@
+'use strict'
+
+const fs = require('@npmcli/fs')
+
+const fixOwner = require('./fix-owner')
+const path = require('path')
+
+module.exports.mkdir = mktmpdir
+
+function mktmpdir (cache, opts = {}) {
+  const { tmpPrefix } = opts
+  const tmpDir = path.join(cache, 'tmp')
+  return fs.mkdir(tmpDir, { recursive: true, owner: 'inherit' })
+    .then(() => {
+      // do not use path.join(), it drops the trailing / if tmpPrefix is unset
+      const target = `${tmpDir}${path.sep}${tmpPrefix || ''}`
+      return fs.mkdtemp(target, { owner: 'inherit' })
+    })
+}
+
+module.exports.withTmp = withTmp
+
+function withTmp (cache, opts, cb) {
+  if (!cb) {
+    cb = opts
+    opts = {}
+  }
+  return fs.withTempDir(path.join(cache, 'tmp'), cb, opts)
+}
+
+module.exports.fix = fixtmpdir
+
+function fixtmpdir (cache) {
+  return fixOwner(cache, path.join(cache, 'tmp'))
+}
