annotate rust/hg-core/src/vfs.rs @ 51864:db7dbe6f7bb2

rust: add Vfs trait This will allow for the use of multiple vfs like in the Python implementation, as well as hiding the details of the upcoming Python vfs wrapper to hg-core.
author Rapha?l Gom?s <rgomes@octobus.net>
date Wed, 19 Jun 2024 14:49:35 +0200
parents 0cc19a53cef4
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};
51864
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};
51864
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};
51864
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
51864
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
51864
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 };
51864
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> {
51864
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
51864
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 }