Browse Source

refactor: clean up asar functionality (#14046)

Shelley Vohr 6 years ago
parent
commit
2963e377ae
1 changed files with 234 additions and 388 deletions
  1. 234 388
      lib/common/asar.js

+ 234 - 388
lib/common/asar.js

@@ -10,26 +10,28 @@
   // Cache asar archive objects.
   const cachedArchives = {}
 
+  // asar error types
+  const NOT_FOUND = 'NOT_FOUND'
+  const NOT_DIR = 'NOT_DIR'
+  const NO_ACCESS = 'NO_ACCESS'
+  const INVALID_ARCHIVE = 'INVALID_ARCHIVE'
+
   const envNoAsar = process.env.ELECTRON_NO_ASAR && process.type !== 'browser' && process.type !== 'renderer'
-  const isAsarDisabled = function () {
-    return process.noAsar || envNoAsar
-  }
+  const isAsarDisabled = () => process.noAsar || envNoAsar
 
-  const getOrCreateArchive = function (p) {
+  const getOrCreateArchive = p => {
     let archive = cachedArchives[p]
-    if (archive != null) {
-      return archive
-    }
+    if (archive != null) return archive
+
     archive = asar.createArchive(p)
-    if (!archive) {
-      return false
-    }
+    if (!archive) return false
+
     cachedArchives[p] = archive
     return archive
   }
 
   // Clean cache on quit.
-  process.on('exit', function () {
+  process.on('exit', () => {
     for (let p in cachedArchives) {
       if (!hasProp.call(cachedArchives, p)) continue
       cachedArchives[p].destroy()
@@ -37,30 +39,22 @@
   })
 
   // Separate asar package's path from full path.
-  const splitPath = function (p) {
+  const splitPath = p => {
     // shortcut to disable asar.
-    if (isAsarDisabled()) {
-      return [false]
-    }
-
-    if (Buffer.isBuffer(p)) {
-      p = p.toString()
-    }
-
-    if (typeof p !== 'string') {
-      return [false]
-    }
-
-    if (p.substr(-5) === '.asar') {
-      return [true, p, '']
-    }
+    if (isAsarDisabled()) return {isAsar: false}
+    if (Buffer.isBuffer(p)) p = p.toString()
+    if (typeof p !== 'string') return {isAsar: false}
+    if (p.endsWith('.asar')) return {isAsar: true, asarPath: p, filePath: ''}
 
     p = path.normalize(p)
-    const index = p.lastIndexOf('.asar' + path.sep)
-    if (index === -1) {
-      return [false]
+    const index = p.lastIndexOf(`.asar${path.sep}`)
+    if (index === -1) return {isAsar: false}
+
+    return {
+      isAsar: true,
+      asarPath: p.substr(0, index + 5),
+      filePath: p.substr(index + 6)
     }
-    return [true, p.substr(0, index + 5), p.substr(index + 6)]
   }
 
   // Convert asar archive's Stats object to fs's Stats object.
@@ -103,78 +97,47 @@
     )
   }
 
-  // Create a ENOENT error.
-  const notFoundError = function (asarPath, filePath, callback) {
-    const error = new Error(`ENOENT, ${filePath} not found in ${asarPath}`)
-    error.code = 'ENOENT'
-    error.errno = -2
-    if (typeof callback !== 'function') {
-      throw error
-    }
-    process.nextTick(function () {
-      callback(error)
-    })
-  }
-
-  // Create a ENOTDIR error.
-  const notDirError = function (callback) {
-    const error = new Error('ENOTDIR, not a directory')
-    error.code = 'ENOTDIR'
-    error.errno = -20
-    if (typeof callback !== 'function') {
-      throw error
-    }
-    process.nextTick(function () {
-      callback(error)
-    })
-  }
-
-  // Create a EACCES error.
-  const accessError = function (asarPath, filePath, callback) {
-    const error = new Error(`EACCES: permission denied, access '${filePath}'`)
-    error.code = 'EACCES'
-    error.errno = -13
-    if (typeof callback !== 'function') {
-      throw error
-    }
-    process.nextTick(function () {
-      callback(error)
-    })
+  const createError = (errorType, {asarPath, filePath, callback} = {}) => {
+    let error
+    switch (errorType) {
+      case NOT_FOUND:
+        error = new Error(`ENOENT, ${filePath} not found in ${asarPath}`)
+        error.code = 'ENOENT'
+        error.errno = -2
+        break
+      case NOT_DIR:
+        error = new Error('ENOTDIR, not a directory')
+        error.code = 'ENOTDIR'
+        error.errno = -20
+        break
+      case NO_ACCESS:
+        error = new Error(`EACCES: permission denied, access '${filePath}'`)
+        error.code = 'EACCES'
+        error.errno = -13
+        break
+      case INVALID_ARCHIVE:
+        error = new Error(`Invalid package ${asarPath}`)
+        break
+      default:
+        throw new Error('invalid error type')
+    }
+    if (typeof callback !== 'function') throw error
+    process.nextTick(() => callback(error))
   }
 
-  // Create invalid archive error.
-  const invalidArchiveError = function (asarPath, callback) {
-    const error = new Error(`Invalid package ${asarPath}`)
-    if (typeof callback !== 'function') {
-      throw error
-    }
-    process.nextTick(function () {
-      callback(error)
-    })
-  }
-
-  // Override APIs that rely on passing file path instead of content to C++.
   const overrideAPISync = function (module, name, arg) {
-    if (arg == null) {
-      arg = 0
-    }
+    if (arg == null) arg = 0
     const old = module[name]
     module[name] = function () {
       const p = arguments[arg]
-      const [isAsar, asarPath, filePath] = splitPath(p)
-      if (!isAsar) {
-        return old.apply(this, arguments)
-      }
+      const {isAsar, asarPath, filePath} = splitPath(p)
+      if (!isAsar) return old.apply(this, arguments)
 
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) {
-        invalidArchiveError(asarPath)
-      }
+      if (!archive) createError(INVALID_ARCHIVE, {asarPath})
 
       const newPath = archive.copyFileOut(filePath)
-      if (!newPath) {
-        notFoundError(asarPath, filePath)
-      }
+      if (!newPath) createError(NOT_FOUND, {asarPath, filePath})
 
       arguments[arg] = newPath
       return old.apply(this, arguments)
@@ -182,52 +145,38 @@
   }
 
   const overrideAPI = function (module, name, arg) {
-    if (arg == null) {
-      arg = 0
-    }
+    if (arg == null) arg = 0
     const old = module[name]
     module[name] = function () {
       const p = arguments[arg]
-      const [isAsar, asarPath, filePath] = splitPath(p)
-      if (!isAsar) {
-        return old.apply(this, arguments)
-      }
+      const {isAsar, asarPath, filePath} = splitPath(p)
+      console.log(`${isAsar}, ${asarPath}, ${filePath}`)
+      if (!isAsar) return old.apply(this, arguments)
 
       const callback = arguments[arguments.length - 1]
-      if (typeof callback !== 'function') {
-        return overrideAPISync(module, name, arg)
-      }
+      if (typeof callback !== 'function') return overrideAPISync(module, name, arg)
 
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) {
-        return invalidArchiveError(asarPath, callback)
-      }
+      if (!archive) return createError(INVALID_ARCHIVE, {asarPath, callback})
 
       const newPath = archive.copyFileOut(filePath)
-      if (!newPath) {
-        return notFoundError(asarPath, filePath, callback)
-      }
+      if (!newPath) return createError(NOT_FOUND, {asarPath, filePath, callback})
 
       arguments[arg] = newPath
       return old.apply(this, arguments)
     }
+
     if (old[util.promisify.custom]) {
       module[name][util.promisify.custom] = function () {
         const p = arguments[arg]
-        const [isAsar, asarPath, filePath] = splitPath(p)
-        if (!isAsar) {
-          return old[util.promisify.custom].apply(this, arguments)
-        }
+        const {isAsar, asarPath, filePath} = splitPath(p)
+        if (!isAsar) return old[util.promisify.custom].apply(this, arguments)
 
         const archive = getOrCreateArchive(asarPath)
-        if (!archive) {
-          return new Promise(() => invalidArchiveError(asarPath))
-        }
+        if (!archive) return new Promise(() => createError(INVALID_ARCHIVE, {asarPath}))
 
         const newPath = archive.copyFileOut(filePath)
-        if (!newPath) {
-          return new Promise(() => notFoundError(asarPath, filePath))
-        }
+        if (!newPath) return new Promise(() => createError(NOT_FOUND, {asarPath, filePath}))
 
         arguments[arg] = newPath
         return old[util.promisify.custom].apply(this, arguments)
@@ -236,141 +185,121 @@
   }
 
   // Override fs APIs.
-  exports.wrapFsWithAsar = function (fs) {
+  exports.wrapFsWithAsar = fs => {
     const logFDs = {}
-    const logASARAccess = function (asarPath, filePath, offset) {
-      if (!process.env.ELECTRON_LOG_ASAR_READS) {
-        return
-      }
+    const logASARAccess = (asarPath, filePath, offset) => {
+      if (!process.env.ELECTRON_LOG_ASAR_READS) return
       if (!logFDs[asarPath]) {
         const path = require('path')
-        const logFilename = path.basename(asarPath, '.asar') + '-access-log.txt'
+        const logFilename = `${path.basename(asarPath, '.asar')}-access-log.txt`
         const logPath = path.join(require('os').tmpdir(), logFilename)
         logFDs[asarPath] = fs.openSync(logPath, 'a')
-        console.log('Logging ' + asarPath + ' access to ' + logPath)
+        console.log(`Logging ${asarPath} access to ${logPath}`)
       }
-      fs.writeSync(logFDs[asarPath], offset + ': ' + filePath + '\n')
+      fs.writeSync(logFDs[asarPath], `${offset}: ${filePath}\n`)
     }
 
     const {lstatSync} = fs
-    fs.lstatSync = function (p) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
-      if (!isAsar) {
-        return lstatSync(p)
-      }
+    fs.lstatSync = p => {
+      const {isAsar, asarPath, filePath} = splitPath(p)
+      if (!isAsar) return lstatSync(p)
+
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) {
-        invalidArchiveError(asarPath)
-      }
+      if (!archive) createError(INVALID_ARCHIVE, {asarPath})
+
       const stats = archive.stat(filePath)
-      if (!stats) {
-        notFoundError(asarPath, filePath)
-      }
+      if (!stats) createError(NOT_FOUND, {asarPath, filePath})
       return asarStatsToFsStats(stats)
     }
 
     const {lstat} = fs
-    fs.lstat = function (p, callback) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
-      if (!isAsar) {
-        return lstat(p, callback)
-      }
+    fs.lstat = (p, callback) => {
+      const {isAsar, asarPath, filePath} = splitPath(p)
+      if (!isAsar) return lstat(p, callback)
+
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) {
-        return invalidArchiveError(asarPath, callback)
-      }
+      if (!archive) return createError(INVALID_ARCHIVE, {asarPath, callback})
+
       const stats = getOrCreateArchive(asarPath).stat(filePath)
-      if (!stats) {
-        return notFoundError(asarPath, filePath, callback)
-      }
-      process.nextTick(function () {
-        callback(null, asarStatsToFsStats(stats))
-      })
+      if (!stats) return createError(NOT_FOUND, {asarPath, filePath, callback})
+
+      process.nextTick(() => callback(null, asarStatsToFsStats(stats)))
     }
 
     const {statSync} = fs
-    fs.statSync = function (p) {
-      const [isAsar] = splitPath(p)
-      if (!isAsar) {
-        return statSync(p)
-      }
+    fs.statSync = p => {
+      const {isAsar} = splitPath(p)
+      if (!isAsar) return statSync(p)
 
       // Do not distinguish links for now.
       return fs.lstatSync(p)
     }
 
     const {stat} = fs
-    fs.stat = function (p, callback) {
-      const [isAsar] = splitPath(p)
-      if (!isAsar) {
-        return stat(p, callback)
-      }
+    fs.stat = (p, callback) => {
+      const {isAsar} = splitPath(p)
+      if (!isAsar) return stat(p, callback)
 
       // Do not distinguish links for now.
-      process.nextTick(function () {
-        fs.lstat(p, callback)
-      })
+      process.nextTick(() => fs.lstat(p, callback))
     }
 
     const {statSyncNoException} = fs
-    fs.statSyncNoException = function (p) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
-      if (!isAsar) {
-        return statSyncNoException(p)
-      }
+    fs.statSyncNoException = p => {
+      const {isAsar, asarPath, filePath} = splitPath(p)
+      if (!isAsar) return statSyncNoException(p)
+
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) {
-        return false
-      }
+      if (!archive) return false
+
       const stats = archive.stat(filePath)
-      if (!stats) {
-        return false
-      }
+      if (!stats) return false
+
       return asarStatsToFsStats(stats)
     }
 
     const {realpathSync} = fs
     fs.realpathSync = function (p) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
+      const {isAsar, asarPath, filePath} = splitPath(p)
       if (!isAsar) return realpathSync.apply(this, arguments)
 
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) return invalidArchiveError(asarPath)
+      if (!archive) return createError(INVALID_ARCHIVE, {asarPath})
 
       const real = archive.realpath(filePath)
-      if (real === false) notFoundError(asarPath, filePath)
+      if (real === false) createError(NOT_FOUND, {asarPath, filePath})
 
       return path.join(realpathSync(asarPath), real)
     }
 
     fs.realpathSync.native = function (p) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
+      const {isAsar, asarPath, filePath} = splitPath(p)
       if (!isAsar) return realpathSync.native.apply(this, arguments)
 
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) return invalidArchiveError(asarPath)
+      if (!archive) return createError(INVALID_ARCHIVE, {asarPath})
 
       const real = archive.realpath(filePath)
-      if (real === false) notFoundError(asarPath, filePath)
+      if (real === false) createError(NOT_FOUND, {asarPath, filePath})
 
       return path.join(realpathSync.native(asarPath), real)
     }
 
     const {realpath} = fs
     fs.realpath = function (p, cache, callback) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
+      const {isAsar, asarPath, filePath} = splitPath(p)
       if (!isAsar) return realpath.apply(this, arguments)
 
       if (typeof cache === 'function') {
         callback = cache
-        cache = void 0
+        cache = undefined
       }
 
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) return invalidArchiveError(asarPath, callback)
+      if (!archive) return createError(INVALID_ARCHIVE, {asarPath, callback})
 
       const real = archive.realpath(filePath)
-      if (real === false) return notFoundError(asarPath, filePath, callback)
+      if (real === false) return createError(NOT_FOUND, {asarPath, filePath, callback})
 
       return realpath(asarPath, (err, p) => {
         return (err) ? callback(err) : callback(null, path.join(p, real))
@@ -378,7 +307,7 @@
     }
 
     fs.realpath.native = function (p, cache, callback) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
+      const {isAsar, asarPath, filePath} = splitPath(p)
       if (!isAsar) return realpath.native.apply(this, arguments)
 
       if (typeof cache === 'function') {
@@ -387,10 +316,10 @@
       }
 
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) return invalidArchiveError(asarPath, callback)
+      if (!archive) return createError(INVALID_ARCHIVE, {asarPath, callback})
 
       const real = archive.realpath(filePath)
-      if (real === false) return notFoundError(asarPath, filePath, callback)
+      if (real === false) return createError(NOT_FOUND, {asarPath, filePath, callback})
 
       return realpath.native(asarPath, (err, p) => {
         return (err) ? callback(err) : callback(null, path.join(p, real))
@@ -398,148 +327,112 @@
     }
 
     const {exists} = fs
-    fs.exists = function (p, callback) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
-      if (!isAsar) {
-        return exists(p, callback)
-      }
+    fs.exists = (p, callback) => {
+      const {isAsar, asarPath, filePath} = splitPath(p)
+      if (!isAsar) return exists(p, callback)
+
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) {
-        return invalidArchiveError(asarPath, callback)
-      }
-      process.nextTick(function () {
-        // Disabled due to false positive in StandardJS
-        // eslint-disable-next-line standard/no-callback-literal
-        callback(archive.stat(filePath) !== false)
-      })
+      if (!archive) return createError(INVALID_ARCHIVE, {asarPath, callback})
+
+      // Disabled due to false positive in StandardJS
+      // eslint-disable-next-line standard/no-callback-literal
+      process.nextTick(() => callback(archive.stat(filePath) !== false))
     }
 
-    fs.exists[util.promisify.custom] = function (p) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
-      if (!isAsar) {
-        return exists[util.promisify.custom](p)
-      }
+    fs.exists[util.promisify.custom] = p => {
+      const {isAsar, asarPath, filePath} = splitPath(p)
+      if (!isAsar) return exists[util.promisify.custom](p)
+
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) {
-        return new Promise(() => invalidArchiveError(asarPath))
-      }
+      if (!archive) return new Promise(() => createError(INVALID_ARCHIVE, {asarPath}))
+
       return Promise.resolve(archive.stat(filePath) !== false)
     }
 
     const {existsSync} = fs
-    fs.existsSync = function (p) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
-      if (!isAsar) {
-        return existsSync(p)
-      }
+    fs.existsSync = p => {
+      const {isAsar, asarPath, filePath} = splitPath(p)
+      if (!isAsar) return existsSync(p)
+
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) {
-        return false
-      }
+      if (!archive) return false
+
       return archive.stat(filePath) !== false
     }
 
     const {access} = fs
     fs.access = function (p, mode, callback) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
-      if (!isAsar) {
-        return access.apply(this, arguments)
-      }
+      const {isAsar, asarPath, filePath} = splitPath(p)
+      if (!isAsar) return access.apply(this, arguments)
+
       if (typeof mode === 'function') {
         callback = mode
         mode = fs.constants.F_OK
       }
+
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) {
-        return invalidArchiveError(asarPath, callback)
-      }
+      if (!archive) return createError(INVALID_ARCHIVE, {asarPath, callback})
+
       const info = archive.getFileInfo(filePath)
-      if (!info) {
-        return notFoundError(asarPath, filePath, callback)
-      }
+      if (!info) return createError(NOT_FOUND, {asarPath, filePath, callback})
+
       if (info.unpacked) {
         const realPath = archive.copyFileOut(filePath)
         return fs.access(realPath, mode, callback)
       }
+
       const stats = getOrCreateArchive(asarPath).stat(filePath)
-      if (!stats) {
-        return notFoundError(asarPath, filePath, callback)
-      }
-      if (mode & fs.constants.W_OK) {
-        return accessError(asarPath, filePath, callback)
-      }
-      process.nextTick(function () {
-        callback()
-      })
+      if (!stats) return createError(NOT_FOUND, {asarPath, filePath, callback})
+
+      if (mode & fs.constants.W_OK) return createError(NO_ACCESS, {asarPath, filePath, callback})
+
+      process.nextTick(() => callback())
     }
 
     const {accessSync} = fs
     fs.accessSync = function (p, mode) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
