Shellscript improvement plus FAT driver implementations

- Improved the run bash script to exit when an error occurs in one of the sub tasks
- Wrote basic FAT16 functions that should give enough information to properly implement the rest of the driver
- FAT structure namings are now in accordence with the microsoft spec of March 2005
This commit is contained in:
2023-02-23 23:54:02 +01:00
parent 50bf952a49
commit a77621faf5
20 changed files with 760 additions and 495 deletions

View File

@ -1,21 +0,0 @@
#pragma once
#include <stdint.h>
#include "./ExtendBootRecord.h"
struct BiosParameterBlock {
uint8_t BootLoaderCodeSection [3];
uint8_t OEM_id [8];
uint16_t BytesPerSector ; // I suspect would be 512
uint8_t SectorsPerCluster ;
uint16_t ReservedSectors;
uint8_t NumberOfFileAllocationTables; // Probably equals 2
uint16_t NumberOfDirectoryEntries; // Root directory must contain entire sectors
uint16_t TotalSectorsInLogicalVolume ; // 0 means >65535 sectors in volume , actual count can be found in LargeSectorCount
uint8_t MediaDescriptor ; // Indication the media descriptor type
uint16_t NumberOfSectorsPerFAT;// only in FAT12 / FAT 16
uint16_t NumberOfSectorsPerTrack;
uint16_t NumberOfHeadsOnMedia;
uint32_t NumberOfHiddenSectors;
uint32_t LargeSectorCount;
ExtendedBootRecord_FAT16 ebpb;
}__attribute__((packed));

View File

@ -1,37 +0,0 @@
#pragma once
#include <stdint-gcc.h>
struct DirectoryEntry {
uint8_t filename [8];
uint8_t Extension [3];
uint8_t attribute;
uint8_t Reserved;
uint8_t creation; // Creation in tenths of a second
uint16_t CreationTime; // Time Created NOTE: Multiply the seconds by 2
uint16_t CreationDate; // Date Created
uint16_t LastAccessDate;
uint16_t ReservedFAT32;
uint16_t LastWriteTime;
uint16_t LastWriteDate;
uint16_t StartingCluster;
uint32_t FilesizeInBytes;
}__attribute__((packed));
typedef struct _DIRECTORY{
uint8_t Filename[8];
uint8_t Ext[3];
uint8_t Attrib;
uint8_t Reserved;
uint8_t TimeCreatedMs;
uint16_t TimeCreated;
uint16_t DateCreated;
uint16_t DateLastAccessed;
uint16_t FirstClusterHiBytes;
uint16_t LastModTime;
uint16_t LastModDate;
uint16_t FirstCluster;
uint32_t FileSize;
}__attribute__((packed)) DIRECTORY, *PDIRECTORY;

View File

@ -1,32 +0,0 @@
#pragma once
#include <stdint.h>
struct ExtendedBootRecord_FAT16{
uint8_t DriveNumber;
uint8_t Reserved;
uint8_t Signature;
const uint32_t VOLUME_ID_SERIAL_NUMBER;
uint8_t volume_label [11];
uint8_t Identifier_string [8];
uint8_t bootCode [448];
uint16_t partitionSignature;
}__attribute__((packed));
struct ExtendedBootRecord_FAT32{
uint32_t SectorsPerFAT;
uint16_t Flags;
const uint16_t FAT_VERSION_NUMBER;
uint32_t rootDirectory_clusterNumber;// Often set to 2;
uint16_t FSInfo_SectorNumber;
uint16_t backup_bpb_sectorNumber;
uint8_t Reserved [12];
uint8_t DriveNumber;
uint8_t Reserved2;
uint8_t Signature; // must be 0x28 or 0x29
uint32_t VOLUME_ID_SERIAL;
uint8_t volume_label[11];
uint8_t SystemIdentifierString [8]; // ALWAYS "FAT32 " but spec says do not trust
uint8_t BootCode [420]; // NICE
uint16_t PartitionSignature; // 0xAA55
}__attribute__((packed));

View File

