huge work on FAT32, initial support for writing

This commit is contained in:
2021-02-14 21:35:47 +01:00
parent 6aa951190e
commit da12992ae8
14 changed files with 609 additions and 91 deletions

View File

@@ -1,11 +1,58 @@
#pragma once
#include <string.h>
#include <string>
#include "Types.h"
namespace FAT32 {
using ClusterNr = uint32_t;
static inline uint16_t getU8(const uint8_t* src) {return src[0];}
static inline uint16_t getU16(const uint8_t* src) {return src[0]<<0 | src[1]<<8;}
static inline uint32_t getU32(const uint8_t* src) {return src[0]<<0 | src[1]<<8 | src[2]<<16 | src[3]<<24;}
static inline size_t min(size_t a, size_t b) {return (a<b) ? a : b;}
struct ClusterNr {
uint32_t val;
ClusterNr() : val(0) {}
ClusterNr(uint32_t val) : val(val) {}
void operator = (const uint32_t val) {this->val = val;}
operator uint32_t() const {return val;}
inline bool isEndOfClusters() const {
return (val & 0x0FFFFFFF) >= 0xFFFFFF8; // only the lower 28 bits are used
}
inline bool isFree() const {
return val == 0;
}
void operator ++() {++val;}
};
const ClusterNr END_OF_CLUSTERS = 0xFFFFFFF;
/** header within the first 512 bytes */
struct FSHeader { // https://www.easeus.com/resource/fat32-disk-structure.htm
uint8_t dummy1[11];
uint16_t bytesPerSector; // @0x0B;
uint8_t sectorsPerCluster; // @0x0D;
uint16_t numReservedSectors; // @0x0E;
uint8_t numberOfFATs; // @0x10;
uint8_t dummy2[4];
uint8_t mediaDescriptor; // @0x15;
uint8_t dummy3[10];
uint32_t sectorsInPartition; // @0x20;
uint32_t sectorsPerFAT; // @0x24;
uint8_t dummy4[4];
uint32_t rootDirFirstCluster; // @0x2C
} __attribute__((packed));
struct FSDesc {
uint16_t bytesPerSector;
@@ -38,8 +85,8 @@ namespace FAT32 {
} bits;
} __attribute__((packed));
/** structure for a DirectoryEntry as defined in the FAT standard */
struct DirEntry {
unsigned char name[8];
unsigned char ext[3];
Attributes attr;
@@ -48,28 +95,69 @@ namespace FAT32 {
uint8_t dummy2[4];
uint16_t firstClusterLo;
uint32_t size; // file size in bytes
} __attribute__((packed));
bool isUnused() const {return name[0] == 0xE5;}
bool isDirectory() const {return attr.bits.directory;}
bool isEndOfDirectory() const {return name[0] == 0x00;}
bool isLongFileName() const {return (attr.raw & 0b1111) == 0b1111;}
/** combine a DirectoryEntry with its absolute location on disk */
struct DirEntryAt {
uint32_t getFirstCluster() const {return firstClusterHi<<16 | firstClusterLo<<0;}
AbsPos posOnDisk;
DirEntry entry;
bool valid;
/** ctor for an invalid entry */
DirEntryAt() : valid(false) {}
/** ctor for a valid entry */
DirEntryAt(AbsPos posOnDisk, DirEntry* entry) : posOnDisk(posOnDisk), entry(*entry), valid(true) {}
static DirEntryAt invalid() {return DirEntryAt();}
/** is this a valid entry? */
bool isValid() const {return valid;}
uint32_t getSize() const {return entry.size;}
void setSize(uint32_t size) {entry.size = size;}
bool isUnused() const {return entry.name[0] == 0xE5;}
bool isDirectory() const {return entry.attr.bits.directory;}
bool isEndOfDirectory() const {return entry.name[0] == 0x00;}
bool isLongFileName() const {return (entry.attr.raw & 0b1111) == 0b1111;}
void setEndOfDirectory() {entry.name[0] = 0x00;}
ClusterNr getFirstCluster() const {return entry.firstClusterHi<<16 | entry.firstClusterLo<<0;}
void setFirstCluster(ClusterNr nr) {entry.firstClusterHi = (uint16_t)(nr << 16); entry.firstClusterLo = (uint16_t)(nr << 0);}
std::string getName() const {
char buf[16];
uint8_t pos = 0;
for (uint8_t i = 0; i < 8; ++i) {if (name[i] != ' ') {buf[pos++] = name[i];}}
for (uint8_t i = 0; i < 8; ++i) {if (entry.name[i] != ' ') {buf[pos++] = entry.name[i];}}
buf[pos++] = '.';
for (uint8_t i = 0; i < 3; ++i) {if ( ext[i] != ' ') {buf[pos++] = ext[i];}}
for (uint8_t i = 0; i < 3; ++i) {if ( entry.ext[i] != ' ') {buf[pos++] = entry.ext[i];}}
buf[pos] = 0;
return std::string(buf);
}
} __attribute__((packed));
void setName(const std::string& str) {
// "zero" fill name and extension
memset(entry.name, ' ', 8);
memset(entry.ext, ' ', 3);
auto pos = str.find('.');
for (size_t i = 0; i < min(pos, str.length()); ++i) {
if (i >= 8) {break;}
entry.name[i] = str[i];
}
for (size_t i = 0; i < min(pos, str.length()); ++i) {
if (i >= 3) {break;}
entry.ext[i] = str[i+pos+1];
}
}
};
static inline uint16_t getU8(const uint8_t* src) {return src[0];}
static inline uint16_t getU16(const uint8_t* src) {return src[0]<<0 | src[1]<<8;}
static inline uint32_t getU32(const uint8_t* src) {return src[0]<<0 | src[1]<<8 | src[2]<<16 | src[3]<<24;}
}