From a0051718865ce0539313a96b7d55589d1b7175a7 Mon Sep 17 00:00:00 2001 From: DragonRaider5 Date: Tue, 8 Jan 2019 19:24:51 +0100 Subject: [PATCH 1/8] Added option to follow symlinks --- lib/core.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/core.js b/lib/core.js index f7424885..34857e5a 100644 --- a/lib/core.js +++ b/lib/core.js @@ -43,6 +43,7 @@ var Archiver = function(format, options) { this._module = false; this._pending = 0; this._pointer = 0; + this._followSymlinks = options.followSymlinks; this._entriesCount = 0; this._entriesProcessedCount = 0; @@ -493,10 +494,16 @@ Archiver.prototype._updateQueueTaskWithStats = function(task, stats) { } else if (stats.isSymbolicLink() && this._moduleSupports('symlink')) { var linkPath = fs.readlinkSync(task.filepath); var dirName = path.dirname(task.filepath); - task.data.type = 'symlink'; - task.data.linkname = path.relative(dirName, path.resolve(dirName, linkPath)); - task.data.sourceType = 'buffer'; - task.source = Buffer.concat([]); + + if (this._followSymlinks) { + task.filepath = linkPath; + return this._updateQueueTaskWithStats(task, fs.lstatSync(task.filepath)); + } else { + task.data.type = 'symlink'; + task.data.linkname = path.relative(dirName, path.resolve(dirName, linkPath)); + task.data.sourceType = 'buffer'; + task.source = Buffer.concat([]); + } } else { if (stats.isDirectory()) { this.emit('warning', new ArchiverError('DIRECTORYNOTSUPPORTED', task.data)); From 5ebc795bf213b50c0f3a13d9cda4108e4b933333 Mon Sep 17 00:00:00 2001 From: DragonRaider5 Date: Tue, 8 Jan 2019 20:39:22 +0100 Subject: [PATCH 2/8] Fixed filepath generation for linked files when following symlinks --- lib/core.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/core.js b/lib/core.js index 34857e5a..f86f2dac 100644 --- a/lib/core.js +++ b/lib/core.js @@ -496,8 +496,10 @@ Archiver.prototype._updateQueueTaskWithStats = function(task, stats) { var dirName = path.dirname(task.filepath); if (this._followSymlinks) { - task.filepath = linkPath; - return this._updateQueueTaskWithStats(task, fs.lstatSync(task.filepath)); + task.filepath = path.resolve(dirName, linkPath); + var stats = fs.lstatSync(task.filepath); + + return this._updateQueueTaskWithStats(task, stats); } else { task.data.type = 'symlink'; task.data.linkname = path.relative(dirName, path.resolve(dirName, linkPath)); From 063583bf1023d46eabe80965f2b8ab12c9162d07 Mon Sep 17 00:00:00 2001 From: DragonRaider5 Date: Tue, 8 Jan 2019 20:43:29 +0100 Subject: [PATCH 3/8] Added recursive statTasks to be able to properly handle symlinked directories Recursive statTasks scan the directory currently beeing statted in case it is a directory and append their contents to the statTask queue --- lib/core.js | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/lib/core.js b/lib/core.js index f86f2dac..58902496 100644 --- a/lib/core.js +++ b/lib/core.js @@ -92,12 +92,13 @@ Archiver.prototype._abort = function() { * @param {EntryData} data The entry data. * @return void */ -Archiver.prototype._append = function(filepath, data) { +Archiver.prototype._append = function(filepath, data, recursive) { data = data || {}; var task = { source: null, - filepath: filepath + filepath: filepath, + recursive: recursive || false }; if (!data.name) { @@ -440,7 +441,32 @@ Archiver.prototype._onStatQueueTask = function(task, callback) { this._queue.push(task); } - setImmediate(callback); + if (task.recursive && stats.isDirectory()) { + fs.readdir(task.filepath, (err, files) => { + if (this._state.aborted) { + setImmediate(callback); + return; + } + + if (err) { + this.emit('warning', err); + setImmediate(callback); + return; + } + + files.forEach((filename) => { + if (filename === '.' || filename === '..') { + return; + } + + this._append(path.join(task.filepath, filename), null, true) + }) + + setImmediate(callback); + }) + } else { + setImmediate(callback); + } }.bind(this)); }; @@ -497,9 +523,8 @@ Archiver.prototype._updateQueueTaskWithStats = function(task, stats) { if (this._followSymlinks) { task.filepath = path.resolve(dirName, linkPath); - var stats = fs.lstatSync(task.filepath); - - return this._updateQueueTaskWithStats(task, stats); + task.recursive = true + return this._updateQueueTaskWithStats(task, fs.lstatSync(task.filepath)); } else { task.data.type = 'symlink'; task.data.linkname = path.relative(dirName, path.resolve(dirName, linkPath)); From 295d55296dc9a1ca7464175947393c54bd32a8b4 Mon Sep 17 00:00:00 2001 From: DragonRaider5 Date: Tue, 8 Jan 2019 22:21:02 +0100 Subject: [PATCH 4/8] Added missing semicolon --- lib/core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core.js b/lib/core.js index 58902496..56932335 100644 --- a/lib/core.js +++ b/lib/core.js @@ -523,7 +523,7 @@ Archiver.prototype._updateQueueTaskWithStats = function(task, stats) { if (this._followSymlinks) { task.filepath = path.resolve(dirName, linkPath); - task.recursive = true + task.recursive = true; return this._updateQueueTaskWithStats(task, fs.lstatSync(task.filepath)); } else { task.data.type = 'symlink'; From 19be2a4a460578e0c32cd718051fa1bce54dd53f Mon Sep 17 00:00:00 2001 From: DragonRaider5 Date: Tue, 8 Jan 2019 22:22:20 +0100 Subject: [PATCH 5/8] Fixed entire paths of resolved symlinked files beeing put into the archive --- lib/core.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/core.js b/lib/core.js index 56932335..9e341b16 100644 --- a/lib/core.js +++ b/lib/core.js @@ -459,7 +459,9 @@ Archiver.prototype._onStatQueueTask = function(task, callback) { return; } - this._append(path.join(task.filepath, filename), null, true) + this._append(path.join(task.filepath, filename), { + name: path.join(task.data.name, filename) + }, true) }) setImmediate(callback); From 2d69a8f33eaed931b2b87dfb2d0a989618b0923d Mon Sep 17 00:00:00 2001 From: DragonRaider5 Date: Tue, 8 Jan 2019 22:23:13 +0100 Subject: [PATCH 6/8] Fixed detection of symlinked directories when following symlinks --- lib/core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core.js b/lib/core.js index 9e341b16..af53e2c0 100644 --- a/lib/core.js +++ b/lib/core.js @@ -441,7 +441,7 @@ Archiver.prototype._onStatQueueTask = function(task, callback) { this._queue.push(task); } - if (task.recursive && stats.isDirectory()) { + if (task.recursive && task.data.type === 'directory') { fs.readdir(task.filepath, (err, files) => { if (this._state.aborted) { setImmediate(callback); From 35d40e0735e8cc43dc0d3cafbc2afa53448df673 Mon Sep 17 00:00:00 2001 From: DragonRaider5 Date: Mon, 14 Jan 2019 14:04:49 +0100 Subject: [PATCH 7/8] Switched from arrow functions to normal functions with bind --- lib/core.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/core.js b/lib/core.js index af53e2c0..ea79b06d 100644 --- a/lib/core.js +++ b/lib/core.js @@ -442,7 +442,7 @@ Archiver.prototype._onStatQueueTask = function(task, callback) { } if (task.recursive && task.data.type === 'directory') { - fs.readdir(task.filepath, (err, files) => { + fs.readdir(task.filepath, function(err, files) { if (this._state.aborted) { setImmediate(callback); return; @@ -454,7 +454,7 @@ Archiver.prototype._onStatQueueTask = function(task, callback) { return; } - files.forEach((filename) => { + files.forEach(function(filename) { if (filename === '.' || filename === '..') { return; } @@ -462,10 +462,10 @@ Archiver.prototype._onStatQueueTask = function(task, callback) { this._append(path.join(task.filepath, filename), { name: path.join(task.data.name, filename) }, true) - }) + }.bind(this)); setImmediate(callback); - }) + }.bind(this)); } else { setImmediate(callback); } From aec7f3b0edacf9c422e914ac2401a706137c8c14 Mon Sep 17 00:00:00 2001 From: DragonRaider5 Date: Mon, 14 Jan 2019 16:05:38 +0100 Subject: [PATCH 8/8] Added missing semicolon --- lib/core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core.js b/lib/core.js index ea79b06d..4ae98d63 100644 --- a/lib/core.js +++ b/lib/core.js @@ -461,7 +461,7 @@ Archiver.prototype._onStatQueueTask = function(task, callback) { this._append(path.join(task.filepath, filename), { name: path.join(task.data.name, filename) - }, true) + }, true); }.bind(this)); setImmediate(callback);