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
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
22 #[derive(Clone)]
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
23 pub struct VfsImpl {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
133 // Safety is "enforced" by locks and assuming other processes are
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
134 // well-behaved. If any misbehaving or malicious process does touch
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
135 // the index, it could lead to corruption. This is inherent
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
136 // to file-based `mmap`, though some platforms have some ways of
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
137 // mitigating.
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
396 /// Writable file object that atomically updates a file
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
397 ///
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
398 /// All writes will go to a temporary copy of the original file. Call
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
399 /// [`Self::close`] when you are done writing, and [`Self`] will rename
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
400 /// the temporary copy to the original name, making the changes
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
401 /// visible. If the object is destroyed without being closed, all your
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
404 pub struct AtomicFile {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
405 /// The temporary file to write to
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
406 fp: std::fs::File,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
407 /// Path of the temp file
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
408 temp_path: PathBuf,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
409 /// Used when stat'ing the file, is useful only if the target file is
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
410 /// guarded by any lock (e.g. repo.lock or repo.wlock).
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
411 check_ambig: bool,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
412 /// Path of the target file
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
413 target_name: PathBuf,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
414 /// Whether the file is open or not
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
415 is_open: bool,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
416 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
417
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
418 impl AtomicFile {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
462 fp: std::fs::File,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
463 check_ambig: bool,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
464 temp_name: PathBuf,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
465 target_name: PathBuf,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
466 ) -> Self {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
467 Self {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
468 fp,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
469 check_ambig,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
470 temp_path: temp_name,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
471 target_name,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
472 is_open: true,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
473 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
474 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
475
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
476 /// Write `buf` to the temporary file
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
477 pub fn write_all(&mut self, buf: &[u8]) -> Result<(), std::io::Error> {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
478 self.fp.write_all(buf)
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
479 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
480
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
481 fn target(&self) -> PathBuf {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
482 self.temp_path
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
483 .parent()
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
484 .expect("should not be at the filesystem root")
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
485 .join(&self.target_name)
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
486 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
487
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
488 /// Close the temporary file and rename to the target
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
489 pub fn close(mut self) -> Result<(), std::io::Error> {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
490 self.fp.flush()?;
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
491 let target = self.target();
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
496 } else {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
497 std::fs::rename(&self.temp_path, target)?;
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
498 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
501 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
502 self.is_open = false;
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
503 Ok(())
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
504 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
505 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
513 impl Drop for AtomicFile {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
514 fn drop(&mut self) {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
517 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
518 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
519 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
520
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
521 /// Abstracts over the VFS to allow for different implementations of the
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
522 /// filesystem layer (like passing one from Python).
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
538 &self,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
545 fn create_atomic(
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
546 &self,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
547 filename: &Path,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
565 fn rename(
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
566 &self,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
567 from: &Path,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
568 to: &Path,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
569 check_ambig: bool,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
579 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
580
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
581 /// These methods will need to be implemented once `rhg` (and other) non-Python
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
582 /// users of `hg-core` start doing more on their own, like writing to files.
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
684 }
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
685
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
686 fn create_atomic(
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
687 &self,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
688 _filename: &Path,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
691 todo!()
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
695 Ok(file
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
696 .metadata()
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
697 .map_err(|e| {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
698 HgError::abort(
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
699 format!("Could not get file metadata: {}", e),
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
700 exit_codes::ABORT,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
701 None,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
702 )
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
703 })?
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
704 .size())
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
722 }
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
723
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
724 fn rename(
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
966 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
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 }