diff --git a/source/SDFS Demo/Kernel.cs b/source/SDFS Demo/Kernel.cs deleted file mode 100644 index f48e0b1..0000000 --- a/source/SDFS Demo/Kernel.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Sys = Cosmos.System; - -namespace SDFS_Demo -{ - public class Kernel : Sys.Kernel - { - protected override void BeforeRun() - { - Console.WriteLine("Cosmos booted successfully. Type a line of text to get it echoed back."); - } - - protected override void Run() - { - Console.Write("Input: "); - var input = Console.ReadLine(); - Console.Write("Text typed: "); - Console.WriteLine(input); - } - } -} diff --git a/source/SDFS.sln b/source/SDFS.sln index ef3141a..709b437 100644 --- a/source/SDFS.sln +++ b/source/SDFS.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.28306.52 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SDFS Demo", "SDFS Demo\SDFS Demo.csproj", "{12BDB11A-DDC1-4EBE-A4D4-CDE925AB599B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SDFS_Demo", "SDFS_Demo\SDFS_Demo.csproj", "{12BDB11A-DDC1-4EBE-A4D4-CDE925AB599B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SDFS", "SDFS\SDFS.csproj", "{7992A7ED-E612-4D4D-A6A7-4064ADEB90B4}" EndProject diff --git a/source/SDFS/IO.cs b/source/SDFS/IO.cs new file mode 100644 index 0000000..c2e41bc --- /dev/null +++ b/source/SDFS/IO.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Generic; +using System.Text; +using SDFS_Directory = SDFS.Logical.Entries.Directory; +using SDFS_File = SDFS.Logical.Entries.File; +using SDFS.Logical.Entries; +using SDFS.Logical; + + +namespace SDFS.IO +{ + public class Directory + { + private static Logical.Entries.Directory sf; + + /// + /// Creates the specified directory + /// + /// + public static void Create(string directory) + { + Filesystem.cFS.Root.AddDirectory(directory); + sf = Filesystem.cFS.Root.GetDirectoryByName(directory); + if (sf == null) + { + // Cannot create required files, aborting creation of directory + throw new Exception("Failed creation of directory."); + } + } + + /// + /// Creates the specified directory + /// + /// + public static void Remove(string directory) + { + SDFS_Directory dir = Filesystem.cFS.Root.GetDirectoryByName(directory); + if (dir != null) + { + Filesystem.cFS.Root.RemoveDirectory(directory); + } + else + { + // Cannot create required files, aborting creation of directory + throw new Exception("Failed deletion of directory."); + } + } + } + + public class File + { + /// + /// Creates the specified file + /// + /// + /// + public static void Create(string file, string directory) + { + SDFS_Directory dir = Filesystem.cFS.Root.GetDirectoryByName(directory); + if (dir != null) + { + dir.AddFile(file); + SDFS_File nf = dir.RetrieveFileByName(file); + if (nf == null) + { + throw new Exception("Could not create!"); + } + + } + else + { + throw new ArgumentException("Bad directory"); + } + } + + public static void Delete(string file, string directory) + { + SDFS_Directory dir = Filesystem.cFS.Root.GetDirectoryByName(directory); + if (dir != null) + { + SDFS_File mFile = dir.RetrieveFileByName(file); + if (mFile != null) + { + dir.RemoveFile(file); + } + else + { + throw new Exception("Could not delete file!"); + } + } + } + + /// + /// Writes the specified byte array into the specified path and filename + /// if the file doesn't exist - create it + /// + /// + /// + /// + public static void WriteAllBytes(string file, string directory, byte[] data) + { + SDFS_Directory dir = Filesystem.cFS.Root.GetDirectoryByName(directory); + if (dir != null) + { + dir.AddFile(file); + SDFS_File nf = dir.RetrieveFileByName(file); + if (nf == null) + { + throw new Exception("Could not create!"); + } + else + { + nf.WriteAllBytes(data); + } + + } + else + { + throw new ArgumentException("Bad directory"); + } + } + /// + /// Writes the specified string into the specified path and filename + /// if the file doesn't exist - create it + /// + /// + /// + /// + public static void WriteAllText(string file, string directory, string data) + { + SDFS_Directory dir = Filesystem.cFS.Root.GetDirectoryByName(directory); + if (dir != null) + { + dir.AddFile(file); + SDFS_File nf = dir.RetrieveFileByName(file); + if (nf == null) + { + throw new Exception("Could not create!"); + } + else + { + nf.WriteAllText(data); + } + + } + else + { + throw new ArgumentException("Bad directory"); + } + } + + + + /// + /// Writes the specified byte array into the specified path and filename + /// if the file doesn't exist - create it + /// + /// + /// + /// + public static byte[] ReadAllBytes(string file, string directory) + { + SDFS_Directory dir = Filesystem.cFS.Root.GetDirectoryByName(directory); + if (dir != null) + { + dir.AddFile(file); + SDFS_File nf = dir.RetrieveFileByName(file); + if (nf == null) + { + throw new Exception("Could not read!"); + } + else + { + return nf.ReadAllBytes(); + } + + } + else + { + throw new ArgumentException("Bad directory"); + } + } + /// + /// Writes the specified string into the specified path and filename + /// if the file doesn't exist - create it + /// + /// + /// + /// + public static string ReadAllText(string file, string directory) + { + SDFS_Directory dir = Filesystem.cFS.Root.GetDirectoryByName(directory); + if (dir != null) + { + dir.AddFile(file); + SDFS_File nf = dir.RetrieveFileByName(file); + if (nf == null) + { + throw new Exception("Could not create!"); + } + else + { + return nf.ReadAllText(); + } + + } + else + { + throw new ArgumentException("Bad directory"); + } + } + } +} diff --git a/source/SDFS/Logical/Block.cs b/source/SDFS/Logical/Block.cs index cebdf92..56e98da 100644 --- a/source/SDFS/Logical/Block.cs +++ b/source/SDFS/Logical/Block.cs @@ -1,10 +1,234 @@ using System; using System.Collections.Generic; using System.Text; +using SDFS.Physical; +using Cosmos.HAL.BlockDevice; namespace SDFS.Logical { public class Block { + /// + /// Maxmimum size of content which a Block can contain + /// + public static uint MaxBlockContentSize = 491; + + /// + /// This block's filesystem partition (private) + /// + private Partition _Partition; + + /// + /// Block number (private) + /// + private ulong _blockNo = 0; + + /// + /// Boolean value - is this block in use? + /// + private bool _Used = false; + + /// + /// Content size of the block + /// + private uint _cSize = 0; + + /// + /// Total size of the block (private) + /// + private ulong _tSize = 0; + + /// + /// Next available block allocation + /// + private ulong _nBlock = 0; + + /// + /// The partition holding the block + /// + public Partition mPartition + { + get + { + return _Partition; + } + } + + /// + /// The number of the current block + /// + public ulong BlockNumber + { + get + { + return _blockNo; + } + } + + /// + /// Bool whether block used or not used + /// + public bool Used + { + get + { + return _Used; + } + set + { + _Used = value; + } + } + + /// + /// The current content size + /// + public uint ContentSize + { + get + { + return _cSize; + } + set + { + _cSize = value; + } + } + + /// + /// Total size of the Entry + /// + public ulong TotalSize + { + get + { + return _tSize; + } + set + { + _tSize = value; + } + } + + /// + /// The next block number to read al the content + /// + public ulong NextBlock + { + get + { + return _nBlock; + } + set + { + _nBlock = value; + } + } + + /// + /// The Content Byte Array. TO-DO: code this better + /// + public Byte[] Content; + + /// + /// Creates a new virtual Block. + /// + /// The Byte data + /// The partition to use + /// The block number + public Block(Byte[] Data, Partition p, ulong bn) + { + _blockNo = bn; + _Partition = p; + Content = new Byte[Data.Length - 21]; + if (Data[0] == 0x00) + { + _Used = false; + for (int i = 0; i < Content.Length; i++) + { + Content[i] = 0; + } + } + else + { + _Used = true; + _cSize = BitConverter.ToUInt32(Data, 1); + _tSize = BitConverter.ToUInt64(Data, 5); + _nBlock = BitConverter.ToUInt64(Data, 13); + for (int i = 21; i < Data.Length; i++) + { + Content[i - 21] = Data[i]; + } + } + } + + /// + /// The + /// + /// The partition to read + /// The blocknumber to read + public static Block Read(Partition p, ulong bn) + { + Byte[] data = p.NewBlockArray(1); + p.ReadBlock(bn, 1, data); + return new Block(data, p, bn); + } + + /// + /// Writes a block into a specific partition + /// + /// The partition to write to + /// The block to write + public static void Write(Partition p, Block b) + { + Byte[] data = new Byte[p.BlockSize]; + int index = 0; + if (b.Used) + { + data[index++] = 0x01; + } + else + { + data[index++] = 0x00; + } + Byte[] x = BitConverter.GetBytes(b.ContentSize); + for (int i = 0; i < x.Length; i++) + { + data[index++] = x[i]; + } + x = BitConverter.GetBytes(b.TotalSize); + for (int i = 0; i < x.Length; i++) + { + data[index++] = x[i]; + } + x = BitConverter.GetBytes(b.NextBlock); + for (int i = 0; i < x.Length; i++) + { + data[index++] = x[i]; + } + x = b.Content; + for (int i = 0; i < x.Length; i++) + { + data[index++] = x[i]; + } + p.WriteBlock(b.BlockNumber, 1, data); + } + + /// + /// Get the next free block from the selected partition (TO-DO: Implement something that runs faster) + /// + /// The partition to get the block from + public static Block GetFreeBlock(Partition p) + { + for (ulong i = 1; i < p.BlockCount; i++) + { + Block b = Read(p, i); + if (!b.Used) + { + return b; + } + } + return null; + } } } diff --git a/source/SDFS/Logical/Entries/Directory.cs b/source/SDFS/Logical/Entries/Directory.cs index 86f082b..80932e4 100644 --- a/source/SDFS/Logical/Entries/Directory.cs +++ b/source/SDFS/Logical/Entries/Directory.cs @@ -1,10 +1,450 @@ using System; using System.Collections.Generic; using System.Text; +using Cosmos.HAL.BlockDevice; +using SDFS.Physical; namespace SDFS.Logical.Entries { public class Directory : Entry { + /// + /// The full path (path+Name) of the current Directory + /// + public String DirectoryName + { + get + { + return Filesystem.ConcatDirectory(_path, Name); + } + } + + /// + /// Creates a new Directory Object + /// + /// The partition to use + /// The block number we want to use + /// The path of the new directory + public Directory(Partition partition, ulong blockNumber, String path) + { + _path = path; + _partition = partition; + sBlock = Block.Read(partition, blockNumber); + if (blockNumber == 1 && path == "/" && sBlock.Content[0] != '/') + { + Char[] nm = "/".ToCharArray(); + for (int i = 0; i < nm.Length; i++) + { + sBlock.Content[i] = (byte)nm[i]; + } + sBlock.Used = true; + sBlock.NextBlock = 0; + Block.Write(partition, sBlock); + } + if (!sBlock.Used) + { + sBlock.Used = true; + String n = "New Directory"; + if (path == Filesystem.Separator) + { + _path = ""; + n = path; + } + CreateEntry(partition, sBlock, n); + } + } + + /// + /// + /// + /// + public Directory[] RetrieveDirectories() + { + Block curb = sBlock; + List d = new List(); + while (curb.NextBlock != 0) + { + int index = 0; + curb = Block.Read(sBlock.mPartition, sBlock.NextBlock); + while (index < curb.ContentSize) + { + ulong a = BitConverter.ToUInt64(curb.Content, index); + index += 8; + uint sep = BitConverter.ToUInt32(curb.Content, index); + index += 4; + if (sep == 1) + { + d.Add(new Directory(_partition, a, Filesystem.ConcatDirectory(_path, Name))); + } + } + } + return d.ToArray(); + } + + /// + /// + /// + /// + public File[] RetrieveFiles() + { + Block curb = sBlock; + List d = new List(); + while (curb.NextBlock != 0) + { + int index = 0; + curb = Block.Read(sBlock.mPartition, sBlock.NextBlock); + while (index < curb.ContentSize) + { + ulong a = BitConverter.ToUInt64(curb.Content, index); + index += 8; + uint sep = BitConverter.ToUInt32(curb.Content, index); + index += 4; + if (sep == 1) + { + d.Add(new File(_partition, a, Filesystem.ConcatDirectory(_path, Name))); + } + } + } + return d.ToArray(); + } + + /// + /// Retrieves the entries stored in the directory + /// + /// + public Entry[] RetrieveEntries() + { + Block edge = sBlock; + List entries = new List(); + while (edge.NextBlock != 0) + { + int index = 0; + edge = Block.Read(sBlock.mPartition, sBlock.NextBlock); + while (index < edge.ContentSize) + { + ulong a = BitConverter.ToUInt64(edge.Content, index); + index += 8; + uint sep = BitConverter.ToUInt32(edge.Content, index); + index += 4; + if (sep == 1) + { + entries.Add(new Directory(_partition, a, Filesystem.ConcatDirectory(_path, Name))); + } + else if (sep == 2) + { + entries.Add(new File(_partition, a, Filesystem.ConcatDirectory(_path, Name))); + } + } + } + return entries.ToArray(); + } + + + /// + /// Creates a new File to the current directory + /// + /// The new File's name + public void AddFile(String Name) + { + Entry[] dirs = RetrieveEntries(); + for (int i = 0; i < dirs.Length; i++) + { + if (dirs[i].Name == Name) + { + // Entry with same Name already exists! + return; + } + } + Block curb = EditBlock(); + Block newfileb = CreateEntry(_partition, Name); + //if (newfileb != null) + //{ + BitConverter.GetBytes(newfileb.BlockNumber).CopyTo(curb.Content, curb.ContentSize); + BitConverter.GetBytes((uint)2).CopyTo(curb.Content, curb.ContentSize + 8); + curb.ContentSize += 12; + Block.Write(_partition, curb); + EditAttributes(EntryAttribute.DtM, UtilityMethods.UNIXTimeStamp); + EditAttributes(EntryAttribute.DtA, UtilityMethods.UNIXTimeStamp); + //} + } + + /// + /// Permits to remove a Directory by passing it's name + /// + /// The Directory's name to remove + public void RemoveDirectory(String Name) + { + Directory[] dirs = RetrieveDirectories(); + bool found = false; + int index = 0; + for (int i = 0; i < dirs.Length; i++) + { + if (dirs[i].Name == Name) + { + index = i; + found = true; + break; + } + } + if (found) + { + RemoveDirectory(dirs[index]); + } + } + + /// + /// Permits to remove a Directory by passing it + /// + /// The Directory to remove + private void RemoveDirectory(Directory Directory) + { + Directory[] subdirs = Directory.RetrieveDirectories(); + for (int i = 0; i < subdirs.Length; i++) + { + Directory.RemoveDirectory(subdirs[i]); + } + File[] subfiles = Directory.RetrieveFiles(); + for (int i = 0; i < subdirs.Length; i++) + { + Directory.RemoveFile(subfiles[i].Name); + } + Filesystem.Clean(Directory.sBlock); + DeleteBlock(Directory.sBlock); + } + + /// + /// Permits to remove a File by passing it's name + /// + /// The File's name to remove + public void RemoveFile(String Name) + { + File[] files = RetrieveFiles(); + bool found = false; + int index = 0; + for (int i = 0; i < files.Length; i++) + { + if (files[i].Name == Name) + { + index = i; + found = true; + break; + } + } + if (found) + { + Filesystem.Clean(files[index].StartBlock); + DeleteBlock(files[index].StartBlock); + } + } + + /// + /// Permits to remove a Block by passing it + /// + /// The Block to remove + private void DeleteBlock(Block FSBlock) + { + Block curb = sBlock; + while (curb.NextBlock != 0) + { + int index = 0; + bool found = false; + List cont = new List(); + curb = Block.Read(sBlock.mPartition, sBlock.NextBlock); + while (index < curb.ContentSize) + { + ulong a = BitConverter.ToUInt64(curb.Content, index); + Byte[] app = BitConverter.GetBytes(a); + for (int i = 0; i < app.Length; i++) + { + cont.Add(app[i]); + } + index += 8; + uint sep = BitConverter.ToUInt32(curb.Content, index); + index += 4; + if (a == FSBlock.BlockNumber) + { + app = BitConverter.GetBytes((uint)0); + for (int i = 0; i < app.Length; i++) + { + cont.Add(app[i]); + } + found = true; + } + else + { + app = BitConverter.GetBytes(sep); + for (int i = 0; i < app.Length; i++) + { + cont.Add(app[i]); + } + } + } + if (found) + { + curb.Content = cont.ToArray(); + curb.ContentSize = (uint)cont.Count; + Block.Write(_partition, curb); + } + } + } + + public void AddDirectory(String Name) + { + Entry[] directories = RetrieveEntries(); + for (int i = 0; i < directories.Length; i++) + { + if (directories[i].Name == Name) + { + // The directory already exists! + return; + } + } + Block edge = EditBlock(); + Block nDirB = CreateEntry(_partition, Name); + BitConverter.GetBytes(nDirB.BlockNumber).CopyTo(edge.Content, edge.ContentSize); + BitConverter.GetBytes((uint)1).CopyTo(edge.Content, edge.ContentSize + 8); + edge.ContentSize += 12; + Block.Write(_partition, edge); + EditAttributes(EntryAttribute.DtM, UtilityMethods.UNIXTimeStamp); + EditAttributes(EntryAttribute.DtA, UtilityMethods.UNIXTimeStamp); + } + + + /// + /// Gets the last Block of the directory + /// + private Block EditBlock() + { + Block ret = sBlock; + while (ret.NextBlock != 0) + { + ret = Block.Read(sBlock.mPartition, sBlock.NextBlock); + } + if (ret.BlockNumber == sBlock.BlockNumber) + { + ret = Block.GetFreeBlock(_partition); + ret.Used = true; + ret.ContentSize = 0; + ret.NextBlock = 0; + sBlock.NextBlock = ret.BlockNumber; + Block.Write(_partition, sBlock); + Block.Write(_partition, ret); + } + if (_partition.NewBlockArray(1).Length - ret.ContentSize < 12) + { + Block block = Block.GetFreeBlock(_partition); + if (block == null) + { + return null; + } + ret.NextBlock = block.BlockNumber; + Block.Write(_partition, ret); + block.Used = true; + ret = block; + } + return ret; + } + + /// + /// Get the directory specified by the Fullname passed + /// + /// The fullname of the directory + public static Directory GetDirectoryByFullName(String fn) + { + Directory dir = Filesystem.cFS.Root; + if (fn == dir.Name) + { + return dir; + } + if (fn == null || fn == "") + { + return null; + } + String[] names = fn.Split('/'); + if (names[0] != "") + { + return null; + } + for (int i = 0; i < names.Length; i++) + { + if (names[i] != null && names[i] != "") + { + dir = dir.GetDirectoryByName(names[i]); + if (dir == null) + { + break; + } + } + } + return dir; + } + + /// + /// Get the directory specified by the Name passed + /// + /// The name of the child directory + public Directory GetDirectoryByName(String n) + { + Directory[] dirs = RetrieveDirectories(); + for (int i = 0; i < dirs.Length; i++) + { + if (dirs[i].Name == n) + { + return dirs[i]; + } + } + return null; + } + + /// + /// Overrides the ToString Method. + /// + public override String ToString() + { + return this.Name; + } + + /// + /// Get the directory specified by the Fullname passed + /// + /// The fullname of the directory + public static File GetFileByFullName(String fn) + { + Directory dir = new Directory(Filesystem.cFS.mPartition, 1, Filesystem.Separator); + if (fn == null || fn == "") + { + return null; + } + String[] names = fn.Split('/'); + for (int i = 0; i < names.Length - 1; i++) + { + if (names[i] != "") + { + dir = dir.GetDirectoryByName(names[i]); + if (dir == null) + { + break; + } + } + } + return dir.RetrieveFileByName(names[names.Length - 1]); + } + + /// + /// Get the file specified by the Name passed + /// + /// The name of the child file + public File RetrieveFileByName(String n) + { + File[] files = RetrieveFiles(); + for (int i = 0; i < files.Length; i++) + { + if (files[i].Name == n) + { + return files[i]; + } + } + return null; + } } } diff --git a/source/SDFS/Logical/Entries/Entry.cs b/source/SDFS/Logical/Entries/Entry.cs index c565379..8597051 100644 --- a/source/SDFS/Logical/Entries/Entry.cs +++ b/source/SDFS/Logical/Entries/Entry.cs @@ -1,10 +1,194 @@ using System; using System.Collections.Generic; using System.Text; +using Cosmos.HAL.BlockDevice; +using SDFS.Physical; namespace SDFS.Logical.Entries { + /// + /// Modifiable attributes of filesystem entries + /// + public enum EntryAttribute + { + /// + /// Date/Time Created + /// + DtC = 0x00, + + /// + /// Date/Time Modified + /// + DtM = 0x08, + + /// + /// Date/Time Last Accessed + /// + DtA = 0x10, + + /// + /// Owner + /// + OwR = 0x18, + + /// + /// Group + /// + GoP = 0x20, + + /// + /// Visisibility + /// + HdN = 0x28, + + /// + /// Read/Write Permissions + /// + ReW = 0x29, + + /// + /// Owner Permissions + /// + OwP = 0x30, + + /// + /// Group Permissions + /// + GrP = 0x3a, + + /// + /// Global Permissions + /// + GlP = 0x3b + } + public class Entry { + /// + /// Char[] array of characters that are invalid for use in files/directories + /// + protected static Char[] UnacceptableChars = new char[] { '/', '?', '*' }; + + /// + /// The starting block of this FileSystem entry + /// + protected Block sBlock; + + /// + /// The filesystem path of the entry + /// + protected String _path; + + /// + /// The partition upon which the entry resides + /// + protected Partition _partition; + + /// + /// The maximum length a filename can be + /// + private static int MaxFNL = 255; + + /// + /// Retrieves the start block + /// + public Block StartBlock + { + get + { + return sBlock; + } + } + + /// + /// Path of the FS entry + /// + public String Path + { + get + { + return _path; + } + } + + /// + /// Returns the FileSystem entryname + /// + public String Name + { + get + { + Byte[] arr = sBlock.Content; + String ret = ""; + for (int i = 0; i < MaxFNL; i++) + { + if (arr[i] == 0) + { + break; + } + ret += ((Char)arr[i]).ToString(); + } + return ret; + } + } + + /// + /// Sets the entry's attributes to the specified + /// + /// + /// + public void EditAttributes(EntryAttribute Attrib, long value) + { + if (Attrib < EntryAttribute.HdN) + { + UtilityMethods.CopyByteToByte(BitConverter.GetBytes(value), 0, sBlock.Content, MaxFNL + (int)Attrib, 8, false); + } + else + { + UtilityMethods.CopyByteToByte(BitConverter.GetBytes(value), 0, sBlock.Content, MaxFNL + (int)Attrib, 1, false); + } + } + + /// + /// Creates a new FS entry at the specified partititon block + /// + /// + /// + /// + /// + protected static Block CreateEntry(Partition _part, Block block, String name) + { + if (block != null && ((!UtilityMethods.StringContains(name, UnacceptableChars)) || block.BlockNumber == 0)) + { + block.Used = true; + block.NextBlock = 0; + block.TotalSize = 0; + char[] nm = name.ToCharArray(); + for (int i = 0; i < nm.Length; i++) + { + block.Content[i] = (byte)nm[i]; + } + if (block.BlockNumber != 0) + { + UtilityMethods.CopyByteToByte(BitConverter.GetBytes(UtilityMethods.UNIXTimeStamp), 0, block.Content, MaxFNL + (int)EntryAttribute.DtC, 8, false); + } + block.Content[nm.Length] = 0; + block.ContentSize = (uint)nm.Length; + Block.Write(_part, block); + return block; + } + return null; + } + + /// + /// Creates a new FS entry at the next available partition block + /// + /// + /// + /// + protected static Block CreateEntry(Partition _part, String name) + { + return CreateEntry(_part, Block.GetFreeBlock(_part), name); + } } } diff --git a/source/SDFS/Logical/Entries/File.cs b/source/SDFS/Logical/Entries/File.cs index bb221a6..014c982 100644 --- a/source/SDFS/Logical/Entries/File.cs +++ b/source/SDFS/Logical/Entries/File.cs @@ -1,10 +1,127 @@ using System; using System.Collections.Generic; -using System.Text; +using Cosmos.HAL.BlockDevice; namespace SDFS.Logical.Entries { public class File : Entry { + /// + /// The full path (path + filename) of the current file + /// + public String Filename + { + get + { + return Filesystem.ConcatDirectory(_path, Name); + } + } + + /// + /// Writes the specified byte array into the file + /// + /// + public void WriteAllBytes(Byte[] Data) + { + if (sBlock.NextBlock != 0) + { + Filesystem.Clean(sBlock); + sBlock.NextBlock = 0; + Block.Write(Filesystem.cFS.mPartition, sBlock); + } + int index = 0; + Block edge = Block.GetFreeBlock(Filesystem.cFS.mPartition); + sBlock.NextBlock = edge.BlockNumber; + Block.Write(_partition, sBlock); + do + { + Byte[] arr = new byte[Block.MaxBlockContentSize]; + index = UtilityMethods.CopyByteToByte(Data, index, arr, 0, arr.Length); + edge.Used = true; + edge.Content = arr; + if (index != Data.Length) + { + Block fB = Block.GetFreeBlock(Filesystem.cFS.mPartition); + edge.NextBlock = fB.BlockNumber; + edge.ContentSize = (uint)arr.Length; + Block.Write(Filesystem.cFS.mPartition, edge); + edge = fB; + } + else + { + edge.ContentSize = (uint)(Data.Length % arr.Length); + Block.Write(Filesystem.cFS.mPartition, edge); + } + } + while (index != Data.Length); + EditAttributes(EntryAttribute.DtM, UtilityMethods.UNIXTimeStamp); + EditAttributes(EntryAttribute.DtA, UtilityMethods.UNIXTimeStamp); + } + + /// + /// Converts the specified text into a byte[] array, and writes the bytes to the file entry (WriteAllBytes()) + /// + /// + public void WriteAllText(String txt) + { + Byte[] tB = new byte[txt.Length]; + UtilityMethods.CopyCharToByte(txt.ToCharArray(), 0, tB, 0, txt.Length); + WriteAllBytes(tB); + } + + /// + /// Returns the bytes stored in the file entry + /// + /// + public Byte[] ReadAllBytes() + { + if (sBlock.NextBlock == 0) + { + return new byte[0]; + } + Block b = sBlock; + List bL = new List(); + while (b.NextBlock != 0) + { + b = Block.Read(b.mPartition, b.NextBlock); + for (int i = 0; i < b.ContentSize; i++) + { + bL.Add(b.Content[i]); + } + } + EditAttributes(EntryAttribute.DtA, UtilityMethods.UNIXTimeStamp); + return bL.ToArray(); + } + + /// + /// Converts the file entry's bytes into a string, and returns it + /// + /// + public string ReadAllText() + { + Byte[] b = ReadAllBytes(); + Char[] txt = new char[b.Length]; + UtilityMethods.CopyByteToChar(b, 0, txt, 0, b.Length); + return UtilityMethods.CharToString(txt); + } + + /// + /// FS File object constructor + /// + /// + /// + /// + public File(Partition part, ulong blockNumber, String path) + { + _path = path; + _partition = part; + sBlock = Block.Read(part, blockNumber); + if (!sBlock.Used) + { + sBlock.Used = true; + String name = "New File"; + CreateEntry(_partition, sBlock, name); + } + } } } diff --git a/source/SDFS/Logical/Filesystem.cs b/source/SDFS/Logical/Filesystem.cs index 5836486..5b98427 100644 --- a/source/SDFS/Logical/Filesystem.cs +++ b/source/SDFS/Logical/Filesystem.cs @@ -1,9 +1,324 @@ using System; +using SDFS.Physical; +using Cosmos.HAL.BlockDevice; +using SDFS.Logical.Entries; namespace SDFS.Logical { public class Filesystem { - + public Directory Root + { + get + { + return new Directory(_Partition, 1, Separator); + } + } + + /// + /// Concatenates a file and it's path location, resulting in full path + /// + /// + /// + /// Full path location of file + public static string ConcatFile(string path, string fname) + { + String file = ""; + file = path.TrimEnd(Separator.ToCharArray()); + if (file == null) + { + file = ""; + } + if (fname != Separator) + { + file += file += Separator + fname; + } + else + { + file = Separator; + } + return file; + } + + /// + /// Concatenates a directory and it's path location, resulting in full path + /// + /// + /// + /// Full path location of directory + public static string ConcatDirectory(string path, string dir) + { + String directory = ""; + directory = path.TrimEnd(Separator.ToCharArray()); + if (directory == null) + { + directory = ""; + } + if (dir != Separator) + { + directory += Separator + dir + Separator; + } + else + { + directory = Separator; + } + return directory; + } + + /// + /// The filesystem that is currently in use + /// + public static Filesystem cFS = null; + + /// + /// Constructor for a filesystem object + /// Runs test for valid FS on specified partition + /// + public Filesystem(Partition aPartition) + { + _Partition = aPartition; + Console.WriteLine("Checking for valid filesystem..."); + if (!IsValidFS()) + { + Console.WriteLine("Generating filesystem..."); + // If unable to detect a valid partition + if (!GenerateFS()) + { + // Error - unable to create a new filesystem on specified partition + throw new Exception("Unable to create a new filesystem on the specified partition"); + } + } + } + + /// + /// Separator character that splits files/directories from their parent directory. + /// + public static string Separator = "/"; + + /// + /// Property of the partition upon which this filesystem resides + /// + private Partition _Partition; + + private static byte[] fsSignature = new byte[] + { + 0x4D, + 0x65, + 0x64, + 0x6C, + 0x69, + 0x44, + 0x46, + 0x53 + }; + + /// + /// Public property of the partition upon which this filesystem resides + /// + public Partition mPartition + { + get + { + return _Partition; + } + } + + /// + /// Returns block size of this FileSystem's partition + /// + public ulong BlockSize + { + get + { + return _Partition.BlockSize; + } + } + + /// + /// Returns block count of this FileSystem's partition + /// + public ulong BlockCount + { + get + { + return _Partition.BlockCount; + } + } + + /// + /// Map a specified filesystem to the methods and properties of SDFS + /// + /// + public static void MapFilesystem (Filesystem fs) + { + cFS = fs; + } + + + /// + /// Generates a new FS block structure on specified filesystem + /// + /// + /// + private static bool GenerateFS(Partition part) + { + Console.WriteLine("Cleaning filesystem blocks..."); + Refresh(part, 10000); + Byte[] data = part.NewBlockArray(1); + fsSignature.CopyTo(data, 0); + Console.WriteLine("Writing filesystem signature\n"); + for (int i = 0; i < fsSignature.Length; i++) + { + data[i] = fsSignature[i]; + } + string MedliDFS = System.Text.Encoding.ASCII.GetString(fsSignature); + for (int i = 0; i < MedliDFS.Length; i++) + { + if (i != MedliDFS.Length) + { + Console.Write(MedliDFS.ToCharArray()[i] + ":"); + } + else + { + Console.Write(MedliDFS.ToCharArray()[i]); + } + + } + part.WriteBlock(0, 1, data); + return true; + } + + /// + /// Generates a new FS block structure on pre-set filesystem + /// + /// + /// + private bool GenerateFS() + { + Console.WriteLine("Cleaning filesystem blocks..."); + //Refresh(_Partition, 10000); + Byte[] data = _Partition.NewBlockArray(1); + //fsSignature.CopyTo(data, 0); + Console.WriteLine("Writing filesystem signature\n"); + for (int i = 0; i < fsSignature.Length; i++) + { + data[i] = fsSignature[i]; + } + string MedliDFS = System.Text.Encoding.ASCII.GetString(fsSignature); + for (int i = 0; i < MedliDFS.Length; i++) + { + if (i != MedliDFS.Length) + { + Console.Write(MedliDFS.ToCharArray()[i] + ":"); + } + else + { + Console.Write(MedliDFS.ToCharArray()[i]); + } + + } + _Partition.WriteBlock(0, 1, data); + return true; + } + + /// + /// Tests to see if partition object (_partition) contains a valid MDFS filesystem block structure (does the partition signature match the ASCII string 'MedliDFS') + /// + /// + public bool IsValidFS() + { + Byte[] data = _Partition.NewBlockArray(1); + for (int i = 0; i < fsSignature.Length; i++) + { + if (fsSignature[i] != data[i]) + { + return false; + } + } + return true; + } + + /// + /// Cleans a filesystem by a specified amount of blocks + /// (default is BlockCount) + /// + /// + public void Refresh(ulong sBlock = 0) + { + Byte[] data = _Partition.NewBlockArray(1); + for (int i = 0; i < data.Length; i++) + { + data[i] = 0; + } + // Proceeding to refresh the filesystem... + ulong lBlock = _Partition.BlockCount; + if (sBlock != 0) + { + lBlock = sBlock; + } + ulong rate = lBlock / 100; + uint perc = 0; + // perc + "% refreshed. " + (uint)lBlock + " blocks remaining. + for (ulong i = 0; i < lBlock; i++) + { + mPartition.WriteBlock(i, 1, data); + if (i % rate == 0) + { + perc++; + } + if (i % 32 == 0) + { + // perc + "% refreshed. " + ((uint)(lBlock - i)) + " blocks remaining. + } + } + // Successfully refreshed filesystem. + } + + /// + /// Cleans a filesystem by a specified amount of blocks + /// (default is BlockCount) + /// + /// + public static void Refresh(Partition aPartition, ulong sBlock = 0) + { + Byte[] data = aPartition.NewBlockArray(1); + for (int i = 0; i < data.Length; i++) + { + data[i] = 0; + } + // Proceeding to refresh the filesystem... + ulong lBlock = aPartition.BlockCount; + if (sBlock != 0) + { + lBlock = sBlock; + } + ulong rate = lBlock / 100; + uint perc = 0; + // perc + "% refreshed. " + (uint)lBlock + " blocks remaining. + for (ulong i = 0; i < lBlock; i++) + { + aPartition.WriteBlock(i, 1, data); + if (i % rate == 0) + { + perc++; + } + if (i % 32 == 0) + { + // perc + "% refreshed. " + ((uint)(lBlock - i)) + " blocks remaining. + } + } + // Successfully refreshed filesystem. + } + + public static void Clean(Block sBlock) + { + Block block = sBlock; + while (block.NextBlock != 0) + { + block = Block.Read(block.mPartition, block.NextBlock); + block.Used = false; + Block.Write(cFS.mPartition, block); + } + } } } diff --git a/source/SDFS/Physical/IDE.cs b/source/SDFS/Physical/IDE.cs index 0352f3c..aa44835 100644 --- a/source/SDFS/Physical/IDE.cs +++ b/source/SDFS/Physical/IDE.cs @@ -1,10 +1,140 @@ using System; using System.Collections.Generic; using System.Text; +using Cosmos.HAL.BlockDevice; namespace SDFS.Physical { public class IDE { + /// + /// List of ATA IDE Devices + /// + public static List Devices + { + get + { + List devs = new List(); + for (int i = 0; i < BlockDevice.Devices.Count; i++) + { + if (BlockDevice.Devices[i] is AtaPio) + { + IDE device = new IDE((AtaPio)BlockDevice.Devices[i]); + devs.Add(device); + } + } + return devs; + } + } + + /// + /// Retrieves this IDE device's size in megabytes + /// + public UInt32 Size + { + get + { + return (uint)(((this.BlockCount * this.BlockSize) / 1024) / 1024) + 1; + } + } + + /// + /// This object's IDE BlockDevice (ATA hard disk drive) + /// + private BlockDevice blockDevice; + + /// + /// Constructor for IDE + /// + /// + public IDE(AtaPio Device) + { + this.blockDevice = Device; + } + + /// + /// Returns this IDE device's block count + /// + public UInt64 BlockCount + { + get + { + return this.blockDevice.BlockCount; + } + } + + /// + /// Returns this IDE device's block size + /// + public UInt64 BlockSize + { + get + { + return this.blockDevice.BlockSize; + } + } + + /// + /// Retrieves a new byte array with a length of (num * BlockSize) + /// + /// + /// New byte[] Array + public Byte[] NewBlockArray(uint num) + { + return blockDevice.NewBlockArray(num); + } + + /// + /// Reads the specified amount of blocks from the BlockDevice + /// + /// Start block number + /// Number of blocks + /// Buffer to write to + public void ReadBlock(ulong aBlockNo, uint aBlockCount, byte[] aData) + { + blockDevice.ReadBlock(aBlockNo, aBlockCount, aData); + } + + /// + /// Writes the specified byte[] array to the specified block and number of blocks + /// + /// Start block number + /// Number of blocks + /// Buffer to write to + public void WriteBlock(ulong aBlockNo, uint aBlockCount, byte[] aData) + { + blockDevice.WriteBlock(aBlockNo, aBlockCount, aData); + } + + + public PrimaryPartition[] PrimaryPartitions + { + get + { + List l = new List(); + for (int i = 0; i < MBR.Partitions.Length; i++) + { + if (MBR.Partitions[i].SystemID != 0) + { + l.Add(new PrimaryPartition(blockDevice, MBR.Partitions[i].StartSector, MBR.Partitions[i].SectorCount, MBR.Partitions[i])); + } + } + return l.ToArray(); + } + } + + /// + /// Retrieves the master boot record of this class instance's BlockDevice + /// + public MBR MBR + { + get + { + Byte[] data = blockDevice.NewBlockArray(1); + this.blockDevice.ReadBlock(0, 1, data); + MBR m = new MBR(data, blockDevice); + return m; + } + } } } diff --git a/source/SDFS/Physical/MBR.cs b/source/SDFS/Physical/MBR.cs index 3f936f4..49333b7 100644 --- a/source/SDFS/Physical/MBR.cs +++ b/source/SDFS/Physical/MBR.cs @@ -1,10 +1,78 @@ using System; using System.Collections.Generic; using System.Text; +using Cosmos.HAL.BlockDevice; namespace SDFS.Physical { public class MBR { + /// + /// An array containing all patitions + /// + public PartitionObj[] Partitions + { + get + { + return mPartitions.ToArray(); + } + } + + /// + /// List of partitions found on the Master Boot Record + /// + private List mPartitions = new List(); + + /// + /// The block device on which this MBR resides + /// + private BlockDevice mBlockDevice; + + /// + /// Constructor for a Master Boot Record + /// + /// + /// + public MBR (Byte[] aMBR, BlockDevice aBlockDevice) + { + mBlockDevice = aBlockDevice; + UtilityMethods.CopyByteToByte(aMBR, 0, BootArray, 0, 440); + Signature = BitConverter.ToUInt32(aMBR, 440); + // Partition entries are located at MBR offsets 446, 462, 478 and 494 + // MBR only consists of 512 bytes + ReadPartitions(aMBR, 446); + ReadPartitions(aMBR, 462); + ReadPartitions(aMBR, 478); + ReadPartitions(aMBR, 494); + } + + /// + /// The Byte Array containing the bootable code and partition information of the MBR + /// + public readonly Byte[] BootArray = new Byte[440]; + + /// + /// The Disk signature + /// + public readonly UInt32 Signature = 0; + + /// + /// Reads the Master Boot Record for partition entries, and parses information such as sector count, block size and partition ID + /// + /// + /// + private void ReadPartitions(byte[] MBR, UInt32 aLocation) + { + byte xPartitionID = MBR[aLocation + 4]; + // A partition ID of 0 identifies an empty (null) partition + if (xPartitionID != 0) + { + UInt32 xStartSector = BitConverter.ToUInt32(MBR, (int)aLocation + 8); + UInt32 xSectorCount = BitConverter.ToUInt32(MBR, (int)aLocation + 12); + + var xPartitionObject = new PartitionObj(xPartitionID, xStartSector, xSectorCount, mBlockDevice.BlockSize); + mPartitions.Add(xPartitionObject); + } + } } } diff --git a/source/SDFS/Physical/Partitions.cs b/source/SDFS/Physical/Partitions.cs index b44ed0e..31d0171 100644 --- a/source/SDFS/Physical/Partitions.cs +++ b/source/SDFS/Physical/Partitions.cs @@ -4,7 +4,49 @@ namespace SDFS.Physical { - public class Partitions + public class PartitionObj { + /// + /// Constructor for a new partition + /// + /// + /// + /// + public PartitionObj(byte SysID, UInt32 startSector, UInt32 sectCount, UInt64 blockSize) + { + SystemID = SysID; + StartSector = startSector; + SectorCount = sectCount; + BlockSize = blockSize; + } + + /// + /// Returns the total size of this partition in megabytes + /// + public UInt32 TotalSize + { + get + { + return (uint)(((BlockSize * SectorCount) / 1024) / 1024); + } + } + + /// + /// Block size of this partition + /// + public readonly UInt64 BlockSize; + + /// + /// The partition's FS ID + /// + public readonly byte SystemID; + /// + /// The partition's starting sector + /// + public readonly UInt32 StartSector; + /// + /// The number of sectors in the partition + /// + public readonly UInt32 SectorCount; } } diff --git a/source/SDFS/Physical/PrimaryPartition.cs b/source/SDFS/Physical/PrimaryPartition.cs new file mode 100644 index 0000000..7d10fea --- /dev/null +++ b/source/SDFS/Physical/PrimaryPartition.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Cosmos.HAL.BlockDevice; + +namespace SDFS.Physical +{ + public class PrimaryPartition : Partition + { + /// + /// The primary partition's block device + /// + BlockDevice HostDevice; + + /// + /// The primary partition's starting sector + /// + ulong StartingSector; + + /// + /// Partition Information instance for this partition + /// + private PartitionObj _Partition; + + /// + /// Readonly public property for partition info instance + /// + public PartitionObj Info + { + get + { + return _Partition; + } + } + + /// + /// Constructor for a primary partition + /// + /// + /// + /// + /// + public PrimaryPartition(BlockDevice aHost, ulong aStartingSector, ulong aSectorCount, PartitionObj info) + : base(aHost, aStartingSector, aSectorCount) + { + HostDevice = aHost; + StartingSector = aStartingSector; + mBlockCount = aSectorCount; + mBlockSize = aHost.BlockSize; + _Partition = info; + } + + + /// + /// Reads the specified number of blocks from this partition + /// + /// Starting block number + /// Number of blocks to read + /// byte[] array to read to + public override void ReadBlock(ulong aBlockNo, ulong aBlockCount, byte[] aData) + { + UInt64 HostBlockNumber = StartingSector + aBlockNo; + CheckBlockNo(HostBlockNumber, aBlockCount); + HostDevice.ReadBlock(HostBlockNumber, aBlockCount, aData); + } + + /// + /// Writes the specified byte[] array to the specified block and number of blocks + /// + /// Starting block number + /// Number of blocks to write to + /// Byte[] array containing data to be written + public override void WriteBlock(ulong aBlockNo, ulong aBlockCount, byte[] aData) + { + UInt64 HostBlockNumber = StartingSector + aBlockNo; + CheckBlockNo(HostBlockNumber, aBlockCount); + HostDevice.WriteBlock(HostBlockNumber, aBlockCount, aData); + } + } +} diff --git a/source/SDFS/Physical/PrimaryPartitions.cs b/source/SDFS/Physical/PrimaryPartitions.cs deleted file mode 100644 index d4f2dc4..0000000 --- a/source/SDFS/Physical/PrimaryPartitions.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace SDFS.Physical -{ - public class PrimaryPartitions - { - } -} diff --git a/source/SDFS/SDFS.csproj b/source/SDFS/SDFS.csproj index 368944a..352df0e 100644 --- a/source/SDFS/SDFS.csproj +++ b/source/SDFS/SDFS.csproj @@ -2,11 +2,11 @@ Library - MDFS + SDFS netcoreapp2.0 - MDFS + SDFS diff --git a/source/SDFS/UtilityMethods.cs b/source/SDFS/UtilityMethods.cs index 0305574..d4aa448 100644 --- a/source/SDFS/UtilityMethods.cs +++ b/source/SDFS/UtilityMethods.cs @@ -6,5 +6,240 @@ namespace SDFS { public class UtilityMethods { + /// + /// Converts a byte array into a hexadecimal string + /// + /// + /// + public static String byteArrayToByteString(Byte[] inp) + { + Byte ch = 0x00; + String ret = ""; + + String[] pseudo = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "A", "B", "C", "D", "E", "F" }; + + for (int i = 0; i < inp.Length; i++) + { + ret += "0x"; + ch = (byte)(inp[i] & 0xF0); + ch = (byte)(ch >> 4); + ch = (byte)(ch & 0x0F); + + ret += pseudo[(int)ch].ToString(); + + ch = (byte)(inp[i] & 0x0F); + ret += pseudo[(int)ch].ToString(); + + ret += " "; + } + return ret; + } + + /// + /// Checks the specified string if it contains the specified char array + /// + /// + /// + /// + public static bool StringContains(String instr, char[] chars) + { + for (int i = 0; i < chars.Length; i++) + { + if (Contains(instr, chars[i])) + { + return true; + } + } + return false; + } + + /// + /// Checks the specified string if it contains the specified char + /// + /// + /// + /// + private static bool Contains(string instr, char p) + { + for (int i = 0; i < instr.Length; i++) + { + if (instr[i] == p) + { + return true; + } + } + return false; + } + + /// + /// Copies the contents of one byte array into another starting at the specified index + /// + /// + /// + /// + /// + /// + /// + public static int CopyByteToByte(byte[] Data, int DataIndex, byte[] Array, int ArrayIndex, int Length) + { + int i = 0; + int j = ArrayIndex; + for (i = DataIndex; i < Length + DataIndex && i < Data.Length; i++) + { + Array[j++] = Data[i]; + } + while (j < Length + ArrayIndex) + { + Array[j++] = 0; + } + return i; + } + + /// + /// Copies the contents of one byte array into another starting at the specified index + /// + /// + /// + /// + /// + /// + /// + /// + public static int CopyByteToByte(byte[] Data, int DataIndex, byte[] Array, int ArrayIndex, int Length, bool writeallzero) + { + int i = 0; + int j = ArrayIndex; + for (i = DataIndex; i < Length + DataIndex && i < Data.Length; i++) + { + Array[j++] = Data[i]; + } + while (writeallzero && j < Length + ArrayIndex) + { + Array[j++] = 0; + } + return i; + } + + /// + /// Copies the contents of a char array into a byte array + /// + /// + /// + /// + /// + /// + /// + public static int CopyCharToByte(Char[] Data, int dind, byte[] arr, int arrind, int many) + { + int i = 0; + int j = arrind; + for (i = dind; i < many && i < Data.Length; i++) + { + arr[j++] = (byte)Data[i]; + } + while (j < many) + { + arr[j++] = 0; + } + return i; + } + + /// + /// Copies the contents of a byte array into a char array + /// + /// + /// + /// + /// + /// + /// + public static int CopyByteToChar(byte[] Data, int dind, Char[] arr, int arrind, int many) + { + int i = 0; + int j = arrind; + for (i = dind; i < many && i < Data.Length; i++) + { + arr[j++] = (Char)Data[i]; + } + while (j < many) + { + arr[j++] = '\0'; + } + return i; + } + + /// + /// Converts a char[] array into a string and returns it + /// + /// + /// + public static string CharToString(char[] text) + { + String ret = ""; + for (int i = 0; i < text.Length; i++) + { + ret += text[i]; + } + return ret; + } + + /// + /// Currently date and time represented in a UNIX timestamp + /// + public static long UNIXTimeStamp + { + get + { + long ret = 0; + long secondsinyear = 31536000; + long secondsinday = 86400; + for (int i = 1970; i < DateTime.Now.Year - 1; i++) + { + ret += secondsinyear; + if ((i % 400 == 0 || (i % 4 == 0 && i % 100 != 0))) + { + ret += secondsinday; + } + } + for (int i = 1; i < DateTime.Now.Month - 1; i++) + { + ret += MonthToDays[i] * secondsinday; + if (i == 2 && (DateTime.Now.Year % 400 == 0 || (DateTime.Now.Year % 4 == 0 && DateTime.Now.Year % 100 != 0))) + { + ret += secondsinday; + } + } + ret += DateTime.Now.Day * secondsinday; + ret += DateTime.Now.Hour * 3600; + ret += DateTime.Now.Minute * 60; + ret += DateTime.Now.Second; + return ret; + } + } + + /// + /// Retrieves the number of days in each month + /// + private static int[] MonthToDays + { + get + { + List l = new List(); + l.Add(31); + l.Add(28); + l.Add(31); + l.Add(30); + l.Add(31); + l.Add(30); + l.Add(31); + l.Add(31); + l.Add(30); + l.Add(31); + l.Add(30); + l.Add(31); + return l.ToArray(); + } + } } } diff --git a/source/SDFS_Demo/DiskHandler.cs b/source/SDFS_Demo/DiskHandler.cs new file mode 100644 index 0000000..8c12c33 --- /dev/null +++ b/source/SDFS_Demo/DiskHandler.cs @@ -0,0 +1,433 @@ +/* + * + * + * This following source is licenced via the following: + * + * + * The Clear BSD License + + * Copyright (c) 2018, Siaranite Solutions, Medli + * All rights reserved. + + * Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of Siaranite Solutions nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. +THIS SOFTWARE IS PROVIDED BY SIARANITE SOLUTIONS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SIARANITE SOLUTIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +using System; +using System.Collections.Generic; +using SDFS.Physical; +using SDFS; + +namespace SDFS_Demo +{ + /// + /// Defines a disk listing + /// + public class DiskListing + { + /// + /// Static List of DiskListings + /// + public static List DiskListings = new List(); + + /// + /// Static List of PartitionListings + /// + public List PartitionListings = new List(); + + /// + /// The DiskListing's BlockDevice + /// + public IDE Disk; + + /// + /// The DiskListing's Disk Number + /// + public int DiskNumber; + + /// + /// Constructor for a Disk Listing + /// + /// + /// + public DiskListing(int num, IDE disk) + { + DiskNumber = num + 1; + Disk = disk; + DiskListings.Add(this); + int pnum = 0; + foreach (PrimaryPartition Partition in disk.PrimaryPartitions) + { + pnum += 1; + PartitionListings.Add(new PartitionListing(pnum, this, Partition.Info)); + } + } + + /// + /// String containing information about the Disk Listing + /// + public string Info + { + get + { + return ("Disk: " + DiskNumber + " Size: " + Disk.Size + " MBs"); + } + } + + public void PartInfo() + { + foreach (PartitionListing partition in PartitionListings) + { + Console.WriteLine(partition.Info); + } + } + + /// + /// Prints information about the DiskListing + /// + public void PrintInfo() + { + Console.WriteLine(Info); + } + } + + /// + /// Defines a partition listing + /// + public class PartitionListing + { + public DiskListing Disk; + public int PartNum; + public PartitionObj Partition; + public uint Size; + public byte ID; + + public PartitionListing(int num, DiskListing disk, PartitionObj part) + { + this.Disk = disk; + this.PartNum = num; + this.Partition = part; + this.Size = part.TotalSize; + this.ID = part.SystemID; + } + + public string Info + { + get + { + return ("Disk: " + this.Disk.DiskNumber + ", Partition: " + this.PartNum + ", Type: " + this.ID + ", Size: " + this.Size + "MBs"); + } + } + } + + /// + /// The Disk Utility class, containing methods and properties + /// + public class SDFSUtility + { + /// + /// Prints information about the currently selected disk, if any is selected + /// + public static void PrintSelectedDisk() + { + if (SelectedDisk != null) + { + + SelectedDisk.PrintInfo(); + } + else + { + Console.WriteLine("No disk is currently selected!"); + } + } + /// + /// Defines the selected DiskListing + /// + public static DiskListing SelectedDisk = null; + + /// + /// Main Disk Utility method, with the list of IDE devices passed as the parameter + /// TODO - Remove the requirement for the IDE array to be passed as array - or move detection to INIT1 + /// + /// + public static void Main(IDE[] List) + { + + bool running = true; + Console.BackgroundColor = ConsoleColor.Blue; + Console.Clear(); + Console.WriteLine("Welcome to the Medli File System Utility [MFSU]"); + Console.WriteLine(""); + while (running == true) + { + Console.WriteLine(""); + Console.WriteLine("1) List Disks 2) Select Disks 3) List Partitions\n4) Create Partitions 5) Exit disk utility"); + Console.WriteLine(""); + Console.Write(">"); + string option = Console.ReadLine().ToLower(); + if (option == "1") + { + ListDisks(); + } + else if (option == "2") + { + SelectDisk(); + } + else if (option == "3") + { + DiskPartInfo(); + } + else if (option == "4") + { + CreatePartitions(); + } + else if (option == "quit" || option == "exit" || option == "5") + { + running = false; + } + else + { + Console.WriteLine(option + ": Invalid option!"); + } + } + Console.Clear(); + } + /// + /// Selects a DiskListing from the list + /// + public static void SelectDisk() + { + SelectedDisk = null; + do + { + Console.WriteLine("Which disk do you wish to use?\n"); + ListDisks(); + string nums = Console.ReadLine(); + int num = int.Parse(nums) - 1; + if (num >= 0 && num < DiskListing.DiskListings.Count) + { + SelectedDisk = DiskListing.DiskListings[num]; + } + } + while (SelectedDisk == null); + } + + /// + /// Lists each of the disks from the list + /// + public static void ListDisks() + { + foreach (DiskListing disklist in DiskListing.DiskListings) + { + if (disklist == SelectedDisk) + { + Console.WriteLine("* " + disklist.Info); + } + else + { + disklist.PrintInfo(); + } + } + } + + /// + /// Lists the partitions in the specified disk + /// + /// + public static void DiskPartInfo() + { + if (SelectedDisk != null) + { + SelectedDisk.PartInfo(); + } + else + { + Console.WriteLine("No disk selected!\n"); + } + } + + //public static void ListPartitions(IDE Device) + //{ + // if (Device == null) + // { + // Console.WriteLine("No disk selected!\n"); + // } + // else + // { + // MBR mbr = Device.MBR; + // PartitionInfo[] partitions = mbr.Partitions; + // if ((partitions.Length > 0) && (partitions.Length <= 4)) + // { + // foreach (PartitionInfo part in partitions) + // { + // Console.WriteLine("Partition ID: " + part.SystemID + " Size: " + part.TotalSize + " MBs"); + // } + // } + // else + // { + // Console.WriteLine("No partitions detected!\n"); + // } + // } + //} + + + /// + /// Creates partitions on the selected disk + /// + public static void CreatePartitions() + { + if (SelectedDisk == null) + { + Console.WriteLine("No disk is currently selected!"); + } + else + { + int PartitionNumber = 0; + ulong DisplayCount = SelectedDisk.Disk.BlockCount - 1; + Console.WriteLine("How many primary partitions do you want to have? (Max. 4)"); + do + { + Console.WriteLine("Insert number"); + String nums = Console.ReadLine(); + PartitionNumber = int.Parse(nums); + } + while (PartitionNumber == 0 || PartitionNumber > 4); + + uint mbrpos = 446; + Byte[] type = new Byte[] { 0x00, 0x00, 0x00, 0x00 }; + uint[] StartBlock = new uint[] { 1, 0, 0, 0 }; + uint[] BlockNum = new uint[] { 0, 0, 0, 0 }; + for (int i = 0; i < PartitionNumber; i++) + { + type[i] = 0xFA; + Console.WriteLine("How many blocks for Partition N. " + (i + 1) + "? (Max: " + ((uint)(DisplayCount - (uint)(PartitionNumber - (i + 1)))).ToString() + "): "); + String nums = Console.ReadLine(); + uint num = (uint)int.Parse(nums); + if (num >= 0 && num <= DisplayCount - (uint)(PartitionNumber - (i + 1))) + { + BlockNum[i] = num; + if (i < PartitionNumber - 1) + { + StartBlock[i + 1] = (num) + StartBlock[i]; + } + DisplayCount = DisplayCount - (num); + } + else + { + i--; + } + } + Byte[] data = SelectedDisk.Disk.NewBlockArray(1); + SelectedDisk.Disk.ReadBlock(0, 1, data); + for (int i = 0; i < 4; i++) + { + mbrpos += 4; + data[mbrpos] = type[i]; + mbrpos += 4; + Byte[] b = BitConverter.GetBytes(StartBlock[i]); + UtilityMethods.CopyByteToByte(b, 0, data, (int)mbrpos, b.Length); + mbrpos += 4; + b = BitConverter.GetBytes(BlockNum[i]); + UtilityMethods.CopyByteToByte(b, 0, data, (int)mbrpos, b.Length); + mbrpos += 4; + SelectedDisk.Disk.WriteBlock(StartBlock[i], 1, SelectedDisk.Disk.NewBlockArray(1)); + } + SelectedDisk.Disk.WriteBlock(0, 1, data); + DiskPartInfo(); + } + } + + public static void CreatePartitions(IDE[] IDEs) + { + int PartitionNumber = 0; + ulong DisplayCount = SelectedDisk.Disk.BlockCount - 1; + Console.WriteLine("How many primary partitions do you want to have? (Max. 4)"); + Console.Write("Insert number:"); + do + { + String nums = Console.ReadLine(); + PartitionNumber = int.Parse(nums); + } + while (PartitionNumber == 0 || PartitionNumber > 4); + + uint mbrpos = 446; + Byte[] type = new Byte[] { 0x00, 0x00, 0x00, 0x00 }; + uint[] StartBlock = new uint[] { 1, 0, 0, 0 }; + uint[] BlockNum = new uint[] { 0, 0, 0, 0 }; + for (int i = 0; i < PartitionNumber; i++) + { + type[i] = 0xFA; + Console.Write("How many blocks for Partition N. " + (i + 1) + "? (Max: " + ((uint)(DisplayCount - (uint)(PartitionNumber - (i + 1)))).ToString() + "): "); + String nums = Console.ReadLine(); + uint num = (uint)int.Parse(nums); + if (num >= 0 && num <= DisplayCount - (uint)(PartitionNumber - (i + 1))) + { + BlockNum[i] = num; + if (i < PartitionNumber - 1) + { + StartBlock[i + 1] = (num) + StartBlock[i]; + } + DisplayCount = DisplayCount - (num); + } + else + { + i--; + } + } + Byte[] data = SelectedDisk.Disk.NewBlockArray(1); + SelectedDisk.Disk.ReadBlock(0, 1, data); + for (int i = 0; i < 4; i++) + { + mbrpos += 4; + data[mbrpos] = type[i]; + mbrpos += 4; + Byte[] b = BitConverter.GetBytes(StartBlock[i]); + UtilityMethods.CopyByteToByte(b, 0, data, (int)mbrpos, b.Length); + mbrpos += 4; + b = BitConverter.GetBytes(BlockNum[i]); + UtilityMethods.CopyByteToByte(b, 0, data, (int)mbrpos, b.Length); + mbrpos += 4; + SelectedDisk.Disk.WriteBlock(StartBlock[i], 1, SelectedDisk.Disk.NewBlockArray(1)); + } + SelectedDisk.Disk.WriteBlock(0, 1, data); + DiskPartInfo(); + } + } +} \ No newline at end of file diff --git a/source/SDFS_Demo/Kernel.cs b/source/SDFS_Demo/Kernel.cs new file mode 100644 index 0000000..e309ddc --- /dev/null +++ b/source/SDFS_Demo/Kernel.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Sys = Cosmos.System; +using SDFS; +using SDFS.Logical; +using SDFS.Physical; + +namespace SDFS_Demo +{ + public class Kernel : Sys.Kernel + { + public static Filesystem fs; + /// + /// Partition containing a valid SDFS partition + /// + private static PrimaryPartition workPartition = null; + + protected override void BeforeRun() + { + IDE[] IDEs = IDE.Devices.ToArray(); + for (int i = 0; i < IDEs.Length; i++) + { + new DiskListing(i, IDEs[i]); + } + + Console.WriteLine("Number of IDE disks: " + IDEs.Length); + Console.WriteLine("Looking for valid partitions..."); + for (int i = 0; i < IDEs.Length; i++) + { + PrimaryPartition[] parts = IDEs[i].PrimaryPartitions; + for (int j = 0; j < parts.Length; j++) + { + if (parts[j].Info.SystemID == 0xFA) + { + workPartition = parts[j]; + } + } + } + //#warning Revert to == null!!! + if (workPartition == null) + { + SDFSUtility.Main(IDEs); + Console.WriteLine("The machine needs to be restarted."); + Console.ReadKey(true); + Sys.Power.Reboot(); + } + + Console.Write("Checking FileSystem... "); + + try + { + fs = new Filesystem(workPartition); + } + catch (Exception ex) + { + Console.WriteLine("Error!" + ex.Message); + } + + Console.WriteLine("\n Size:" + workPartition.Info.TotalSize + "MBs"); + Console.WriteLine("Type: " + workPartition.Info.SystemID.ToString()); + + Console.ReadKey(true); + try + { + fs.Root.AddDirectory("Test"); + SDFS.IO.File.WriteAllText("test.txt", "Test", "Welcome to SDFS Filesystem"); + string ExampleString = SDFS.IO.File.ReadAllText("test.txt", "Test"); + + Console.WriteLine(ExampleString); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + Console.ReadKey(true); + } + + } + + protected override void Run() + { + Console.ReadKey(true); + } + } +} \ No newline at end of file diff --git a/source/SDFS Demo/SDFS Demo.csproj b/source/SDFS_Demo/SDFS_Demo.csproj similarity index 93% rename from source/SDFS Demo/SDFS Demo.csproj rename to source/SDFS_Demo/SDFS_Demo.csproj index 3dfd74f..5b57caa 100644 --- a/source/SDFS Demo/SDFS Demo.csproj +++ b/source/SDFS_Demo/SDFS_Demo.csproj @@ -22,6 +22,8 @@ VMware Use VMware Player or Workstation to deploy and debug. 192.168.0.8 + SDFS_Demo + SDFS_Demo