UNPKG

extract-base-iterator

Version:

Base iterator for extract iterators like tar-iterator and zip-iterator

68 lines (67 loc) 3 kB
import fs from 'fs'; import { rm } from 'fs-remove-compat'; import isAbsolute from 'is-absolute'; import mkdirp from 'mkdirp-classic'; import path from 'path'; import Queue from 'queue-cb'; import chmod from './fs/chmod.js'; import chown from './fs/chown.js'; import utimes from './fs/utimes.js'; import { objectAssign } from './shared/index.js'; import safeJoinPath from './shared/safeJoinPath.js'; import stripPath from './shared/stripPath.js'; import validateAttributes from './validateAttributes.js'; import waitForAccess from './waitForAccess.js'; const MANDATORY_ATTRIBUTES = [ 'mode', 'mtime', 'path', 'linkpath' ]; let LinkEntry = class LinkEntry { create(dest, options, callback) { callback = typeof options === 'function' ? options : callback; options = typeof options === 'function' ? {} : options || {}; if (typeof callback === 'function') { try { const normalizedPath = path.normalize(this.path); const fullPath = safeJoinPath(dest, stripPath(normalizedPath, options)); if (isAbsolute(this.linkpath)) { const err = new Error(`Absolute linkpath rejected: '${this.linkpath}'`); err.code = 'ETRAVERSAL'; throw err; } const normalizedLinkpath = path.normalize(this.linkpath); const linkFullPath = safeJoinPath(dest, stripPath(normalizedLinkpath, options)); const queue = new Queue(1); if (options.force) { queue.defer((callback)=>{ rm(fullPath, (err)=>{ err && err.code !== 'ENOENT' ? callback(err) : callback(); }); }); } queue.defer((cb)=>mkdirp(path.dirname(fullPath), (err)=>cb(err))); queue.defer((cb)=>waitForAccess(linkFullPath, cb)); // ensure target file is accessible before linking queue.defer((cb)=>fs.link(linkFullPath, fullPath, (err)=>cb(err))); queue.defer((cb)=>waitForAccess(fullPath, cb)); queue.defer((cb)=>chmod(fullPath, this, options, (err)=>cb(err))); queue.defer((cb)=>chown(fullPath, this, options, (err)=>cb(err))); queue.defer((cb)=>utimes(fullPath, this, options, (err)=>cb(err))); queue.await(callback); } catch (err) { callback(err); } return; } return new Promise((resolve, reject)=>this.create(dest, options, (err)=>err ? reject(err) : resolve(true))); } destroy() {} constructor(attributes){ validateAttributes(attributes, MANDATORY_ATTRIBUTES); objectAssign(this, attributes); if (this.basename === undefined) this.basename = path.basename(this.path); if (this.type === undefined) this.type = 'link'; } }; export { LinkEntry as default };