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.Reader
io.Seeker io.Seeker
io.Closer io.Closer
io.ReaderAt
} }
// Implements a Handle within a subsection of another Handle. // 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 offset += me.off
} else if whence == 2 { } else if whence == 2 {
whence = 0 whence = 0
offset = me.off + me.n offset += me.off + me.n
} }
ret, err = me.h.Seek(offset, whence) ret, err = me.h.Seek(offset, whence)
me.cur = ret
ret -= me.off ret -= me.off
return return
} }
@ -1766,6 +1768,17 @@ func (me *sectionHandle) Read(b []byte) (n int, err error) {
return 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) { func (f File) Open() (h Handle, err error) {
h = f.t.NewReadHandle() h = f.t.NewReadHandle()
_, err = h.Seek(f.offset, os.SEEK_SET) _, err = h.Seek(f.offset, os.SEEK_SET)

View File

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