Skip to content
This repository has been archived by the owner on Jan 13, 2024. It is now read-only.

Commit

Permalink
fix(bootstrap): prevent overriding existing node addon file (#1611)
Browse files Browse the repository at this point in the history
Fixes: #1589 

Co-authored-by: Keimling, Rene <[email protected]>
  • Loading branch information
renkei and Keimling, Rene authored May 9, 2022
1 parent 137a9e0 commit f0c4e8c
Showing 1 changed file with 53 additions and 10 deletions.
63 changes: 53 additions & 10 deletions prelude/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,28 +181,71 @@ function copyInChunks(

// TODO: replace this with fs.cpSync when we drop Node < 16
function copyFolderRecursiveSync(source, target) {
let files = [];

// Check if folder needs to be created or integrated
// Build target folder
const targetFolder = path.join(target, path.basename(source));

// Check if target folder needs to be created or integrated
if (!fs.existsSync(targetFolder)) {
fs.mkdirSync(targetFolder);
}

// Copy
if (fs.lstatSync(source).isDirectory()) {
files = fs.readdirSync(source);
files.forEach((file) => {
const files = fs.readdirSync(source);

for (const file of files) {
// Build source name
const curSource = path.join(source, file);

// Call this function recursively as long as source is a directory
if (fs.lstatSync(curSource).isDirectory()) {
copyFolderRecursiveSync(curSource, targetFolder);
} else {
fs.copyFileSync(
curSource,
path.join(targetFolder, path.basename(curSource))
);
// Current source is a file, it must be available on the real filesystem
// instead of the virtual snapshot file system to load it by process.dlopen.
//
// Before we try to copy we do some checks.
// See https://github.com/vercel/pkg/issues/1589 for more details.

// Build target file name
const curTarget = path.join(targetFolder, path.basename(curSource));

if (fs.existsSync(curTarget)) {
// Target file already exists, read source and target file...
const curSourceContent = fs.readFileSync(curSource, {
encoding: 'binary',
});
const curTargetContent = fs.readFileSync(curTarget, {
encoding: 'binary',
});

// ...and calculate checksum from source and target file
const curSourceHash = createHash('sha256')
.update(curSourceContent)
.digest('hex');
const curTargetHash = createHash('sha256')
.update(curTargetContent)
.digest('hex');

// If checksums are equal then there is nothing to do here
// ==> target already exists and is up-to-date
if (curSourceHash === curTargetHash) {
continue;
}
}

// Target must be copied because it either does not exist or is outdated.
// Due to the possibility that mutliple instances of this app start simultaneously,
// the copy action might fail. Only one starting instance gets write access.
//
// We don't catch any error here because it does not make sense to go ahead and to
// try to load the file while another instance has not yet finished the copy action.
// If the app start fails then the user should try to start the app later again.
// Unfortunately, we cannot implement delayed retries ourselves because process.dlopen
// is a synchronous function, promises are not supported.
fs.copyFileSync(curSource, curTarget);
}
});
}
}
}

Expand Down

0 comments on commit f0c4e8c

Please sign in to comment.