using System;
using System.IO;
namespace fat_file_system_cs
{
internal class VirtualDisk
{
private const int CLUSTER_SIZE = 1024;
private const int CLUSTERS_NUMBER = 1024;
private long diskSize = 0;
private string? diskPath = null;
private FileStream? diskFileStream = null;
private bool isOpen = false;
public void Initialize(string path, bool createIfMissing = true)
{
if (this.isOpen)
throw new InvalidOperationException("Disk is already initialized");
this.diskPath = path;
this.diskSize = CLUSTERS_NUMBER * CLUSTER_SIZE;
try
{
if (!File.Exists(diskPath))
{
if (createIfMissing)
this.CreateEmptyDisk(path);
else
throw new FileNotFoundException("Couldn't find the specified disk path");
}
this.diskFileStream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
this.isOpen = true;
}
catch (Exception ex)
{
this.isOpen = false;
throw new IOException($"Failed to open disk: {ex.Message}", ex);
}
}
private void CreateEmptyDisk(string path)
{
FileStream? tempFileStream = null;
try
{
tempFileStream = new FileStream(path, FileMode.Create, FileAccess.Write);
byte[] emptyClusterPlaceholder = new byte[CLUSTER_SIZE];
for (int i = 0; i < CLUSTERS_NUMBER; i++)
tempFileStream.Write(emptyClusterPlaceholder, 0, CLUSTER_SIZE);
tempFileStream.Flush();
}
catch (Exception ex)
{
throw new IOException($"Failed to create disk file: {ex.Message}", ex);
}
finally
{
tempFileStream?.Close();
}
}
public byte[] ReadCluster(int clusterNumber)
{
if (!this.isOpen)
throw new InvalidOperationException("Disk is not open");
if (clusterNumber < 0 || clusterNumber >= CLUSTERS_NUMBER)
throw new ArgumentOutOfRangeException(nameof(clusterNumber), "Invalid cluster number");
byte[] buffer = new byte[CLUSTER_SIZE];
long offset = clusterNumber * CLUSTER_SIZE;
this.diskFileStream!.Seek(offset, SeekOrigin.Begin);
int bytesRead = this.diskFileStream.Read(buffer, 0, CLUSTER_SIZE);
if (bytesRead < CLUSTER_SIZE)
throw new IOException("Failed to read full cluster");
return buffer;
}
public void WriteCluster(int clusterNumber, byte[] data)
{
if (!this.isOpen)
throw new InvalidOperationException("Disk is not open");
if (clusterNumber < 0 || clusterNumber >= CLUSTERS_NUMBER)
throw new ArgumentOutOfRangeException(nameof(clusterNumber), "Invalid cluster number");
if (data.Length != CLUSTER_SIZE)
throw new ArgumentException("Data must be exactly one cluster in size");
long offset = clusterNumber * CLUSTER_SIZE;
this.diskFileStream!.Seek(offset, SeekOrigin.Begin);
this.diskFileStream.Write(data, 0, CLUSTER_SIZE);
this.diskFileStream.Flush();
}
public long GetDiskSize()
{
return this.diskSize;
}
public void CloseDisk()
{
if (this.diskFileStream != null)
{
this.diskFileStream.Flush();
this.diskFileStream.Close();
this.diskFileStream = null;
}
this.isOpen = false;
}
}
}
Comments