diff options
Diffstat (limited to 'firmware/export/fat.h')
-rw-r--r-- | firmware/export/fat.h | 225 |
1 files changed, 135 insertions, 90 deletions
diff --git a/firmware/export/fat.h b/firmware/export/fat.h index a0d52acc35..3aa1e254dc 100644 --- a/firmware/export/fat.h +++ b/firmware/export/fat.h @@ -18,123 +18,168 @@ * KIND, either express or implied. * ****************************************************************************/ - #ifndef FAT_H #define FAT_H #include <stdbool.h> -#include "mv.h" /* for volume definitions */ +#include <sys/types.h> +#include <time.h> #include "config.h" #include "system.h" +#include "mv.h" /* for volume definitions */ + +/******** + **** DO NOT use these functions directly unless otherwise noted. Required + **** synchronization is done by higher-level interfaces to minimize locking + **** overhead. + **** + **** Volume, drive, string, etc. parameters should also be checked by + **** callers for gross violations-- NULL strings, out-of-bounds values, + **** etc. + ****/ + +/**************************************************************************** + ** Values that can be overridden by a target in config-[target].h + **/ + +/* if your ATA implementation can do better, go right ahead and increase this + * value */ +#ifndef FAT_MAX_TRANSFER_SIZE +#define FAT_MAX_TRANSFER_SIZE 256 +#endif -/* This value can be overwritten by a target in config-[target].h, but - that behaviour is still experimental */ +/* still experimental? */ +/* increasing this will increase the total memory used by the cache; the + cache, as noted in disk_cache.h, has other minimum requirements that may + prevent reducing its number of entries in order to compensate */ #ifndef SECTOR_SIZE #define SECTOR_SIZE 512 #endif +/** + ****************************************************************************/ + +#define INVALID_SECNUM (0xfffffffeul) /* sequential, not FAT */ +#define FAT_MAX_FILE_SIZE (0xfffffffful) /* 2^32-1 bytes */ +#define MAX_DIRENTRIES 65536 +#define MAX_DIRECTORY_SIZE (MAX_DIRENTRIES*32) /* 2MB max size */ + +/* these aren't I/O error conditions, so define specially; failure rc's + * shouldn't return the last digit as "0", therefore this is unambiguous */ +#define FAT_RC_ENOSPC (-10) +#define FAT_SEEK_EOF (-20) + /* Number of bytes reserved for a file name (including the trailing \0). - Since names are stored in the entry as UTF-8, we won't be able to + Since names are stored in the entry as UTF-8, we won't be ble to store all names allowed by FAT. In FAT, a name can have max 255 characters (not bytes!). Since the UTF-8 encoding of a char may take up to 4 bytes, there will be names that we won't be able to store completely. For such names, the short DOS name is used. */ -#define FAT_FILENAME_BYTES 256 - +#define FAT_DIRENTRY_NAME_MAX 255 struct fat_direntry { - unsigned char name[FAT_FILENAME_BYTES]; /* UTF-8 encoded name plus \0 */ - unsigned short attr; /* Attributes */ - unsigned char crttimetenth; /* Millisecond creation - time stamp (0-199) */ - unsigned short crttime; /* Creation time */ - unsigned short crtdate; /* Creation date */ - unsigned short lstaccdate; /* Last access date */ - unsigned short wrttime; /* Last write time */ - unsigned short wrtdate; /* Last write date */ - unsigned long filesize; /* File size in bytes */ - long firstcluster; /* fstclusterhi<<16 + fstcluslo */ + union { + uint8_t name[255+1+4]; /* UTF-8 name plus \0 plus parse slop */ + uint16_t ucssegs[5+20][13]; /* UTF-16 segment buffer - layout saves... */ + }; /* ...130 bytes (important if stacked) */ + uint16_t ucsterm; /* allow one NULL-term after ucssegs */ + uint8_t shortname[13]; /* DOS filename (OEM charset) */ + uint8_t attr; /* file attributes */ + uint8_t crttimetenth; /* millisecond creation time stamp (0-199) */ + uint16_t crttime; /* creation time */ + uint16_t crtdate; /* creation date */ + uint16_t lstaccdate; /* last access date */ + uint16_t wrttime; /* last write time */ + uint16_t wrtdate; /* last write date */ + uint32_t filesize; /* file size in bytes */ + int32_t firstcluster; /* first FAT cluster of file, 0 if empty */ }; -#define FAT_ATTR_READ_ONLY 0x01 -#define FAT_ATTR_HIDDEN 0x02 -#define FAT_ATTR_SYSTEM 0x04 -#define FAT_ATTR_VOLUME_ID 0x08 -#define FAT_ATTR_DIRECTORY 0x10 -#define FAT_ATTR_ARCHIVE 0x20 -#define FAT_ATTR_VOLUME 0x40 /* this is a volume, not a real directory */ +/* cursor structure used for scanning directories; holds the last-returned + entry information */ +struct fat_dirscan_info +{ + unsigned int entry; /* short dir entry index in parent */ + unsigned int entries; /* number of dir entries used */ +}; + +#define FAT_RW_VAL (0u - 1) +/* basic FAT file information about where to find a file and who houses it */ struct fat_file { - long firstcluster; /* first cluster in file */ - long lastcluster; /* cluster of last access */ - long lastsector; /* sector of last access */ - long clusternum; /* current clusternum */ - long sectornum; /* sector number in this cluster */ - unsigned int direntry; /* short dir entry index from start of dir */ - unsigned int direntries; /* number of dir entries used by this file */ - long dircluster; /* first cluster of dir */ - bool eof; #ifdef HAVE_MULTIVOLUME - int volume; /* file resides on which volume */ + int volume; /* file resides on which volume (first!) */ #endif + long firstcluster; /* first cluster in file */ + long dircluster; /* first cluster of parent directory */ + struct fat_dirscan_info e; /* entry information */ }; -struct fat_dir +/* this stores what was last accessed when read or writing a file's data */ +struct fat_filestr { - unsigned char sectorcache[SECTOR_SIZE] CACHEALIGN_ATTR; - unsigned int entry; - unsigned int entrycount; - long sector; - struct fat_file file; - /* There are 2-bytes per characters. We don't want to bother too much, as LFN entries are - * at much 255 characters longs, that's at most 20 LFN entries. Each entry hold at most - * 13 characters, that a total of 260 characters. So we keep a buffer of that size. - * Keep coherent with fat.c code. */ - unsigned char longname[260 * 2]; -} CACHEALIGN_ATTR; - -#ifdef HAVE_HOTSWAP -extern void fat_lock(void); -extern void fat_unlock(void); -#endif + struct fat_file *fatfilep; /* common file information */ + long lastcluster; /* cluster of last access */ + unsigned long lastsector; /* sector of last access */ + long clusternum; /* cluster number of last access */ + unsigned long sectornum; /* sector number within current cluster */ + bool eof; /* end-of-file reached */ +}; + +/** File entity functions **/ +int fat_create_file(struct fat_file *parent, const char *name, + uint8_t attr, struct fat_file *file, + struct fat_direntry *fatent); +bool fat_dir_is_parent(const struct fat_file *dir, const struct fat_file *file); +bool fat_file_is_same(const struct fat_file *file1, const struct fat_file *file2); +int fat_fstat(struct fat_file *file, struct fat_direntry *entry); +int fat_open(const struct fat_file *parent, long startcluster, + struct fat_file *file); +int fat_open_rootdir(IF_MV(int volume,) struct fat_file *dir); +enum fat_remove_op /* what should fat_remove(), remove? */ +{ + FAT_RM_DIRENTRIES = 0x1, /* remove only directory entries */ + FAT_RM_DATA = 0x2, /* remove only file data */ + FAT_RM_ALL = 0x3, /* remove all of above */ +}; +int fat_remove(struct fat_file *file, enum fat_remove_op what); +int fat_rename(struct fat_file *parent, struct fat_file *file, + const unsigned char *newname); -extern void fat_init(void); -extern int fat_get_bytes_per_sector(IF_MV_NONVOID(int volume)); -extern int fat_mount(IF_MV(int volume,) IF_MD(int drive,) long startsector); -extern int fat_unmount(int volume, bool flush); -extern void fat_size(IF_MV(int volume,) /* public for info */ - unsigned long* size, - unsigned long* free); -extern void fat_recalc_free(IF_MV_NONVOID(int volume)); /* public for debug info screen */ -extern int fat_create_dir(const char* name, - struct fat_dir* newdir, - struct fat_dir* dir); -extern int fat_open(IF_MV(int volume,) - long cluster, - struct fat_file* ent, - const struct fat_dir* dir); -extern int fat_create_file(const char* name, - struct fat_file* ent, - struct fat_dir* dir); -extern long fat_readwrite(struct fat_file *ent, long sectorcount, - void* buf, bool write ); -extern int fat_closewrite(struct fat_file *ent, long size, int attr); -extern int fat_seek(struct fat_file *ent, unsigned long sector ); -extern int fat_remove(struct fat_file *ent); -extern int fat_truncate(const struct fat_file *ent); -extern int fat_rename(struct fat_file* file, - struct fat_dir* dir, - const unsigned char* newname, - long size, int attr); - -extern int fat_opendir(IF_MV(int volume,) - struct fat_dir *ent, unsigned long startcluster, - const struct fat_dir *parent_dir); -extern int fat_getnext(struct fat_dir *ent, struct fat_direntry *entry); -extern unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume)); /* public for debug info screen */ -extern bool fat_ismounted(int volume); -extern void* fat_get_sector_buffer(void); -extern void fat_release_sector_buffer(void); +/** File stream functions **/ +int fat_closewrite(struct fat_filestr *filestr, uint32_t size, + struct fat_direntry *fatentp); +void fat_filestr_init(struct fat_filestr *filestr, struct fat_file *file); +unsigned long fat_query_sectornum(const struct fat_filestr *filestr); +long fat_readwrite(struct fat_filestr *filestr, unsigned long sectorcount, + void *buf, bool write); +void fat_rewind(struct fat_filestr *filestr); +int fat_seek(struct fat_filestr *filestr, unsigned long sector); +int fat_truncate(const struct fat_filestr *filestr); -#endif +/** Directory stream functions **/ +struct filestr_cache; +int fat_readdir(struct fat_filestr *dirstr, struct fat_dirscan_info *scan, + struct filestr_cache *cachep, struct fat_direntry *entry); +void fat_rewinddir(struct fat_dirscan_info *scan); + +/** Mounting and unmounting functions **/ +bool fat_ismounted(IF_MV_NONVOID(int volume)); +int fat_mount(IF_MV(int volume,) IF_MD(int drive,) unsigned long startsector); +int fat_unmount(IF_MV_NONVOID(int volume)); + +/** Debug screen stuff **/ +#ifdef MAX_LOG_SECTOR_SIZE +int fat_get_bytes_per_sector(IF_MV_NONVOID(int volume)); +#endif /* MAX_LOG_SECTOR_SIZE */ +unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume)); +void fat_recalc_free(IF_MV_NONVOID(int volume)); +bool fat_size(IF_MV(int volume,) unsigned long *size, unsigned long *free); + +/** Misc. **/ +time_t fattime_mktime(uint16_t fatdate, uint16_t fattime); +void fat_empty_fat_direntry(struct fat_direntry *entry); +void fat_init(void); + +#endif /* FAT_H */ |