@@ -39,13 +39,8 @@ type remoteProc struct {
3939 cmd * exec.Cmd
4040}
4141
42- type targetFile interface {
43- io.ReadWriteSeeker
44- io.Closer
45- }
46-
4742func usage () {
48- fmt .Fprintf (os .Stderr , "Usage: %s [--ssh-flags=\" ...\" ] [--no-compress] [--verbose] <src> <dst>\n src and dst is [[user@]host:]path\n " , os .Args [0 ])
43+ _ , _ = fmt .Fprintf (os .Stderr , "Usage: %s [--ssh-flags=\" ...\" ] [--no-compress] [--verbose] <src> <dst>\n src and dst is [[user@]host:]path\n " , os .Args [0 ])
4944 os .Exit (2 )
5045}
5146
@@ -118,41 +113,51 @@ func (p *localProc) Start(cmdReader io.Reader, cmdWriter io.WriteCloser, errChan
118113}
119114
120115func (p * localProc ) run (cmdReader io.Reader , cmdWriter io.WriteCloser , errChan chan error ) {
116+ var err error
121117 if p .mode == modeSource {
122- errChan <- doSource (p .p , cmdReader , cmdWriter , p .opts )
118+ err = doSource (p .p , cmdReader , cmdWriter , p .opts )
123119 } else {
124- errChan <- doTarget (p .p , cmdReader , cmdWriter , p .opts )
120+ err = doTarget (p .p , cmdReader , cmdWriter , p .opts )
121+ }
122+
123+ cerr := cmdWriter .Close ()
124+ if err == nil {
125+ err = cerr
125126 }
127+ errChan <- err
128+ }
126129
127- cmdWriter .Close ()
130+ func (p * remoteProc ) pipeCopy (dst io.WriteCloser , src io.Reader ) {
131+ _ , err := io .Copy (dst , src )
132+ if err != nil {
133+ log .Printf ("pipe copy failed: %v" , err )
134+ }
135+ err = dst .Close ()
136+ if err != nil {
137+ log .Printf ("close failed after pipe copy: %v" , err )
138+ }
128139}
129140
130141func (p * remoteProc ) Start (cmdReader io.Reader , cmdWriter io.WriteCloser , errChan chan error ) error {
131- p .cmd .Stdout = cmdWriter
132142 p .cmd .Stderr = os .Stderr
143+ p .cmd .Stdin = cmdReader
133144
134- w , err := p .cmd .StdinPipe ()
145+ r , err := p .cmd .StdoutPipe ()
135146 if err != nil {
136147 return err
137148 }
138149
139- go func () {
140- io .Copy (w , cmdReader )
141- w .Close ()
142- }()
143-
144150 err = p .cmd .Start ()
145151 if err != nil {
146152 return err
147153 }
148- go p .run (cmdWriter , errChan )
154+ go p .run (cmdWriter , r , errChan )
149155 return nil
150156}
151157
152- func (p * remoteProc ) run (writer io.Closer , errChan chan error ) {
153- err := p .cmd .Wait ()
154- writer .Close ()
155- errChan <- err
158+ func (p * remoteProc ) run (w io.WriteCloser , r io.Reader , errChan chan error ) {
159+ p .pipeCopy (w , r )
160+ errChan <- p .cmd .Wait ()
156161}
157162
158163func doSource (p string , cmdReader io.Reader , cmdWriter io.WriteCloser , opts * options ) error {
@@ -176,83 +181,93 @@ func doSource(p string, cmdReader io.Reader, cmdWriter io.WriteCloser, opts *opt
176181 src = sf
177182 }
178183
179- size , err := src .Seek (0 , os . SEEK_END )
184+ size , err := src .Seek (0 , io . SeekEnd )
180185 if err != nil {
181186 return err
182187 }
183188
184- _ , err = src .Seek (0 , os . SEEK_SET )
189+ _ , err = src .Seek (0 , io . SeekStart )
185190 if err != nil {
186191 return err
187192 }
188193
189194 err = diskrsync .Source (src , size , cmdReader , cmdWriter , true , opts .verbose )
190- cmdWriter .Close ()
195+ cerr := cmdWriter .Close ()
196+ if err == nil {
197+ err = cerr
198+ }
191199 return err
192200}
193201
194- func doTarget (p string , cmdReader io.Reader , cmdWriter io.WriteCloser , opts * options ) error {
195- var w targetFile
196- useBuffer := false
202+ func doTarget (p string , cmdReader io.Reader , cmdWriter io.WriteCloser , opts * options ) ( err error ) {
203+ var w spgz. SparseFile
204+ useReadBuffer := false
197205
198206 f , err := os .OpenFile (p , os .O_RDWR | os .O_CREATE , 0666 )
199207 if err != nil {
200- return err
208+ return
201209 }
202210
203211 info , err := f .Stat ()
204212 if err != nil {
205- f .Close ()
206- return err
213+ _ = f .Close ()
214+ return
207215 }
208216
209- if info .Mode () & (os .ModeDevice | os .ModeCharDevice ) != 0 {
210- w = f
211- useBuffer = true
217+ if info .Mode ()& (os .ModeDevice | os .ModeCharDevice ) != 0 {
218+ w = spgz . NewSparseFileWithoutHolePunching ( f )
219+ useReadBuffer = true
212220 } else if ! opts .noCompress {
213221 sf , err := spgz .NewFromFileSize (f , os .O_RDWR | os .O_CREATE , diskrsync .DefTargetBlockSize )
214222 if err != nil {
215223 if err != spgz .ErrInvalidFormat {
216224 if err == spgz .ErrPunchHoleNotSupported {
217225 err = fmt .Errorf ("target does not support compression. Try with -no-compress option (error was '%v')" , err )
218226 }
219- f .Close ()
227+ _ = f .Close ()
220228 return err
221229 }
222230 } else {
223- w = sf
231+ w = & diskrsync. FixingSpgzFileWrapper { SpgzFile : sf }
224232 }
225233 }
226234
227235 if w == nil {
228- w = spgz .NewSparseWriter ( spgz . NewSparseFileWithFallback (f ) )
229- useBuffer = true
236+ w = spgz .NewSparseFileWithFallback (f )
237+ useReadBuffer = true
230238 }
231239
232- defer w .Close ()
240+ defer func () {
241+ cerr := w .Close ()
242+ if err == nil {
243+ err = cerr
244+ }
245+ }()
233246
234- size , err := w .Seek (0 , os . SEEK_END )
247+ size , err := w .Seek (0 , io . SeekEnd )
235248 if err != nil {
236249 return err
237250 }
238251
239- _ , err = w .Seek (0 , os . SEEK_SET )
252+ _ , err = w .Seek (0 , io . SeekStart )
240253
241254 if err != nil {
242255 return err
243256 }
244257
245- err = diskrsync .Target (w , size , cmdReader , cmdWriter , useBuffer , opts .verbose )
246- cmdWriter .Close ()
258+ err = diskrsync .Target (w , size , cmdReader , cmdWriter , useReadBuffer , opts .verbose )
259+ cerr := cmdWriter .Close ()
260+ if err == nil {
261+ err = cerr
262+ }
247263
248- return err
264+ return
249265}
250266
251- func doCmd (opts * options ) bool {
267+ func doCmd (opts * options ) ( err error ) {
252268 src , err := createProc (flag .Arg (0 ), modeSource , opts )
253269 if err != nil {
254- log .Printf ("Could not create source: %v" , err )
255- return false
270+ return fmt .Errorf ("could not create source: %w" , err )
256271 }
257272
258273 path := flag .Arg (1 )
@@ -262,8 +277,7 @@ func doCmd(opts *options) bool {
262277
263278 dst , err := createProc (path , modeTarget , opts )
264279 if err != nil {
265- log .Printf ("Could not create target: %v" , err )
266- return false
280+ return fmt .Errorf ("could not create target: %w" , err )
267281 }
268282
269283 srcErrChan := make (chan error , 1 )
@@ -276,24 +290,42 @@ func doCmd(opts *options) bool {
276290 sw := & diskrsync.CountingWriteCloser {WriteCloser : srcWriter }
277291
278292 if opts .verbose {
279- src .Start (sr , sw , srcErrChan )
293+ err = src .Start (sr , sw , srcErrChan )
280294 } else {
281- src .Start (srcReader , srcWriter , srcErrChan )
295+ err = src .Start (srcReader , srcWriter , srcErrChan )
296+ }
297+
298+ if err != nil {
299+ return fmt .Errorf ("could not start source: %w" , err )
282300 }
283301
284- dst .Start (dstReader , dstWriter , dstErrChan )
285- dstErr := <- dstErrChan
286- if dstErr != nil {
287- log .Printf ("Target error: %v" , dstErr )
302+ err = dst .Start (dstReader , dstWriter , dstErrChan )
303+ if err != nil {
304+ return fmt .Errorf ("could not start target: %w" , err )
288305 }
289- srcErr := <- srcErrChan
290- if srcErr != nil {
291- log .Printf ("Source error: %v" , srcErr )
306+
307+ L:
308+ for srcErrChan != nil || dstErrChan != nil {
309+ select {
310+ case dstErr := <- dstErrChan :
311+ if dstErr != nil {
312+ err = fmt .Errorf ("target error: %w" , dstErr )
313+ break L
314+ }
315+ dstErrChan = nil
316+ case srcErr := <- srcErrChan :
317+ if srcErr != nil {
318+ err = fmt .Errorf ("source error: %w" , srcErr )
319+ break L
320+ }
321+ srcErrChan = nil
322+ }
292323 }
324+
293325 if opts .verbose {
294326 log .Printf ("Read: %d, wrote: %d\n " , sr .Count (), sw .Count ())
295327 }
296- return srcErr == nil && dstErr == nil
328+ return
297329}
298330
299331func main () {
@@ -328,9 +360,9 @@ func main() {
328360 if flag .Arg (0 ) == "" || flag .Arg (1 ) == "" {
329361 usage ()
330362 }
331- ok := doCmd (& opts )
332- if ! ok {
333- os . Exit ( 1 )
363+ err := doCmd (& opts )
364+ if err != nil {
365+ log . Fatal ( err )
334366 }
335367 }
336368
0 commit comments