5e97cf7a2e
* Moved filepiece into storj
* Fix linter errors
* Seek comment for linter
* gofmt/golinter accidentally removed import
* Fix small typos
* Use the weird iota. P cool dude ✌️
* Do things the cool way
* Changes requested by kaloyan
* didn't need test main
137 lines
2.8 KiB
Go
137 lines
2.8 KiB
Go
// Copyright (C) 2018 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package fpiece
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"os"
|
|
)
|
|
|
|
// Chunk - Section of data to be concurrently read
|
|
type Chunk struct {
|
|
file *os.File
|
|
start int64
|
|
final int64
|
|
currentPos int64
|
|
}
|
|
|
|
// NewChunk - Create Chunk
|
|
func NewChunk(file *os.File, offset int64, length int64) (*Chunk, error) {
|
|
if length < 0 {
|
|
return nil, errors.New("Invalid Length")
|
|
}
|
|
|
|
return &Chunk{file, offset, length + offset, offset}, nil
|
|
}
|
|
|
|
// Size - Get size of Chunk
|
|
func (f *Chunk) Size() int64 {
|
|
return f.final - f.start
|
|
}
|
|
|
|
// Close - Close file associated with chunk
|
|
func (f *Chunk) Close() error {
|
|
return f.file.Close()
|
|
}
|
|
|
|
// Read - Concurrently read from Chunk
|
|
func (f *Chunk) Read(b []byte) (n int, err error) {
|
|
if f.currentPos >= f.final {
|
|
return 0, io.EOF
|
|
}
|
|
|
|
var readLen int64 // starts at 0
|
|
if f.final-f.currentPos > int64(len(b)) {
|
|
readLen = int64(len(b))
|
|
} else {
|
|
readLen = f.final - f.currentPos
|
|
}
|
|
|
|
n, err = f.file.ReadAt(b[:readLen], f.currentPos)
|
|
f.currentPos += int64(n)
|
|
return n, err
|
|
}
|
|
|
|
// ReadAt - Concurrently read from Chunk at specific offset
|
|
func (f *Chunk) ReadAt(p []byte, off int64) (n int, err error) {
|
|
if off < 0 || off >= f.final-f.start {
|
|
return 0, io.EOF
|
|
}
|
|
|
|
off += f.start
|
|
|
|
if max := f.final - off; int64(len(p)) > max {
|
|
p = p[:max]
|
|
n, err = f.file.ReadAt(p, off)
|
|
if err == nil {
|
|
err = io.EOF
|
|
}
|
|
return n, err
|
|
}
|
|
return f.file.ReadAt(p, off)
|
|
}
|
|
|
|
// Write - Concurrently write to Chunk
|
|
func (f *Chunk) Write(b []byte) (n int, err error) {
|
|
if f.currentPos >= f.final {
|
|
return 0, io.EOF
|
|
}
|
|
|
|
var writeLen int64 // starts at 0
|
|
if f.final-f.currentPos > int64(len(b)) {
|
|
writeLen = int64(len(b))
|
|
} else {
|
|
writeLen = f.final - f.currentPos
|
|
}
|
|
|
|
n, err = f.file.WriteAt(b[:writeLen], f.currentPos)
|
|
f.currentPos += int64(n)
|
|
return n, err
|
|
}
|
|
|
|
// WriteAt - Concurrently write to Chunk at specific offset
|
|
func (f *Chunk) WriteAt(p []byte, off int64) (n int, err error) {
|
|
if off < 0 || off >= f.final-f.start {
|
|
return 0, io.EOF
|
|
}
|
|
|
|
off += f.start
|
|
|
|
if max := f.final - off; int64(len(p)) > max {
|
|
p = p[:max]
|
|
n, err = f.file.WriteAt(p, off)
|
|
if err == nil {
|
|
err = io.EOF
|
|
}
|
|
return n, err
|
|
}
|
|
return f.file.WriteAt(p, off)
|
|
}
|
|
|
|
var errWhence = errors.New("Seek: invalid whence")
|
|
var errOffset = errors.New("Seek: invalid offset")
|
|
|
|
// Seek - Seek to position of chunk for reading/writing at specific offset
|
|
func (f *Chunk) Seek(offset int64, whence int) (int64, error) {
|
|
switch whence {
|
|
default:
|
|
return 0, errWhence
|
|
case io.SeekStart:
|
|
offset += f.start
|
|
case io.SeekCurrent:
|
|
offset += f.currentPos
|
|
case io.SeekEnd:
|
|
offset += f.final
|
|
}
|
|
|
|
// Do not seek to where somewhere outside the chunk
|
|
if offset < f.start || offset > f.final {
|
|
return 0, errOffset
|
|
}
|
|
|
|
f.currentPos = offset
|
|
return offset - f.start, nil
|
|
}
|