doDownload starts a download. f is expected to be an existing file open in RW mode
(t *Transfer, workerNum int, f *os.File, cb ProgressCallback)
| 211 | |
| 212 | // doDownload starts a download. f is expected to be an existing file open in RW mode |
| 213 | func (a *SSHAdapter) doDownload(t *Transfer, workerNum int, f *os.File, cb ProgressCallback) error { |
| 214 | args := a.argumentsForTransfer(t, "download") |
| 215 | conn, err := a.transfer.Connection(workerNum) |
| 216 | if err != nil { |
| 217 | return err |
| 218 | } |
| 219 | conn.Lock() |
| 220 | defer conn.Unlock() |
| 221 | err = conn.SendMessage(fmt.Sprintf("get-object %s", t.Oid), args) |
| 222 | if err != nil { |
| 223 | return err |
| 224 | } |
| 225 | status, args, data, err := conn.ReadStatusWithData() |
| 226 | if err != nil { |
| 227 | return err |
| 228 | } |
| 229 | if status < 200 || status > 299 { |
| 230 | buffer := &bytes.Buffer{} |
| 231 | if data != nil { |
| 232 | io.CopyN(buffer, data, 1024) |
| 233 | io.Copy(io.Discard, data) |
| 234 | } |
| 235 | return errors.NewRetriableError(errors.New(tr.Tr.Get("got status %d when fetching OID %s: %s", status, t.Oid, buffer.String()))) |
| 236 | } |
| 237 | |
| 238 | var actualSize int64 |
| 239 | seenSize := false |
| 240 | for _, arg := range args { |
| 241 | if strings.HasPrefix(arg, "size=") { |
| 242 | if seenSize { |
| 243 | return errors.NewProtocolError(tr.Tr.Get("unexpected size argument"), nil) |
| 244 | } |
| 245 | actualSize, err = strconv.ParseInt(arg[5:], 10, 64) |
| 246 | if err != nil || actualSize < 0 { |
| 247 | return errors.NewProtocolError(tr.Tr.Get("expected valid size, got %q", arg[5:]), err) |
| 248 | } |
| 249 | seenSize = true |
| 250 | } |
| 251 | } |
| 252 | if !seenSize { |
| 253 | return errors.NewProtocolError(tr.Tr.Get("no size argument seen"), nil) |
| 254 | } |
| 255 | |
| 256 | dlfilename := f.Name() |
| 257 | // Wrap callback to give name context |
| 258 | ccb := func(totalSize int64, readSoFar int64, readSinceLast int) error { |
| 259 | if cb != nil { |
| 260 | return cb(t.Name, totalSize, readSoFar, readSinceLast) |
| 261 | } |
| 262 | return nil |
| 263 | } |
| 264 | hasher := tools.NewHashingReader(data) |
| 265 | written, err := tools.CopyWithCallback(f, hasher, t.Size, ccb) |
| 266 | if err != nil { |
| 267 | return errors.Wrap(err, tr.Tr.Get("cannot write data to temporary file %q", dlfilename)) |
| 268 | } |
| 269 | |
| 270 | if actual := hasher.Hash(); actual != t.Oid { |
no test coverage detected