/*
 * fat.h
 *
 * Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _FAT_H_
#define _FAT_H_

#include <filesystem.h>
#include <clock.h>

#define FATFS_ATTR_READONLY  0x01
#define FATFS_ATTR_HIDDEN    0x02
#define FATFS_ATTR_SYSTEM    0x04
#define FATFS_ATTR_VOLUME_ID 0x08
#define FATFS_ATTR_DIRECTORY 0x10
#define FATFS_ATTR_ARCHIVE   0x20

#define FATFS_FREE_CLUSTER    0x00000000
#define FATFS_INVALID_CLUSTER 0xFFFFFFF0
#define FATFS_BAD_CLUSTER     0xFFFFFFF7
#define FATFS_END_CLUSTER     0xFFFFFFF8
#define FATFS_LAST_CLUSTER    0xFFFFFFFF

#define FATFS_DELETED '\xE5'

typedef enum
{
    FAT12,
    FAT16,
    FAT32
} fat_version_t;

typedef struct
{
    mounted_volume_t header;
    fat_version_t type;
    word_t bytes_per_sector;
    byte_t sectors_per_cluster;
    word_t reserved_sectors;
    dword_t root_dir_cluster;
    word_t num_root_dirents;
    byte_t num_fats;
    dword_t sectors_per_fat;
    dword_t total_clusters;
    dword_t last_free_cluster;
    dword_t owner_uid;
} fatfs_volume_t;

typedef struct
{
    file_t header;
    cache_descriptor_t cache;
    dword_t first_cluster;
    dword_t dirent_cluster;
    dword_t dirent_index;
} fatfs_file_t;

typedef struct
{
    file_instance_t header;
    dword_t last_offset;
    dword_t last_cluster;
} fatfs_file_instance_t;

#pragma pack(push, 1)

typedef struct
{
    byte_t drive_num;
    byte_t reserved;
    byte_t signature;
    dword_t volume_id;
    byte_t volume_label[11];
    byte_t identifier[8];
} fatfs_ext_bpb_t;

typedef struct
{
    dword_t sectors_per_fat;
    word_t flags, version;
    dword_t root_dir_cluster;
    word_t fsinfo_cluster;
    word_t backup_bs;
    byte_t reserved[12];
    byte_t drive_num;
    byte_t ntflags;
    byte_t signature;
    dword_t volume_id;
    byte_t volume_label[11];
    byte_t identifier[8];
} fatfs_ext_bpb_32_t;

typedef struct
{
    byte_t jump[3];
    byte_t oem_string[8];
    word_t bytes_per_sector;
    byte_t sectors_per_cluster;
    word_t reserved_sectors;
    byte_t num_fats;
    word_t num_dirent;
    word_t total_sectors;
    byte_t mdb;
    word_t sectors_per_fat;
    word_t sectors_per_track;
    word_t heads;
    dword_t hidden_sector_count;
    dword_t total_sectors_32;
    union
    {
        fatfs_ext_bpb_t ext_bpb;
        fatfs_ext_bpb_32_t ext_bpb_32;
    };
} fatfs_bpb_t;

typedef struct
{
    byte_t filename[8];
    byte_t extension[3];
    byte_t attributes;
    byte_t reserved;
    byte_t duration;
    word_t creation_time, creation_date;
    word_t last_accessed_date;
    word_t first_cluster_high;
    word_t modification_time, modification_date;
    word_t first_cluster_low;
    dword_t size;
} fatfs_dirent_t;

#pragma pack(pop)

dword_t fatfs_driver_load(void);

#endif
