///|
fn read_cluster_bytes(
data : Array[Byte],
layout : Layout,
cluster : Int,
) -> Result[Bytes, FatError] {
let sector = match layout.cluster_sector(cluster) {
Err(err) => return Err(err)
Ok(ok_val) => ok_val
}
slice_bytes(
data,
sector * layout.bytes_per_sector,
layout.bytes_per_cluster(),
)
}
///|
fn write_cluster_bytes(
data : Array[Byte],
layout : Layout,
cluster : Int,
payload : Bytes,
payload_off : Int,
payload_len : Int,
) -> Result[Unit, FatError] {
let sector = match layout.cluster_sector(cluster) {
Err(err) => return Err(err)
Ok(ok_val) => ok_val
}
let dest = sector * layout.bytes_per_sector
match fill_bytes(data, dest, layout.bytes_per_cluster(), b'\x00') {
Err(err) => return Err(err)
Ok(_) => ()
}
let mut i = 0
while i < payload_len {
data[dest + i] = payload[payload_off + i]
i = i + 1
}
Ok(())
}
///|
fn read_file_bytes(
data : Array[Byte],
layout : Layout,
cluster : Int,
size : Int,
) -> Result[Bytes, FatError] {
if size < 0 {
return Err(Corrupt("negative file size"))
}
if size == 0 {
return Ok(Bytes::make(0, b'\x00'))
}
let chain = match follow_chain(data, layout, cluster) {
Err(err) => return Err(err)
Ok(ok_val) => ok_val
}
let needed = (size + layout.bytes_per_cluster() - 1) /
layout.bytes_per_cluster()
if chain.length() < needed {
return Err(Corrupt("cluster chain is shorter than the directory size"))
}
let out = Array::make(size, b'\x00')
let mut copied = 0
let mut i = 0
while copied < size && i < chain.length() {
let chunk = match read_cluster_bytes(data, layout, chain[i]) {
Err(err) => return Err(err)
Ok(ok_val) => ok_val
}
let take = size - copied
let n = if take < chunk.length() { take } else { chunk.length() }
for j = 0; j < n; j = j + 1 {
out[copied + j] = chunk[j]
}
copied = copied + n
i = i + 1
}
Ok(Bytes::from_array(out))
}
///|
fn write_file_bytes(
data : Array[Byte],
layout : Layout,
payload : Bytes,
old_cluster : Int,
) -> Result[Int, FatError] {
if old_cluster != 0 {
match free_chain(data, layout, old_cluster) {
Err(err) => return Err(err)
Ok(_) => ()
}
}
if payload.length() == 0 {
return Ok(0)
}
let cluster_size = layout.bytes_per_cluster()
let count = (payload.length() + cluster_size - 1) / cluster_size
let first = match alloc_chain(data, layout, count, 2) {
Err(err) => return Err(err)
Ok(ok_val) => ok_val
}
let chain = match follow_chain(data, layout, first) {
Err(err) => return Err(err)
Ok(ok_val) => ok_val
}
let mut offset = 0
for i = 0; i < chain.length(); i = i + 1 {
let remaining = payload.length() - offset
let n = if remaining < cluster_size { remaining } else { cluster_size }
match write_cluster_bytes(data, layout, chain[i], payload, offset, n) {
Err(err) => return Err(err)
Ok(_) => ()
}
offset = offset + n
}
Ok(first)
}
///|
fn directory_is_empty(
data : Array[Byte],
layout : Layout,
cluster : Int,
) -> Result[Bool, FatError] {
let records = match read_directory(data, layout, cluster) {
Err(err) => return Err(err)
Ok(ok_val) => ok_val
}
for i = 0; i < records.length(); i = i + 1 {
if !records[i].is_dot() && !records[i].is_volume_id() {
return Ok(false)
}
}
Ok(true)
}