Skip to content

Commit 813062f

Browse files
authored
Merge pull request #1875 from CosmosOS/feature/iso9660
[vfs] Implement ISO9660 file system
2 parents 12b1a09 + fb3b887 commit 813062f

File tree

5 files changed

+345
-2
lines changed

5 files changed

+345
-2
lines changed

source/Cosmos.HAL2/BlockDevice/IDE.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using Cosmos.HAL.BlockDevice;
34

45
namespace Cosmos.HAL.BlockDevice
@@ -20,9 +21,15 @@ internal static void InitDriver()
2021
Initialize(Ata.ControllerIdEnum.Secondary, Ata.BusPositionEnum.Master);
2122
Console.WriteLine("ATA Secondary Slave");
2223
Initialize(Ata.ControllerIdEnum.Secondary, Ata.BusPositionEnum.Slave);
24+
25+
//Add in the atapi devices
26+
foreach (var item in ATAPIPartions)
27+
{
28+
BlockDevice.Devices.Add(item);
29+
}
2330
}
2431
}
25-
32+
private static List<Partition> ATAPIPartions = new List<Partition>();
2633
private static void Initialize(Ata.ControllerIdEnum aControllerID, Ata.BusPositionEnum aBusPosition)
2734
{
2835
var xIO = aControllerID == Ata.ControllerIdEnum.Primary ? Core.Global.BaseIOGroups.ATA1 : Core.Global.BaseIOGroups.ATA2;
@@ -39,7 +46,10 @@ private static void Initialize(Ata.ControllerIdEnum aControllerID, Ata.BusPositi
3946
else if (xATA.DriveType == ATA_PIO.SpecLevel.ATAPI)
4047
{
4148
var atapi = new ATAPI(xATA);
42-
BlockDevice.Devices.Add(atapi);
49+
50+
//TODO: Replace 1000000 with proper size once ATAPI driver implements it
51+
//Add the atapi device to an array so we reorder them to be last
52+
ATAPIPartions.Add(new Partition(atapi, 0, 1000000));
4353
Ata.AtaDebugger.Send("ATA device with speclevel ATAPI found");
4454
return;
4555
}

source/Cosmos.System2/FileSystem/CosmosVFS.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
using Cosmos.HAL.BlockDevice;
88
using Cosmos.System.FileSystem.FAT;
9+
using Cosmos.System.FileSystem.ISO9660;
910
using Cosmos.System.FileSystem.Listing;
1011
using Cosmos.System.FileSystem.VFS;
1112

@@ -42,6 +43,7 @@ public override void Initialize(bool aShowInfo)
4243
mFileSystems = new List<FileSystem>();
4344
mRegisteredFileSystems = new List<FileSystemFactory>();
4445

46+
RegisterFileSystem(new ISO9660FileSystemFactory());
4547
RegisterFileSystem(new FatFileSystemFactory());
4648

4749
InitializePartitions(aShowInfo);
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Text;
5+
using Cosmos.System.FileSystem.Listing;
6+
7+
namespace Cosmos.System.FileSystem.ISO9660
8+
{
9+
internal class ISO9660DirectoryEntry : DirectoryEntry
10+
{
11+
ISO9660FileSystem fs;
12+
internal ISO9660Directory internalEntry;
13+
14+
public ISO9660DirectoryEntry(ISO9660Directory internalEntry, ISO9660FileSystem aFileSystem, ISO9660DirectoryEntry aParent, string aFullPath, string aName, long aSize, DirectoryEntryTypeEnum aEntryType) : base(aFileSystem, aParent, aFullPath, aName, aSize, aEntryType)
15+
{
16+
this.internalEntry = internalEntry;
17+
fs = aFileSystem;
18+
}
19+
public override Stream GetFileStream()
20+
{
21+
return new MemoryStream(fs.ReadFile(internalEntry));
22+
}
23+
24+
public override long GetUsedSpace()
25+
{
26+
return internalEntry.FileSize;
27+
}
28+
29+
public override void SetName(string aName)
30+
{
31+
throw new NotImplementedException("Read only file system");
32+
}
33+
34+
public override void SetSize(long aSize)
35+
{
36+
throw new NotImplementedException("Read only file system");
37+
}
38+
}
39+
internal class ISO9660Directory
40+
{
41+
public byte Length;
42+
public byte ExtLength;
43+
public uint LBA;
44+
public uint FileSize;
45+
public byte FileFlags;
46+
47+
public byte FileIdLen;
48+
public string FileID;
49+
}
50+
}
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Text;
5+
using Cosmos.HAL.BlockDevice;
6+
using Cosmos.System.FileSystem.Listing;
7+
8+
namespace Cosmos.System.FileSystem.ISO9660
9+
{
10+
public class ISO9660FileSystem : FileSystem
11+
{
12+
private string label;
13+
public override long AvailableFreeSpace => 0;
14+
15+
public override long TotalFreeSpace => 0;
16+
17+
public override string Type => "ISO9660";
18+
19+
public override string Label { get => label; set => throw new NotImplementedException("Read only file system"); }
20+
21+
private ISO9660Directory RootDir;
22+
23+
public ISO9660FileSystem(Partition aDevice, string aRootPath, long aSize)
24+
: base(aDevice, aRootPath, aSize)
25+
{
26+
if (aDevice == null)
27+
{
28+
throw new ArgumentNullException(nameof(aDevice));
29+
}
30+
31+
if (String.IsNullOrEmpty(aRootPath))
32+
{
33+
throw new ArgumentException("Argument is null or empty", nameof(aRootPath));
34+
}
35+
36+
//Read primary descriptor
37+
var primaryDescriptor = aDevice.NewBlockArray(1);
38+
aDevice.ReadBlock(0x10, 1, ref primaryDescriptor);
39+
var r = new BinaryReader(new MemoryStream(primaryDescriptor));
40+
41+
var volType = r.ReadByte();
42+
var id = r.ReadBytes(5);
43+
var version = r.ReadByte();
44+
45+
//this should always be 1
46+
if (volType != 1)
47+
{
48+
throw new Exception("Volume descriptor " + volType + " not implemented");
49+
}
50+
51+
r.ReadByte(); //unused
52+
r.ReadBytes(32); // System Identifier
53+
label = Encoding.ASCII.GetString(r.ReadBytes(32)); //Volume Identifier
54+
55+
r.BaseStream.Position = 156;
56+
var b = r.ReadBytes(34);
57+
BinaryReader rootdir = new BinaryReader(new MemoryStream(b));
58+
RootDir = ReadDirectoryEntry(rootdir);
59+
}
60+
/// <summary>
61+
/// Reads directory contents
62+
/// </summary>
63+
/// <param name="locOfExtent">Location of extent</param>
64+
/// <returns>List of Directorys</returns>
65+
private List<ISO9660Directory> ReadDirectory(uint locOfExtent)
66+
{
67+
var dirs = new List<ISO9660Directory>();
68+
var locOfExt = Device.NewBlockArray(1);
69+
Device.ReadBlock(locOfExtent, 1, ref locOfExt);
70+
var lba = new BinaryReader(new MemoryStream(locOfExt));
71+
72+
//Skip past the . and .. directoryies
73+
var len1 = lba.ReadByte();
74+
lba.BaseStream.Position += len1 - 1;
75+
var len2 = lba.ReadByte();
76+
lba.BaseStream.Position += len2 - 1;
77+
78+
while (true)
79+
{
80+
var e = ReadDirectoryEntry(lba);
81+
if (e.Length == 0)
82+
break;
83+
dirs.Add(e);
84+
}
85+
return dirs;
86+
}
87+
/// <summary>
88+
/// Reads a DirectoryEntry
89+
/// </summary>
90+
/// <param name="lba">Binary reader</param>
91+
/// <returns>A ISO9660Directory</returns>
92+
private ISO9660Directory ReadDirectoryEntry(BinaryReader lba)
93+
{
94+
var old = lba.BaseStream.Position;
95+
96+
var dir = new ISO9660Directory();
97+
dir.Length = lba.ReadByte();
98+
dir.ExtLength = lba.ReadByte();
99+
100+
101+
//Read LBA (8 bytes)
102+
var locofextbytesPT1 = lba.ReadBytes(4);
103+
var locofextbytesPT2 = lba.ReadBytes(4);
104+
locofextbytesPT1 = ReverseArray(locofextbytesPT1, true);
105+
byte[] rv = new byte[locofextbytesPT1.Length + locofextbytesPT2.Length];
106+
Buffer.BlockCopy(locofextbytesPT1, 0, rv, 0, locofextbytesPT1.Length);
107+
Buffer.BlockCopy(locofextbytesPT2, 0, rv, locofextbytesPT1.Length, locofextbytesPT2.Length);
108+
dir.LBA = BitConverter.ToUInt32(rv, 0);
109+
110+
//Read data length (8 bytes)
111+
var sizePT1 = lba.ReadBytes(4);
112+
var sizePT2 = lba.ReadBytes(4);
113+
sizePT1 = ReverseArray(sizePT1, true);
114+
byte[] rv2 = new byte[sizePT1.Length + sizePT2.Length];
115+
Buffer.BlockCopy(sizePT1, 0, rv2, 0, sizePT1.Length);
116+
Buffer.BlockCopy(sizePT2, 0, rv2, sizePT1.Length, sizePT2.Length);
117+
dir.FileSize = BitConverter.ToUInt32(rv2, 0);
118+
119+
lba.ReadBytes(7); //recording date & time
120+
lba.BaseStream.Position = old + 25;
121+
dir.FileFlags = lba.ReadByte();
122+
123+
124+
lba.ReadBytes(6); //Unneeded fields
125+
126+
dir.FileIdLen = lba.ReadByte();
127+
128+
var str = lba.ReadBytes(dir.FileIdLen);
129+
dir.FileID = Encoding.ASCII.GetString(str);
130+
lba.BaseStream.Position = old + dir.Length;
131+
132+
return dir;
133+
}
134+
/// <summary>
135+
/// Reverses an array
136+
/// </summary>
137+
/// <param name="array"></param>
138+
/// <param name="isLittleEndian"></param>
139+
/// <returns></returns>
140+
private byte[] ReverseArray(byte[] array, bool isLittleEndian)
141+
{
142+
List<byte> b = new List<byte>();
143+
if (BitConverter.IsLittleEndian)
144+
{
145+
if (isLittleEndian)
146+
{
147+
//no need to swap
148+
return array;
149+
}
150+
}
151+
for (int i = array.Length - 1; i >= 0; i--)
152+
{
153+
b.Add(array[i]);
154+
}
155+
return b.ToArray();
156+
}
157+
/// <summary>
158+
/// Reads a file
159+
/// </summary>
160+
/// <param name="entry">File Entry</param>
161+
/// <returns>Byte array of the file</returns>
162+
internal byte[] ReadFile(ISO9660Directory entry)
163+
{
164+
var oldsize = entry.FileSize;
165+
byte[] file = new byte[entry.FileSize];
166+
var SectorIndex = entry.LBA;
167+
int offset = 0;
168+
byte[] sector = new byte[2048];
169+
while (true)
170+
{
171+
Device.ReadBlock(SectorIndex, 1, ref sector);
172+
173+
if (entry.FileSize < 2048)
174+
{
175+
for (int i = 0; i < entry.FileSize; i++)
176+
{
177+
file[offset + i] = sector[i];
178+
}
179+
entry.FileSize = oldsize;
180+
break;
181+
}
182+
else
183+
{
184+
//Read more sectors
185+
Buffer.BlockCopy(sector, 0, file, offset, sector.Length);
186+
187+
offset += 2048;
188+
entry.FileSize -= 2048;
189+
SectorIndex++;
190+
}
191+
}
192+
return file;
193+
}
194+
public override void DisplayFileSystemInfo()
195+
{
196+
global::System.Console.WriteLine("Volume label is " + label);
197+
}
198+
public override List<DirectoryEntry> GetDirectoryListing(DirectoryEntry baseDirectory)
199+
{
200+
var baseEntry = (ISO9660DirectoryEntry)baseDirectory;
201+
var dirEntries = ReadDirectory(baseEntry.internalEntry.LBA);
202+
List<DirectoryEntry> entries = new List<DirectoryEntry>();
203+
var parent = new ISO9660DirectoryEntry(baseEntry.internalEntry, this, baseEntry, baseDirectory.mFullPath, ".", 0, DirectoryEntryTypeEnum.Directory);
204+
foreach (var item in dirEntries)
205+
{
206+
DirectoryEntryTypeEnum type;
207+
if ((item.FileFlags & (1 << 1)) != 0)
208+
{
209+
type = DirectoryEntryTypeEnum.Directory;
210+
}
211+
else
212+
{
213+
type = DirectoryEntryTypeEnum.File;
214+
}
215+
var properID = item.FileID.Remove(item.FileID.Length - 2); //remove the ;1 part from the file name
216+
entries.Add(new ISO9660DirectoryEntry(item, this, parent, Path.Combine(parent.mFullPath, properID), properID, 0, type));
217+
}
218+
return entries;
219+
}
220+
public override DirectoryEntry GetRootDirectory()
221+
{
222+
return new ISO9660DirectoryEntry(RootDir, this, null, RootPath, RootPath, 0, DirectoryEntryTypeEnum.Directory);
223+
}
224+
#region Unused
225+
public override DirectoryEntry CreateDirectory(DirectoryEntry aParentDirectory, string aNewDirectory)
226+
{
227+
throw new NotImplementedException("Read only file system");
228+
}
229+
230+
public override DirectoryEntry CreateFile(DirectoryEntry aParentDirectory, string aNewFile)
231+
{
232+
throw new NotImplementedException("Read only file system");
233+
}
234+
235+
public override void DeleteDirectory(DirectoryEntry aPath)
236+
{
237+
throw new NotImplementedException("Read only file system");
238+
}
239+
240+
public override void DeleteFile(DirectoryEntry aPath)
241+
{
242+
throw new NotImplementedException("Read only file system");
243+
}
244+
public override void Format(string aDriveFormat, bool aQuick)
245+
{
246+
throw new NotImplementedException();
247+
}
248+
#endregion
249+
}
250+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using Cosmos.HAL.BlockDevice;
5+
6+
namespace Cosmos.System.FileSystem.ISO9660
7+
{
8+
public class ISO9660FileSystemFactory : FileSystemFactory
9+
{
10+
public override string Name => "ISO9660";
11+
12+
public override FileSystem Create(Partition aDevice, string aRootPath, long aSize)
13+
{
14+
return new ISO9660FileSystem(aDevice, aRootPath, aSize);
15+
}
16+
17+
public override bool IsType(Partition aDevice)
18+
{
19+
var primarySectory = aDevice.NewBlockArray(1);
20+
aDevice.ReadBlock(0x10, 1, ref primarySectory);
21+
if (Encoding.ASCII.GetString(primarySectory, 1, 5) == "CD001")
22+
{
23+
return true;
24+
}
25+
else
26+
{
27+
return false;
28+
}
29+
}
30+
}
31+
}

0 commit comments

Comments
 (0)