summaryrefslogtreecommitdiff
path: root/firmware/export/fat.h
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/export/fat.h')
-rw-r--r--firmware/export/fat.h225
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 */