storj/pkg/filepiece/fpiece.go

137 lines
2.8 KiB
Go
Raw Normal View History

// 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
}