@ -4,105 +4,198 @@
#include "FAT.h"
#include "../../ata pio/ATAPIO.h"
#include "../../../memory/KernelHeap.h"
#include "../../../../CoreLib/Memory.h"
#include "../../partitiontables/mbr/MasterBootRecord.h"
#include <CoreLib/Memory.h>
void FAT::Read(PFILE file, unsigned char* buffer , unsigned int length)
superblock* FAT::Mount(filesystem *fs, const char* name ,vfsmount *mnt)
{
}
FILE FAT::Open(char* filename)
{
char* tokstate = NULL;
char* nextdir = strtok(filename, "/", &tokstate);
while (nextdir)
if( strncmp (fs->name, "fat", 3 ) != 0 )
{
// Read the root directory
printf("First entry to look for: %s\n", nextdir);
nextdir = strtok(NULL, "/", &tokstate);
printf("Can't mount filesystem with none fat type!\n");
return nullptr;
}
FILE file;
file.flags = FS_INVALID;
return file;
superblock* sb = (superblock*) malloc(sizeof(superblock));
directoryEntry* root = (directoryEntry*) malloc(sizeof (directoryEntry));
root->name = (char*) name;
root->node = nullptr;
root->parent = nullptr;
dentry_operations* op = (dentry_operations*) malloc(sizeof(dentry_operations));
op->compare = FAT::compare;
root->op = op;
mnt->mnt_count =1;
mnt->mnt_devname = "QEMU HDD";
mnt->mnt_flags = 0;
mnt->mnt_parent = nullptr;
mnt->root = root;
mnt->sb = sb;
sb->type = fs;
sb->root = root;
//sb->fs_info = getBPB();
return sb;
}
void FAT::Write(PFILE file, unsigned char* buffer, unsigned int length)
int FAT::Read(file* file, void* buffer , int length)
{
return 0;
}
void ParseDateInteger(unsigned int date){
printf("Date (hex) 0x%x\n", date);
unsigned int year = (date >> 9 )+ 1980;
unsigned int month = (date & 0xf0 ) >> 4;
unsigned int day = date & 0xf ;
printf("Date: (D,M,Y) %d, %d ,%d\n", day , month, year );
int FAT::Write(file* file, const void* buffer, int length)
{
return 0;
}
int FAT::compare (directoryEntry*, char* filename, char* filename2)
{
// use the size of the smallest string
int a = strlen(filename);
int b = strlen(filename2);
if( a == b ){
return strncmp(filename, filename2, a);
}
return a-b;
}
int FAT::create(inode* dir_node, inode** target, const char* component_name){}
int FAT::lookup (inode*, inode**, const char*){}
BiosParameterBlock* getBPB(PTR_PARTITION partition, bool DEBUG =false ){
FAT_TYPE FAT::determineFATType(BiosParameterBlock* bpb){
int RootDirSector = ((bpb->RootEntCnt * 32) + (bpb->BytsPerSec -1)) / bpb->BytsPerSec;
int FATSz = 0;
if(bpb->FATSz16 != 0){
FATSz = bpb->FATSz16;
} else{
// FATSz = bpb->FATSz32;
}
int TotSec = 0;
if(bpb->TotSec16 != 0){
TotSec= bpb->TotSec16;
}else{
TotSec = bpb->TotSec32;
}
int DataSec = TotSec - (bpb->RsvdSecCnt + (bpb->NumFATs * FATSz) + RootDirSector);
int CountofClusters = DataSec / bpb->SecPerClus;
if(CountofClusters < 4085){
return FAT_TYPE::FAT12;
} else if (CountofClusters < 65525) {
return FAT_TYPE::FAT16;
} else{
return FAT_TYPE::FAT32;
}
};
BiosParameterBlock* FAT::getBPB( bool DEBUG ){
BiosParameterBlock* bpb = (BiosParameterBlock*) malloc(sizeof(BiosParameterBlock));
ATAPIO_PORT port = (ATAPIO_PORT)(partition->Disk & 0x01FF);
DEVICE_DRIVE drive = (DEVICE_DRIVE)(partition->Disk >> 16);
printf("ATAPIO_PORT: 0x%x DEVICE_DRIVE: 0x%x\n",port, drive);
printf("Partition Start Address (LBA): 0x%x\n", partition->StartAddress);
ATAPIO::Read(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER, partition->StartAddress, (uint16_t*) bpb);
uint16_t StartAddress = 0x00 ;
ATAPIO::Read(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER, StartAddress, (uint16_t*) bpb);
if(DEBUG)
{
printf("OEM ID: %s\n", bpb->OEM_id);
printf("Bytes per sector: %d\n", bpb->BytesPerSector);
printf("Sectors per cluster: %d\n", bpb->SectorsPerCluster);
printf("Reserved sectors: %d\n", bpb->ReservedSectors);
printf("Number of FAT: %d\n", bpb->NumberOfFileAllocationTables);
printf("Number of Dir entries: %d\n", bpb->NumberOfDirectoryEntries);
printf("Total Sectors in volume: %d\n", bpb->TotalSectorsInLogicalVolume);
printf("Sectors per FAT: %d\n", bpb->NumberOfSectorsPerFAT);
printf("OEM ID: %s\n", bpb->OEMName);
printf("Bytes per sector: %d\n", bpb->BytsPerSec);
printf("Sectors per cluster: %d\n", bpb->SecPerClus);
printf("Reserved sectors: %d\n", bpb->RsvdSecCnt);
printf("Number of FAT: %d\n", bpb->NumFATs);
printf("Number of Dir entries: %d\n", bpb->RootEntCnt);
printf("Total Sectors in volume: %d\n", bpb->TotSec16 == 0 ? bpb->TotSec32 : bpb->TotSec16);
printf("Sectors per FAT: %d\n", bpb->FATSz16 );
}
return bpb;
}
bool FAT::Validate(PTR_PARTITION partition )
{
auto* bootParams = getBPB(partition, true);
if(bootParams->OEM_id) {
return true;
uint16_t FAT::GetFATEntry (BiosParameterBlock* bpb, unsigned int cluster){
int FATSz =0;
if(bpb->FATSz16 != 0){
FATSz = bpb->FATSz16;
} else{
//FATSz = bpb->FATSz32;
}
return false;
int FATOffset = 0;
FAT_TYPE type = FAT::determineFATType(bpb);
if( type == FAT_TYPE::FAT16){
FATOffset = cluster *2;
} else if( type == FAT_TYPE::FAT32){
FATOffset = cluster * 4;
}
int thisFATSecNum = bpb->RsvdSecCnt + (FATOffset / bpb->BytsPerSec); // Sector number containing the entry for the cluster
// For any other FAT other then the default
// SectorNumber = (FATNumber * FATSz) + ThisFATSecNum
uint16_t buff[bpb->BytsPerSec];
ATAPIO::Read(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER, thisFATSecNum, buff );
int thisFATEntOffset = FATOffset % bpb->BytsPerSec; // offset for the entry in the sector containing the entry for the cluster
uint16_t ClusterEntryValue = 0;
// Get the FATEntry
if(type == FAT_TYPE::FAT16){
return *((uint16_t*) &buff[thisFATEntOffset]);
}
else{
// FAT32 logic
return 0;
}
}
void FAT::Info(_PARTITION *pPartition, PFS pSystem) {
pSystem->Read = FAT::Read;
pSystem->Write = FAT::Write;
pSystem->Open = FAT::Open;
uint16_t FAT::DetermineFreeSpace()
{
// Loop through all FAT entries in all FAT's
// to construct a list of free/available clusters
// Free clusters are recorded with all 0's except on FAT32 where
// the highest order 4 bits should be ignored.
/*
* The number of sectors reserved for each FAT (count of sectors in the BPB_FATSz16 or
BPB_FATSz32 fields) may be bigger than the actual number of sectors required for
containing the entire FAT. Therefore, there may be totally unused FAT sectors at the end of
each FAT in the FAT region of the volume. Each implementation must determine the value
for the last valid sector in the FAT using CountOfClusters (the last valid sector in the FAT
is the one containing the FAT entry numbered CountOfClusters + 1).
All sectors reserved for the FAT beyond the last valid sector (defined as the one containing
the FAT entry for the last cluster) must be set to 0x0 during volume initialization/format.
*/
}
uint16_t* ReadFAT (BiosParameterBlock& bpb , PTR_PARTITION partition, bool DEBUG = false ) {
uint32_t FATAddress = partition->StartAddress + bpb.ReservedSectors ;
int FAT::GetSectorOfRootDirectory (BiosParameterBlock* bpb)
{
return (bpb->RsvdSecCnt + (bpb->NumFATs * bpb->FATSz16));
}
int FAT::RootDirSize(BiosParameterBlock* bpb)
{
int size = bpb->RootEntCnt * 32;
if((size % bpb->BytsPerSec) != 0){
printf("ERR: Root entry count invalid!\n");
return -1;
}
return size;
}
uint16_t* ReadFAT (BiosParameterBlock& bpb , bool DEBUG = false ) {
uint32_t FATAddress = /*StartAddress*/ 0x00 + bpb.RsvdSecCnt ;
uint16_t* FAT = (uint16_t*)malloc(sizeof (uint16_t) * 256);
ATAPIO_PORT port = (ATAPIO_PORT)(partition->Disk & 0x01FF);
DEVICE_DRIVE drive = (DEVICE_DRIVE)(partition->Disk >> 16);
ATAPIO::Read(port, drive, FATAddress, FAT );
ATAPIO::Read(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER, FATAddress, FAT );
// Show data in terminal
if(DEBUG){
@ -115,14 +208,15 @@ uint16_t* ReadFAT (BiosParameterBlock& bpb , PTR_PARTITION partition, bool DEBUG
return FAT;
}
void readFile(uint32_t DataRegion, DirectoryEntry* entry, uint16_t FATentry, BiosParameterBlock& bpb ){
void readFile(uint32_t DataRegion, DIR* entry, uint16_t FATentry, BiosParameterBlock& bpb ){
printf("Show contents");
printf("Start cluster of the file: 0x%x\n", entry->StartingCluster);
printf("Start cluster of the file: 0x%x\n", entry->FileSize);
printf("IS it only 1 cluster? %s\n", FATentry == 0xFFFF ? "Yes" : "No");
uint32_t sector = DataRegion + ((entry->StartingCluster - 0x02) * bpb.SectorsPerCluster);
uint32_t sector = DataRegion + ((entry->FileSize - 0x02) * bpb.SecPerClus);
uint16_t dataBlob[256];
@ -134,66 +228,21 @@ void readFile(uint32_t DataRegion, DirectoryEntry* entry, uint16_t FATentry, Bio
}
kterm_put('\n');
}
/*
void listFilesInRoot(MBR& mbr, BiosParameterBlock& bpb ){
auto FATAddress = mbr.TableEntries[0].LBA_partition_start + bpb.ReservedSectors;
uint32_t RootDirectoryRegion = FATAddress + ( bpb.NumberOfFileAllocationTables * bpb.NumberOfSectorsPerFAT );
uint32_t DataRegion = RootDirectoryRegion + ((bpb.NumberOfDirectoryEntries * 32) / bpb.BytesPerSector );
uint16_t* FAT = ReadFAT(bpb, mbr);
uint16_t data2 [256];
ATA_DEVICE::Read(BUS_PORT::Primary, DEVICE_DRIVE::MASTER, RootDirectoryRegion, data2 );
auto* RootDirectory = (DirectoryEntry*) data2;
// List files in root
for(int i= 0; i < sizeof (data2) / sizeof (DirectoryEntry); i++ ) {
auto *entry = (DirectoryEntry * )((uint32_t) RootDirectory + (i * sizeof(DirectoryEntry)));
if (entry->filename[0] == (uint8_t) 0x00)
continue; // There are no more entries in this directory or the entry is free
if (entry->attribute & ATTRIBUTES::ATT_HIDDEN)
continue;
if(entry->attribute & ATTRIBUTES::ATTR_SYSTEM)
continue;
if(entry->attribute & ATTRIBUTES::ATTR_VOLUME_ID)
continue;
// Print the filename;
for (char n: entry->filename) {
if (n == 0x20)
break;
kterm_put(n);
}
for (unsigned char n: entry->Extension) {
kterm_put(n);
}
kterm_put('\n');
printf("Attribute: %x \n", entry->attribute);
printf("FileSize: %d Bytes\n", entry->FilesizeInBytes);
if (entry->FilesizeInBytes != 0x0 && (entry->attribute != 0x10)) {
readFile(DataRegion,entry, FAT[i], bpb);
}
}
free(FAT);
}
FILE fsysFatDirectory (const char* DirectoryName){
FILE file;
file fsysFatDirectory (const char* DirectoryName){
file file;
unsigned char* buf;
PDIRECTORY directory;
char DosFileName[11];
ToDosFileName(DirectoryName, DosFileName, 11);
//ToDosFileName(DirectoryName, DosFileName, 11);
DosFileName[11] =0;
for (int sector=0; sector <14 ; sector++){
ATA_DEVICE::Read(BUS_PORT::Primary, DEVICE_DRIVE::MASTER, mountInfo.rootOffset + sector, (uint16_t*)buf);
ATAPIO::Read(BUS_PORT::Primary, DEVICE_DRIVE::MASTER, mountInfo.rootOffset + sector, (uint16_t*)buf);
directory = (PDIRECTORY) buf;
for (int i =0; i < 16; i++){
@ -209,9 +258,9 @@ FILE fsysFatDirectory (const char* DirectoryName){
file.filelength = directory->FileSize;
if(directory->Attrib == 0x10){
file.flags = FS_DIRECTORY;
file.flags = 2;
} else {
file.flags = FS_FILE;
file.flags = 1;
}
return file;
}
@ -220,7 +269,7 @@ FILE fsysFatDirectory (const char* DirectoryName){
}
// Can't find file
file.flags = FS_INVALID;
file.flags = -1;
return file;
}
@ -300,9 +349,9 @@ FILE fsysFatOpenSubDir(FILE kFile, const char* filename){
// set file type;
if(pkDir->Attrib == 0x10){
file.flags = FS_DIRECTORY;
file.flags = 2;
} else{
file.flags = FS_FILE;
file.flags = 1;
}
return file;
@ -312,7 +361,7 @@ FILE fsysFatOpenSubDir(FILE kFile, const char* filename){
}
}
// unable to find file
file.flags = FS_INVALID;
file.flags = -1;
return file;
}
*/
*/

View File

@ -2,48 +2,152 @@
// Created by nigel on 21/02/23.
//
#pragma once
#include "ExtendBootRecord.h"
#include "BiosParameterBlock.h"
#include "DirectoryEntry.h"
#include "../../vfs/StorageTypes.h"
#include "../../vfs/vfs_types.h"
#include "../../vfs/vfs_types.h"
#include "../../partitiontables/mbr/MasterBootRecord.h"
// Date Format
// [0..4] Day
// [5..8] Month
// [9..15] Year
struct ExtendedBootRecord_FAT16{
uint8_t DrvNum;
uint8_t Reserved1;
uint8_t BootSig;
const uint32_t VolID;
uint8_t VolLab [11];
uint8_t FilSysType [8];
uint8_t bootCode [448];
uint16_t Signature_word;
uint8_t SecRmndr[512];
}__attribute__((packed));
// Time Format
// [0..4] Seconds
// [5..10] Minute
// [11..15] Hour
struct ExtendedBootRecord_FAT32{
uint32_t SectorsPerFAT;
uint16_t Flags;
const uint16_t FAT_VERSION_NUMBER;
uint32_t rootDirectory_clusterNumber;// Often set to 2;
uint16_t FSInfo_SectorNumber;
uint16_t backup_bpb_sectorNumber;
uint8_t Reserved [12];
uint8_t DriveNumber;
uint8_t Reserved2;
uint8_t Signature; // must be 0x28 or 0x29
uint32_t VOLUME_ID_SERIAL;
uint8_t volume_label[11];
uint8_t SystemIdentifierString [8]; // ALWAYS "FAT32 " but spec says do not trust
uint8_t BootCode [420]; // NICE
uint16_t PartitionSignature; // 0xAA55
}__attribute__((packed));
struct BiosParameterBlock {
uint8_t jmpBoot[3];
uint8_t OEMName [8];
uint16_t BytsPerSec ; // I suspect would be 512
uint8_t SecPerClus ;
uint16_t RsvdSecCnt;
uint8_t NumFATs; // Probably equals 2
uint16_t RootEntCnt; // Root directory must contain entire sectors
uint16_t TotSec16 ; // 0 means >65535 sectors in volume , actual count can be found in LargeSectorCount
uint8_t Media ; // Indication the media descriptor type
uint16_t FATSz16;// only in FAT12 / FAT 16
uint16_t SecPerTrk;
uint16_t NumHeads;
uint32_t HiddSec;
uint32_t TotSec32;
ExtendedBootRecord_FAT16 ebpb;
}__attribute__((packed));
struct DIR {
uint8_t Name [11];
uint8_t ATTR ;
uint8_t NTRes;
uint8_t CrtTimeTenth; // File Creation time component - count of tenths of a second (between 0 and 199)
uint16_t CrtTime; // Creation time. Granularity is 2 seconds
uint16_t CrtDate; // Creation date.
uint16_t LstAccDate; // Last Access Date (Last read or write date)
uint16_t FstClusHi; // High Word of first data cluster for file/directory described
uint16_t WrtTime; // Last Modification time | Must equal CrtTime
uint16_t WrtDate; // Last Modification date | Must equal CrtDate
uint16_t FstClusLO; // Low word of first data cluster for file/directory described
uint32_t FileSize; // size in bytes of file/directory described
}__attribute__((packed));
typedef struct _DIRECTORY{
uint8_t Filename[8];
uint8_t Ext[3];
uint8_t Attrib;
uint8_t Reserved;
uint8_t TimeCreatedMs;
uint16_t TimeCreated;
uint16_t DateCreated;
uint16_t DateLastAccessed;
uint16_t FirstClusterHiBytes;
uint16_t LastModTime;
uint16_t LastModDate;
uint16_t FirstCluster;
uint32_t FileSize;
}__attribute__((packed)) DIRECTORY, *PDIRECTORY;
enum struct FAT_TYPE{
FAT12,
FAT16,
FAT32,
VFAT,
UNKOWN
};
class FAT {
public:
// Wanted API for vfs
static file Open(char* filename);
static int close(file* file);
static int Read(file* file, void* buffer , int length);
static int Write(file* file, const void* buffer, int length);
static int create(inode* dir_node, inode** target, const char* component_name);
static int lookup(inode* , inode**, const char*);
static int compare(directoryEntry* , char* , char*);
static superblock* Mount(filesystem* fs, const char* name ,vfsmount* mount);
static bool Validate(PTR_PARTITION partition );
// TEMP
static void listFilesInRoot(MBR* mbr, BiosParameterBlock* bpb );
static BiosParameterBlock* getBPB( bool DEBUG =false );
static FAT_TYPE determineFATType(BiosParameterBlock* bpb);
static uint16_t GetFATEntry(BiosParameterBlock*, unsigned int);
static uint16_t DetermineFreeSpace();
static int GetSectorOfRootDirectory(BiosParameterBlock*);
static int RootDirSize(BiosParameterBlock*);
static FILE Open(char* filename);
static void Read(PFILE file, unsigned char* buffer , unsigned int length);
static void Write(PFILE file, unsigned char* buffer, unsigned int length);
static const int FREE = 0x0000;
static const int ALLOCATED = 0x0002;
static const int BAD = 0xFFF7;
static const int EOF = 0xFFFF;
static void Info(_PARTITION *pPartition, PFS pSystem);
static const int ClnShutBitMask = 0x8000;
static const int HrdErrBitMask = 0x4000;
static const char DOS_TRAILING_SPACE = 0x20;
static const char FREE_DIR = 0xE5; // If KANJI charset 0x05
static const char FREE_DIR_2 = 0x00; // All directories after this are free including this one
private:
enum struct TYPE{
FAT,
FAT16,
FAT32,
VFAT
};
enum ATTRIBUTES {
ATTR_READ_ONLY = 0x01,
ATT_HIDDEN = 0x02,
ATTR_HIDDEN = 0x02,
ATTR_SYSTEM = 0x04,
ATTR_VOLUME_ID = 0x08,
ATTR_DIRECTORY = 0x10,
ATTR_ARCHIVE = 0x20
ATTR_ARCHIVE = 0x20,
ATTR_LONG_NAME = (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID)
};
private:
enum ENTRY_SIZE {
FAT12 = 12,
FAT16 = 16,
FAT32 = 32
};
};

View File

@ -0,0 +1,40 @@
//
// Created by nigel on 23/02/23.
//
#pragma once
#include "../../../terminal/kterm.h"
// Date Format
// [0..4] Day
// [5..8] Month
// [9..15] Year
class MSDOSDATE {
static void ParseDate(unsigned int date){
printf("Date (hex) 0x%x\n", date);
unsigned int year = (date >> 9 )+ 1980;
unsigned int month = (date & 0xf0 ) >> 4;
unsigned int day = date & 0xf ;
printf("Date: (D,M,Y) %d, %d ,%d\n", day , month, year );
}
};
// Time Format
// [0..4] Seconds
// [5..10] Minute
// [11..15] Hour
class MSDOSTIME {
static void ParseTime(unsigned int time)
{
printf("Time (hex) 0x%x\n", time);
unsigned int seconds = ( time & 0x0f) * 2;
unsigned int minutes = (time & 0xf0);
unsigned int hours = (time & 0xf00);
printf("Time (H:M:S) %d:%d:%d\n", hours, minutes, seconds);
}
};