From 3920fd9d22ecb07135eb21cda503e17c36b2dd23 Mon Sep 17 00:00:00 2001 From: Tom M Date: Mon, 25 Apr 2016 15:42:47 -0500 Subject: [PATCH] Support setting setuid/setgid/sticky in updateMetadata (#162) Adapt tests to support for setuid/setgid/sticky bits Relates to #156 --- lib/fileOperations.js | 3 +- test/destModes.js | 86 ++++++++++++++++++++++++++++++++++++++++-- test/fileOperations.js | 29 ++++++++++++-- 3 files changed, 109 insertions(+), 9 deletions(-) diff --git a/lib/fileOperations.js b/lib/fileOperations.js index e323fb70..cec9efb3 100644 --- a/lib/fileOperations.js +++ b/lib/fileOperations.js @@ -6,8 +6,7 @@ var isEqual = require('lodash.isequal'); var isValidDate = require('vali-date'); // TODO shared module -// TODO include sticky/setuid/setgid, i.e. 7777? -var MASK_MODE = parseInt('0777', 8); +var MASK_MODE = parseInt('7777', 8); var DEFAULT_FILE_MODE = parseInt('0666', 8); var APPEND_MODE_REGEXP = /a/; diff --git a/test/destModes.js b/test/destModes.js index 84a05256..edefae13 100644 --- a/test/destModes.js +++ b/test/destModes.js @@ -23,13 +23,14 @@ function wipeOut() { }); } -var MASK_MODE = parseInt('777', 8); +var MASK_MODE = parseInt('7777', 8); function masked(mode) { return mode & MASK_MODE; } var isWindows = (os.platform() === 'win32'); +var isDarwin = (os.platform() === 'darwin'); describe('.dest() with custom modes', function() { beforeEach(wipeOut); @@ -70,6 +71,46 @@ describe('.dest() with custom modes', function() { stream.end(); }); + + + it('should set the sticky bit on the mode of a written stream file if set on the vinyl object', function(done) { + if (isWindows) { + this.skip(); + return; + } + + var inputPath = path.join(__dirname, './fixtures/test.coffee'); + var inputBase = path.join(__dirname, './fixtures/'); + var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); + var expectedContents = fs.readFileSync(inputPath); + var expectedMode = parseInt('1655', 8); + + var contentStream = through.obj(); + var expectedFile = new File({ + base: inputBase, + cwd: __dirname, + path: inputPath, + contents: contentStream, + stat: { + mode: expectedMode, + }, + }); + + var onEnd = function() { + expect(masked(fs.lstatSync(expectedPath).mode)).toEqual(expectedMode); + done(); + }; + + var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); + stream.on('end', onEnd); + stream.write(expectedFile); + setTimeout(function() { + contentStream.write(expectedContents); + contentStream.end(); + }, 100); + stream.end(); + }); + it('should set the mode of a written stream file if set on the vinyl object', function(done) { if (isWindows) { this.skip(); @@ -143,6 +184,41 @@ describe('.dest() with custom modes', function() { stream.end(); }); + it('should set sticky bit on the mode of a written directory if set on the vinyl object', function(done) { + if (isWindows) { + this.skip(); + return; + } + + var inputPath = path.join(__dirname, './fixtures/test'); + var inputBase = path.join(__dirname, './fixtures/'); + var expectedPath = path.join(__dirname, './out-fixtures/test'); + var expectedMode = parseInt('1655', 8); + + var expectedFile = new File({ + base: inputBase, + cwd: __dirname, + path: inputPath, + contents: null, + stat: { + isDirectory: function() { + return true; + }, + mode: expectedMode, + }, + }); + + var onEnd = function() { + expect(masked(fs.lstatSync(expectedPath).mode)).toEqual(expectedMode); + done(); + }; + + var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); + stream.on('end', onEnd); + stream.write(expectedFile); + stream.end(); + }); + it('should write new files with the mode specified in options', function(done) { if (isWindows) { this.skip(); @@ -255,11 +331,13 @@ describe('.dest() with custom modes', function() { return; } + var inputBase = path.join(__dirname, './fixtures'); var inputPath = path.join(__dirname, './fixtures/wow/suchempty'); var expectedBase = path.join(__dirname, './out-fixtures/wow'); var expectedPath = path.join(__dirname, './out-fixtures/wow/suchempty'); - var expectedDirMode = parseInt('755', 8); + // NOTE: Darwin does not set setgid + var expectedDirMode = isDarwin ? parseInt('755', 8) : parseInt('2755', 8); var expectedFileMode = parseInt('655', 8); var firstFile = new File({ @@ -322,7 +400,7 @@ describe('.dest() with custom modes', function() { stream.end(); }); - it('should see a file with special chmod (setuid/setgid/sticky) as matching', function(done) { + it('should see a file with special chmod (setuid/setgid/sticky) as distinct', function(done) { if (isWindows) { this.skip(); return; @@ -349,7 +427,7 @@ describe('.dest() with custom modes', function() { }); var onEnd = function() { - expect(fchmodSpy.calls.length).toEqual(0); + expect(fchmodSpy.calls.length).toEqual(1); done(); }; diff --git a/test/fileOperations.js b/test/fileOperations.js index c5ccaac6..568263cf 100644 --- a/test/fileOperations.js +++ b/test/fileOperations.js @@ -21,7 +21,7 @@ var updateMetadata = fo.updateMetadata; var resolution = defaultResolution(); -var MASK_MODE = parseInt('777', 8); +var MASK_MODE = parseInt('7777', 8); function masked(mode) { return mode & MASK_MODE; @@ -170,13 +170,13 @@ describe('getModeDiff', function() { done(); }); - it('ignores the sticky/setuid/setgid bits', function(done) { + it('includes the sticky/setuid/setgid bits', function(done) { var fsMode = parseInt('1777', 8); var vfsMode = parseInt('4777', 8); var result = getModeDiff(fsMode, vfsMode); - expect(result).toEqual(0); + expect(result).toEqual(fsMode ^ vfsMode); done(); }); @@ -795,6 +795,29 @@ describe('updateMetadata', function() { }); }); + + it('updates the sticky bit on mode on fs and vinyl object if there is a diff', function(done) { + if (isWindows) { + this.skip(); + return; + } + + var fchmodSpy = expect.spyOn(fs, 'fchmod').andCallThrough(); + + var mode = parseInt('1777', 8); + file.stat.mode = mode; + + var fd = fs.openSync(inputPath, 'w+'); + + updateMetadata(fd, file, function(err, fd2) { + expect(fchmodSpy.calls.length).toEqual(1); + var stats = fs.fstatSync(fd); + expect(file.stat.mode).toEqual(stats.mode); + + fs.close(fd2, done); + }); + }); + it('forwards fchmod error and descriptor upon error', function(done) { if (isWindows) { this.skip();