This commit is contained in:
2022-07-18 02:50:52 +00:00
parent befd344ab0
commit 06181b34d6
8569 changed files with 818704 additions and 352705 deletions
+4 -3
View File
@@ -15,9 +15,10 @@ module.exports = contentPath
function contentPath (cache, integrity) {
const sri = ssri.parse(integrity, { single: true })
// contentPath is the *strongest* algo given
return path.join.apply(
path,
[contentDir(cache), sri.algorithm].concat(hashToSegments(sri.hexDigest()))
return path.join(
contentDir(cache),
sri.algorithm,
...hashToSegments(sri.hexDigest())
)
}
+45 -62
View File
@@ -2,8 +2,7 @@
const util = require('util')
const figgyPudding = require('figgy-pudding')
const fs = require('graceful-fs')
const fs = require('fs')
const fsm = require('fs-minipass')
const ssri = require('ssri')
const contentPath = require('./path')
@@ -12,30 +11,25 @@ const Pipeline = require('minipass-pipeline')
const lstat = util.promisify(fs.lstat)
const readFile = util.promisify(fs.readFile)
const ReadOpts = figgyPudding({
size: {}
})
module.exports = read
const MAX_SINGLE_READ_SIZE = 64 * 1024 * 1024
function read (cache, integrity, opts) {
opts = ReadOpts(opts)
function read (cache, integrity, opts = {}) {
const { size } = opts
return withContentSri(cache, integrity, (cpath, sri) => {
// get size
return lstat(cpath).then(stat => ({ stat, cpath, sri }))
}).then(({ stat, cpath, sri }) => {
if (typeof opts.size === 'number' && stat.size !== opts.size) {
throw sizeError(opts.size, stat.size)
}
if (stat.size > MAX_SINGLE_READ_SIZE) {
if (typeof size === 'number' && stat.size !== size)
throw sizeError(size, stat.size)
if (stat.size > MAX_SINGLE_READ_SIZE)
return readPipeline(cpath, stat.size, sri, new Pipeline()).concat()
}
return readFile(cpath, null).then((data) => {
if (!ssri.checkData(data, sri)) {
if (!ssri.checkData(data, sri))
throw integrityError(sri, cpath)
}
return data
})
})
@@ -45,11 +39,11 @@ const readPipeline = (cpath, size, sri, stream) => {
stream.push(
new fsm.ReadStream(cpath, {
size,
readSize: MAX_SINGLE_READ_SIZE
readSize: MAX_SINGLE_READ_SIZE,
}),
ssri.integrityStream({
integrity: sri,
size
size,
})
)
return stream
@@ -57,17 +51,15 @@ const readPipeline = (cpath, size, sri, stream) => {
module.exports.sync = readSync
function readSync (cache, integrity, opts) {
opts = ReadOpts(opts)
function readSync (cache, integrity, opts = {}) {
const { size } = opts
return withContentSriSync(cache, integrity, (cpath, sri) => {
const data = fs.readFileSync(cpath)
if (typeof opts.size === 'number' && opts.size !== data.length) {
throw sizeError(opts.size, data.length)
}
if (typeof size === 'number' && size !== data.length)
throw sizeError(size, data.length)
if (ssri.checkData(data, sri)) {
if (ssri.checkData(data, sri))
return data
}
throw integrityError(sri, cpath)
})
@@ -76,17 +68,16 @@ function readSync (cache, integrity, opts) {
module.exports.stream = readStream
module.exports.readStream = readStream
function readStream (cache, integrity, opts) {
opts = ReadOpts(opts)
function readStream (cache, integrity, opts = {}) {
const { size } = opts
const stream = new Pipeline()
withContentSri(cache, integrity, (cpath, sri) => {
// just lstat to ensure it exists
return lstat(cpath).then((stat) => ({ stat, cpath, sri }))
}).then(({ stat, cpath, sri }) => {
if (typeof opts.size === 'number' && opts.size !== stat.size) {
return stream.emit('error', sizeError(opts.size, stat.size))
}
if (typeof size === 'number' && size !== stat.size)
return stream.emit('error', sizeError(size, stat.size))
readPipeline(cpath, stat.size, sri, stream)
}, er => stream.emit('error', er))
@@ -100,15 +91,13 @@ if (fs.copyFile) {
copyFile = util.promisify(fs.copyFile)
}
function copy (cache, integrity, dest, opts) {
opts = ReadOpts(opts)
function copy (cache, integrity, dest) {
return withContentSri(cache, integrity, (cpath, sri) => {
return copyFile(cpath, dest)
})
}
function copySync (cache, integrity, dest, opts) {
opts = ReadOpts(opts)
function copySync (cache, integrity, dest) {
return withContentSriSync(cache, integrity, (cpath, sri) => {
return fs.copyFileSync(cpath, dest)
})
@@ -117,21 +106,21 @@ function copySync (cache, integrity, dest, opts) {
module.exports.hasContent = hasContent
function hasContent (cache, integrity) {
if (!integrity) {
if (!integrity)
return Promise.resolve(false)
}
return withContentSri(cache, integrity, (cpath, sri) => {
return lstat(cpath).then((stat) => ({ size: stat.size, sri, stat }))
}).catch((err) => {
if (err.code === 'ENOENT') {
if (err.code === 'ENOENT')
return false
}
if (err.code === 'EPERM') {
if (process.platform !== 'win32') {
/* istanbul ignore else */
if (process.platform !== 'win32')
throw err
} else {
else
return false
}
}
})
}
@@ -139,23 +128,23 @@ function hasContent (cache, integrity) {
module.exports.hasContent.sync = hasContentSync
function hasContentSync (cache, integrity) {
if (!integrity) {
if (!integrity)
return false
}
return withContentSriSync(cache, integrity, (cpath, sri) => {
try {
const stat = fs.lstatSync(cpath)
return { size: stat.size, sri, stat }
} catch (err) {
if (err.code === 'ENOENT') {
if (err.code === 'ENOENT')
return false
}
if (err.code === 'EPERM') {
if (process.platform !== 'win32') {
/* istanbul ignore else */
if (process.platform !== 'win32')
throw err
} else {
else
return false
}
}
}
})
@@ -173,9 +162,10 @@ function withContentSri (cache, integrity, fn) {
const cpath = contentPath(cache, digests[0])
return fn(cpath, digests[0])
} else {
// Can't use race here because a generic error can happen before a ENOENT error, and can happen before a valid result
// Can't use race here because a generic error can happen before
// a ENOENT error, and can happen before a valid result
return Promise
.all(sri[sri.pickAlgorithm()].map((meta) => {
.all(digests.map((meta) => {
return withContentSri(cache, meta, fn)
.catch((err) => {
if (err.code === 'ENOENT') {
@@ -190,21 +180,16 @@ function withContentSri (cache, integrity, fn) {
.then((results) => {
// Return the first non error if it is found
const result = results.find((r) => !(r instanceof Error))
if (result) {
if (result)
return result
}
// Throw the No matching content found error
const enoentError = results.find((r) => r.code === 'ENOENT')
if (enoentError) {
if (enoentError)
throw enoentError
}
// Throw generic error
const genericError = results.find((r) => r instanceof Error)
if (genericError) {
throw genericError
}
throw results.find((r) => r instanceof Error)
})
}
}
@@ -231,16 +216,14 @@ function withContentSriSync (cache, integrity, fn) {
return fn(cpath, digests[0])
} else {
let lastErr = null
for (const meta of sri[sri.pickAlgorithm()]) {
for (const meta of digests) {
try {
return withContentSriSync(cache, meta, fn)
} catch (err) {
lastErr = err
}
}
if (lastErr) {
throw lastErr
}
throw lastErr
}
}
+4 -7
View File
@@ -10,13 +10,10 @@ module.exports = rm
function rm (cache, integrity) {
return hasContent(cache, integrity).then((content) => {
if (content) {
const sri = content.sri
if (sri) {
return rimraf(contentPath(cache, sri)).then(() => true)
}
} else {
// ~pretty~ sure we can't end up with a content lacking sri, but be safe
if (content && content.sri)
return rimraf(contentPath(cache, content.sri)).then(() => true)
else
return false
}
})
}
+26 -24
View File
@@ -4,7 +4,7 @@ const util = require('util')
const contentPath = require('./path')
const fixOwner = require('../util/fix-owner')
const fs = require('graceful-fs')
const fs = require('fs')
const moveFile = require('../util/move-file')
const Minipass = require('minipass')
const Pipeline = require('minipass-pipeline')
@@ -20,20 +20,17 @@ const writeFile = util.promisify(fs.writeFile)
module.exports = write
function write (cache, data, opts) {
opts = opts || {}
if (opts.algorithms && opts.algorithms.length > 1) {
function write (cache, data, opts = {}) {
const { algorithms, size, integrity } = opts
if (algorithms && algorithms.length > 1)
throw new Error('opts.algorithms only supports a single algorithm for now')
}
if (typeof opts.size === 'number' && data.length !== opts.size) {
return Promise.reject(sizeError(opts.size, data.length))
}
const sri = ssri.fromData(data, {
algorithms: opts.algorithms
})
if (opts.integrity && !ssri.checkData(data, opts.integrity, opts)) {
return Promise.reject(checksumError(opts.integrity, sri))
}
if (typeof size === 'number' && data.length !== size)
return Promise.reject(sizeError(size, data.length))
const sri = ssri.fromData(data, algorithms ? { algorithms } : {})
if (integrity && !ssri.checkData(data, integrity, opts))
return Promise.reject(checksumError(integrity, sri))
return disposer(makeTmp(cache, opts), makeTmpDisposer,
(tmp) => {
@@ -90,8 +87,7 @@ class CacacheWriteStream extends Flush {
}
}
function writeStream (cache, opts) {
opts = opts || {}
function writeStream (cache, opts = {}) {
return new CacacheWriteStream(cache, opts)
}
@@ -115,13 +111,17 @@ function pipeToTmp (inputStream, cache, tmpTarget, opts) {
const hashStream = ssri.integrityStream({
integrity: opts.integrity,
algorithms: opts.algorithms,
size: opts.size
size: opts.size,
})
hashStream.on('integrity', i => {
integrity = i
})
hashStream.on('size', s => {
size = s
})
hashStream.on('integrity', i => { integrity = i })
hashStream.on('size', s => { size = s })
const outStream = new fsm.WriteStream(tmpTarget, {
flags: 'wx'
flags: 'wx',
})
// NB: this can throw if the hashStream has a problem with
@@ -135,21 +135,23 @@ function pipeToTmp (inputStream, cache, tmpTarget, opts) {
return pipeline.promise()
.then(() => ({ integrity, size }))
.catch(er => rimraf(tmpTarget).then(() => { throw er }))
.catch(er => rimraf(tmpTarget).then(() => {
throw er
}))
}
function makeTmp (cache, opts) {
const tmpTarget = uniqueFilename(path.join(cache, 'tmp'), opts.tmpPrefix)
return fixOwner.mkdirfix(cache, path.dirname(tmpTarget)).then(() => ({
target: tmpTarget,
moved: false
moved: false,
}))
}
function makeTmpDisposer (tmp) {
if (tmp.moved) {
if (tmp.moved)
return Promise.resolve()
}
return rimraf(tmp.target)
}