Skip to content

Commit

Permalink
Add the noChmod option
Browse files Browse the repository at this point in the history
This allows a way to suppress the call to process.umask() while
still being as compliant as possible with the modes as defined
in the tarball entries.

Re: npm/cli#1103
  • Loading branch information
isaacs committed Jan 6, 2021
1 parent 3c1afee commit c08bfdc
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 4 deletions.
15 changes: 14 additions & 1 deletion README.md
Expand Up @@ -302,7 +302,6 @@ The following options are supported:
- `mtime` Set to a `Date` object to force a specific `mtime` for
everything added to the archive. Overridden by `noMtime`.


The following options are mostly internal, but can be modified in some
advanced use cases, such as re-using caches between runs.

Expand Down Expand Up @@ -396,6 +395,13 @@ The following options are supported:
the `filter` option described above.)
- `onentry` A function that gets called with `(entry)` for each entry
that passes the filter.
- `onwarn` A function that will get called with `(code, message, data)` for
any warnings encountered. (See "Warnings and Errors")
- `noChmod` Set to true to omit calling `fs.chmod()` to ensure that the
extracted file matches the entry mode. This also suppresses the call to
`process.umask()` to determine the default umask value, since tar will
extract with whatever mode is provided, and let the process `umask` apply
normally.

The following options are mostly internal, but can be modified in some
advanced use cases, such as re-using caches between runs.
Expand Down Expand Up @@ -451,6 +457,8 @@ The following options are supported:
the call to `onentry`. Set `noResume: true` to suppress this
behavior. Note that by opting into this, the stream will never
complete until the entry data is consumed.
- `onwarn` A function that will get called with `(code, message, data)` for
any warnings encountered. (See "Warnings and Errors")

### tar.u(options, fileList, callback) [alias: tar.update]

Expand Down Expand Up @@ -708,6 +716,11 @@ Most unpack errors will cause a `warn` event to be emitted. If the
that passes the filter.
- `onwarn` A function that will get called with `(code, message, data)` for
any warnings encountered. (See "Warnings and Errors")
- `noChmod` Set to true to omit calling `fs.chmod()` to ensure that the
extracted file matches the entry mode. This also suppresses the call to
`process.umask()` to determine the default umask value, since tar will
extract with whatever mode is provided, and let the process `umask` apply
normally.

### class tar.Unpack.Sync

Expand Down
10 changes: 7 additions & 3 deletions lib/unpack.js
Expand Up @@ -169,11 +169,14 @@ class Unpack extends Parser {

this.cwd = path.resolve(opt.cwd || process.cwd())
this.strip = +opt.strip || 0
this.processUmask = process.umask()
// if we're not chmodding, then we don't need the process umask
this.processUmask = opt.noChmod ? 0 : process.umask()
this.umask = typeof opt.umask === 'number' ? opt.umask : this.processUmask

// default mode for dirs created as parents
this.dmode = opt.dmode || (0o0777 & (~this.umask))
this.fmode = opt.fmode || (0o0666 & (~this.umask))

this.on('entry', entry => this[ONENTRY](entry))
}

Expand Down Expand Up @@ -299,6 +302,7 @@ class Unpack extends Parser {
cache: this.dirCache,
cwd: this.cwd,
mode: mode,
noChmod: this.noChmod,
}, cb)
}

Expand Down Expand Up @@ -475,7 +479,7 @@ class Unpack extends Parser {

else if (st.isDirectory()) {
if (entry.type === 'Directory') {
if (!entry.mode || (st.mode & 0o7777) === entry.mode)
if (!this.noChmod && (!entry.mode || (st.mode & 0o7777) === entry.mode))
this[MAKEFS](null, entry, done)
else {
fs.chmod(entry.absolute, entry.mode,
Expand Down Expand Up @@ -538,7 +542,7 @@ class UnpackSync extends Unpack {
try {
if (st.isDirectory()) {
if (entry.type === 'Directory') {
if (entry.mode && (st.mode & 0o7777) !== entry.mode)
if (!this.noChmod && entry.mode && (st.mode & 0o7777) !== entry.mode)
fs.chmodSync(entry.absolute, entry.mode)
} else
fs.rmdirSync(entry.absolute)
Expand Down
42 changes: 42 additions & 0 deletions test/unpack.js
Expand Up @@ -1916,6 +1916,48 @@ t.test('use explicit chmod when required by umask', t => {
})
})

t.test('dont use explicit chmod if noChmod flag set', t => {
process.umask(0o022)
const { umask } = process
t.teardown(() => process.umask = umask)
process.umask = () => {
throw new Error('should not call process.umask()')
}

const basedir = path.resolve(unpackdir, 'umask-no-chmod')

const data = makeTar([
{
path: 'x/y/z',
mode: 0o775,
type: 'Directory',
},
'',
'',
])

const check = t => {
const st = fs.statSync(basedir + '/x/y/z')
t.equal(st.mode & 0o777, 0o755)
rimraf.sync(basedir)
t.end()
}

t.test('async', t => {
mkdirp.sync(basedir)
const unpack = new Unpack({ cwd: basedir, noChmod: true })
unpack.on('close', _ => check(t))
unpack.end(data)
})

return t.test('sync', t => {
mkdirp.sync(basedir)
const unpack = new Unpack.Sync({ cwd: basedir, noChmod: true})
unpack.end(data)
check(t)
})
})

t.test('chown implicit dirs and also the entries', t => {
const basedir = path.resolve(unpackdir, 'chownr')

Expand Down

0 comments on commit c08bfdc

Please sign in to comment.