| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- 'use strict'
- const fs = process.versions.electron ? require('original-fs') : require('fs')
- const path = require('path')
- const tmp = require('tmp')
- const UINT64 = require('cuint').UINT64
- class Filesystem {
- constructor (src) {
- this.src = path.resolve(src)
- this.header = {files: {}}
- this.offset = UINT64(0)
- }
- searchNodeFromDirectory (p) {
- let json = this.header
- const dirs = p.split(path.sep)
- for (const dir of dirs) {
- if (dir !== '.') {
- json = json.files[dir]
- }
- }
- return json
- }
- searchNodeFromPath (p) {
- p = path.relative(this.src, p)
- if (!p) { return this.header }
- const name = path.basename(p)
- const node = this.searchNodeFromDirectory(path.dirname(p))
- if (node.files == null) {
- node.files = {}
- }
- if (node.files[name] == null) {
- node.files[name] = {}
- }
- return node.files[name]
- }
- insertDirectory (p, shouldUnpack) {
- const node = this.searchNodeFromPath(p)
- if (shouldUnpack) {
- node.unpacked = shouldUnpack
- }
- node.files = {}
- return node.files
- }
- insertFile (p, shouldUnpack, file, options, callback) {
- const dirNode = this.searchNodeFromPath(path.dirname(p))
- const node = this.searchNodeFromPath(p)
- if (shouldUnpack || dirNode.unpacked) {
- node.size = file.stat.size
- node.unpacked = true
- process.nextTick(callback)
- return
- }
- const handler = () => {
- const size = file.transformed ? file.transformed.stat.size : file.stat.size
- // JavaScript can not precisely present integers >= UINT32_MAX.
- if (size > 4294967295) {
- throw new Error(`${p}: file size can not be larger than 4.2GB`)
- }
- node.size = size
- node.offset = this.offset.toString()
- if (process.platform !== 'win32' && (file.stat.mode & 0o100)) {
- node.executable = true
- }
- this.offset.add(UINT64(size))
- return callback()
- }
- const tr = options.transform && options.transform(p)
- if (tr) {
- return tmp.file(function (err, path) {
- if (err) { return handler() }
- const out = fs.createWriteStream(path)
- const stream = fs.createReadStream(p)
- stream.pipe(tr).pipe(out)
- return out.on('close', function () {
- file.transformed = {
- path,
- stat: fs.lstatSync(path)
- }
- return handler()
- })
- })
- } else {
- return process.nextTick(handler)
- }
- }
- insertLink (p, stat) {
- const link = path.relative(fs.realpathSync(this.src), fs.realpathSync(p))
- if (link.substr(0, 2) === '..') {
- throw new Error(`${p}: file links out of the package`)
- }
- const node = this.searchNodeFromPath(p)
- node.link = link
- return link
- }
- listFiles () {
- const files = []
- const fillFilesFromHeader = function (p, json) {
- if (!json.files) {
- return
- }
- return (() => {
- const result = []
- for (const f in json.files) {
- const fullPath = path.join(p, f)
- files.push(fullPath)
- result.push(fillFilesFromHeader(fullPath, json.files[f]))
- }
- return result
- })()
- }
- fillFilesFromHeader('/', this.header)
- return files
- }
- getNode (p) {
- const node = this.searchNodeFromDirectory(path.dirname(p))
- const name = path.basename(p)
- if (name) {
- return node.files[name]
- } else {
- return node
- }
- }
- getFile (p, followLinks) {
- followLinks = typeof followLinks === 'undefined' ? true : followLinks
- const info = this.getNode(p)
- // if followLinks is false we don't resolve symlinks
- if (info.link && followLinks) {
- return this.getFile(info.link)
- } else {
- return info
- }
- }
- }
- module.exports = Filesystem
|