Newer
Older
tree-os / src / kernel / memory / fileSystem.c
#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);
    printf("size: %i\n", info->fatSize * info->bootSector->sectorSize *
                             sizeof(void *) / info->version / 8);
    info->knownFolders = malloc(info->fatSize * info->bootSector->sectorSize /
                                sizeof(void *) * info->version / 8);
}

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 == 0xFFFF;
    }
    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 folderScanCluster(FatInfo *info, uint32_t cluster,
                       FileSystemFolder *parent);

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;
    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;
    folderScanCluster(info, getClusterSector(info, cluster), folder);
    while (!isClusterEnd(info, cluster)) {
        cluster = getNextCluster(info, cluster);
        if (cluster > 0xFF00) {
            return;
        }
        folderScanCluster(info, getClusterSector(info, cluster), folder);
    }
}

void setupFile(char *name, FileSystemFolder *parent) {
    FileSystemFile *file = malloc(sizeof(FileSystemFile));
    file->name = name;
    file->type = FS_FILE;
    file->subType = 0;
    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, parent);
    }
}

void folderScanCluster(FatInfo *info, uint32_t sector,
                       FileSystemFolder *parent) {
    void *clusterData = malloc(info->bootSector->sectorSize *
                               info->bootSector->sectorsPerCluster);
    info->hardDrive->access(info->hardDrive, sector, clusterData,
                            info->bootSector->sectorsPerCluster, 0);
    FatDirectoryEntry *directory = clusterData;
    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);
    free(clusterData);
}

void mountDisk(HardDrive *drive) {
    void *bootSector = malloc(512);
    drive->access(drive, 0, bootSector, 1, 0);
    FatBootSector *boot = bootSector;
    FatInfo *info = malloc(sizeof(FatInfo));
    setupFatInfo(info, boot, drive);
    printf("type: FAT%i\n", info->version);
    rootFolder.children = malloc(sizeof(ListElement *));
    folderScanCluster(info, info->firstRootSector, &rootFolder);
}