Skip to content

Commit

Permalink
fix(runtime/fs): preserve permissions in copyFileSync for macOS (deno…
Browse files Browse the repository at this point in the history
  • Loading branch information
littledivy committed Jan 14, 2023
1 parent 6878234 commit ae2981d
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 2 deletions.
27 changes: 27 additions & 0 deletions cli/tests/unit/copy_file_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,30 @@ Deno.test(
}, Deno.errors.PermissionDenied);
},
);

function copyFileSyncMode(content: string): void {
const tempDir = Deno.makeTempDirSync();
const fromFilename = tempDir + "/from.txt";
const toFilename = tempDir + "/to.txt";
Deno.writeTextFileSync(fromFilename, content);
Deno.chmodSync(fromFilename, 0o100755);

Deno.copyFileSync(fromFilename, toFilename);
const toStat = Deno.statSync(toFilename);
assertEquals(toStat.mode!, 0o100755);
}

Deno.test(
{
ignore: Deno.build.os === "windows",
permissions: { read: true, write: true },
},
function copyFileSyncChmod() {
// this Tests different optimization paths on MacOS:
//
// < 128 KB clonefile() w/ fallback to copyfile()
// > 128 KB
copyFileSyncMode("Hello world!");
copyFileSyncMode("Hello world!".repeat(128 * 1024));
},
);
21 changes: 19 additions & 2 deletions runtime/ops/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,8 @@ fn op_copy_file_sync(
use libc::unlink;
use std::ffi::CString;
use std::io::Read;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::fs::PermissionsExt;

let from = CString::new(from).unwrap();
let to = CString::new(to).unwrap();
Expand Down Expand Up @@ -909,8 +911,23 @@ fn op_copy_file_sync(
let mut buf = [0u8; 128 * 1024];
let mut from_file =
std::fs::File::open(&from_path).map_err(err_mapper)?;
let mut to_file =
std::fs::File::create(&to_path).map_err(err_mapper)?;
let perm = from_file.metadata().map_err(err_mapper)?.permissions();

let mut to_file = std::fs::OpenOptions::new()
// create the file with the correct mode right away
.mode(perm.mode())
.write(true)
.create(true)
.truncate(true)
.open(&to_path)
.map_err(err_mapper)?;
let writer_metadata = to_file.metadata()?;
if writer_metadata.is_file() {
// Set the correct file permissions, in case the file already existed.
// Don't set the permissions on already existing non-files like
// pipes/FIFOs or device nodes.
to_file.set_permissions(perm)?;
}
loop {
let nread = from_file.read(&mut buf).map_err(err_mapper)?;
if nread == 0 {
Expand Down

0 comments on commit ae2981d

Please sign in to comment.