source: trip-planner-front/node_modules/cacache/lib/content/read.js@ ceaed42

Last change on this file since ceaed42 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 6.2 KB
Line 
1'use strict'
2
3const util = require('util')
4
5const fs = require('fs')
6const fsm = require('fs-minipass')
7const ssri = require('ssri')
8const contentPath = require('./path')
9const Pipeline = require('minipass-pipeline')
10
11const lstat = util.promisify(fs.lstat)
12const readFile = util.promisify(fs.readFile)
13
14module.exports = read
15
16const MAX_SINGLE_READ_SIZE = 64 * 1024 * 1024
17function read (cache, integrity, opts = {}) {
18 const { size } = opts
19 return withContentSri(cache, integrity, (cpath, sri) => {
20 // get size
21 return lstat(cpath).then(stat => ({ stat, cpath, sri }))
22 }).then(({ stat, cpath, sri }) => {
23 if (typeof size === 'number' && stat.size !== size)
24 throw sizeError(size, stat.size)
25
26 if (stat.size > MAX_SINGLE_READ_SIZE)
27 return readPipeline(cpath, stat.size, sri, new Pipeline()).concat()
28
29 return readFile(cpath, null).then((data) => {
30 if (!ssri.checkData(data, sri))
31 throw integrityError(sri, cpath)
32
33 return data
34 })
35 })
36}
37
38const readPipeline = (cpath, size, sri, stream) => {
39 stream.push(
40 new fsm.ReadStream(cpath, {
41 size,
42 readSize: MAX_SINGLE_READ_SIZE,
43 }),
44 ssri.integrityStream({
45 integrity: sri,
46 size,
47 })
48 )
49 return stream
50}
51
52module.exports.sync = readSync
53
54function readSync (cache, integrity, opts = {}) {
55 const { size } = opts
56 return withContentSriSync(cache, integrity, (cpath, sri) => {
57 const data = fs.readFileSync(cpath)
58 if (typeof size === 'number' && size !== data.length)
59 throw sizeError(size, data.length)
60
61 if (ssri.checkData(data, sri))
62 return data
63
64 throw integrityError(sri, cpath)
65 })
66}
67
68module.exports.stream = readStream
69module.exports.readStream = readStream
70
71function readStream (cache, integrity, opts = {}) {
72 const { size } = opts
73 const stream = new Pipeline()
74 withContentSri(cache, integrity, (cpath, sri) => {
75 // just lstat to ensure it exists
76 return lstat(cpath).then((stat) => ({ stat, cpath, sri }))
77 }).then(({ stat, cpath, sri }) => {
78 if (typeof size === 'number' && size !== stat.size)
79 return stream.emit('error', sizeError(size, stat.size))
80
81 readPipeline(cpath, stat.size, sri, stream)
82 }, er => stream.emit('error', er))
83
84 return stream
85}
86
87let copyFile
88if (fs.copyFile) {
89 module.exports.copy = copy
90 module.exports.copy.sync = copySync
91 copyFile = util.promisify(fs.copyFile)
92}
93
94function copy (cache, integrity, dest) {
95 return withContentSri(cache, integrity, (cpath, sri) => {
96 return copyFile(cpath, dest)
97 })
98}
99
100function copySync (cache, integrity, dest) {
101 return withContentSriSync(cache, integrity, (cpath, sri) => {
102 return fs.copyFileSync(cpath, dest)
103 })
104}
105
106module.exports.hasContent = hasContent
107
108function hasContent (cache, integrity) {
109 if (!integrity)
110 return Promise.resolve(false)
111
112 return withContentSri(cache, integrity, (cpath, sri) => {
113 return lstat(cpath).then((stat) => ({ size: stat.size, sri, stat }))
114 }).catch((err) => {
115 if (err.code === 'ENOENT')
116 return false
117
118 if (err.code === 'EPERM') {
119 /* istanbul ignore else */
120 if (process.platform !== 'win32')
121 throw err
122 else
123 return false
124 }
125 })
126}
127
128module.exports.hasContent.sync = hasContentSync
129
130function hasContentSync (cache, integrity) {
131 if (!integrity)
132 return false
133
134 return withContentSriSync(cache, integrity, (cpath, sri) => {
135 try {
136 const stat = fs.lstatSync(cpath)
137 return { size: stat.size, sri, stat }
138 } catch (err) {
139 if (err.code === 'ENOENT')
140 return false
141
142 if (err.code === 'EPERM') {
143 /* istanbul ignore else */
144 if (process.platform !== 'win32')
145 throw err
146 else
147 return false
148 }
149 }
150 })
151}
152
153function withContentSri (cache, integrity, fn) {
154 const tryFn = () => {
155 const sri = ssri.parse(integrity)
156 // If `integrity` has multiple entries, pick the first digest
157 // with available local data.
158 const algo = sri.pickAlgorithm()
159 const digests = sri[algo]
160
161 if (digests.length <= 1) {
162 const cpath = contentPath(cache, digests[0])
163 return fn(cpath, digests[0])
164 } else {
165 // Can't use race here because a generic error can happen before
166 // a ENOENT error, and can happen before a valid result
167 return Promise
168 .all(digests.map((meta) => {
169 return withContentSri(cache, meta, fn)
170 .catch((err) => {
171 if (err.code === 'ENOENT') {
172 return Object.assign(
173 new Error('No matching content found for ' + sri.toString()),
174 { code: 'ENOENT' }
175 )
176 }
177 return err
178 })
179 }))
180 .then((results) => {
181 // Return the first non error if it is found
182 const result = results.find((r) => !(r instanceof Error))
183 if (result)
184 return result
185
186 // Throw the No matching content found error
187 const enoentError = results.find((r) => r.code === 'ENOENT')
188 if (enoentError)
189 throw enoentError
190
191 // Throw generic error
192 throw results.find((r) => r instanceof Error)
193 })
194 }
195 }
196
197 return new Promise((resolve, reject) => {
198 try {
199 tryFn()
200 .then(resolve)
201 .catch(reject)
202 } catch (err) {
203 reject(err)
204 }
205 })
206}
207
208function withContentSriSync (cache, integrity, fn) {
209 const sri = ssri.parse(integrity)
210 // If `integrity` has multiple entries, pick the first digest
211 // with available local data.
212 const algo = sri.pickAlgorithm()
213 const digests = sri[algo]
214 if (digests.length <= 1) {
215 const cpath = contentPath(cache, digests[0])
216 return fn(cpath, digests[0])
217 } else {
218 let lastErr = null
219 for (const meta of digests) {
220 try {
221 return withContentSriSync(cache, meta, fn)
222 } catch (err) {
223 lastErr = err
224 }
225 }
226 throw lastErr
227 }
228}
229
230function sizeError (expected, found) {
231 const err = new Error(`Bad data size: expected inserted data to be ${expected} bytes, but got ${found} instead`)
232 err.expected = expected
233 err.found = found
234 err.code = 'EBADSIZE'
235 return err
236}
237
238function integrityError (sri, path) {
239 const err = new Error(`Integrity verification failed for ${sri} (${path})`)
240 err.code = 'EINTEGRITY'
241 err.sri = sri
242 err.path = path
243 return err
244}
Note: See TracBrowser for help on using the repository browser.