-      if (!isAsar) {
-        return accessSync.apply(this, arguments)
-      }
-      if (mode == null) {
-        mode = fs.constants.F_OK
-      }
+      const {isAsar, asarPath, filePath} = splitPath(p)
+      if (!isAsar) return accessSync.apply(this, arguments)
+      if (mode == null) mode = fs.constants.F_OK
+
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) {
-        invalidArchiveError(asarPath)
-      }
+      if (!archive) createError(INVALID_ARCHIVE, {asarPath})
+
       const info = archive.getFileInfo(filePath)
-      if (!info) {
-        notFoundError(asarPath, filePath)
-      }
+      if (!info) createError(NOT_FOUND, {asarPath, filePath})
       if (info.unpacked) {
         const realPath = archive.copyFileOut(filePath)
         return fs.accessSync(realPath, mode)
       }
+
       const stats = getOrCreateArchive(asarPath).stat(filePath)
-      if (!stats) {
-        notFoundError(asarPath, filePath)
-      }
-      if (mode & fs.constants.W_OK) {
-        accessError(asarPath, filePath)
-      }
+      if (!stats) createError(NOT_FOUND, {asarPath, filePath})
+      if (mode & fs.constants.W_OK) createError(NO_ACCESS, {asarPath, filePath})
     }
 
     const {readFile} = fs
     fs.readFile = function (p, options, callback) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
