-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy pathdotslash_cache.rs
131 lines (111 loc) · 3.95 KB
/
dotslash_cache.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under both the MIT license found in the
* LICENSE-MIT file in the root directory of this source tree and the Apache
* License, Version 2.0 found in the LICENSE-APACHE file in the root directory
* of this source tree.
*/
use std::env;
use std::ffi::OsString;
use std::path::Path;
use std::path::PathBuf;
#[cfg(unix)]
use nix::unistd;
#[cfg(unix)]
use crate::util;
pub const DOTSLASH_CACHE_ENV: &str = "DOTSLASH_CACHE";
#[derive(Debug)]
pub struct DotslashCache {
cache_dir: PathBuf,
}
/// The DotSlash cache is organized as follows:
/// - Any subfolder that starts with two lowercase hex digits is the parent
/// folder for artifacts whose *artifact hash* starts with those two hex
/// digits (see `ArtifactLocation::artifact_directory`).
/// - The only other subfolder is `locks/`, which internally is organized
/// to the root of the cache folder.
///
/// The motivation behind this organization is to keep the paths to artifacts
/// as short as reasonably possible to avoid exceeding `MAX_PATH` on Windows.
/// The `locks/` folder is kept separate so it can be blown away independent of
/// the artifacts.
impl DotslashCache {
pub fn new() -> Self {
Self::new_in(get_dotslash_cache())
}
pub fn new_in<P: Into<PathBuf>>(p: P) -> Self {
Self {
cache_dir: p.into(),
}
}
pub fn cache_dir(&self) -> &Path {
&self.cache_dir
}
pub fn artifacts_dir(&self) -> &Path {
&self.cache_dir
}
/// artifact_hash_prefix should be two lowercase hex digits.
pub fn locks_dir(&self, artifact_hash_prefix: &str) -> PathBuf {
self.cache_dir.join("locks").join(artifact_hash_prefix)
}
}
impl Default for DotslashCache {
fn default() -> Self {
Self::new()
}
}
/// Return the directory where DotSlash should write its cached artifacts.
/// Although DotSlash does not currently have any global config files,
/// if it did, most platforms would prefer config files to be stored in
/// a separate directory that is backed up and should not be blown away
/// when the user is low on space like /tmp.
fn get_dotslash_cache() -> PathBuf {
if let Some(val) = env::var_os(DOTSLASH_CACHE_ENV) {
return PathBuf::from(val);
}
// `dirs` returns the preferred cache directory for the user and the
// platform based on these rules: https://docs.rs/dirs/*/dirs/fn.cache_dir.html
let cache_dir = match dirs::cache_dir() {
Some(cache_dir) => cache_dir.join("dotslash"),
None => panic!("could not find DotSlash root - specify $DOTSLASH_CACHE"),
};
// `dirs` relies on `$HOME`. When running under `sudo` `$HOME` may not be
// the sudoer's home dir. We want to avoid the situation where some
// privileged user (like `root`) owns the cache dir in some other user's
// home dir.
//
// Note that on a devserver (and macOS is basically the same):
//
// ```
// $ bash -c 'echo $SUDO_USER $USER $HOME'
// asuarez asuarez /home/asuarez
// $ sudo bash -c 'echo $SUDO_USER $USER $HOME'
// asuarez root /home/asuarez
// $ sudo -H bash -c 'echo $SUDO_USER $USER $HOME'
// asuarez root /root
// ```
//
// i.e., `$USER` is reliable in the presence of sudo but `$HOME` is not.
#[cfg(unix)]
if !util::is_path_safe_to_own(&cache_dir) {
let temp_dir = env::temp_dir();
// e.g. $TEMP/dotslash-UID
return named_cache_dir_at(temp_dir);
}
cache_dir
}
#[cfg_attr(windows, expect(dead_code))]
fn named_cache_dir_at<P: Into<PathBuf>>(dir: P) -> PathBuf {
let mut name = OsString::from("dotslash-");
// e.g. dotslash-UID
#[cfg(unix)]
name.push(unistd::getuid().as_raw().to_string());
// e.g. dotslash-$USERNAME
#[cfg(windows)]
name.push(env::var_os("USERNAME").unwrap_or_else(|| "".into()));
// e.g. $DIR/dotslash-UID
let mut dir = dir.into();
dir.push(name);
dir
}