annotate rust/hg-core/src/lock.rs @ 52167:7be39c5110c9

hg-core: add a complete VFS This will be used from Python in a later change. More changes are needed in hg-core and rhg to properly clean up the APIs of the old VFS implementation but it can be done when the dust settles and we start adding more functionality to the pure Rust VFS.
author Rapha?l Gom?s <rgomes@octobus.net>
date Mon, 29 Jul 2024 20:47:43 +0200
parents db7dbe6f7bb2
children
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;
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51864
diff changeset
5 use crate::vfs::Vfs;
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49930
diff changeset
6 use crate::vfs::VfsImpl;
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
7 use std::io;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
8 use std::io::ErrorKind;
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51864
diff changeset
9 use std::path::Path;
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
10
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
11 #[derive(derive_more::From)]
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
12 pub enum LockError {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
13 AlreadyHeld,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
14 #[from]
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
15 Other(HgError),
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
16 }
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 /// Try to call `f` with the lock acquired, without waiting.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
19 ///
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
20 /// 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
21 /// 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
22 /// 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
23 /// 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
24 /// return value of `f` is forwarded.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
25 pub fn try_with_lock_no_wait<R>(
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49930
diff changeset
26 hg_vfs: &VfsImpl,
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
27 lock_filename: &str,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
28 f: impl FnOnce() -> R,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
29 ) -> Result<R, LockError> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
30 let our_lock_data = &*OUR_LOCK_DATA;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
31 for _retry in 0..5 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
32 match make_lock(hg_vfs, lock_filename, our_lock_data) {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
33 Ok(()) => {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
34 let result = f();
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
35 unlock(hg_vfs, lock_filename)?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
36 return Ok(result);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
37 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
38 Err(HgError::IoError { error, .. })
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
39 if error.kind() == ErrorKind::AlreadyExists =>
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
40 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
41 let lock_data = read_lock(hg_vfs, lock_filename)?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
42 if lock_data.is_none() {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
43 // Lock was apparently just released, retry acquiring it
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
44 continue;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
45 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
46 if !lock_should_be_broken(&lock_data) {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
47 return Err(LockError::AlreadyHeld);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
48 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
49 // 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
50 // anymore. Break it, but with another lock to
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
51 // avoid a race.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
52 break_lock(hg_vfs, lock_filename)?;
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 // Retry acquiring
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 Err(error) => Err(error)?,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
57 }
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 Err(LockError::AlreadyHeld)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
60 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
61
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49930
diff changeset
62 fn break_lock(hg_vfs: &VfsImpl, lock_filename: &str) -> Result<(), LockError> {
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
63 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
64 // Check again in case some other process broke and
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
65 // acquired the lock in the meantime
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
66 let lock_data = read_lock(hg_vfs, lock_filename)?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
67 if !lock_should_be_broken(&lock_data) {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
68 return Err(LockError::AlreadyHeld);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
69 }
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51864
diff changeset
70 Ok(hg_vfs.unlink(Path::new(lock_filename))?)
48417
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 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
73
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
74 #[cfg(unix)]
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
75 fn make_lock(
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49930
diff changeset
76 hg_vfs: &VfsImpl,
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
77 lock_filename: &str,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
78 data: &str,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
79 ) -> Result<(), HgError> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
80 // Use a symbolic link because creating it is atomic.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
81 // The link’s "target" contains data not representing any path.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
82 let fake_symlink_target = data;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
83 hg_vfs.create_symlink(lock_filename, fake_symlink_target)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
84 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
85
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
86 fn read_lock(
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49930
diff changeset
87 hg_vfs: &VfsImpl,
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
88 lock_filename: &str,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
89 ) -> Result<Option<String>, HgError> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
90 let link_target =
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
91 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
92 if let Some(target) = link_target {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
93 let data = target
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
94 .into_os_string()
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
95 .into_string()
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
96 .map_err(|_| HgError::corrupted("non-UTF-8 lock data"))?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
97 Ok(Some(data))
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
98 } else {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
99 Ok(None)
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 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
102
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49930
diff changeset
103 fn unlock(hg_vfs: &VfsImpl, lock_filename: &str) -> Result<(), HgError> {
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51864
diff changeset
104 hg_vfs.unlink(Path::new(lock_filename))
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
105 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
106
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
107 /// 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
108 /// running anymore.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
109 fn lock_should_be_broken(data: &Option<String>) -> bool {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
110 (|| -> 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
111 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
112 if prefix != *LOCK_PREFIX {
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
113 return Some(false);
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 let process_is_running;
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 #[cfg(unix)]
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
118 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
119 let pid: libc::pid_t = pid.parse().ok()?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
120 unsafe {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
121 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
122 let result = libc::kill(pid, signal);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
123 if result == 0 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
124 process_is_running = true
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
125 } else {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
126 let errno =
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
127 io::Error::last_os_error().raw_os_error().unwrap();
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
128 process_is_running = errno != libc::ESRCH
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 }
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 Some(!process_is_running)
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 .unwrap_or(false)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
136 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
137
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
138 lazy_static::lazy_static! {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
139 /// A string which is used to differentiate pid namespaces
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
140 ///
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
141 /// 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
142 /// 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
143 /// extra Linux-specific pid namespace identifier.
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
144 static ref LOCK_PREFIX: String = {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
145 // 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
146
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
147 /// 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
148 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
149 // 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
150 #[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
151 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
152 let hostname_bytes = unsafe {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
153 let result = libc::gethostname(buffer.as_mut_ptr(), BUFFER_SIZE);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
154 if result != 0 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
155 panic!("gethostname: {}", io::Error::last_os_error())
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 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
158 };
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
159 let hostname =
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
160 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
161
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
162 #[cfg(target_os = "linux")]
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
163 {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
164 use std::os::linux::fs::MetadataExt;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
165 match std::fs::metadata("/proc/self/ns/pid") {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
166 Ok(meta) => {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
167 return format!("{}/{:x}", hostname, meta.st_ino())
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
168 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
169 Err(error) => {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
170 // TODO: match on `error.kind()` when `NotADirectory`
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
171 // is available on all supported Rust versions:
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
172 // https://github.com/rust-lang/rust/issues/86442
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
173 use libc::{
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
174 ENOENT, // ErrorKind::NotFound
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
175 ENOTDIR, // ErrorKind::NotADirectory
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
176 EACCES, // ErrorKind::PermissionDenied
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
177 };
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
178 match error.raw_os_error() {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
179 Some(ENOENT) | Some(ENOTDIR) | Some(EACCES) => {}
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
180 _ => panic!("stat /proc/self/ns/pid: {}", error),
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 }
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 hostname.to_owned()
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
187 };
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
188
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
189 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
190 }