func (f *File) WriteAt(b []byte, off int64) (n int, err error) { req := fxpWriteMsg{Handle: f.handle} fxpCh, err := f.sftp.chans.newChan() if err != nil { return } defer f.sftp.chans.remove(fxpCh.id) req.SetID(fxpCh.id) for len(b) > 0 { req.Offset = uint64(n) + uint64(off) l := min(uint64(len(b)), maxDataBytes) req.Data = b[:l] if err = f.sftp.writePacket(ssh.Marshal(req)); err != nil { return } resp := fxpCh.waitForResponse() switch msg := resp.(type) { case *fxpStatusResp: if msg.Status != OK { err = msg return } n += int(l) b = b[l:] default: panic("unexpected message type returned from server") } } return }
func (f *File) ReadAt(b []byte, off int64) (n int, err error) { req := fxpReadMsg{Handle: f.handle} fxpCh, err := f.sftp.chans.newChan() if err != nil { return } defer f.sftp.chans.remove(fxpCh.id) req.SetID(fxpCh.id) for len(b) > 0 { req.Offset = uint64(n) + uint64(off) req.Length = uint32(min(uint64(len(b)), maxDataBytes)) if err = f.sftp.writePacket(ssh.Marshal(req)); err != nil { return } resp := fxpCh.waitForResponse() switch msg := resp.(type) { case *fxpStatusResp: if msg.Status == eof { err = io.EOF return } err = msg return case *fxpDataResp: n += copy(b, msg.Data) b = b[len(msg.Data):] default: panic("unexpected message type returned from server") } } return }
// init starts the SFTP protocol by negotiating the protocol version to use and // starts the response handler in a goroutine. func (s *Client) init() error { msg := fxpInitMsg{ Version: 3, } if err := s.writePacket(ssh.Marshal(msg)); err != nil { return err } packet, err := s.readOnePacket() if err != nil { return err } resp, err := decodeClient(packet) if err != nil { return err } switch resp := resp.(type) { case *fxpVersionMsg: if resp.Version != 3 { return errors.New("only version 3 of Client protocol supported") } default: return errors.New("invalid packet received during initialization") } go s.mainLoop() return nil }
// init starts the SFTP protocol by negotiating the protocol version to use and // starts the response handler in a goroutine. func (s *Client) init() error { msg := fxpInitMsg{ Version: 3, } if err := s.writePacket(ssh.Marshal(msg)); err != nil { return err } packet, err := s.readOnePacket() if err != nil { return err } resp, err := decodeClient(packet) if err != nil { return err } switch resp := resp.(type) { case *fxpVersionMsg: if resp.Version != 3 { return errors.New("only version 3 of Client protocol supported") } default: return errors.New("invalid packet received during initialization") } vers := resp.(*fxpVersionMsg) s.exts = make(map[string]extension) if len(vers.Ext) > 0 { exts := vers.Ext for len(exts) > 0 { ew := extensionWire{} if err := ssh.Unmarshal(exts, &ew); err != nil { return err } if len(exts) < 2 { break } exts = ew.Rest e := extension{ Name: ew.Name, Data: ew.Data, } // OpenSSH's sftp-server implementation specifies that // the data portion of an extension is an ASCII-encoded // version number. This is not part of the SFTP // specification, however. if n, err := strconv.Atoi(ew.Data); err == nil { e.version = n } s.exts[e.Name] = e } } go s.mainLoop() return nil }
// sendRequests sends a request to the server and returns a new channel on // which the response will be sent. func (s *Client) sendRequest(req ider) (*fxpChan, error) { fxpCh, err := s.chans.newChan() if err != nil { return nil, err } req.SetID(fxpCh.id) if err := s.writePacket(ssh.Marshal(req)); err != nil { return nil, err } return fxpCh, nil }