summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/Applications/Demos/GOL.cpp11
-rw-r--r--Source/Applications/PaperWork/main.cpp7
-rw-r--r--Source/Kernel/Core/Log.ns.cpp6
-rw-r--r--Source/Kernel/Core/Sys.ns.cpp6
-rw-r--r--Source/Kernel/Core/Sys.ns.h4
-rw-r--r--Source/Kernel/Core/kmain.wtf.cpp46
-rw-r--r--Source/Kernel/Devices/ATA/ATAController.class.cpp55
-rw-r--r--Source/Kernel/Devices/ATA/ATAController.class.h48
-rw-r--r--Source/Kernel/Devices/ATA/ATADrive.class.cpp75
-rw-r--r--Source/Kernel/Devices/ATA/ATADrive.class.h30
-rw-r--r--Source/Kernel/Devices/Floppy/FloppyController.class.cpp17
-rw-r--r--Source/Kernel/Devices/Floppy/FloppyController.class.h6
-rw-r--r--Source/Kernel/Devices/Floppy/FloppyDrive.class.cpp64
-rw-r--r--Source/Kernel/Devices/Floppy/FloppyDrive.class.h2
-rw-r--r--Source/Kernel/FileSystems/FAT/FATDirectoryNode.class.h16
-rw-r--r--Source/Kernel/FileSystems/FAT/FATFS.class.cpp247
-rw-r--r--Source/Kernel/FileSystems/FAT/FATFS.class.h134
-rw-r--r--Source/Kernel/FileSystems/FAT/FATFileNode.class.h16
-rw-r--r--Source/Kernel/FileSystems/RamFS/RamFS.class.cpp11
-rw-r--r--Source/Kernel/FileSystems/RamFS/RamFS.class.h6
-rw-r--r--Source/Kernel/FileSystems/RamFS/RamFileNode.class.h2
-rw-r--r--Source/Kernel/Linker/ElfBinary.class.cpp2
-rw-r--r--Source/Kernel/Linker/MelonBinary.class.cpp2
-rw-r--r--Source/Kernel/Makefile3
-rw-r--r--Source/Kernel/Shell/KernelShell-fs.class.cpp18
-rw-r--r--Source/Kernel/Shell/KernelShell-sys.class.cpp41
-rw-r--r--Source/Kernel/Shell/KernelShell.class.cpp28
-rw-r--r--Source/Kernel/Shell/KernelShell.class.h3
-rw-r--r--Source/Kernel/UserManager/Usr.ns.cpp26
-rw-r--r--Source/Kernel/VFS/BlockCache.class.cpp89
-rw-r--r--Source/Kernel/VFS/BlockCache.class.h32
-rw-r--r--Source/Kernel/VFS/DirectoryNode.class.cpp45
-rw-r--r--Source/Kernel/VFS/DirectoryNode.class.h15
-rw-r--r--Source/Kernel/VFS/FSNode.proto.h4
-rw-r--r--Source/Kernel/VFS/File.class.cpp3
-rw-r--r--Source/Kernel/VFS/FileSystem.proto.h19
-rw-r--r--Source/Kernel/VFS/Part.ns.cpp45
-rw-r--r--Source/Kernel/VFS/Part.ns.h18
-rw-r--r--Source/Kernel/VFS/Partition.class.cpp10
-rw-r--r--Source/Kernel/VFS/Partition.class.h4
-rw-r--r--Source/Kernel/VFS/VFS.ns.cpp123
-rw-r--r--Source/Kernel/VFS/VFS.ns.h16
-rw-r--r--Source/Library/Common/BasicString.class.cpp4
-rw-r--r--Source/Library/Common/BasicString.class.h2
-rw-r--r--Source/Library/Common/ByteArray.class.cpp4
-rw-r--r--Source/Library/Common/String.class.cpp8
-rw-r--r--Source/Library/Common/String.class.h2
-rw-r--r--Source/Library/Common/WChar.class.cpp59
-rw-r--r--Source/Library/Common/WChar.class.h30
49 files changed, 1335 insertions, 129 deletions
diff --git a/Source/Applications/Demos/GOL.cpp b/Source/Applications/Demos/GOL.cpp
index 32eb30a..e6da3a6 100644
--- a/Source/Applications/Demos/GOL.cpp
+++ b/Source/Applications/Demos/GOL.cpp
@@ -1,6 +1,7 @@
#include <Binding/VirtualTerminal.class.h>
#include <Binding/Thread.class.h>
#include <String.class.h>
+#include <ByteArray.class.h>
#include <Rand.ns.h>
int main(Vector<String> args) {
@@ -22,7 +23,7 @@ int main(Vector<String> args) {
}
}
- char *tmp = new char[w * h + 1];
+ ByteArray tmp((w + 1) * (h + 1));
bool run = true;
while (run) {
@@ -37,7 +38,7 @@ int main(Vector<String> args) {
}
}
outvt.moveCursor(0, 0);
- outvt << String(tmp, w*h) << "Press Ctrl+h for help";
+ outvt << tmp.toString() << "Press Ctrl+h for help";
//Compute next generation
for (int y = 0; y < h; y++) {
@@ -82,12 +83,16 @@ int main(Vector<String> args) {
u64int y = Rand::rand() * h / Rand::max();
cells[x * h + y] = true;
}
+ } else if (kp.character == WChar("p")) {
+ outvt << " [PAUSED] press a key to resume";
+ invt.getKeypress();
} else if (kp.character == WChar("h")) {
outvt << "\n\n** Melon's demo Game Of Life Simulator help :\n";
outvt << " - ctrl+c : quit\n";
outvt << " - ctrl+h : show this\n";
+ outvt << " - ctrl+p : pause\n";
outvt << " - ctrl+r : add some random cells\n";
- outvt << " - ctrl+R : add more cells, but not random\n\n";
+ outvt << " - ctrl+R : add more cells, still random\n\n";
outvt << "Press any key to return to simultaor...";
invt.getKeypress();
}
diff --git a/Source/Applications/PaperWork/main.cpp b/Source/Applications/PaperWork/main.cpp
index 1a4c1c7..2fb40df 100644
--- a/Source/Applications/PaperWork/main.cpp
+++ b/Source/Applications/PaperWork/main.cpp
@@ -1,6 +1,8 @@
#include <Binding/Process.class.h>
#include <String.class.h>
+#define DEFAULT_SHELL "/Applications/Shell/Shell.app"
+
int main(Vector<String> args) {
String act = "init";
if (args.size() == 2) {
@@ -36,7 +38,10 @@ int main(Vector<String> args) {
outvt << "Authentication failed.\n\n";
continue;
}
- Process p = Process::run("/Applications/Shell/Shell.app");
+ outvt << "What shell to run [" << DEFAULT_SHELL << "]? ";
+ String sh = invt.readLine();
+ if (sh == "") sh = DEFAULT_SHELL;
+ Process p = Process::run(sh);
if (p.valid()) {
p.setInVT(invt);
p.setOutVT(outvt);
diff --git a/Source/Kernel/Core/Log.ns.cpp b/Source/Kernel/Core/Log.ns.cpp
index 1727024..d51aa55 100644
--- a/Source/Kernel/Core/Log.ns.cpp
+++ b/Source/Kernel/Core/Log.ns.cpp
@@ -1,4 +1,6 @@
#include "Log.ns.h"
+#include <FileSystems/RamFS/RamFS.class.h>
+#include <VTManager/SimpleVT.class.h>
#include <VFS/VFS.ns.h>
namespace Log {
@@ -11,6 +13,10 @@ void init(u8int loglevel) {
if (VFS::find("/System/Logs") == 0) VFS::createDirectory("/System/Logs");
logs[KL_PANIC] = new TextFile("/System/Logs/Panic.log", FM_APPEND);
+ if (!logs[KL_PANIC]->valid()) { //FS maybee not read/write, mount a ramfs
+ VFS::mount("/System/Logs:ramfs", kvt);
+ logs[KL_PANIC] = new TextFile("/System/Logs/Panic.log", FM_APPEND);
+ }
if (KL_CRITICAL <= loglevel) logs[KL_CRITICAL] = new TextFile("/System/Logs/Critical.log", FM_APPEND);
if (KL_ERROR <= loglevel) logs[KL_ERROR] = new TextFile("/System/Logs/Error.log", FM_APPEND);
if (KL_WARNING <= loglevel) logs[KL_WARNING] = new TextFile("/System/Logs/Warning.log", FM_APPEND);
diff --git a/Source/Kernel/Core/Sys.ns.cpp b/Source/Kernel/Core/Sys.ns.cpp
index eeb92ee..c5af3e8 100644
--- a/Source/Kernel/Core/Sys.ns.cpp
+++ b/Source/Kernel/Core/Sys.ns.cpp
@@ -18,6 +18,10 @@ void outb (u16int port, u8int value) {
asm volatile ("outb %1, %0" : : "dN" (port), "a" (value));
}
+void outw (u16int port, u16int value) {
+ asm volatile ("outw %1, %0" : : "dN" (port), "a" (value));
+}
+
u8int inb (u16int port) {
u8int ret;
asm volatile ("inb %1, %0" : "=a" (ret) : "dN" (port));
@@ -83,7 +87,7 @@ void dumpRegs(registers_t *regs, VirtualTerminal& vt) {
void stackTrace(u32int ebp, VirtualTerminal& vt, u32int maxframes) {
u32int *stack = (u32int*)ebp;
- for (u32int i = 0; i < maxframes and (u32int)stack > 0xC0000000; i++) {
+ for (u32int i = 0; i < maxframes and (u32int)stack > 0xC0000000 and (u32int)stack < (ebp + 0x10000); i++) {
vt << "Frame: " << (u32int)stack << " n:" << stack[0] << " r:" << stack[1] << "\n";
stack = (u32int*)stack[0];
}
diff --git a/Source/Kernel/Core/Sys.ns.h b/Source/Kernel/Core/Sys.ns.h
index 4d15676..26f04e6 100644
--- a/Source/Kernel/Core/Sys.ns.h
+++ b/Source/Kernel/Core/Sys.ns.h
@@ -18,11 +18,15 @@
//This file contains system-relative functions
class String;
+class SimpleVT;
class VirtualTerminal;
struct registers_t;
+extern SimpleVT* kvt;
+
namespace Sys {
void outb(u16int port, u8int value);
+ void outw(u16int port, u8int value);
u8int inb(u16int port);
u16int inw(u16int port);
void dumpRegs(registers_t *regs, VirtualTerminal& vt);
diff --git a/Source/Kernel/Core/kmain.wtf.cpp b/Source/Kernel/Core/kmain.wtf.cpp
index 0486702..ad11eaf 100644
--- a/Source/Kernel/Core/kmain.wtf.cpp
+++ b/Source/Kernel/Core/kmain.wtf.cpp
@@ -7,6 +7,7 @@
#include <Devices/Display/VESADisplay.class.h>
#include <Devices/Keyboard/PS2Keyboard.class.h>
#include <Devices/Floppy/FloppyDrive.class.h>
+#include <Devices/ATA/ATAController.class.h>
#include <Devices/Timer.class.h>
#include <DeviceManager/Disp.ns.h>
#include <DeviceManager/Dev.ns.h>
@@ -25,6 +26,7 @@
#include <Rand.ns.h>
#include <VFS/Part.ns.h>
#include <FileSystems/RamFS/RamFS.class.h>
+#include <FileSystems/FAT/FATFS.class.h>
#include <VFS/FileNode.class.h>
#include <VFS/VFS.ns.h>
#include <VFS/DirectoryNode.class.h>
@@ -37,6 +39,8 @@ extern u32int end; //Placement address
extern "C" void kmain(multiboot_info_t* mbd, u32int magic);
+SimpleVT* kvt;
+
u32int logoAnimation(void* p) {
SimpleVT& vt = *((SimpleVT*)p);
vt.setColor(8);
@@ -83,7 +87,7 @@ u32int logoAnimation(void* p) {
void selectVideoMode(SimpleVT& v) {
Disp::getModes();
- v << "\n\nPlease select a graphic mode in the list below:\n";
+ v << "\nPlease select a graphic mode in the list below:\n";
for (u32int i = 0; i < Disp::modes.size(); i++) {
Disp::mode_t& m = Disp::modes[i];
@@ -140,9 +144,9 @@ void kmain(multiboot_info_t* mbd, u32int magic) {
Disp::setText(vgaout);
//Create a VT for logging what kernel does
- SimpleVT *kvt = new ScrollableVT(25, 80, 20, KVT_FGCOLOR, KVT_BGCOLOR);
+ kvt = new ScrollableVT(25, 80, 20, KVT_FGCOLOR, KVT_BGCOLOR);
kvt->map(0, 0);
- *kvt << "Melon is loading...";
+ *kvt << "Melon is loading...\n";
IDT::init(); //Setup interrupts
@@ -164,13 +168,17 @@ void kmain(multiboot_info_t* mbd, u32int magic) {
//*************************************** PARSE COMMAND LINE
Vector<String> opts = kcmdline.split(" ");
- String keymap = "fr", init = "/System/Applications/PaperWork.app";
+ String keymap = "builtin", init = "/System/Applications/PaperWork.app";
+ String root = "ramfs:0";
+ Vector<String> mount;
bool enableVESA = true;
for (u32int i = 0; i < opts.size(); i++) {
Vector<String> opt = opts[i].split(":");
if (opt[0] == "vesa" && opt[1] != "enabled") enableVESA = false;
if (opt[0] == "keymap") keymap = opt[1];
if (opt[0] == "init") init = opt[1];
+ if (opt[0] == "root") root = opts[i].substr(5);
+ if (opt[0] == "mount") mount.push(opts[i].substr(6));
}
//*************************************** DEVICE SETUP
@@ -179,17 +187,35 @@ void kmain(multiboot_info_t* mbd, u32int magic) {
Kbd::setFocus(kvt); //Set focus to virtual terminal
if (enableVESA) Dev::registerDevice(new VESADisplay());
FloppyController::detect();
+ ATAController::detect();
- //*************************************** MOUNT ROOT FILESYSTEM
+ //*************************************** MOUNT FILESYSTEMS
- FileSystem* fs = RamFS::mount((u8int*)mods[0].mod_start, 1024 * 1024, NULL);
+ { // mount root filesystem
+ if (!VFS::mount(String("/:") += root, kvt, mbd)) PANIC("Cannot mount root filesystem.");
+ }
DirectoryNode* cwd;
- cwd = fs->getRootNode();
+ cwd = VFS::getRootNode();
Task::currProcess()->setCwd(cwd);
- VFS::setRootNode(cwd);
+
+ // mount other filesystems
+ for (u32int i = 0; i < mount.size(); i++) {
+ VFS::mount(mount[i], kvt, mbd);
+ }
+
+ {
+ TextFile mounts("/System/Configuration/Mount", FM_READ);
+ while (mounts.valid() && !mounts.eof()) {
+ String m = mounts.readLine();
+ if (!m.empty() && m[0] != WChar("#")) VFS::mount(m, kvt, mbd);
+ }
+ }
+
+
+ //*************************************** LOAD SYSTEM STUFF
if (keymap != "builtin") {
- if (!Kbd::loadKeymap(keymap)) *kvt << "\nWARNING : Could not load keymap " << keymap << ", using built-in keymap instead.";
+ if (!Kbd::loadKeymap(keymap)) *kvt << "WARNING : Could not load keymap " << keymap << ", using built-in keymap instead.";
}
Log::init(KL_STATUS); //Setup logging
@@ -199,7 +225,7 @@ void kmain(multiboot_info_t* mbd, u32int magic) {
Log::log(KL_STATUS, "kmain : User list loaded");
if (init.empty()) {
- *kvt << "\n\n";
+ *kvt << "\n";
new KernelShell(cwd, kvt);
while (KernelShell::getInstances() > 0) {
Task::currThread()->sleep(100);
diff --git a/Source/Kernel/Devices/ATA/ATAController.class.cpp b/Source/Kernel/Devices/ATA/ATAController.class.cpp
new file mode 100644
index 0000000..d8073d0
--- /dev/null
+++ b/Source/Kernel/Devices/ATA/ATAController.class.cpp
@@ -0,0 +1,55 @@
+#include "ATADrive.class.h"
+
+#include <DeviceManager/Dev.ns.h>
+#include <VFS/Part.ns.h>
+
+String ATAController::getClass() {
+ return "controller.ata";
+}
+
+String ATAController::getName() {
+ return String("ATA controller #") + String::number(m_number);
+}
+
+void ATAController::detect() {
+ ATAController *c[2];
+ c[0] = new ATAController(ATA_BUS1_BASE, 0);
+ c[1] = new ATAController(ATA_BUS2_BASE, 1);
+ Dev::registerDevice(c[0]); Dev::registerDevice(c[1]);
+ for (u32int d = 0; d < 2; d++) {
+ for (u32int r = 0; r < 2; r++) {
+ ATADrive* drv = c[d]->m_drives[r];
+ if (drv != 0) {
+ Dev::registerDevice(drv);
+ Part::registerDevice(drv);
+ }
+ }
+ }
+}
+
+ATAController::ATAController(u32int base, u8int number) : Mutex(MUTEX_TRUE) {
+ m_base = base; m_number = number;
+ m_drives[0] = NULL; m_drives[1] = NULL;
+ identify(false); //Identify master device
+ identify(true); //Identify slave device
+ unlock();
+}
+
+void ATAController::identify(bool slave) {
+ if (!locked()) return;
+ if (m_drives[(slave ? 1 : 0)] != NULL) return;
+ writeByte(ATA_PORT_DRIVE_SELECT, (slave ? 0xB0 : 0xA0));
+ writeByte(ATA_PORT_COMMAND, ATA_CMD_IDENTIFY);
+ u8int ret = readByte(ATA_PORT_COMMAND);
+ if (ret == 0) return; //Drive does not exist
+ while ((ret & 0x88) != 0x08 and (ret & 1) != 1) {
+ ret = readByte(ATA_PORT_COMMAND);
+ }
+ if ((ret & 1) == 1) return; //Error while IDENTIFY
+ u16int data[256];
+ for (u32int i = 0; i < 256; i++) data[i] = readWord(ATA_PORT_DATA);
+ u32int blocks = (data[61] << 16) | data[60];
+ if (blocks != 0) { //Drive supports LBA28
+ m_drives[(slave ? 1 : 0)] = new ATADrive(this, slave, blocks, data);
+ }
+}
diff --git a/Source/Kernel/Devices/ATA/ATAController.class.h b/Source/Kernel/Devices/ATA/ATAController.class.h
new file mode 100644
index 0000000..89176c9
--- /dev/null
+++ b/Source/Kernel/Devices/ATA/ATAController.class.h
@@ -0,0 +1,48 @@
+#ifndef DEF_ATACONTROLLER_CLASS_H
+#define DEF_ATACONTROLLER_CLASS_H
+
+#include <Devices/Device.proto.h>
+#include <Mutex.class.h>
+
+#define ATA_BUS1_BASE 0x1F0
+#define ATA_BUS2_BASE 0x170
+
+#define ATA_PORT_DATA 0
+#define ATA_PORT_FEATURES_ERROR 1
+#define ATA_PORT_SECT_COUNT 2
+#define ATA_PORT_PARTIAL1 3
+#define ATA_PORT_PARTIAL2 4
+#define ATA_PORT_PARTIAL3 5
+#define ATA_PORT_DRIVE_SELECT 6
+#define ATA_PORT_COMMAND 7
+
+#define ATA_CMD_IDENTIFY 0xEC
+#define ATA_CMD_READ 0x20
+#define ATA_CMD_WRITE 0x30
+
+class ATADrive;
+
+class ATAController : public Device, public Mutex {
+ friend class ATADrive;
+ private:
+ ATAController(u32int base, u8int number);
+
+ u32int m_base;
+ u8int m_number;
+
+ ATADrive* m_drives[2];
+
+ void writeWord(u16int port, u16int word) { Sys::outw(m_base + port, word); }
+ void writeByte(u16int port, u8int byte) { Sys::outb(m_base + port, byte); }
+ u8int readByte(u16int port) { return Sys::inb(m_base + port); }
+ u16int readWord(u16int port) { return Sys::inw(m_base + port); }
+
+ void identify(bool slave); //Identifies a drive and adds it to m_drives
+
+ public:
+ static void detect();
+ String getClass();
+ String getName();
+};
+
+#endif
diff --git a/Source/Kernel/Devices/ATA/ATADrive.class.cpp b/Source/Kernel/Devices/ATA/ATADrive.class.cpp
new file mode 100644
index 0000000..247e798
--- /dev/null
+++ b/Source/Kernel/Devices/ATA/ATADrive.class.cpp
@@ -0,0 +1,75 @@
+#include "ATADrive.class.h"
+
+String ATADrive::getClass() {
+ return "block.ata";
+}
+
+String ATADrive::getName() {
+ return String("ATA drive ") += String::number(m_ctrlr->m_number) += String(m_isSlave ? ".slave " : ".master ")
+ += String::number(m_blockCount / (1024 * 1024 / blockSize())) += "MB";
+}
+
+ATADrive::ATADrive(ATAController* ctrlr, bool isSlave, u32int blockCount, u16int* identifyData) {
+ m_ctrlr = ctrlr;
+ m_isSlave = isSlave;
+ m_blockCount = blockCount;
+ for (u32int i = 0; i < 256; i++) m_identifyData[i] = identifyData[i];
+}
+
+bool ATADrive::readOnly() {
+ return true;
+}
+
+u64int ATADrive::blocks() {
+ return m_blockCount;
+}
+
+void ATADrive::cmdCommon(u32int numblock, u32int count) {
+ m_ctrlr->writeByte(ATA_PORT_FEATURES_ERROR, 0);
+ m_ctrlr->writeByte(ATA_PORT_SECT_COUNT, count);
+ m_ctrlr->writeByte(ATA_PORT_PARTIAL1, numblock);
+ m_ctrlr->writeByte(ATA_PORT_PARTIAL2, numblock >> 8);
+ m_ctrlr->writeByte(ATA_PORT_PARTIAL3, numblock >> 16);
+
+ m_ctrlr->writeByte(ATA_PORT_DRIVE_SELECT, 0xE0 | (m_isSlave ? 0x10 : 0) | ((numblock >> 24) & 0x0F));
+}
+
+bool ATADrive::readBlocks(u64int start, u32int count, u8int* data) {
+ if (start + count >= m_blockCount) return false;
+
+ m_ctrlr->waitLock();
+ cmdCommon(start, count);
+ m_ctrlr->writeByte(ATA_PORT_COMMAND, ATA_CMD_READ);
+
+ while (!(m_ctrlr->readByte(ATA_PORT_COMMAND) & 0x08)); //Wait for the drive to be ready
+
+ for (u32int idx = 0; idx < count * 256; idx++) {
+ u16int tmpword = m_ctrlr->readWord(ATA_PORT_DATA);
+ data[idx * 2] = (u8int)tmpword;
+ data[idx * 2 + 1] = (u8int)(tmpword >> 8);
+ }
+ m_ctrlr->unlock();
+ return true;
+}
+
+bool ATADrive::writeBlocks(u64int start, u32int count, u8int* data) {
+ if (start + count >= m_blockCount) return false;
+ if (readOnly()) return false;
+
+ m_ctrlr->waitLock();
+ cmdCommon(start, count);
+ m_ctrlr->writeByte(ATA_PORT_COMMAND, ATA_CMD_WRITE);
+
+ while (!(m_ctrlr->readByte(ATA_PORT_COMMAND) & 0x08)); //Wait for the drive to be ready
+
+ for (u32int idx = 0; idx < count * 256; idx++) {
+ u16int tmpword = (data[idx * 2]) | (data[idx * 2 + 1] << 8);
+ m_ctrlr->writeByte(ATA_PORT_DATA, tmpword);
+ }
+ m_ctrlr->unlock();
+ return true;
+}
+
+u32int ATADrive::blockSize() {
+ return 512;
+}
diff --git a/Source/Kernel/Devices/ATA/ATADrive.class.h b/Source/Kernel/Devices/ATA/ATADrive.class.h
new file mode 100644
index 0000000..b6087bf
--- /dev/null
+++ b/Source/Kernel/Devices/ATA/ATADrive.class.h
@@ -0,0 +1,30 @@
+#ifndef DEF_ATADRIVE_CLASS_H
+#define DEF_ATADRIVE_CLASS_H
+
+#include "ATAController.class.h"
+#include <Devices/BlockDevice.proto.h>
+
+class ATADrive : public BlockDevice {
+ friend class ATAController;
+ private:
+ ATADrive(ATAController* ctrlr, bool isSlave, u32int blockCount, u16int* identifyData);
+
+ ATAController* m_ctrlr;
+ bool m_isSlave;
+ u32int m_blockCount;
+ u16int m_identifyData[256];
+
+ void cmdCommon(u32int numblock, u32int count);
+
+ public:
+ String getClass();
+ String getName();
+
+ bool readOnly();
+ u64int blocks();
+ bool readBlocks(u64int start, u32int count, u8int* data);
+ bool writeBlocks(u64int start, u32int count, u8int* data);
+ u32int blockSize();
+};
+
+#endif
diff --git a/Source/Kernel/Devices/Floppy/FloppyController.class.cpp b/Source/Kernel/Devices/Floppy/FloppyController.class.cpp
index 146ce28..7201c5c 100644
--- a/Source/Kernel/Devices/Floppy/FloppyController.class.cpp
+++ b/Source/Kernel/Devices/Floppy/FloppyController.class.cpp
@@ -96,6 +96,7 @@ FloppyController::FloppyController(u32int base, u8int irq) : m_driveMutex(false)
m_drives[0] = NULL;
m_drives[1] = NULL;
m_first = false;
+ Dev::requestIRQ(this, m_irq);
}
void FloppyController::detect() { //TODO : do this better
@@ -144,16 +145,14 @@ void FloppyController::setDOR() {
dor |= 0x10;
if (m_drives[1] != NULL and m_drives[1]->m_motorState != 0)
dor |= 0x20;
- asm volatile ("cli");
+ resetIrq();
outb(m_base + FR_DOR, dor);
if (m_first) { //First time we set the DOR, controller initialized
- Task::currThread()->waitIRQ(m_irq);
+ waitIrq();
int st0, cyl;
checkInterrupt(&st0, &cyl);
m_first = false;
}
- asm volatile ("sti");
- //PANIC("test");
}
void FloppyController::setActiveDrive(u8int drive) {
@@ -190,10 +189,10 @@ u8int FloppyController::readData() {
bool FloppyController::reset() {
outb(m_base + FR_DOR, 0x00); //Disable controller
m_first = true;
- setNoActiveDrive();
if (m_drives[0] != NULL) m_drives[0]->m_motorState = 0;
if (m_drives[1] != NULL) m_drives[1]->m_motorState = 0;
+ setNoActiveDrive();
for (int i = 0; i < 2; i++) {
if (m_drives[i] != NULL) {
@@ -203,3 +202,11 @@ bool FloppyController::reset() {
}
return true;
}
+
+void FloppyController::handleIRQ(registers_t regs, int irq) {
+ m_irqHappened = true;
+}
+
+void FloppyController::waitIrq() {
+ while (!m_irqHappened) Task::currThread()->sleep(10);
+}
diff --git a/Source/Kernel/Devices/Floppy/FloppyController.class.h b/Source/Kernel/Devices/Floppy/FloppyController.class.h
index a27d853..f0a7c10 100644
--- a/Source/Kernel/Devices/Floppy/FloppyController.class.h
+++ b/Source/Kernel/Devices/Floppy/FloppyController.class.h
@@ -60,6 +60,8 @@ class FloppyController : public Device {
bool m_first;
+ bool m_irqHappened;
+
FloppyDrive* m_drives[2];
void checkInterrupt(int *st0, int *cyl);
@@ -69,6 +71,10 @@ class FloppyController : public Device {
bool writeCmd(u8int cmd); //Sends command to controller
u8int readData(); //Reads a byte from controller
bool reset();
+
+ void handleIRQ(registers_t regs, int irq);
+ void resetIrq() { m_irqHappened = false; }
+ void waitIrq();
public:
static void detect();
diff --git a/Source/Kernel/Devices/Floppy/FloppyDrive.class.cpp b/Source/Kernel/Devices/Floppy/FloppyDrive.class.cpp
index 7edf24a..b7fd69b 100644
--- a/Source/Kernel/Devices/Floppy/FloppyDrive.class.cpp
+++ b/Source/Kernel/Devices/Floppy/FloppyDrive.class.cpp
@@ -2,6 +2,7 @@
#include "FloppyController.class.h"
#include <TaskManager/Task.ns.h>
#include <DeviceManager/Time.ns.h>
+#include <VTManager/SimpleVT.class.h>
#include <Core/Log.ns.h>
using namespace Sys;
@@ -91,16 +92,18 @@ bool FloppyDrive::calibrate() {
int st0, cyl = -1;
- if (!setMotorState(true)) return false;
+ if (!setMotorState(true)) {
+ *kvt << getName() << ": calibrate fail\n";
+ return false;
+ }
for (int i = 0; i < 10; i++) {
- asm volatile("cli");
+ m_fdc->resetIrq();
m_fdc->writeCmd(FC_RECALIBRATE);
m_fdc->writeCmd(m_driveNumber);
- Task::currThread()->waitIRQ(m_fdc->m_irq);
+ m_fdc->waitIrq();
m_fdc->checkInterrupt(&st0, &cyl);
- asm volatile("sti");
if (st0 & 0xC0) {
continue;
@@ -111,6 +114,7 @@ bool FloppyDrive::calibrate() {
}
}
setMotorState(false);
+ *kvt << getName() << ": calibrate fail\n";
return false;
}
@@ -137,47 +141,44 @@ bool FloppyDrive::killMotor() {
return true;
}
-bool FloppyDrive::seek(u32int cyli, s32int head) {
+bool FloppyDrive::seek(u32int cyli, s32int head, bool recursive) {
if (cyli >= m_cylinders) return false;
- m_fdc->setActiveDrive(m_driveNumber);
setMotorState(true); //Turn on motor
int st0, cyl = -1;
- for (u32int i = 0; i < 10; i++) {
- asm volatile ("cli");
+ for (u32int i = 0; i < (recursive ? 10 : 5); i++) {
+ m_fdc->resetIrq();
m_fdc->writeCmd(FC_SEEK);
- m_fdc->writeCmd(head << 2);
+ m_fdc->writeCmd(head << 2 | m_driveNumber);
m_fdc->writeCmd(cyl);
- Task::currThread()->waitIRQ(m_fdc->m_irq);
+ m_fdc->waitIrq();
m_fdc->checkInterrupt(&st0, &cyl);
- asm volatile("sti");
if (st0 & 0xC0) { //Error
continue;
}
- if (cyl == 0xFF or cyl == 0x00) { //0xFF for bochs, 0x00 for qemu :D
- setMotorState(false);
- m_fdc->setNoActiveDrive();
- return true;
- }
- if (cyl == (int)cyli) {
+ if (cyl == 0xFF or cyl == 0x00 or cyl == (int)cyli) { //0xFF for bochs, 0x00 for qemu :D
setMotorState(false);
- m_fdc->setNoActiveDrive();
return true;
}
}
- setMotorState(false);
- m_fdc->setNoActiveDrive();
- return false;
+ if (recursive) {
+ setMotorState(false);
+ *kvt << getName() << ": seek fail\n";
+ return false;
+ } else {
+ calibrate();
+ return seek(cyli, head, true);
+ }
}
bool FloppyDrive::doTrack(u32int cyl, u8int dir) {
+ m_fdc->setActiveDrive(m_driveNumber);
if (!seek(cyl, 0)) return false;
if (!seek(cyl, 1)) return false;
- m_fdc->setActiveDrive(m_driveNumber);
u8int cmd, flags = 0xC0;
switch (dir) {
@@ -203,7 +204,7 @@ bool FloppyDrive::doTrack(u32int cyl, u8int dir) {
Task::currThread()->sleep(100);
- asm volatile("cli");
+ m_fdc->resetIrq();
m_fdc->writeCmd(cmd);
m_fdc->writeCmd(m_driveNumber); //Drive number & first head << 2
m_fdc->writeCmd(cyl); //Cylinder
@@ -214,7 +215,7 @@ bool FloppyDrive::doTrack(u32int cyl, u8int dir) {
m_fdc->writeCmd(0x1B);
m_fdc->writeCmd(0xFF);
- Task::currThread()->waitIRQ(m_fdc->m_irq);
+ m_fdc->waitIrq();
u8int st0, st1, st2, rcy, rhe, rse, bps;
st0 = m_fdc->readData();
@@ -224,7 +225,6 @@ bool FloppyDrive::doTrack(u32int cyl, u8int dir) {
rhe = m_fdc->readData();
rse = m_fdc->readData();
bps = m_fdc->readData();
- asm volatile("sti");
int error = 0;
@@ -274,12 +274,11 @@ bool FloppyDrive::doTrack(u32int cyl, u8int dir) {
bool FloppyDrive::readOnly() {
m_fdc->setActiveDrive(m_driveNumber);
- asm volatile("cli");
+ m_fdc->resetIrq();
m_fdc->writeCmd(FC_SENSE_DRIVE_STATUS);
m_fdc->writeCmd(m_driveNumber);
- Task::currThread()->waitIRQ(m_fdc->m_irq);
+ m_fdc->waitIrq();
u8int st3 = m_fdc->readData();
- asm volatile("sti");
bool ret = (st3 & 0x80 ? true : false);
@@ -296,16 +295,13 @@ bool FloppyDrive::readBlocks(u64int start, u32int count, u8int *data) {
u32int startblock = start;
if (count == 1) {
u32int cylinder = (startblock / (m_sectors * 2)), offset = (startblock % (m_sectors * 2)) * 512;
- if (m_buffCyl == cylinder && m_buffTime >= Time::uptime() - 4) {
- memcpy(data, (const u8int*)(&m_buffer[offset]), 512);
- return true;
- } else {
+ if (m_buffCyl != cylinder or m_buffTime < Time::uptime() - 4) {
if (!doTrack(cylinder, FD_READ)) return false;
m_buffCyl = cylinder;
m_buffTime = Time::uptime();
- memcpy(data, (const u8int*)(&m_buffer[offset]), 512);
- return true;
}
+ memcpy(data, (const u8int*)(&m_buffer[offset]), 512);
+ return true;
} else {
m_buffCyl = 0xFFFF; //Invalid cylinder
m_buffTime = 0;
diff --git a/Source/Kernel/Devices/Floppy/FloppyDrive.class.h b/Source/Kernel/Devices/Floppy/FloppyDrive.class.h
index 75926ea..73229b1 100644
--- a/Source/Kernel/Devices/Floppy/FloppyDrive.class.h
+++ b/Source/Kernel/Devices/Floppy/FloppyDrive.class.h
@@ -22,7 +22,7 @@ class FloppyDrive : public BlockDevice {
bool calibrate();
bool setMotorState(bool on);
bool killMotor();
- bool seek(u32int cyli, s32int head);
+ bool seek(u32int cyli, s32int head, bool recursive = false);
bool doTrack(u32int cyl, u8int dir);
public:
diff --git a/Source/Kernel/FileSystems/FAT/FATDirectoryNode.class.h b/Source/Kernel/FileSystems/FAT/FATDirectoryNode.class.h
new file mode 100644
index 0000000..c2f55e1
--- /dev/null
+++ b/Source/Kernel/FileSystems/FAT/FATDirectoryNode.class.h
@@ -0,0 +1,16 @@
+#ifndef DEF_FATDIRECTORYNODE_CLASS_H
+#define DEF_FATDIRECTORYNODE_CLASS_H
+
+#include <VFS/DirectoryNode.class.h>
+
+class FATDirectoryNode : public DirectoryNode {
+ friend class FATFS;
+ FATDirectoryNode(String name, FileSystem* fs, FSNode* parent, u32int permissions = 0777,
+ u32int uid = 0, u32int gid = 0) :
+ DirectoryNode(name, fs, parent, permissions, uid, gid) {}
+
+ u32int m_firstCluster;
+ u32int m_firstDirEntryID; //id of the first directory entry corresponding to this file in parent directory
+};
+
+#endif
diff --git a/Source/Kernel/FileSystems/FAT/FATFS.class.cpp b/Source/Kernel/FileSystems/FAT/FATFS.class.cpp
new file mode 100644
index 0000000..4c20b3f
--- /dev/null
+++ b/Source/Kernel/FileSystems/FAT/FATFS.class.cpp
@@ -0,0 +1,247 @@
+#include "FATFS.class.h"
+#include <VTManager/SimpleVT.class.h>
+#include "FATFileNode.class.h"
+#include "FATDirectoryNode.class.h"
+#include <VFS/VFS.ns.h>
+#include <ByteArray.class.h>
+
+#define FIRSTCLUS(node) ((u32int&)(node->type() == NT_DIRECTORY ? \
+ ((FATDirectoryNode*)(node))->m_firstCluster : \
+ ((FATFileNode*)(node))->m_firstCluster))
+#define FIRSTDEID(node) ((u32int&)(node->type() == NT_DIRECTORY ? \
+ ((FATDirectoryNode*)(node))->m_firstDirEntryID : \
+ ((FATFileNode*)(node))->m_firstDirEntryID))
+
+FileSystem* FATFS::mount(Partition* p, DirectoryNode* mountpoint, bool readwrite) {
+ if (readwrite) return 0;
+ if (mountpoint != 0 and !mountpoint->mountpointable()) return 0;
+ // *** READ BOOT SECTOR ***
+ union {
+ fat_BS_t s;
+ u8int c[512];
+ } bs;
+ if (!p->readBlocks(0, 1, bs.c)) return 0;
+ // *** CHECK FILESYSTEM TYPE ***
+ if (bs.s.extBS_16.boot_signature != 0x28 and bs.s.extBS_16.boot_signature != 0x29
+ and bs.s.extBS_32.boot_signature != 0x28 and bs.s.extBS_32.boot_signature != 0x29) return 0;
+ // *** DO SOME CALCULATIONS ***
+ FATFS* fs = new FATFS(p);
+ fs->m_fatSize = (bs.s.table_size_16 == 0 ? bs.s.extBS_32.table_size_32 : bs.s.table_size_16);
+ fs->m_totalSectors = (bs.s.total_sectors_16 == 0 ? bs.s.total_sectors_32 : bs.s.total_sectors_16);
+ fs->m_rootDirSectors = ((bs.s.root_entry_count * 32) + (bs.s.bytes_per_sector - 1)) / bs.s.bytes_per_sector;
+ fs->m_firstDataSector = bs.s.reserved_sector_count + (fs->m_fatSize * bs.s.table_count);
+ fs->m_clusterSize = bs.s.bytes_per_sector * bs.s.sectors_per_cluster;
+ u32int dataSectors = fs->m_totalSectors - (fs->m_firstDataSector + fs->m_rootDirSectors);
+ fs->m_countOfClusters = dataSectors / bs.s.sectors_per_cluster;
+ if (fs->m_countOfClusters < 4085) { //Find out FAT type
+ fs->m_fatType = 12;
+ } else if (fs->m_countOfClusters < 65525) {
+ fs->m_fatType = 16;
+ } else {
+ fs->m_fatType = 32;
+ }
+ fs->m_readOnly = true;
+ fs->m_bs = bs.s;
+ // *** CREATE ROOT DIRECTORY NODE ***
+ fs->m_rootNode = new FATDirectoryNode("/", fs, mountpoint);
+ FIRSTCLUS(fs->m_rootNode) = 2;
+ if (fs->m_fatType == 32) FIRSTCLUS(fs->m_rootNode) = bs.s.extBS_32.root_cluster;
+ if (!fs->m_rootNode->loadContent()) {
+ *kvt << "Could not read FAT filesystem root directory.\n";
+ delete fs;
+ return 0;
+ }
+ fs->m_fatCache.init(fs->m_fatType == 12 ? 8 : (fs->m_fatType == 16 ? 20 : 40));
+ if (mountpoint != 0) mountpoint->mount(fs->m_rootNode);
+ VFS::registerFilesystem(fs);
+ *kvt << "Detected a FAT" << (s64int)fs->m_fatType << " filesystem.\n" <<
+ "root_dir_sectors:" << fs->m_rootDirSectors << " fat_size:" << fs->m_fatSize << " total_sectors:" <<
+ fs->m_totalSectors << " data_sectors:" << dataSectors << " count_of_clusters:" << fs->m_countOfClusters <<
+ " sizeof(fat_dir_entry_t):" << sizeof(fat_dir_entry_t) << " first_data_sector:" << fs->m_firstDataSector <<
+ " cluster_size:" << fs->m_clusterSize << "\n";
+ return fs;
+}
+
+u32int FATFS::nextCluster(u32int cluster) {
+ u8int fat_table[m_part->blockSize()];
+ u32int val;
+ if (m_fatType == 12) {
+ u32int fat_offset = cluster + (cluster / 2);
+ u32int fat_sector = m_bs.reserved_sector_count + (fat_offset / m_part->blockSize());
+ u32int ent_offset = fat_offset % m_part->blockSize();
+ m_fatCache.readBlocks(fat_sector, 1, fat_table);
+ u16int tblval = *(u16int*)&fat_table[ent_offset];
+ if (cluster & 1) val = tblval >> 4;
+ else val = tblval & 0x0FFF;
+ if (val >= 0xFF7) val = 0;
+ } else if (m_fatType == 16) {
+ u32int fat_offset = cluster * 2;
+ u32int fat_sector = m_bs.reserved_sector_count + (fat_offset / m_part->blockSize());
+ u32int ent_offset = fat_offset % m_part->blockSize();
+ m_fatCache.readBlocks(fat_sector, 1, fat_table);
+ u16int tblval = *(u16int*)&fat_table[ent_offset];
+ val = tblval;
+ if (tblval >= 0xFFF7) val = 0;
+ } else if (m_fatType == 32) {
+ u32int fat_offset = cluster * 4;
+ u32int fat_sector = m_bs.reserved_sector_count + (fat_offset / m_part->blockSize());
+ u32int ent_offset = fat_offset % m_part->blockSize();
+ m_fatCache.readBlocks(fat_sector, 1, fat_table);
+ val = *(u32int*)&fat_table[ent_offset] & 0x0FFFFFFF;
+ if (val >= 0x0FFFFFF7) val = 0;
+ }
+ return val;
+}
+
+bool FATFS::readCluster(u32int cluster, u8int* data) {
+ u32int firstSector = ((cluster - 2) * m_bs.sectors_per_cluster) + m_firstDataSector;
+ if (cluster > 2 and m_fatType != 32) firstSector += m_rootDirSectors;
+ return m_part->readBlocks(firstSector, m_bs.sectors_per_cluster, data);
+}
+
+bool FATFS::unmount() {
+ if (m_readOnly) return true;
+ return false;
+}
+
+bool FATFS::setName(FSNode* node, String name) {
+ if (m_readOnly) return false;
+ return false;
+}
+
+bool FATFS::setPermissions(FSNode* node, u32int permissions) {
+ if (m_readOnly) return false;
+ return false;
+}
+
+bool FATFS::setUid(FSNode* node, u32int uid) {
+ if (m_readOnly) return false;
+ return false;
+}
+
+bool FATFS::setGid(FSNode* node, u32int gid) {
+ if (m_readOnly) return false;
+ return false;
+}
+
+bool FATFS::setParent(FSNode* node, FSNode* parent) {
+ if (m_readOnly) return false;
+ return false;
+}
+
+u32int FATFS::read(FileNode* file, u64int position, u32int max_length, u8int *data) {
+ u32int len = max_length;
+ if (position >= file->getLength()) return 0;
+ if (position + len > file->getLength()) len = file->getLength() - position;
+ u32int firstCluster = position / m_clusterSize, clusterOffset = position % m_clusterSize;
+ u32int clusters = (len + clusterOffset) / m_clusterSize + 1, lastClusBytesToRead = (len + clusterOffset) % m_clusterSize;
+ u32int clust = FIRSTCLUS(file);
+ //Find first cluster
+ for (u32int i = 0; i < firstCluster and clust != 0; i++) clust = nextCluster(clust);
+ if (clust == 0) return 0;
+ //Read first cluster
+ u8int* temp = (u8int*)Mem::alloc(m_clusterSize);
+ readCluster(clust, temp);
+ memcpy(data, temp + clusterOffset, (len > m_clusterSize - clusterOffset ? m_clusterSize - clusterOffset : len));
+ //Read next cluster
+ u32int pos = (m_clusterSize - clusterOffset);
+ for (u32int i = 1; i < clusters; i++) {
+ clust = nextCluster(clust);
+ if (clust == 0) break;
+ readCluster(clust, temp);
+ memcpy(data + pos, temp, (i == clusters - 1 ? lastClusBytesToRead : m_clusterSize));
+ pos += m_clusterSize;
+ }
+ Mem::free(temp);
+ return len;
+}
+
+bool FATFS::write(FileNode* file, u64int position, u32int length, u8int* data) {
+ if (m_readOnly) return false;
+ return false;
+}
+
+bool FATFS::truncate(FileNode* file) {
+ if (m_readOnly) return false;
+ return false;
+}
+
+bool FATFS::loadContents(DirectoryNode* dir) {
+ u32int cluster = FIRSTCLUS(dir);
+ union {
+ u8int *c;
+ fat_dir_entry_t *e;
+ } e;
+
+ u32int entries = m_clusterSize / sizeof(fat_dir_entry_t);
+ if (cluster == 2 and m_fatType != 32) { //This is the value we use for the root directory
+ e.c = (u8int*)Mem::alloc(m_rootDirSectors * m_part->blockSize());
+ if (!m_part->readBlocks(m_firstDataSector, m_rootDirSectors, e.c)) return false;
+ } else {
+ e.c = (u8int*)Mem::alloc(m_clusterSize);
+ }
+
+ ByteArray lfnBuffer;
+ while (cluster != 0) {
+ if (cluster != 2 or m_fatType == 32) {
+ if (!readCluster(cluster, e.c)) return false;
+ }
+ for (u32int i = 0; i < entries; i++) {
+ if (e.e[i].attributes == FA_LFN && e.c[i*32] != 0xE5) { //Long file name entry
+ u8int num = e.c[i*32] & 0x3;
+ if (lfnBuffer.size() < num * 26) lfnBuffer.resize(num * 26);
+ num--;
+ memcpy(lfnBuffer + (num * 26), e.c + (i*32 + 1), 10);
+ memcpy(lfnBuffer + (num * 26 + 10), e.c + (i*32 + 14), 12);
+ memcpy(lfnBuffer + (num * 26 + 22), e.c + (i*32 + 28), 4);
+ }
+ if (e.e[i].attributes & FA_VOLUMEID) continue;
+ if (e.e[i].name[0] == 0 or e.e[i].name[0] == 0xE5) continue; //Nothing intresting here.
+ String name;
+ if (lfnBuffer.empty()) {
+ for (int j = 0; j < 8; j++) {
+ if (e.e[i].name[j] == ' ') break;
+ name += WChar(e.e[i].name[j]);
+ }
+ for (int j = 0; j < 3; j++) {
+ if (e.e[i].extension[j] == ' ') break;
+ if (j == 0) name += ".";
+ name += WChar(e.e[i].extension[j]);
+ }
+ } else {
+ name = lfnBuffer.toString(UE_UTF16_LE);
+ lfnBuffer.clear();
+ }
+ u32int first_clus = (e.e[i].first_clust_high << 16) + e.e[i].first_clust_low;
+ FSNode* n;
+ if (e.e[i].attributes & FA_DIRECTORY) {
+ if (name == "." or name == "..") continue;
+ n = new FATDirectoryNode(name, this, dir);
+ } else {
+ n = new FATFileNode(name, this, dir, e.e[i].size);
+ }
+ FIRSTCLUS(n) = first_clus;
+ dir->getChildren().push(n);
+ }
+ if (cluster == 2 && m_fatType != 32) break; //We are in a FAT12/16 root directory
+ cluster = nextCluster(cluster);
+ }
+
+ Mem::free(e.c);
+ return true;
+}
+
+FileNode* FATFS::createFile(DirectoryNode* parent, String name) {
+ if (m_readOnly) return false;
+ return 0;
+}
+
+DirectoryNode* FATFS::createDirectory(DirectoryNode* parent, String name) {
+ if (m_readOnly) return false;
+ return 0;
+}
+
+bool FATFS::remove(DirectoryNode* parent, FSNode* node) {
+ if (m_readOnly) return false;
+ return false;
+}
diff --git a/Source/Kernel/FileSystems/FAT/FATFS.class.h b/Source/Kernel/FileSystems/FAT/FATFS.class.h
new file mode 100644
index 0000000..114622a
--- /dev/null
+++ b/Source/Kernel/FileSystems/FAT/FATFS.class.h
@@ -0,0 +1,134 @@
+#ifndef DEF_FATFS_CLASS_H
+#define DEF_FATFS_CLASS_H
+
+#include <VFS/FileSystem.proto.h>
+#include <VFS/Part.ns.h>
+#include <VFS/BlockCache.class.h>
+
+struct fat_extBS_32_t { //Extended boot sector for FAT32
+ unsigned int table_size_32;
+ unsigned short extended_flags;
+ unsigned short fat_version;
+ unsigned int root_cluster;
+ unsigned short fat_info;
+ unsigned short backup_BS_sector;
+ unsigned char reserved_0[12];
+ unsigned char drive_number;
+ unsigned char reserved_1;
+ unsigned char boot_signature;
+ unsigned int volume_id;
+ unsigned char volume_label[11];
+ unsigned char fat_type_label[8];
+}__attribute__((packed));
+
+struct fat_extBS_16_t { //Extended boot sector for FAT12 and FAT16
+ unsigned char bios_drive_num;
+ unsigned char reserved1;
+ unsigned char boot_signature;
+ unsigned int volume_id;
+ unsigned char volume_label[11];
+ unsigned char fat_type_label[8];
+}__attribute__((packed));
+
+struct fat_BS_t { //Boot sector
+ unsigned char bootjmp[3];
+ unsigned char oem_name[8];
+ unsigned short bytes_per_sector;
+ unsigned char sectors_per_cluster;
+ unsigned short reserved_sector_count;
+ unsigned char table_count;
+ unsigned short root_entry_count;
+ unsigned short total_sectors_16;
+ unsigned char media_type;
+ unsigned short table_size_16;
+ unsigned short sectors_per_track;
+ unsigned short head_side_count;
+ unsigned int hidden_sector_count;
+ unsigned int total_sectors_32;
+ union {
+ fat_extBS_32_t extBS_32;
+ fat_extBS_16_t extBS_16;
+ };
+}__attribute__((packed));
+
+struct fat_date_t {
+ u16int year : 7;
+ u16int month : 4;
+ u16int day : 5;
+}__attribute__((packed));
+
+struct fat_time_t {
+ u16int hour : 5;
+ u16int minutes : 6;
+ u16int seconds : 5;
+}__attribute__((packed));
+
+struct fat_dir_entry_t {
+ char name[8];
+ char extension[3];
+ u8int attributes;
+ u8int reserved;
+ u8int createtenthsofseconds;
+ fat_time_t created_time;
+ fat_date_t created_date;
+ fat_date_t accessed_date;
+ u16int first_clust_high; //always 0 on FAT12/16
+ fat_time_t modified_time;
+ fat_date_t modified_date;
+ u16int first_clust_low;
+ u32int size;
+}__attribute__((packed));
+
+#define FA_READONLY 0x01
+#define FA_HIDDEN 0x02
+#define FA_SYSTEM 0x04
+#define FA_VOLUMEID 0x08
+#define FA_DIRECTORY 0x10
+#define FA_ARCHIVE 0x20
+#define FA_LFN 0x0F
+
+class FATFS : public FileSystem {
+ private:
+ fat_BS_t m_bs;
+ bool m_readOnly;
+ u32int m_fatSize; //Size of one FAT, in sectors
+ u32int m_totalSectors; //Total sectors used by the FAT
+ u32int m_rootDirSectors; //Sectors used by the root directory
+ u32int m_firstDataSector; //First data sector, start of cluster 2
+ u32int m_countOfClusters; //Count of usable clusters, EXCLUDING the ones used by the root directory
+ u32int m_clusterSize; //size of a cluster in bytes
+ u32int m_fatType; //12, 16 or 32
+ Partition* m_part;
+ BlockCache<Partition> m_fatCache;
+
+ u32int nextCluster(u32int cluster); //Get the next cluster number in the chain (0 = EOF)
+ bool readCluster(u32int cluster, u8int* data); //Read the content of a cluster to a buffer
+
+ ~FATFS() {}
+ FATFS(Partition* p) : m_part(p), m_fatCache(p) {}
+
+ public:
+ static FileSystem* mount(Partition* p, DirectoryNode* mountpoint, bool readwrite = false);
+
+ bool unmount();
+
+ bool setName(FSNode* node, String name);
+ bool setPermissions(FSNode* node, u32int permissions);
+ bool setUid(FSNode* node, u32int uid);
+ bool setGid(FSNode* node, u32int gid);
+ bool setParent(FSNode* node, FSNode* parent);
+
+ u32int read(FileNode* file, u64int position, u32int max_length, u8int *data);
+ bool write(FileNode* file, u64int position, u32int length, u8int *data);
+ bool truncate(FileNode* file);
+
+ bool loadContents(DirectoryNode* dir);
+ FileNode* createFile(DirectoryNode* parent, String name);
+ DirectoryNode* createDirectory(DirectoryNode* parent, String name);
+ bool remove(DirectoryNode* parent, FSNode* node);
+
+ Partition* getPart() { return m_part; }
+};
+
+#endif
+
diff --git a/Source/Kernel/FileSystems/FAT/FATFileNode.class.h b/Source/Kernel/FileSystems/FAT/FATFileNode.class.h
new file mode 100644
index 0000000..b64f911
--- /dev/null
+++ b/Source/Kernel/FileSystems/FAT/FATFileNode.class.h
@@ -0,0 +1,16 @@
+#ifndef DEF_FATFILENODE_CLASS_H
+#define DEF_FATFILENODE_CLASS_H
+
+#include <VFS/FileNode.class.h>
+
+class FATFileNode : public FileNode {
+ friend class FATFS;
+ FATFileNode (String name, FileSystem* fs, FSNode* parent, u32int size, u32int permissions = 0777,
+ u32int uid = 0, u32int gid = 0) :
+ FileNode(name, fs, parent, size, permissions, uid, gid){}
+
+ u32int m_firstCluster;
+ u32int m_firstDirEntryID; //id of the first directory entry corresponding to this file in parent directory
+};
+
+#endif
diff --git a/Source/Kernel/FileSystems/RamFS/RamFS.class.cpp b/Source/Kernel/FileSystems/RamFS/RamFS.class.cpp
index 5997841..e6370d0 100644
--- a/Source/Kernel/FileSystems/RamFS/RamFS.class.cpp
+++ b/Source/Kernel/FileSystems/RamFS/RamFS.class.cpp
@@ -1,30 +1,36 @@
#include "RamFS.class.h"
#include <VFS/DirectoryNode.class.h>
#include "RamFileNode.class.h"
+#include <VFS/VFS.ns.h>
RamFS::RamFS() {
}
RamFS::~RamFS() {
- delete m_rootNode;
}
RamFS* RamFS::mount(u32int maxSize, DirectoryNode* mountpoint) {
+ if (mountpoint != 0 and !mountpoint->mountpointable()) return 0;
RamFS* rfs = new RamFS();
rfs->m_maxSize = maxSize;
rfs->m_usedSize = 0;
rfs->m_isWritable = true;
rfs->m_rootNode = new DirectoryNode("/", rfs, mountpoint);
+ if (mountpoint != 0) mountpoint->mount(rfs->m_rootNode);
+ VFS::registerFilesystem(rfs);
return rfs;
}
RamFS* RamFS::mount(u8int *ptr, u32int maxSize, DirectoryNode* mountpoint, bool writable) {
+ if (mountpoint != 0 and !mountpoint->mountpointable()) return 0;
RamFS* rfs = new RamFS();
rfs->m_maxSize = maxSize;
rfs->m_usedSize = 0;
rfs->m_isWritable = true;
rfs->m_rootNode = new DirectoryNode("/", rfs, mountpoint);
+ if (mountpoint != 0) mountpoint->mount(rfs->m_rootNode);
+ VFS::registerFilesystem(rfs);
union {
u8int* c;
@@ -81,7 +87,7 @@ RamFS* RamFS::mount(u8int *ptr, u32int maxSize, DirectoryNode* mountpoint, bool
}
bool RamFS::unmount() {
- return m_rootNode->unmountable();
+ return true;
}
bool RamFS::setName(FSNode* node, String name) { return true; }
@@ -164,6 +170,7 @@ bool RamFS::remove(DirectoryNode* parent, FSNode* node) {
if (node->type() == NT_FILE) {
u8int *d = ((RamFileNode*)node)->m_data;
if (d != 0) Mem::free(d);
+ ((RamFileNode*)node)->m_data = 0;
}
return true;
}
diff --git a/Source/Kernel/FileSystems/RamFS/RamFS.class.h b/Source/Kernel/FileSystems/RamFS/RamFS.class.h
index 1d60796..0368e60 100644
--- a/Source/Kernel/FileSystems/RamFS/RamFS.class.h
+++ b/Source/Kernel/FileSystems/RamFS/RamFS.class.h
@@ -17,10 +17,10 @@ struct initrd_file_header {
class RamFS : public FileSystem {
private:
- ~RamFS();
+ virtual ~RamFS();
RamFS(const RamFS& other);
RamFS();
- bool unmount(); //TO BE USED ONLY BY VFS::UNMOUNT (when will exist...)
+ bool unmount();
u32int m_maxSize;
u32int m_usedSize;
@@ -43,6 +43,8 @@ class RamFS : public FileSystem {
FileNode* createFile(DirectoryNode* parent, String name);
DirectoryNode* createDirectory(DirectoryNode* parent, String name);
bool remove(DirectoryNode* parent, FSNode* node);
+
+ Partition* getPart() { return 0; }
};
#endif
diff --git a/Source/Kernel/FileSystems/RamFS/RamFileNode.class.h b/Source/Kernel/FileSystems/RamFS/RamFileNode.class.h
index d600630..2abad64 100644
--- a/Source/Kernel/FileSystems/RamFS/RamFileNode.class.h
+++ b/Source/Kernel/FileSystems/RamFS/RamFileNode.class.h
@@ -11,6 +11,8 @@ class RamFileNode : public FileNode {
u32int uid = 0, u32int gid = 0) :
FileNode(name, fs, parent, 0, permissions, uid, gid), m_data(0) {}
+ ~RamFileNode() { if (m_data != 0) delete m_data; }
+
u8int *m_data; //We don't take care of allocation/freeing here, RamFS:: does that for us
void setLength(u32int length) { m_length = length; }
diff --git a/Source/Kernel/Linker/ElfBinary.class.cpp b/Source/Kernel/Linker/ElfBinary.class.cpp
index 27e5474..0518c38 100644
--- a/Source/Kernel/Linker/ElfBinary.class.cpp
+++ b/Source/Kernel/Linker/ElfBinary.class.cpp
@@ -9,7 +9,7 @@ ElfBinary::~ElfBinary() {
Binary* ElfBinary::load(File& file) {
elf_ehdr_t hdr;
- file.read<elf_ehdr_t> (&hdr);
+ if (!file.read<elf_ehdr_t> (&hdr)) return 0;
//Verify we have an elf file
if (hdr.e_ident[0] != 0x7F or hdr.e_ident[1] != 'E' or hdr.e_ident[2] != 'L' or hdr.e_ident[3] != 'F') return 0;
diff --git a/Source/Kernel/Linker/MelonBinary.class.cpp b/Source/Kernel/Linker/MelonBinary.class.cpp
index 0737b71..8a85977 100644
--- a/Source/Kernel/Linker/MelonBinary.class.cpp
+++ b/Source/Kernel/Linker/MelonBinary.class.cpp
@@ -2,7 +2,7 @@
Binary* MelonBinary::load(File& file) {
u32int magic;
- file.read<u32int>(&magic);
+ if (!file.read<u32int>(&magic)) return 0;
if (magic == 0xFEEDBEEF) {
MelonBinary* r = new MelonBinary;
file.read<u32int>(&r->m_size);
diff --git a/Source/Kernel/Makefile b/Source/Kernel/Makefile
index a70c8c5..660017a 100644
--- a/Source/Kernel/Makefile
+++ b/Source/Kernel/Makefile
@@ -66,6 +66,7 @@ Objects = Core/loader.wtf.o \
VFS/DirectoryNode.class.o \
UserManager/Usr.ns.o \
FileSystems/RamFS/RamFS.class.o \
+ FileSystems/FAT/FATFS.class.o \
SyscallManager/IDT.ns.o \
SyscallManager/Ressource.class.o \
SyscallManager/Res.ns.o \
@@ -76,6 +77,8 @@ Objects = Core/loader.wtf.o \
Devices/Keyboard/PS2Keyboard.class.o \
Devices/Floppy/FloppyController.class.o \
Devices/Floppy/FloppyDrive.class.o \
+ Devices/ATA/ATAController.class.o \
+ Devices/ATA/ATADrive.class.o \
Devices/Timer.class.o
all: $(OutFile)
diff --git a/Source/Kernel/Shell/KernelShell-fs.class.cpp b/Source/Kernel/Shell/KernelShell-fs.class.cpp
index fa2078d..c389d45 100644
--- a/Source/Kernel/Shell/KernelShell-fs.class.cpp
+++ b/Source/Kernel/Shell/KernelShell-fs.class.cpp
@@ -125,3 +125,21 @@ void KernelShell::run(Vector<String>& args) {
}
}
}
+
+void KernelShell::hexdump(Vector<String>& args) {
+ if (args.size() == 1) {
+ *m_vt << "No file to hexdump.\n";
+ } else {
+ for (u32int i = 1; i < args.size(); i++) {
+ File f(args[i], FM_READ, m_cwd);
+ if (f.valid()) {
+ u8int *buff = (u8int*)Mem::alloc(f.length());
+ f.read(f.length(), buff);
+ m_vt->hexDump(buff, f.length());
+ Mem::free(buff);
+ } else {
+ *m_vt << "Error reading from file " << args[i] << "\n";
+ }
+ }
+ }
+}
diff --git a/Source/Kernel/Shell/KernelShell-sys.class.cpp b/Source/Kernel/Shell/KernelShell-sys.class.cpp
index 6243b0f..da5378b 100644
--- a/Source/Kernel/Shell/KernelShell-sys.class.cpp
+++ b/Source/Kernel/Shell/KernelShell-sys.class.cpp
@@ -4,6 +4,8 @@
#include <MemoryManager/Mem.ns.h>
#include <MemoryManager/PhysMem.ns.h>
#include <VFS/Part.ns.h>
+#include <VFS/VFS.ns.h>
+#include <FileSystems/RamFS/RamFS.class.h>
void KernelShell::devices(Vector<String>& args) {
Vector<Device*> dev = Dev::findDevices();
@@ -58,3 +60,42 @@ void KernelShell::part(Vector<String>& args) {
}
}
}
+
+void KernelShell::mount(Vector<String>& args) {
+ if (args.size() == 1) {
+ for (u32int i = 0; i < VFS::filesystems.size(); i++) {
+ *m_vt << VFS::filesystems[i]->getIdentifier() << "\n";
+ }
+ } else if (args.size() == 2) {
+ if (args[1] == "help") {
+ *m_vt << "Usage: mount [help|<options>]\n" <<
+ "Options formats :\n" <<
+ " - <mountpoint>:ramfs\n" <<
+ " - <mountpoint>:[<dev_class>]:<dev_number>:<part_number>[:<type>[:[ro|rw]]]\n" <<
+ "You can have a list of available block devices and partitions by typing 'part'.\n";
+ } else {
+ if (VFS::mount(args[1], m_vt)) *m_vt << "Ok, filesystem mounted.\n";
+ }
+ } else {
+ *m_vt << "Usage: mount [<device> <mountpoint>\n";
+ }
+}
+
+void KernelShell::readblock(Vector<String>& args) {
+ if (args.size() == 3) {
+ Vector<Device*> devcs = Dev::findDevices("block");
+ u32int id = args[1].toInt(), block = args[2].toInt();
+ if (id < devcs.size()) {
+ BlockDevice* bdev = (BlockDevice*)devcs[id];
+ *m_vt << "Block " << block << " from device " << bdev->getName() << " (" << bdev->getClass() << ")\n";
+ u8int* buff = (u8int*)Mem::alloc(bdev->blockSize());
+ bdev->readBlocks(block, 1, buff);
+ m_vt->hexDump(buff, 32);
+ Mem::free(buff);
+ } else {
+ *m_vt << "Block device #" << id << " does not exist.\n";
+ }
+ } else {
+ *m_vt << "Usage: readblock <dev id> <block id>\n";
+ }
+}
diff --git a/Source/Kernel/Shell/KernelShell.class.cpp b/Source/Kernel/Shell/KernelShell.class.cpp
index d62d822..71a717a 100644
--- a/Source/Kernel/Shell/KernelShell.class.cpp
+++ b/Source/Kernel/Shell/KernelShell.class.cpp
@@ -3,8 +3,8 @@
#include <DeviceManager/Kbd.ns.h>
#include <SimpleList.class.h>
#include <MemoryManager/PhysMem.ns.h>
-#include <VFS/VFS.ns.h>
#include <TaskManager/Task.ns.h>
+#include <VFS/VFS.ns.h>
u32int KernelShell::m_instances = 0;
@@ -60,6 +60,9 @@ u32int KernelShell::run() {
{"free", &KernelShell::free},
{"uptime", &KernelShell::uptime},
{"part", &KernelShell::part},
+ {"readblock", &KernelShell::readblock},
+ {"mount", &KernelShell::mount},
+ {"hexdump", &KernelShell::hexdump},
{0, 0}
};
@@ -81,6 +84,9 @@ u32int KernelShell::run() {
*m_vt << " - free shows memory usage (frames and kheap)\n";
*m_vt << " - uptime shows seconds since boot\n";
*m_vt << " - part shows all detected block devs and partitions\n";
+ *m_vt << " - mount shows mounted devices or mounts a ramfs\n";
+ *m_vt << " - readblock reads a block from a block device and dumps it\n";
+ *m_vt << " - hexdump shows a hexadecimal dump of a file\n";
*m_vt << " - Standard UNIX commands : ls cd cat pwd rm mkdir wf\n";
*m_vt << " - Scroll up with shift+pgup !\n";
} else if (tokens[0] == "reboot") {
@@ -92,6 +98,26 @@ u32int KernelShell::run() {
} else if (tokens[0] == "exit") {
if (tokens.size() == 1) return 0;
return tokens[1].toInt();
+ } else if (tokens[0] == "unmount") {
+ if (tokens.size() == 2) {
+ FSNode* n = VFS::find(tokens[1], m_cwd);
+ bool ok = false;
+ if (n == 0) {
+ ok = false;
+ } else {
+ String p = VFS::path(n);
+ for (u32int i = 0; i < VFS::filesystems.size(); i++) {
+ if (VFS::path(VFS::filesystems[i]->getRootNode()) == p) {
+ ok = VFS::unmount(VFS::filesystems[i]);
+ break;
+ }
+ }
+ }
+ if (ok) *m_vt << "Ok, filesystem unmounted.\n";
+ else *m_vt << "Error.\n";
+ } else {
+ *m_vt << "Usage: unmount <mountpoint>\n";
+ }
} else if (tokens[0] != "" or tokens.size() != 1) {
u32int i = 0;
bool found = false;
diff --git a/Source/Kernel/Shell/KernelShell.class.h b/Source/Kernel/Shell/KernelShell.class.h
index e7549c2..9655def 100644
--- a/Source/Kernel/Shell/KernelShell.class.h
+++ b/Source/Kernel/Shell/KernelShell.class.h
@@ -27,6 +27,7 @@ class KernelShell {
void rm(Vector<String>& args);
void wf(Vector<String>& args);
void run(Vector<String>& args);
+ void hexdump(Vector<String>& args);
//in KernelShell-sys
void devices(Vector<String>& args);
@@ -34,6 +35,8 @@ class KernelShell {
void free(Vector<String>& args);
void uptime(Vector<String>& args);
void part(Vector<String>& args);
+ void readblock(Vector<String>& args);
+ void mount(Vector<String>& args);
void setup(DirectoryNode* cwd, VirtualTerminal *vt);
diff --git a/Source/Kernel/UserManager/Usr.ns.cpp b/Source/Kernel/UserManager/Usr.ns.cpp
index ecf9bae..66e159e 100644
--- a/Source/Kernel/UserManager/Usr.ns.cpp
+++ b/Source/Kernel/UserManager/Usr.ns.cpp
@@ -26,11 +26,13 @@ void load() {
if (VFS::find("/System/Configuration/Groups")) VFS::find("/System/Configuration/Groups")->setPermissions(0600);
if (VFS::find("/System/Configuration/Users")) VFS::find("/System/Configuration/Users")->setPermissions(0600);
TextFile groups("/System/Configuration/Groups", FM_READ);
- while (!groups.eof()) {
- String s = groups.readLine();
- Vector<String> data = s.split(":");
- if (data.size() == 2 and !(s[0] == WChar("#"))) {
- m_groups = m_groups->cons(Group(data[1], data[0].toInt()));
+ if (groups.valid()) {
+ while (!groups.eof()) {
+ String s = groups.readLine();
+ Vector<String> data = s.split(":");
+ if (data.size() == 2 and !(s[0] == WChar("#"))) {
+ m_groups = m_groups->cons(Group(data[1], data[0].toInt()));
+ }
}
}
if (m_groups == 0) {
@@ -39,12 +41,14 @@ void load() {
}
TextFile users("/System/Configuration/Users", FM_READ);
- while (!users.eof()) {
- String s = users.readLine();
- if (s == "" or s[0] == WChar("#")) continue;
- Vector<String> data = s.split(":");
- if (data.size() == 6) {
- m_users = m_users->cons(User(data[1], data[4], data[5], group(data[2].toInt()), data[3], data[0].toInt()));
+ if (users.valid()) {
+ while (!users.eof()) {
+ String s = users.readLine();
+ if (s == "" or s[0] == WChar("#")) continue;
+ Vector<String> data = s.split(":");
+ if (data.size() == 6) {
+ m_users = m_users->cons(User(data[1], data[4], data[5], group(data[2].toInt()), data[3], data[0].toInt()));
+ }
}
}
if (m_users == 0) {
diff --git a/Source/Kernel/VFS/BlockCache.class.cpp b/Source/Kernel/VFS/BlockCache.class.cpp
new file mode 100644
index 0000000..d505a99
--- /dev/null
+++ b/Source/Kernel/VFS/BlockCache.class.cpp
@@ -0,0 +1,89 @@
+#include <DeviceManager/Time.ns.h>
+
+template <typename T>
+BlockCache<T>::BlockCache(T* dev) {
+ m_dev = dev;
+ m_count = 0;
+}
+
+template <typename T>
+BlockCache<T>::~BlockCache() {
+ sync();
+ m_count = 0;
+ delete m_cache;
+ delete m_cacheInfo;
+}
+
+template <typename T>
+void BlockCache<T>::sync() {
+ for (u32int i = 0; i < m_count; i++) {
+ if (m_cacheInfo[i].dirty) m_dev->writeBlocks(m_cacheInfo[i].id, 1, m_cache + (i * m_dev->blockSize()));
+ }
+}
+
+template <typename T>
+void BlockCache<T>::init(u32int count) {
+ m_count = count;
+ m_cacheInfo = new cached_block_t[count];
+ for (u32int i = 0; i < m_count; i++) {
+ m_cacheInfo[i].id = 0;
+ m_cacheInfo[i].lastuse = 0;
+ m_cacheInfo[i].dirty = false;
+ }
+ m_cache = (u8int*)Mem::alloc(m_count * m_dev->blockSize());
+}
+
+template <typename T>
+bool BlockCache<T>::setCache(u64int block, u8int* data, bool dirty) {
+ u32int best = 0;
+ for (u32int i = 0; i < m_count; i++) {
+ if (m_cacheInfo[i].id == block) {
+ best = i;
+ break;
+ }
+ if (m_cacheInfo[i].lastuse < m_cacheInfo[best].lastuse) best = i;
+ }
+ if (best >= m_count) return false;
+ if (m_cacheInfo[best].dirty && (m_cacheInfo[best].id != block or !dirty))
+ m_dev->writeBlocks(m_cacheInfo[best].id, 1, m_cache + (best * m_dev->blockSize()));
+ m_cacheInfo[best].id = block;
+ m_cacheInfo[best].lastuse = Time::uptime();
+ m_cacheInfo[best].dirty = dirty;
+ memcpy(m_cache + (best * m_dev->blockSize()), data, m_dev->blockSize());
+ return true;
+}
+
+template <typename T>
+bool BlockCache<T>::getCache(u64int block, u8int* data) {
+ for (u32int i = 0; i < m_count; i++) {
+ if (m_cacheInfo[i].id == block && m_cacheInfo[i].lastuse != 0) {
+ m_cacheInfo[i].lastuse = Time::uptime();
+ memcpy(data, m_cache + (i * m_dev->blockSize()), m_dev->blockSize());
+ return true;
+ }
+ }
+ return false;
+}
+
+template <typename T>
+bool BlockCache<T>::readBlocks(u64int startblock, u32int count, u8int* data) {
+ if (count == 1) {
+ if (getCache(startblock, data)) return true;
+ if (!m_dev->readBlocks(startblock, count, data)) return false;
+ setCache(startblock, data);
+ return true;
+ } else {
+ return m_dev->readBlocks(startblock, count, data);
+ }
+}
+
+template <typename T>
+bool BlockCache<T>::writeBlocks(u64int startblock, u32int count, u8int* data) {
+ if (m_dev->readOnly()) return false;
+ if (count == 1) {
+ if (!setCache(startblock, data, true)) return m_dev->writeBlocks(startblock, count, data);
+ return true;
+ } else {
+ return m_dev->writeBlocks(startblock, count, data);
+ }
+}
diff --git a/Source/Kernel/VFS/BlockCache.class.h b/Source/Kernel/VFS/BlockCache.class.h
new file mode 100644
index 0000000..0b26180
--- /dev/null
+++ b/Source/Kernel/VFS/BlockCache.class.h
@@ -0,0 +1,32 @@
+#ifndef DEF_BLOCKCACHE_CLASS_H
+#define DEF_BLOCKCACHE_CLASS_H
+
+template <typename T>
+class BlockCache {
+ private:
+ T* m_dev;
+ u32int m_count;
+ struct cached_block_t {
+ u64int id;
+ u32int lastuse;
+ bool dirty;
+ } *m_cacheInfo;
+ u8int* m_cache;
+
+ void sync();
+ bool setCache(u64int block, u8int* data, bool dirty = false);
+ bool getCache(u64int block, u8int* data);
+
+ public:
+ BlockCache(T* dev);
+ ~BlockCache();
+ void init(u32int count);
+
+ bool readBlocks(u64int startblock, u32int count, u8int* data);
+ bool writeBlocks(u64int startblock, u32int count, u8int* data);
+
+};
+
+#include "BlockCache.class.cpp"
+
+#endif
diff --git a/Source/Kernel/VFS/DirectoryNode.class.cpp b/Source/Kernel/VFS/DirectoryNode.class.cpp
index 74c1ff8..55365f0 100644
--- a/Source/Kernel/VFS/DirectoryNode.class.cpp
+++ b/Source/Kernel/VFS/DirectoryNode.class.cpp
@@ -6,6 +6,15 @@ call_t DirectoryNode::m_callTable[] = {
CALL0(0, 0)
};
+DirectoryNode::~DirectoryNode() {
+ if (m_contentLoaded) {
+ for (u32int i = 0; i < m_children.size(); i++) {
+ delete m_children[i];
+ }
+ }
+ if (m_name == "/" && m_parent != NULL) ((DirectoryNode*)(m_parent))->unmount();
+}
+
u32int DirectoryNode::getIdxChildSC(u32int idx) {
if (!runnable()) return (u32int) - 1;
FSNode* n = getChild(idx);
@@ -21,15 +30,29 @@ u32int DirectoryNode::getNameChildSC(u32int name) {
return (u32int) - 1;
}
+u64int DirectoryNode::getLength() {
+ if (m_mounts != 0) return m_mounts->getLength();
+ if (!m_contentLoaded)
+ if (!loadContent())
+ return 0;
+ return m_length;
+}
+
+FSNode* DirectoryNode::getParent() {
+ //if (m_name == "/" and m_parent != 0) return m_parent->getParent();
+ return m_parent;
+}
+
bool DirectoryNode::removable() {
if (!m_contentLoaded)
if (!loadContent())
return false;
- return m_children.empty();
+ return m_children.empty() && (m_mounts == 0);
}
bool DirectoryNode::unmountable() {
if (!m_contentLoaded) return true;
+ if (m_mounts != 0) return false;
for (u32int i = 0; i < m_children.size(); i++) {
if (m_children[i]->type() == NT_DIRECTORY) {
if (!((DirectoryNode*)m_children[i])->unmountable()) return false;
@@ -40,7 +63,22 @@ bool DirectoryNode::unmountable() {
return true;
}
+bool DirectoryNode::mountpointable() {
+ if (!m_contentLoaded)
+ if (!loadContent()) return false;
+ return m_children.empty();
+}
+
+void DirectoryNode::mount(DirectoryNode* childRoot) {
+ m_mounts = childRoot;
+}
+
+void DirectoryNode::unmount() {
+ m_mounts = 0;
+}
+
bool DirectoryNode::loadContent() {
+ if (m_mounts != 0) return m_mounts->loadContent();
if (m_contentLoaded) return true;
bool b = m_fs->loadContents(this);
if (!b) return false;
@@ -50,6 +88,7 @@ bool DirectoryNode::loadContent() {
}
FSNode* DirectoryNode::getChild(u32int index) {
+ if (m_mounts != 0) return m_mounts->getChild(index);
if (!m_contentLoaded)
if (!loadContent())
return NULL;
@@ -58,6 +97,7 @@ FSNode* DirectoryNode::getChild(u32int index) {
}
FSNode* DirectoryNode::getChild(const String& name) {
+ if (m_mounts != 0) return m_mounts->getChild(name);
if (!m_contentLoaded)
if (!loadContent())
return NULL;
@@ -69,18 +109,21 @@ FSNode* DirectoryNode::getChild(const String& name) {
}
FileNode* DirectoryNode::createFile(const String& name) {
+ if (m_mounts != 0) return m_mounts->createFile(name);
FileNode* n = m_fs->createFile(this, name);
m_length = m_children.size();
return n;
}
DirectoryNode* DirectoryNode::createDirectory(const String& name) {
+ if (m_mounts != 0) return m_mounts->createDirectory(name);
DirectoryNode* n = m_fs->createDirectory(this, name);
m_length = m_children.size();
return n;
}
bool DirectoryNode::remove(FSNode* child) {
+ if (m_mounts != 0) return m_mounts->remove(child);
//Check node is indeed one of our childs
if (!m_contentLoaded)
if (!loadContent())
diff --git a/Source/Kernel/VFS/DirectoryNode.class.h b/Source/Kernel/VFS/DirectoryNode.class.h
index 4d9b211..1fc4c52 100644
--- a/Source/Kernel/VFS/DirectoryNode.class.h
+++ b/Source/Kernel/VFS/DirectoryNode.class.h
@@ -8,6 +8,7 @@ class DirectoryNode : public FSNode {
protected:
Vector<FSNode*> m_children;
bool m_contentLoaded;
+ DirectoryNode* m_mounts; //Root node of the filesystem mounted here, null if none
//Syscalls
static call_t m_callTable[];
@@ -19,20 +20,20 @@ class DirectoryNode : public FSNode {
u32int uid = 0, u32int gid = 0) :
FSNode(name, fs, parent, 0, permissions, uid, gid), m_children(), m_contentLoaded(false) {
addCallTable(m_callTable);
+ m_mounts = 0;
}
- virtual ~DirectoryNode() {
- if (m_contentLoaded) {
- for (u32int i = 0; i < m_children.size(); i++) {
- delete m_children[i];
- }
- }
- }
+ virtual ~DirectoryNode();
Vector<FSNode*> &getChildren() { return m_children; } //MUST BE USED ONLY BY FILESYSTEMS
u8int type() { return NT_DIRECTORY; }
+ u64int getLength();
+ FSNode* getParent();
bool removable();
bool unmountable();
+ bool mountpointable();
+ void mount(DirectoryNode* childRoot);
+ void unmount();
bool loadContent();
FSNode* getChild(u32int index);
diff --git a/Source/Kernel/VFS/FSNode.proto.h b/Source/Kernel/VFS/FSNode.proto.h
index 0aafc8a..a46c79d 100644
--- a/Source/Kernel/VFS/FSNode.proto.h
+++ b/Source/Kernel/VFS/FSNode.proto.h
@@ -44,12 +44,12 @@ class FSNode : public Ressource {
virtual bool used() { return false; } //True if file is read/written from/to
const String& getName() { return m_name; }
- u64int getLength() { return m_length; }
+ virtual u64int getLength() { return m_length; }
u32int getPermissions() { return m_permissions; }
u32int getUid() { return m_uid; }
u32int getGid() { return m_gid; }
FileSystem *getFS() { return m_fs; }
- FSNode* getParent() { return m_parent; }
+ virtual FSNode* getParent() { return m_parent; }
//Helper functions
bool readable(User* user = 0);
diff --git a/Source/Kernel/VFS/File.class.cpp b/Source/Kernel/VFS/File.class.cpp
index c5ddcd6..84561a5 100644
--- a/Source/Kernel/VFS/File.class.cpp
+++ b/Source/Kernel/VFS/File.class.cpp
@@ -33,7 +33,7 @@ bool File::open(String filename, u8int mode, FSNode* start, bool vrfyperm) {
if (node == NULL){
if (mode == FM_READ) return false;
node = VFS::createFile(filename, start, vrfyperm);
- if (node == 0) return false;
+ if (node == NULL) return false;
}
if (node->type() != NT_FILE) return false;
@@ -137,6 +137,7 @@ bool File::seek(u64int count, u8int mode) {
}
bool File::eof() {
+ if (!m_valid) return false;
return m_position == m_file->getLength();
}
diff --git a/Source/Kernel/VFS/FileSystem.proto.h b/Source/Kernel/VFS/FileSystem.proto.h
index a614c13..172c82c 100644
--- a/Source/Kernel/VFS/FileSystem.proto.h
+++ b/Source/Kernel/VFS/FileSystem.proto.h
@@ -5,17 +5,26 @@
class FSNode;
class FileNode;
class DirectoryNode;
+class FileSystem;
+
+namespace VFS {
+ bool unmount(FileSystem*);
+}
//This abstract class describes a filesystem
class FileSystem {
+ friend bool VFS::unmount(FileSystem*);
+ private:
+ String m_identifier;
+
protected:
- virtual ~FileSystem() {}
+ virtual ~FileSystem();
bool m_isWritable; //false = read only
DirectoryNode* m_rootNode;
- public:
- bool unmount();
+ virtual bool unmount() = 0; //Sync data with the disk
+ public:
bool isWritable() { return m_isWritable; }
DirectoryNode* getRootNode() { return m_rootNode; }
@@ -34,6 +43,10 @@ class FileSystem {
virtual FileNode* createFile(DirectoryNode* parent, String name) = 0;
virtual DirectoryNode* createDirectory(DirectoryNode* parent, String name) = 0;
virtual bool remove(DirectoryNode* parent, FSNode* node) = 0;
+
+ virtual Partition* getPart() = 0;
+ void setIdentifier(String s) { m_identifier = s; }
+ String getIdentifier() { return m_identifier; }
};
#endif
diff --git a/Source/Kernel/VFS/Part.ns.cpp b/Source/Kernel/VFS/Part.ns.cpp
index 6408dbd..415a150 100644
--- a/Source/Kernel/VFS/Part.ns.cpp
+++ b/Source/Kernel/VFS/Part.ns.cpp
@@ -1,5 +1,7 @@
#include "Part.ns.h"
+#include <VTManager/SimpleVT.class.h>
+
namespace Part {
Vector<BlockDevice*> devices;
@@ -7,6 +9,21 @@ Vector<Partition*> partitions;
void readPartitionTable(BlockDevice *dev) { //TODO : read partition table from device
partitions.push(new Partition(dev, 0, 0, dev->blocks())); //Insert whole device as a partition
+
+ u8int* mbr = (u8int*)Mem::alloc(dev->blockSize());
+ if (!dev->readBlocks(0, 1, mbr)) return;
+
+ mbr_entry_t* entries = (mbr_entry_t*)((u32int)mbr + 0x1BE);
+
+ for (u32int i = 0; i < 4; i++) {
+ if ((entries[i].bootable == 0 or entries[i].bootable == 0x80) and entries[i].id != 0
+ and entries[i].s_lba != 0 and entries[i].size != 0
+ and entries[i].s_lba < dev->blocks() and entries[i].size < dev->blocks()) {
+ partitions.push(new Partition(dev, i + 1, entries[i].s_lba, entries[i].size));
+ }
+ }
+
+ Mem::free(mbr);
}
void registerDevice(BlockDevice *dev) {
@@ -56,4 +73,32 @@ u32int getDeviceID(BlockDevice* dev) {
return (u32int) - 1;
}
+BlockDevice* dev(String _class, u32int idx) {
+ if (_class.empty()) return devices[idx];
+ for (u32int i = 0; i < devices.size(); i++) {
+ String devclass = devices[i]->getClass();
+ if (devclass == _class or (devclass.size() > _class.size() and devclass.substr(0, _class.size()) == _class)) {
+ if (idx == 0) {
+ return devices[i];
+ } else {
+ idx--;
+ }
+ }
+ }
+ return NULL;
+}
+
+Partition* part(BlockDevice* dev, u32int idx) {
+ for (u32int i = 0; i < partitions.size(); i++) {
+ if (partitions[i]->getDevice() == dev && partitions[i]->getPartNumber() == idx) {
+ return partitions[i];
+ }
+ }
+ return NULL;
+}
+
+String partIdentifier(Partition* p) {
+ return String("d") += String::number(getDeviceID(p->getDevice())) += String("p") += String::number(p->getPartNumber());
+}
+
}
diff --git a/Source/Kernel/VFS/Part.ns.h b/Source/Kernel/VFS/Part.ns.h
index 40a0fb2..e6a358c 100644
--- a/Source/Kernel/VFS/Part.ns.h
+++ b/Source/Kernel/VFS/Part.ns.h
@@ -6,6 +6,19 @@
#include <VFS/Partition.class.h>
namespace Part {
+ struct mbr_entry_t {
+ u8int bootable; /* 0 = no, 0x80 = bootable */
+ u8int s_head; /* Starting head */
+ u16int s_sector : 6; /* Starting sector */
+ u16int s_cyl : 10; /* Starting cylinder */
+ u8int id; /* System ID */
+ u8int e_head; /* Ending head */
+ u16int e_sector : 6; /* Ending sector */
+ u16int e_cyl : 10; /* Ending cylinder */
+ u32int s_lba; /* Starting sector (LBA value) */
+ u32int size; /* Total sector number */
+ } __attribute__ ((packed));
+
extern Vector<BlockDevice*> devices;
extern Vector<Partition*> partitions;
@@ -13,6 +26,11 @@ namespace Part {
void unregisterDevice(BlockDevice* dev);
u32int getDeviceID(BlockDevice* dev);
+
+ BlockDevice* dev(String _class, u32int idx);
+ Partition* part(BlockDevice* dev, u32int idx);
+
+ String partIdentifier(Partition* p); //Simply to help recognize the partition
}
#endif
diff --git a/Source/Kernel/VFS/Partition.class.cpp b/Source/Kernel/VFS/Partition.class.cpp
index b62f33c..9da3461 100644
--- a/Source/Kernel/VFS/Partition.class.cpp
+++ b/Source/Kernel/VFS/Partition.class.cpp
@@ -2,21 +2,23 @@
using namespace CMem; //For memcpy
-Partition::Partition(BlockDevice* dev, u8int partnumber, u64int startblock, u64int blockcount) {
+Partition::Partition(BlockDevice* dev, u8int partnumber, u64int startblock, u64int blockcount)
+: m_cache(dev) {
m_device = dev;
m_partnumber = partnumber;
m_startblock = startblock;
m_blockcount = blockcount;
+ m_cache.init(10 + (m_device->blocks() / 1000 > 100 ? 100 : m_device->blocks() / 1000));
}
bool Partition::readBlocks(u64int startblock, u32int count, u8int *data) {
if (startblock + count > m_startblock + m_blockcount) return false;
- return m_device->readBlocks(startblock - m_startblock, count, data);
+ return m_cache.readBlocks(startblock + m_startblock, count, data);
}
bool Partition::writeBlocks(u64int startblock, u32int count, u8int *data) {
if (startblock + count > m_startblock + m_blockcount) return false;
- return m_device->writeBlocks(startblock - m_startblock, count, data);
+ return m_cache.writeBlocks(startblock + m_startblock, count, data);
}
bool Partition::read(u64int start, u32int length, u8int *data) {
@@ -65,4 +67,4 @@ BlockDevice* Partition::getDevice() { return m_device; }
u64int Partition::getStartBlock() { return m_startblock; }
u64int Partition::getBlockCount() { return m_blockcount; }
u8int Partition::getPartNumber() { return m_partnumber; }
-u32int Partition::getBlockSize() { return m_device->blockSize(); }
+u32int Partition::blockSize() { return m_device->blockSize(); }
diff --git a/Source/Kernel/VFS/Partition.class.h b/Source/Kernel/VFS/Partition.class.h
index 8df1c4f..eb0aafd 100644
--- a/Source/Kernel/VFS/Partition.class.h
+++ b/Source/Kernel/VFS/Partition.class.h
@@ -2,10 +2,12 @@
#define DEF_PARTITION_CLASS_H
#include <Devices/BlockDevice.proto.h>
+#include <VFS/BlockCache.class.h>
class Partition {
private:
BlockDevice* m_device;
+ BlockCache<BlockDevice> m_cache;
u64int m_startblock, m_blockcount;
u8int m_partnumber; //Partition number in partition table of device
@@ -24,7 +26,7 @@ class Partition {
u64int getStartBlock();
u64int getBlockCount();
u8int getPartNumber();
- u32int getBlockSize();
+ u32int blockSize();
inline u64int blocks() { return getBlockCount(); }
};
diff --git a/Source/Kernel/VFS/VFS.ns.cpp b/Source/Kernel/VFS/VFS.ns.cpp
index e95b911..cf68653 100644
--- a/Source/Kernel/VFS/VFS.ns.cpp
+++ b/Source/Kernel/VFS/VFS.ns.cpp
@@ -1,19 +1,130 @@
#include "VFS.ns.h"
#include <VFS/FileNode.class.h>
+#include <Vector.class.h>
+#include <VTManager/VirtualTerminal.proto.h>
+
+#include <VFS/Part.ns.h>
+#include <FileSystems/RamFS/RamFS.class.h>
+#include <FileSystems/FAT/FATFS.class.h>
+
+struct local_fs_t {
+ const char* name;
+ mount_callback_t cb;
+} fileSystems[] = {
+ {"fat", FATFS::mount},
+ {0, 0}
+};
+
+FileSystem::~FileSystem() { delete m_rootNode; }
namespace VFS {
-DirectoryNode *rootNode;
+DirectoryNode *rootNode = 0;
+Vector<FileSystem*> filesystems;
+
+DirectoryNode* getRootNode() {
+ return rootNode;
+}
+
+void registerFilesystem(FileSystem* fs) {
+ unregisterFilesystem(fs);
+ filesystems.push(fs);
+ if (rootNode == 0) rootNode = fs->getRootNode();
+}
-//TODO : mount stuff
+void unregisterFilesystem(FileSystem* fs) {
+ for (u32int i = 0; i < filesystems.size(); i++) {
+ if (filesystems[i] == fs) {
+ filesystems[i] = filesystems.back();
+ filesystems.pop();
+ break;
+ }
+ }
+}
-bool setRootNode(DirectoryNode* node) {
- rootNode = node;
+bool unmount(FileSystem* fs) {
+ if (!fs->getRootNode()->unmountable()) return false;
+ if (fs->getRootNode() == rootNode) return false;
+ if (!fs->unmount()) return false;
+ delete fs; //Will automatically delete the root node (destructor is in this file);
return true;
}
-DirectoryNode* getRootNode() {
- return rootNode;
+bool mount(String str, VirtualTerminal* vt, multiboot_info_t *mbd) {
+ Vector<String> fs = str.split(":");
+ DirectoryNode* root;
+ if (fs[0] == "/") {
+ root = NULL;
+ } else {
+ FSNode* n = VFS::find(fs[0]);
+ if (n == NULL) {
+ *vt << "Mountpoint does not exist : " << fs[0] << "\n";
+ return false;
+ }
+ if (n->type() != NT_DIRECTORY) {
+ *vt << "Mountpoint is not a directory : " << fs[0] << "\n";
+ return false;
+ }
+ root = (DirectoryNode*)n;
+ }
+ if (fs[1] == "ramfs") {
+ if (fs.size() > 2) {
+ if (mbd != 0) {
+ module_t *mods = (module_t*)mbd->mods_addr;
+ if (fs[2].toInt() >= mbd->mods_count) {
+ *vt << "Invalid module number for filesystem to mount on " << fs[0] << "\n";
+ return false;
+ }
+ FileSystem* wat = RamFS::mount((u8int*)mods[fs[2].toInt()].mod_start, 1024 * 1024, root);
+ if (wat != NULL) {
+ wat->setIdentifier(str);
+ return true;
+ }
+ return false;
+ } else {
+ *vt << "Cannot mount kernel modules outside of kernel command line.\n";
+ return false;
+ }
+ } else {
+ FileSystem* wat = RamFS::mount(1024 * 1024, root);
+ if (wat != NULL) {
+ wat->setIdentifier(str);
+ return true;
+ }
+ return false;
+ }
+ } else {
+ if (fs.size() < 4) {
+ *vt << "Syntax: <mountpoint>:[<dev_class>]:<dev_id>:<part_id>[:<fs_type>[:[ro|rw]]]\n";
+ return false;
+ }
+ if (fs.size() < 5) fs.push("");
+ if (fs.size() < 6) fs.push("ro"); //By default, mount file systems read-only
+ BlockDevice* d = Part::dev(fs[1], fs[2].toInt());
+ Partition* p = Part::part(d, fs[3].toInt());
+ for (u32int i = 0; i < filesystems.size(); i++) {
+ if (filesystems[i]->getPart() == p) {
+ *vt << "Cannot mount " << str << " : partition already mounted.\n";
+ return false;
+ }
+ }
+ for (u32int i = 0; fileSystems[i].cb != 0; i++) {
+ if (fs[4] == fileSystems[i].name or fs[4] == "") {
+ FileSystem* mounted = fileSystems[i].cb(p, root, (fs[5] == "rw"));
+ if (mounted != NULL) {
+ mounted->setIdentifier(str);
+ return true;
+ } else if (fs[4] != "") {
+ *vt << "Could not mount filesystem on " << fs[0] << "\n";
+ if (root == NULL) PANIC("Error while mounting root filesystem.");
+ return false;
+ }
+ }
+ }
+ *vt << "Unknown filesystem type for filesystem to mount on " << fs[0] << "\n";
+ if (root == NULL) PANIC("Unknown filesystem type for root file system.");
+ return false;
+ }
}
FSNode* find(const String& path, FSNode* start) {
diff --git a/Source/Kernel/VFS/VFS.ns.h b/Source/Kernel/VFS/VFS.ns.h
index f1d628f..eede728 100644
--- a/Source/Kernel/VFS/VFS.ns.h
+++ b/Source/Kernel/VFS/VFS.ns.h
@@ -1,17 +1,27 @@
#ifndef DEF_VFS_NS_H
#define DEF_VFS_NS_H
+#include <Core/multiboot.wtf.h>
+
#include <VFS/DirectoryNode.class.h>
#include <VFS/FileSystem.proto.h>
+#include <Vector.class.h>
-typedef FileSystem* (* mountcallback)(Partition* partition);
+typedef FileSystem* (* mount_callback_t)(Partition* partition, DirectoryNode* mountpoint, bool readwrite);
namespace VFS {
- void registerMountCallback(mountcallback mcb);
+ extern Vector<FileSystem*> filesystems;
+
+ void registerMountCallback(mount_callback_t mcb);
bool mount(Partition* partition, DirectoryNode *mountpoint);
- bool setRootNode(DirectoryNode* root);
DirectoryNode* getRootNode();
+ void registerFilesystem(FileSystem* fs);
+ void unregisterFilesystem(FileSystem* fs);
+ bool unmount(FileSystem* fs);
+
+ bool mount(String str, VirtualTerminal* logvt, multiboot_info_t* mbd = 0);
+
FSNode* find(const String& path, FSNode* start = 0);
FSNode* createFile(const String& path, FSNode* start = 0, bool vrfyperm = false);
FSNode* createDirectory(const String& path, FSNode* start = 0, bool vrfyperm = false);
diff --git a/Source/Library/Common/BasicString.class.cpp b/Source/Library/Common/BasicString.class.cpp
index f3a6164..ddb4e2c 100644
--- a/Source/Library/Common/BasicString.class.cpp
+++ b/Source/Library/Common/BasicString.class.cpp
@@ -173,8 +173,10 @@ Vector< BasicString<T> > BasicString<T>::split(T sep) const {
}
template <typename T>
-BasicString<T> BasicString<T>::substr(s32int start, u32int size) {
+BasicString<T> BasicString<T>::substr(s32int start, s32int size) {
+ if (size == 0) return BasicString<T>();
if (start < 0) start = m_length - start;
+ if (size == -1) size = m_length - start;
BasicString<T> ret;
ret.m_string = new T[size + 1];
ret.m_length = size;
diff --git a/Source/Library/Common/BasicString.class.h b/Source/Library/Common/BasicString.class.h
index 21041e8..03d82c1 100644
--- a/Source/Library/Common/BasicString.class.h
+++ b/Source/Library/Common/BasicString.class.h
@@ -46,7 +46,7 @@ class BasicString {
bool contains(const T& chr) const;
Vector< BasicString<T> > split(T sep) const;
- BasicString<T> substr(s32int start, u32int size);
+ BasicString<T> substr(s32int start, s32int size = -1);
};
#include "BasicString.class.cpp"
diff --git a/Source/Library/Common/ByteArray.class.cpp b/Source/Library/Common/ByteArray.class.cpp
index 2a42702..95326f7 100644
--- a/Source/Library/Common/ByteArray.class.cpp
+++ b/Source/Library/Common/ByteArray.class.cpp
@@ -50,9 +50,9 @@ void ByteArray::resize(u32int size) {
}
String ByteArray::toString (u8int encoding) {
- char* c = new char[m_length + 1];
+ char* c = new char[m_length + 4];
memcpy((u8int*)c, m_string, m_length);
- c[m_length] = 0; //Add NULL terminator
+ for (int i = 0; i < 4; i++) c[m_length + i] = 0; //Add NULL terminator
String r(c, encoding);
delete c;
return r;
diff --git a/Source/Library/Common/String.class.cpp b/Source/Library/Common/String.class.cpp
index 63ff837..fe851bd 100644
--- a/Source/Library/Common/String.class.cpp
+++ b/Source/Library/Common/String.class.cpp
@@ -84,8 +84,8 @@ void String::affect (const char* string, u8int encoding) {
return;
}
m_string = new WChar[m_length + 1];
- int i = 0, l = strlen(string), c = 0;
- while (i < l) {
+ u32int i = 0, c = 0;
+ while (c < m_length) {
i += m_string[c].affect(string + i, encoding);
c++;
}
@@ -191,8 +191,10 @@ Vector<String> String::split(WChar c) const {
return ret;
}
-String String::substr(s32int start, u32int size) {
+String String::substr(s32int start, s32int size) {
+ if (size == 0) return String();
if (start < 0) start = m_length - start;
+ if (size == -1) size = m_length - start;
String ret;
ret.m_string = new WChar[size + 1];
ret.m_length = size;
diff --git a/Source/Library/Common/String.class.h b/Source/Library/Common/String.class.h
index 0d48ce6..b623fb2 100644
--- a/Source/Library/Common/String.class.h
+++ b/Source/Library/Common/String.class.h
@@ -43,7 +43,7 @@ class String : public BasicString<WChar> {
Vector<String> split(WChar c) const;
- String substr(s32int start, u32int size);
+ String substr(s32int start, s32int size = -1);
};
#endif
diff --git a/Source/Library/Common/WChar.class.cpp b/Source/Library/Common/WChar.class.cpp
index f5bd5bc..312a5db 100644
--- a/Source/Library/Common/WChar.class.cpp
+++ b/Source/Library/Common/WChar.class.cpp
@@ -29,8 +29,10 @@ WChar::WChar(char c) {
WChar::WChar(const char* c, u8int encoding) {
if (encoding == UE_UTF8) affectUtf8(c);
- if (encoding == UE_UTF16) affectUtf16(c);
- if (encoding == UE_UTF32) affectUtf32(c);
+ if (encoding == UE_UTF16_LE) affectUtf16le(c);
+ if (encoding == UE_UTF16_BE) affectUtf16be(c);
+ if (encoding == UE_UTF32_LE) affectUtf32le(c);
+ if (encoding == UE_UTF32_BE) affectUtf32be(c);
}
u32int WChar::ucharLen(const char* c, u8int encoding) {
@@ -40,18 +42,21 @@ u32int WChar::ucharLen(const char* c, u8int encoding) {
else if ((c[0] & 0xF0) == 0xE0) return 3;
else if ((c[0] & 0xF8) == 0xF0) return 4;
else return 1;
- } else if (encoding == UE_UTF16) {
+ } else if (encoding == UE_UTF16_BE) {
if ((c[0] & 0xFC) == 0xD8 and (c[2] & 0xFC) == 0xDC) return 4;
else return 2;
- } else if (encoding == UE_UTF32) {
+ } else if (encoding == UE_UTF16_LE) {
+ if ((c[1] & 0xFC) == 0xD8 and (c[3] & 0xFC) == 0xDC) return 4;
+ else return 2;
+ } else if (encoding == UE_UTF32_LE or encoding == UE_UTF16_BE) {
return 4;
}
return 1;
}
u32int WChar::utfLen(const char* c, u8int encoding) {
- int i = 0, l = strlen(c), co = 0;
- while (i < l) {
+ int i = 0, co = 0;
+ while (WChar(c + i, encoding) != 0) {
i += ucharLen(c + i, encoding);
co++;
}
@@ -90,7 +95,7 @@ u32int WChar::affectUtf8(const char* c) { //Returns the number of bytes for the
return 1;
}
-u32int WChar::affectUtf16(const char* c) {
+u32int WChar::affectUtf16be(const char* c) {
if ((c[0] & 0xFC) == 0xD8 and // 11111100b, 11011000b
(c[2] & 0xFC) == 0xDC) { // 11111100b, 11011100b
u32int w = ((c[0] & 0x03) << 2) | ((c[1] & 0xC0) >> 6);
@@ -108,13 +113,38 @@ u32int WChar::affectUtf16(const char* c) {
}
}
-u32int WChar::affectUtf32(const char* c) {
+u32int WChar::affectUtf16le(const char* c) {
+ if ((c[1] & 0xFC) == 0xD8 and // 11111100b, 11011000b
+ (c[3] & 0xFC) == 0xDC) { // 11111100b, 11011100b
+ u32int w = ((c[1] & 0x03) << 2) | ((c[0] & 0xC0) >> 6);
+ u32int x = (c[0] & 0x3F);
+ u32int y = ((c[3] & 0x03) << 8) | (c[3]);
+ value = ((w + 1) << 16) | (x << 10) | y;
+ if (value >= 0xD800 and value <= 0xDFFF) value = 0; //These values are unallowed
+ if (value >= 0xFFFE and value <= 0xFFFF) value = 0;
+ return 4;
+ } else {
+ value = (c[1] << 8) | (c[0]);
+ if (value >= 0xD800 and value <= 0xDFFF) value = 0; //These values are unallowed
+ if (value >= 0xFFFE and value <= 0xFFFF) value = 0;
+ return 2;
+ }
+}
+
+u32int WChar::affectUtf32be(const char* c) {
value = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
if (value >= 0xD800 and value <= 0xDFFF) value = 0; //These values are unallowed
if (value >= 0xFFFE and value <= 0xFFFF) value = 0;
return 4;
}
+u32int WChar::affectUtf32le(const char* c) {
+ value = (c[3] << 24) | (c[2] << 16) | (c[1] << 8) | c[0];
+ if (value >= 0xD800 and value <= 0xDFFF) value = 0; //These values are unallowed
+ if (value >= 0xFFFE and value <= 0xFFFF) value = 0;
+ return 4;
+}
+
u8int WChar::toAscii() {
if (value < 128) return (char)value;
for (int i = 0; i < 128; i++) {
@@ -144,9 +174,9 @@ uchar_repr_t WChar::toUtf8() {
return r;
}
-//TODO : code WChar::toUtf16
+//TODO : code WChar::toUtf16(be|le)
-uchar_repr_t WChar::toUtf32() {
+uchar_repr_t WChar::toUtf32be() {
uchar_repr_t r;
r.c[0] = (value >> 24) & 0xFF;
r.c[1] = (value >> 16) & 0xFF;
@@ -154,3 +184,12 @@ uchar_repr_t WChar::toUtf32() {
r.c[3] = value & 0xFF;
return r;
}
+
+uchar_repr_t WChar::toUtf32le() {
+ uchar_repr_t r;
+ r.c[3] = (value >> 24) & 0xFF;
+ r.c[2] = (value >> 16) & 0xFF;
+ r.c[1] = (value >> 8) & 0xFF;
+ r.c[0] = value & 0xFF;
+ return r;
+}
diff --git a/Source/Library/Common/WChar.class.h b/Source/Library/Common/WChar.class.h
index 5d6d26b..afaeb44 100644
--- a/Source/Library/Common/WChar.class.h
+++ b/Source/Library/Common/WChar.class.h
@@ -9,8 +9,10 @@
enum {
UE_UTF8,
- UE_UTF16,
- UE_UTF32,
+ UE_UTF16_LE,
+ UE_UTF16_BE,
+ UE_UTF32_LE,
+ UE_UTF32_BE,
};
union uchar_repr_t {
@@ -31,13 +33,17 @@ struct WChar {
void affectAscii(char c);
u32int affectUtf8(const char* c);
- u32int affectUtf16(const char* c);
- u32int affectUtf32(const char* c);
+ u32int affectUtf16le(const char* c);
+ u32int affectUtf16be(const char* c);
+ u32int affectUtf32le(const char* c);
+ u32int affectUtf32be(const char* c);
u32int affect(const char* c, u8int encoding = UE_UTF8) {
if (encoding == UE_UTF8) return affectUtf8(c);
- if (encoding == UE_UTF16) return affectUtf16(c);
- if (encoding == UE_UTF32) return affectUtf32(c);
+ if (encoding == UE_UTF16_LE) return affectUtf16le(c);
+ if (encoding == UE_UTF16_BE) return affectUtf16be(c);
+ if (encoding == UE_UTF32_LE) return affectUtf32le(c);
+ if (encoding == UE_UTF32_BE) return affectUtf32be(c);
affectAscii(c[0]); //Default case :/
return 1;
}
@@ -45,13 +51,17 @@ struct WChar {
u8int toAscii();
uchar_repr_t toUtf8();
- uchar_repr_t toUtf16();
- uchar_repr_t toUtf32();
+ uchar_repr_t toUtf16le();
+ uchar_repr_t toUtf16be();
+ uchar_repr_t toUtf32le();
+ uchar_repr_t toUtf32be();
uchar_repr_t encode(u8int encoding = UE_UTF8) {
if (encoding == UE_UTF8) return toUtf8();
- //if (encoding == UE_UTF16) return toUtf16();
- if (encoding == UE_UTF32) return toUtf32();
+ //if (encoding == UE_UTF16_LE) return toUtf16le();
+ //if (encoding == UE_UTF16_BE) return toUtf16be();
+ if (encoding == UE_UTF32_LE) return toUtf32le();
+ if (encoding == UE_UTF32_BE) return toUtf32be();
uchar_repr_t x;
x.c[0] = toAscii();
return x;