1
- use std:: borrow:: Cow ;
2
1
use std:: {
2
+ borrow:: Cow ,
3
3
fs:: OpenOptions ,
4
4
io:: Write ,
5
5
path:: { Path , PathBuf } ,
@@ -286,12 +286,8 @@ 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
- use std:: os:: unix:: fs:: PermissionsExt ;
290
289
let mut perm = std:: fs:: symlink_metadata ( path) ?. permissions ( ) ;
291
- let mut mode = perm. mode ( ) ;
292
- mode &= 0o777 ; // Clear non-rwx bits (setuid, setgid, sticky).
293
- mode |= ( mode & 0o444 ) >> 2 ; // Let readers also execute.
294
- perm. set_mode ( mode) ;
290
+ set_mode_executable ( & mut perm) ;
295
291
std:: fs:: set_permissions ( path, perm) ?;
296
292
}
297
293
// NOTE: we don't call `file.sync_all()` here knowing that some filesystems don't handle this well.
@@ -300,3 +296,76 @@ pub(crate) fn finalize_entry(
300
296
file. close ( ) ?;
301
297
Ok ( ( ) )
302
298
}
299
+
300
+ #[ cfg( unix) ]
301
+ fn set_mode_executable ( perm : & mut std:: fs:: Permissions ) {
302
+ use std:: os:: unix:: fs:: PermissionsExt ;
303
+ let mut mode = perm. mode ( ) ;
304
+ mode &= 0o777 ; // Clear non-rwx bits (setuid, setgid, sticky).
305
+ mode |= ( mode & 0o444 ) >> 2 ; // Let readers also execute.
306
+ perm. set_mode ( mode) ;
307
+ }
308
+
309
+ #[ cfg( test) ]
310
+ mod tests {
311
+ #[ test]
312
+ #[ cfg( unix) ]
313
+ fn set_mode_executable ( ) {
314
+ 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 ) ,
359
+ ] ;
360
+ for ( old, expected) in cases {
361
+ 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 ( ) ;
365
+ assert_eq ! (
366
+ actual, expected,
367
+ "{old:06o} should become {expected:04o} but became {actual:04o}"
368
+ ) ;
369
+ }
370
+ }
371
+ }
0 commit comments