Mercurial > public > mercurial-scm > hg
annotate rust/hg-core/src/vfs.rs @ 53042:cdd7bf612c7b stable tip
bundle-spec: properly format boolean parameter (issue6960)
This was breaking automatic clone bundle generation. This changeset fixes it and
add a test to catch it in the future.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Tue, 11 Mar 2025 02:29:42 +0100 |
parents | a48c688d3e80 |
children |
rev | line source |
---|---|
52180
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1 use crate::errors::{HgError, HgResultExt, IoErrorContext, IoResultExt}; |
51864 | 2 use crate::exit_codes; |
52168
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
3 use crate::fncache::FnCache; |
52178
bd8081e9fd62
rust: don't star export from the `revlog` module
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52168
diff
changeset
|
4 use crate::revlog::path_encode::path_encode; |
52168
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
5 use crate::utils::files::{get_bytes_from_path, get_path_from_bytes}; |
51864 | 6 use dyn_clone::DynClone; |
52180
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
7 use format_bytes::format_bytes; |
47955
e834b79def74
rust: Switch to the memmap2-rs crate
Simon Sapin <simon.sapin@octobus.net>
parents:
47952
diff
changeset
|
8 use memmap2::{Mmap, MmapOptions}; |
52168
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
9 use rand::distributions::{Alphanumeric, DistString}; |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
10 use std::fs::{File, Metadata, OpenOptions}; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
11 use std::io::{ErrorKind, Read, Seek, Write}; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
12 use std::os::fd::AsRawFd; |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
13 use std::os::unix::fs::{MetadataExt, PermissionsExt}; |
47952
9cd35c8c6044
rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
14 use std::path::{Path, PathBuf}; |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
15 #[cfg(test)] |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
16 use std::sync::atomic::AtomicUsize; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
17 #[cfg(test)] |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
18 use std::sync::atomic::Ordering; |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
19 use std::sync::OnceLock; |
47952
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 |
51864 | 22 #[derive(Clone)] |
23 pub struct VfsImpl { | |
24 pub(crate) base: PathBuf, | |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
25 pub readonly: bool, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
26 pub mode: Option<u32>, |
47952
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 |
48199
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
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:
47955
diff
changeset
|
30 |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
diff
changeset
|
32 static UMASK: OnceLock<u32> = OnceLock::new(); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
33 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
34 fn get_umask() -> u32 { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
35 *UMASK.get_or_init(|| unsafe { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
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:
52157
diff
changeset
|
38 let mask = libc::umask(0); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
39 libc::umask(mask); |
52310
33d8cb64e9da
rust: fix darwin build
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
52306
diff
changeset
|
40 #[allow(clippy::useless_conversion)] |
33d8cb64e9da
rust: fix darwin build
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
52306
diff
changeset
|
41 (mask & 0o777).into() |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
42 }) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
43 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
44 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
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:
52157
diff
changeset
|
47 match base.as_ref().metadata() { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
48 Ok(meta) => { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
diff
changeset
|
50 let mode = meta.mode(); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
51 // avoid some useless chmods |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
52 if (0o777 & !get_umask()) == (0o777 & mode) { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
53 None |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
54 } else { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
55 Some(mode) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
56 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
57 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
58 Err(_) => None, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
59 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
60 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
61 |
51864 | 62 impl VfsImpl { |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
diff
changeset
|
64 let mode = get_mode(&base); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
65 Self { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
66 base, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
67 readonly, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
68 mode, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
69 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
70 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
71 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
diff
changeset
|
73 |
47952
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 |
48345
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48199
diff
changeset
|
78 pub fn symlink_metadata( |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48199
diff
changeset
|
79 &self, |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48199
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:
48199
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:
48199
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:
48199
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:
48199
diff
changeset
|
84 } |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48199
diff
changeset
|
85 |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48199
diff
changeset
|
86 pub fn read_link( |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48199
diff
changeset
|
87 &self, |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48199
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:
48199
diff
changeset
|
89 ) -> Result<PathBuf, HgError> { |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48199
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:
48199
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:
48199
diff
changeset
|
92 } |
d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents:
48199
diff
changeset
|
93 |
47952
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 |
49485
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48418
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:
48418
diff
changeset
|
103 pub fn try_read( |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48418
diff
changeset
|
104 &self, |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48418
diff
changeset
|
105 relative_path: impl AsRef<Path>, |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48418
diff
changeset
|
106 ) -> Result<Option<Vec<u8>>, HgError> { |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48418
diff
changeset
|
107 match self.read(relative_path) { |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48418
diff
changeset
|
108 Err(e) => match &e { |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48418
diff
changeset
|
109 HgError::IoError { error, .. } => match error.kind() { |
49914
58074252db3c
rust: run `cargo clippy`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49485
diff
changeset
|
110 ErrorKind::NotFound => Ok(None), |
49485
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48418
diff
changeset
|
111 _ => Err(e), |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48418
diff
changeset
|
112 }, |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48418
diff
changeset
|
113 _ => Err(e), |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48418
diff
changeset
|
114 }, |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48418
diff
changeset
|
115 Ok(v) => Ok(Some(v)), |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48418
diff
changeset
|
116 } |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48418
diff
changeset
|
117 } |
ffd4b1f1c9cb
rhg: add sparse support
Rapha?l Gom?s <rgomes@octobus.net>
parents:
48418
diff
changeset
|
118 |
48199
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
diff
changeset
|
119 fn mmap_open_gen( |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
diff
changeset
|
120 &self, |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
diff
changeset
|
121 relative_path: impl AsRef<Path>, |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
diff
changeset
|
122 ) -> Result<Result<Mmap, FileNotFound>, HgError> { |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
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:
47955
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:
47955
diff
changeset
|
125 Err(err) => { |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
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:
47955
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:
47955
diff
changeset
|
128 }; |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
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:
47955
diff
changeset
|
130 } |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
diff
changeset
|
131 Ok(file) => file, |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
diff
changeset
|
132 }; |
51864 | 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)`? | |
48199
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
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:
47955
diff
changeset
|
140 .when_reading_file(&path)?; |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
diff
changeset
|
141 Ok(Ok(mmap)) |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
diff
changeset
|
142 } |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
diff
changeset
|
143 |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
diff
changeset
|
144 pub fn mmap_open_opt( |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
diff
changeset
|
145 &self, |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
diff
changeset
|
146 relative_path: impl AsRef<Path>, |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
diff
changeset
|
147 ) -> Result<Option<Mmap>, HgError> { |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
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:
47955
diff
changeset
|
149 } |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
diff
changeset
|
150 |
47952
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> { |
48199
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
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:
47955
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:
47955
diff
changeset
|
157 Ok(res) => Ok(res), |
9d0e5629cfbf
rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
47955
diff
changeset
|
158 } |
47952
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 |
48417
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48345
diff
changeset
|
161 #[cfg(unix)] |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48345
diff
changeset
|
162 pub fn create_symlink( |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48345
diff
changeset
|
163 &self, |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48345
diff
changeset
|
164 relative_link_path: impl AsRef<Path>, |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48345
diff
changeset
|
165 target_path: impl AsRef<Path>, |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48345
diff
changeset
|
166 ) -> Result<(), HgError> { |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48345
diff
changeset
|
167 let link_path = self.join(relative_link_path); |
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48345
diff
changeset
|
168 std::os::unix::fs::symlink(target_path, &link_path) |
48418
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
diff
changeset
|
169 .when_writing_file(&link_path) |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
diff
changeset
|
170 } |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
diff
changeset
|
171 |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
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:
48417
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:
48417
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:
48417
diff
changeset
|
175 /// content, never a partial write. |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
diff
changeset
|
176 pub fn atomic_write( |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
diff
changeset
|
177 &self, |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
diff
changeset
|
178 relative_path: impl AsRef<Path>, |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
diff
changeset
|
179 contents: &[u8], |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
diff
changeset
|
180 ) -> Result<(), HgError> { |
52345
a48c688d3e80
rhg: set the expected dirstate permissions (0o666 minus umask)
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
52310
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:
52310
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:
52310
diff
changeset
|
183 .tempfile_in(&self.base) |
51864 | 184 .when_writing_file(&self.base)?; |
48418
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
diff
changeset
|
185 tmp.write_all(contents) |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
diff
changeset
|
186 .and_then(|()| tmp.flush()) |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
diff
changeset
|
187 .when_writing_file(tmp.path())?; |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
diff
changeset
|
188 let path = self.join(relative_path); |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
diff
changeset
|
189 tmp.persist(&path) |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
diff
changeset
|
190 .map_err(|e| e.error) |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
diff
changeset
|
191 .when_writing_file(&path)?; |
abeae090ce67
rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents:
48417
diff
changeset
|
192 Ok(()) |
48417
5734b03ecf3e
rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents:
48345
diff
changeset
|
193 } |
47952
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(); |
52180
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
200 match path.metadata() { |
47952
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 |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
214 /// Abstraction over the files handled by a [`Vfs`]. |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
215 #[derive(Debug)] |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
216 pub enum VfsFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
217 Atomic(AtomicFile), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
218 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
219 Normal { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
220 file: File, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
221 path: PathBuf, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
223 /// See [`is_filetime_ambiguous`]. |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
224 check_ambig: Option<Metadata>, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
225 }, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
226 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
227 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
228 impl VfsFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
229 pub fn normal(file: File, path: PathBuf) -> Self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
230 Self::Normal { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
231 file, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
232 check_ambig: None, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
233 path, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
234 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
235 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
236 pub fn normal_check_ambig( |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
237 file: File, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
238 path: PathBuf, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
239 ) -> Result<Self, HgError> { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
240 Ok(Self::Normal { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
241 file, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
243 path, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
244 }) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
245 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
246 pub fn try_clone(&self) -> Result<VfsFile, HgError> { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
247 Ok(match self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
248 VfsFile::Atomic(AtomicFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
249 fp, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
250 temp_path, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
251 check_ambig, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
252 target_name, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
253 is_open, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
254 }) => Self::Atomic(AtomicFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
256 temp_path: temp_path.clone(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
257 check_ambig: *check_ambig, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
258 target_name: target_name.clone(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
259 is_open: *is_open, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
260 }), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
261 VfsFile::Normal { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
262 file, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
263 check_ambig, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
264 path, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
265 } => Self::Normal { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
266 file: file.try_clone().when_reading_file(path)?, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
267 check_ambig: check_ambig.clone(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
268 path: path.to_owned(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
269 }, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
270 }) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
271 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
273 match self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
275 VfsFile::Normal { file, .. } => file.set_len(len), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
276 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
277 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
278 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
280 match self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
281 VfsFile::Atomic(atomic_file) => atomic_file.fp.metadata(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
282 VfsFile::Normal { file, .. } => file.metadata(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
283 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
284 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
285 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
286 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
287 impl AsRawFd for VfsFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
289 match self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
291 VfsFile::Normal { file, .. } => file.as_raw_fd(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
292 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
293 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
294 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
295 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
296 impl Seek for VfsFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
298 match self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
299 VfsFile::Atomic(atomic_file) => atomic_file.seek(pos), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
300 VfsFile::Normal { file, .. } => file.seek(pos), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
301 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
302 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
303 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
304 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
305 impl Read for VfsFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
307 match self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
309 VfsFile::Normal { file, .. } => file.read(buf), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
310 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
311 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
312 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
313 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
314 impl Write for VfsFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
316 match self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
318 VfsFile::Normal { file, .. } => file.write(buf), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
319 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
320 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
321 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
322 fn flush(&mut self) -> std::io::Result<()> { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
323 match self { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
324 VfsFile::Atomic(atomic_file) => atomic_file.fp.flush(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
325 VfsFile::Normal { file, .. } => file.flush(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
326 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
327 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
328 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
329 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
330 impl Drop for VfsFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
331 fn drop(&mut self) { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
332 if let VfsFile::Normal { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
333 path, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
334 check_ambig: Some(old), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
335 .. |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
336 } = self |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
337 { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
338 avoid_timestamp_ambiguity(path, old) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
339 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
340 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
341 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
342 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
344 /// applicable for tests. |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
345 #[cfg(test)] |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
346 static TIMESTAMP_FIXES_CALLS: AtomicUsize = AtomicUsize::new(0); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
347 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
348 fn avoid_timestamp_ambiguity(path: &Path, old: &Metadata) { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
349 if let Ok(new) = path.metadata() { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
350 let is_ambiguous = is_filetime_ambiguous(&new, old); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
351 if is_ambiguous { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
352 let advanced = |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
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:
52180
diff
changeset
|
355 #[cfg(test)] |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
356 { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
357 TIMESTAMP_FIXES_CALLS.fetch_add(1, Ordering::Relaxed); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
358 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
359 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
360 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
361 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
362 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
363 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
365 /// |
52306
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52294
diff
changeset
|
366 /// `S[N]` below means stat of a file at `N`-th change: |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
367 /// |
52306
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52294
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:
52294
diff
changeset
|
369 /// - `S[n-1].ctime == S[n].ctime` |
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52294
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:
52294
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:
52294
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:
52294
diff
changeset
|
373 /// - `S[n-1].ctime > S[n].ctime`: never occurs naturally (don't care) |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
374 /// |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
375 /// Case (*2) above means that a file was changed twice or more at |
52306
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52294
diff
changeset
|
376 /// same time in sec (= `S[n-1].ctime`), and comparison of timestamp |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
377 /// is ambiguous. |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
378 /// |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
380 /// timestamp is ambiguous". |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
381 /// |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
382 /// But advancing mtime only in case (*2) doesn't work as |
52306
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52294
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:
52294
diff
changeset
|
384 /// might be equal to manually advanced `S[n-1 or earlier].mtime`. |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
385 /// |
52306
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52294
diff
changeset
|
386 /// Therefore, all `S[n-1].ctime == S[n].ctime` cases should be |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
388 /// by confliction between such mtime. |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
389 /// |
52306
a876ab6c3fd5
rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52294
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:
52294
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:
52294
diff
changeset
|
392 pub fn is_filetime_ambiguous(new: &Metadata, old: &Metadata) -> bool { |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
393 new.ctime() == old.ctime() |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
394 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
395 |
51864 | 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. | |
52180
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
403 #[derive(Debug)] |
51864 | 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( | |
52180
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
420 target_path: impl AsRef<Path>, |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
421 empty: bool, |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
422 check_ambig: bool, |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
423 ) -> Result<Self, HgError> { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
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:
52179
diff
changeset
|
425 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
426 let random_id = |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
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:
52179
diff
changeset
|
428 let filename = |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
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:
52179
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:
52179
diff
changeset
|
431 let temp_filename = |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
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:
52179
diff
changeset
|
433 let temp_path = |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
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:
52179
diff
changeset
|
435 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
436 if !empty { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
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:
52179
diff
changeset
|
438 .with_context(|| IoErrorContext::CopyingFile { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
439 from: target_path.to_owned(), |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
440 to: temp_path.to_owned(), |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
441 }) |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
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:
52179
diff
changeset
|
443 .io_not_found_as_none()?; |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
444 } |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
445 let fp = std::fs::OpenOptions::new() |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
446 .write(true) |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
447 .create(true) |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
448 .truncate(empty) |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
449 .open(&temp_path) |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
450 .when_writing_file(&temp_path)?; |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
451 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
452 Ok(Self { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
453 fp, |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
454 temp_path, |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
455 check_ambig, |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
456 target_name: target_path, |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
457 is_open: true, |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
458 }) |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
459 } |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
460 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
461 pub fn from_file( |
51864 | 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 { | |
52180
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
493 if let Ok(stat) = target.metadata() { |
51864 | 494 std::fs::rename(&self.temp_path, &target)?; |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
495 avoid_timestamp_ambiguity(&target, &stat); |
51864 | 496 } else { |
497 std::fs::rename(&self.temp_path, target)?; | |
498 } | |
499 } else { | |
52180
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
500 std::fs::rename(&self.temp_path, target)?; |
51864 | 501 } |
502 self.is_open = false; | |
503 Ok(()) | |
504 } | |
505 } | |
506 | |
52180
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
507 impl Seek for AtomicFile { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
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:
52179
diff
changeset
|
509 self.fp.seek(pos) |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
510 } |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
511 } |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
512 |
51864 | 513 impl Drop for AtomicFile { |
514 fn drop(&mut self) { | |
515 if self.is_open { | |
52179
82007b8c189e
rust-vfs: delete the temp file and not the target on drop
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52178
diff
changeset
|
516 std::fs::remove_file(&self.temp_path).ok(); |
51864 | 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 { | |
52294
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52182
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:
52182
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:
52182
diff
changeset
|
526 fn open(&self, filename: &Path) -> Result<VfsFile, HgError>; |
52182
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52181
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:
52181
diff
changeset
|
528 /// `filename`, relative to this VFS's root. |
52294
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52182
diff
changeset
|
529 fn open_write(&self, filename: &Path) -> Result<VfsFile, HgError>; |
52182
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52181
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:
52181
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:
52181
diff
changeset
|
532 /// for an ambiguous mtime on [`drop`]. See [`is_filetime_ambiguous`]. |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
533 fn open_check_ambig(&self, filename: &Path) -> Result<VfsFile, HgError>; |
52182
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52181
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:
52181
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:
52181
diff
changeset
|
536 /// it will be truncated to 0 bytes. |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
537 fn create( |
51864 | 538 &self, |
539 filename: &Path, | |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
540 check_ambig: bool, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
541 ) -> Result<VfsFile, HgError>; |
52182
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52181
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:
52181
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:
52181
diff
changeset
|
544 /// it will be truncated to 0 bytes. |
51864 | 545 fn create_atomic( |
546 &self, | |
547 filename: &Path, | |
548 check_ambig: bool, | |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
549 ) -> Result<VfsFile, HgError>; |
52182
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52181
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:
52181
diff
changeset
|
551 /// usual IO errors (invalid file handle, permissions, etc.) |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
552 fn file_size(&self, file: &VfsFile) -> Result<u64, HgError>; |
52182
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52181
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:
52181
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:
52181
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:
52181
diff
changeset
|
556 /// to do anything with this path will get the same error. |
51864 | 557 fn exists(&self, filename: &Path) -> bool; |
52182
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52181
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:
52181
diff
changeset
|
559 /// are the usual IO errors (lacking permission, file does not exist, etc.) |
51864 | 560 fn unlink(&self, filename: &Path) -> Result<(), HgError>; |
52182
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52181
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:
52181
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:
52181
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:
52181
diff
changeset
|
564 /// ambiguous mtime on rename. See [`is_filetime_ambiguous`]. |
51864 | 565 fn rename( |
566 &self, | |
567 from: &Path, | |
568 to: &Path, | |
569 check_ambig: bool, | |
570 ) -> Result<(), HgError>; | |
52182
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52181
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:
52181
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:
52181
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:
52181
diff
changeset
|
574 /// ambiguous mtime on rename. See [`is_filetime_ambiguous`]. |
51864 | 575 fn copy(&self, from: &Path, to: &Path) -> Result<(), HgError>; |
52182
85bff84f0ad5
rust-vfs: add docstrings to all VFS methods on the trait
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52181
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:
52181
diff
changeset
|
577 /// operations are done. |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
578 fn base(&self) -> &Path; |
51864 | 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 { | |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
584 fn open(&self, filename: &Path) -> Result<VfsFile, HgError> { |
52294
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52182
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:
52182
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:
52182
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:
52182
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:
52182
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:
52182
diff
changeset
|
590 )) |
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52182
diff
changeset
|
591 } |
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52182
diff
changeset
|
592 |
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52182
diff
changeset
|
593 fn open_write(&self, filename: &Path) -> Result<VfsFile, HgError> { |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
594 if self.readonly { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
595 return Err(HgError::abort( |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
596 "write access in a readonly vfs", |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
597 exit_codes::ABORT, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
598 None, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
599 )); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
600 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
601 // TODO auditpath |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
602 let path = self.base.join(filename); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
603 copy_in_place_if_hardlink(&path)?; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
604 |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
605 Ok(VfsFile::normal( |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
606 OpenOptions::new() |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
607 .create(false) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
608 .create_new(false) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
609 .write(true) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
610 .read(true) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
611 .open(&path) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
612 .when_writing_file(&path)?, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
613 path.to_owned(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
614 )) |
51864 | 615 } |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
616 |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
617 fn open_check_ambig(&self, filename: &Path) -> Result<VfsFile, HgError> { |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
618 if self.readonly { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
619 return Err(HgError::abort( |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
620 "write access in a readonly vfs", |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
621 exit_codes::ABORT, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
622 None, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
623 )); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
624 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
625 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
626 let path = self.base.join(filename); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
627 copy_in_place_if_hardlink(&path)?; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
628 |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
629 // TODO auditpath |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
630 VfsFile::normal_check_ambig( |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
631 OpenOptions::new() |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
632 .write(true) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
634 .create(false) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
635 .open(&path) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
636 .when_reading_file(&path)?, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
637 path.to_owned(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
638 ) |
51864 | 639 } |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
640 |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
641 fn create( |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
642 &self, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
643 filename: &Path, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
644 check_ambig: bool, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
645 ) -> Result<VfsFile, HgError> { |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
646 if self.readonly { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
647 return Err(HgError::abort( |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
648 "write access in a readonly vfs", |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
649 exit_codes::ABORT, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
650 None, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
651 )); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
652 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
653 // TODO auditpath |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
654 let path = self.base.join(filename); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
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:
52157
diff
changeset
|
657 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
658 let file = OpenOptions::new() |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
659 .create(true) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
660 .truncate(true) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
661 .write(true) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
662 .read(true) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
663 .open(&path) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
664 .when_writing_file(&path)?; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
665 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
666 if let Some(mode) = self.mode { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
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:
52157
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:
52157
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:
52157
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:
52157
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:
52157
diff
changeset
|
673 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
674 |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
675 Ok(VfsFile::Normal { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
676 file, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
677 check_ambig: if check_ambig { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
678 Some(path.metadata().when_reading_file(&path)?) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
679 } else { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
680 None |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
681 }, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
682 path: path.to_owned(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
683 }) |
51864 | 684 } |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
685 |
51864 | 686 fn create_atomic( |
687 &self, | |
688 _filename: &Path, | |
689 _check_ambig: bool, | |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
690 ) -> Result<VfsFile, HgError> { |
51864 | 691 todo!() |
692 } | |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
693 |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
694 fn file_size(&self, file: &VfsFile) -> Result<u64, HgError> { |
51864 | 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 } | |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
706 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
707 fn exists(&self, filename: &Path) -> bool { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
708 self.base.join(filename).exists() |
51864 | 709 } |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
710 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
diff
changeset
|
712 if self.readonly { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
713 return Err(HgError::abort( |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
714 "write access in a readonly vfs", |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
715 exit_codes::ABORT, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
716 None, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
717 )); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
718 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
719 let path = self.base.join(filename); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
720 std::fs::remove_file(&path) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
721 .with_context(|| IoErrorContext::RemovingFile(path)) |
51864 | 722 } |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
723 |
51864 | 724 fn rename( |
725 &self, | |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
726 from: &Path, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
727 to: &Path, |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
728 check_ambig: bool, |
51864 | 729 ) -> Result<(), HgError> { |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
730 if self.readonly { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
731 return Err(HgError::abort( |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
732 "write access in a readonly vfs", |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
733 exit_codes::ABORT, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
734 None, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
735 )); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
736 } |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
737 let old_stat = if check_ambig { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
738 Some( |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
739 from.metadata() |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
740 .when_reading_file(from) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
741 .io_not_found_as_none()?, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
742 ) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
743 } else { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
744 None |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
745 }; |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
746 let from = self.base.join(from); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
747 let to = self.base.join(to); |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
748 std::fs::rename(&from, &to).with_context(|| { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
749 IoErrorContext::RenamingFile { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
750 from, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
751 to: to.to_owned(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
752 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
753 })?; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
754 if let Some(Some(old)) = old_stat { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
755 avoid_timestamp_ambiguity(&to, &old); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
756 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
757 Ok(()) |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
758 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
759 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
diff
changeset
|
761 let from = self.base.join(from); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
762 let to = self.base.join(to); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
763 std::fs::copy(&from, &to) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
764 .with_context(|| IoErrorContext::CopyingFile { from, to }) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
765 .map(|_| ()) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
766 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
767 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
768 fn base(&self) -> &Path { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
769 &self.base |
51864 | 770 } |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
771 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
772 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
773 fn fix_directory_permissions( |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
774 base: &Path, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
775 path: &Path, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
776 mode: u32, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
777 ) -> Result<(), HgError> { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
778 let mut ancestors = path.ancestors(); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
779 ancestors.next(); // yields the path itself |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
780 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
781 for ancestor in ancestors { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
782 if ancestor == base { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
783 break; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
784 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
diff
changeset
|
786 std::fs::set_permissions(ancestor, perm) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
787 .when_writing_file(ancestor)?; |
51864 | 788 } |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
789 Ok(()) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
790 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
791 |
52168
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
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:
52167
diff
changeset
|
793 /// adds new entries to the `fncache`. |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
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:
52167
diff
changeset
|
795 pub struct FnCacheVfs { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
796 inner: VfsImpl, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
797 fncache: Box<dyn FnCache>, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
798 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
799 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
800 impl Clone for FnCacheVfs { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
801 fn clone(&self) -> Self { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
802 Self { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
803 inner: self.inner.clone(), |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
804 fncache: dyn_clone::clone_box(&*self.fncache), |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
805 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
806 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
807 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
808 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
809 impl FnCacheVfs { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
810 pub fn new( |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
811 base: PathBuf, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
812 readonly: bool, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
813 fncache: Box<dyn FnCache>, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
814 ) -> Self { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
815 let inner = VfsImpl::new(base, readonly); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
816 Self { inner, fncache } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
817 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
818 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
819 fn maybe_add_to_fncache( |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
820 &self, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
821 filename: &Path, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
822 encoded_path: &Path, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
823 ) -> Result<(), HgError> { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
824 let relevant_file = (filename.starts_with("data/") |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
825 || filename.starts_with("meta/")) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
826 && is_revlog_file(filename); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
827 if relevant_file { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
828 let not_load = !self.fncache.is_loaded() |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
829 && (self.exists(filename) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
830 && self |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
831 .inner |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
832 .join(encoded_path) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
833 .metadata() |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
834 .when_reading_file(encoded_path)? |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
835 .size() |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
836 != 0); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
837 if !not_load { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
838 self.fncache.add(filename); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
839 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
840 }; |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
841 Ok(()) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
842 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
843 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
844 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
845 impl Vfs for FnCacheVfs { |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
846 fn open(&self, filename: &Path) -> Result<VfsFile, HgError> { |
52168
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
847 let encoded = path_encode(&get_bytes_from_path(filename)); |
52294
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52182
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:
52182
diff
changeset
|
849 self.inner.open(filename) |
52168
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
850 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
851 |
52294
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52182
diff
changeset
|
852 fn open_write(&self, filename: &Path) -> Result<VfsFile, HgError> { |
52168
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
853 let encoded = path_encode(&get_bytes_from_path(filename)); |
52294
645d247d4c75
rust-vfs: rename `open` to `open_write` and `open_read` to `open`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52182
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:
52182
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:
52182
diff
changeset
|
856 self.inner.open_write(encoded_path) |
52168
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
857 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
858 |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
859 fn open_check_ambig(&self, filename: &Path) -> Result<VfsFile, HgError> { |
52168
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
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:
52167
diff
changeset
|
861 let filename = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
862 self.inner.open_check_ambig(filename) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
863 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
864 |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
865 fn create( |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
866 &self, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
867 filename: &Path, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
868 check_ambig: bool, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
869 ) -> Result<VfsFile, HgError> { |
52168
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
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:
52167
diff
changeset
|
871 let encoded_path = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
872 self.maybe_add_to_fncache(filename, encoded_path)?; |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
873 self.inner.create(encoded_path, check_ambig) |
52168
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
874 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
875 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
876 fn create_atomic( |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
877 &self, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
878 filename: &Path, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
879 check_ambig: bool, |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
880 ) -> Result<VfsFile, HgError> { |
52168
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
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:
52167
diff
changeset
|
882 let filename = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
883 self.inner.create_atomic(filename, check_ambig) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
884 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
885 |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
886 fn file_size(&self, file: &VfsFile) -> Result<u64, HgError> { |
52168
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
887 self.inner.file_size(file) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
888 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
889 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
890 fn exists(&self, filename: &Path) -> bool { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
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:
52167
diff
changeset
|
892 let filename = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
893 self.inner.exists(filename) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
894 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
895 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
896 fn unlink(&self, filename: &Path) -> Result<(), HgError> { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
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:
52167
diff
changeset
|
898 let filename = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
899 self.inner.unlink(filename) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
900 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
901 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
902 fn rename( |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
903 &self, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
904 from: &Path, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
905 to: &Path, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
906 check_ambig: bool, |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
907 ) -> Result<(), HgError> { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
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:
52167
diff
changeset
|
909 let from = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
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:
52167
diff
changeset
|
911 let to = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
912 self.inner.rename(from, to, check_ambig) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
913 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
914 |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
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:
52167
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:
52167
diff
changeset
|
917 let from = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
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:
52167
diff
changeset
|
919 let to = get_path_from_bytes(&encoded); |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
920 self.inner.copy(from, to) |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
921 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
922 fn base(&self) -> &Path { |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
923 self.inner.base() |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
924 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
925 } |
067ec8574c33
hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52167
diff
changeset
|
926 |
52167
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
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:
52157
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:
52157
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:
52157
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:
52157
diff
changeset
|
932 if metadata.nlink() > 0 { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
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:
52157
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:
52157
diff
changeset
|
936 let tmpfile = tmpdir.join(name); |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
diff
changeset
|
938 .with_context(|| IoErrorContext::CopyingFile { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
939 from: path.to_owned(), |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
940 to: tmpfile.to_owned(), |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
941 })?; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
diff
changeset
|
943 IoErrorContext::CopyingFile { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
944 from: path.to_owned(), |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
945 to: tmpfile.to_owned(), |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
946 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
947 })?; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
diff
changeset
|
949 IoErrorContext::RenamingFile { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
950 from: tmpfile, |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
951 to: path.to_owned(), |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
952 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
953 })?; |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
954 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
955 Ok(()) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
956 } |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
957 |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
diff
changeset
|
959 path.as_ref() |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
960 .extension() |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
961 .map(|ext| { |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
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:
52157
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:
52157
diff
changeset
|
964 }) |
7be39c5110c9
hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52157
diff
changeset
|
965 .unwrap_or(false) |
51864 | 966 } |
967 | |
47952
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 } |
50180
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49485
diff
changeset
|
975 |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49485
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:
49485
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:
49485
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:
49485
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:
49485
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:
49485
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:
49485
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:
49485
diff
changeset
|
983 |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49485
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:
49485
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:
49485
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:
49485
diff
changeset
|
987 }; |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49485
diff
changeset
|
988 |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49485
diff
changeset
|
989 unsafe { |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49485
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:
49485
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:
49485
diff
changeset
|
992 |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49485
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:
49485
diff
changeset
|
994 } |
be019ac8c1e4
dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents:
49485
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 } |
52180
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1006 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1007 #[cfg(test)] |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1008 mod tests { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1009 use super::*; |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1010 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1011 #[test] |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1012 fn test_atomic_file() { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
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:
52179
diff
changeset
|
1014 let target_path = dir.join("sometargetname"); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1015 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1016 for empty in [true, false] { |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
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:
52179
diff
changeset
|
1018 assert!(file.is_open); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1019 let filename = |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
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:
52179
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:
52179
diff
changeset
|
1022 assert_eq!(filename.len(), 29, "{}", filename); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1023 assert!(filename.contains("sometargetname")); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1024 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
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:
52179
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:
52179
diff
changeset
|
1027 } |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1028 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1029 assert!(!target_path.exists()); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
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:
52179
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:
52179
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:
52179
diff
changeset
|
1033 assert_eq!( |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1034 std::fs::read(&target_path).unwrap(), |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1035 b"version 1".to_vec() |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1036 ); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
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:
52179
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:
52179
diff
changeset
|
1039 // affect the target path. |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1040 drop(file); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1041 assert_eq!( |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1042 std::fs::read(&target_path).unwrap(), |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1043 b"version 1".to_vec() |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1044 ); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1045 assert!(!temp_path.exists()); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1046 |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
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:
52179
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:
52179
diff
changeset
|
1049 assert_eq!( |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1050 std::fs::read(&target_path).unwrap(), |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1051 b"version 1".to_vec() |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1052 ); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1053 file.close().unwrap(); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1054 assert_eq!( |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1055 std::fs::read(&target_path).unwrap(), |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1056 b"version 2!".to_vec(), |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1057 "{}", |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
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:
52179
diff
changeset
|
1059 ); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1060 assert!(target_path.exists()); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1061 assert!(!temp_path.exists()); |
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1062 } |
52181
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1063 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1064 #[test] |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1065 fn test_vfs_file_check_ambig() { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1066 let dir = tempfile::tempdir().unwrap().into_path(); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1067 let file_path = dir.join("file"); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1068 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
1070 let file = std::fs::OpenOptions::new() |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1071 .write(true) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1072 .open(file_path) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1073 .unwrap(); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1074 let old_stat = if check_ambig { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1075 Some(file.metadata().unwrap()) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1076 } else { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1077 None |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1078 }; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1079 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1080 let mut vfs_file = VfsFile::Normal { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1081 file, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1082 path: file_path.to_owned(), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1083 check_ambig: old_stat, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1084 }; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1085 vfs_file.write_all(b"contents").unwrap(); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1086 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1087 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1088 std::fs::OpenOptions::new() |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1089 .write(true) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1090 .create(true) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1091 .truncate(false) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1092 .open(&file_path) |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1093 .unwrap(); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1094 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1095 let number_of_writes = 3; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1096 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
diff
changeset
|
1098 // on "filesystem time" |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1099 for _ in 0..5 { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1100 TIMESTAMP_FIXES_CALLS.store(0, Ordering::Relaxed); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1101 vfs_file_write(&file_path, false); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1102 let old_stat = file_path.metadata().unwrap(); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1103 if old_stat.ctime() != old_stat.mtime() { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1104 // subsequent changing never causes ambiguity |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1105 continue; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1106 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1107 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
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:
52180
diff
changeset
|
1110 for _ in 0..number_of_writes { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1111 vfs_file_write(&file_path, true); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1112 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1113 let new_stat = file_path.metadata().unwrap(); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1114 if !is_filetime_ambiguous(&new_stat, &old_stat) { |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1115 // timestamp ambiguity was naturally avoided while repetition |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1116 continue; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1117 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1118 |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1119 assert_eq!( |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1120 TIMESTAMP_FIXES_CALLS.load(Ordering::Relaxed), |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1121 number_of_writes |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1122 ); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1123 assert_eq!( |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1124 old_stat.mtime() + number_of_writes as i64, |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1125 file_path.metadata().unwrap().mtime() |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1126 ); |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1127 break; |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1128 } |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
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:
52180
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:
52180
diff
changeset
|
1131 // still work on fast platforms. |
8d35941689af
rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52180
diff
changeset
|
1132 } |
52180
735bf027dd1d
rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents:
52179
diff
changeset
|
1133 } |