rust-chg: send client side umask to server
This is equivalent to forwardumask() of hgclient.c.
Differential Revision: https://phab.mercurial-scm.org/D8382
--- 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) };