@@ -521,7 +521,9 @@ func (c *cmdFilePull) Run(cmd *cobra.Command, args []string) error {
521
521
target := filepath .Clean (args [len (args )- 1 ])
522
522
523
523
targetIsDir := false
524
- sb , err := os .Stat (target )
524
+ targetIsLink := false
525
+
526
+ targetInfo , err := os .Stat (target )
525
527
if err != nil && ! errors .Is (err , fs .ErrNotExist ) {
526
528
return err
527
529
}
@@ -535,7 +537,7 @@ func (c *cmdFilePull) Run(cmd *cobra.Command, args []string) error {
535
537
* 3. We are dealing with recursive copy
536
538
*/
537
539
if err == nil {
538
- targetIsDir = sb .IsDir ()
540
+ targetIsDir = targetInfo .IsDir ()
539
541
if ! targetIsDir && len (args )- 1 > 1 {
540
542
return fmt .Errorf (i18n .G ("More than one file to download, but target is not a directory" ))
541
543
}
@@ -559,19 +561,46 @@ func (c *cmdFilePull) Run(cmd *cobra.Command, args []string) error {
559
561
return err
560
562
}
561
563
564
+ sftpClients := map [string ]* sftp.Client {}
565
+
566
+ defer func () {
567
+ for _ , sftpClient := range sftpClients {
568
+ _ = sftpClient .Close ()
569
+ }
570
+ }()
571
+
562
572
for _ , resource := range resources {
563
573
pathSpec := strings .SplitN (resource .name , "/" , 2 )
564
574
if len (pathSpec ) != 2 {
565
575
return fmt .Errorf (i18n .G ("Invalid source %s" ), resource .name )
566
576
}
567
577
568
- buf , resp , err := fileGetWrapper (resource .server , pathSpec [0 ], pathSpec [1 ])
578
+ sftpConn , ok := sftpClients [pathSpec [0 ]]
579
+ if ! ok {
580
+ sftpConn , err = resource .server .GetInstanceFileSFTP (pathSpec [0 ])
581
+ if err != nil {
582
+ return err
583
+ }
584
+
585
+ sftpClients [pathSpec [0 ]] = sftpConn
586
+ }
587
+
588
+ src , err := sftpConn .Open (pathSpec [1 ])
569
589
if err != nil {
570
590
return err
571
591
}
572
592
593
+ srcInfo , err := sftpConn .Lstat (pathSpec [1 ])
594
+ if err != nil {
595
+ return err
596
+ }
597
+
598
+ if srcInfo .Mode ()& os .ModeSymlink == os .ModeSymlink {
599
+ targetIsLink = true
600
+ }
601
+
573
602
// Deal with recursion
574
- if resp . Type == "directory" {
603
+ if srcInfo . IsDir () {
575
604
if c .file .flagRecursive {
576
605
if ! util .PathExists (target ) {
577
606
err := os .MkdirAll (target , DirMode )
@@ -600,56 +629,16 @@ func (c *cmdFilePull) Run(cmd *cobra.Command, args []string) error {
600
629
targetPath = target
601
630
}
602
631
603
- logger .Infof ("Pulling %s from %s (%s)" , targetPath , pathSpec [1 ], resp .Type )
632
+ var f * os.File
633
+ var linkName string
604
634
605
- if resp .Type == "symlink" {
606
- linkTarget , err := io .ReadAll (buf )
635
+ if targetPath == "-" {
636
+ f = os .Stdout
637
+ } else if targetIsLink {
638
+ linkName , err = sftpConn .ReadLink (pathSpec [1 ])
607
639
if err != nil {
608
640
return err
609
641
}
610
-
611
- // Follow the symlink
612
- if targetPath == "-" || c .file .flagRecursive {
613
- i := 0
614
- for {
615
- newPath := strings .TrimSuffix (string (linkTarget ), "\n " )
616
- if ! strings .HasPrefix (newPath , "/" ) {
617
- newPath = filepath .Clean (filepath .Join (filepath .Dir (pathSpec [1 ]), newPath ))
618
- }
619
-
620
- buf , resp , err = resource .server .GetInstanceFile (pathSpec [0 ], newPath )
621
- if err != nil {
622
- return err
623
- }
624
-
625
- if resp .Type != "symlink" {
626
- break
627
- }
628
-
629
- i ++
630
- if i > 255 {
631
- return fmt .Errorf (i18n .G ("Too many links" ))
632
- }
633
-
634
- // Update link target for next iteration.
635
- linkTarget , err = io .ReadAll (buf )
636
- if err != nil {
637
- return err
638
- }
639
- }
640
- } else {
641
- err = os .Symlink (strings .TrimSpace (string (linkTarget )), targetPath )
642
- if err != nil {
643
- return err
644
- }
645
-
646
- continue
647
- }
648
- }
649
-
650
- var f * os.File
651
- if targetPath == "-" {
652
- f = os .Stdout
653
642
} else {
654
643
f , err = os .Create (targetPath )
655
644
if err != nil {
@@ -658,7 +647,7 @@ func (c *cmdFilePull) Run(cmd *cobra.Command, args []string) error {
658
647
659
648
defer func () { _ = f .Close () }()
660
649
661
- err = os .Chmod (targetPath , os .FileMode (resp .Mode ))
650
+ err = os .Chmod (targetPath , os .FileMode (srcInfo .Mode () ))
662
651
if err != nil {
663
652
return err
664
653
}
@@ -685,16 +674,18 @@ func (c *cmdFilePull) Run(cmd *cobra.Command, args []string) error {
685
674
},
686
675
}
687
676
688
- _ , err = io .Copy (writer , buf )
689
- if err != nil {
690
- progress .Done ("" )
691
- return err
692
- }
693
-
694
- err = f .Close ()
695
- if err != nil {
696
- progress .Done ("" )
697
- return err
677
+ if targetIsLink {
678
+ err = os .Symlink (linkName , srcInfo .Name ())
679
+ if err != nil {
680
+ progress .Done ("" )
681
+ return err
682
+ }
683
+ } else {
684
+ _ , err = io .Copy (writer , src )
685
+ if err != nil {
686
+ progress .Done ("" )
687
+ return err
688
+ }
698
689
}
699
690
700
691
progress .Done ("" )
0 commit comments