Mercurial > public > mercurial-scm > hg-stable
annotate rust/hg-core/src/vfs.rs @ 52769:1b7a57a5b47a
rust: add safe bindings to bdiff.c
I wrote C FFI bindings manually rather than using a bindgen build step because
there are only 2 structs and 3 functions and they're not going to change.
Note that the relative path in build.rs means that cargo publish will no longer
work. If in the future we want to publish to crates.io, we would probably need
to add a Makefile step that copies bdiff sources into the hg-core crate.
author | Mitchell Kember <mkember@janestreet.com> |
---|---|
date | Wed, 18 Dec 2024 10:35:01 -0500 |
parents | a48c688d3e80 |
children |
rev | line source |
---|---|
52310
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1 use crate::errors::{HgError, HgResultExt, IoErrorContext, IoResultExt}; |
51906 | 2 use crate::exit_codes; |
52298
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
3 use crate::fncache::FnCache; |
52308
bd8081e9fd62
rust: don't star export from the `revlog` module
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52298
diff
changeset
|
4 use crate::revlog::path_encode::path_encode; |
52298
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
5 use crate::utils::files::{get_bytes_from_path, get_path_from_bytes}; |
51906 | 6 use dyn_clone::DynClone; |
52310
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
7 use format_bytes::format_bytes; |
47983
e834b79def74
rust: Switch to the memmap2-rs crate
Simon Sapin <simon.sapin@octobus.net>
parents:
47980
diff
changeset
|
8 use memmap2::{Mmap, MmapOptions}; |
52298
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
9 use rand::distributions::{Alphanumeric, DistString}; |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
10 use std::fs::{File, Metadata, OpenOptions}; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
11 use std::io::{ErrorKind, Read, Seek, Write}; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
12 use std::os::fd::AsRawFd; |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
13 use std::os::unix::fs::{MetadataExt, PermissionsExt}; |
47980
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
14 use std::path::{Path, PathBuf}; |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
15 #[cfg(test)] |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
16 use std::sync::atomic::AtomicUsize; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
17 #[cfg(test)] |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
18 use std::sync::atomic::Ordering; |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
19 use std::sync::OnceLock; |
47980
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
20 |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
21 /// Filesystem access abstraction for the contents of a given "base" diretory |
51906 | 22 #[derive(Clone)] |
23 pub struct VfsImpl { | |
24 pub(crate) base: PathBuf, | |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
25 pub readonly: bool, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
26 pub mode: Option<u32>, |
47980
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
27 } |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
28 |
48211
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
29 struct FileNotFound(std::io::Error, PathBuf); |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
30 |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
31 /// Store the umask for the whole process since it's expensive to get. |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
32 static UMASK: OnceLock<u32> = OnceLock::new(); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
33 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
34 fn get_umask() -> u32 { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
35 *UMASK.get_or_init(|| unsafe { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
36 // TODO is there any way of getting the umask without temporarily |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
37 // setting it? Doesn't this affect all threads in this tiny window? |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
38 let mask = libc::umask(0); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
39 libc::umask(mask); |
52346
33d8cb64e9da
rust: fix darwin build
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
52342
diff
changeset
|
40 #[allow(clippy::useless_conversion)] |
33d8cb64e9da
rust: fix darwin build
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
52342
diff
changeset
|
41 (mask & 0o777).into() |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
42 }) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
43 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
44 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
45 /// Return the (unix) mode with which we will create/fix files |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
46 fn get_mode(base: impl AsRef<Path>) -> Option<u32> { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
47 match base.as_ref().metadata() { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
48 Ok(meta) => { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
49 // files in .hg/ will be created using this mode |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
50 let mode = meta.mode(); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
51 // avoid some useless chmods |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
52 if (0o777 & !get_umask()) == (0o777 & mode) { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
53 None |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
54 } else { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
55 Some(mode) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
56 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
57 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
58 Err(_) => None, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
59 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
60 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
61 |
51906 | 62 impl VfsImpl { |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
63 pub fn new(base: PathBuf, readonly: bool) -> Self { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
64 let mode = get_mode(&base); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
65 Self { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
66 base, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
67 readonly, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
68 mode, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
69 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
70 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
71 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
72 // XXX these methods are probably redundant with VFS trait? |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
73 |
47980
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
74 pub fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf { |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
75 self.base.join(relative_path) |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
76 } |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
77 |
48394
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48211
diff
changeset
|
78 pub fn symlink_metadata( |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48211
diff
changeset
|
79 &self, |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48211
diff
changeset
|
80 relative_path: impl AsRef<Path>, |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48211
diff
changeset
|
81 ) -> Result<std::fs::Metadata, HgError> { |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48211
diff
changeset
|
82 let path = self.join(relative_path); |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48211
diff
changeset
|
83 std::fs::symlink_metadata(&path).when_reading_file(&path) |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48211
diff
changeset
|
84 } |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48211
diff
changeset
|
85 |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48211
diff
changeset
|
86 pub fn read_link( |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48211
diff
changeset
|
87 &self, |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48211
diff
changeset
|
88 relative_path: impl AsRef<Path>, |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48211
diff
changeset
|
89 ) -> Result<PathBuf, HgError> { |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48211
diff
changeset
|
90 let path = self.join(relative_path); |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48211
diff
changeset
|
91 std::fs::read_link(&path).when_reading_file(&path) |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48211
diff
changeset
|
92 } |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48211
diff
changeset
|
93 |
47980
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
94 pub fn read( |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
95 &self, |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
96 relative_path: impl AsRef<Path>, |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
97 ) -> Result<Vec<u8>, HgError> { |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
98 let path = self.join(relative_path); |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
99 std::fs::read(&path).when_reading_file(&path) |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
100 } |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
101 |
49499
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48464
diff
changeset
|
102 /// Returns `Ok(None)` if the file does not exist. |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48464
diff
changeset
|
103 pub fn try_read( |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48464
diff
changeset
|
104 &self, |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48464
diff
changeset
|
105 relative_path: impl AsRef<Path>, |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48464
diff
changeset
|
106 ) -> Result<Option<Vec<u8>>, HgError> { |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48464
diff
changeset
|
107 match self.read(relative_path) { |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48464
diff
changeset
|
108 Err(e) => match &e { |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48464
diff
changeset
|
109 HgError::IoError { error, .. } => match error.kind() { |
49987
58074252db3c
rust: run `cargo clippy`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
110 ErrorKind::NotFound => Ok(None), |
49499
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48464
diff
changeset
|
111 _ => Err(e), |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48464
diff
changeset
|
112 }, |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48464
diff
changeset
|
113 _ => Err(e), |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48464
diff
changeset
|
114 }, |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48464
diff
changeset
|
115 Ok(v) => Ok(Some(v)), |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48464
diff
changeset
|
116 } |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48464
diff
changeset
|
117 } |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48464
diff
changeset
|
118 |
48211
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
119 fn mmap_open_gen( |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
120 &self, |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
121 relative_path: impl AsRef<Path>, |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
122 ) -> Result<Result<Mmap, FileNotFound>, HgError> { |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
123 let path = self.join(relative_path); |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
124 let file = match std::fs::File::open(&path) { |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
125 Err(err) => { |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
126 if let ErrorKind::NotFound = err.kind() { |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
127 return Ok(Err(FileNotFound(err, path))); |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
128 }; |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
129 return (Err(err)).when_reading_file(&path); |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
130 } |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
131 Ok(file) => file, |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
132 }; |
51906 | 133 // Safety is "enforced" by locks and assuming other processes are |
134 // well-behaved. If any misbehaving or malicious process does touch | |
135 // the index, it could lead to corruption. This is inherent | |
136 // to file-based `mmap`, though some platforms have some ways of | |
137 // mitigating. | |
138 // TODO linux: set the immutable flag with `chattr(1)`? | |
48211
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
139 let mmap = unsafe { MmapOptions::new().map(&file) } |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
140 .when_reading_file(&path)?; |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
141 Ok(Ok(mmap)) |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
142 } |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
143 |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
144 pub fn mmap_open_opt( |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
145 &self, |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
146 relative_path: impl AsRef<Path>, |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
147 ) -> Result<Option<Mmap>, HgError> { |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
148 self.mmap_open_gen(relative_path).map(|res| res.ok()) |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
149 } |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
150 |
47980
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
151 pub fn mmap_open( |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
152 &self, |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
153 relative_path: impl AsRef<Path>, |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
154 ) -> Result<Mmap, HgError> { |
48211
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
155 match self.mmap_open_gen(relative_path)? { |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
156 Err(FileNotFound(err, path)) => Err(err).when_reading_file(&path), |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
157 Ok(res) => Ok(res), |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47983
diff
changeset
|
158 } |
47980
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
159 } |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
160 |
48463
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48394
diff
changeset
|
161 #[cfg(unix)] |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48394
diff
changeset
|
162 pub fn create_symlink( |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48394
diff
changeset
|
163 &self, |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48394
diff
changeset
|
164 relative_link_path: impl AsRef<Path>, |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48394
diff
changeset
|
165 target_path: impl AsRef<Path>, |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48394
diff
changeset
|
166 ) -> Result<(), HgError> { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48394
diff
changeset
|
167 let link_path = self.join(relative_link_path); |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48394
diff
changeset
|
168 std::os::unix::fs::symlink(target_path, &link_path) |
48464
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
169 .when_writing_file(&link_path) |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
170 } |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
171 |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
172 /// Write `contents` into a temporary file, then rename to `relative_path`. |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
173 /// This makes writing to a file "atomic": a reader opening that path will |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
174 /// see either the previous contents of the file or the complete new |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
175 /// content, never a partial write. |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
176 pub fn atomic_write( |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
177 &self, |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
178 relative_path: impl AsRef<Path>, |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
179 contents: &[u8], |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
180 ) -> Result<(), HgError> { |
52377
a48c688d3e80
rhg: set the expected dirstate permissions (0o666 minus umask)
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
52346
diff
changeset
|
181 let mut tmp = tempfile::Builder::new() |
a48c688d3e80
rhg: set the expected dirstate permissions (0o666 minus umask)
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
52346
diff
changeset
|
182 .permissions(std::fs::Permissions::from_mode(0o666)) |
a48c688d3e80
rhg: set the expected dirstate permissions (0o666 minus umask)
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
52346
diff
changeset
|
183 .tempfile_in(&self.base) |
51906 | 184 .when_writing_file(&self.base)?; |
48464
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
185 tmp.write_all(contents) |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
186 .and_then(|()| tmp.flush()) |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
187 .when_writing_file(tmp.path())?; |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
188 let path = self.join(relative_path); |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
189 tmp.persist(&path) |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
190 .map_err(|e| e.error) |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
191 .when_writing_file(&path)?; |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48463
diff
changeset
|
192 Ok(()) |
48463
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48394
diff
changeset
|
193 } |
47980
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
194 } |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
195 |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
196 fn fs_metadata( |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
197 path: impl AsRef<Path>, |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
198 ) -> Result<Option<std::fs::Metadata>, HgError> { |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
199 let path = path.as_ref(); |
52310
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
200 match path.metadata() { |
47980
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
201 Ok(meta) => Ok(Some(meta)), |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
202 Err(error) => match error.kind() { |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
203 // TODO: when we require a Rust version where `NotADirectory` is |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
204 // stable, invert this logic and return None for it and `NotFound` |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
205 // and propagate any other error. |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
206 ErrorKind::PermissionDenied => Err(error).with_context(|| { |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
207 IoErrorContext::ReadingMetadata(path.to_owned()) |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
208 }), |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
209 _ => Ok(None), |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
210 }, |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
211 } |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
212 } |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
213 |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
214 /// Abstraction over the files handled by a [`Vfs`]. |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
215 #[derive(Debug)] |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
216 pub enum VfsFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
217 Atomic(AtomicFile), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
218 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
219 Normal { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
220 file: File, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
221 path: PathBuf, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
222 /// If `Some`, check (and maybe fix) this file's timestamp ambiguity. |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
223 /// See [`is_filetime_ambiguous`]. |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
224 check_ambig: Option<Metadata>, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
225 }, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
226 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
227 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
228 impl VfsFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
229 pub fn normal(file: File, path: PathBuf) -> Self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
230 Self::Normal { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
231 file, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
232 check_ambig: None, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
233 path, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
234 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
235 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
236 pub fn normal_check_ambig( |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
237 file: File, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
238 path: PathBuf, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
239 ) -> Result<Self, HgError> { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
240 Ok(Self::Normal { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
241 file, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
242 check_ambig: Some(path.metadata().when_reading_file(&path)?), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
243 path, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
244 }) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
245 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
246 pub fn try_clone(&self) -> Result<VfsFile, HgError> { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
247 Ok(match self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
248 VfsFile::Atomic(AtomicFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
249 fp, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
250 temp_path, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
251 check_ambig, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
252 target_name, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
253 is_open, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
254 }) => Self::Atomic(AtomicFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
255 fp: fp.try_clone().when_reading_file(temp_path)?, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
256 temp_path: temp_path.clone(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
257 check_ambig: *check_ambig, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
258 target_name: target_name.clone(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
259 is_open: *is_open, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
260 }), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
261 VfsFile::Normal { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
262 file, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
263 check_ambig, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
264 path, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
265 } => Self::Normal { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
266 file: file.try_clone().when_reading_file(path)?, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
267 check_ambig: check_ambig.clone(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
268 path: path.to_owned(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
269 }, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
270 }) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
271 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
272 pub fn set_len(&self, len: u64) -> Result<(), std::io::Error> { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
273 match self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
274 VfsFile::Atomic(atomic_file) => atomic_file.fp.set_len(len), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
275 VfsFile::Normal { file, .. } => file.set_len(len), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
276 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
277 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
278 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
279 pub fn metadata(&self) -> Result<std::fs::Metadata, std::io::Error> { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
280 match self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
281 VfsFile::Atomic(atomic_file) => atomic_file.fp.metadata(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
282 VfsFile::Normal { file, .. } => file.metadata(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
283 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
284 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
285 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
286 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
287 impl AsRawFd for VfsFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
288 fn as_raw_fd(&self) -> std::os::unix::prelude::RawFd { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
289 match self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
290 VfsFile::Atomic(atomic_file) => atomic_file.fp.as_raw_fd(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
291 VfsFile::Normal { file, .. } => file.as_raw_fd(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
292 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
293 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
294 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
295 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
296 impl Seek for VfsFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
297 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
298 match self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
299 VfsFile::Atomic(atomic_file) => atomic_file.seek(pos), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
300 VfsFile::Normal { file, .. } => file.seek(pos), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
301 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
302 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
303 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
304 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
305 impl Read for VfsFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
306 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
307 match self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
308 VfsFile::Atomic(atomic_file) => atomic_file.fp.read(buf), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
309 VfsFile::Normal { file, .. } => file.read(buf), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
310 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
311 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
312 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
313 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
314 impl Write for VfsFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
315 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
316 match self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
317 VfsFile::Atomic(atomic_file) => atomic_file.fp.write(buf), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
318 VfsFile::Normal { file, .. } => file.write(buf), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
319 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
320 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
321 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
322 fn flush(&mut self) -> std::io::Result<()> { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
323 match self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
324 VfsFile::Atomic(atomic_file) => atomic_file.fp.flush(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
325 VfsFile::Normal { file, .. } => file.flush(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
326 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
327 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
328 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
329 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
330 impl Drop for VfsFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
331 fn drop(&mut self) { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
332 if let VfsFile::Normal { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
333 path, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
334 check_ambig: Some(old), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
335 .. |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
336 } = self |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
337 { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
338 avoid_timestamp_ambiguity(path, old) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
339 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
340 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
341 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
342 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
343 /// Records the number of times we've fixed a timestamp ambiguity, only |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
344 /// applicable for tests. |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
345 #[cfg(test)] |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
346 static TIMESTAMP_FIXES_CALLS: AtomicUsize = AtomicUsize::new(0); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
347 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
348 fn avoid_timestamp_ambiguity(path: &Path, old: &Metadata) { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
349 if let Ok(new) = path.metadata() { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
350 let is_ambiguous = is_filetime_ambiguous(&new, old); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
351 if is_ambiguous { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
352 let advanced = |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
353 filetime::FileTime::from_unix_time(old.mtime() + 1, 0); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
354 if filetime::set_file_times(path, advanced, advanced).is_ok() { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
355 #[cfg(test)] |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
356 { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
357 TIMESTAMP_FIXES_CALLS.fetch_add(1, Ordering::Relaxed); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
358 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
359 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
360 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
361 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
362 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
363 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
364 /// Examine whether new stat is ambiguous against old one |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
365 /// |
52342
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52330
diff
changeset
|
366 /// `S[N]` below means stat of a file at `N`-th change: |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
367 /// |
52342
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52330
diff
changeset
|
368 /// - `S[n-1].ctime < S[n].ctime`: can detect change of a file |
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52330
diff
changeset
|
369 /// - `S[n-1].ctime == S[n].ctime` |
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52330
diff
changeset
|
370 /// - `S[n-1].ctime < S[n].mtime`: means natural advancing (*1) |
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52330
diff
changeset
|
371 /// - `S[n-1].ctime == S[n].mtime`: is ambiguous (*2) |
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52330
diff
changeset
|
372 /// - `S[n-1].ctime > S[n].mtime`: never occurs naturally (don't care) |
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52330
diff
changeset
|
373 /// - `S[n-1].ctime > S[n].ctime`: never occurs naturally (don't care) |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
374 /// |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
375 /// Case (*2) above means that a file was changed twice or more at |
52342
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52330
diff
changeset
|
376 /// same time in sec (= `S[n-1].ctime`), and comparison of timestamp |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
377 /// is ambiguous. |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
378 /// |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
379 /// Base idea to avoid such ambiguity is "advance mtime 1 sec, if |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
380 /// timestamp is ambiguous". |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
381 /// |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
382 /// But advancing mtime only in case (*2) doesn't work as |
52342
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52330
diff
changeset
|
383 /// expected, because naturally advanced `S[n].mtime` in case (*1) |
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52330
diff
changeset
|
384 /// might be equal to manually advanced `S[n-1 or earlier].mtime`. |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
385 /// |
52342
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52330
diff
changeset
|
386 /// Therefore, all `S[n-1].ctime == S[n].ctime` cases should be |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
387 /// treated as ambiguous regardless of mtime, to avoid overlooking |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
388 /// by confliction between such mtime. |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
389 /// |
52342
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52330
diff
changeset
|
390 /// Advancing mtime `if isambig(new, old)` ensures `S[n-1].mtime != |
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52330
diff
changeset
|
391 /// S[n].mtime`, even if size of a file isn't changed. |
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52330
diff
changeset
|
392 pub fn is_filetime_ambiguous(new: &Metadata, old: &Metadata) -> bool { |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
393 new.ctime() == old.ctime() |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
394 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
395 |
51906 | 396 /// Writable file object that atomically updates a file |
397 /// | |
398 /// All writes will go to a temporary copy of the original file. Call | |
399 /// [`Self::close`] when you are done writing, and [`Self`] will rename | |
400 /// the temporary copy to the original name, making the changes | |
401 /// visible. If the object is destroyed without being closed, all your | |
402 /// writes are discarded. | |
52310
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
403 #[derive(Debug)] |
51906 | 404 pub struct AtomicFile { |
405 /// The temporary file to write to | |
406 fp: std::fs::File, | |
407 /// Path of the temp file | |
408 temp_path: PathBuf, | |
409 /// Used when stat'ing the file, is useful only if the target file is | |
410 /// guarded by any lock (e.g. repo.lock or repo.wlock). | |
411 check_ambig: bool, | |
412 /// Path of the target file | |
413 target_name: PathBuf, | |
414 /// Whether the file is open or not | |
415 is_open: bool, | |
416 } | |
417 | |
418 impl AtomicFile { | |
419 pub fn new( | |
52310
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
420 target_path: impl AsRef<Path>, |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
421 empty: bool, |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
422 check_ambig: bool, |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
423 ) -> Result<Self, HgError> { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
424 let target_path = target_path.as_ref().to_owned(); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
425 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
426 let random_id = |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
427 Alphanumeric.sample_string(&mut rand::thread_rng(), 12); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
428 let filename = |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
429 target_path.file_name().expect("target has no filename"); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
430 let filename = get_bytes_from_path(filename); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
431 let temp_filename = |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
432 format_bytes!(b".{}-{}~", filename, random_id.as_bytes()); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
433 let temp_path = |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
434 target_path.with_file_name(get_path_from_bytes(&temp_filename)); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
435 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
436 if !empty { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
437 std::fs::copy(&target_path, &temp_path) |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
438 .with_context(|| IoErrorContext::CopyingFile { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
439 from: target_path.to_owned(), |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
440 to: temp_path.to_owned(), |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
441 }) |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
442 // If it doesn't exist, create it on open |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
443 .io_not_found_as_none()?; |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
444 } |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
445 let fp = std::fs::OpenOptions::new() |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
446 .write(true) |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
447 .create(true) |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
448 .truncate(empty) |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
449 .open(&temp_path) |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
450 .when_writing_file(&temp_path)?; |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
451 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
452 Ok(Self { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
453 fp, |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
454 temp_path, |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
455 check_ambig, |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
456 target_name: target_path, |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
457 is_open: true, |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
458 }) |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
459 } |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
460 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
461 pub fn from_file( |
51906 | 462 fp: std::fs::File, |
463 check_ambig: bool, | |
464 temp_name: PathBuf, | |
465 target_name: PathBuf, | |
466 ) -> Self { | |
467 Self { | |
468 fp, | |
469 check_ambig, | |
470 temp_path: temp_name, | |
471 target_name, | |
472 is_open: true, | |
473 } | |
474 } | |
475 | |
476 /// Write `buf` to the temporary file | |
477 pub fn write_all(&mut self, buf: &[u8]) -> Result<(), std::io::Error> { | |
478 self.fp.write_all(buf) | |
479 } | |
480 | |
481 fn target(&self) -> PathBuf { | |
482 self.temp_path | |
483 .parent() | |
484 .expect("should not be at the filesystem root") | |
485 .join(&self.target_name) | |
486 } | |
487 | |
488 /// Close the temporary file and rename to the target | |
489 pub fn close(mut self) -> Result<(), std::io::Error> { | |
490 self.fp.flush()?; | |
491 let target = self.target(); | |
492 if self.check_ambig { | |
52310
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
493 if let Ok(stat) = target.metadata() { |
51906 | 494 std::fs::rename(&self.temp_path, &target)?; |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
495 avoid_timestamp_ambiguity(&target, &stat); |
51906 | 496 } else { |
497 std::fs::rename(&self.temp_path, target)?; | |
498 } | |
499 } else { | |
52310
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
500 std::fs::rename(&self.temp_path, target)?; |
51906 | 501 } |
502 self.is_open = false; | |
503 Ok(()) | |
504 } | |
505 } | |
506 | |
52310
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
507 impl Seek for AtomicFile { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
508 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
509 self.fp.seek(pos) |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
510 } |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
511 } |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
512 |
51906 | 513 impl Drop for AtomicFile { |
514 fn drop(&mut self) { | |
515 if self.is_open { | |
52309
82007b8c189e
rust-vfs: delete the temp file and not the target on drop
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52308
diff
changeset
|
516 std::fs::remove_file(&self.temp_path).ok(); |
51906 | 517 } |
518 } | |
519 } | |
520 | |
521 /// Abstracts over the VFS to allow for different implementations of the | |
522 /// filesystem layer (like passing one from Python). | |
523 pub trait Vfs: Sync + Send + DynClone { | |
52330
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
524 /// Open a [`VfsFile::Normal`] for reading the file at `filename`, |
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
525 /// relative to this VFS's root. |
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
526 fn open(&self, filename: &Path) -> Result<VfsFile, HgError>; |
52312
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
527 /// Open a [`VfsFile::Normal`] for writing and reading the file at |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
528 /// `filename`, relative to this VFS's root. |
52330
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
529 fn open_write(&self, filename: &Path) -> Result<VfsFile, HgError>; |
52312
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
530 /// Open a [`VfsFile::Normal`] for reading and writing the file at |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
531 /// `filename`, relative to this VFS's root. This file will be checked |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
532 /// for an ambiguous mtime on [`drop`]. See [`is_filetime_ambiguous`]. |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
533 fn open_check_ambig(&self, filename: &Path) -> Result<VfsFile, HgError>; |
52312
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
534 /// Create a [`VfsFile::Normal`] for reading and writing the file at |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
535 /// `filename`, relative to this VFS's root. If the file already exists, |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
536 /// it will be truncated to 0 bytes. |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
537 fn create( |
51906 | 538 &self, |
539 filename: &Path, | |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
540 check_ambig: bool, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
541 ) -> Result<VfsFile, HgError>; |
52312
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
542 /// Create a [`VfsFile::Atomic`] for reading and writing the file at |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
543 /// `filename`, relative to this VFS's root. If the file already exists, |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
544 /// it will be truncated to 0 bytes. |
51906 | 545 fn create_atomic( |
546 &self, | |
547 filename: &Path, | |
548 check_ambig: bool, | |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
549 ) -> Result<VfsFile, HgError>; |
52312
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
550 /// Return the total file size in bytes of the open `file`. Errors are |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
551 /// usual IO errors (invalid file handle, permissions, etc.) |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
552 fn file_size(&self, file: &VfsFile) -> Result<u64, HgError>; |
52312
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
553 /// Return `true` if `filename` exists relative to this VFS's root. Errors |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
554 /// will coerce to `false`, to this also returns `false` if there are |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
555 /// IO problems. This is fine because any operation that actually tries |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
556 /// to do anything with this path will get the same error. |
51906 | 557 fn exists(&self, filename: &Path) -> bool; |
52312
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
558 /// Remove the file at `filename` relative to this VFS's root. Errors |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
559 /// are the usual IO errors (lacking permission, file does not exist, etc.) |
51906 | 560 fn unlink(&self, filename: &Path) -> Result<(), HgError>; |
52312
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
561 /// Rename the file `from` to `to`, both relative to this VFS's root. |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
562 /// Errors are the usual IO errors (lacking permission, file does not |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
563 /// exist, etc.). If `check_ambig` is `true`, the VFS will check for an |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
564 /// ambiguous mtime on rename. See [`is_filetime_ambiguous`]. |
51906 | 565 fn rename( |
566 &self, | |
567 from: &Path, | |
568 to: &Path, | |
569 check_ambig: bool, | |
570 ) -> Result<(), HgError>; | |
52312
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
571 /// Rename the file `from` to `to`, both relative to this VFS's root. |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
572 /// Errors are the usual IO errors (lacking permission, file does not |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
573 /// exist, etc.). If `check_ambig` is passed, the VFS will check for an |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
574 /// ambiguous mtime on rename. See [`is_filetime_ambiguous`]. |
51906 | 575 fn copy(&self, from: &Path, to: &Path) -> Result<(), HgError>; |
52312
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
576 /// Returns the absolute root path of this VFS, relative to which all |
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52311
diff
changeset
|
577 /// operations are done. |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
578 fn base(&self) -> &Path; |
51906 | 579 } |
580 | |
581 /// These methods will need to be implemented once `rhg` (and other) non-Python | |
582 /// users of `hg-core` start doing more on their own, like writing to files. | |
583 impl Vfs for VfsImpl { | |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
584 fn open(&self, filename: &Path) -> Result<VfsFile, HgError> { |
52330
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
585 // TODO auditpath |
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
586 let path = self.base.join(filename); |
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
587 Ok(VfsFile::normal( |
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
588 std::fs::File::open(&path).when_reading_file(&path)?, |
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
589 filename.to_owned(), |
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
590 )) |
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
591 } |
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
592 |
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
593 fn open_write(&self, filename: &Path) -> Result<VfsFile, HgError> { |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
594 if self.readonly { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
595 return Err(HgError::abort( |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
596 "write access in a readonly vfs", |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
597 exit_codes::ABORT, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
598 None, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
599 )); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
600 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
601 // TODO auditpath |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
602 let path = self.base.join(filename); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
603 copy_in_place_if_hardlink(&path)?; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
604 |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
605 Ok(VfsFile::normal( |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
606 OpenOptions::new() |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
607 .create(false) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
608 .create_new(false) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
609 .write(true) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
610 .read(true) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
611 .open(&path) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
612 .when_writing_file(&path)?, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
613 path.to_owned(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
614 )) |
51906 | 615 } |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
616 |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
617 fn open_check_ambig(&self, filename: &Path) -> Result<VfsFile, HgError> { |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
618 if self.readonly { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
619 return Err(HgError::abort( |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
620 "write access in a readonly vfs", |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
621 exit_codes::ABORT, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
622 None, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
623 )); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
624 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
625 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
626 let path = self.base.join(filename); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
627 copy_in_place_if_hardlink(&path)?; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
628 |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
629 // TODO auditpath |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
630 VfsFile::normal_check_ambig( |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
631 OpenOptions::new() |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
632 .write(true) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
633 .read(true) // Can be used for reading to save on `open` calls |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
634 .create(false) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
635 .open(&path) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
636 .when_reading_file(&path)?, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
637 path.to_owned(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
638 ) |
51906 | 639 } |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
640 |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
641 fn create( |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
642 &self, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
643 filename: &Path, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
644 check_ambig: bool, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
645 ) -> Result<VfsFile, HgError> { |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
646 if self.readonly { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
647 return Err(HgError::abort( |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
648 "write access in a readonly vfs", |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
649 exit_codes::ABORT, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
650 None, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
651 )); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
652 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
653 // TODO auditpath |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
654 let path = self.base.join(filename); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
655 let parent = path.parent().expect("file at root"); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
656 std::fs::create_dir_all(parent).when_writing_file(parent)?; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
657 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
658 let file = OpenOptions::new() |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
659 .create(true) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
660 .truncate(true) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
661 .write(true) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
662 .read(true) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
663 .open(&path) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
664 .when_writing_file(&path)?; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
665 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
666 if let Some(mode) = self.mode { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
667 // Creating the file with the right permission (with `.mode()`) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
668 // may not work since umask takes effect for file creation. |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
669 // So we need to fix the permission after creating the file. |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
670 fix_directory_permissions(&self.base, &path, mode)?; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
671 let perm = std::fs::Permissions::from_mode(mode & 0o666); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
672 std::fs::set_permissions(&path, perm).when_writing_file(&path)?; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
673 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
674 |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
675 Ok(VfsFile::Normal { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
676 file, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
677 check_ambig: if check_ambig { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
678 Some(path.metadata().when_reading_file(&path)?) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
679 } else { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
680 None |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
681 }, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
682 path: path.to_owned(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
683 }) |
51906 | 684 } |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
685 |
51906 | 686 fn create_atomic( |
687 &self, | |
688 _filename: &Path, | |
689 _check_ambig: bool, | |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
690 ) -> Result<VfsFile, HgError> { |
51906 | 691 todo!() |
692 } | |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
693 |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
694 fn file_size(&self, file: &VfsFile) -> Result<u64, HgError> { |
51906 | 695 Ok(file |
696 .metadata() | |
697 .map_err(|e| { | |
698 HgError::abort( | |
699 format!("Could not get file metadata: {}", e), | |
700 exit_codes::ABORT, | |
701 None, | |
702 ) | |
703 })? | |
704 .size()) | |
705 } | |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
706 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
707 fn exists(&self, filename: &Path) -> bool { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
708 self.base.join(filename).exists() |
51906 | 709 } |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
710 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
711 fn unlink(&self, filename: &Path) -> Result<(), HgError> { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
712 if self.readonly { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
713 return Err(HgError::abort( |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
714 "write access in a readonly vfs", |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
715 exit_codes::ABORT, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
716 None, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
717 )); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
718 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
719 let path = self.base.join(filename); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
720 std::fs::remove_file(&path) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
721 .with_context(|| IoErrorContext::RemovingFile(path)) |
51906 | 722 } |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
723 |
51906 | 724 fn rename( |
725 &self, | |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
726 from: &Path, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
727 to: &Path, |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
728 check_ambig: bool, |
51906 | 729 ) -> Result<(), HgError> { |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
730 if self.readonly { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
731 return Err(HgError::abort( |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
732 "write access in a readonly vfs", |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
733 exit_codes::ABORT, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
734 None, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
735 )); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
736 } |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
737 let old_stat = if check_ambig { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
738 Some( |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
739 from.metadata() |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
740 .when_reading_file(from) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
741 .io_not_found_as_none()?, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
742 ) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
743 } else { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
744 None |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
745 }; |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
746 let from = self.base.join(from); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
747 let to = self.base.join(to); |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
748 std::fs::rename(&from, &to).with_context(|| { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
749 IoErrorContext::RenamingFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
750 from, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
751 to: to.to_owned(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
752 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
753 })?; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
754 if let Some(Some(old)) = old_stat { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
755 avoid_timestamp_ambiguity(&to, &old); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
756 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
757 Ok(()) |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
758 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
759 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
760 fn copy(&self, from: &Path, to: &Path) -> Result<(), HgError> { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
761 let from = self.base.join(from); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
762 let to = self.base.join(to); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
763 std::fs::copy(&from, &to) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
764 .with_context(|| IoErrorContext::CopyingFile { from, to }) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
765 .map(|_| ()) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
766 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
767 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
768 fn base(&self) -> &Path { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
769 &self.base |
51906 | 770 } |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
771 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
772 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
773 fn fix_directory_permissions( |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
774 base: &Path, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
775 path: &Path, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
776 mode: u32, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
777 ) -> Result<(), HgError> { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
778 let mut ancestors = path.ancestors(); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
779 ancestors.next(); // yields the path itself |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
780 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
781 for ancestor in ancestors { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
782 if ancestor == base { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
783 break; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
784 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
785 let perm = std::fs::Permissions::from_mode(mode); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
786 std::fs::set_permissions(ancestor, perm) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
787 .when_writing_file(ancestor)?; |
51906 | 788 } |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
789 Ok(()) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
790 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
791 |
52298
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
792 /// A VFS that understands the `fncache` store layout (file encoding), and |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
793 /// adds new entries to the `fncache`. |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
794 /// TODO Only works when using from Python for now. |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
795 pub struct FnCacheVfs { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
796 inner: VfsImpl, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
797 fncache: Box<dyn FnCache>, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
798 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
799 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
800 impl Clone for FnCacheVfs { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
801 fn clone(&self) -> Self { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
802 Self { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
803 inner: self.inner.clone(), |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
804 fncache: dyn_clone::clone_box(&*self.fncache), |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
805 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
806 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
807 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
808 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
809 impl FnCacheVfs { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
810 pub fn new( |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
811 base: PathBuf, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
812 readonly: bool, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
813 fncache: Box<dyn FnCache>, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
814 ) -> Self { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
815 let inner = VfsImpl::new(base, readonly); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
816 Self { inner, fncache } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
817 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
818 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
819 fn maybe_add_to_fncache( |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
820 &self, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
821 filename: &Path, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
822 encoded_path: &Path, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
823 ) -> Result<(), HgError> { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
824 let relevant_file = (filename.starts_with("data/") |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
825 || filename.starts_with("meta/")) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
826 && is_revlog_file(filename); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
827 if relevant_file { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
828 let not_load = !self.fncache.is_loaded() |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
829 && (self.exists(filename) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
830 && self |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
831 .inner |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
832 .join(encoded_path) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
833 .metadata() |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
834 .when_reading_file(encoded_path)? |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
835 .size() |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
836 != 0); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
837 if !not_load { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
838 self.fncache.add(filename); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
839 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
840 }; |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
841 Ok(()) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
842 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
843 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
844 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
845 impl Vfs for FnCacheVfs { |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
846 fn open(&self, filename: &Path) -> Result<VfsFile, HgError> { |
52298
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
847 let encoded = path_encode(&get_bytes_from_path(filename)); |
52330
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
848 let filename = get_path_from_bytes(&encoded); |
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
849 self.inner.open(filename) |
52298
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
850 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
851 |
52330
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
852 fn open_write(&self, filename: &Path) -> Result<VfsFile, HgError> { |
52298
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
853 let encoded = path_encode(&get_bytes_from_path(filename)); |
52330
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
854 let encoded_path = get_path_from_bytes(&encoded); |
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
855 self.maybe_add_to_fncache(filename, encoded_path)?; |
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52312
diff
changeset
|
856 self.inner.open_write(encoded_path) |
52298
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
857 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
858 |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
859 fn open_check_ambig(&self, filename: &Path) -> Result<VfsFile, HgError> { |
52298
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
860 let encoded = path_encode(&get_bytes_from_path(filename)); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
861 let filename = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
862 self.inner.open_check_ambig(filename) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
863 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
864 |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
865 fn create( |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
866 &self, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
867 filename: &Path, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
868 check_ambig: bool, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
869 ) -> Result<VfsFile, HgError> { |
52298
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
870 let encoded = path_encode(&get_bytes_from_path(filename)); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
871 let encoded_path = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
872 self.maybe_add_to_fncache(filename, encoded_path)?; |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
873 self.inner.create(encoded_path, check_ambig) |
52298
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
874 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
875 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
876 fn create_atomic( |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
877 &self, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
878 filename: &Path, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
879 check_ambig: bool, |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
880 ) -> Result<VfsFile, HgError> { |
52298
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
881 let encoded = path_encode(&get_bytes_from_path(filename)); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
882 let filename = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
883 self.inner.create_atomic(filename, check_ambig) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
884 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
885 |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
886 fn file_size(&self, file: &VfsFile) -> Result<u64, HgError> { |
52298
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
887 self.inner.file_size(file) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
888 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
889 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
890 fn exists(&self, filename: &Path) -> bool { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
891 let encoded = path_encode(&get_bytes_from_path(filename)); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
892 let filename = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
893 self.inner.exists(filename) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
894 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
895 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
896 fn unlink(&self, filename: &Path) -> Result<(), HgError> { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
897 let encoded = path_encode(&get_bytes_from_path(filename)); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
898 let filename = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
899 self.inner.unlink(filename) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
900 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
901 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
902 fn rename( |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
903 &self, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
904 from: &Path, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
905 to: &Path, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
906 check_ambig: bool, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
907 ) -> Result<(), HgError> { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
908 let encoded = path_encode(&get_bytes_from_path(from)); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
909 let from = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
910 let encoded = path_encode(&get_bytes_from_path(to)); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
911 let to = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
912 self.inner.rename(from, to, check_ambig) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
913 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
914 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
915 fn copy(&self, from: &Path, to: &Path) -> Result<(), HgError> { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
916 let encoded = path_encode(&get_bytes_from_path(from)); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
917 let from = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
918 let encoded = path_encode(&get_bytes_from_path(to)); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
919 let to = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
920 self.inner.copy(from, to) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
921 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
922 fn base(&self) -> &Path { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
923 self.inner.base() |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
924 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
925 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52297
diff
changeset
|
926 |
52297
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
927 /// Detects whether `path` is a hardlink and does a tmp copy + rename erase |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
928 /// to turn it into its own file. Revlogs are usually hardlinked when doing |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
929 /// a local clone, and we don't want to modify the original repo. |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
930 fn copy_in_place_if_hardlink(path: &Path) -> Result<(), HgError> { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
931 let metadata = path.metadata().when_writing_file(path)?; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
932 if metadata.nlink() > 0 { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
933 // If it's hardlinked, copy it and rename it back before changing it. |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
934 let tmpdir = path.parent().expect("file at root"); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
935 let name = Alphanumeric.sample_string(&mut rand::thread_rng(), 16); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
936 let tmpfile = tmpdir.join(name); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
937 std::fs::create_dir_all(tmpfile.parent().expect("file at root")) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
938 .with_context(|| IoErrorContext::CopyingFile { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
939 from: path.to_owned(), |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
940 to: tmpfile.to_owned(), |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
941 })?; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
942 std::fs::copy(path, &tmpfile).with_context(|| { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
943 IoErrorContext::CopyingFile { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
944 from: path.to_owned(), |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
945 to: tmpfile.to_owned(), |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
946 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
947 })?; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
948 std::fs::rename(&tmpfile, path).with_context(|| { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
949 IoErrorContext::RenamingFile { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
950 from: tmpfile, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
951 to: path.to_owned(), |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
952 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
953 })?; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
954 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
955 Ok(()) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
956 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
957 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
958 pub fn is_revlog_file(path: impl AsRef<Path>) -> bool { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
959 path.as_ref() |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
960 .extension() |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
961 .map(|ext| { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
962 ["i", "idx", "d", "dat", "n", "nd", "sda"] |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
963 .contains(&ext.to_string_lossy().as_ref()) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
964 }) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52287
diff
changeset
|
965 .unwrap_or(false) |
51906 | 966 } |
967 | |
47980
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
968 pub(crate) fn is_dir(path: impl AsRef<Path>) -> Result<bool, HgError> { |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
969 Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_dir())) |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
970 } |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
971 |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
972 pub(crate) fn is_file(path: impl AsRef<Path>) -> Result<bool, HgError> { |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
973 Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_file())) |
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
974 } |
49669
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
975 |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
976 /// Returns whether the given `path` is on a network file system. |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
977 /// Taken from `cargo`'s codebase. |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
978 #[cfg(target_os = "linux")] |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
979 pub(crate) fn is_on_nfs_mount(path: impl AsRef<Path>) -> bool { |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
980 use std::ffi::CString; |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
981 use std::mem; |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
982 use std::os::unix::prelude::*; |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
983 |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
984 let path = match CString::new(path.as_ref().as_os_str().as_bytes()) { |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
985 Ok(path) => path, |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
986 Err(_) => return false, |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
987 }; |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
988 |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
989 unsafe { |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
990 let mut buf: libc::statfs = mem::zeroed(); |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
991 let r = libc::statfs(path.as_ptr(), &mut buf); |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
992 |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
993 r == 0 && buf.f_type as u32 == libc::NFS_SUPER_MAGIC as u32 |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
994 } |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49499
diff
changeset
|
995 } |
50274
0cc19a53cef4
rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
50252
diff
changeset
|
996 |
0cc19a53cef4
rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
50252
diff
changeset
|
997 /// Similar to what Cargo does; although detecting NFS (or non-local |
0cc19a53cef4
rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
50252
diff
changeset
|
998 /// file systems) _should_ be possible on other operating systems, |
0cc19a53cef4
rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
50252
diff
changeset
|
999 /// we'll just assume that mmap() works there, for now; after all, |
0cc19a53cef4
rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
50252
diff
changeset
|
1000 /// _some_ functionality is better than a compile error, i.e. none at |
0cc19a53cef4
rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
50252
diff
changeset
|
1001 /// all |
0cc19a53cef4
rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
50252
diff
changeset
|
1002 #[cfg(not(target_os = "linux"))] |
0cc19a53cef4
rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
50252
diff
changeset
|
1003 pub(crate) fn is_on_nfs_mount(_path: impl AsRef<Path>) -> bool { |
0cc19a53cef4
rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
50252
diff
changeset
|
1004 false |
0cc19a53cef4
rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
50252
diff
changeset
|
1005 } |
52310
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1006 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1007 #[cfg(test)] |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1008 mod tests { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1009 use super::*; |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1010 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1011 #[test] |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1012 fn test_atomic_file() { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1013 let dir = tempfile::tempdir().unwrap().into_path(); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1014 let target_path = dir.join("sometargetname"); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1015 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1016 for empty in [true, false] { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1017 let file = AtomicFile::new(&target_path, empty, false).unwrap(); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1018 assert!(file.is_open); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1019 let filename = |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1020 file.temp_path.file_name().unwrap().to_str().unwrap(); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1021 // Make sure we have a coherent temp name |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1022 assert_eq!(filename.len(), 29, "{}", filename); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1023 assert!(filename.contains("sometargetname")); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1024 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1025 // Make sure the temp file is created in the same folder |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1026 assert_eq!(target_path.parent(), file.temp_path.parent()); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1027 } |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1028 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1029 assert!(!target_path.exists()); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1030 std::fs::write(&target_path, "version 1").unwrap(); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1031 let mut file = AtomicFile::new(&target_path, false, false).unwrap(); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1032 file.write_all(b"version 2!").unwrap(); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1033 assert_eq!( |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1034 std::fs::read(&target_path).unwrap(), |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1035 b"version 1".to_vec() |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1036 ); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1037 let temp_path = file.temp_path.to_owned(); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1038 // test that dropping the file should discard the temp file and not |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1039 // affect the target path. |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1040 drop(file); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1041 assert_eq!( |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1042 std::fs::read(&target_path).unwrap(), |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1043 b"version 1".to_vec() |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1044 ); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1045 assert!(!temp_path.exists()); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1046 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1047 let mut file = AtomicFile::new(&target_path, false, false).unwrap(); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1048 file.write_all(b"version 2!").unwrap(); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1049 assert_eq!( |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1050 std::fs::read(&target_path).unwrap(), |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1051 b"version 1".to_vec() |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1052 ); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1053 file.close().unwrap(); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1054 assert_eq!( |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1055 std::fs::read(&target_path).unwrap(), |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1056 b"version 2!".to_vec(), |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1057 "{}", |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1058 std::fs::read_to_string(&target_path).unwrap() |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1059 ); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1060 assert!(target_path.exists()); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1061 assert!(!temp_path.exists()); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1062 } |
52311
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1063 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1064 #[test] |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1065 fn test_vfs_file_check_ambig() { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1066 let dir = tempfile::tempdir().unwrap().into_path(); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1067 let file_path = dir.join("file"); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1068 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1069 fn vfs_file_write(file_path: &Path, check_ambig: bool) { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1070 let file = std::fs::OpenOptions::new() |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1071 .write(true) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1072 .open(file_path) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1073 .unwrap(); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1074 let old_stat = if check_ambig { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1075 Some(file.metadata().unwrap()) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1076 } else { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1077 None |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1078 }; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1079 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1080 let mut vfs_file = VfsFile::Normal { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1081 file, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1082 path: file_path.to_owned(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1083 check_ambig: old_stat, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1084 }; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1085 vfs_file.write_all(b"contents").unwrap(); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1086 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1087 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1088 std::fs::OpenOptions::new() |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1089 .write(true) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1090 .create(true) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1091 .truncate(false) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1092 .open(&file_path) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1093 .unwrap(); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1094 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1095 let number_of_writes = 3; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1096 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1097 // Try multiple times, because reproduction of an ambiguity depends |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1098 // on "filesystem time" |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1099 for _ in 0..5 { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1100 TIMESTAMP_FIXES_CALLS.store(0, Ordering::Relaxed); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1101 vfs_file_write(&file_path, false); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1102 let old_stat = file_path.metadata().unwrap(); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1103 if old_stat.ctime() != old_stat.mtime() { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1104 // subsequent changing never causes ambiguity |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1105 continue; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1106 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1107 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1108 // Repeat atomic write with `check_ambig == true`, to examine |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1109 // whether the mtime is advanced multiple times as expected |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1110 for _ in 0..number_of_writes { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1111 vfs_file_write(&file_path, true); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1112 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1113 let new_stat = file_path.metadata().unwrap(); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1114 if !is_filetime_ambiguous(&new_stat, &old_stat) { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1115 // timestamp ambiguity was naturally avoided while repetition |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1116 continue; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1117 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1118 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1119 assert_eq!( |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1120 TIMESTAMP_FIXES_CALLS.load(Ordering::Relaxed), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1121 number_of_writes |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1122 ); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1123 assert_eq!( |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1124 old_stat.mtime() + number_of_writes as i64, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1125 file_path.metadata().unwrap().mtime() |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1126 ); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1127 break; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1128 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1129 // If we've arrived here without breaking, we might not have |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1130 // tested anything because the platform is too slow. This test will |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1131 // still work on fast platforms. |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52310
diff
changeset
|
1132 } |
52310
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52309
diff
changeset
|
1133 } |