@@ -5307,3 +5307,138 @@ mod same_file {
5307
5307
assert_eq ! ( at. read( FILE_NAME ) , CONTENTS , ) ;
5308
5308
}
5309
5309
}
5310
+
5311
+ // the following tests are for how the cp should behave when the source is a symlink
5312
+ // and link option is given
5313
+ #[ cfg( all( unix, not( target_os = "android" ) ) ) ]
5314
+ mod link_deref {
5315
+
5316
+ use crate :: common:: util:: { AtPath , TestScenario } ;
5317
+ use std:: os:: unix:: fs:: MetadataExt ;
5318
+
5319
+ const FILE : & str = "file" ;
5320
+ const FILE_LINK : & str = "file_link" ;
5321
+ const DIR : & str = "dir" ;
5322
+ const DIR_LINK : & str = "dir_link" ;
5323
+ const DANG_LINK : & str = "dang_link" ;
5324
+ const DST : & str = "dst" ;
5325
+
5326
+ fn setup_link_deref_tests ( source : & str , at : & AtPath ) {
5327
+ match source {
5328
+ FILE_LINK => {
5329
+ at. touch ( FILE ) ;
5330
+ at. symlink_file ( FILE , FILE_LINK ) ;
5331
+ }
5332
+ DIR_LINK => {
5333
+ at. mkdir ( DIR ) ;
5334
+ at. symlink_dir ( DIR , DIR_LINK ) ;
5335
+ }
5336
+ DANG_LINK => at. symlink_file ( "nowhere" , DANG_LINK ) ,
5337
+ _ => { }
5338
+ }
5339
+ }
5340
+
5341
+ // cp --link shouldn't deref source if -P is given
5342
+ #[ test]
5343
+ fn test_cp_symlink_as_source_with_link_and_no_deref ( ) {
5344
+ for src in [ FILE_LINK , DIR_LINK , DANG_LINK ] {
5345
+ for r in [ false , true ] {
5346
+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
5347
+ let at = & scene. fixtures ;
5348
+ setup_link_deref_tests ( src, at) ;
5349
+ let mut args = vec ! [ "--link" , "-P" , src, DST ] ;
5350
+ if r {
5351
+ args. push ( "-R" ) ;
5352
+ } ;
5353
+ scene. ucmd ( ) . args ( & args) . succeeds ( ) . no_stderr ( ) ;
5354
+ at. is_symlink ( DST ) ;
5355
+ let src_ino = at. symlink_metadata ( src) . ino ( ) ;
5356
+ let dest_ino = at. symlink_metadata ( DST ) . ino ( ) ;
5357
+ assert_eq ! ( src_ino, dest_ino) ;
5358
+ }
5359
+ }
5360
+ }
5361
+
5362
+ // Dereferencing should fail for dangling symlink.
5363
+ #[ test]
5364
+ fn test_cp_dang_link_as_source_with_link ( ) {
5365
+ for option in [ "" , "-L" , "-H" ] {
5366
+ for r in [ false , true ] {
5367
+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
5368
+ let at = & scene. fixtures ;
5369
+ setup_link_deref_tests ( DANG_LINK , at) ;
5370
+ let mut args = vec ! [ "--link" , DANG_LINK , DST ] ;
5371
+ if r {
5372
+ args. push ( "-R" ) ;
5373
+ } ;
5374
+ if !option. is_empty ( ) {
5375
+ args. push ( option) ;
5376
+ }
5377
+ scene
5378
+ . ucmd ( )
5379
+ . args ( & args)
5380
+ . fails ( )
5381
+ . stderr_contains ( "No such file or directory" ) ;
5382
+ }
5383
+ }
5384
+ }
5385
+
5386
+ // Dereferencing should fail for the 'dir_link' without -R.
5387
+ #[ test]
5388
+ fn test_cp_dir_link_as_source_with_link ( ) {
5389
+ for option in [ "" , "-L" , "-H" ] {
5390
+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
5391
+ let at = & scene. fixtures ;
5392
+ setup_link_deref_tests ( DIR_LINK , at) ;
5393
+ let mut args = vec ! [ "--link" , DIR_LINK , DST ] ;
5394
+ if !option. is_empty ( ) {
5395
+ args. push ( option) ;
5396
+ }
5397
+ scene
5398
+ . ucmd ( )
5399
+ . args ( & args)
5400
+ . fails ( )
5401
+ . stderr_contains ( "cp: -r not specified; omitting directory" ) ;
5402
+ }
5403
+ }
5404
+
5405
+ // cp --link -R 'dir_link' should create a new directory.
5406
+ #[ test]
5407
+ fn test_cp_dir_link_as_source_with_link_and_r ( ) {
5408
+ for option in [ "" , "-L" , "-H" ] {
5409
+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
5410
+ let at = & scene. fixtures ;
5411
+ setup_link_deref_tests ( DIR_LINK , at) ;
5412
+ let mut args = vec ! [ "--link" , "-R" , DIR_LINK , DST ] ;
5413
+ if !option. is_empty ( ) {
5414
+ args. push ( option) ;
5415
+ }
5416
+ scene. ucmd ( ) . args ( & args) . succeeds ( ) ;
5417
+ at. dir_exists ( DST ) ;
5418
+ }
5419
+ }
5420
+
5421
+ //cp --link 'file_link' should create a hard link to the target.
5422
+ #[ test]
5423
+ fn test_cp_file_link_as_source_with_link ( ) {
5424
+ for option in [ "" , "-L" , "-H" ] {
5425
+ for r in [ false , true ] {
5426
+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
5427
+ let at = & scene. fixtures ;
5428
+ setup_link_deref_tests ( FILE_LINK , at) ;
5429
+ let mut args = vec ! [ "--link" , "-R" , FILE_LINK , DST ] ;
5430
+ if !option. is_empty ( ) {
5431
+ args. push ( option) ;
5432
+ }
5433
+ if r {
5434
+ args. push ( "-R" ) ;
5435
+ }
5436
+ scene. ucmd ( ) . args ( & args) . succeeds ( ) ;
5437
+ at. file_exists ( DST ) ;
5438
+ let src_ino = at. symlink_metadata ( FILE ) . ino ( ) ;
5439
+ let dest_ino = at. symlink_metadata ( DST ) . ino ( ) ;
5440
+ assert_eq ! ( src_ino, dest_ino) ;
5441
+ }
5442
+ }
5443
+ }
5444
+ }
0 commit comments