@@ -102,9 +102,7 @@ use crate::core::compiler::CompileTarget;
102
102
use crate :: core:: Workspace ;
103
103
use crate :: util:: paths;
104
104
use crate :: util:: { CargoResult , FileLock } ;
105
- use std:: fs;
106
105
use std:: path:: { Path , PathBuf } ;
107
- use tempfile:: Builder as TempFileBuilder ;
108
106
109
107
/// Contains the paths of all target output locations.
110
108
///
@@ -148,43 +146,12 @@ impl Layout {
148
146
if let Some ( target) = target {
149
147
root. push ( target. short_name ( ) ) ;
150
148
}
151
- // We need root to exist before we do the tempdir/rename dance inside it.
152
- if !root. as_path_unlocked ( ) . exists ( ) {
153
- root. create_dir ( ) ?;
154
- }
155
- let dest_base = dest;
156
149
let dest = root. join ( dest) ;
157
150
// If the root directory doesn't already exist go ahead and create it
158
151
// here. Use this opportunity to exclude it from backups as well if the
159
152
// system supports it since this is a freshly created folder.
160
153
//
161
- // We do this in two steps (first create a temporary directory and exlucde
162
- // it from backups, then rename it to the desired name. If we created the
163
- // directory directly where it should be and then excluded it from backups
164
- // we would risk a situation where cargo is interrupted right after the directory
165
- // creation but before the exclusion the the directory would remain non-excluded from
166
- // backups because we only perform exclusion right after we created the directory
167
- // ourselves.
168
- if !dest. as_path_unlocked ( ) . exists ( ) {
169
- // We need the tempdir created in root instead of $TMP, because only then we can be
170
- // easily sure that rename() will succeed (the new name needs to be on the same mount
171
- // point as the old one).
172
- let tempdir = TempFileBuilder :: new ( )
173
- . prefix ( dest_base)
174
- . tempdir_in ( root. as_path_unlocked ( ) ) ?;
175
- exclude_from_backups ( & tempdir. path ( ) ) ;
176
- // Previously std::fs::create_dir_all() (through paths::create_dir_all()) was used
177
- // here to create the directory directly and fs::create_dir_all() explicitly treats
178
- // the directory being created concurrently by another thread or process as success,
179
- // hence the check below to follow the existing behavior. If we get an error at
180
- // rename() and suddently the directory (which didn't exist a moment earlier) exists
181
- // we can infer from it it's another cargo process doing work.
182
- if let Err ( e) = fs:: rename ( tempdir. path ( ) , dest. as_path_unlocked ( ) ) {
183
- if !dest. as_path_unlocked ( ) . exists ( ) {
184
- return Err ( anyhow:: Error :: from ( e) ) ;
185
- }
186
- }
187
- }
154
+ paths:: create_dir_all_excluded_from_backups_atomic ( dest. as_path_unlocked ( ) ) ?;
188
155
189
156
// For now we don't do any more finer-grained locking on the artifact
190
157
// directory, so just lock the entire thing for the duration of this
@@ -250,48 +217,3 @@ impl Layout {
250
217
& self . build
251
218
}
252
219
}
253
-
254
- /// Marks the directory as excluded from archives/backups.
255
- ///
256
- /// This is recommended to prevent derived/temporary files from bloating backups. There are two
257
- /// mechanisms used to achieve this right now:
258
- ///
259
- /// * A dedicated resource property excluding from Time Machine backups on macOS
260
- /// * CACHEDIR.TAG files supported by various tools in a platform-independent way
261
- fn exclude_from_backups ( path : & Path ) {
262
- exclude_from_time_machine ( path) ;
263
- let _ = std:: fs:: write (
264
- path. join ( "CACHEDIR.TAG" ) ,
265
- "Signature: 8a477f597d28d172789f06886806bc55
266
- # This file is a cache directory tag created by cargo.
267
- # For information about cache directory tags see https://bford.info/cachedir/" ,
268
- ) ;
269
- // Similarly to exclude_from_time_machine() we ignore errors here as it's an optional feature.
270
- }
271
-
272
- #[ cfg( not( target_os = "macos" ) ) ]
273
- fn exclude_from_time_machine ( _: & Path ) { }
274
-
275
- #[ cfg( target_os = "macos" ) ]
276
- /// Marks files or directories as excluded from Time Machine on macOS
277
- fn exclude_from_time_machine ( path : & Path ) {
278
- use core_foundation:: base:: TCFType ;
279
- use core_foundation:: { number, string, url} ;
280
- use std:: ptr;
281
-
282
- // For compatibility with 10.7 a string is used instead of global kCFURLIsExcludedFromBackupKey
283
- let is_excluded_key: Result < string:: CFString , _ > = "NSURLIsExcludedFromBackupKey" . parse ( ) ;
284
- let path = url:: CFURL :: from_path ( path, false ) ;
285
- if let ( Some ( path) , Ok ( is_excluded_key) ) = ( path, is_excluded_key) {
286
- unsafe {
287
- url:: CFURLSetResourcePropertyForKey (
288
- path. as_concrete_TypeRef ( ) ,
289
- is_excluded_key. as_concrete_TypeRef ( ) ,
290
- number:: kCFBooleanTrue as * const _ ,
291
- ptr:: null_mut ( ) ,
292
- ) ;
293
- }
294
- }
295
- // Errors are ignored, since it's an optional feature and failure
296
- // doesn't prevent Cargo from working
297
- }
0 commit comments