From a9b4e7b8722a2ec3e7520cd2ab2eea0c1b09d109 Mon Sep 17 00:00:00 2001 From: JrainLau Date: Wed, 6 Mar 2024 07:47:13 +0800 Subject: [PATCH] fix: fix symlink pointing error in filesystem.insertLink (#301) Co-authored-by: jrainliu --- lib/filesystem.js | 4 +++- test/api-spec.js | 5 +++++ test/input/packthis-with-symlink/A/real.txt | 1 + test/input/packthis-with-symlink/Current | 1 + test/input/packthis-with-symlink/real.txt | 1 + test/util/compareFiles.js | 17 +++++++++++++++-- 6 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 test/input/packthis-with-symlink/A/real.txt create mode 120000 test/input/packthis-with-symlink/Current create mode 120000 test/input/packthis-with-symlink/real.txt diff --git a/lib/filesystem.js b/lib/filesystem.js index f61c041..27b00a1 100644 --- a/lib/filesystem.js +++ b/lib/filesystem.js @@ -99,7 +99,9 @@ class Filesystem { } insertLink (p) { - const link = path.relative(fs.realpathSync(this.src), fs.realpathSync(p)) + const symlink = fs.readlinkSync(p) + const parentPath = path.dirname(p) + const link = path.relative(fs.realpathSync(this.src), path.join(parentPath, symlink)) if (link.substr(0, 2) === '..') { throw new Error(`${p}: file "${link}" links out of the package`) } diff --git a/test/api-spec.js b/test/api-spec.js index d50323d..2239d1a 100644 --- a/test/api-spec.js +++ b/test/api-spec.js @@ -81,6 +81,11 @@ describe('api', function () { asar.extractAll('test/input/extractthis-unpack-dir.asar', 'tmp/extractthis-unpack-dir-api/') return compDirs('tmp/extractthis-unpack-dir-api/', 'test/expected/extractthis') }) + it('should extract an archive with symlink', async () => { + await asar.createPackageWithOptions('test/input/packthis-with-symlink/', 'tmp/packthis-with-symlink.asar', { dot: false }) + asar.extractAll('tmp/packthis-with-symlink.asar', 'tmp/packthis-with-symlink/') + return compFiles('tmp/packthis-with-symlink/real.txt', 'test/input/packthis-with-symlink/real.txt') + }) it('should handle multibyte characters in paths', async () => { await asar.createPackageWithOptions('test/input/packthis-unicode-path/', 'tmp/packthis-unicode-path.asar', { globOptions: { diff --git a/test/input/packthis-with-symlink/A/real.txt b/test/input/packthis-with-symlink/A/real.txt new file mode 100644 index 0000000..59f6076 --- /dev/null +++ b/test/input/packthis-with-symlink/A/real.txt @@ -0,0 +1 @@ +I AM REAL TXT FILE diff --git a/test/input/packthis-with-symlink/Current b/test/input/packthis-with-symlink/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/test/input/packthis-with-symlink/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/test/input/packthis-with-symlink/real.txt b/test/input/packthis-with-symlink/real.txt new file mode 120000 index 0000000..abbcc03 --- /dev/null +++ b/test/input/packthis-with-symlink/real.txt @@ -0,0 +1 @@ +Current/real.txt \ No newline at end of file diff --git a/test/util/compareFiles.js b/test/util/compareFiles.js index 485ba2b..d80d9aa 100644 --- a/test/util/compareFiles.js +++ b/test/util/compareFiles.js @@ -7,6 +7,19 @@ module.exports = async function (actualFilePath, expectedFilePath) { if (process.env.ELECTRON_ASAR_SPEC_UPDATE) { await fs.writeFile(expectedFilePath, await fs.readFile(actualFilePath)) } - const [actual, expected] = await Promise.all([fs.readFile(actualFilePath, 'utf8'), fs.readFile(expectedFilePath, 'utf8')]) - assert.strictEqual(actual, expected) + const [actualFileContent, expectedFileContent] = await Promise.all([fs.readFile(actualFilePath, 'utf8'), fs.readFile(expectedFilePath, 'utf8')]) + assert.strictEqual(actualFileContent, expectedFileContent) + + const [actualIsSymlink, expectedIsSymlink] = [isSymbolicLinkSync(actualFilePath), isSymbolicLinkSync(expectedFilePath)] + assert.strictEqual(actualIsSymlink, expectedIsSymlink) + + if (actualIsSymlink && expectedIsSymlink) { + const [actualSymlinkPointer, expectedSymlinkPointer] = [fs.readlinkSync(actualFilePath), fs.readlinkSync(expectedFilePath)] + assert.strictEqual(actualSymlinkPointer, expectedSymlinkPointer) + } +} + +function isSymbolicLinkSync (path) { + const stats = fs.lstatSync(path) + return stats.isSymbolicLink() }