Use protocol provided buffers for requests (fixes #1157)

This commit is contained in:
Audrius Butkevicius 2015-07-29 21:38:22 +01:00
parent b63351074c
commit 1977c526e4
2 changed files with 27 additions and 48 deletions

View File

@ -705,19 +705,19 @@ func (m *Model) Close(device protocol.DeviceID, err error) {
// Request returns the specified data segment by reading it from local disk. // Request returns the specified data segment by reading it from local disk.
// Implements the protocol.Model interface. // Implements the protocol.Model interface.
func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset int64, size int, hash []byte, flags uint32, options []protocol.Option) ([]byte, error) { func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset int64, hash []byte, flags uint32, options []protocol.Option, buf []byte) error {
if offset < 0 || size < 0 { if offset < 0 {
return nil, protocol.ErrNoSuchFile return protocol.ErrNoSuchFile
} }
if !m.folderSharedWith(folder, deviceID) { if !m.folderSharedWith(folder, deviceID) {
l.Warnf("Request from %s for file %s in unshared folder %q", deviceID, name, folder) l.Warnf("Request from %s for file %s in unshared folder %q", deviceID, name, folder)
return nil, protocol.ErrNoSuchFile return protocol.ErrNoSuchFile
} }
if flags != 0 { if flags != 0 {
// We don't currently support or expect any flags. // We don't currently support or expect any flags.
return nil, fmt.Errorf("protocol error: unknown flags 0x%x in Request message", flags) return fmt.Errorf("protocol error: unknown flags 0x%x in Request message", flags)
} }
// Verify that the requested file exists in the local model. We only need // Verify that the requested file exists in the local model. We only need
@ -739,7 +739,7 @@ func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset
if !ok { if !ok {
l.Warnf("Request from %s for file %s in nonexistent folder %q", deviceID, name, folder) l.Warnf("Request from %s for file %s in nonexistent folder %q", deviceID, name, folder)
return nil, protocol.ErrNoSuchFile return protocol.ErrNoSuchFile
} }
// This call is really expensive for large files, as we load the full // This call is really expensive for large files, as we load the full
@ -747,21 +747,21 @@ func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset
// space for, read, and deserialize. // space for, read, and deserialize.
lf, ok := folderFiles.Get(protocol.LocalDeviceID, name) lf, ok := folderFiles.Get(protocol.LocalDeviceID, name)
if !ok { if !ok {
return nil, protocol.ErrNoSuchFile return protocol.ErrNoSuchFile
} }
if lf.IsInvalid() || lf.IsDeleted() { if lf.IsInvalid() || lf.IsDeleted() {
if debug { if debug {
l.Debugf("%v REQ(in): %s: %q / %q o=%d s=%d; invalid: %v", m, deviceID, folder, name, offset, size, lf) l.Debugf("%v REQ(in): %s: %q / %q o=%d s=%d; invalid: %v", m, deviceID, folder, name, offset, len(buf), lf)
} }
return nil, protocol.ErrInvalid return protocol.ErrInvalid
} }
if offset > lf.Size() { if offset > lf.Size() {
if debug { if debug {
l.Debugf("%v REQ(in; nonexistent): %s: %q o=%d s=%d", m, deviceID, name, offset, size) l.Debugf("%v REQ(in; nonexistent): %s: %q o=%d s=%d", m, deviceID, name, offset, len(buf))
} }
return nil, protocol.ErrNoSuchFile return protocol.ErrNoSuchFile
} }
m.rvmut.Lock() m.rvmut.Lock()
@ -792,7 +792,7 @@ func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset
} }
if debug && deviceID != protocol.LocalDeviceID { if debug && deviceID != protocol.LocalDeviceID {
l.Debugf("%v REQ(in): %s: %q / %q o=%d s=%d", m, deviceID, folder, name, offset, size) l.Debugf("%v REQ(in): %s: %q / %q o=%d s=%d", m, deviceID, folder, name, offset, len(buf))
} }
m.fmut.RLock() m.fmut.RLock()
fn := filepath.Join(m.folderCfgs[folder].Path(), name) fn := filepath.Join(m.folderCfgs[folder].Path(), name)
@ -803,7 +803,7 @@ func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset
if info, err := os.Lstat(fn); err == nil && info.Mode()&os.ModeSymlink != 0 { if info, err := os.Lstat(fn); err == nil && info.Mode()&os.ModeSymlink != 0 {
target, _, err := symlinks.Read(fn) target, _, err := symlinks.Read(fn)
if err != nil { if err != nil {
return nil, err return err
} }
reader = strings.NewReader(target) reader = strings.NewReader(target)
} else { } else {
@ -811,19 +811,18 @@ func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset
// at any moment. // at any moment.
reader, err = os.Open(fn) reader, err = os.Open(fn)
if err != nil { if err != nil {
return nil, err return err
} }
defer reader.(*os.File).Close() defer reader.(*os.File).Close()
} }
buf := make([]byte, size)
_, err = reader.ReadAt(buf, offset) _, err = reader.ReadAt(buf, offset)
if err != nil { if err != nil {
return nil, err return err
} }
return buf, nil return nil
} }
func (m *Model) CurrentFolderFile(folder string, file string) (protocol.FileInfo, bool) { func (m *Model) CurrentFolderFile(folder string, file string) (protocol.FileInfo, bool) {

View File

@ -99,8 +99,11 @@ func TestRequest(t *testing.T) {
m.ServeBackground() m.ServeBackground()
m.ScanFolder("default") m.ScanFolder("default")
bs := make([]byte, protocol.BlockSize)
// Existing, shared file // Existing, shared file
bs, err := m.Request(device1, "default", "foo", 0, 6, nil, 0, nil) bs = bs[:6]
err := m.Request(device1, "default", "foo", 0, nil, 0, nil, bs)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -109,58 +112,35 @@ func TestRequest(t *testing.T) {
} }
// Existing, nonshared file // Existing, nonshared file
bs, err = m.Request(device2, "default", "foo", 0, 6, nil, 0, nil) err = m.Request(device2, "default", "foo", 0, nil, 0, nil, bs)
if err == nil { if err == nil {
t.Error("Unexpected nil error on insecure file read") t.Error("Unexpected nil error on insecure file read")
} }
if bs != nil {
t.Errorf("Unexpected non nil data on insecure file read: %q", string(bs))
}
// Nonexistent file // Nonexistent file
bs, err = m.Request(device1, "default", "nonexistent", 0, 6, nil, 0, nil) err = m.Request(device1, "default", "nonexistent", 0, nil, 0, nil, bs)
if err == nil { if err == nil {
t.Error("Unexpected nil error on insecure file read") t.Error("Unexpected nil error on insecure file read")
} }
if bs != nil {
t.Errorf("Unexpected non nil data on insecure file read: %q", string(bs))
}
// Shared folder, but disallowed file name // Shared folder, but disallowed file name
bs, err = m.Request(device1, "default", "../walk.go", 0, 6, nil, 0, nil) err = m.Request(device1, "default", "../walk.go", 0, nil, 0, nil, bs)
if err == nil { if err == nil {
t.Error("Unexpected nil error on insecure file read") t.Error("Unexpected nil error on insecure file read")
} }
if bs != nil {
t.Errorf("Unexpected non nil data on insecure file read: %q", string(bs))
}
// Larger block than available
bs, err = m.Request(device1, "default", "foo", 0, 42, nil, 0, nil)
if err == nil {
t.Error("Unexpected nil error on insecure file read")
}
if bs != nil {
t.Errorf("Unexpected non nil data on insecure file read: %q", string(bs))
}
// Negative offset // Negative offset
bs, err = m.Request(device1, "default", "foo", -4, 6, nil, 0, nil) err = m.Request(device1, "default", "foo", -4, nil, 0, nil, bs[:0])
if err == nil { if err == nil {
t.Error("Unexpected nil error on insecure file read") t.Error("Unexpected nil error on insecure file read")
} }
if bs != nil {
t.Errorf("Unexpected non nil data on insecure file read: %q", string(bs))
}
// Negative size // Larger block than available
bs, err = m.Request(device1, "default", "foo", 4, -4, nil, 0, nil) bs = bs[:42]
err = m.Request(device1, "default", "foo", 0, nil, 0, nil, bs)
if err == nil { if err == nil {
t.Error("Unexpected nil error on insecure file read") t.Error("Unexpected nil error on insecure file read")
} }
if bs != nil {
t.Errorf("Unexpected non nil data on insecure file read: %q", string(bs))
}
} }
func genFiles(n int) []protocol.FileInfo { func genFiles(n int) []protocol.FileInfo {