diff --git a/internal/model/model.go b/internal/model/model.go index af1a0e988..0ea49b040 100644 --- a/internal/model/model.go +++ b/internal/model/model.go @@ -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. // 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) { - if offset < 0 || size < 0 { - return nil, protocol.ErrNoSuchFile +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 { + return protocol.ErrNoSuchFile } if !m.folderSharedWith(folder, deviceID) { 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 { // 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 @@ -739,7 +739,7 @@ func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset if !ok { 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 @@ -747,21 +747,21 @@ func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset // space for, read, and deserialize. lf, ok := folderFiles.Get(protocol.LocalDeviceID, name) if !ok { - return nil, protocol.ErrNoSuchFile + return protocol.ErrNoSuchFile } if lf.IsInvalid() || lf.IsDeleted() { 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 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() @@ -792,7 +792,7 @@ func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset } 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() 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 { target, _, err := symlinks.Read(fn) if err != nil { - return nil, err + return err } reader = strings.NewReader(target) } else { @@ -811,19 +811,18 @@ func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset // at any moment. reader, err = os.Open(fn) if err != nil { - return nil, err + return err } defer reader.(*os.File).Close() } - buf := make([]byte, size) _, err = reader.ReadAt(buf, offset) if err != nil { - return nil, err + return err } - return buf, nil + return nil } func (m *Model) CurrentFolderFile(folder string, file string) (protocol.FileInfo, bool) { diff --git a/internal/model/model_test.go b/internal/model/model_test.go index c285c9c96..9243cc8ca 100644 --- a/internal/model/model_test.go +++ b/internal/model/model_test.go @@ -99,8 +99,11 @@ func TestRequest(t *testing.T) { m.ServeBackground() m.ScanFolder("default") + bs := make([]byte, protocol.BlockSize) + // 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 { t.Error(err) } @@ -109,58 +112,35 @@ func TestRequest(t *testing.T) { } // 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 { 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 - 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 { 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 - 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 { 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 - 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 { 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 - bs, err = m.Request(device1, "default", "foo", 4, -4, nil, 0, nil) + // Larger block than available + bs = bs[:42] + err = m.Request(device1, "default", "foo", 0, nil, 0, nil, bs) 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)) - } } func genFiles(n int) []protocol.FileInfo {