@@ -5245,3 +5245,138 @@ mod same_file {
5245
5245
assert_eq ! ( at. read( FILE_NAME ) , CONTENTS , ) ;
5246
5246
}
5247
5247
}
5248
+
5249
+ // the following tests are for how the cp should behave when the source is a symlink
5250
+ // and link option is given
5251
+ #[ cfg( unix) ]
5252
+ mod link_deref {
5253
+
5254
+ use crate :: common:: util:: { AtPath , TestScenario } ;
5255
+ use std:: os:: unix:: fs:: MetadataExt ;
5256
+
5257
+ const FILE : & str = "file" ;
5258
+ const FILE_LINK : & str = "file_link" ;
5259
+ const DIR : & str = "dir" ;
5260
+ const DIR_LINK : & str = "dir_link" ;
5261
+ const DANG_LINK : & str = "dang_link" ;
5262
+ const DST : & str = "dst" ;
5263
+
5264
+ fn setup_link_deref_tests ( source : & str , at : & AtPath ) {
5265
+ match source {
5266
+ FILE_LINK => {
5267
+ at. touch ( FILE ) ;
5268
+ at. symlink_file ( FILE , FILE_LINK )
5269
+ }
5270
+ DIR_LINK => {
5271
+ at. mkdir ( DIR ) ;
5272
+ at. symlink_dir ( DIR , DIR_LINK )
5273
+ }
5274
+ DANG_LINK => at. symlink_file ( "nowhere" , DANG_LINK ) ,
5275
+ _ => todo ! ( ) ,
5276
+ }
5277
+ }
5278
+
5279
+ // cp --link shouldn't deref source if -P is given
5280
+ #[ test]
5281
+ fn test_cp_symlink_as_source_with_link_and_no_deref ( ) {
5282
+ for src in [ FILE_LINK , DIR_LINK , DANG_LINK ] {
5283
+ for r in [ false , true ] {
5284
+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
5285
+ let at = & scene. fixtures ;
5286
+ setup_link_deref_tests ( src, at) ;
5287
+ let mut args = vec ! [ "--link" , "-P" , src, DST ] ;
5288
+ if r {
5289
+ args. push ( "-R" )
5290
+ } ;
5291
+ scene. ucmd ( ) . args ( & args) . succeeds ( ) . no_stderr ( ) ;
5292
+ at. is_symlink ( DST ) ;
5293
+ let src_ino = at. symlink_metadata ( src) . ino ( ) ;
5294
+ let dest_ino = at. symlink_metadata ( DST ) . ino ( ) ;
5295
+ assert_eq ! ( src_ino, dest_ino, ) ;
5296
+ }
5297
+ }
5298
+ }
5299
+
5300
+ // Dereferencing should fail for dangling symlink.
5301
+ #[ test]
5302
+ fn test_cp_dang_link_as_source_with_link ( ) {
5303
+ for option in [ "" , "-L" , "-H" ] {
5304
+ for r in [ false , true ] {
5305
+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
5306
+ let at = & scene. fixtures ;
5307
+ setup_link_deref_tests ( DANG_LINK , at) ;
5308
+ let mut args = vec ! [ "--link" , DANG_LINK , DST ] ;
5309
+ if r {
5310
+ args. push ( "-R" )
5311
+ } ;
5312
+ if !option. is_empty ( ) {
5313
+ args. push ( & option)
5314
+ }
5315
+ scene
5316
+ . ucmd ( )
5317
+ . args ( & args)
5318
+ . fails ( )
5319
+ . stderr_contains ( "No such file or directory" ) ;
5320
+ }
5321
+ }
5322
+ }
5323
+
5324
+ // Dereferencing should fail for the 'dir_link' without -R.
5325
+ #[ test]
5326
+ fn test_cp_dir_link_as_source_with_link ( ) {
5327
+ for option in [ "" , "-L" , "-H" ] {
5328
+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
5329
+ let at = & scene. fixtures ;
5330
+ setup_link_deref_tests ( DIR_LINK , at) ;
5331
+ let mut args = vec ! [ "--link" , DIR_LINK , DST ] ;
5332
+ if !option. is_empty ( ) {
5333
+ args. push ( & option)
5334
+ }
5335
+ scene
5336
+ . ucmd ( )
5337
+ . args ( & args)
5338
+ . fails ( )
5339
+ . stderr_contains ( "cp: -r not specified; omitting directory" ) ;
5340
+ }
5341
+ }
5342
+
5343
+ // cp --link -R 'dir_link' should create a new directory.
5344
+ #[ test]
5345
+ fn test_cp_dir_link_as_source_with_link_and_r ( ) {
5346
+ for option in [ "" , "-L" , "-H" ] {
5347
+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
5348
+ let at = & scene. fixtures ;
5349
+ setup_link_deref_tests ( DIR_LINK , at) ;
5350
+ let mut args = vec ! [ "--link" , "-R" , DIR_LINK , DST ] ;
5351
+ if !option. is_empty ( ) {
5352
+ args. push ( & option)
5353
+ }
5354
+ scene. ucmd ( ) . args ( & args) . succeeds ( ) ;
5355
+ at. dir_exists ( DST ) ;
5356
+ }
5357
+ }
5358
+
5359
+ //cp --link 'file_link' should create a hard link to the target.
5360
+ #[ test]
5361
+ fn test_cp_file_link_as_source_with_link ( ) {
5362
+ for option in [ "" , "-L" , "-H" ] {
5363
+ for r in [ false , true ] {
5364
+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
5365
+ let at = & scene. fixtures ;
5366
+ setup_link_deref_tests ( FILE_LINK , at) ;
5367
+ let mut args = vec ! [ "--link" , "-R" , FILE_LINK , DST ] ;
5368
+ if !option. is_empty ( ) {
5369
+ args. push ( & option)
5370
+ }
5371
+ if r {
5372
+ args. push ( "-R" )
5373
+ }
5374
+ scene. ucmd ( ) . args ( & args) . succeeds ( ) ;
5375
+ at. file_exists ( DST ) ;
5376
+ let src_ino = at. symlink_metadata ( FILE ) . ino ( ) ;
5377
+ let dest_ino = at. symlink_metadata ( DST ) . ino ( ) ;
5378
+ assert_eq ! ( src_ino, dest_ino)
5379
+ }
5380
+ }
5381
+ }
5382
+ }
0 commit comments