/*++

Copyright (c) 2000-2001  Microsoft Corporation

Module Name:

    fatsup.c

Abstract:

    This module implements FAT file system utility routines.

--*/

#include "fatx.h"

//
// A condensed table of legal fat character values
//
const ULONG FatxFatIllegalTable[] = {
    0xffffffff,
    0xfc009c04,
    0x10000000,
    0x10000000,
    0x00000000,
    0x00000000,
    0x00000000,
    0x00000000,
};

BOOLEAN
FatxIsValidFatFileName(
    IN POBJECT_STRING FileName
    )
/*++

Routine Description:

    This routine checks if the supplied file name is a legal FAT file name

Arguments:

    FileName - Specifies the buffer to check for validity.

Return Value:

    Returns TRUE if the string is valid, else FALSE.

--*/
{
    POSTR Buffer;
    POSTR EndingBuffer;
    OCHAR Char;

    //
    // If the file name is zero or too long, then the name is not valid.
    //

    if ((FileName->Length == 0) || (FileName->Length > FAT_FILE_NAME_LENGTH)) {
        return FALSE;
    }

    //
    // Perform some preliminary checks if the name begins with a period.
    //

    Buffer = FileName->Buffer;
    EndingBuffer = Buffer + FileName->Length / sizeof(OCHAR);

    if (*Buffer == '.') {

        //
        // If the name is "." or "..", then the name is not valid.
        //

        if ((FileName->Length == sizeof(OCHAR)) ||
            (FileName->Length == sizeof(OCHAR) * 2) && (*(Buffer + 1) == '.')) {
            return FALSE;
        }
    }

    //
    // Process the rest of the file name.
    //

    while (Buffer < EndingBuffer) {

        Char = *Buffer++;

        //
        // Check for illegal FAT characters.
        //

        if (FatxFatIllegalTable[Char >> 5] & (1 << (Char & 31))) {
            return FALSE;
        }
    }

    return TRUE;
}

LARGE_INTEGER
FatxFatTimestampToTime(
    IN PFAT_TIME_STAMP FatTimestamp
    )
/*++

Routine Description:

    This routine converts a FAT timestamp to a NT system time.

Arguments:

    FatTimestamp - Specifies the timestamp to convert to NT system time.

Return Value:

    Conversion to NT system time.

--*/
{
    LARGE_INTEGER SystemTime;
    TIME_FIELDS TimeField;

    TimeField.Year = (USHORT)(FatTimestamp->Year + 2000);
    TimeField.Month = FatTimestamp->Month;
    TimeField.Day = FatTimestamp->Day;
    TimeField.Hour = FatTimestamp->Hour;
    TimeField.Minute = FatTimestamp->Minute;
    TimeField.Second = (USHORT)(FatTimestamp->DoubleSeconds * 2);
    TimeField.Milliseconds = 0;

    if (!RtlTimeFieldsToTime(&TimeField, &SystemTime)) {
        SystemTime.QuadPart = 0;
    }

    return SystemTime;
}

LOGICAL
FatxTimeToFatTimestamp(
    IN PLARGE_INTEGER Time,
    OUT PFAT_TIME_STAMP FatTimestamp
    )
/*++

Routine Description:

    This routine converts a NT system time to a FAT timestamp.

Arguments:

    Time - Specifies the NT system time.

    FatTimestamp - Specifies the buffer to receive the FAT timestamp.

Return Value:

    Returns TRUE if the time could be converted to a valid FAT time, else FALSE.

--*/
{

    LARGE_INTEGER LocalTime;
    TIME_FIELDS TimeField;

    //
    // Round the time up to the nearest double second.
    //

    LocalTime.QuadPart = Time->QuadPart + (2 * 1000 * 1000 * 10 - 1);

    RtlTimeToTimeFields(&LocalTime, &TimeField);

    FatTimestamp->Year = (USHORT)(TimeField.Year - 2000);
    FatTimestamp->Month = TimeField.Month;
    FatTimestamp->Day = TimeField.Day;
    FatTimestamp->Hour = TimeField.Hour;
    FatTimestamp->Minute = TimeField.Minute;
    FatTimestamp->DoubleSeconds = (USHORT)(TimeField.Second >> 1);

    return (TimeField.Year >= 2000) && (TimeField.Year <= 2000 + 127);
}

LARGE_INTEGER
FatxRoundToFatTime(
    IN PLARGE_INTEGER Time
    )
/*++

Routine Description:

    This routine rounds a NT system time to FAT granularity (two seconds).

Arguments:

    Time - Specifies the NT system time.

Return Value:

    Rounded NT system time.

--*/
{
    FAT_TIME_STAMP FatTimestamp;

    //
    // Convert the time to a FAT timestamp and back.
    //

    if ((Time->QuadPart != 0) && FatxTimeToFatTimestamp(Time, &FatTimestamp)) {
        return FatxFatTimestampToTime(&FatTimestamp);
    } else {
        return *Time;
    }
}
