All files / tar/lib mkdir.js

100% Statements 81/81
100% Branches 42/42
100% Functions 10/10
100% Lines 80/80
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119    3x 3x 3x       4x 4x 4x       8x       3x 397x 397x 397x 397x 397x   397x 114x 107x 114x     397x 283x   114x 7x   107x 107x 107x     3x 1003x 100x 903x 903x 903x 715x 188x     190x 190x 28x 28x 3x 25x 19x 6x 3x 3x 1x 2x   3x 2x   1x     162x     3x 231x 231x 231x 231x 231x   231x 141x   90x 7x 7x 7x     83x 83x 83x       752x 599x   153x 153x 142x   11x 9x 4x 4x 5x 2x 2x 2x 2x 3x 2x     79x    
'use strict'
// wrapper around mkdirp for tar's needs.
const mkdirp = require('mkdirp')
const fs = require('fs')
const path = require('path')
 
class SymlinkError extends Error {
  constructor (symlink, path) {
    super('Cannot extract through symbolic link')
    this.path = path
    this.symlink = symlink
  }
 
  get name () {
    return 'SylinkError'
  }
}
 
const mkdir = module.exports = (dir, opt, cb) => {
  const mode = opt.mode
  const preserve = opt.preserve
  const unlink = opt.unlink
  const cache = opt.cache
  const cwd = opt.cwd
 
  const done = er => {
    if (!er)
      cache.set(dir, true)
    cb(er)
  }
 
  if (cache && cache.get(dir) === true || dir === cwd)
    return cb()
 
  if (preserve)
    return mkdirp(dir, mode, done)
 
  const sub = path.relative(cwd, dir)
  const parts = sub.split(/\/|\\/)
  mkdir_(cwd, parts, mode, cache, unlink, done)
}
 
const mkdir_ = (base, parts, mode, cache, unlink, cb) => {
  if (!parts.length)
    return cb()
  const p = parts.shift()
  const part = base + '/' + p
  if (cache.get(part))
    return mkdir_(part, parts, mode, cache, unlink, cb)
  fs.mkdir(part, mode, onmkdir(part, parts, mode, cache, unlink, cb))
}
 
const onmkdir = (part, parts, mode, cache, unlink, cb) => er => {
  if (er) {
    fs.lstat(part, (statEr, st) => {
      if (statEr)
        cb(statEr)
      else if (st.isDirectory())
        mkdir_(part, parts, mode, cache, unlink, cb)
      else if (unlink)
        fs.unlink(part, er => {
          if (er)
            return cb(er)
          fs.mkdir(part, mode, onmkdir(part, parts, mode, cache, unlink, cb))
        })
      else if (st.isSymbolicLink())
        return cb(new SymlinkError(part, part + '/' + parts.join('/')))
      else
        cb(er)
    })
  } else
    mkdir_(part, parts, mode, cache, unlink, cb)
}
 
const mkdirSync = module.exports.sync = (dir, opt) => {
  const mode = opt.mode
  const preserve = opt.preserve
  const unlink = opt.unlink
  const cache = opt.cache
  const cwd = opt.cwd
 
  if (cache && cache.get(dir) === true || dir === cwd)
    return
 
  if (preserve) {
    mkdirp.sync(dir, mode)
    cache.set(dir, true)
    return
  }
 
  const sub = path.relative(cwd, dir)
  const parts = sub.split(/\/|\\/)
  for (let p = parts.shift(), part = cwd;
       p && (part += '/' + p);
       p = parts.shift()) {
 
    if (cache.get(part))
      continue
 
    try {
      fs.mkdirSync(part, mode)
      cache.set(part, true)
    } catch (er) {
      const st = fs.lstatSync(part)
      if (st.isDirectory()) {
        cache.set(part, true)
        continue
      } else if (unlink) {
        fs.unlinkSync(part)
        fs.mkdirSync(part, mode)
        cache.set(part, true)
        continue
      } else if (st.isSymbolicLink())
        return new SymlinkError(part, part + '/' + parts.join('/'))
    }
  }
  cache.set(dir, true)
}