From 51513ae19a2b260ba33bdb37dd910b290b96d64a Mon Sep 17 00:00:00 2001 From: Tarcisio Gruppi Date: Tue, 1 Feb 2022 09:49:06 -0300 Subject: [PATCH] vfmt: keep file permissions with -w on !windows (#13334) --- cmd/tools/vfmt.v | 8 ++++++++ vlib/os/inode.c.v | 22 ++++++++++++++++++++++ vlib/os/inode_test.v | 13 +++++++++++++ 3 files changed, 43 insertions(+) diff --git a/cmd/tools/vfmt.v b/cmd/tools/vfmt.v index 9390dd23a7..c8c588686e 100644 --- a/cmd/tools/vfmt.v +++ b/cmd/tools/vfmt.v @@ -259,7 +259,15 @@ fn (foptions &FormatOptions) post_process_file(file string, formatted_file_path file_bak := '${file}.bak' os.cp(file, file_bak) or {} } + mut perms_to_restore := u32(0) + $if !windows { + fm := os.inode(file) + perms_to_restore = fm.bitmask() + } os.mv_by_cp(formatted_file_path, file) or { panic(err) } + $if !windows { + os.chmod(file, int(perms_to_restore)) or { panic(err) } + } eprintln('Reformatted file: $file') } else { eprintln('Already formatted file: $file') diff --git a/vlib/os/inode.c.v b/vlib/os/inode.c.v index 230c9c23ae..0c8296c320 100644 --- a/vlib/os/inode.c.v +++ b/vlib/os/inode.c.v @@ -20,6 +20,22 @@ pub: execute bool } +// bitmask returns a 3 bit sequence in the order RWE where +// the bit is set to 1 if the value is true or 0 otherwise. +pub fn (p FilePermission) bitmask() u32 { + mut mask := u32(0) + if p.read { + mask |= 4 + } + if p.write { + mask |= 2 + } + if p.execute { + mask |= 1 + } + return mask +} + struct FileMode { pub: typ FileType @@ -28,6 +44,12 @@ pub: others FilePermission } +// bitmask returns a 9 bit sequence in the order owner + group + others. +// This is a valid bitmask to use with `os.chmod`. +pub fn (m FileMode) bitmask() u32 { + return m.owner.bitmask() << 6 | m.group.bitmask() << 3 | m.others.bitmask() +} + // inode returns the mode of the file/inode containing inode type and permission information // it supports windows for regular files but it doesn't matter if you use owner, group or others when checking permissions on windows pub fn inode(path string) FileMode { diff --git a/vlib/os/inode_test.v b/vlib/os/inode_test.v index f716bc2765..eaa31852bc 100644 --- a/vlib/os/inode_test.v +++ b/vlib/os/inode_test.v @@ -41,3 +41,16 @@ fn test_inode_file_owner_permission() { assert mode.owner.write assert !mode.owner.execute } + +fn test_inode_file_permissions_bitmask() { + if user_os() == 'windows' { + println('> skipping ${@FN} on windows') + return + } + filename := './test3.txt' + mut file := open_file(filename, 'w', 0o641) or { return } + file.close() + mode := inode(filename) + rm(filename) or {} + assert mode.bitmask() == 0o641 +}