/* * Copyright (c) 2008 Jakub Jermar * Copyright (c) 2011 Oleg Romanenko * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @addtogroup exfat * @{ */ #ifndef EXFAT_EXFAT_H_ #define EXFAT_EXFAT_H_ #include "exfat_fat.h" #include #include #include #include #include "../../vfs/vfs.h" #ifndef dprintf #define dprintf(...) printf(__VA_ARGS__) #endif #define BS_BLOCK 0 #define BS_SIZE 512 #define BPS(bs) ((uint32_t) (1 << (bs->bytes_per_sector))) #define SPC(bs) ((uint32_t) (1 << (bs->sec_per_cluster))) #define BPC(bs) ((uint32_t) (BPS(bs) * SPC(bs))) #define VOL_FS(bs) uint64_t_le2host(bs->volume_start) #define VOL_CNT(bs) uint64_t_le2host(bs->volume_count) #define FAT_FS(bs) uint32_t_le2host(bs->fat_sector_start) #define FAT_CNT(bs) uint32_t_le2host(bs->fat_sector_count) #define DATA_FS(bs) uint32_t_le2host(bs->data_start_sector) #define DATA_CNT(bs) uint32_t_le2host(bs->data_clusters) #define ROOT_FC(bs) uint32_t_le2host(bs->rootdir_cluster) #define VOL_FLAGS(bs) uint16_t_le2host(bs->volume_flags) #define EXFAT_NODE(node) ((node) ? (exfat_node_t *) (node)->data : NULL) #define FS_NODE(node) ((node) ? (node)->bp : NULL) #define DPS(bs) (BPS((bs)) / sizeof(exfat_dentry_t)) typedef struct exfat_bs { uint8_t jump[3]; /* 0x00 jmp and nop instructions */ uint8_t oem_name[8]; /* 0x03 "EXFAT " */ uint8_t __reserved[53]; /* 0x0B always 0 */ uint64_t volume_start; /* 0x40 partition first sector */ uint64_t volume_count; /* 0x48 partition sectors count */ uint32_t fat_sector_start; /* 0x50 FAT first sector */ uint32_t fat_sector_count; /* 0x54 FAT sectors count */ uint32_t data_start_sector; /* 0x58 Data region first cluster sector */ uint32_t data_clusters; /* 0x5C total clusters count */ uint32_t rootdir_cluster; /* 0x60 first cluster of the root dir */ uint32_t volume_serial; /* 0x64 volume serial number */ struct { /* 0x68 FS version */ uint8_t minor; uint8_t major; } __attribute__((packed)) version; uint16_t volume_flags; /* 0x6A volume state flags */ uint8_t bytes_per_sector; /* 0x6C sector size as (1 << n) */ uint8_t sec_per_cluster; /* 0x6D sectors per cluster as (1 << n) */ uint8_t fat_count; /* 0x6E always 1 */ uint8_t drive_no; /* 0x6F always 0x80 */ uint8_t allocated_percent; /* 0x70 percentage of allocated space */ uint8_t _reserved2[7]; /* 0x71 reserved */ uint8_t bootcode[390]; /* Boot code */ uint16_t signature; /* the value of 0xAA55 */ } __attribute__((__packed__)) exfat_bs_t; typedef enum { EXFAT_UNKNOW, EXFAT_DIRECTORY, EXFAT_FILE, EXFAT_BITMAP, EXFAT_UCTABLE } exfat_node_type_t; struct exfat_node; struct exfat_idx_t; typedef struct { /** Used indices (position) hash table link. */ ht_link_t uph_link; /** Used indices (index) hash table link. */ ht_link_t uih_link; fibril_mutex_t lock; service_id_t service_id; fs_index_t index; /* Does parent node fragmented or not? */ bool parent_fragmented; /** * Parent node's first cluster. * Zero is used if this node is not linked, in which case nodep must * contain a pointer to the in-core node structure. * One is used when the parent is the root directory. */ exfat_cluster_t pfc; /** Directory entry index within the parent node. */ unsigned pdi; /** Pointer to in-core node instance. */ struct exfat_node *nodep; } exfat_idx_t; /** exFAT in-core node. */ typedef struct exfat_node { /** Back pointer to the FS node. */ fs_node_t *bp; fibril_mutex_t lock; exfat_node_type_t type; exfat_idx_t *idx; /** * Node's first cluster. * Zero is used for zero-length nodes. * One is used to mark root directory. */ exfat_cluster_t firstc; /** exFAT in-core node free list link. */ link_t ffn_link; aoff64_t size; unsigned lnkcnt; unsigned refcnt; bool dirty; /* Should we do walk-on-FAT or not */ bool fragmented; /* * Cache of the node's last and "current" cluster to avoid some * unnecessary FAT walks. */ /* Node's last cluster in FAT. */ bool lastc_cached_valid; exfat_cluster_t lastc_cached_value; /* Node's "current" cluster, i.e. where the last I/O took place. */ bool currc_cached_valid; aoff64_t currc_cached_bn; exfat_cluster_t currc_cached_value; } exfat_node_t; extern vfs_out_ops_t exfat_ops; extern libfs_ops_t exfat_libfs_ops; extern errno_t exfat_idx_get_new(exfat_idx_t **, service_id_t); extern exfat_idx_t *exfat_idx_get_by_pos(service_id_t, exfat_cluster_t, unsigned); extern exfat_idx_t *exfat_idx_get_by_index(service_id_t, fs_index_t); extern void exfat_idx_destroy(exfat_idx_t *); extern void exfat_idx_hashin(exfat_idx_t *); extern void exfat_idx_hashout(exfat_idx_t *); extern errno_t exfat_idx_init(void); extern void exfat_idx_fini(void); extern errno_t exfat_idx_init_by_service_id(service_id_t); extern void exfat_idx_fini_by_service_id(service_id_t); extern errno_t exfat_node_expand(service_id_t, exfat_node_t *, exfat_cluster_t); extern errno_t exfat_node_put(fs_node_t *); extern errno_t exfat_bitmap_get(fs_node_t **, service_id_t); extern errno_t exfat_uctable_get(fs_node_t **, service_id_t); #endif /** * @} */