From: Matt Joiner Date: Wed, 4 Mar 2015 02:06:33 +0000 (+1100) Subject: Implement Handle.ReadAt X-Git-Tag: v1.0.0~1302 X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=779f4d3b970f7053b25a55ede7b2acaadc8441a6;p=btrtrc.git Implement Handle.ReadAt --- diff --git a/client.go b/client.go index 648dbd9c..78269d61 100644 --- a/client.go +++ b/client.go @@ -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) diff --git a/torrent.go b/torrent.go index 890d77ac..cd9f2633 100644 --- a/torrent.go +++ b/torrent.go @@ -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 }