#include <_stdio.h> #include <alloc.h> #include <fileSystem.h> #include <util.h> FileSystemFolder rootFolder = { .name = "/", .type = FS_FOLDER, .children = NULL}; void printFolderTree(FileSystemFolder *folder, char *prefix) { char *nextPrefix = stringCombine(prefix, " "); for (ListElement *current = *folder->children; current; current = current->next) { FileSystemTreeNode *child = current->data; printf("%s%s\n", prefix, child->name); if (child->type == FS_FOLDER) { if (child->name[0] == '.') { continue; } printFolderTree(current->data, nextPrefix); } } free(nextPrefix); } void printFileSystemTree() { printFolderTree(&rootFolder, ""); } void setupFatInfo(FatInfo *info, FatBootSector *boot, HardDrive *hardDrive) { info->bootSector = boot; info->rootDirectorySize = (boot->rootEntryCount * 32 + boot->sectorSize - 1) / boot->sectorSize; info->fatSize = boot->fatSize16Bit ? boot->fatSize16Bit : 0; info->totalSectorCount = boot->totalSectorCount16Bit ? boot->totalSectorCount16Bit : boot->totalSectorCount32Bit; uint32_t dataSectorCount = info->totalSectorCount - (boot->reservedSectorCount + (boot->FATCount * info->fatSize) + info->rootDirectorySize); uint32_t clusterCount = dataSectorCount / boot->sectorsPerCluster; if (clusterCount < 4085) { info->version = 12; } else if (clusterCount < 65525) { info->version = 16; } else { info->version = 32; } info->firstDataSector = boot->reservedSectorCount + (boot->FATCount * info->fatSize) + info->rootDirectorySize; info->firstFatSector = boot->reservedSectorCount; info->firstRootSector = info->firstDataSector - info->rootDirectorySize; info->fat = malloc(info->fatSize * boot->sectorSize); info->hardDrive = hardDrive; hardDrive->access(hardDrive, info->firstFatSector, info->fat, info->fatSize, 0); info->knownFolders = malloc(info->fatSize * info->bootSector->sectorSize / sizeof(void *) * info->version / 8); info->clusterSize = info->bootSector->sectorSize * info->bootSector->sectorsPerCluster; } uint32_t getNextCluster(FatInfo *info, uint32_t cluster) { switch (info->version) { case 16: return ((uint16_t *)info->fat)[cluster]; } return 00; } bool isClusterEnd(FatInfo *info, uint32_t cluster) { switch (info->version) { case 16: return cluster > 0xFF00; } return true; } char *getFullString(LongNameEntry *name) { char *string = malloc(14); string[14] = 0; for (uint8_t i = 0; i < 5; i++) { string[i] = name->name1[i * 2]; } for (uint8_t i = 0; i < 6; i++) { string[5 + i] = name->name2[i * 2]; } for (uint8_t i = 0; i < 2; i++) { string[11 + i] = name->name3[i * 2]; } return string; } char *getCombinedName(ListElement **longName) { char *current = "", *new; while (*longName != NULL) { new = stringCombine(popBeginning(longName), current); if (strlen(current)) { free(current); } current = new; } return current; } char *getName(ListElement **longName, FatDirectoryEntry *directory) { if (listCount(*longName)) { return getCombinedName(longName); } char *name = malloc(12); // 8:3 short name name[11] = 0; for (uint8_t i = 0; i < 11; i++) { name[i] = directory->name[i]; } return name; } uint32_t getClusterSector(FatInfo *info, uint32_t cluster) { return info->firstDataSector + ((cluster - 2) * info->bootSector->sectorsPerCluster); } void scanFolder(FatInfo *info, void *data, FileSystemFolder *parent); uint16_t getClusterChainLength(FatInfo *info, uint32_t firstCluster) { uint16_t i = 0; uint32_t currentCluster = firstCluster; while (!isClusterEnd(info, currentCluster)) { currentCluster = getNextCluster(info, currentCluster); i++; } return i; } void *readClusterChain(FatInfo *info, uint32_t firstCluster) { uint16_t length = getClusterChainLength(info, firstCluster); void *data = malloc(length * info->clusterSize + 1); ((uint8_t *)data)[length * info->clusterSize] = 0; uint32_t currentCluster = firstCluster; for (uint16_t i = 0; i < length; i++) { info->hardDrive->access(info->hardDrive, getClusterSector(info, currentCluster), data + i * info->clusterSize, info->bootSector->sectorsPerCluster, 0); } return data; } void setupFolder(char *name, FatDirectoryEntry *directory, FatInfo *info, FileSystemFolder *parent) { FileSystemFolder *folder = malloc(sizeof(FileSystemFolder)); folder->name = name; folder->type = FS_FOLDER; uint32_t cluster = directory->firstDataClusterLower | directory->fistDataClusterUpper << 16; folder->cluster = cluster; listAdd(parent->children, folder); if (info->knownFolders[cluster]) { folder->children = info->knownFolders[cluster]; return; } if (cluster == 0) { folder->children = rootFolder.children; return; } folder->children = malloc(sizeof(ListElement **)); info->knownFolders[cluster] = folder->children; *folder->children = NULL; void *data = readClusterChain(info, cluster); scanFolder(info, data, folder); free(data); } void setupFile(char *name, FatDirectoryEntry *directory, FileSystemFolder *parent) { FileSystemFile *file = malloc(sizeof(FileSystemFile)); uint32_t cluster = directory->firstDataClusterLower | directory->fistDataClusterUpper << 16; file->cluster = cluster; file->name = name; file->type = FS_FILE; file->subType = 0; file->size = directory->size; listAdd(parent->children, file); } void setupChild(char *name, FatDirectoryEntry *directoryEntry, FatInfo *info, FileSystemFolder *parent) { if (directoryEntry->attributes & FAT_ATTRIBUTE_VOLUME_ID) { info->volumeID = name; return; } if (directoryEntry->attributes & FAT_ATTRIBUTE_DIRECTORY) { setupFolder(name, directoryEntry, info, parent); } else { setupFile(name, directoryEntry, parent); } } void scanFolder(FatInfo *info, void *data, FileSystemFolder *parent) { FatDirectoryEntry *directory = data; ListElement *longName = NULL; uint32_t i; for (i = 0; i < info->bootSector->sectorSize * info->bootSector->sectorsPerCluster / sizeof(FatDirectoryEntry); i++) { if (directory[i].name[0] == 0) { break; } if (directory[i].name[0] == (char)0xE5 || directory[i].name[0] == (char)0xFF) { continue; } if (directory[i].attributes == FAT_ATTRIBUTE_LONG_NAME) { listAdd(&longName, getFullString((void *)&(directory[i]))); continue; } setupChild(getName(&longName, &directory[i]), &directory[i], info, parent); } listClear(&longName, true); } FatInfo *info; void mountDisk(HardDrive *drive) { void *bootSector = malloc(512); drive->access(drive, 0, bootSector, 1, 0); FatBootSector *boot = bootSector; info = malloc(sizeof(FatInfo)); setupFatInfo(info, boot, drive); rootFolder.children = malloc(sizeof(ListElement *)); void *data = malloc(info->clusterSize * info->rootDirectorySize); info->hardDrive->access(info->hardDrive, info->firstRootSector, data, info->rootDirectorySize, 0); scanFolder(info, data, &rootFolder); free(data); } File *readFile(char *path) { if (path[0] != '/') { printf("relative file paths not implemented yet!\n"); return NULL; } char *currentName = path + 1; FileSystemFolder *currentFolder = &rootFolder; while (strlen(currentName)) { foreach (*currentFolder->children) { FileSystemTreeNode *node = current->data; uint16_t i; for (i = 0; currentName[i] != '/' && currentName[i] != 0; i++) { if (node->name[i] != currentName[i]) { i = 0; break; } } if (i != strlen(node->name) || i == 0) { continue; } if (currentName + i == path + strlen(path)) { File *file = malloc(sizeof(File)); file->file = (void *)node; file->absolutePath = path; file->path = path; file->data = readClusterChain(info, file->file->cluster); return file; } currentFolder = (void *)node; currentName += strlen(node->name) + 1; } } return NULL; }