Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / node-pre-gyp / node_modules / tar / lib / write-entry.js
diff --git a/legacy-libs/node-pre-gyp/node_modules/tar/lib/write-entry.js b/legacy-libs/node-pre-gyp/node_modules/tar/lib/write-entry.js
new file mode 100644 (file)
index 0000000..0c01900
--- /dev/null
@@ -0,0 +1,422 @@
+'use strict'
+const Buffer = require('./buffer.js')
+const MiniPass = require('minipass')
+const Pax = require('./pax.js')
+const Header = require('./header.js')
+const ReadEntry = require('./read-entry.js')
+const fs = require('fs')
+const path = require('path')
+
+const types = require('./types.js')
+const maxReadSize = 16 * 1024 * 1024
+const PROCESS = Symbol('process')
+const FILE = Symbol('file')
+const DIRECTORY = Symbol('directory')
+const SYMLINK = Symbol('symlink')
+const HARDLINK = Symbol('hardlink')
+const HEADER = Symbol('header')
+const READ = Symbol('read')
+const LSTAT = Symbol('lstat')
+const ONLSTAT = Symbol('onlstat')
+const ONREAD = Symbol('onread')
+const ONREADLINK = Symbol('onreadlink')
+const OPENFILE = Symbol('openfile')
+const ONOPENFILE = Symbol('onopenfile')
+const CLOSE = Symbol('close')
+const MODE = Symbol('mode')
+const warner = require('./warn-mixin.js')
+const winchars = require('./winchars.js')
+
+const modeFix = require('./mode-fix.js')
+
+const WriteEntry = warner(class WriteEntry extends MiniPass {
+  constructor (p, opt) {
+    opt = opt || {}
+    super(opt)
+    if (typeof p !== 'string')
+      throw new TypeError('path is required')
+    this.path = p
+    // suppress atime, ctime, uid, gid, uname, gname
+    this.portable = !!opt.portable
+    // until node has builtin pwnam functions, this'll have to do
+    this.myuid = process.getuid && process.getuid()
+    this.myuser = process.env.USER || ''
+    this.maxReadSize = opt.maxReadSize || maxReadSize
+    this.linkCache = opt.linkCache || new Map()
+    this.statCache = opt.statCache || new Map()
+    this.preservePaths = !!opt.preservePaths
+    this.cwd = opt.cwd || process.cwd()
+    this.strict = !!opt.strict
+    this.noPax = !!opt.noPax
+    this.noMtime = !!opt.noMtime
+    this.mtime = opt.mtime || null
+
+    if (typeof opt.onwarn === 'function')
+      this.on('warn', opt.onwarn)
+
+    if (!this.preservePaths && path.win32.isAbsolute(p)) {
+      // absolutes on posix are also absolutes on win32
+      // so we only need to test this one to get both
+      const parsed = path.win32.parse(p)
+      this.warn('stripping ' + parsed.root + ' from absolute path', p)
+      this.path = p.substr(parsed.root.length)
+    }
+
+    this.win32 = !!opt.win32 || process.platform === 'win32'
+    if (this.win32) {
+      this.path = winchars.decode(this.path.replace(/\\/g, '/'))
+      p = p.replace(/\\/g, '/')
+    }
+
+    this.absolute = opt.absolute || path.resolve(this.cwd, p)
+
+    if (this.path === '')
+      this.path = './'
+
+    if (this.statCache.has(this.absolute))
+      this[ONLSTAT](this.statCache.get(this.absolute))
+    else
+      this[LSTAT]()
+  }
+
+  [LSTAT] () {
+    fs.lstat(this.absolute, (er, stat) => {
+      if (er)
+        return this.emit('error', er)
+      this[ONLSTAT](stat)
+    })
+  }
+
+  [ONLSTAT] (stat) {
+    this.statCache.set(this.absolute, stat)
+    this.stat = stat
+    if (!stat.isFile())
+      stat.size = 0
+    this.type = getType(stat)
+    this.emit('stat', stat)
+    this[PROCESS]()
+  }
+
+  [PROCESS] () {
+    switch (this.type) {
+      case 'File': return this[FILE]()
+      case 'Directory': return this[DIRECTORY]()
+      case 'SymbolicLink': return this[SYMLINK]()
+      // unsupported types are ignored.
+      default: return this.end()
+    }
+  }
+
+  [MODE] (mode) {
+    return modeFix(mode, this.type === 'Directory')
+  }
+
+  [HEADER] () {
+    if (this.type === 'Directory' && this.portable)
+      this.noMtime = true
+
+    this.header = new Header({
+      path: this.path,
+      linkpath: this.linkpath,
+      // only the permissions and setuid/setgid/sticky bitflags
+      // not the higher-order bits that specify file type
+      mode: this[MODE](this.stat.mode),
+      uid: this.portable ? null : this.stat.uid,
+      gid: this.portable ? null : this.stat.gid,
+      size: this.stat.size,
+      mtime: this.noMtime ? null : this.mtime || this.stat.mtime,
+      type: this.type,
+      uname: this.portable ? null :
+        this.stat.uid === this.myuid ? this.myuser : '',
+      atime: this.portable ? null : this.stat.atime,
+      ctime: this.portable ? null : this.stat.ctime
+    })
+
+    if (this.header.encode() && !this.noPax)
+      this.write(new Pax({
+        atime: this.portable ? null : this.header.atime,
+        ctime: this.portable ? null : this.header.ctime,
+        gid: this.portable ? null : this.header.gid,
+        mtime: this.noMtime ? null : this.mtime || this.header.mtime,
+        path: this.path,
+        linkpath: this.linkpath,
+        size: this.header.size,
+        uid: this.portable ? null : this.header.uid,
+        uname: this.portable ? null : this.header.uname,
+        dev: this.portable ? null : this.stat.dev,
+        ino: this.portable ? null : this.stat.ino,
+        nlink: this.portable ? null : this.stat.nlink
+      }).encode())
+    this.write(this.header.block)
+  }
+
+  [DIRECTORY] () {
+    if (this.path.substr(-1) !== '/')
+      this.path += '/'
+    this.stat.size = 0
+    this[HEADER]()
+    this.end()
+  }
+
+  [SYMLINK] () {
+    fs.readlink(this.absolute, (er, linkpath) => {
+      if (er)
+        return this.emit('error', er)
+      this[ONREADLINK](linkpath)
+    })
+  }
+
+  [ONREADLINK] (linkpath) {
+    this.linkpath = linkpath
+    this[HEADER]()
+    this.end()
+  }
+
+  [HARDLINK] (linkpath) {
+    this.type = 'Link'
+    this.linkpath = path.relative(this.cwd, linkpath)
+    this.stat.size = 0
+    this[HEADER]()
+    this.end()
+  }
+
+  [FILE] () {
+    if (this.stat.nlink > 1) {
+      const linkKey = this.stat.dev + ':' + this.stat.ino
+      if (this.linkCache.has(linkKey)) {
+        const linkpath = this.linkCache.get(linkKey)
+        if (linkpath.indexOf(this.cwd) === 0)
+          return this[HARDLINK](linkpath)
+      }
+      this.linkCache.set(linkKey, this.absolute)
+    }
+
+    this[HEADER]()
+    if (this.stat.size === 0)
+      return this.end()
+
+    this[OPENFILE]()
+  }
+
+  [OPENFILE] () {
+    fs.open(this.absolute, 'r', (er, fd) => {
+      if (er)
+        return this.emit('error', er)
+      this[ONOPENFILE](fd)
+    })
+  }
+
+  [ONOPENFILE] (fd) {
+    const blockLen = 512 * Math.ceil(this.stat.size / 512)
+    const bufLen = Math.min(blockLen, this.maxReadSize)
+    const buf = Buffer.allocUnsafe(bufLen)
+    this[READ](fd, buf, 0, buf.length, 0, this.stat.size, blockLen)
+  }
+
+  [READ] (fd, buf, offset, length, pos, remain, blockRemain) {
+    fs.read(fd, buf, offset, length, pos, (er, bytesRead) => {
+      if (er)
+        return this[CLOSE](fd, _ => this.emit('error', er))
+      this[ONREAD](fd, buf, offset, length, pos, remain, blockRemain, bytesRead)
+    })
+  }
+
+  [CLOSE] (fd, cb) {
+    fs.close(fd, cb)
+  }
+
+  [ONREAD] (fd, buf, offset, length, pos, remain, blockRemain, bytesRead) {
+    if (bytesRead <= 0 && remain > 0) {
+      const er = new Error('encountered unexpected EOF')
+      er.path = this.absolute
+      er.syscall = 'read'
+      er.code = 'EOF'
+      this[CLOSE](fd, _ => _)
+      return this.emit('error', er)
+    }
+
+    if (bytesRead > remain) {
+      const er = new Error('did not encounter expected EOF')
+      er.path = this.absolute
+      er.syscall = 'read'
+      er.code = 'EOF'
+      this[CLOSE](fd, _ => _)
+      return this.emit('error', er)
+    }
+
+    // null out the rest of the buffer, if we could fit the block padding
+    if (bytesRead === remain) {
+      for (let i = bytesRead; i < length && bytesRead < blockRemain; i++) {
+        buf[i + offset] = 0
+        bytesRead ++
+        remain ++
+      }
+    }
+
+    const writeBuf = offset === 0 && bytesRead === buf.length ?
+      buf : buf.slice(offset, offset + bytesRead)
+    remain -= bytesRead
+    blockRemain -= bytesRead
+    pos += bytesRead
+    offset += bytesRead
+
+    this.write(writeBuf)
+
+    if (!remain) {
+      if (blockRemain)
+        this.write(Buffer.alloc(blockRemain))
+      this.end()
+      this[CLOSE](fd, _ => _)
+      return
+    }
+
+    if (offset >= length) {
+      buf = Buffer.allocUnsafe(length)
+      offset = 0
+    }
+    length = buf.length - offset
+    this[READ](fd, buf, offset, length, pos, remain, blockRemain)
+  }
+})
+
+class WriteEntrySync extends WriteEntry {
+  constructor (path, opt) {
+    super(path, opt)
+  }
+
+  [LSTAT] () {
+    this[ONLSTAT](fs.lstatSync(this.absolute))
+  }
+
+  [SYMLINK] () {
+    this[ONREADLINK](fs.readlinkSync(this.absolute))
+  }
+
+  [OPENFILE] () {
+    this[ONOPENFILE](fs.openSync(this.absolute, 'r'))
+  }
+
+  [READ] (fd, buf, offset, length, pos, remain, blockRemain) {
+    let threw = true
+    try {
+      const bytesRead = fs.readSync(fd, buf, offset, length, pos)
+      this[ONREAD](fd, buf, offset, length, pos, remain, blockRemain, bytesRead)
+      threw = false
+    } finally {
+      if (threw)
+        try { this[CLOSE](fd) } catch (er) {}
+    }
+  }
+
+  [CLOSE] (fd) {
+    fs.closeSync(fd)
+  }
+}
+
+const WriteEntryTar = warner(class WriteEntryTar extends MiniPass {
+  constructor (readEntry, opt) {
+    opt = opt || {}
+    super(opt)
+    this.preservePaths = !!opt.preservePaths
+    this.portable = !!opt.portable
+    this.strict = !!opt.strict
+    this.noPax = !!opt.noPax
+    this.noMtime = !!opt.noMtime
+
+    this.readEntry = readEntry
+    this.type = readEntry.type
+    if (this.type === 'Directory' && this.portable)
+      this.noMtime = true
+
+    this.path = readEntry.path
+    this.mode = this[MODE](readEntry.mode)
+    this.uid = this.portable ? null : readEntry.uid
+    this.gid = this.portable ? null : readEntry.gid
+    this.uname = this.portable ? null : readEntry.uname
+    this.gname = this.portable ? null : readEntry.gname
+    this.size = readEntry.size
+    this.mtime = this.noMtime ? null : opt.mtime || readEntry.mtime
+    this.atime = this.portable ? null : readEntry.atime
+    this.ctime = this.portable ? null : readEntry.ctime
+    this.linkpath = readEntry.linkpath
+
+    if (typeof opt.onwarn === 'function')
+      this.on('warn', opt.onwarn)
+
+    if (path.isAbsolute(this.path) && !this.preservePaths) {
+      const parsed = path.parse(this.path)
+      this.warn(
+        'stripping ' + parsed.root + ' from absolute path',
+        this.path
+      )
+      this.path = this.path.substr(parsed.root.length)
+    }
+
+    this.remain = readEntry.size
+    this.blockRemain = readEntry.startBlockSize
+
+    this.header = new Header({
+      path: this.path,
+      linkpath: this.linkpath,
+      // only the permissions and setuid/setgid/sticky bitflags
+      // not the higher-order bits that specify file type
+      mode: this.mode,
+      uid: this.portable ? null : this.uid,
+      gid: this.portable ? null : this.gid,
+      size: this.size,
+      mtime: this.noMtime ? null : this.mtime,
+      type: this.type,
+      uname: this.portable ? null : this.uname,
+      atime: this.portable ? null : this.atime,
+      ctime: this.portable ? null : this.ctime
+    })
+
+    if (this.header.encode() && !this.noPax)
+      super.write(new Pax({
+        atime: this.portable ? null : this.atime,
+        ctime: this.portable ? null : this.ctime,
+        gid: this.portable ? null : this.gid,
+        mtime: this.noMtime ? null : this.mtime,
+        path: this.path,
+        linkpath: this.linkpath,
+        size: this.size,
+        uid: this.portable ? null : this.uid,
+        uname: this.portable ? null : this.uname,
+        dev: this.portable ? null : this.readEntry.dev,
+        ino: this.portable ? null : this.readEntry.ino,
+        nlink: this.portable ? null : this.readEntry.nlink
+      }).encode())
+
+    super.write(this.header.block)
+    readEntry.pipe(this)
+  }
+
+  [MODE] (mode) {
+    return modeFix(mode, this.type === 'Directory')
+  }
+
+  write (data) {
+    const writeLen = data.length
+    if (writeLen > this.blockRemain)
+      throw new Error('writing more to entry than is appropriate')
+    this.blockRemain -= writeLen
+    return super.write(data)
+  }
+
+  end () {
+    if (this.blockRemain)
+      this.write(Buffer.alloc(this.blockRemain))
+    return super.end()
+  }
+})
+
+WriteEntry.Sync = WriteEntrySync
+WriteEntry.Tar = WriteEntryTar
+
+const getType = stat =>
+  stat.isFile() ? 'File'
+  : stat.isDirectory() ? 'Directory'
+  : stat.isSymbolicLink() ? 'SymbolicLink'
+  : 'Unsupported'
+
+module.exports = WriteEntry