-      if (!isAsar) {
-        return readFile.apply(this, arguments)
-      }
+      const {isAsar, asarPath, filePath} = splitPath(p)
+      if (!isAsar) return readFile.apply(this, arguments)
+
       if (typeof options === 'function') {
         callback = options
-        options = {
-          encoding: null
-        }
+        options = { encoding: null }
       } else if (typeof options === 'string') {
-        options = {
-          encoding: options
-        }
+        options = { encoding: options }
       } else if (options === null || options === undefined) {
-        options = {
-          encoding: null
-        }
+        options = { encoding: null }
       } else if (typeof options !== 'object') {
         throw new TypeError('Bad arguments')
       }
-      const {encoding} = options
 
+      const {encoding} = options
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) {
-        return invalidArchiveError(asarPath, callback)
-      }
+      if (!archive) return createError(INVALID_ARCHIVE, {asarPath, callback})
+
       const info = archive.getFileInfo(filePath)
-      if (!info) {
-        return notFoundError(asarPath, filePath, callback)
-      }
-      if (info.size === 0) {
-        return process.nextTick(function () {
-          callback(null, encoding ? '' : Buffer.alloc(0))
-        })
-      }
+      if (!info) return createError(NOT_FOUND, {asarPath, filePath, callback})
+      if (info.size === 0) return process.nextTick(() => callback(null, encoding ? '' : Buffer.alloc(0)))
       if (info.unpacked) {
         const realPath = archive.copyFileOut(filePath)
         return fs.readFile(realPath, options, callback)
@@ -547,158 +440,115 @@
 
       const buffer = Buffer.alloc(info.size)
       const fd = archive.getFd()
-      if (!(fd >= 0)) {
-        return notFoundError(asarPath, filePath, callback)
-      }
+      if (!(fd >= 0)) return createError(NOT_FOUND, {asarPath, filePath, callback})
+
       logASARAccess(asarPath, filePath, info.offset)
-      fs.read(fd, buffer, 0, info.size, info.offset, function (error) {
+      fs.read(fd, buffer, 0, info.size, info.offset, error => {
         callback(error, encoding ? buffer.toString(encoding) : buffer)
       })
     }
 
     const {readFileSync} = fs
     fs.readFileSync = function (p, options) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
-      if (!isAsar) {
-        return readFileSync.apply(this, arguments)
-      }
+      const {isAsar, asarPath, filePath} = splitPath(p)
+      if (!isAsar) return readFileSync.apply(this, arguments)
+
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) {
-        invalidArchiveError(asarPath)
-      }
+      if (!archive) createError(INVALID_ARCHIVE, {asarPath})
+
       const info = archive.getFileInfo(filePath)
-      if (!info) {
-        notFoundError(asarPath, filePath)
-      }
-      if (info.size === 0) {
-        if (options) {
-          return ''
-        } else {
-          return Buffer.alloc(0)
-        }
-      }
+      if (!info) createError(NOT_FOUND, {asarPath, filePath})
+      if (info.size === 0) return (options) ? '' : Buffer.alloc(0)
       if (info.unpacked) {
         const realPath = archive.copyFileOut(filePath)
         return fs.readFileSync(realPath, options)
       }
+
       if (!options) {
-        options = {
-          encoding: null
-        }
+        options = { encoding: null }
       } else if (typeof options === 'string') {
-        options = {
-          encoding: options
-        }
+        options = { encoding: options }
       } else if (typeof options !== 'object') {
         throw new TypeError('Bad arguments')
       }
+
       const {encoding} = options
       const buffer = Buffer.alloc(info.size)
       const fd = archive.getFd()
-      if (!(fd >= 0)) {
-        notFoundError(asarPath, filePath)
-      }
+      if (!(fd >= 0)) createError(NOT_FOUND, {asarPath, filePath})
+
       logASARAccess(asarPath, filePath, info.offset)
       fs.readSync(fd, buffer, 0, info.size, info.offset)
-      if (encoding) {
-        return buffer.toString(encoding)
-      } else {
-        return buffer
-      }
+      return (encoding) ? buffer.toString(encoding) : buffer
     }
 
     const {readdir} = fs
     fs.readdir = function (p, callback) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
