Implement Handle.ReadAt

This commit is contained in:
Matt Joiner 2015-03-04 13:06:33 +11:00
parent 63361b7b47
commit 779f4d3b97
2 changed files with 48 additions and 22 deletions

View File

@ -1726,6 +1726,7 @@ type Handle interface {
io.Reader
io.Seeker
io.Closer
io.ReaderAt
}
// Implements a Handle within a subsection of another Handle.
@ -1739,9 +1740,10 @@ func (me *sectionHandle) Seek(offset int64, whence int) (ret int64, err error) {
offset += me.off
} else if whence == 2 {
whence = 0
offset = me.off + me.n
offset += me.off + me.n
}
ret, err = me.h.Seek(offset, whence)
me.cur = ret
ret -= me.off
return
}
@ -1766,6 +1768,17 @@ func (me *sectionHandle) Read(b []byte) (n int, err error) {
return
}
func (me *sectionHandle) ReadAt(b []byte, off int64) (n int, err error) {
if off >= me.n {
err = io.EOF
return
}
if int64(len(b)) >= me.n-off {
b = b[:me.n-off]
}
return me.h.ReadAt(b, me.off+off)
}
func (f File) Open() (h Handle, err error) {
h = f.t.NewReadHandle()
_, err = h.Seek(f.offset, os.SEEK_SET)

View File

@ -7,6 +7,7 @@ import (
"io"
"log"
"net"
"os"
"sort"
"sync"
"time"
@ -106,9 +107,10 @@ type torrent struct {
}
// A file-like handle to torrent data that implements SectionOpener. Opened
// sections are be reused so long as Reads are contiguous.
// sections will be reused so long as Reads and ReadAt's are contiguous.
type handle struct {
rc io.ReadCloser
rcOff int64
curOff int64
so SectionOpener
size int64
@ -122,41 +124,52 @@ func (h *handle) Close() error {
return nil
}
func (h *handle) Read(b []byte) (n int, err error) {
max := h.t.prepareRead(h.curOff)
if int64(len(b)) > max {
b = b[:max]
func (h *handle) ReadAt(b []byte, off int64) (n int, err error) {
return h.readAt(b, off)
}
func (h *handle) readAt(b []byte, off int64) (n int, err error) {
avail := h.t.prepareRead(off)
if int64(len(b)) > avail {
b = b[:avail]
}
if int64(len(b)) > h.size-off {
b = b[:h.size-off]
}
if h.rcOff != off && h.rc != nil {
h.rc.Close()
h.rc = nil
}
if h.rc == nil {
h.rc, err = h.so.OpenSection(h.curOff, h.size-h.curOff)
h.rc, err = h.so.OpenSection(off, h.size-off)
if err != nil {
return
}
h.rcOff = off
}
n, err = h.rc.Read(b)
h.curOff += int64(n)
h.rcOff += int64(n)
return
}
func (h *handle) Read(b []byte) (n int, err error) {
n, err = h.readAt(b, h.curOff)
h.curOff = h.rcOff
return
}
func (h *handle) Seek(off int64, whence int) (newOff int64, err error) {
switch whence {
case 0:
newOff = off
case 1:
newOff += off
case 2:
newOff = h.size + off
case os.SEEK_SET:
h.curOff = off
case os.SEEK_CUR:
h.curOff += off
case os.SEEK_END:
h.curOff = h.size + off
default:
err = errors.New("bad whence")
}
if newOff == h.curOff {
return
}
h.curOff = newOff
if h.rc != nil {
h.Close()
h.rc = nil
}
newOff = h.curOff
return
}