annotate rust/hg-core/src/vfs.rs @ 51950:93a533fa04ec

tests: stabilize `test-sparse.t` on Windows One of the reserved characters for path values is '*', so it can't be used. Fortunately, missing this seems to not get in the way of any other tests, and it is removed shortly after with `rm -r foo*bar`, and the extant 'foo-bar' matches the pattern.
author Matt Harbison <matt_harbison@yahoo.com>
date Fri, 04 Oct 2024 01:23:31 -0400
parents db7dbe6f7bb2
children 46c68c0fe137
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
47952
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
1 use crate::errors::{HgError, IoErrorContext, IoResultExt};
51868
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
2 use crate::exit_codes;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
3 use dyn_clone::DynClone;
47955
e834b79def74 rust: Switch to the memmap2-rs crate
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
4 use memmap2::{Mmap, MmapOptions};
51868
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
5 use std::fs::File;
48418
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
6 use std::io::{ErrorKind, Write};
51868
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
7 use std::os::unix::fs::MetadataExt;
47952
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
8 use std::path::{Path, PathBuf};
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
9
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
10 /// Filesystem access abstraction for the contents of a given "base" diretory
51868
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
11 #[derive(Clone)]
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
12 pub struct VfsImpl {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
13 pub(crate) base: PathBuf,
47952
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
14 }
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
15
48199
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
16 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
17
51868
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
18 impl VfsImpl {
47952
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
19 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
20 self.base.join(relative_path)
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
21 }
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
22
48345
d5a91701f7dc rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents: 48199
diff changeset
23 pub fn symlink_metadata(
d5a91701f7dc rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents: 48199
diff changeset
24 &self,
d5a91701f7dc rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents: 48199
diff changeset
25 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
26 ) -> 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
27 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
28 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
29 }
d5a91701f7dc rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents: 48199
diff changeset
30
d5a91701f7dc rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents: 48199
diff changeset
31 pub fn read_link(
d5a91701f7dc rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents: 48199
diff changeset
32 &self,
d5a91701f7dc rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents: 48199
diff changeset
33 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
34 ) -> Result<PathBuf, HgError> {
d5a91701f7dc rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents: 48199
diff changeset
35 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
36 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
37 }
d5a91701f7dc rhg: Fix status desambiguation of symlinks and executable files
Simon Sapin <simon.sapin@octobus.net>
parents: 48199
diff changeset
38
47952
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
39 pub fn read(
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
40 &self,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
41 relative_path: impl AsRef<Path>,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
42 ) -> Result<Vec<u8>, HgError> {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
43 let path = self.join(relative_path);
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
44 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
45 }
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
46
49485
ffd4b1f1c9cb rhg: add sparse support
Raphaël Gomès <rgomes@octobus.net>
parents: 48418
diff changeset
47 /// 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
48 pub fn try_read(
ffd4b1f1c9cb rhg: add sparse support
Raphaël Gomès <rgomes@octobus.net>
parents: 48418
diff changeset
49 &self,
ffd4b1f1c9cb rhg: add sparse support
Raphaël Gomès <rgomes@octobus.net>
parents: 48418
diff changeset
50 relative_path: impl AsRef<Path>,
ffd4b1f1c9cb rhg: add sparse support
Raphaël Gomès <rgomes@octobus.net>
parents: 48418
diff changeset
51 ) -> Result<Option<Vec<u8>>, HgError> {
ffd4b1f1c9cb rhg: add sparse support
Raphaël Gomès <rgomes@octobus.net>
parents: 48418
diff changeset
52 match self.read(relative_path) {
ffd4b1f1c9cb rhg: add sparse support
Raphaël Gomès <rgomes@octobus.net>
parents: 48418
diff changeset
53 Err(e) => match &e {
ffd4b1f1c9cb rhg: add sparse support
Raphaël Gomès <rgomes@octobus.net>
parents: 48418
diff changeset
54 HgError::IoError { error, .. } => match error.kind() {
49914
58074252db3c rust: run `cargo clippy`
Raphaël Gomès <rgomes@octobus.net>
parents: 49485
diff changeset
55 ErrorKind::NotFound => Ok(None),
49485
ffd4b1f1c9cb rhg: add sparse support
Raphaël Gomès <rgomes@octobus.net>
parents: 48418
diff changeset
56 _ => Err(e),
ffd4b1f1c9cb rhg: add sparse support
Raphaël Gomès <rgomes@octobus.net>
parents: 48418
diff changeset
57 },
ffd4b1f1c9cb rhg: add sparse support
Raphaël Gomès <rgomes@octobus.net>
parents: 48418
diff changeset
58 _ => Err(e),
ffd4b1f1c9cb rhg: add sparse support
Raphaël Gomès <rgomes@octobus.net>
parents: 48418
diff changeset
59 },
ffd4b1f1c9cb rhg: add sparse support
Raphaël Gomès <rgomes@octobus.net>
parents: 48418
diff changeset
60 Ok(v) => Ok(Some(v)),
ffd4b1f1c9cb rhg: add sparse support
Raphaël Gomès <rgomes@octobus.net>
parents: 48418
diff changeset
61 }
ffd4b1f1c9cb rhg: add sparse support
Raphaël Gomès <rgomes@octobus.net>
parents: 48418
diff changeset
62 }
ffd4b1f1c9cb rhg: add sparse support
Raphaël Gomès <rgomes@octobus.net>
parents: 48418
diff changeset
63
48199
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
64 fn mmap_open_gen(
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
65 &self,
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
66 relative_path: impl AsRef<Path>,
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
67 ) -> Result<Result<Mmap, FileNotFound>, HgError> {
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
68 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
69 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
70 Err(err) => {
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
71 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
72 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
73 };
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
74 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
75 }
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
76 Ok(file) => file,
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
77 };
51868
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
78 // Safety is "enforced" by locks and assuming other processes are
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
79 // well-behaved. If any misbehaving or malicious process does touch
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
80 // the index, it could lead to corruption. This is inherent
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
81 // to file-based `mmap`, though some platforms have some ways of
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
82 // mitigating.
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
83 // 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
84 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
85 .when_reading_file(&path)?;
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
86 Ok(Ok(mmap))
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
87 }
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
88
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
89 pub fn mmap_open_opt(
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
90 &self,
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
91 relative_path: impl AsRef<Path>,
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
92 ) -> Result<Option<Mmap>, HgError> {
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
93 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
94 }
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
95
47952
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
96 pub fn mmap_open(
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
97 &self,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
98 relative_path: impl AsRef<Path>,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
99 ) -> Result<Mmap, HgError> {
48199
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
100 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
101 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
102 Ok(res) => Ok(res),
9d0e5629cfbf rhg: do not fail when the repo is empty
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47955
diff changeset
103 }
47952
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
104 }
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
105
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
106 pub fn rename(
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
107 &self,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
108 relative_from: impl AsRef<Path>,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
109 relative_to: impl AsRef<Path>,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
110 ) -> Result<(), HgError> {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
111 let from = self.join(relative_from);
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
112 let to = self.join(relative_to);
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
113 std::fs::rename(&from, &to)
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
114 .with_context(|| IoErrorContext::RenamingFile { from, to })
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
115 }
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
116
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
117 pub fn remove_file(
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
118 &self,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
119 relative_path: impl AsRef<Path>,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
120 ) -> Result<(), HgError> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
121 let path = self.join(relative_path);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
122 std::fs::remove_file(&path)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
123 .with_context(|| IoErrorContext::RemovingFile(path))
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
124 }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
125
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
126 #[cfg(unix)]
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
127 pub fn create_symlink(
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
128 &self,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
129 relative_link_path: impl AsRef<Path>,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
130 target_path: impl AsRef<Path>,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
131 ) -> Result<(), HgError> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
132 let link_path = self.join(relative_link_path);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
133 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
134 .when_writing_file(&link_path)
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
135 }
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
136
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
137 /// 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
138 /// 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
139 /// 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
140 /// content, never a partial write.
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
141 pub fn atomic_write(
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
142 &self,
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
143 relative_path: impl AsRef<Path>,
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
144 contents: &[u8],
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
145 ) -> Result<(), HgError> {
51868
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
146 let mut tmp = tempfile::NamedTempFile::new_in(&self.base)
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
147 .when_writing_file(&self.base)?;
48418
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
148 tmp.write_all(contents)
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
149 .and_then(|()| tmp.flush())
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
150 .when_writing_file(tmp.path())?;
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
151 let path = self.join(relative_path);
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
152 tmp.persist(&path)
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
153 .map_err(|e| e.error)
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
154 .when_writing_file(&path)?;
abeae090ce67 rust: Add Vfs::write_atomic
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
155 Ok(())
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48345
diff changeset
156 }
47952
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
157 }
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 fn fs_metadata(
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
160 path: impl AsRef<Path>,
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
161 ) -> Result<Option<std::fs::Metadata>, HgError> {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
162 let path = path.as_ref();
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
163 match std::fs::metadata(path) {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
164 Ok(meta) => Ok(Some(meta)),
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
165 Err(error) => match error.kind() {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
166 // 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
167 // 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
168 // and propagate any other error.
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
169 ErrorKind::PermissionDenied => Err(error).with_context(|| {
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
170 IoErrorContext::ReadingMetadata(path.to_owned())
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
171 }),
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
172 _ => Ok(None),
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
173 },
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
174 }
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
175 }
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
176
51868
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
177 /// Writable file object that atomically updates a file
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
178 ///
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
179 /// All writes will go to a temporary copy of the original file. Call
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
180 /// [`Self::close`] when you are done writing, and [`Self`] will rename
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
181 /// the temporary copy to the original name, making the changes
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
182 /// visible. If the object is destroyed without being closed, all your
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
183 /// writes are discarded.
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
184 pub struct AtomicFile {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
185 /// The temporary file to write to
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
186 fp: std::fs::File,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
187 /// Path of the temp file
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
188 temp_path: PathBuf,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
189 /// Used when stat'ing the file, is useful only if the target file is
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
190 /// guarded by any lock (e.g. repo.lock or repo.wlock).
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
191 check_ambig: bool,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
192 /// Path of the target file
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
193 target_name: PathBuf,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
194 /// Whether the file is open or not
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
195 is_open: bool,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
196 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
197
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
198 impl AtomicFile {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
199 pub fn new(
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
200 fp: std::fs::File,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
201 check_ambig: bool,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
202 temp_name: PathBuf,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
203 target_name: PathBuf,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
204 ) -> Self {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
205 Self {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
206 fp,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
207 check_ambig,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
208 temp_path: temp_name,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
209 target_name,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
210 is_open: true,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
211 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
212 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
213
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
214 /// Write `buf` to the temporary file
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
215 pub fn write_all(&mut self, buf: &[u8]) -> Result<(), std::io::Error> {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
216 self.fp.write_all(buf)
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
217 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
218
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
219 fn target(&self) -> PathBuf {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
220 self.temp_path
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
221 .parent()
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
222 .expect("should not be at the filesystem root")
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
223 .join(&self.target_name)
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
224 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
225
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
226 /// Close the temporary file and rename to the target
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
227 pub fn close(mut self) -> Result<(), std::io::Error> {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
228 self.fp.flush()?;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
229 let target = self.target();
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
230 if self.check_ambig {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
231 if let Ok(stat) = std::fs::metadata(&target) {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
232 std::fs::rename(&self.temp_path, &target)?;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
233 let new_stat = std::fs::metadata(&target)?;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
234 let ctime = new_stat.ctime();
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
235 let is_ambiguous = ctime == stat.ctime();
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
236 if is_ambiguous {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
237 let advanced =
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
238 filetime::FileTime::from_unix_time(ctime + 1, 0);
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
239 filetime::set_file_times(target, advanced, advanced)?;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
240 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
241 } else {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
242 std::fs::rename(&self.temp_path, target)?;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
243 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
244 } else {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
245 std::fs::rename(&self.temp_path, target).unwrap();
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
246 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
247 self.is_open = false;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
248 Ok(())
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
249 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
250 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
251
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
252 impl Drop for AtomicFile {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
253 fn drop(&mut self) {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
254 if self.is_open {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
255 std::fs::remove_file(self.target()).ok();
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
256 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
257 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
258 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
259
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
260 /// Abstracts over the VFS to allow for different implementations of the
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
261 /// filesystem layer (like passing one from Python).
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
262 pub trait Vfs: Sync + Send + DynClone {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
263 fn open(&self, filename: &Path) -> Result<std::fs::File, HgError>;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
264 fn open_read(&self, filename: &Path) -> Result<std::fs::File, HgError>;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
265 fn open_check_ambig(
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
266 &self,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
267 filename: &Path,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
268 ) -> Result<std::fs::File, HgError>;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
269 fn create(&self, filename: &Path) -> Result<std::fs::File, HgError>;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
270 /// Must truncate the new file if exist
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
271 fn create_atomic(
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
272 &self,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
273 filename: &Path,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
274 check_ambig: bool,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
275 ) -> Result<AtomicFile, HgError>;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
276 fn file_size(&self, file: &File) -> Result<u64, HgError>;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
277 fn exists(&self, filename: &Path) -> bool;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
278 fn unlink(&self, filename: &Path) -> Result<(), HgError>;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
279 fn rename(
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
280 &self,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
281 from: &Path,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
282 to: &Path,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
283 check_ambig: bool,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
284 ) -> Result<(), HgError>;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
285 fn copy(&self, from: &Path, to: &Path) -> Result<(), HgError>;
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
286 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
287
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
288 /// These methods will need to be implemented once `rhg` (and other) non-Python
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
289 /// users of `hg-core` start doing more on their own, like writing to files.
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
290 impl Vfs for VfsImpl {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
291 fn open(&self, _filename: &Path) -> Result<std::fs::File, HgError> {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
292 todo!()
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
293 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
294 fn open_read(&self, filename: &Path) -> Result<std::fs::File, HgError> {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
295 let path = self.base.join(filename);
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
296 std::fs::File::open(&path).when_reading_file(&path)
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
297 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
298 fn open_check_ambig(
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
299 &self,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
300 _filename: &Path,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
301 ) -> Result<std::fs::File, HgError> {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
302 todo!()
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
303 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
304 fn create(&self, _filename: &Path) -> Result<std::fs::File, HgError> {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
305 todo!()
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
306 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
307 fn create_atomic(
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
308 &self,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
309 _filename: &Path,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
310 _check_ambig: bool,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
311 ) -> Result<AtomicFile, HgError> {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
312 todo!()
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
313 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
314 fn file_size(&self, file: &File) -> Result<u64, HgError> {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
315 Ok(file
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
316 .metadata()
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
317 .map_err(|e| {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
318 HgError::abort(
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
319 format!("Could not get file metadata: {}", e),
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
320 exit_codes::ABORT,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
321 None,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
322 )
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
323 })?
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
324 .size())
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
325 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
326 fn exists(&self, _filename: &Path) -> bool {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
327 todo!()
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
328 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
329 fn unlink(&self, _filename: &Path) -> Result<(), HgError> {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
330 todo!()
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
331 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
332 fn rename(
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
333 &self,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
334 _from: &Path,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
335 _to: &Path,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
336 _check_ambig: bool,
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
337 ) -> Result<(), HgError> {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
338 todo!()
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
339 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
340 fn copy(&self, _from: &Path, _to: &Path) -> Result<(), HgError> {
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
341 todo!()
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
342 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
343 }
db7dbe6f7bb2 rust: add Vfs trait
Raphaël Gomès <rgomes@octobus.net>
parents: 50274
diff changeset
344
47952
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
345 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
346 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
347 }
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
348
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
349 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
350 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
351 }
50180
be019ac8c1e4 dirstate-v2: don't mmap the data file when on NFS
Raphaël Gomès <rgomes@octobus.net>
parents: 49485
diff changeset
352
be019ac8c1e4 dirstate-v2: don't mmap the data file when on NFS
Raphaël Gomès <rgomes@octobus.net>
parents: 49485
diff changeset
353 /// 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
354 /// 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
355 #[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
356 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
357 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
358 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
359 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
360
be019ac8c1e4 dirstate-v2: don't mmap the data file when on NFS
Raphaël Gomès <rgomes@octobus.net>
parents: 49485
diff changeset
361 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
362 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
363 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
364 };
be019ac8c1e4 dirstate-v2: don't mmap the data file when on NFS
Raphaël Gomès <rgomes@octobus.net>
parents: 49485
diff changeset
365
be019ac8c1e4 dirstate-v2: don't mmap the data file when on NFS
Raphaël Gomès <rgomes@octobus.net>
parents: 49485
diff changeset
366 unsafe {
be019ac8c1e4 dirstate-v2: don't mmap the data file when on NFS
Raphaël Gomès <rgomes@octobus.net>
parents: 49485
diff changeset
367 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
368 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
369
be019ac8c1e4 dirstate-v2: don't mmap the data file when on NFS
Raphaël Gomès <rgomes@octobus.net>
parents: 49485
diff changeset
370 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
371 }
be019ac8c1e4 dirstate-v2: don't mmap the data file when on NFS
Raphaël Gomès <rgomes@octobus.net>
parents: 49485
diff changeset
372 }
50274
0cc19a53cef4 rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 50252
diff changeset
373
0cc19a53cef4 rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 50252
diff changeset
374 /// 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
375 /// 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
376 /// 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
377 /// _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
378 /// all
0cc19a53cef4 rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 50252
diff changeset
379 #[cfg(not(target_os = "linux"))]
0cc19a53cef4 rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 50252
diff changeset
380 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
381 false
0cc19a53cef4 rust: fix building on macOS (issue6801)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 50252
diff changeset
382 }