From 50fba5e62484b0feec50b571f76edca45a607a38 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Wed, 6 Jul 2016 03:43:28 +0200 Subject: split --- meta/file.go | 13 +++++ meta/info.go | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++ meta/torrent.go | 163 +------------------------------------------------------- 3 files changed, 170 insertions(+), 162 deletions(-) create mode 100644 meta/file.go create mode 100644 meta/info.go diff --git a/meta/file.go b/meta/file.go new file mode 100644 index 0000000..2ec14cb --- /dev/null +++ b/meta/file.go @@ -0,0 +1,13 @@ +package meta + +import "path" + +type File struct { + Length int `bencode:"length"` + MD5Sum []byte `bencode:"md5sum,optional"` // never seen in wildlife + Path []string `bencode:"path"` +} + +func (f File) Name() string { + return path.Join(f.Path...) +} diff --git a/meta/info.go b/meta/info.go new file mode 100644 index 0000000..8f76c72 --- /dev/null +++ b/meta/info.go @@ -0,0 +1,156 @@ +package meta + +import ( + "crypto/sha1" + "errors" + "fmt" + "os" + "path" +) + +var ErrNotImplemented = errors.New("not implemented") + +type Info struct { + Files []File `bencode:"files"` + Length int `bencode:"length"` + MD5Sum []byte `bencode:"md5sum,optional"` // never seen in wildlife + Name string `bencode:"name"` + PieceLength int `bencode:"piece length"` + Pieces []byte `bencode:"pieces"` // compact mode + Private bool `bencode:"private"` // BEP-0027 + RootHash []byte `bencode:"root hash"` // BEP-0030 +} + +func (i Info) TotalLength() int { + if i.Length > 0 { + return i.Length + } + var l int + for _, f := range i.Files { + l += f.Length + } + return l +} + +func (i Info) GetPieces() []Piece { + length := i.TotalLength() + n := length / i.PieceLength + last := length % i.PieceLength + if last > 0 { + n++ + } + p := make([]Piece, n) + for k := 0; k < n; k++ { + p[k].Length = i.PieceLength + if k+1 == n { + p[k].Length = length + } + off := k * sha1.Size + copy(p[k].Sum[:], i.Pieces[off:off+sha1.Size]) + p[k].Offset = k * i.PieceLength + } + return p +} + +func (i Info) FullPath(n int) (string, error) { + if i.isSingleFile() { + return i.Name, nil + } + if n >= len(i.Files) || n < 0 { + return "", errors.New("out of range") + } + return path.Join(i.Name, i.Files[n].Name()), nil +} + +func (i Info) Offset(piece int) int { + return i.PieceLength * piece +} + +func (i Info) FindFile(off int) (int, int) { + for n, l := range i.Files { + if l.Length > off { + return n, off + } + off -= l.Length + } + return 0, off +} + +/* + * 0 1 2 3 4 5 6 7 #piece + * |----|----|----|----|----|----|----|--| pieces + * |-|----|--|----|----------|-|----|----| files + * 0 1 2 3 4 5 6 7 #file + */ + +func (i Info) isSingleFile() bool { + return len(i.Files) == 0 +} + +// FIXME WriteAt ... +func (i Info) WriteAt(b []byte, off int64) (n int, err error) { + return 0, ErrNotImplemented +} + +// FIXME ReadAt ... +func (i Info) ReadAt(b []byte, off int64) (n int, err error) { + if i.isSingleFile() { + fd, err := os.OpenFile(i.Name, os.O_RDWR|os.O_CREATE, 0644) + if err != nil { + return 0, err + } + defer fd.Close() + return fd.ReadAt(b, int64(i.PieceLength)*off) + } else { + n, off := i.FindFile(int(off)) + start := off + end := i.PieceLength + for k := n; k < len(i.Files); k++ { + f := i.Files[n] + p, err := i.FullPath(k) + if err != nil { + return 0, err + } + fd, err := os.OpenFile(p, os.O_RDWR|os.O_CREATE, 0644) + if err != nil { + return 0, err + } + defer fd.Close() + if end > f.Length { + end = f.Length + } + fd.ReadAt(b[start:end], int64(off)) + start = end + end = i.PieceLength + off += f.Length + if start == end { + return cap(b), nil + } + } + } + return 0, ErrNotImplemented +} + +// Last returns size of last truncated piece +func (i Info) Last() int { + return i.TotalLength() % i.PieceLength +} + +// Full returns count of full pieces +func (i Info) Full() int { + return i.TotalLength() / i.PieceLength +} + +func (i Info) String() string { + var s string + for n, f := range i.Files { + p, err := i.FullPath(n) + if err != nil { + panic(err) + } + s += fmt.Sprintf(" %s (%d)\n", p, f.Length) + } + s += fmt.Sprintf("%s (%d) ", i.Name, i.TotalLength()) + s += fmt.Sprintf("%d × %d + %d\n", i.Full(), i.PieceLength, i.Last()) + return s +} diff --git a/meta/torrent.go b/meta/torrent.go index 03c8693..a3d169e 100644 --- a/meta/torrent.go +++ b/meta/torrent.go @@ -3,171 +3,10 @@ package meta // see also: https://en.wikipedia.org/wiki/Torrent_file import ( - "crypto/sha1" - "errors" "fmt" - "os" - "path" "time" ) -var ErrNotImplemented = errors.New("not implemented") - -type File struct { - Length int `bencode:"length"` - MD5Sum []byte `bencode:"md5sum,optional"` // never seen in wildlife - Path []string `bencode:"path"` -} - -func (f File) Name() string { - return path.Join(f.Path...) -} - -type Info struct { - Files []File `bencode:"files"` - Length int `bencode:"length"` - MD5Sum []byte `bencode:"md5sum,optional"` // never seen in wildlife - Name string `bencode:"name"` - PieceLength int `bencode:"piece length"` - Pieces []byte `bencode:"pieces"` - Private bool `bencode:"private"` // BEP-0027 - RootHash []byte `bencode:"root hash"` // BEP-0030 -} - -func (i Info) TotalLength() int { - if i.Length > 0 { - return i.Length - } - var l int - for _, f := range i.Files { - l += f.Length - } - return l -} - -func (i Info) GetPieces() []Piece { - length := i.TotalLength() - n := length / i.PieceLength - last := length % i.PieceLength - if last > 0 { - n++ - } - p := make([]Piece, n) - for k := 0; k < n; k++ { - p[k].Length = i.PieceLength - if k+1 == n { - p[k].Length = length - } - off := k * sha1.Size - copy(p[k].Sum[:], i.Pieces[off:off+sha1.Size]) - p[k].Offset = k * i.PieceLength - } - return p -} - -func (i Info) FullPath(n int) (string, error) { - if i.isSingleFile() { - return i.Name, nil - } - if n >= len(i.Files) || n < 0 { - return "", errors.New("out of range") - } - return path.Join(i.Name, i.Files[n].Name()), nil -} - -func (i Info) Offset(piece int) int { - return i.PieceLength * piece -} - -func (i Info) FindFile(off int) (int, int) { - for n, l := range i.Files { - if l.Length > off { - return n, off - } - off -= l.Length - } - return 0, off -} - -/* - * 0 1 2 3 4 5 6 7 #piece - * |----|----|----|----|----|----|----|--| pieces - * |-|----|--|----|----------|-|----|----| files - * 0 1 2 3 4 5 6 7 #file - */ - -// FIXME WriteAt ... -func (i Info) WriteAt(b []byte, off int64) (n int, err error) { - return 0, ErrNotImplemented -} - -// FIXME ReadAt ... -func (i Info) ReadAt(b []byte, off int64) (n int, err error) { - if i.isSingleFile() { - fd, err := os.OpenFile(i.Name, os.O_RDWR|os.O_CREATE, 0644) - if err != nil { - return 0, err - } - defer fd.Close() - return fd.ReadAt(b, int64(i.PieceLength)*off) - } else { - n, off := i.FindFile(int(off)) - start := off - end := i.PieceLength - for k := n; k < len(i.Files); k++ { - f := i.Files[n] - p, err := i.FullPath(k) - if err != nil { - return 0, err - } - fd, err := os.OpenFile(p, os.O_RDWR|os.O_CREATE, 0644) - if err != nil { - return 0, err - } - defer fd.Close() - if end > f.Length { - end = f.Length - } - fd.ReadAt(b[start:end], int64(off)) - start = end - end = i.PieceLength - off += f.Length - if start == end { - return cap(b), nil - } - } - } - return 0, ErrNotImplemented -} - -func (i Info) isSingleFile() bool { - return len(i.Files) == 0 -} - -// Last returns size of last truncated piece -func (i Info) Last() int { - return i.TotalLength() % i.PieceLength -} - -// Full returns count of full pieces -func (i Info) Full() int { - return i.TotalLength() / i.PieceLength -} - -func (i Info) String() string { - var s string - for n, f := range i.Files { - p, err := i.FullPath(n) - if err != nil { - panic(err) - } - s += fmt.Sprintf(" %s (%d)\n", p, f.Length) - } - s += fmt.Sprintf("%s (%d) ", i.Name, i.TotalLength()) - s += fmt.Sprintf("%d × %d + %d\n", i.Full(), i.PieceLength, i.Last()) - return s -} - type Nodes map[string]int // Host:Port type Torrent struct { @@ -181,7 +20,7 @@ type Torrent struct { Info Info `bencode:"info"` URLList string `bencode:"url-list,optional"` InfoHash []byte `bencode:"-"` - Nodes Nodes `bencode:"nodes"` // BEP-0005 + //Nodes Nodes `bencode:"nodes"` // BEP-0005 } func (t Torrent) String() string { -- cgit v1.2.3