返回 CodeWhale
file_lock.rs
根目录 / crates / secrets / src / file_lock.rs
1 //! Shared file-store write lock. Native uses the same fd-lock 4.0.4 and
2 //! persistent `<filename>.lock` protocol. Never delete or replace that inode.
3 //! Older writers bypassing this protocol cannot participate safely.
4 use crate::SecretsError;
5 use std::{fs, path::Path};
6
7 pub(crate) fn open_private(path: &Path, create: bool) -> Result<fs::File, SecretsError> {
8 match fs::symlink_metadata(path) {
9 Ok(meta) if meta.file_type().is_symlink() || !meta.is_file() => {
10 return Err(std::io::Error::other("The secret store must be a regular file.").into());
11 }
12 Ok(_) => {}
13 Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}
14 Err(error) => return Err(error.into()),
15 }
16 let mut options = fs::OpenOptions::new();
17 options
18 .read(true)
19 .write(create)
20 .create(create)
21 .truncate(false);
22 #[cfg(unix)]
23 {
24 use std::os::unix::fs::OpenOptionsExt;
25 options.mode(0o600).custom_flags(libc::O_NOFOLLOW);
26 }
27 #[cfg(windows)]
28 {
29 use std::os::windows::fs::OpenOptionsExt;
30 options.custom_flags(0x0020_0000); // FILE_FLAG_OPEN_REPARSE_POINT
31 }
32 let file = options.open(path)?;
33 let meta = file.metadata()?;
34 if !meta.is_file() {
35 return Err(std::io::Error::other("The secret store must be a regular file.").into());
36 }
37 #[cfg(unix)]
38 {
39 use std::os::unix::fs::PermissionsExt;
40 let mode = meta.permissions().mode() & 0o777;
41 if mode & 0o077 != 0 {
42 return Err(SecretsError::InsecurePermissions {
43 path: path.into(),
44 mode,
45 });
46 }
47 }
48 #[cfg(windows)]
49 {
50 use std::os::windows::fs::MetadataExt;
51 if meta.file_attributes() & 0x400 != 0 {
52 return Err(
53 std::io::Error::other("The secret store cannot be a reparse point.").into(),
54 );
55 }
56 }
57 Ok(file)
58 }
59
60 pub(crate) fn with_write_lock<T>(
61 path: &Path,
62 operation: impl FnOnce(&Path) -> Result<T, SecretsError>,
63 ) -> Result<T, SecretsError> {
64 let parent = path
65 .parent()
66 .filter(|p| !p.as_os_str().is_empty())
67 .unwrap_or(Path::new("."));
68 let mut directory = fs::DirBuilder::new();
69 directory.recursive(true);
70 #[cfg(unix)]
71 {
72 use std::os::unix::fs::DirBuilderExt;
73 directory.mode(0o700);
74 }
75 directory.create(parent)?;
76 let filename = path
77 .file_name()
78 .ok_or_else(|| std::io::Error::other("Invalid secret store path."))?;
79 let path = parent.canonicalize()?.join(filename);
80 let mut lock_name = path.as_os_str().to_os_string();
81 lock_name.push(".lock");
82 let mut lock = fd_lock::RwLock::new(open_private(Path::new(&lock_name), true)?);
83 let _guard = lock.write()?;
84 operation(&path)
85 }
86
86 lines RUST