Mercurial > public > mercurial-scm > hg
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 |
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 | 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 | 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 | 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 | 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 | 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 | 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 } |