diff options
Diffstat (limited to 'Source/Kernel/FileSystems')
-rw-r--r-- | Source/Kernel/FileSystems/FAT/FATDirectoryNode.class.h | 16 | ||||
-rw-r--r-- | Source/Kernel/FileSystems/FAT/FATFS.class.cpp | 247 | ||||
-rw-r--r-- | Source/Kernel/FileSystems/FAT/FATFS.class.h | 134 | ||||
-rw-r--r-- | Source/Kernel/FileSystems/FAT/FATFileNode.class.h | 16 | ||||
-rw-r--r-- | Source/Kernel/FileSystems/RamFS/RamFS.class.cpp | 11 | ||||
-rw-r--r-- | Source/Kernel/FileSystems/RamFS/RamFS.class.h | 6 | ||||
-rw-r--r-- | Source/Kernel/FileSystems/RamFS/RamFileNode.class.h | 2 |
7 files changed, 428 insertions, 4 deletions
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..fbefc02 --- /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(); + + String getDevDescription() { return Part::partIdentifier(m_part); } + + 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/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..042baa9 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; @@ -35,6 +35,8 @@ class RamFS : public FileSystem { bool setGid(FSNode* node, u32int gid); bool setParent(FSNode* node, FSNode* parent); + String getDevDescription() { return "ramfs"; } + 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); 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; } |