annotate rust/hg-core/src/vfs.rs @ 52310:33d8cb64e9da

rust: fix darwin build
author Dan Villiom Podlaski Christiansen <danchr@gmail.com>
date Mon, 18 Nov 2024 15:42:09 +0100
parents a876ab6c3fd5
children a48c688d3e80
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> {
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
181 let mut tmp = tempfile::NamedTempFile::new_in(&self.base)
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
182 .when_writing_file(&self.base)?;
48418
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
183 tmp.write_all(contents)
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
184 .and_then(|()| tmp.flush())
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
185 .when_writing_file(tmp.path())?;
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
186 let path = self.join(relative_path);
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
187 tmp.persist(&path)
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
188 .map_err(|e| e.error)
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
189 .when_writing_file(&path)?;
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
190 Ok(())
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
191 }
47952
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
192 }
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
193
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
194 fn fs_metadata(
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
195 path: impl AsRef<Path>,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
196 ) -> Result<Option<std::fs::Metadata>, HgError> {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
197 let path = path.as_ref();
52180
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
198 match path.metadata() {
47952
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
199 Ok(meta) => Ok(Some(meta)),
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
200 Err(error) => match error.kind() {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
201 // 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
202 // 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
203 // and propagate any other error.
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
204 ErrorKind::PermissionDenied => Err(error).with_context(|| {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
205 IoErrorContext::ReadingMetadata(path.to_owned())
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
206 }),
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
207 _ => Ok(None),
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 }
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
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
212 /// Abstraction over the files handled by a [`Vfs`].
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
213 #[derive(Debug)]
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
214 pub enum VfsFile {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
215 Atomic(AtomicFile),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
216
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
217 Normal {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
218 file: File,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
219 path: PathBuf,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
220 /// 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
221 /// See [`is_filetime_ambiguous`].
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
222 check_ambig: Option<Metadata>,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
223 },
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
224 }
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 impl VfsFile {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
227 pub fn normal(file: File, path: PathBuf) -> Self {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
228 Self::Normal {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
229 file,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
230 check_ambig: None,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
231 path,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
232 }
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
233 }
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
234 pub fn normal_check_ambig(
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
235 file: File,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
236 path: PathBuf,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
237 ) -> Result<Self, HgError> {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
238 Ok(Self::Normal {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
239 file,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
240 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
241 path,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
242 })
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
243 }
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
244 pub fn try_clone(&self) -> Result<VfsFile, HgError> {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
245 Ok(match self {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
246 VfsFile::Atomic(AtomicFile {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
247 fp,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
248 temp_path,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
249 check_ambig,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
250 target_name,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
251 is_open,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
252 }) => Self::Atomic(AtomicFile {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
253 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
254 temp_path: temp_path.clone(),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
255 check_ambig: *check_ambig,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
256 target_name: target_name.clone(),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
257 is_open: *is_open,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
258 }),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
259 VfsFile::Normal {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
260 file,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
261 check_ambig,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
262 path,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
263 } => Self::Normal {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
264 file: file.try_clone().when_reading_file(path)?,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
265 check_ambig: check_ambig.clone(),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
266 path: path.to_owned(),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
267 },
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
268 })
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 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
271 match self {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
272 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
273 VfsFile::Normal { file, .. } => file.set_len(len),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
274 }
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
275 }
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 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
278 match self {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
279 VfsFile::Atomic(atomic_file) => atomic_file.fp.metadata(),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
280 VfsFile::Normal { file, .. } => file.metadata(),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
281 }
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
282 }
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 impl AsRawFd for VfsFile {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
286 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
287 match self {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
288 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
289 VfsFile::Normal { file, .. } => file.as_raw_fd(),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
290 }
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
291 }
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 impl Seek for VfsFile {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
295 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
296 match self {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
297 VfsFile::Atomic(atomic_file) => atomic_file.seek(pos),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
298 VfsFile::Normal { file, .. } => file.seek(pos),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
299 }
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
300 }
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 impl Read for VfsFile {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
304 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
305 match self {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
306 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
307 VfsFile::Normal { file, .. } => file.read(buf),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
308 }
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
309 }
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 impl Write for VfsFile {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
313 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
314 match self {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
315 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
316 VfsFile::Normal { file, .. } => file.write(buf),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
317 }
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
318 }
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 fn flush(&mut self) -> std::io::Result<()> {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
321 match self {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
322 VfsFile::Atomic(atomic_file) => atomic_file.fp.flush(),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
323 VfsFile::Normal { file, .. } => file.flush(),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
324 }
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
325 }
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 impl Drop for VfsFile {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
329 fn drop(&mut self) {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
330 if let VfsFile::Normal {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
331 path,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
332 check_ambig: Some(old),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
333 ..
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
334 } = self
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 avoid_timestamp_ambiguity(path, old)
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 }
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 /// 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
342 /// applicable for tests.
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
343 #[cfg(test)]
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
344 static TIMESTAMP_FIXES_CALLS: AtomicUsize = AtomicUsize::new(0);
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
345
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
346 fn avoid_timestamp_ambiguity(path: &Path, old: &Metadata) {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
347 if let Ok(new) = path.metadata() {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
348 let is_ambiguous = is_filetime_ambiguous(&new, old);
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
349 if is_ambiguous {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
350 let advanced =
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
351 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
352 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
353 #[cfg(test)]
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
354 {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
355 TIMESTAMP_FIXES_CALLS.fetch_add(1, Ordering::Relaxed);
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 }
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 /// 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
363 ///
52306
a876ab6c3fd5 rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52294
diff changeset
364 /// `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
365 ///
52306
a876ab6c3fd5 rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52294
diff changeset
366 /// - `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
367 /// - `S[n-1].ctime == S[n].ctime`
a876ab6c3fd5 rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52294
diff changeset
368 /// - `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
369 /// - `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
370 /// - `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
371 /// - `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
372 ///
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
373 /// 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
374 /// 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
375 /// is ambiguous.
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
376 ///
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
377 /// 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
378 /// timestamp is ambiguous".
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
379 ///
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
380 /// 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
381 /// 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
382 /// 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
383 ///
52306
a876ab6c3fd5 rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52294
diff changeset
384 /// 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
385 /// 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
386 /// by confliction between such mtime.
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
387 ///
52306
a876ab6c3fd5 rust: fix `cargo doc` warnings
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52294
diff changeset
388 /// 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
389 /// 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
390 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
391 new.ctime() == old.ctime()
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
392 }
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
393
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
394 /// Writable file object that atomically updates a file
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
395 ///
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
396 /// 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
397 /// [`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
398 /// 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
399 /// 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
400 /// writes are discarded.
52180
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
401 #[derive(Debug)]
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
402 pub struct AtomicFile {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
403 /// The temporary file to write to
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
404 fp: std::fs::File,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
405 /// Path of the temp file
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
406 temp_path: PathBuf,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
407 /// 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
408 /// 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
409 check_ambig: bool,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
410 /// Path of the target file
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
411 target_name: PathBuf,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
412 /// Whether the file is open or not
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
413 is_open: bool,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
414 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
415
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
416 impl AtomicFile {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
417 pub fn new(
52180
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
418 target_path: impl AsRef<Path>,
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
419 empty: bool,
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
420 check_ambig: bool,
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
421 ) -> Result<Self, HgError> {
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
422 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
423
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
424 let random_id =
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
425 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
426 let filename =
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
427 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
428 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
429 let temp_filename =
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
430 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
431 let temp_path =
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
432 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
433
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
434 if !empty {
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
435 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
436 .with_context(|| IoErrorContext::CopyingFile {
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
437 from: target_path.to_owned(),
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
438 to: temp_path.to_owned(),
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
439 })
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
440 // 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
441 .io_not_found_as_none()?;
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
442 }
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
443 let fp = std::fs::OpenOptions::new()
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
444 .write(true)
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
445 .create(true)
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
446 .truncate(empty)
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
447 .open(&temp_path)
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
448 .when_writing_file(&temp_path)?;
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
449
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
450 Ok(Self {
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
451 fp,
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
452 temp_path,
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
453 check_ambig,
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
454 target_name: target_path,
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
455 is_open: true,
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
456 })
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
457 }
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 pub fn from_file(
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
460 fp: std::fs::File,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
461 check_ambig: bool,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
462 temp_name: PathBuf,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
463 target_name: PathBuf,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
464 ) -> Self {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
465 Self {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
466 fp,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
467 check_ambig,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
468 temp_path: temp_name,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
469 target_name,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
470 is_open: true,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
471 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
472 }
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 /// Write `buf` to the temporary file
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
475 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
476 self.fp.write_all(buf)
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
477 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
478
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
479 fn target(&self) -> PathBuf {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
480 self.temp_path
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
481 .parent()
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
482 .expect("should not be at the filesystem root")
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
483 .join(&self.target_name)
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
484 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
485
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
486 /// 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
487 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
488 self.fp.flush()?;
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
489 let target = self.target();
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
490 if self.check_ambig {
52180
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
491 if let Ok(stat) = target.metadata() {
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
492 std::fs::rename(&self.temp_path, &target)?;
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
493 avoid_timestamp_ambiguity(&target, &stat);
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
494 } else {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
495 std::fs::rename(&self.temp_path, target)?;
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
496 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
497 } else {
52180
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
498 std::fs::rename(&self.temp_path, target)?;
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
499 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
500 self.is_open = false;
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
501 Ok(())
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
502 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
503 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
504
52180
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
505 impl Seek for AtomicFile {
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
506 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
507 self.fp.seek(pos)
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
508 }
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
509 }
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
510
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
511 impl Drop for AtomicFile {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
512 fn drop(&mut self) {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
513 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
514 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
515 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
516 }
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 /// 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
520 /// filesystem layer (like passing one from Python).
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
521 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
522 /// 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
523 /// 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
524 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
525 /// 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
526 /// `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
527 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
528 /// 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
529 /// `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
530 /// 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
531 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
532 /// 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
533 /// `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
534 /// it will be truncated to 0 bytes.
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
535 fn create(
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
536 &self,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
537 filename: &Path,
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
538 check_ambig: bool,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
539 ) -> 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
540 /// 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
541 /// `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
542 /// it will be truncated to 0 bytes.
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
543 fn create_atomic(
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
544 &self,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
545 filename: &Path,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
546 check_ambig: bool,
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
547 ) -> 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
548 /// 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
549 /// 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
550 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
551 /// 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
552 /// 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
553 /// 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
554 /// 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
555 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
556 /// 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
557 /// 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
558 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
559 /// 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
560 /// 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
561 /// 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
562 /// 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
563 fn rename(
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
564 &self,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
565 from: &Path,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
566 to: &Path,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
567 check_ambig: bool,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
568 ) -> 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
569 /// 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
570 /// 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
571 /// 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
572 /// 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
573 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
574 /// 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
575 /// operations are done.
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
576 fn base(&self) -> &Path;
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
577 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
578
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
579 /// 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
580 /// 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
581 impl Vfs for VfsImpl {
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
582 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
583 // 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
584 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
585 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
586 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
587 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
588 ))
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 }
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 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
592 if self.readonly {
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
593 return Err(HgError::abort(
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
594 "write access in a readonly vfs",
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
595 exit_codes::ABORT,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
596 None,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
597 ));
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
598 }
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
599 // TODO auditpath
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
600 let path = self.base.join(filename);
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
601 copy_in_place_if_hardlink(&path)?;
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
602
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
603 Ok(VfsFile::normal(
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
604 OpenOptions::new()
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
605 .create(false)
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
606 .create_new(false)
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
607 .write(true)
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
608 .read(true)
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
609 .open(&path)
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
610 .when_writing_file(&path)?,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
611 path.to_owned(),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
612 ))
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
613 }
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
614
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
615 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
616 if self.readonly {
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
617 return Err(HgError::abort(
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
618 "write access in a readonly vfs",
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
619 exit_codes::ABORT,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
620 None,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
621 ));
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
622 }
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 let path = self.base.join(filename);
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
625 copy_in_place_if_hardlink(&path)?;
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
626
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
627 // TODO auditpath
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
628 VfsFile::normal_check_ambig(
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
629 OpenOptions::new()
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
630 .write(true)
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
631 .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
632 .create(false)
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
633 .open(&path)
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
634 .when_reading_file(&path)?,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
635 path.to_owned(),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
636 )
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
637 }
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
638
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
639 fn create(
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
640 &self,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
641 filename: &Path,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
642 check_ambig: bool,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
643 ) -> Result<VfsFile, HgError> {
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
644 if self.readonly {
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
645 return Err(HgError::abort(
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
646 "write access in a readonly vfs",
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
647 exit_codes::ABORT,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
648 None,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
649 ));
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
650 }
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
651 // TODO auditpath
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
652 let path = self.base.join(filename);
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
653 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
654 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
655
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
656 let file = OpenOptions::new()
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
657 .create(true)
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
658 .truncate(true)
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
659 .write(true)
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
660 .read(true)
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
661 .open(&path)
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
662 .when_writing_file(&path)?;
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
663
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
664 if let Some(mode) = self.mode {
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
665 // 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
666 // 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
667 // 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
668 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
669 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
670 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
671 }
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
672
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
673 Ok(VfsFile::Normal {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
674 file,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
675 check_ambig: if check_ambig {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
676 Some(path.metadata().when_reading_file(&path)?)
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
677 } else {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
678 None
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
679 },
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
680 path: path.to_owned(),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
681 })
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
682 }
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
683
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
684 fn create_atomic(
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
685 &self,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
686 _filename: &Path,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
687 _check_ambig: bool,
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
688 ) -> Result<VfsFile, HgError> {
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
689 todo!()
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
690 }
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
691
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
692 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
693 Ok(file
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
694 .metadata()
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
695 .map_err(|e| {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
696 HgError::abort(
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
697 format!("Could not get file metadata: {}", e),
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
698 exit_codes::ABORT,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
699 None,
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
700 )
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
701 })?
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
702 .size())
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
703 }
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
704
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
705 fn exists(&self, filename: &Path) -> bool {
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
706 self.base.join(filename).exists()
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
707 }
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
708
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
709 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
710 if self.readonly {
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
711 return Err(HgError::abort(
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
712 "write access in a readonly vfs",
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
713 exit_codes::ABORT,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
714 None,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
715 ));
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
716 }
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
717 let path = self.base.join(filename);
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
718 std::fs::remove_file(&path)
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
719 .with_context(|| IoErrorContext::RemovingFile(path))
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
720 }
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
721
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
722 fn rename(
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
723 &self,
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
724 from: &Path,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
725 to: &Path,
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
726 check_ambig: bool,
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
727 ) -> Result<(), HgError> {
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
728 if self.readonly {
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
729 return Err(HgError::abort(
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
730 "write access in a readonly vfs",
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
731 exit_codes::ABORT,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
732 None,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
733 ));
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
734 }
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
735 let old_stat = if check_ambig {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
736 Some(
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
737 from.metadata()
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
738 .when_reading_file(from)
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
739 .io_not_found_as_none()?,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
740 )
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
741 } else {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
742 None
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
743 };
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
744 let from = self.base.join(from);
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
745 let to = self.base.join(to);
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
746 std::fs::rename(&from, &to).with_context(|| {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
747 IoErrorContext::RenamingFile {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
748 from,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
749 to: to.to_owned(),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
750 }
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
751 })?;
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
752 if let Some(Some(old)) = old_stat {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
753 avoid_timestamp_ambiguity(&to, &old);
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
754 }
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
755 Ok(())
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
756 }
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
757
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
758 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
759 let from = self.base.join(from);
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
760 let to = self.base.join(to);
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
761 std::fs::copy(&from, &to)
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
762 .with_context(|| IoErrorContext::CopyingFile { from, to })
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
763 .map(|_| ())
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
764 }
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
765
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
766 fn base(&self) -> &Path {
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
767 &self.base
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
768 }
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
769 }
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
770
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
771 fn fix_directory_permissions(
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
772 base: &Path,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
773 path: &Path,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
774 mode: u32,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
775 ) -> Result<(), HgError> {
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
776 let mut ancestors = path.ancestors();
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
777 ancestors.next(); // yields the path itself
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
778
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
779 for ancestor in ancestors {
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
780 if ancestor == base {
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
781 break;
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
782 }
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
783 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
784 std::fs::set_permissions(ancestor, perm)
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
785 .when_writing_file(ancestor)?;
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
786 }
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
787 Ok(())
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
788 }
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
789
52168
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
790 /// 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
791 /// adds new entries to the `fncache`.
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
792 /// 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
793 pub struct FnCacheVfs {
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
794 inner: VfsImpl,
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
795 fncache: Box<dyn FnCache>,
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
796 }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
797
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
798 impl Clone for FnCacheVfs {
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
799 fn clone(&self) -> Self {
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
800 Self {
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
801 inner: self.inner.clone(),
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
802 fncache: dyn_clone::clone_box(&*self.fncache),
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
803 }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
804 }
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 impl FnCacheVfs {
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
808 pub fn new(
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
809 base: PathBuf,
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
810 readonly: bool,
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
811 fncache: Box<dyn FnCache>,
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
812 ) -> Self {
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
813 let inner = VfsImpl::new(base, readonly);
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
814 Self { inner, fncache }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
815 }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
816
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
817 fn maybe_add_to_fncache(
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
818 &self,
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
819 filename: &Path,
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
820 encoded_path: &Path,
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
821 ) -> Result<(), HgError> {
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
822 let relevant_file = (filename.starts_with("data/")
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
823 || filename.starts_with("meta/"))
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
824 && is_revlog_file(filename);
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
825 if relevant_file {
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
826 let not_load = !self.fncache.is_loaded()
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
827 && (self.exists(filename)
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
828 && self
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
829 .inner
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
830 .join(encoded_path)
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
831 .metadata()
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
832 .when_reading_file(encoded_path)?
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
833 .size()
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
834 != 0);
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
835 if !not_load {
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
836 self.fncache.add(filename);
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
837 }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
838 };
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
839 Ok(())
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 }
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 impl Vfs for FnCacheVfs {
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
844 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
845 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
846 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
847 self.inner.open(filename)
52168
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
848 }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
849
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
850 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
851 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
852 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
853 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
854 self.inner.open_write(encoded_path)
52168
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
855 }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
856
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
857 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
858 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
859 let filename = get_path_from_bytes(&encoded);
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
860 self.inner.open_check_ambig(filename)
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
861 }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
862
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
863 fn create(
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
864 &self,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
865 filename: &Path,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
866 check_ambig: bool,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
867 ) -> Result<VfsFile, HgError> {
52168
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
868 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
869 let encoded_path = get_path_from_bytes(&encoded);
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
870 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
871 self.inner.create(encoded_path, check_ambig)
52168
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
872 }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
873
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
874 fn create_atomic(
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
875 &self,
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
876 filename: &Path,
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
877 check_ambig: bool,
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
878 ) -> Result<VfsFile, HgError> {
52168
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
879 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
880 let filename = get_path_from_bytes(&encoded);
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
881 self.inner.create_atomic(filename, check_ambig)
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
882 }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
883
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
884 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
885 self.inner.file_size(file)
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
886 }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
887
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
888 fn exists(&self, filename: &Path) -> bool {
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
889 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
890 let filename = get_path_from_bytes(&encoded);
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
891 self.inner.exists(filename)
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
892 }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
893
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
894 fn unlink(&self, filename: &Path) -> Result<(), HgError> {
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
895 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
896 let filename = get_path_from_bytes(&encoded);
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
897 self.inner.unlink(filename)
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
898 }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
899
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
900 fn rename(
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
901 &self,
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
902 from: &Path,
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
903 to: &Path,
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
904 check_ambig: bool,
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
905 ) -> Result<(), HgError> {
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
906 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
907 let from = get_path_from_bytes(&encoded);
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(to));
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
909 let to = get_path_from_bytes(&encoded);
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
910 self.inner.rename(from, to, check_ambig)
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
911 }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
912
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
913 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
914 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
915 let from = get_path_from_bytes(&encoded);
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(to));
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
917 let to = get_path_from_bytes(&encoded);
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
918 self.inner.copy(from, to)
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
919 }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
920 fn base(&self) -> &Path {
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
921 self.inner.base()
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
922 }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
923 }
067ec8574c33 hg-core: add FnCacheVFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52167
diff changeset
924
52167
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
925 /// 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
926 /// 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
927 /// 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
928 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
929 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
930 if metadata.nlink() > 0 {
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
931 // 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
932 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
933 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
934 let tmpfile = tmpdir.join(name);
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
935 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
936 .with_context(|| IoErrorContext::CopyingFile {
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
937 from: path.to_owned(),
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
938 to: tmpfile.to_owned(),
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
939 })?;
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
940 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
941 IoErrorContext::CopyingFile {
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
942 from: path.to_owned(),
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
943 to: tmpfile.to_owned(),
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
944 }
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
945 })?;
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
946 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
947 IoErrorContext::RenamingFile {
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
948 from: tmpfile,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
949 to: path.to_owned(),
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
950 }
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
951 })?;
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 Ok(())
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
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
956 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
957 path.as_ref()
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
958 .extension()
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
959 .map(|ext| {
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
960 ["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
961 .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
962 })
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52157
diff changeset
963 .unwrap_or(false)
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
964 }
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50274
diff changeset
965
47952
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
966 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
967 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
968 }
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
969
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
970 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
971 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
972 }
50180
be019ac8c1e4 dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49485
diff changeset
973
be019ac8c1e4 dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49485
diff changeset
974 /// 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
975 /// 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
976 #[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
977 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
978 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
979 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
980 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
981
be019ac8c1e4 dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49485
diff changeset
982 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
983 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
984 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
985 };
be019ac8c1e4 dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49485
diff changeset
986
be019ac8c1e4 dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49485
diff changeset
987 unsafe {
be019ac8c1e4 dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49485
diff changeset
988 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
989 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
990
be019ac8c1e4 dirstate-v2: don't mmap the data file when on NFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49485
diff changeset
991 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
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 }
50274
0cc19a53cef4 rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 50252
diff changeset
994
0cc19a53cef4 rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 50252
diff changeset
995 /// 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
996 /// 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
997 /// 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
998 /// _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
999 /// all
0cc19a53cef4 rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 50252
diff changeset
1000 #[cfg(not(target_os = "linux"))]
0cc19a53cef4 rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 50252
diff changeset
1001 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
1002 false
0cc19a53cef4 rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 50252
diff changeset
1003 }
52180
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1004
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1005 #[cfg(test)]
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1006 mod tests {
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1007 use super::*;
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1008
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1009 #[test]
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1010 fn test_atomic_file() {
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1011 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
1012 let target_path = dir.join("sometargetname");
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1013
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1014 for empty in [true, false] {
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1015 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
1016 assert!(file.is_open);
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1017 let filename =
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1018 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
1019 // 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
1020 assert_eq!(filename.len(), 29, "{}", filename);
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1021 assert!(filename.contains("sometargetname"));
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1022
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1023 // 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
1024 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
1025 }
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1026
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1027 assert!(!target_path.exists());
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1028 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
1029 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
1030 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
1031 assert_eq!(
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1032 std::fs::read(&target_path).unwrap(),
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1033 b"version 1".to_vec()
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1034 );
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1035 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
1036 // 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
1037 // affect the target path.
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1038 drop(file);
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1039 assert_eq!(
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1040 std::fs::read(&target_path).unwrap(),
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1041 b"version 1".to_vec()
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1042 );
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1043 assert!(!temp_path.exists());
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 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
1046 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
1047 assert_eq!(
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1048 std::fs::read(&target_path).unwrap(),
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1049 b"version 1".to_vec()
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1050 );
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1051 file.close().unwrap();
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1052 assert_eq!(
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1053 std::fs::read(&target_path).unwrap(),
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1054 b"version 2!".to_vec(),
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1055 "{}",
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1056 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
1057 );
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1058 assert!(target_path.exists());
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1059 assert!(!temp_path.exists());
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1060 }
52181
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1061
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1062 #[test]
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1063 fn test_vfs_file_check_ambig() {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1064 let dir = tempfile::tempdir().unwrap().into_path();
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1065 let file_path = dir.join("file");
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1066
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1067 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
1068 let file = std::fs::OpenOptions::new()
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1069 .write(true)
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1070 .open(file_path)
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1071 .unwrap();
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1072 let old_stat = if check_ambig {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1073 Some(file.metadata().unwrap())
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1074 } else {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1075 None
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1076 };
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1077
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1078 let mut vfs_file = VfsFile::Normal {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1079 file,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1080 path: file_path.to_owned(),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1081 check_ambig: old_stat,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1082 };
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1083 vfs_file.write_all(b"contents").unwrap();
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
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1086 std::fs::OpenOptions::new()
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1087 .write(true)
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1088 .create(true)
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1089 .truncate(false)
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1090 .open(&file_path)
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1091 .unwrap();
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1092
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1093 let number_of_writes = 3;
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 // 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
1096 // on "filesystem time"
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1097 for _ in 0..5 {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1098 TIMESTAMP_FIXES_CALLS.store(0, Ordering::Relaxed);
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1099 vfs_file_write(&file_path, false);
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1100 let old_stat = file_path.metadata().unwrap();
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1101 if old_stat.ctime() != old_stat.mtime() {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1102 // subsequent changing never causes ambiguity
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1103 continue;
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1104 }
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1105
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1106 // 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
1107 // 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
1108 for _ in 0..number_of_writes {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1109 vfs_file_write(&file_path, true);
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1110 }
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1111 let new_stat = file_path.metadata().unwrap();
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1112 if !is_filetime_ambiguous(&new_stat, &old_stat) {
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1113 // timestamp ambiguity was naturally avoided while repetition
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1114 continue;
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1115 }
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1116
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1117 assert_eq!(
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1118 TIMESTAMP_FIXES_CALLS.load(Ordering::Relaxed),
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1119 number_of_writes
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1120 );
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1121 assert_eq!(
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1122 old_stat.mtime() + number_of_writes as i64,
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1123 file_path.metadata().unwrap().mtime()
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1124 );
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1125 break;
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 // 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
1128 // 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
1129 // still work on fast platforms.
8d35941689af rust-vfs: support checkambig
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52180
diff changeset
1130 }
52180
735bf027dd1d rust-vfs: add tests to `AtomicFile`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52179
diff changeset
1131 }