Ejemplo n.º 1
0
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
}
Ejemplo n.º 2
0
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
}
Ejemplo n.º 3
0
// 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
}
Ejemplo n.º 4
0
// 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
}
Ejemplo n.º 5
0
// 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
}