...
1 package rifs
2
3 import (
4 "errors"
5 "io"
6 "os"
7
8 "github.com/dsoprea/go-logging"
9 )
10
11 var (
12
13
14
15 ErrSeekBeyondBound = errors.New("seek beyond boundary")
16 )
17
18
19
20
21
22 type BoundedReadWriteSeeker struct {
23 io.ReadWriteSeeker
24
25 currentOffset int64
26 minimumOffset int64
27
28 staticFileSize int64
29 }
30
31
32 func NewBoundedReadWriteSeeker(rws io.ReadWriteSeeker, minimumOffset int64, staticFileSize int64) (brws *BoundedReadWriteSeeker, err error) {
33 defer func() {
34 if state := recover(); state != nil {
35 err = log.Wrap(state.(error))
36 }
37 }()
38
39 if minimumOffset < 0 {
40 log.Panicf("BoundedReadWriteSeeker minimum offset must be zero or larger: (%d)", minimumOffset)
41 }
42
43
44 _, err = rws.Seek(minimumOffset, os.SEEK_SET)
45 log.PanicIf(err)
46
47 brws = &BoundedReadWriteSeeker{
48 ReadWriteSeeker: rws,
49
50 currentOffset: 0,
51 minimumOffset: minimumOffset,
52
53 staticFileSize: staticFileSize,
54 }
55
56 return brws, nil
57 }
58
59
60
61 func (brws *BoundedReadWriteSeeker) Seek(offset int64, whence int) (updatedOffset int64, err error) {
62 defer func() {
63 if state := recover(); state != nil {
64 err = log.Wrap(state.(error))
65 }
66 }()
67
68 fileSize := brws.staticFileSize
69
70
71 if whence == os.SEEK_END && fileSize == 0 {
72 realFileSizeRaw, err := brws.ReadWriteSeeker.Seek(0, os.SEEK_END)
73 log.PanicIf(err)
74
75 fileSize = realFileSizeRaw - brws.minimumOffset
76 }
77
78 updatedOffset, err = CalculateSeek(brws.currentOffset, offset, whence, fileSize)
79 log.PanicIf(err)
80
81 if brws.staticFileSize != 0 && updatedOffset > brws.staticFileSize {
82
83
84
85 return 0, ErrSeekBeyondBound
86 }
87
88 if updatedOffset != brws.currentOffset {
89 updatedRealOffset := updatedOffset + brws.minimumOffset
90
91 _, err = brws.ReadWriteSeeker.Seek(updatedRealOffset, os.SEEK_SET)
92 log.PanicIf(err)
93
94 brws.currentOffset = updatedOffset
95 }
96
97 return updatedOffset, nil
98 }
99
100
101 func (brws *BoundedReadWriteSeeker) Read(buffer []byte) (readCount int, err error) {
102 defer func() {
103 if state := recover(); state != nil {
104 err = log.Wrap(state.(error))
105 }
106 }()
107
108 if brws.staticFileSize != 0 {
109 availableCount := brws.staticFileSize - brws.currentOffset
110 if availableCount == 0 {
111 return 0, io.EOF
112 }
113
114 if int64(len(buffer)) > availableCount {
115 buffer = buffer[:availableCount]
116 }
117 }
118
119 readCount, err = brws.ReadWriteSeeker.Read(buffer)
120 brws.currentOffset += int64(readCount)
121
122 if err != nil {
123 if err == io.EOF {
124 return 0, err
125 }
126
127 log.Panic(err)
128 }
129
130 return readCount, nil
131 }
132
133
134 func (brws *BoundedReadWriteSeeker) Write(buffer []byte) (writtenCount int, err error) {
135 defer func() {
136 if state := recover(); state != nil {
137 err = log.Wrap(state.(error))
138 }
139 }()
140
141 if brws.staticFileSize != 0 {
142 log.Panicf("writes can not be performed if a static file-size was given")
143 }
144
145 writtenCount, err = brws.ReadWriteSeeker.Write(buffer)
146 brws.currentOffset += int64(writtenCount)
147
148 log.PanicIf(err)
149
150 return writtenCount, nil
151 }
152
153
154 func (brws *BoundedReadWriteSeeker) MinimumOffset() int64 {
155 return brws.minimumOffset
156 }
157
View as plain text