annotate rust/hg-core/src/lock.rs @ 51470:406b413e3cf2 stable

rust-filepatterns: export glob_to_re function Making this function public should not risk freezing the internal API, and it can be useful for all downstream code that needs to perform glob matching against byte strings, such as RHGitaly where it will be useful to match on branches and tags.
author Georges Racinet <georges.racinet@octobus.net>
date Mon, 11 Mar 2024 13:23:18 +0100
parents e98fd81bb151
children db7dbe6f7bb2
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
1 //! Filesystem-based locks for local repositories
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
2
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
3 use crate::errors::HgError;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
4 use crate::errors::HgResultExt;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
5 use crate::vfs::Vfs;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
6 use std::io;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
7 use std::io::ErrorKind;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
8
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
9 #[derive(derive_more::From)]
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
10 pub enum LockError {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
11 AlreadyHeld,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
12 #[from]
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
13 Other(HgError),
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
14 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
15
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
16 /// Try to call `f` with the lock acquired, without waiting.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
17 ///
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
18 /// If the lock is aready held, `f` is not called and `LockError::AlreadyHeld`
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
19 /// is returned. `LockError::Io` is returned for any unexpected I/O error
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
20 /// accessing the lock file, including for removing it after `f` was called.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
21 /// The return value of `f` is dropped in that case. If all is successful, the
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
22 /// return value of `f` is forwarded.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
23 pub fn try_with_lock_no_wait<R>(
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
24 hg_vfs: Vfs,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
25 lock_filename: &str,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
26 f: impl FnOnce() -> R,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
27 ) -> Result<R, LockError> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
28 let our_lock_data = &*OUR_LOCK_DATA;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
29 for _retry in 0..5 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
30 match make_lock(hg_vfs, lock_filename, our_lock_data) {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
31 Ok(()) => {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
32 let result = f();
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
33 unlock(hg_vfs, lock_filename)?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
34 return Ok(result);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
35 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
36 Err(HgError::IoError { error, .. })
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
37 if error.kind() == ErrorKind::AlreadyExists =>
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
38 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
39 let lock_data = read_lock(hg_vfs, lock_filename)?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
40 if lock_data.is_none() {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
41 // Lock was apparently just released, retry acquiring it
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
42 continue;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
43 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
44 if !lock_should_be_broken(&lock_data) {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
45 return Err(LockError::AlreadyHeld);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
46 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
47 // The lock file is left over from a process not running
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
48 // anymore. Break it, but with another lock to
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
49 // avoid a race.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
50 break_lock(hg_vfs, lock_filename)?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
51
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
52 // Retry acquiring
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
53 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
54 Err(error) => Err(error)?,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
55 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
56 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
57 Err(LockError::AlreadyHeld)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
58 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
59
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
60 fn break_lock(hg_vfs: Vfs, lock_filename: &str) -> Result<(), LockError> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
61 try_with_lock_no_wait(hg_vfs, &format!("{}.break", lock_filename), || {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
62 // Check again in case some other process broke and
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
63 // acquired the lock in the meantime
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
64 let lock_data = read_lock(hg_vfs, lock_filename)?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
65 if !lock_should_be_broken(&lock_data) {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
66 return Err(LockError::AlreadyHeld);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
67 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
68 Ok(hg_vfs.remove_file(lock_filename)?)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
69 })?
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
70 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
71
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
72 #[cfg(unix)]
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
73 fn make_lock(
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
74 hg_vfs: Vfs,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
75 lock_filename: &str,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
76 data: &str,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
77 ) -> Result<(), HgError> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
78 // Use a symbolic link because creating it is atomic.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
79 // The link’s "target" contains data not representing any path.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
80 let fake_symlink_target = data;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
81 hg_vfs.create_symlink(lock_filename, fake_symlink_target)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
82 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
83
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
84 fn read_lock(
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
85 hg_vfs: Vfs,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
86 lock_filename: &str,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
87 ) -> Result<Option<String>, HgError> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
88 let link_target =
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
89 hg_vfs.read_link(lock_filename).io_not_found_as_none()?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
90 if let Some(target) = link_target {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
91 let data = target
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
92 .into_os_string()
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
93 .into_string()
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
94 .map_err(|_| HgError::corrupted("non-UTF-8 lock data"))?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
95 Ok(Some(data))
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
96 } else {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
97 Ok(None)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
98 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
99 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
100
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
101 fn unlock(hg_vfs: Vfs, lock_filename: &str) -> Result<(), HgError> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
102 hg_vfs.remove_file(lock_filename)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
103 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
104
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
105 /// Return whether the process that is/was holding the lock is known not to be
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
106 /// running anymore.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
107 fn lock_should_be_broken(data: &Option<String>) -> bool {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
108 (|| -> Option<bool> {
49632
29cf3167e459 hg-core: remove unneeded trait now that we support Rust 1.52+
Raphaël Gomès <rgomes@octobus.net>
parents: 48962
diff changeset
109 let (prefix, pid) = data.as_ref()?.split_once(':')?;
49930
e98fd81bb151 rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents: 49632
diff changeset
110 if prefix != *LOCK_PREFIX {
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
111 return Some(false);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
112 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
113 let process_is_running;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
114
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
115 #[cfg(unix)]
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
116 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
117 let pid: libc::pid_t = pid.parse().ok()?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
118 unsafe {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
119 let signal = 0; // Test if we could send a signal, without sending
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
120 let result = libc::kill(pid, signal);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
121 if result == 0 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
122 process_is_running = true
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
123 } else {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
124 let errno =
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
125 io::Error::last_os_error().raw_os_error().unwrap();
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
126 process_is_running = errno != libc::ESRCH
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
127 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
128 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
129 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
130
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
131 Some(!process_is_running)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
132 })()
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
133 .unwrap_or(false)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
134 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
135
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
136 lazy_static::lazy_static! {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
137 /// A string which is used to differentiate pid namespaces
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
138 ///
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
139 /// It's useful to detect "dead" processes and remove stale locks with
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
140 /// confidence. Typically it's just hostname. On modern linux, we include an
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
141 /// extra Linux-specific pid namespace identifier.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
142 static ref LOCK_PREFIX: String = {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
143 // Note: this must match the behavior of `_getlockprefix` in `mercurial/lock.py`
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
144
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
145 /// Same as https://github.com/python/cpython/blob/v3.10.0/Modules/socketmodule.c#L5414
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
146 const BUFFER_SIZE: usize = 1024;
49930
e98fd81bb151 rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents: 49632
diff changeset
147 // This cast is *needed* for platforms with signed chars
e98fd81bb151 rust-clippy: fix most warnings in `hg-core`
Raphaël Gomès <rgomes@octobus.net>
parents: 49632
diff changeset
148 #[allow(clippy::unnecessary_cast)]
48962
59be65b7cdfd rust-hg-core: use correct type for libc hostname buffer
Luke Granger-Brown <hg@lukegb.com>
parents: 48417
diff changeset
149 let mut buffer = [0 as libc::c_char; BUFFER_SIZE];
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
150 let hostname_bytes = unsafe {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
151 let result = libc::gethostname(buffer.as_mut_ptr(), BUFFER_SIZE);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
152 if result != 0 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
153 panic!("gethostname: {}", io::Error::last_os_error())
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
154 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
155 std::ffi::CStr::from_ptr(buffer.as_mut_ptr()).to_bytes()
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
156 };
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
157 let hostname =
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
158 std::str::from_utf8(hostname_bytes).expect("non-UTF-8 hostname");
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
159
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
160 #[cfg(target_os = "linux")]
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
161 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
162 use std::os::linux::fs::MetadataExt;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
163 match std::fs::metadata("/proc/self/ns/pid") {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
164 Ok(meta) => {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
165 return format!("{}/{:x}", hostname, meta.st_ino())
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
166 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
167 Err(error) => {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
168 // TODO: match on `error.kind()` when `NotADirectory`
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
169 // is available on all supported Rust versions:
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
170 // https://github.com/rust-lang/rust/issues/86442
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
171 use libc::{
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
172 ENOENT, // ErrorKind::NotFound
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
173 ENOTDIR, // ErrorKind::NotADirectory
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
174 EACCES, // ErrorKind::PermissionDenied
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
175 };
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
176 match error.raw_os_error() {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
177 Some(ENOENT) | Some(ENOTDIR) | Some(EACCES) => {}
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
178 _ => panic!("stat /proc/self/ns/pid: {}", error),
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
179 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
180 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
181 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
182 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
183
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
184 hostname.to_owned()
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
185 };
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
186
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
187 static ref OUR_LOCK_DATA: String = format!("{}:{}", &*LOCK_PREFIX, std::process::id());
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
188 }