93 lines
2.1 KiB
Go
93 lines
2.1 KiB
Go
package fat
|
|
|
|
import (
|
|
"io"
|
|
"math"
|
|
|
|
"github.com/mitchellh/go-fs"
|
|
)
|
|
|
|
type ClusterChain struct {
|
|
device fs.BlockDevice
|
|
fat *FAT
|
|
startCluster uint32
|
|
readOffset uint32
|
|
writeOffset uint32
|
|
}
|
|
|
|
func (c *ClusterChain) Read(p []byte) (n int, err error) {
|
|
bpc := c.fat.bs.BytesPerCluster()
|
|
chain := c.fat.Chain(c.startCluster)
|
|
|
|
dataOffset := uint32(0)
|
|
for dataOffset < uint32(len(p)) {
|
|
chainIdx := c.readOffset / bpc
|
|
if int(chainIdx) >= len(chain) {
|
|
err = io.EOF
|
|
return
|
|
}
|
|
|
|
clusterOffset := c.fat.bs.ClusterOffset(int(chain[chainIdx]))
|
|
clusterOffset += c.readOffset % bpc
|
|
dataOffsetEnd := dataOffset + bpc
|
|
dataOffsetEnd -= c.readOffset % bpc
|
|
dataOffsetEnd = uint32(math.Min(float64(dataOffsetEnd), float64(len(p))))
|
|
|
|
var nw int
|
|
nw, err = c.device.ReadAt(p[dataOffset:dataOffsetEnd], int64(clusterOffset))
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
c.readOffset += uint32(nw)
|
|
dataOffset += uint32(nw)
|
|
n += nw
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// Write will write to the cluster chain, expanding it if necessary.
|
|
func (c *ClusterChain) Write(p []byte) (n int, err error) {
|
|
bpc := c.fat.bs.BytesPerCluster()
|
|
chain := c.fat.Chain(c.startCluster)
|
|
chainLength := uint32(len(chain)) * bpc
|
|
|
|
if chainLength < c.writeOffset+uint32(len(p)) {
|
|
// We need to grow the chain
|
|
bytesNeeded := (c.writeOffset + uint32(len(p))) - chainLength
|
|
clustersNeeded := int(math.Ceil(float64(bytesNeeded) / float64(bpc)))
|
|
chain, err = c.fat.ResizeChain(c.startCluster, len(chain)+clustersNeeded)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Write the FAT out
|
|
if err = c.fat.WriteToDevice(c.device); err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
dataOffset := uint32(0)
|
|
for dataOffset < uint32(len(p)) {
|
|
chainIdx := c.writeOffset / bpc
|
|
clusterOffset := c.fat.bs.ClusterOffset(int(chain[chainIdx]))
|
|
clusterOffset += c.writeOffset % bpc
|
|
dataOffsetEnd := dataOffset + bpc
|
|
dataOffsetEnd -= c.writeOffset % bpc
|
|
dataOffsetEnd = uint32(math.Min(float64(dataOffsetEnd), float64(len(p))))
|
|
|
|
var nw int
|
|
nw, err = c.device.WriteAt(p[dataOffset:dataOffsetEnd], int64(clusterOffset))
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
c.writeOffset += uint32(nw)
|
|
dataOffset += uint32(nw)
|
|
n += nw
|
|
}
|
|
|
|
return
|
|
}
|