xaizek / tos (License: GPLv3 only) (since 2018-12-07)
This is an alternative version of sources presented as part of Write Your Own OS video tutorial by Viktor Engelmann.
<root> / src / fs / fat.cpp (28562263136e6a86e5aa9e0177c1b86932de5977) (2,601B) (mode 100644) [raw]
#include "fs/fat.hpp"

#include "drv/ATA.hpp"
#include "print.hpp"

using namespace fs;

FAT::FAT(drv::ATA &hd, std::uint32_t partitionOffset) : hd(hd)
{
    std::uint8_t bpbData[512];
    hd.read28(partitionOffset, bpbData);

    BiosParameterBlock32 bpb(bpbData);

    fatStart = partitionOffset + bpb.reservedSectors;
    dataStart = fatStart + bpb.tableSize*bpb.fatCopies;
    rootStart = dataStart + bpb.sectorsPerCluster*(bpb.rootCluster - 2);
    sectorsPerCluster = bpb.sectorsPerCluster;

    kprint("sectors per cluster: ", sectorsPerCluster, "\n");
}

void
FAT::printFiles()
{
    std::uint8_t dirData[512];
    hd.read28(rootStart, dirData);

    std::uint8_t *dataPtr = dirData;
    Fields<DirectoryEntryFat32, 16> dirent(dataPtr);

    for (int i = 0; i < 16; ++i) {
        DirectoryEntryFat32 &ent = dirent[i];

        if (ent.name[0] == 0x00) {
            break;
        }

        if ((ent.attributes & 0x0f) == 0x0f) {
            continue;
        }

        char foo[] = "        \n";
        for (int j = 0; j < 8; ++j) {
            foo[j] = ent.name[j];
        }
        kprint(foo);

        // Skip directories.
        if (!(ent.attributes & 0x10)) {
            printFileContents(ent);
        }
    }
}

void
FAT::printFileContents(const DirectoryEntryFat32 &ent) const
{
    std::uint32_t firstCluster = ent.firstClusterHi;
    firstCluster = (firstCluster << 16) | ent.firstClusterLow;

    std::int32_t size = ent.size;
    std::int32_t currentCluster = firstCluster;
    std::uint8_t buffer[513];

    while (size > 0) {
        std::uint32_t sector = dataStart
                             + sectorsPerCluster*(currentCluster - 2);
        std::uint32_t sectorOffset = 0;

        while (size > 0) {
            hd.read28(sector + sectorOffset, { buffer, 512 });

            buffer[size > 512 ? 512 : size] = '\0';
            kprint(reinterpret_cast<const char *>(buffer));

            size -= 512;

            if (++sectorOffset == sectorsPerCluster) {
                break;
            }
        }

        if (size <= 0) {
            break;
        }

        std::uint8_t fat[512];
        std::uint32_t fatSector = currentCluster/(512/sizeof(std::uint32_t));
        hd.read28(fatStart + fatSector, fat);
        std::uint32_t fatOffset = currentCluster%(512/sizeof(std::uint32_t))*4;

        currentCluster = fat[fatOffset + 3] & 0x0f;
        currentCluster = (currentCluster << 8) | fat[fatOffset + 2];
        currentCluster = (currentCluster << 8) | fat[fatOffset + 1];
        currentCluster = (currentCluster << 8) | fat[fatOffset + 0];
    }
}
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/tos

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/tos

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master