summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Init.rfsbin0 -> 157 bytes
-rw-r--r--Makefile13
-rw-r--r--Media/Screenshots/2009-09-13-182343_728x426_scrot.pngbin0 -> 18477 bytes
-rw-r--r--Media/Screenshots/2009-09-13-182350_728x426_scrot.pngbin0 -> 20016 bytes
-rw-r--r--Media/Screenshots/2009-09-13-182402_728x426_scrot.pngbin0 -> 19280 bytes
-rw-r--r--Media/Screenshots/2009-09-13-182715_728x426_scrot.pngbin0 -> 18838 bytes
-rw-r--r--Source/Kernel/Core/kmain.wtf.cpp83
-rw-r--r--Source/Kernel/FileSystems/RamFS/RamFS.class.cpp143
-rw-r--r--Source/Kernel/FileSystems/RamFS/RamFS.class.h43
-rw-r--r--Source/Kernel/FileSystems/RamFS/RamFileNode.class.h19
-rw-r--r--Source/Kernel/Library/String.class.cpp30
-rw-r--r--Source/Kernel/Library/String.class.h36
-rw-r--r--Source/Kernel/Library/Vector.class.cpp44
-rw-r--r--Source/Kernel/Library/Vector.class.h5
-rw-r--r--Source/Kernel/Library/WChar.class.cpp6
-rw-r--r--Source/Kernel/Library/WChar.class.h10
-rw-r--r--Source/Kernel/Makefile3
-rwxr-xr-xSource/Kernel/Melon.kebin118873 -> 167382 bytes
-rw-r--r--Source/Kernel/Ressources/Welcome.txt1
-rw-r--r--Source/Kernel/VFS/DirectoryNode.class.cpp76
-rw-r--r--Source/Kernel/VFS/DirectoryNode.class.h31
-rw-r--r--Source/Kernel/VFS/FSNode.proto.h70
-rw-r--r--Source/Kernel/VFS/FileNode.class.h31
-rw-r--r--Source/Kernel/VFS/FileSystem.proto.h36
-rw-r--r--Source/Kernel/VFS/VFS.ns.h22
-rw-r--r--Source/Kernel/VTManager/VirtualTerminal.class.cpp2
-rw-r--r--Source/Kernel/VTManager/VirtualTerminal.class.h4
-rwxr-xr-xSource/Tools/MakeRamFS/MakeRamFSbin0 -> 12483 bytes
-rw-r--r--Source/Tools/MakeRamFS/Makefile38
-rw-r--r--Source/Tools/MakeRamFS/main.cpp95
30 files changed, 776 insertions, 65 deletions
diff --git a/Init.rfs b/Init.rfs
new file mode 100644
index 0000000..cec0405
--- /dev/null
+++ b/Init.rfs
Binary files differ
diff --git a/Makefile b/Makefile
index 32cd382..664900f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,12 @@
-.PHONY: clean, mrproper, Init.img
+.PHONY: clean, mrproper, Init.rfs
-Files = Source/Kernel/Melon.ke
+Files = Source/Kernel/Melon.ke Init.rfs
Floppy = Melon.img
-Projects = Kernel
+Projects = Kernel Tools/MakeRamFS
+RamFS = Init.rfs
+RamFSFiles = :/System :/System/Applications Source/Kernel/Ressources/Welcome.txt:/Welcome.txt :/System/Configuration
all:
for p in $(Projects); do \
@@ -26,7 +28,10 @@ mproper:
make -C Source mrproper -s; \
done
-floppy:
+$(RamFS):
+ Source/Tools/MakeRamFS/MakeRamFS $(RamFS) $(RamFSFiles)
+
+floppy: $(RamFS)
sudo mount $(Floppy) Mount -o loop
for f in $(Files); do \
sudo cp $$f Mount; \
diff --git a/Media/Screenshots/2009-09-13-182343_728x426_scrot.png b/Media/Screenshots/2009-09-13-182343_728x426_scrot.png
new file mode 100644
index 0000000..37476a8
--- /dev/null
+++ b/Media/Screenshots/2009-09-13-182343_728x426_scrot.png
Binary files differ
diff --git a/Media/Screenshots/2009-09-13-182350_728x426_scrot.png b/Media/Screenshots/2009-09-13-182350_728x426_scrot.png
new file mode 100644
index 0000000..f621d8c
--- /dev/null
+++ b/Media/Screenshots/2009-09-13-182350_728x426_scrot.png
Binary files differ
diff --git a/Media/Screenshots/2009-09-13-182402_728x426_scrot.png b/Media/Screenshots/2009-09-13-182402_728x426_scrot.png
new file mode 100644
index 0000000..bf584d6
--- /dev/null
+++ b/Media/Screenshots/2009-09-13-182402_728x426_scrot.png
Binary files differ
diff --git a/Media/Screenshots/2009-09-13-182715_728x426_scrot.png b/Media/Screenshots/2009-09-13-182715_728x426_scrot.png
new file mode 100644
index 0000000..37311da
--- /dev/null
+++ b/Media/Screenshots/2009-09-13-182715_728x426_scrot.png
Binary files differ
diff --git a/Source/Kernel/Core/kmain.wtf.cpp b/Source/Kernel/Core/kmain.wtf.cpp
index a7bb6e0..808e254 100644
--- a/Source/Kernel/Core/kmain.wtf.cpp
+++ b/Source/Kernel/Core/kmain.wtf.cpp
@@ -19,6 +19,10 @@
#include <SyscallManager/IDT.ns.h>
#include <Library/String.class.h>
#include <VFS/Part.ns.h>
+#include <FileSystems/RamFS/RamFS.class.h>
+#include <VFS/FileNode.class.h>
+#include <VFS/VFS.ns.h>
+#include <VFS/DirectoryNode.class.h>
#include <Ressources/logo.cd>
#include <Ressources/keymap-fr.wtf.c>
@@ -107,25 +111,84 @@ void kmain(multiboot_info_t* mbd, u32int magic) {
PROCESSING(kvt, "Detecting floppy drives...");
FloppyController::detect(); OK(kvt);
+ FileSystem* fs = new RamFS((u8int*)mods[0].mod_start, 1024 * 1024);
+ DirectoryNode* cwd;
+ cwd = fs->getRootNode();
+ VFS::setRootNode(cwd);
+
asm volatile("sti");
while(1) {
kvt->setColor(0);
- *kvt << "> ";
+ *kvt << cwd->getName() << " : ";
kvt->setColor(8);
- String tmp = kvt->readLine();
+ Vector<String> tokens = kvt->readLine().split(" ");
kvt->setColor(0);
- if (tmp == "help") {
+ if (tokens[0] == "help") {
*kvt << " - Command list for integrated kernel shell:\n";
*kvt << " - help shows this help screen\n";
*kvt << " - reboot reboots your computer\n";
+ *kvt << " - ls [<dir>] shows contents of a directory\n";
+ *kvt << " - cd <dir> goes to directory <dir>\n";
+ *kvt << " - cat <file> shows contents of file <file>\n";
+ *kvt << " - pwd prints current directory\n";
*kvt << " - devices shows all detected devices on your computer\n";
*kvt << " - free shows memory usage (physical frames and kernel heap)\n";
*kvt << " - uptime shows seconds since boot\n";
*kvt << " - part shows all detected block devices and partitions\n";
- } else if (tmp == "reboot") {
+ } else if (tokens[0] == "reboot") {
Sys::reboot();
- } else if (tmp == "devices") {
+ } else if (tokens[0] == "ls") {
+ DirectoryNode* d = cwd;
+ if (tokens.size() == 2) {
+ FSNode* n = VFS::find(tokens[1], cwd);
+ d = NULL;
+ if (n == NULL)
+ *kvt << "No such directory : " << tokens[1] << "\n";
+ else if (n->type() != NT_DIRECTORY)
+ *kvt << "Not a directory : " << tokens[1] << "\n";
+ else
+ d = (DirectoryNode*)n;
+ }
+ for (u32int i = 0; d != NULL && i < d->getLength(); i++) {
+ FSNode* n = d->getChild(i);
+ if (n->type() == NT_FILE) {
+ FileNode* f = (FileNode*)n;
+ *kvt << " - FILE\t" << f->getName();
+ kvt->setCursorCol(30);
+ *kvt << (s32int)f->getLength() << " bytes.\n";
+ } else if (n->type() == NT_DIRECTORY) {
+ *kvt << " - DIR\t" << n->getName();
+ kvt->setCursorCol(30);
+ *kvt << (s32int)n->getLength() << " items.\n";
+ }
+ }
+ } else if (tokens[0] == "cd") {
+ FSNode* n = VFS::find(tokens[1], cwd);
+ if (n == NULL)
+ *kvt << "No such directory : " << tokens[1] << "\n";
+ else if (n->type() != NT_DIRECTORY)
+ *kvt << "Not a directory : " << tokens[1] << "\n";
+ else
+ cwd = (DirectoryNode*)n;
+ } else if (tokens[0] == "cat") {
+ for (u32int i = 1; i < tokens.size(); i++) {
+ FSNode* n = VFS::find(tokens[i], cwd);
+ if (n == NULL) {
+ *kvt << "No such file : " << tokens[1] << "\n";
+ } else if (n->type() != NT_FILE) {
+ *kvt << "Not a file : " << tokens[1] << "\n";
+ } else {
+ FileNode* f = (FileNode*) n;
+ u8int *buff = (u8int*)Mem::kalloc(f->getLength());
+ f->read(0, f->getLength(), buff);
+ *kvt << String((const char*) buff);
+ Mem::kfree(buff);
+ }
+ }
+ } else if (tokens[0] == "pwd") {
+ *kvt << "Current location : " << VFS::path(cwd) << "\n";
+ } else if (tokens[0] == "devices") {
Vector<Device*> dev = Dev::findDevices();
*kvt << " - Detected devices :\n";
for (u32int i = 0; i < dev.size(); i++) {
@@ -133,16 +196,16 @@ void kmain(multiboot_info_t* mbd, u32int magic) {
kvt->setCursorCol(25);
*kvt << dev[i]->getName() << "\n";
}
- } else if (tmp == "free") {
+ } else if (tokens[0] == "free") {
u32int frames = PhysMem::total(), freef = PhysMem::free();
*kvt << " - Free frames : " << (s32int)freef << " (" << (s32int)(freef * 4 / 1024) << "Mo) of "
<< (s32int)frames << " (" << (s32int)(frames * 4 / 1024) << "Mo).\n";
u32int kh = Mem::kheapSize(), freek = Mem::kheapFree;
*kvt << " - Kernel heap free : " << (s32int)(freek / 1024 / 1024) << "Mo (" << (s32int)(freek / 1024) <<
"Ko) of " << (s32int)(kh / 1024 / 1024) << "Mo (" << (s32int)(kh / 1024) << "Ko).\n";
- } else if (tmp == "uptime") {
+ } else if (tokens[0] == "uptime") {
*kvt << " - Uptime : " << (s32int)(Time::uptime()) << "s.\n";
- } else if (tmp == "part") {
+ } else if (tokens[0] == "part") {
*kvt << " * ID\tClass Name\n";
for (u32int i = 0; i < Part::devices.size(); i++) {
*kvt << " - " << (s32int)i << "\t";
@@ -161,8 +224,8 @@ void kmain(multiboot_info_t* mbd, u32int magic) {
}
}
}
- } else if (!tmp.empty()) {
- *kvt << " - Unrecognized command: " << tmp << "\n";
+ } else if (tokens.size() > 1 or tokens[0] != "") {
+ *kvt << " - Unrecognized command: " << tokens[0] << "\n";
}
}
PANIC("END OF KMAIN");
diff --git a/Source/Kernel/FileSystems/RamFS/RamFS.class.cpp b/Source/Kernel/FileSystems/RamFS/RamFS.class.cpp
new file mode 100644
index 0000000..7e29e08
--- /dev/null
+++ b/Source/Kernel/FileSystems/RamFS/RamFS.class.cpp
@@ -0,0 +1,143 @@
+#include "RamFS.class.h"
+#include <VFS/DirectoryNode.class.h>
+#include "RamFileNode.class.h"
+
+RamFS::RamFS(u32int maxSize) {
+ m_maxSize = maxSize;
+ m_usedSize = 0;
+ m_isWritable = true;
+ m_rootNode = new DirectoryNode("/", this, NULL);
+}
+
+RamFS::RamFS(u8int *ptr, u32int maxSize, bool writable) {
+ m_maxSize = maxSize;
+ m_usedSize = 0;
+ m_isWritable = true;
+ m_rootNode = new DirectoryNode("/", this, NULL);
+
+ union {
+ u8int* c;
+ initrd_header* i;
+ initrd_file_header* f;
+ } curr;
+ curr.c = ptr;
+
+ if (curr.i->magic != INITRD_MAGIC) return;
+ u32int files = curr.i->files;
+ curr.i++; //Increment pointer of size of initrd header
+ DEBUG_HEX(files); DEBUG(" is initrd file count.");
+ for (u32int i = 0; i < files; i++) {
+ initrd_file_header h = *(curr.f);
+ curr.f++; //Increment pointer of size of file header
+ if (h.name_length != 0 or h.file_length != 0) {
+ String name((const char*)(curr.c));
+ curr.c += h.name_length + 1; //Increment pointer of length of name
+
+ //Find out a vector conaining parent directories, and set name to the effective file name
+ if (name[0] == WChar("/")) name = name.substr(1, name.size() - 1);
+
+ //Find node for parent directory
+ String mname = "";
+ DirectoryNode* parent = m_rootNode;
+ for (u32int i = 0; i < name.size(); i++) {
+ if (name[i] == WChar("/")) {
+ FSNode* n = parent->getChild(mname);
+ if (n == NULL) break;
+ if (n->type() != NT_DIRECTORY) break;
+ parent = (DirectoryNode*)n;
+ mname.clear();
+ } else {
+ mname += name[i];
+ }
+ }
+ name = mname;
+
+ //Add new node
+ if (h.file_length == 0) {
+ parent->createDirectory(name);
+ } else {
+ FileNode* file = parent->createFile(name);
+ file->write(0, h.file_length, curr.c);
+ curr.c += h.file_length;
+ }
+ }
+ }
+}
+
+bool RamFS::setName(FSNode* node, String name) { return true; }
+bool RamFS::setPermissions(FSNode* node, u32int permissions) { return true; }
+bool RamFS::setUid(FSNode* node, u32int uid) { return true; }
+bool RamFS::setGid(FSNode* node, u32int gid) { return true; }
+bool RamFS::setParent(FSNode* node, FSNode* parent) {
+ if (parent->getFS() == this) return true;
+ return false;
+}
+
+u32int RamFS::read(FileNode* file, u64int position, u32int max_length, u8int *data) {
+ RamFileNode *node = (RamFileNode*) file;
+ if (file->getLength() <= position) return 0;
+ u32int length = file->getLength() - position;
+ if (length > max_length) length = max_length;
+ memcpy(data, node->m_data + position, length);
+ return length;
+}
+
+bool RamFS::write(FileNode* file, u64int position, u32int length, u8int *data) {
+ if (!m_isWritable) return false;
+ RamFileNode *node = (RamFileNode*) file;
+
+ u32int end = position + length;
+ if (end > node->getLength()) {
+ if (m_usedSize - node->getLength() + end > m_maxSize) return false;
+ m_usedSize -= node->getLength();
+ m_usedSize += end;
+
+ u8int* data = (u8int*)Mem::kalloc(end);
+ if (data == 0) return false; //Invalid pointer
+ if (node->m_data != 0) {
+ memcpy(data, node->m_data, node->getLength());
+ Mem::kfree(node->m_data);
+ }
+ node->m_data = data;
+ node->setLength(end);
+ }
+ memcpy(node->m_data + position, data, length);
+ return true;
+}
+
+bool RamFS::truncate(FileNode* file) {
+ if (!m_isWritable) return false;
+ RamFileNode *node = (RamFileNode*) file;
+
+ Mem::kfree(node->m_data);
+ node->setLength(0);
+ node->m_data = 0;
+
+ return true;
+}
+
+bool RamFS::loadContents(DirectoryNode* dir) { return true; } //Nothing to do.
+
+FileNode* RamFS::createFile(DirectoryNode* parent, String name) {
+ if (!m_isWritable) return NULL;
+ if (parent->getFS() != this) return NULL;
+
+ RamFileNode* n = new RamFileNode(name, this, parent);
+ parent->loadContent();
+ parent->getChildren().push(n);
+
+ return n;
+}
+
+DirectoryNode* RamFS::createDirectory(DirectoryNode* parent, String name) {
+ if (!m_isWritable) return NULL;
+ if (parent->getFS() != this) return NULL;
+
+ DirectoryNode* d = new DirectoryNode(name, this, parent);
+ parent->loadContent();
+ parent->getChildren().push(d);
+
+ return d;
+}
+
+bool RamFS::remove(DirectoryNode* parent, FSNode* node) { return true; }
diff --git a/Source/Kernel/FileSystems/RamFS/RamFS.class.h b/Source/Kernel/FileSystems/RamFS/RamFS.class.h
new file mode 100644
index 0000000..0a3f0c4
--- /dev/null
+++ b/Source/Kernel/FileSystems/RamFS/RamFS.class.h
@@ -0,0 +1,43 @@
+#ifndef DEF_RAMFS_CLASS_H
+#define DEF_RAMFS_CLASS_H
+
+#include <VFS/FileSystem.proto.h>
+
+struct initrd_header {
+ unsigned int magic;
+ unsigned int files;
+};
+
+struct initrd_file_header {
+ unsigned int name_length;
+ unsigned int file_length;
+};
+
+#define INITRD_MAGIC 0x1337BEEF
+
+class RamFS : public FileSystem {
+ private:
+ u32int m_maxSize;
+ u32int m_usedSize;
+
+ public:
+ RamFS(u32int maxSize); //Creates an empty RAM file system
+ RamFS(u8int* ptr, u32int maxSize, bool writable = true); //Creates a RAM file system from data loaded in memory. format to be defined
+
+ 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);
+};
+
+#endif
diff --git a/Source/Kernel/FileSystems/RamFS/RamFileNode.class.h b/Source/Kernel/FileSystems/RamFS/RamFileNode.class.h
new file mode 100644
index 0000000..d600630
--- /dev/null
+++ b/Source/Kernel/FileSystems/RamFS/RamFileNode.class.h
@@ -0,0 +1,19 @@
+#ifndef DEF_RAMFILENODE_CLASS_H
+#define DEF_RAMFILENODE_CLASS_H
+
+#include <VFS/FileNode.class.h>
+
+class RamFileNode : public FileNode {
+ friend class RamFS;
+
+ private:
+ RamFileNode (String name, FileSystem* fs, FSNode* parent, u32int permissions = 0777,
+ u32int uid = 0, u32int gid = 0) :
+ FileNode(name, fs, parent, 0, permissions, uid, gid), m_data(0) {}
+
+ u8int *m_data; //We don't take care of allocation/freeing here, RamFS:: does that for us
+
+ void setLength(u32int length) { m_length = length; }
+};
+
+#endif
diff --git a/Source/Kernel/Library/String.class.cpp b/Source/Kernel/Library/String.class.cpp
index e70d19f..5ee216c 100644
--- a/Source/Kernel/Library/String.class.cpp
+++ b/Source/Kernel/Library/String.class.cpp
@@ -54,7 +54,7 @@ String::String() {
m_length = 0;
}
-String::String(char* string) {
+String::String(const char* string) {
m_length = WChar::utf8len(string);
if (m_length == 0) {
m_string = 0;
@@ -100,7 +100,7 @@ void String::operator= (const String &other) {
m_string[m_length] = 0;
}
-void String::operator= (char* string) {
+void String::operator= (const char* string) {
m_length = WChar::utf8len(string);
if (m_string != 0) delete [] m_string;
if (m_length == 0) {
@@ -116,7 +116,7 @@ void String::operator= (char* string) {
m_string[m_length] = 0;
}
-bool String::operator== (String &other) {
+bool String::operator== (const String &other) const {
if (m_length != other.m_length) return false;
for (u32int i = 0; i < m_length; i++) {
if (m_string[i] != other.m_string[i]) return false;
@@ -124,7 +124,7 @@ bool String::operator== (String &other) {
return true;
}
-bool String::operator== (char* string) {
+bool String::operator== (const char* string) const {
if (m_length != WChar::utf8len(string)) return false;
int i = 0, l = strlen(string), c = 0;
WChar tmp;
@@ -136,7 +136,7 @@ bool String::operator== (char* string) {
return true;
}
-String& String::operator+= (String &other) {
+String& String::operator+= (const String &other) {
WChar* newdata = new WChar[m_length + other.m_length + 1];
for (u32int i = 0; i < m_length; i++) {
newdata[i] = m_string[i];
@@ -151,7 +151,7 @@ String& String::operator+= (String &other) {
return *this;
}
-String& String::operator+= (char* other) {
+String& String::operator+= (const char* other) {
WChar* newdata = new WChar[m_length + WChar::utf8len(other) + 1];
for (u32int i = 0; i < m_length; i++) {
newdata[i] = m_string[i];
@@ -181,22 +181,22 @@ String& String::operator+= (WChar other) {
return *this;
}
-String& String::operator+ (String &other) { //Can be optimized
+String& String::operator+ (const String &other) const { //Can be optimized
String ret(*this);
return (ret += other);
}
-String& String::operator+ (char* other) { //Can be optimized
+String& String::operator+ (const char* other) const { //Can be optimized
String ret(*this);
return (ret += other);
}
-String& String::operator+ (WChar other) {
+String& String::operator+ (WChar other) const {
String ret(*this);
return (ret += other);
}
-s32int String::toInt() {
+s32int String::toInt() const {
if (m_string == 0) return 0;
s32int pos = 0, number = 0;
bool negative = false;
@@ -213,7 +213,7 @@ s32int String::toInt() {
return number;
}
-u32int String::toInt16() {
+u32int String::toInt16() const {
if (m_string == 0) return 0;
u32int pos = 0, number = 0;
if (m_string[0].value == '0' && m_string[1].value == 'x') pos = 2;
@@ -236,11 +236,11 @@ u32int String::toInt16() {
return number;
}
-WChar& String::operator[] (int index) {
+WChar& String::operator[] (int index) const {
return m_string[index];
}
-u32int String::size() {
+u32int String::size() const {
return m_length;
}
@@ -250,11 +250,11 @@ void String::clear() {
m_string = 0;
}
-bool String::empty() {
+bool String::empty() const {
return (m_length == 0);
}
-Vector<String> String::split(WChar c) {
+Vector<String> String::split(WChar c) const {
Vector<String> ret;
ret.push(String(""));
for (u32int i = 0; i < m_length; i++) {
diff --git a/Source/Kernel/Library/String.class.h b/Source/Kernel/Library/String.class.h
index ecbc2a0..01cc6a8 100644
--- a/Source/Kernel/Library/String.class.h
+++ b/Source/Kernel/Library/String.class.h
@@ -15,31 +15,33 @@ class String {
static String hex(u32int number);
static String number(s32int number);
- String(char* string);
+ String(const char* string);
String();
String(const String &other);
~String();
void operator= (const String &other);
- void operator= (char* string);
-
- bool operator== (String &other);
- bool operator== (char* string);
- String &operator+= (String &other);
- String &operator+= (char* other);
+ void operator= (const char* string);
+
+ bool operator== (const String &other) const;
+ bool operator== (const char* string) const;
+ bool operator!= (const String &other) { return !(operator== (other)); }
+ bool operator!= (const char* other) { return !(operator== (other)); }
+ String &operator+= (const String &other);
+ String &operator+= (const char* other);
String &operator+= (WChar other);
- String &operator+ (String &other);
- String &operator+ (char* other);
- String &operator+ (WChar other);
- s32int toInt();
- u32int toInt16(); //From HEX
- WChar& operator[] (int index);
-
- u32int size();
+ String &operator+ (const String &other) const;
+ String &operator+ (const char* other) const;
+ String &operator+ (WChar other) const;
+ s32int toInt() const;
+ u32int toInt16() const; //From HEX
+ WChar& operator[] (int index) const;
+
+ u32int size() const;
void clear();
- bool empty();
+ bool empty() const;
- Vector<String> split(WChar c);
+ Vector<String> split(WChar c) const;
String substr(s32int start, s32int size);
};
diff --git a/Source/Kernel/Library/Vector.class.cpp b/Source/Kernel/Library/Vector.class.cpp
index aaa777f..8b032ca 100644
--- a/Source/Kernel/Library/Vector.class.cpp
+++ b/Source/Kernel/Library/Vector.class.cpp
@@ -1,22 +1,36 @@
using namespace CMem; //strlen and memcpy
+#define DELDATA if (m_data != NULL and m_size != 0) { \
+ for (u32int i = 0; i < m_size; i++) { \
+ m_data[i].~T(); \
+ } \
+ Mem::kfree(m_data); \
+}
+
template <typename T>
Vector<T>::Vector() {
+ //DEBUG_HEX((u32int)this); DEBUG(" NEW EMPTY");
+ //DEBUG_HEX(sizeof(T)); DEBUG(" sizeof(T)");
m_data = 0;
m_size = 0;
}
template <typename T>
Vector<T>::Vector(u32int size) {
+ //DEBUG_HEX((u32int)this); DEBUG(" NEW ZERO");
m_data = new T[size];
m_size = size;
}
template <typename T>
-Vector<T>::Vector(u32int size, T value) {
+Vector<T>::Vector(u32int size, const T& value) {
+ //DEBUG_HEX((u32int)this); DEBUG(" NEW FILLED");
//m_data = (T*)Mem::kalloc(size * sizeof(T));
- m_data = new T[size](value);
+ m_data = new T[size];
m_size = size;
+ for (u32int i = 0; i < m_size; i++) {
+ new (&m_data[i]) T(value);
+ }
/*for (u32int i = 0; i < size; i++) {
m_data[i] = new(&m_data[i]) T(value);
}*/
@@ -24,16 +38,31 @@ Vector<T>::Vector(u32int size, T value) {
template <typename T>
Vector<T>::Vector(const Vector<T> &other) {
+ //DEBUG_HEX((u32int)this); DEBUG(" COPY REF");
+ m_size = other.m_size;
+ m_data = (T*)Mem::kalloc(m_size * sizeof(T));
+ for (u32int i = 0; i < m_size; i++) {
+ new(&m_data[i]) T(other.m_data[i]);
+ }
+}
+
+template <typename T>
+Vector<T>& Vector<T>::operator= (const Vector<T> &other) {
+ //DEBUG_HEX((u32int)this); DEBUG(" COPY EQ");
+ DELDATA;
m_size = other.m_size;
m_data = (T*)Mem::kalloc(m_size * sizeof(T));
for (u32int i = 0; i < m_size; i++) {
new(&m_data[i]) T(other.m_data[i]);
}
+ return *this;
}
template <typename T>
Vector<T>::~Vector() {
- if (m_data != 0) delete[] m_data;
+ //DEBUG_HEX((u32int)this); DEBUG(" DELETE");
+ DELDATA;
+ //if (m_data != 0) delete[] m_data;
}
template <typename T>
@@ -42,10 +71,13 @@ T& Vector<T>::operator[] (u32int index) {
}
template <typename T>
-void Vector<T>::push(T element) {
+void Vector<T>::push(const T& element) {
T* newdata = (T*)Mem::kalloc((m_size + 1) * sizeof(T));
- memcpy((u8int*)newdata, (const u8int*) m_data, m_size * sizeof(T));
+ if (m_size != 0 and m_data != 0) {
+ memcpy((u8int*)newdata, (const u8int*) m_data, m_size * sizeof(T));
+ }
new(&newdata[m_size]) T(element); //Construct by copy
+ //newdata[m_size] = element;
m_size++;
Mem::kfree(m_data);
m_data = newdata;
@@ -97,7 +129,7 @@ bool Vector<T>::empty() {
template <typename T>
void Vector<T>::clear() {
if (empty()) return;
- Mem::kfree(m_data);
+ DELDATA
m_data = 0;
m_size = 0;
}
diff --git a/Source/Kernel/Library/Vector.class.h b/Source/Kernel/Library/Vector.class.h
index 9763d2c..ca86c2a 100644
--- a/Source/Kernel/Library/Vector.class.h
+++ b/Source/Kernel/Library/Vector.class.h
@@ -12,13 +12,14 @@ class Vector {
public:
Vector();
Vector(u32int size);
- Vector(u32int size, T value);
+ Vector(u32int size, const T& value);
Vector(const Vector<T> &other);
+ Vector<T>& operator= (const Vector<T> &other);
~Vector();
T& operator[] (u32int index);
- void push(T element);
+ void push(const T& element);
//void push(T& element);
void pop();
diff --git a/Source/Kernel/Library/WChar.class.cpp b/Source/Kernel/Library/WChar.class.cpp
index c1a1977..bb1269d 100644
--- a/Source/Kernel/Library/WChar.class.cpp
+++ b/Source/Kernel/Library/WChar.class.cpp
@@ -19,11 +19,11 @@ WChar::WChar(char c) {
affectAscii(c);
}
-WChar::WChar(char* c) {
+WChar::WChar(const char* c) {
affectUtf8(c);
}
-u32int WChar::utf8len(char* c) {
+u32int WChar::utf8len(const char* c) {
int i = 0, l = CMem::strlen(c), co = 0;
while (i < l) {
if ((c[i] & 0x80) == 0) i += 1;
@@ -41,7 +41,7 @@ void WChar::affectAscii(char c) {
else value = CP437[c + 128];
}
-u32int WChar::affectUtf8(char* c) { //Returns the number of bytes for the character
+u32int WChar::affectUtf8(const char* c) { //Returns the number of bytes for the character
/*if ((c[0] & 0xB0) == 0x80) { //11000000b == 10000000b, means we are IN a sequence
value = 0;
return 1;
diff --git a/Source/Kernel/Library/WChar.class.h b/Source/Kernel/Library/WChar.class.h
index c582017..9ddccd1 100644
--- a/Source/Kernel/Library/WChar.class.h
+++ b/Source/Kernel/Library/WChar.class.h
@@ -9,14 +9,14 @@ struct WChar {
WChar(); //Creates a null character
WChar(char c); //From ascii character
- WChar(char* c); //From utf8 string
+ WChar(const char* c); //From utf8 string
- static u32int utf8len(char* c); //Returns count of utf8 characters in string
+ static u32int utf8len(const char* c); //Returns count of utf8 characters in string
void affectAscii(char c);
- u32int affectUtf8(char* c);
- void affectUtf16(char* c);
- void affectUtf32(char* c);
+ u32int affectUtf8(const char* c);
+ void affectUtf16(const char* c);
+ void affectUtf32(const char* c);
u8int toAscii();
inline WChar operator+ (u32int other) {
diff --git a/Source/Kernel/Makefile b/Source/Kernel/Makefile
index e0f2068..79dfbb3 100644
--- a/Source/Kernel/Makefile
+++ b/Source/Kernel/Makefile
@@ -38,6 +38,9 @@ Objects = Core/loader.wtf.o \
Library/WChar.class.o \
VFS/Partition.class.o \
VFS/Part.ns.o \
+ VFS/VFS.ns.o \
+ VFS/DirectoryNode.class.o \
+ FileSystems/RamFS/RamFS.class.o \
SyscallManager/IDT.ns.o \
SyscallManager/IDT.wtf.o \
Devices/Display/VGATextOutput.class.o \
diff --git a/Source/Kernel/Melon.ke b/Source/Kernel/Melon.ke
index 552d00c..418c1a8 100755
--- a/Source/Kernel/Melon.ke
+++ b/Source/Kernel/Melon.ke
Binary files differ
diff --git a/Source/Kernel/Ressources/Welcome.txt b/Source/Kernel/Ressources/Welcome.txt
new file mode 100644
index 0000000..97d6755
--- /dev/null
+++ b/Source/Kernel/Ressources/Welcome.txt
@@ -0,0 +1 @@
+Hi, this is a file located on an InitRD ! éàç...
diff --git a/Source/Kernel/VFS/DirectoryNode.class.cpp b/Source/Kernel/VFS/DirectoryNode.class.cpp
new file mode 100644
index 0000000..d624e97
--- /dev/null
+++ b/Source/Kernel/VFS/DirectoryNode.class.cpp
@@ -0,0 +1,76 @@
+#include "DirectoryNode.class.h"
+
+bool DirectoryNode::removable() {
+ if (!m_contentLoaded)
+ if (!loadContent())
+ return false;
+ return m_children.empty();
+}
+
+bool DirectoryNode::loadContent() {
+ if (m_contentLoaded) return true;
+ bool b = m_fs->loadContents(this);
+ if (!b) return false;
+ m_length = m_children.size();
+ m_contentLoaded = true;
+ return b;
+}
+
+FSNode* DirectoryNode::getChild(u32int index) {
+ if (!m_contentLoaded)
+ if (!loadContent())
+ return NULL;
+ if (index >= m_children.size()) return NULL;
+ return m_children[index];
+}
+
+FSNode* DirectoryNode::getChild(const String& name) {
+ if (!m_contentLoaded)
+ if (!loadContent())
+ return NULL;
+ for (u32int i = 0; i < m_children.size(); i++) {
+ if (name == m_children[i]->getName())
+ return m_children[i];
+ }
+ return NULL;
+}
+
+FileNode* DirectoryNode::createFile(const String& name) {
+ FileNode* n = m_fs->createFile(this, name);
+ m_length = m_children.size();
+ return n;
+}
+
+DirectoryNode* DirectoryNode::createDirectory(const String& name) {
+ DirectoryNode* n = m_fs->createDirectory(this, name);
+ m_length = m_children.size();
+ return n;
+}
+
+bool DirectoryNode::remove(FSNode* child) {
+ //Check node is indeed one of our childs
+ if (!m_contentLoaded)
+ if (!loadContent())
+ return false;
+ u32int idx = (u32int) - 1;
+ for (u32int i = 0; i < m_children.size(); i++) {
+ if (m_children[i] == child) {
+ idx = i;
+ break;
+ }
+ }
+ if (idx == (u32int) - 1) return false;
+
+ //Check if we can remove node
+ if (!m_children[idx]->removable()) return false;
+ if (m_fs != m_children[idx]->getFS()) return false; //We could !be on the same FS
+
+ //Ask FS to remove node
+ if (!m_fs->remove(this, child)) return false;
+
+ //Remove node from our children list
+ m_children[idx] = m_children.back();
+ m_children.pop();
+
+ return true;
+}
diff --git a/Source/Kernel/VFS/DirectoryNode.class.h b/Source/Kernel/VFS/DirectoryNode.class.h
new file mode 100644
index 0000000..5de523e
--- /dev/null
+++ b/Source/Kernel/VFS/DirectoryNode.class.h
@@ -0,0 +1,31 @@
+#ifndef DEF_DIRECTORYNODE_CLASS_H
+#define DEF_DIRECTORYNODE_CLASS_H
+
+#include <VFS/FileNode.class.h>
+#include <Library/Vector.class.h>
+
+class DirectoryNode : public FSNode {
+ protected:
+ Vector<FSNode*> m_children;
+ bool m_contentLoaded;
+
+ public:
+ DirectoryNode(String name, FileSystem* fs, FSNode* parent, u32int permissions = 0777,
+ u32int uid = 0, u32int gid = 0) :
+ FSNode(name, fs, parent, 0, permissions, uid, gid), m_children(), m_contentLoaded(false) {}
+ virtual ~DirectoryNode() {}
+
+ Vector<FSNode*> &getChildren() { return m_children; } //MUST BE USED ONLY BY FILESYSTEMS
+
+ u8int type() { return NT_DIRECTORY; }
+ bool removable();
+
+ bool loadContent();
+ FSNode* getChild(u32int index);
+ FSNode* getChild(const String& name);
+ FileNode* createFile(const String& name);
+ DirectoryNode* createDirectory(const String& name);
+ bool remove(FSNode* child); //Removes a child node from this directory
+};
+
+#endif
diff --git a/Source/Kernel/VFS/FSNode.proto.h b/Source/Kernel/VFS/FSNode.proto.h
new file mode 100644
index 0000000..bcf9393
--- /dev/null
+++ b/Source/Kernel/VFS/FSNode.proto.h
@@ -0,0 +1,70 @@
+#ifndef DEF_FSNODE_PROTO_H
+#define DEF_FSNODE_PROTO_H
+
+#include <Core/common.wtf.h>
+#include <Library/String.class.h>
+class FSNode;
+#include <VFS/FileSystem.proto.h>
+
+enum {
+ NT_FILE = 1,
+ NT_DIRECTORY = 2,
+ NT_SYMLINK = 3,
+ NT_MOUNTPOINT = 4
+};
+
+class FSNode {
+ protected:
+ String m_name;
+ u32int m_length;
+ u32int m_permissions, m_uid, m_gid;
+ FileSystem *m_fs;
+ FSNode *m_parent;
+
+ public:
+ FSNode(String name, FileSystem* fs, FSNode* parent, u32int length = 0, u32int permissions = 0777,
+ u32int uid = 0, u32int gid = 0) :
+ m_name(name), m_length(length), m_permissions(permissions),
+ m_uid(uid), m_gid(gid), m_fs(fs), m_parent(parent) {}
+ virtual ~FSNode() {}
+
+ virtual u8int type() = 0;
+ virtual bool removable() = 0; //True for files, false for non-empty directories, true otherwise
+
+ const String& getName() { return m_name; }
+ u32int 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; }
+
+ public:
+ bool setName(String name) {
+ bool b = m_fs->setName(this, name);
+ if (b) m_name = name;
+ return b;
+ }
+ bool setPermissions(u32int permissions) {
+ bool b = m_fs->setPermissions(this, permissions);
+ if (b) m_permissions = permissions;
+ return b;
+ }
+ bool setUid(u32int uid) {
+ bool b = m_fs->setUid(this, uid);
+ if (b) m_uid = uid;
+ return b;
+ }
+ bool setGid(u32int gid) {
+ bool b = m_fs->setGid(this, gid);
+ if (b) m_gid = gid;
+ return b;
+ }
+ bool setParent(FSNode* parent) {
+ bool b = m_fs->setParent(this, parent); //FSSetParent is only expected to move files/directories in the same filesystem
+ if (b) m_parent = parent;
+ return b;
+ }
+};
+
+#endif
diff --git a/Source/Kernel/VFS/FileNode.class.h b/Source/Kernel/VFS/FileNode.class.h
new file mode 100644
index 0000000..b3a3f67
--- /dev/null
+++ b/Source/Kernel/VFS/FileNode.class.h
@@ -0,0 +1,31 @@
+#ifndef DEF_FILENODE_CLASS_H
+#define DEF_FILENODE_CLASS_H
+
+#include <VFS/FSNode.proto.h>
+
+class FileNode : public FSNode {
+ protected:
+ FileNode(String name, FileSystem* fs, FSNode* parent, u32int length = 0, u32int permissions = 0777,
+ u32int uid = 0, u32int gid = 0): FSNode(name, fs, parent, length, permissions, uid, gid) {}
+
+ public:
+ virtual ~FileNode() {}
+
+ u8int type() { return NT_FILE; }
+ bool removable() { return true; }
+
+ u32int read(u64int position, u32int max_length, u8int *data) {
+ return m_fs->read(this, position, max_length, data);
+ }
+
+ bool write(u64int position, u32int length, u8int *data) {
+ return m_fs->write(this, position, length, data);
+ }
+
+ bool truncate() {
+ return m_fs->truncate(this);
+ }
+
+};
+
+#endif
diff --git a/Source/Kernel/VFS/FileSystem.proto.h b/Source/Kernel/VFS/FileSystem.proto.h
new file mode 100644
index 0000000..2f768a7
--- /dev/null
+++ b/Source/Kernel/VFS/FileSystem.proto.h
@@ -0,0 +1,36 @@
+#ifndef DEF_FILESYSTEM_PROTO_H
+#define DEF_FILESYSTEM_PROTO_H
+
+#include <VFS/Partition.class.h>
+class FSNode;
+class FileNode;
+class DirectoryNode;
+
+//This abstract class describes a filesystem
+class FileSystem {
+ protected:
+ bool m_isWritable; //false = read only
+ DirectoryNode* m_rootNode;
+
+ public:
+ bool isWritable() { return m_isWritable; }
+ DirectoryNode* getRootNode() { return m_rootNode; }
+
+ //Must be implemented by the filesystem
+ virtual bool setName(FSNode* node, String name) = 0;
+ virtual bool setPermissions(FSNode* node, u32int permissions) = 0;
+ virtual bool setUid(FSNode* node, u32int uid) = 0;
+ virtual bool setGid(FSNode* node, u32int gid) = 0;
+ virtual bool setParent(FSNode* node, FSNode* parent) = 0;
+
+ virtual u32int read(FileNode* file, u64int position, u32int max_length, u8int *data) = 0;
+ virtual bool write(FileNode* file, u64int position, u32int length, u8int *data) = 0;
+ virtual bool truncate(FileNode* file) = 0;
+
+ virtual bool loadContents(DirectoryNode* dir) = 0;
+ virtual FileNode* createFile(DirectoryNode* parent, String name) = 0;
+ virtual DirectoryNode* createDirectory(DirectoryNode* parent, String name) = 0;
+ virtual bool remove(DirectoryNode* parent, FSNode* node) = 0;
+};
+
+#endif
diff --git a/Source/Kernel/VFS/VFS.ns.h b/Source/Kernel/VFS/VFS.ns.h
new file mode 100644
index 0000000..1021d7c
--- /dev/null
+++ b/Source/Kernel/VFS/VFS.ns.h
@@ -0,0 +1,22 @@
+#ifndef DEF_VFS_NS_H
+#define DEF_VFS_NS_H
+
+#include <VFS/DirectoryNode.class.h>
+#include <VFS/FileSystem.proto.h>
+
+typedef FileSystem* (* mountcallback)(Partition* partition);
+
+namespace VFS {
+ void registerMountCallback(mountcallback mcb);
+ bool mount(Partition* partition, DirectoryNode mountpoint);
+ bool setRootNode(DirectoryNode* root);
+ DirectoryNode* getRootNode();
+
+ FSNode* find(const String& path, FSNode* start = 0);
+ FSNode* createFile(const String& path, FSNode* start = 0);
+ FSNode* createDirectory(const String& path, FSNode* start = 0);
+ bool remove(const String& path, FSNode* start = 0); //Returns false for non-empty directories
+ String path(FSNode* node); //Returns complete path for a node
+}
+
+#endif
diff --git a/Source/Kernel/VTManager/VirtualTerminal.class.cpp b/Source/Kernel/VTManager/VirtualTerminal.class.cpp
index dde487c..be1299c 100644
--- a/Source/Kernel/VTManager/VirtualTerminal.class.cpp
+++ b/Source/Kernel/VTManager/VirtualTerminal.class.cpp
@@ -129,7 +129,7 @@ void VirtualTerminal::put(WChar c, bool updatecsr) {
if (updatecsr) updateCursor();
}
-void VirtualTerminal::write(String s, bool updatecsr) {
+void VirtualTerminal::write(const String& s, bool updatecsr) {
for (u32int i = 0; i < s.size(); i++) {
put(s[i], false);
}
diff --git a/Source/Kernel/VTManager/VirtualTerminal.class.h b/Source/Kernel/VTManager/VirtualTerminal.class.h
index 62aa650..6bdcf84 100644
--- a/Source/Kernel/VTManager/VirtualTerminal.class.h
+++ b/Source/Kernel/VTManager/VirtualTerminal.class.h
@@ -46,13 +46,13 @@ class VirtualTerminal {
//Display functions
void put(WChar c, bool updatecsr = true);
- void write(String s, bool updatecsr = true);
+ void write(const String& s, bool updatecsr = true);
void writeDec(s32int i, bool updatecsr = true);
void writeHex(u32int i, bool updatecsr = true);
void hexDump(u8int* ptr, u32int sz);
- inline VirtualTerminal& operator<<(String s) { write(s); return *this; }
+ inline VirtualTerminal& operator<<(const String& s) { write(s); return *this; }
//inline VirtualTerminal& operator<<(WChar c) { put(c); return *this; }
inline VirtualTerminal& operator<<(s32int i) { writeDec(i); return *this; }
inline VirtualTerminal& operator<<(u32int i) { writeHex(i); return *this; }
diff --git a/Source/Tools/MakeRamFS/MakeRamFS b/Source/Tools/MakeRamFS/MakeRamFS
new file mode 100755
index 0000000..be1dc1a
--- /dev/null
+++ b/Source/Tools/MakeRamFS/MakeRamFS
Binary files differ
diff --git a/Source/Tools/MakeRamFS/Makefile b/Source/Tools/MakeRamFS/Makefile
new file mode 100644
index 0000000..019ec29
--- /dev/null
+++ b/Source/Tools/MakeRamFS/Makefile
@@ -0,0 +1,38 @@
+.PHONY: clean, mrproper
+
+CC = gcc
+CXX = g++
+LD = gcc
+LDFLAGS = -lstdc++
+CFLAGS =
+CXXFLAGS =
+
+OutFile = MakeRamFS
+Objects = main.o
+
+all: $(OutFile)
+ echo "* Done with $(OutFile)."
+
+rebuild: mrproper all
+
+$(OutFile): $(Objects)
+ echo "* Linking executable : $(OutFile)..."
+ $(LD) -o $(OutFile) $(LDFLAGS) $^
+
+%.o: %.c
+ echo "* Compiling $<..."
+ $(CC) -c $< -o $@ $(CFLAGS)
+
+%.o: %.cpp
+ echo "* Compiling $<..."
+ $(CXX) -c $< -o $@ $(CXXFLAGS)
+
+clean:
+ echo "* Removing object files..."
+ rm -rf *.o
+ rm -rf */*.o
+ rm -rf */*/*.o
+
+mrproper: clean
+ echo "* Removing executable : $(OutFile)"
+ rm -rf $(OutFile)
diff --git a/Source/Tools/MakeRamFS/main.cpp b/Source/Tools/MakeRamFS/main.cpp
new file mode 100644
index 0000000..dcb2a2b
--- /dev/null
+++ b/Source/Tools/MakeRamFS/main.cpp
@@ -0,0 +1,95 @@
+#include <iostream>
+#include <fstream>
+#include <string>
+
+using namespace std;
+
+struct ramfs_header {
+ unsigned int magic; //For error checking
+ unsigned int files;
+};
+
+struct ramfs_file_header {
+ unsigned int name_length;
+ unsigned int file_length;
+};
+
+#define INITRD_MAGIC 0x1337BEEF
+
+int main(int argc, char *argv[]) {
+ if (argc < 2) {
+ cerr << "Error : no output file specified." << endl;
+ cerr << "Usage : MakeRamFS <output.img> [<filename>:<ramfs filename> [...] ]" << endl;
+ return 1;
+ }
+
+ ofstream output(argv[1], ios::out | ios::binary);
+
+ ramfs_header hdr;
+ hdr.magic = INITRD_MAGIC;
+ hdr.files = argc - 2;
+
+ output.write((char*)&hdr, sizeof(ramfs_header));
+
+ for (int i = 2; i < argc; i++) {
+ string name(argv[i]);
+ string file;
+ while (!name.empty()) {
+ if (name[0] == ':') {
+ name = name.substr(1, name.size() - 1);
+ break;
+ }
+ file += name[0];
+ name = name.substr(1, name.size() - 1);
+ }
+
+ ramfs_file_header fhdr;
+
+ if (file == "") { //This is a directory
+ fhdr.name_length = name.size();
+ fhdr.file_length = 0; //File length of 0 means directory
+ output.write((char*)&fhdr, sizeof(ramfs_file_header));
+ output << name;
+ output << '\0';
+ continue;
+ }
+
+ ifstream infile(file.c_str(), ios::in | ios::binary);
+
+ if (!infile) {
+ fhdr.name_length = 0; //Name and length = 0 means invalid file
+ fhdr.file_length = 0;
+ output.write((char*)&fhdr, sizeof(ramfs_file_header));
+ continue;
+ }
+
+ fhdr.name_length = name.size();
+ fhdr.file_length = 0;
+ while (!infile.eof()) {
+ char c;
+ infile.read(&c, 1);
+ fhdr.file_length++;
+ }
+
+ infile.close(); infile.open(file.c_str(), ios::in | ios::binary); //Rewind file
+
+ output.write((char*)&fhdr, sizeof(ramfs_file_header));
+
+ output << name;
+ output << '\0';
+
+ char *c = new char[fhdr.file_length];
+ for (int i = 0; i < fhdr.file_length; i++) {
+ char ch;
+ infile.read(&ch, 1);
+ output.write(&ch, 1);
+ }
+ delete [] c;
+
+ infile.close();
+ }
+
+ output.close();
+
+ return 0;
+}