]> Sergey Matveev's repositories - btrtrc.git/blob - data/mmap/mmap.go
Encapsulate torrent data, and provide os.File and mmap-based implementations
[btrtrc.git] / data / mmap / mmap.go
1 package mmap
2
3 import (
4         "fmt"
5         "os"
6         "path/filepath"
7
8         "bitbucket.org/anacrolix/go.torrent/mmap_span"
9         "github.com/anacrolix/libtorgo/metainfo"
10         "launchpad.net/gommap"
11 )
12
13 func TorrentData(md *metainfo.Info, location string) (mms *mmap_span.MMapSpan, err error) {
14         mms = &mmap_span.MMapSpan{}
15         defer func() {
16                 if err != nil {
17                         mms.Close()
18                         mms = nil
19                 }
20         }()
21         for _, miFile := range md.UpvertedFiles() {
22                 fileName := filepath.Join(append([]string{location, md.Name}, miFile.Path...)...)
23                 err = os.MkdirAll(filepath.Dir(fileName), 0777)
24                 if err != nil {
25                         err = fmt.Errorf("error creating data directory %q: %s", filepath.Dir(fileName), err)
26                         return
27                 }
28                 var file *os.File
29                 file, err = os.OpenFile(fileName, os.O_CREATE|os.O_RDWR, 0666)
30                 if err != nil {
31                         return
32                 }
33                 func() {
34                         defer file.Close()
35                         var fi os.FileInfo
36                         fi, err = file.Stat()
37                         if err != nil {
38                                 return
39                         }
40                         if fi.Size() < miFile.Length {
41                                 err = file.Truncate(miFile.Length)
42                                 if err != nil {
43                                         return
44                                 }
45                         }
46                         if miFile.Length == 0 {
47                                 // Can't mmap() regions with length 0.
48                                 return
49                         }
50                         var mMap gommap.MMap
51                         mMap, err = gommap.MapRegion(file.Fd(), 0, miFile.Length, gommap.PROT_READ|gommap.PROT_WRITE, gommap.MAP_SHARED)
52                         if err != nil {
53                                 err = fmt.Errorf("error mapping file %q, length %d: %s", file.Name(), miFile.Length, err)
54                                 return
55                         }
56                         if int64(len(mMap)) != miFile.Length {
57                                 panic("mmap has wrong length")
58                         }
59                         mms.Append(mMap)
60                 }()
61                 if err != nil {
62                         return
63                 }
64         }
65         return
66 }