-      if (!isAsar) {
-        return readdir.apply(this, arguments)
-      }
+      const {isAsar, asarPath, filePath} = splitPath(p)
+      if (!isAsar) return readdir.apply(this, arguments)
+
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) {
-        return invalidArchiveError(asarPath, callback)
-      }
+      if (!archive) return createError(INVALID_ARCHIVE, {asarPath, callback})
+
       const files = archive.readdir(filePath)
-      if (!files) {
-        return notFoundError(asarPath, filePath, callback)
-      }
-      process.nextTick(function () {
-        callback(null, files)
-      })
+      if (!files) return createError(NOT_FOUND, {asarPath, filePath, callback})
+
+      process.nextTick(() => callback(null, files))
     }
 
     const {readdirSync} = fs
     fs.readdirSync = function (p) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
-      if (!isAsar) {
-        return readdirSync.apply(this, arguments)
-      }
+      const {isAsar, asarPath, filePath} = splitPath(p)
+      if (!isAsar) return readdirSync.apply(this, arguments)
+
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) {
-        invalidArchiveError(asarPath)
-      }
+      if (!archive) createError(INVALID_ARCHIVE, {asarPath})
+
       const files = archive.readdir(filePath)
-      if (!files) {
-        notFoundError(asarPath, filePath)
-      }
+      if (!files) createError(NOT_FOUND, {asarPath, filePath})
+
       return files
     }
 
     const {internalModuleReadJSON} = process.binding('fs')
