rust-chg: send client side umask to server
authorYuya Nishihara <yuya@tcha.org>
Thu, 04 Oct 2018 22:44:37 +0900
changeset 44684 065048e66f32
parent 44683 9ce613d648de
child 44685 80d6e3415636
rust-chg: send client side umask to server This is equivalent to forwardumask() of hgclient.c. Differential Revision: https://phab.mercurial-scm.org/D8382
rust/chg/src/clientext.rs
rust/chg/src/locator.rs
rust/chg/src/main.rs
rust/chg/src/procutil.rs
--- a/rust/chg/src/clientext.rs	Sun Oct 07 16:14:21 2018 +0900
+++ b/rust/chg/src/clientext.rs	Thu Oct 04 22:44:37 2018 +0900
@@ -5,9 +5,10 @@
 
 //! cHg extensions to command server client.
 
-use bytes::Bytes;
+use bytes::{BufMut, Bytes, BytesMut};
 use std::ffi::OsStr;
 use std::io;
+use std::mem;
 use std::os::unix::ffi::OsStrExt;
 use std::os::unix::io::AsRawFd;
 use std::path::Path;
@@ -41,6 +42,9 @@
         I: IntoIterator<Item = (P, P)>,
         P: AsRef<OsStr>;
 
+    /// Changes the umask of the server process.
+    fn set_umask(self, mask: u32) -> OneShotRequest<C>;
+
     /// Runs the specified Mercurial command with cHg extension.
     fn run_command_chg<I, P, H>(self, handler: H, args: I) -> ChgRunCommand<C, H>
     where
@@ -90,6 +94,12 @@
         OneShotRequest::start_with_args(self, b"setenv", message::pack_env_vars_os(vars))
     }
 
+    fn set_umask(self, mask: u32) -> OneShotRequest<C> {
+        let mut args = BytesMut::with_capacity(mem::size_of_val(&mask));
+        args.put_u32_be(mask);
+        OneShotRequest::start_with_args(self, b"setumask2", args)
+    }
+
     fn run_command_chg<I, P, H>(self, handler: H, args: I) -> ChgRunCommand<C, H>
     where
         I: IntoIterator<Item = P>,
--- a/rust/chg/src/locator.rs	Sun Oct 07 16:14:21 2018 +0900
+++ b/rust/chg/src/locator.rs	Thu Oct 04 22:44:37 2018 +0900
@@ -24,8 +24,14 @@
 use super::message::{Instruction, ServerSpec};
 use super::procutil;
 
-const REQUIRED_SERVER_CAPABILITIES: &[&str] =
-    &["attachio", "chdir", "runcommand", "setenv", "validate"];
+const REQUIRED_SERVER_CAPABILITIES: &[&str] = &[
+    "attachio",
+    "chdir",
+    "runcommand",
+    "setenv",
+    "setumask2",
+    "validate",
+];
 
 /// Helper to connect to and spawn a server process.
 #[derive(Clone, Debug)]
--- a/rust/chg/src/main.rs	Sun Oct 07 16:14:21 2018 +0900
+++ b/rust/chg/src/main.rs	Thu Oct 04 22:44:37 2018 +0900
@@ -73,6 +73,7 @@
 }
 
 fn run() -> io::Result<i32> {
+    let umask = unsafe { procutil::get_umask() }; // not thread safe
     let mut loc = Locator::prepare_from_env()?;
     loc.set_early_args(locator::collect_early_args(env::args_os().skip(1)));
     let handler = ChgUiHandler::new();
@@ -80,6 +81,7 @@
     let fut = loc
         .connect()
         .and_then(|(_, client)| client.attach_io(io::stdin(), io::stdout(), io::stderr()))
+        .and_then(move |client| client.set_umask(umask))
         .and_then(|client| {
             let pid = client.server_spec().process_id.unwrap();
             let pgid = client.server_spec().process_group_id;
--- a/rust/chg/src/procutil.rs	Sun Oct 07 16:14:21 2018 +0900
+++ b/rust/chg/src/procutil.rs	Thu Oct 04 22:44:37 2018 +0900
@@ -25,6 +25,19 @@
     unsafe { libc::geteuid() }
 }
 
+/// Returns the umask of the current process.
+///
+/// # Safety
+///
+/// This is unsafe because the umask value is temporarily changed, and
+/// the change can be observed from the other threads. Don't call this in
+/// multi-threaded context.
+pub unsafe fn get_umask() -> u32 {
+    let mask = libc::umask(0);
+    libc::umask(mask);
+    mask
+}
+
 /// Changes the given fd to blocking mode.
 pub fn set_blocking_fd(fd: RawFd) -> io::Result<()> {
     let flags = unsafe { libc::fcntl(fd, libc::F_GETFL) };