1
1
use std:: {
2
2
borrow:: Cow ,
3
- fs:: OpenOptions ,
3
+ fs:: { OpenOptions , Permissions } ,
4
4
io:: Write ,
5
5
path:: { Path , PathBuf } ,
6
6
} ;
@@ -286,9 +286,10 @@ pub(crate) fn finalize_entry(
286
286
// For possibly existing, overwritten files, we must change the file mode explicitly.
287
287
#[ cfg( unix) ]
288
288
if let Some ( path) = set_executable_after_creation {
289
- let mut perm = std:: fs:: symlink_metadata ( path) ?. permissions ( ) ;
290
- set_mode_executable ( & mut perm) ;
291
- std:: fs:: set_permissions ( path, perm) ?;
289
+ let old_perm = std:: fs:: symlink_metadata ( path) ?. permissions ( ) ;
290
+ if let Some ( new_perm) = set_mode_executable ( old_perm) {
291
+ std:: fs:: set_permissions ( path, new_perm) ?;
292
+ }
292
293
}
293
294
// NOTE: we don't call `file.sync_all()` here knowing that some filesystems don't handle this well.
294
295
// revisit this once there is a bug to fix.
@@ -298,73 +299,100 @@ pub(crate) fn finalize_entry(
298
299
}
299
300
300
301
#[ cfg( unix) ]
301
- fn set_mode_executable ( perm : & mut std :: fs :: Permissions ) {
302
+ fn set_mode_executable ( mut perm : Permissions ) -> Option < Permissions > {
302
303
use std:: os:: unix:: fs:: PermissionsExt ;
303
304
let mut mode = perm. mode ( ) ;
305
+ if mode & 0o170000 != 0o100000 {
306
+ return None ; // Stop if we don't have a regular file anymore.
307
+ }
304
308
mode &= 0o777 ; // Clear non-rwx bits (setuid, setgid, sticky).
305
309
mode |= ( mode & 0o444 ) >> 2 ; // Let readers also execute.
306
310
perm. set_mode ( mode) ;
311
+ Some ( perm)
307
312
}
308
313
309
- #[ cfg( test) ]
314
+ #[ cfg( all ( test, unix ) ) ]
310
315
mod tests {
316
+ fn pretty ( maybe_mode : Option < u32 > ) -> String {
317
+ match maybe_mode {
318
+ Some ( mode) => format ! ( "Some({mode:04o})" ) ,
319
+ None => "None" . into ( ) ,
320
+ }
321
+ }
322
+
311
323
#[ test]
312
- #[ cfg( unix) ]
313
324
fn set_mode_executable ( ) {
314
325
let cases = [
315
- // Common cases.
316
- ( 0o100755 , 0o755 ) ,
317
- ( 0o100644 , 0o755 ) ,
318
- ( 0o100750 , 0o750 ) ,
319
- ( 0o100640 , 0o750 ) ,
320
- ( 0o100700 , 0o700 ) ,
321
- ( 0o100600 , 0o700 ) ,
322
- ( 0o100775 , 0o775 ) ,
323
- ( 0o100664 , 0o775 ) ,
324
- ( 0o100770 , 0o770 ) ,
325
- ( 0o100660 , 0o770 ) ,
326
- ( 0o100764 , 0o775 ) ,
327
- ( 0o100760 , 0o770 ) ,
328
- // Some less common cases.
329
- ( 0o100674 , 0o775 ) ,
330
- ( 0o100670 , 0o770 ) ,
331
- ( 0o100000 , 0o000 ) ,
332
- ( 0o100400 , 0o500 ) ,
333
- ( 0o100440 , 0o550 ) ,
334
- ( 0o100444 , 0o555 ) ,
335
- ( 0o100462 , 0o572 ) ,
336
- ( 0o100242 , 0o252 ) ,
337
- ( 0o100167 , 0o177 ) ,
338
- // Some cases with set-user-ID, set-group-ID, and sticky bits.
339
- ( 0o104755 , 0o755 ) ,
340
- ( 0o104644 , 0o755 ) ,
341
- ( 0o102755 , 0o755 ) ,
342
- ( 0o102644 , 0o755 ) ,
343
- ( 0o101755 , 0o755 ) ,
344
- ( 0o101644 , 0o755 ) ,
345
- ( 0o106755 , 0o755 ) ,
346
- ( 0o106644 , 0o755 ) ,
347
- ( 0o104750 , 0o750 ) ,
348
- ( 0o104640 , 0o750 ) ,
349
- ( 0o102750 , 0o750 ) ,
350
- ( 0o102640 , 0o750 ) ,
351
- ( 0o101750 , 0o750 ) ,
352
- ( 0o101640 , 0o750 ) ,
353
- ( 0o106750 , 0o750 ) ,
354
- ( 0o106640 , 0o750 ) ,
355
- ( 0o107644 , 0o755 ) ,
356
- ( 0o107000 , 0o000 ) ,
357
- ( 0o106400 , 0o500 ) ,
358
- ( 0o102462 , 0o572 ) ,
326
+ // Common cases:
327
+ ( 0o100755 , Some ( 0o755 ) ) ,
328
+ ( 0o100644 , Some ( 0o755 ) ) ,
329
+ ( 0o100750 , Some ( 0o750 ) ) ,
330
+ ( 0o100640 , Some ( 0o750 ) ) ,
331
+ ( 0o100700 , Some ( 0o700 ) ) ,
332
+ ( 0o100600 , Some ( 0o700 ) ) ,
333
+ ( 0o100775 , Some ( 0o775 ) ) ,
334
+ ( 0o100664 , Some ( 0o775 ) ) ,
335
+ ( 0o100770 , Some ( 0o770 ) ) ,
336
+ ( 0o100660 , Some ( 0o770 ) ) ,
337
+ ( 0o100764 , Some ( 0o775 ) ) ,
338
+ ( 0o100760 , Some ( 0o770 ) ) ,
339
+ // Less common:
340
+ ( 0o100674 , Some ( 0o775 ) ) ,
341
+ ( 0o100670 , Some ( 0o770 ) ) ,
342
+ ( 0o100000 , Some ( 0o000 ) ) ,
343
+ ( 0o100400 , Some ( 0o500 ) ) ,
344
+ ( 0o100440 , Some ( 0o550 ) ) ,
345
+ ( 0o100444 , Some ( 0o555 ) ) ,
346
+ ( 0o100462 , Some ( 0o572 ) ) ,
347
+ ( 0o100242 , Some ( 0o252 ) ) ,
348
+ ( 0o100167 , Some ( 0o177 ) ) ,
349
+ // With set-user-ID, set-group-ID, and sticky bits:
350
+ ( 0o104755 , Some ( 0o755 ) ) ,
351
+ ( 0o104644 , Some ( 0o755 ) ) ,
352
+ ( 0o102755 , Some ( 0o755 ) ) ,
353
+ ( 0o102644 , Some ( 0o755 ) ) ,
354
+ ( 0o101755 , Some ( 0o755 ) ) ,
355
+ ( 0o101644 , Some ( 0o755 ) ) ,
356
+ ( 0o106755 , Some ( 0o755 ) ) ,
357
+ ( 0o106644 , Some ( 0o755 ) ) ,
358
+ ( 0o104750 , Some ( 0o750 ) ) ,
359
+ ( 0o104640 , Some ( 0o750 ) ) ,
360
+ ( 0o102750 , Some ( 0o750 ) ) ,
361
+ ( 0o102640 , Some ( 0o750 ) ) ,
362
+ ( 0o101750 , Some ( 0o750 ) ) ,
363
+ ( 0o101640 , Some ( 0o750 ) ) ,
364
+ ( 0o106750 , Some ( 0o750 ) ) ,
365
+ ( 0o106640 , Some ( 0o750 ) ) ,
366
+ ( 0o107644 , Some ( 0o755 ) ) ,
367
+ ( 0o107000 , Some ( 0o000 ) ) ,
368
+ ( 0o106400 , Some ( 0o500 ) ) ,
369
+ ( 0o102462 , Some ( 0o572 ) ) ,
370
+ // Where it was replaced with a directory due to a race:
371
+ ( 0o040755 , None ) ,
372
+ ( 0o040644 , None ) ,
373
+ ( 0o040600 , None ) ,
374
+ ( 0o041755 , None ) ,
375
+ ( 0o041644 , None ) ,
376
+ ( 0o046644 , None ) ,
377
+ // Where it was replaced with a symlink due to a race:
378
+ ( 0o120777 , None ) ,
379
+ ( 0o120644 , None ) ,
380
+ // Where it was replaced with some other non-regular file due to a race:
381
+ ( 0o140644 , None ) ,
382
+ ( 0o060644 , None ) ,
383
+ ( 0o020644 , None ) ,
384
+ ( 0o010644 , None ) ,
359
385
] ;
360
- for ( old , expected) in cases {
386
+ for ( old_mode , expected) in cases {
361
387
use std:: os:: unix:: fs:: PermissionsExt ;
362
- let mut perm = std:: fs:: Permissions :: from_mode ( old) ;
363
- super :: set_mode_executable ( & mut perm) ;
364
- let actual = perm. mode ( ) ;
388
+ let old_perm = std:: fs:: Permissions :: from_mode ( old_mode) ;
389
+ let actual = super :: set_mode_executable ( old_perm) . map ( |perm| perm. mode ( ) ) ;
365
390
assert_eq ! (
366
- actual, expected,
367
- "{old:06o} should become {expected:04o} but became {actual:04o}"
391
+ actual,
392
+ expected,
393
+ "{old_mode:06o} should become {}, became {}" ,
394
+ pretty( expected) ,
395
+ pretty( actual)
368
396
) ;
369
397
}
370
398
}
0 commit comments