-    process.binding('fs').internalModuleReadJSON = function (p) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
-      if (!isAsar) {
-        return internalModuleReadJSON(p)
-      }
+    process.binding('fs').internalModuleReadJSON = p => {
+      const {isAsar, asarPath, filePath} = splitPath(p)
+      if (!isAsar) return internalModuleReadJSON(p)
+
       const archive = getOrCreateArchive(asarPath)
-      if (!archive) {
-        return
-      }
+      if (!archive) return
+
       const info = archive.getFileInfo(filePath)
-      if (!info) {
-        return
-      }
-      if (info.size === 0) {
-        return ''
-      }
+      if (!info) return
+      if (info.size === 0) return ''
       if (info.unpacked) {
         const realPath = archive.copyFileOut(filePath)
-        return fs.readFileSync(realPath, {
-          encoding: 'utf8'
-        })
+        return fs.readFileSync(realPath, {encoding: 'utf8'})
       }
+
       const buffer = Buffer.alloc(info.size)
       const fd = archive.getFd()
-      if (!(fd >= 0)) {
-        return
-      }
+      if (!(fd >= 0)) return
+
       logASARAccess(asarPath, filePath, info.offset)
       fs.readSync(fd, buffer, 0, info.size, info.offset)
       return buffer.toString('utf8')
     }
 
     const {internalModuleStat} = process.binding('fs')
