Skip to content

Commit

Permalink
use lchown to address part 1 of TOCTOU issue
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacs committed Sep 15, 2018
1 parent a631d84 commit 36a93e3
Showing 1 changed file with 10 additions and 5 deletions.
15 changes: 10 additions & 5 deletions chownr.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,24 @@
const fs = require('fs')
const path = require('path')

/* istanbul ignore next */
const LCHOWN = fs.lchown ? 'lchown' : 'chown'
/* istanbul ignore next */
const LCHOWNSYNC = fs.lchownSync ? 'lchownSync' : 'chownSync'

const chownr = (p, uid, gid, cb) => {
fs.readdir(p, (er, children) => {
// any error other than ENOTDIR means it's not readable, or
// doesn't exist. give up.
if (er && er.code !== 'ENOTDIR') return cb(er)
if (er || !children.length) return fs.lchown(p, uid, gid, cb)
if (er || !children.length) return fs[LCHOWN](p, uid, gid, cb)

let len = children.length
let errState = null
const then = er => {
if (errState) return
if (er) return cb(errState = er)
if (-- len === 0) return fs.lchown(p, uid, gid, cb)
if (-- len === 0) return fs[LCHOWN](p, uid, gid, cb)
}

children.forEach(child => {
Expand All @@ -36,10 +41,10 @@ const chownrSync = (p, uid, gid) => {
try {
children = fs.readdirSync(p)
} catch (er) {
if (er && er.code === 'ENOTDIR') return fs.lchownSync(p, uid, gid)
if (er && er.code === 'ENOTDIR') return fs[LCHOWNSYNC](p, uid, gid)
throw er
}
if (!children.length) return fs.lchownSync(p, uid, gid)
if (!children.length) return fs[LCHOWNSYNC](p, uid, gid)

children.forEach(child => {
const pathChild = path.resolve(p, child)
Expand All @@ -48,7 +53,7 @@ const chownrSync = (p, uid, gid) => {
chownrSync(pathChild, uid, gid)
})

return fs.lchownSync(p, uid, gid)
return fs[LCHOWNSYNC](p, uid, gid)
}

module.exports = chownr
Expand Down

0 comments on commit 36a93e3

Please sign in to comment.