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