gitlab.com/apertussolutions/u-root@v7.0.0+incompatible/cmds/core/scp/scp.go (about) 1 // Copyright 2012-2018 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Scp copies files between hosts on a network. 6 // 7 // Synopsis: 8 // scp [-t|-f] [FILE] 9 // 10 // Description: 11 // If -t is given, decode SCP protocol from stdin and write to FILE. 12 // If -f is given, stream FILE over SCP protocol to stdout. 13 // 14 // Options: 15 // -t: Act as the target 16 // -f: Act as the source 17 // -v: Passed if SCP is verbose, ignored 18 package main 19 20 import ( 21 "flag" 22 "fmt" 23 "io" 24 "log" 25 "os" 26 "path" 27 ) 28 29 const ( 30 SUCCESS = 0 31 ) 32 33 var ( 34 isTarget = flag.Bool("t", false, "Act as the target") 35 isSource = flag.Bool("f", false, "Act as the source") 36 _ = flag.Bool("v", false, "Ignored") 37 ) 38 39 func scpSingleSource(w io.Writer, r io.Reader, pth string) error { 40 f, err := os.Open(pth) 41 if err != nil { 42 return err 43 } 44 defer f.Close() 45 s, err := f.Stat() 46 if err != nil { 47 return err 48 } 49 filename := path.Base(pth) 50 w.Write([]byte(fmt.Sprintf("C0%o %d %s\n", s.Mode(), s.Size(), filename))) 51 if response(r) != SUCCESS { 52 return fmt.Errorf("response was not success") 53 } 54 _, err = io.Copy(w, f) 55 if err != nil { 56 return fmt.Errorf("copy error: %v", err) 57 } 58 reply(w, SUCCESS) 59 60 if response(r) != SUCCESS { 61 return fmt.Errorf("response was not success") 62 } 63 return nil 64 } 65 66 func scpSingleSink(w io.Writer, r io.Reader, path string) error { 67 var mode os.FileMode 68 var size int64 69 filename := "" 70 71 // Ignore the filename, assume it has been provided on the command line. 72 // This will not work with directories and recursive copy, but that's not 73 // supported right now. 74 if _, err := fmt.Fscanf(r, "C0%o %d %s\n", &mode, &size, &filename); err != nil { 75 if err == io.ErrUnexpectedEOF { 76 return io.EOF 77 } 78 return fmt.Errorf("fscanf: %v", err) 79 } 80 f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, mode) 81 if err != nil { 82 return fmt.Errorf("open error: %v", err) 83 } 84 reply(w, SUCCESS) 85 defer f.Close() 86 87 _, err = io.CopyN(f, r, size) 88 if err != nil { 89 return fmt.Errorf("copy error: %v", err) 90 } 91 if response(r) != SUCCESS { 92 return fmt.Errorf("response was not success") 93 } 94 reply(w, SUCCESS) 95 return nil 96 } 97 98 func scpSource(w io.Writer, r io.Reader, path string) error { 99 // Sink->Source is started with a response 100 if response(r) != SUCCESS { 101 return fmt.Errorf("response was not success") 102 } 103 return scpSingleSource(w, r, path) 104 } 105 106 func scpSink(w io.Writer, r io.Reader, path string) error { 107 reply(w, SUCCESS) 108 for { 109 if err := scpSingleSink(w, r, path); err != nil { 110 if err == io.EOF { 111 break 112 } 113 return err 114 } 115 } 116 return nil 117 } 118 119 func reply(out io.Writer, r byte) { 120 out.Write([]byte{r}) 121 } 122 123 func response(in io.Reader) byte { 124 b := make([]byte, 1) 125 in.Read(b) 126 return b[0] 127 } 128 129 func main() { 130 flag.Parse() 131 132 if flag.NArg() == 0 { 133 log.Fatalf("no file provided") 134 } 135 136 if *isSource == *isTarget { 137 log.Fatalf("-t or -f needs to be supplied, and not both") 138 } 139 140 if *isSource { 141 if err := scpSource(os.Stdout, os.Stdin, flag.Args()[0]); err != nil { 142 log.Fatalf("scp: %v", err) 143 } 144 } else if *isTarget { 145 if err := scpSink(os.Stdout, os.Stdin, flag.Args()[0]); err != nil { 146 log.Fatalf("scp: %v", err) 147 } 148 } 149 }