Repository: SerenityOS/serenity
File: Kernel/FileSystem/FATFS/Inode.cpp (C++)

Code before:

    FATEntry entry {};

    bool valid_sfn = SFNUtils::is_valid_sfn(name);

    if (valid_sfn) {
        TRY(encode_known_good_sfn_for(entry, name));
    } else {
        auto sfn = TRY(SFNUtils::create_sfn_from_lfn(name));
        auto existing_sfns = TRY(collect_sfns());
        TRY(create_unique_sfn_for(entry, move(sfn), move(existing_sfns)));
    }

    // TODO: We should set the hidden attribute if the file starts with a dot or read only (the same way Linux does this).
    if (mode & S_IFDIR)
        entry.attributes |= FATAttributes::Directory;

    // FIXME: Set the dates

    Vector<FATLongFileNameEntry> lfn_entries = {};
    if (!valid_sfn)
        lfn_entries = TRY(create_lfn_entries(name, lfn_entry_checksum(entry)));

    MutexLocker locker(m_inode_lock);

    auto entries = TRY(allocate_entries(lfn_entries.size() + 1));

    if (mode & S_IFDIR) {
        u32 allocated_cluster = TRY(fs().allocate_cluster());
        if (fs().m_fat_version == FATVersion::FAT32)
            entry.first_cluster_high = allocated_cluster >> 16;

        entry.first_cluster_low = allocated_cluster & 0xFFFF;

        // This is used for generating a directory's "." and ".." entries.
        auto create_directory_entry = [&](StringView entry_name) {
            VERIFY(entry_name.length() <= 8);
            FATEntry directory_entry {};
            memset(directory_entry.filename, ' ', 8);
            memset(directory_entry.extension, ' ', 3);
            for (size_t i = 0; i < entry_name.length(); ++i)
                directory_entry.filename[i] = entry_name[i];
            directory_entry.attributes |= FATAttributes::Directory;
            return directory_entry;
        };

        FATEntry current_directory = create_directory_entry("."sv);

        current_directory.first_cluster_low = entry.first_cluster_low;
        if (fs().m_fat_version == FATVersion::FAT32)
            current_directory.first_cluster_high = entry.first_cluster_high;

Review comment (suggestion):
Linux returns `EPERM` here: "also returned if the file system containing pathname does not support the type of node requested." (https://linux.die.net/man/2/mknod)
Not sure if we should follow that and if other OSes also use that errno.

Code after:
{
    auto packed_date = TRY(to_packed_dos_date(timestamp));
    auto packed_time = TRY(to_packed_dos_time(timestamp));

    entry.creation_date = move(packed_date);
    entry.creation_time = move(packed_time);

    // NOTE: The "creation_time_seconds" field not only compensates for the fact that seconds are counted in intervals of two,
    // it also adds in rudimentary support for millisecond precision, though this is limited to only two digits.
    auto day_start_precision = days_since_epoch(entry.creation_date.year + AK::first_dos_year, entry.creation_date.month, entry.creation_date.day) * 86'400;
    auto day_precision = entry.creation_time.hour * 60 * 60 + entry.creation_time.minute * 60 + entry.creation_time.second * 2;
    entry.creation_time_seconds = (timestamp.truncated_milliseconds_since_epoch() - day_start_precision * 1000 - day_precision * 1000) / 10;
    VERIFY(entry.creation_time_seconds < 200);

    return {};
}

ErrorOr<NonnullRefPtr<Inode>> FATInode::create_child(StringView name, mode_t mode, dev_t, UserID, GroupID)
{
    MutexLocker locker(m_inode_lock);
    VERIFY(has_flag(m_entry.attributes, FATAttributes::Directory));

    dbgln_if(FAT_DEBUG, "FATInode[{}]::create_child(): creating inode \"{}\"", identifier(), name);

    if (!Kernel::is_directory(mode) && !Kernel::is_regular_file(mode))
        return ENOTSUP;

    FATEntry entry {};

    bool valid_sfn = SFNUtils::is_valid_sfn(name);

    if (valid_sfn) {
        TRY(encode_known_good_sfn_for(entry, name));
    } else {
        auto sfn = TRY(SFNUtils::create_sfn_from_lfn(name));
        auto existing_sfns = TRY(collect_sfns());
        TRY(create_unique_sfn_for(entry, move(sfn), move(existing_sfns)));
    }

    // TODO: We should set the hidden attribute if the file starts with a dot or read only (the same way Linux does this).
    if (mode & S_IFDIR)
        entry.attributes |= FATAttributes::Directory;

    auto now = kgettimeofday();
    if (auto error_or_void = fill_in_creation_time(entry, now); !error_or_void.is_error()) {
        entry.modification_date = entry.creation_date;
        entry.modification_time = entry.creation_time;
        entry.last_accessed_date = entry.creation_date;
    }

    Vector<FATLongFileNameEntry> lfn_entries = {};