##// END OF EJS Templates
copies: follow copies across merge base without source file (issue6163)...
copies: follow copies across merge base without source file (issue6163) As in the previous patch, consider these two histories: @ 4 'rename x to y' | o 3 'add x again' | o 2 'remove x' | | o 1 'modify x' |/ o 0 'add x' @ 4 'rename x to y' | o 3 'add x again' | | o 2 'modify x' | | | o 1 'add x' |/ o 0 'base' We trace copies from the 'modify x' commit to commit 4 by going via the merge base (commit 0). When tracing file 'y' (_tracefile()) in the first case, we immediately find the rename from 'x'. We check to see if 'x' exists in the merge base, which it does, so we consider it a valid copy. In the second case, 'x' does not exist in the merge base, so it's not considered a valid copy. As a workaround, this patch makes it so we also attempt the check in mergecopies's base commit (commit 1 in the second case). That feels pretty ugly to me, but I don't have any better ideas. Note that we actually also check not only that the filename matches, but also that the file's nodeid matches. I don't know why we do that, but it was like that already before I rewrote mergecopies(). That means that the rebase will still fail in cases like this (again, it already failed before my rewrite): @ 4 'rename x to y' | o 3 'add x again with content X2' | o 2 'remove x' | | o 1 'modify x to content X2' |/ o 1 'modify x to content X1' | o 0 'add x with content X0' Differential Revision: https://phab.mercurial-scm.org/D6604

File last commit:

r40156:89742f1f default
r42798:819712de default
Show More
procutil.rs
87 lines | 2.5 KiB | application/rls-services+xml | RustLexer
// Copyright 2018 Yuya Nishihara <yuya@tcha.org>
//
// This software may be used and distributed according to the terms of the
// GNU General Public License version 2 or any later version.
//! Low-level utility for signal and process handling.
use libc::{self, c_int, pid_t, size_t, ssize_t};
use std::io;
use std::os::unix::io::RawFd;
use std::sync;
#[link(name = "procutil", kind = "static")]
extern "C" {
// sendfds.c
fn sendfds(sockfd: c_int, fds: *const c_int, fdlen: size_t) -> ssize_t;
// sighandlers.c
fn setupsignalhandler(pid: pid_t, pgid: pid_t) -> c_int;
fn restoresignalhandler() -> c_int;
}
/// Returns the effective uid of the current process.
pub fn get_effective_uid() -> u32 {
unsafe { libc::geteuid() }
}
/// 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) };
if flags < 0 {
return Err(io::Error::last_os_error());
}
let r = unsafe { libc::fcntl(fd, libc::F_SETFL, flags & !libc::O_NONBLOCK) };
if r < 0 {
return Err(io::Error::last_os_error())
}
Ok(())
}
/// Sends file descriptors via the given socket.
pub fn send_raw_fds(sock_fd: RawFd, fds: &[RawFd]) -> io::Result<()> {
let r = unsafe { sendfds(sock_fd, fds.as_ptr(), fds.len() as size_t) };
if r < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
static SETUP_SIGNAL_HANDLER: sync::Once = sync::Once::new();
static RESTORE_SIGNAL_HANDLER: sync::Once = sync::Once::new();
/// Installs signal handlers to forward signals to the server.
///
/// # Safety
///
/// This touches global states, and thus synchronized as a one-time
/// initialization function.
pub fn setup_signal_handler_once(pid: u32, pgid: Option<u32>) -> io::Result<()> {
let pid_signed = pid as i32;
let pgid_signed = pgid.map(|n| n as i32).unwrap_or(0);
let mut r = 0;
SETUP_SIGNAL_HANDLER.call_once(|| {
r = unsafe { setupsignalhandler(pid_signed, pgid_signed) };
});
if r < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
/// Restores the original signal handlers.
///
/// # Safety
///
/// This touches global states, and thus synchronized as a one-time
/// initialization function.
pub fn restore_signal_handler_once() -> io::Result<()> {
let mut r = 0;
RESTORE_SIGNAL_HANDLER.call_once(|| {
r = unsafe { restoresignalhandler() };
});
if r < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}