Cosmos/source/Cosmos.Kernel.FileSystems/Old/Ext2.cs
2008-06-05 22:18:12 +00:00

472 lines
16 KiB
C#

using System;
using Cosmos.Hardware.Storage;
using System.Collections.Generic;
using System.IO;
using Cosmos.FileSystem;
namespace Cosmos.Kernel.FileSystem {
public unsafe partial class Ext2 {
private class FileStream: Stream {
private uint mINodeNumber;
private Ext2 mFilesystem;
private uint mPosition = 0;
public FileStream(uint aINodeNumber, Ext2 aFilesystem) {
mINodeNumber = aINodeNumber;
mFilesystem = aFilesystem;
}
public override bool CanRead {
get {
return true;
}
}
public override bool CanSeek {
get {
return true;
}
}
public override bool CanWrite {
get {
return false;
}
}
public override void Flush() {
}
public override long Length {
get {
INode xINode;
mFilesystem.ReadINode(mINodeNumber, out xINode);
long xSize = xINode.Size;
return xSize;
}
}
public override long Position {
get {
return mPosition;
}
set {
mPosition = (uint)value;
}
}
// todo: add support for reading one chunk of data which spans multiple logical blocks
public override int Read(byte[] buffer, int offset, int count) {
uint xBlock = (mPosition / mFilesystem.mBlockSize);
if (xBlock != 0) {
return 0;
}
INode xINode;
if (!mFilesystem.ReadINode(mINodeNumber, out xINode)) {
return -1;
}
int xBytesToRead = count;
//byte* xBuffer = (byte*)Heap.MemAlloc(mFilesystem.mBlockSize);
byte* xBuffer = null;
while (xBytesToRead > 0) {
if (!mFilesystem.ReadINodeContents(&xINode, xBlock, xBuffer)) {
return -2;
}
uint xBufferOffset = mPosition % mFilesystem.mBlockSize;
for (int i = 0; i < count; i++) {
buffer[offset + i] = xBuffer[xBufferOffset + i];
}
xBytesToRead -= (int)(mFilesystem.mBlockSize - (mPosition % mFilesystem.mBlockSize));
xBlock++;
}
return count;
}
public override long Seek(long offset, SeekOrigin origin) {
if (origin == SeekOrigin.Begin)
mPosition = (uint)offset;
else if (origin == SeekOrigin.Current)
mPosition += (uint)offset;
else
mPosition = (uint)(Length + offset);
return mPosition;
}
public override void SetLength(long value) {
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count) {
throw new NotImplementedException();
}
}
private Partition mBackend;
private SuperBlock mSuperBlock;
private uint mBlockSize;
private uint mGroupsCount;
private uint mGroupDescriptorsPerBlock;
private GroupDescriptor[] mGroupDescriptors;
public const uint EXT2_ROOT_INO = 0x02;
public Ext2(Partition aBackend) {
if (aBackend == null) {
throw new ArgumentNullException("aBackend");
}
mBackend = aBackend;
}
private bool ReadSuperBlock() {
var xBytes = mBackend.ReadBlock(2);
fixed (byte* xByteBuff = &xBytes[0]) {
var xByteBuffAsSuperBlock = (SuperBlock*)xByteBuff;
mSuperBlock = xByteBuffAsSuperBlock[0];
// DebugUtil.SendExt2_SuperBlock("", mSuperBlock);
mBlockSize = (uint)(1024 << (byte)(mSuperBlock.LogBlockSize));
// DebugUtil.SendDoubleNumber("Numbers", "", mSuperBlock.INodesCount, 32, mSuperBlock.INodesPerGroup, 32);
mGroupsCount = mSuperBlock.INodesCount / mSuperBlock.INodesPerGroup;
mGroupDescriptorsPerBlock = (uint)(mBlockSize / sizeof(GroupDescriptor));
if (!ReadGroupDescriptorsOfBlock()) {
return false;
}
}
return true;
}
private unsafe bool ReadGroupDescriptorsOfBlock() {
byte[] xBytes;
mGroupDescriptors = new GroupDescriptor[mGroupsCount];
GroupDescriptor* xDescriptorPtr=(GroupDescriptor*)0;
for (int i = 0; i < mGroupsCount; i++) {
// DebugUtil.SendNumber("Ext2", "ReadGroupDescriptorsOfBlock, I", (uint)i, 16);
uint xATABlock = (uint)(mBlockSize / mBackend.BlockSize);
xATABlock += (uint)(i / mGroupDescriptorsPerBlock);
if ((i % 16) == 0) {
xBytes= mBackend.ReadBlock(xATABlock);
fixed (byte* xDescriptorPtr2 = &xBytes[0]) {
xDescriptorPtr = (GroupDescriptor*)xDescriptorPtr2;
}
}
//GroupDescriptor* xItem = (GroupDescriptor*)Heap.MemAlloc((uint)sizeof(GroupDescriptor));
//CopyPointers((byte*)&xDescriptorPtr[i % mGroupDescriptorsPerBlock], (byte*)xItem, (uint)sizeof(GroupDescriptor));
//mGroupDescriptors[i] = *xItem;
// DebugUtil.SendExt2_GroupDescriptor("ReadGroupDescriptorsOfBlock", xATABlock, i, 0, xDescriptorPtr[i % mGroupDescriptorsPerBlock]);
}
return true;
}
public bool Initialize() {
return ReadSuperBlock();
}
private static unsafe bool ConvertBitmapToBoolArray(uint* aBitmap, bool[] aArray) {
if (aArray == null || aArray.Length != 32) {
Console.WriteLine("[ConvertBitmapToBoolArray] Incorrect Array");
return false;
}
uint xValue = *aBitmap;
for (byte b = 0; b < 32; b++) {
uint xCheckBit = (uint)(1 << b);
aArray[b] = (xValue & xCheckBit) != 0;
}
return true;
}
private static void CopyPointers(byte* aSource, byte* aDest, uint aLength) {
for (int i = 0; i < aLength; i++) {
aDest[i] = aSource[i];
}
}
public Stream OpenFile(string[] xPath) {
//ushort* xBuffer = (ushort*)Heap.MemAlloc(mBackend.BlockSize);
//byte* xExt2BlockBuffer = (byte*)Heap.MemAlloc(mBlockSize);
//INode xCurrentINode;
//if (!ReadINode(EXT2_ROOT_INO, out xCurrentINode)) {
// Heap.MemFree((uint)xBuffer);
// Heap.MemFree((uint)xExt2BlockBuffer);
// return null;
//}
//bool xCurrentINodeChanged = true;
//uint xInspectedINodeCount = 0;
//uint xINodeNumber = EXT2_ROOT_INO;
//for (int i = 0; i < xPath.Length; i++) {
// Console.Write("ReadFile, Iteration ");
// ATAOld.WriteNumber((uint)i, 8);
// Console.WriteLine("");
// if (!xCurrentINodeChanged) {
// Console.WriteLine("Terminating for loop, CurrentINode didn't change");
// Heap.MemFree((uint)xBuffer);
// Heap.MemFree((uint)xExt2BlockBuffer);
// return null;
// }
// xCurrentINodeChanged = false;
// if (!ReadINodeContents(&xCurrentINode, 0, xExt2BlockBuffer)) {
// Heap.MemFree((uint)xBuffer);
// Heap.MemFree((uint)xExt2BlockBuffer);
// return null;
// }
// DirectoryEntry* xEntryPtr = (DirectoryEntry*)xExt2BlockBuffer;
// uint xTotalSize = mBlockSize;
// while (xTotalSize != 0) {
// DebugUtil.SendExt2_DirectoryEntry(xEntryPtr);
// uint xPtrAddress = (uint)xEntryPtr;
// char[] xName = new char[xEntryPtr->NameLength];
// byte* xNamePtr = &xEntryPtr->FirstNameChar;
// for (int c = 0; c < xName.Length; c++) {
// xName[c] = (char)xNamePtr[c];
// }
// xInspectedINodeCount++;
// if (EqualsName(xPath[i], xName)) {
// if (!ReadINode(xEntryPtr->INodeNumber, out xCurrentINode)) {
// Heap.MemFree((uint)xBuffer);
// Heap.MemFree((uint)xExt2BlockBuffer);
// return null;
// }
// xCurrentINodeChanged = true;
// xINodeNumber = xEntryPtr->INodeNumber;
// xTotalSize = 0;
// continue;
// }
// xPtrAddress += xEntryPtr->RecordLength;
// xTotalSize -= xEntryPtr->RecordLength;
// xEntryPtr = (DirectoryEntry*)xPtrAddress;
// }
//}
//if (xCurrentINodeChanged) {
// DebugUtil.SendMessage("Ext2", "ReadFile, for loop exited with an inode change");
//} else {
// DebugUtil.SendMessage("Ext2", "ReadFile, for loop exited without an inode change");
//}
//if ((xCurrentINode.Mode & INodeModeEnum.RegularFile) == 0) {
// Console.WriteLine("No file after for loop");
// return null;
//}
//Stream xResult = new FileStream(xINodeNumber, this);
//Heap.MemFree((uint)xBuffer);
//Heap.MemFree((uint)xExt2BlockBuffer);
//return xResult;
throw new Exception("Ext2 not supported");
}
private unsafe bool ReadINode(uint aINodeNumber, out INode aINode) {
//DebugUtil.SendNumber("Ext2", "reading INode", aINodeNumber, 32);
//aINodeNumber--;
//uint xGroup = aINodeNumber / mSuperBlock.INodesPerGroup;
//DebugUtil.SendNumber("Ext2", "xGroup", xGroup, 32);
//uint xIndex = (aINodeNumber % mSuperBlock.INodesPerGroup) * mSuperBlock.INodeSize;
//DebugUtil.SendNumber("Ext2", "xIndex", xIndex, 32);
//uint xOffset = xIndex % mBlockSize;
//DebugUtil.SendNumber("Ext2", "xOffset", xOffset, 32);
//uint xLogBlockNumber = mGroupDescriptors[xGroup].INodeTable;
//DebugUtil.SendNumber("Ext2", "InodeBitmap", mGroupDescriptors[xGroup].INodeBitmap, 32);
//DebugUtil.SendNumber("Ext2", "xLogBlockNumber(1)", xLogBlockNumber, 32);
//xLogBlockNumber += (xIndex / mBlockSize);
//DebugUtil.SendNumber("Ext2", "xLogBlockNumber(2)", xLogBlockNumber, 32);
//uint xPhBlockNumber = (xLogBlockNumber * mBlockSize) / mBackend.BlockSize;
uint xPhBlockNumber = 0;
//xPhBlockNumber += xIndex / mBackend.BlockSize;
//xIndex %= mBackend.BlockSize;
var xBytes = mBackend.ReadBlock(xPhBlockNumber);
//DebugUtil.SendNumber("Ext2", "BlockOffset", xIndex, 32);
//fixed (byte* xINodePtr = &xBytes[xIndex]) {
fixed (byte* xINodePtr = &xBytes[0]) {
aINode = *(INode*)xINodePtr;
}
return true;
}
/// <summary>
/// Reads the logical block at index <paramref name="aBlock"/>. Make sure the buffer is of the correct size
/// </summary>
private bool ReadINodeContents(INode* aINode, uint aBlock, byte* aBuffer) {
uint xBlock;
switch (aBlock) {
case 0:
xBlock = aINode->Block1;
break;
case 1:
xBlock = aINode->Block2;
break;
case 2:
xBlock = aINode->Block3;
break;
case 3:
xBlock = aINode->Block4;
break;
case 4:
xBlock = aINode->Block5;
break;
case 5:
xBlock = aINode->Block6;
break;
case 6:
xBlock = aINode->Block7;
break;
case 7:
xBlock = aINode->Block8;
break;
case 8:
xBlock = aINode->Block9;
break;
case 9:
xBlock = aINode->Block10;
break;
case 10:
xBlock = aINode->Block11;
break;
case 11:
xBlock = aINode->Block12;
break;
default:
Console.WriteLine("Ext2|ReadINodeContents, Only reading of direct blocks supported (12 logical blocks)");
return false;
}
uint xBase = xBlock * (mBlockSize / mBackend.BlockSize);
for (int i = 0; i < (mBlockSize / mBackend.BlockSize); i++) {
var xBytes = mBackend.ReadBlock((uint)(xBase + i));
for (int b = 0; b < xBytes.Length; b++) {
aBuffer[(i * mBackend.BlockSize) + b] = xBytes[b];
}
}
return true;
}
public unsafe byte[] ReadFile(string[] xPath) {
INode xINode;
if (!GetINodeByName(xPath, out xINode)) {
return null;
}
uint xSize = xINode.Size;
if (xSize > mBackend.BlockSize) {
xSize = mBackend.BlockSize;
}
// DebugUtil.SendNumber("Ext2", "ReadFile, Block1", xINode.Block1, 32);
//byte* xBuff = (byte*)Heap.MemAlloc(mBlockSize);
try {
//if (!ReadINodeContents(&xINode, 0, xBuff)) {
return null;
//}
byte[] xResult = new byte[xSize];
for (int i = 0; i < xSize; i++) {
//xResult[i] = xBuff[i];
}
return xResult;
} finally {
//Heap.MemFree((uint)xBuff);
}
}
private bool GetINodeByName(string[] aPath, out INode aINode) {
//ushort* xBuffer = (ushort*)Heap.MemAlloc(mBackend.BlockSize);
//byte* xExt2BlockBuffer = (byte*)Heap.MemAlloc(mBlockSize);
byte* xExt2BlockBuffer = null;
INode xCurrentINode = new INode();
aINode = xCurrentINode;
if (!ReadINode(EXT2_ROOT_INO, out xCurrentINode)) {
// Heap.MemFree((uint)xBuffer);
// Heap.MemFree((uint)xExt2BlockBuffer);
return false;
}
bool xCurrentINodeChanged = true;
uint xInspectedINodeCount = 0;
for (int i = 0; i < aPath.Length; i++) {
Console.Write("ReadFile, Iteration ");
ATAOld.WriteNumber((uint)i, 8);
Console.WriteLine("");
if (!xCurrentINodeChanged) {
Console.WriteLine("Terminating for loop, CurrentINode didn't change");
// Heap.MemFree((uint)xBuffer);
// Heap.MemFree((uint)xExt2BlockBuffer);
return false;
}
xCurrentINodeChanged = false;
if (!ReadINodeContents(&xCurrentINode, 0, xExt2BlockBuffer)) {
// Heap.MemFree((uint)xBuffer);
// Heap.MemFree((uint)xExt2BlockBuffer);
return false;
}
DirectoryEntry* xEntryPtr = (DirectoryEntry*)xExt2BlockBuffer;
uint xTotalSize = mBlockSize;
while (xTotalSize != 0) {
// DebugUtil.SendExt2_DirectoryEntry(xEntryPtr);
uint xPtrAddress = (uint)xEntryPtr;
char[] xName = new char[xEntryPtr->NameLength];
byte* xNamePtr = &xEntryPtr->FirstNameChar;
for (int c = 0; c < xName.Length; c++) {
xName[c] = (char)xNamePtr[c];
}
xInspectedINodeCount++;
if (EqualsName(aPath[i], xName)) {
if (!ReadINode(xEntryPtr->INodeNumber, out xCurrentINode)) {
// Heap.MemFree((uint)xBuffer);
//Heap.MemFree((uint)xExt2BlockBuffer);
return false;
}
xCurrentINodeChanged = true;
xTotalSize = 0;
continue;
}
xPtrAddress += xEntryPtr->RecordLength;
xTotalSize -= xEntryPtr->RecordLength;
xEntryPtr = (DirectoryEntry*)xPtrAddress;
}
}
aINode = xCurrentINode;
return true;
}
public string[] GetDirectoryEntries(string[] aPath) {
List<string> xResult = new List<string>(32);
INode xINode;
//byte* xExt2BlockBuffer = (byte*)Heap.MemAlloc(mBlockSize);
byte* xExt2BlockBuffer = null;
if (!GetINodeByName(aPath, out xINode)) {
throw new Exception("Couldn't find path!");
}
if ((xINode.Mode & INodeModeEnum.Directory) == 0) {
Console.WriteLine("Ext2|GetDirectoryEntries, No directory after for loop");
return null;
}
// if (!ReadINodeContents(&xINode, 0, xExt2BlockBuffer)) {
// Heap.MemFree((uint)xExt2BlockBuffer);
return null;
// }
DirectoryEntry* xEntry = (DirectoryEntry*)xExt2BlockBuffer;
uint xSize = mBlockSize;
// DebugUtil.SendMessage("Ext2", "GetDirectoryEntries");
while (xSize != 0) {
// DebugUtil.SendExt2_DirectoryEntry(xEntry);
uint xPtrAddress = (uint)xEntry;
char[] xName = new char[xEntry->NameLength];
byte* xNamePtr = &xEntry->FirstNameChar;
for (int c = 0; c < xName.Length; c++) {
byte b = xNamePtr[c];
xName[c] = (char)b;
}
xResult.Add(new String(xName));
xPtrAddress += xEntry->RecordLength;
xSize -= xEntry->RecordLength;
xEntry = (DirectoryEntry*)xPtrAddress;
}
// Heap.MemFree((uint)xExt2BlockBuffer);
return xResult.ToArray();
}
private static bool EqualsName(string a1, char[] a2) {
if (a1 == null || a2 == null) {
return false;
}
if (a1.Length != a2.Length) {
return false;
}
for (int i = 0; i < a1.Length; i++) {
if (a1[i] != a2[i]) {
return false;
}
}
return true;
}
}
}