annotate rust/hg-core/src/vfs.rs @ 52769:1b7a57a5b47a

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