-    process.binding('fs').internalModuleStat = function (p) {
-      const [isAsar, asarPath, filePath] = splitPath(p)
-      if (!isAsar) {
-        return internalModuleStat(p)
-      }
+    process.binding('fs').internalModuleStat = p => {
+      const {isAsar, asarPath, filePath} = splitPath(p)
+      if (!isAsar) return internalModuleStat(p)
+
+      // -ENOENT
       const archive = getOrCreateArchive(asarPath)
+      if (!archive) return -34
 
       // -ENOENT
-      if (!archive) {
-        return -34
-      }
       const stats = archive.stat(filePath)
+      if (!stats) return -34
 
-      // -ENOENT
-      if (!stats) {
-        return -34
-      }
-      if (stats.isDirectory) {
-        return 1
-      } else {
-        return 0
-      }
+      return (stats.isDirectory) ? 1 : 0
     }
 
     // Calling mkdir for directory inside asar archive should throw ENOTDIR
@@ -707,23 +557,19 @@
     // widely used.
     if (process.platform === 'win32') {
       const {mkdir} = fs
-      fs.mkdir = function (p, mode, callback) {
-        if (typeof mode === 'function') {
-          callback = mode
-        }
-        const [isAsar, , filePath] = splitPath(p)
-        if (isAsar && filePath.length) {
-          return notDirError(callback)
-        }
+      fs.mkdir = (p, mode, callback) => {
+        if (typeof mode === 'function') callback = mode
+
+        const {isAsar, filePath} = splitPath(p)
+        if (isAsar && filePath.length) return createError(NOT_DIR, {callback})
+
         mkdir(p, mode, callback)
       }
 
       const {mkdirSync} = fs
       fs.mkdirSync = function (p, mode) {
-        const [isAsar, , filePath] = splitPath(p)
-        if (isAsar && filePath.length) {
-          notDirError()
-        }
+        const {isAsar, filePath} = splitPath(p)
+        if (isAsar && filePath.length) createError(NOT_DIR)
         return mkdirSync(p, mode)
       }
     }