1 //--------------------------------------------------------------------------------------------------
2 // Copyright (C) 2022 Marcus Geelnard
4 // Redistribution and use in source and binary forms, with or without modification, are permitted
5 // provided that the following conditions are met:
7 // 1. Redistributions of source code must retain the above copyright notice, this list of
8 // conditions and the following disclaimer.
10 // 2. Redistributions in binary form must reproduce the above copyright notice, this list of
11 // conditions and the following disclaimer in the documentation and/or other materials provided
12 // with the distribution.
14 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
15 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
17 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
20 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
21 // WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 //--------------------------------------------------------------------------------------------------
24 //--------------------------------------------------------------------------------------------------
25 // MFAT - A minimal I/O library for FAT (File Allocation Table) volumes
27 // The API of this library is modelled after the POSIX.1-2017 file I/O C API:s (but it is not fully
29 //--------------------------------------------------------------------------------------------------
41 #define MFAT_BLOCK_SIZE 512
43 // Flags for mfat_open().
44 #define MFAT_O_RDONLY 1
45 #define MFAT_O_WRONLY 2
46 #define MFAT_O_RDWR (MFAT_O_RDONLY | MFAT_O_WRONLY)
47 #define MFAT_O_APPEND 4
48 #define MFAT_O_CREAT 8
49 #define MFAT_O_DIRECTORY 16
51 // Whence values for mfat_lseek().
52 #define MFAT_SEEK_SET 0 ///< The offset is set to offset bytes.
53 #define MFAT_SEEK_CUR 1 ///< The offset is set to its current location plus offset bytes.
54 #define MFAT_SEEK_END 2 ///< The offset is set to the size of the file plus offset bytes.
56 // Values for mfat_stat_t.st_mode (OR:able bits).
57 #define MFAT_S_IFREG 0x8000 ///< Regular file.
58 #define MFAT_S_IFDIR 0x4000 ///< Directory.
59 #define MFAT_S_IRUSR 0x0100 ///< R for owner.
60 #define MFAT_S_IWUSR 0x0080 ///< W for owner.
61 #define MFAT_S_IXUSR 0x0040 ///< X for owner.
62 #define MFAT_S_IRGRP 0x0020 ///< R for group (same as MFAT_S_IRUSR).
63 #define MFAT_S_IWGRP 0x0010 ///< W for group (same as MFAT_S_IWUSR).
64 #define MFAT_S_IXGRP 0x0008 ///< X for group (same as MFAT_S_IXUSR).
65 #define MFAT_S_IROTH 0x0004 ///< R for other (same as MFAT_S_IRUSR).
66 #define MFAT_S_IWOTH 0x0002 ///< W for other (same as MFAT_S_IWUSR).
67 #define MFAT_S_IXOTH 0x0001 ///< X for other (same as MFAT_S_IXUSR).
69 // Macros for decoding the st_mode field of mfat_stat_t.
70 #define MFAT_S_ISREG(m) (((m)&MFAT_S_IFREG) != 0U)
71 #define MFAT_S_ISDIR(m) (((m)&MFAT_S_IFDIR) != 0U)
73 // The values of this struct are compatible with struct tm in <time.h>, so it is easy to convert the
74 // date/time to other representations using mktime(), for instance.
76 uint16_t year
; ///< Year (1980-2235).
77 uint8_t month
; ///< Month of year (1-12).
78 uint8_t day
; ///< Day of month (1-31).
79 uint8_t hour
; ///< Hour of day (0-23).
80 uint8_t minute
; ///< Minute of hour (0-59).
81 uint8_t second
; ///< Second of minute (0-59).
85 uint32_t st_mode
; ///< File permission bits plus MFAT_S_IFREG or MFAT_S_IFDIR.
86 uint32_t st_size
; ///< Size in bytes.
87 mfat_time_t st_mtim
; ///< Modification time.
90 /// @brief Block reader function pointer.
91 /// @param ptr Pointer to the buffer to read to.
92 /// @param block_no The block to read (relative to start of the storage medium).
93 /// @param custom The custom data pointer that was passed to mfat_init().
94 /// @returns zero (0) on success, or -1 on failure.
95 typedef int (*mfat_read_block_fun_t
)(char* ptr
, unsigned block_no
, void* custom
);
97 /// @brief Block writer function pointer.
98 /// @param ptr Pointer to the buffer to write from.
99 /// @param block_no The block to write (relative to start of the storage medium).
100 /// @param custom The custom data pointer that was passed to mfat_init().
101 /// @returns zero (0) on success, or -1 on failure.
102 typedef int (*mfat_write_block_fun_t
)(const char* ptr
, unsigned block_no
, void* custom
);
104 /// @brief Mount FAT volumes.
106 /// The provided read and write functions implement access to the storage medium, and the optional
107 /// custom data pointer can be used by these functions for keeping track of necessary state.
109 /// Before the function returns, it will identify and "mount" all FAT volumes on the storage medium.
110 /// If no FAT volumes are found, the function will return -1 (indicating failure).
112 /// This function needs to be called before calling any other library functions.
113 /// @param read_fun A block reader function pointer.
114 /// @param write_fun A block writer function pointer.
115 /// @param custom A custom data handle that is passed to the read/write functions (may be NULL).
116 /// @returns zero (0) on success, or -1 on failure.
117 int mfat_mount(mfat_read_block_fun_t read_fun
, mfat_write_block_fun_t write_fun
, void* custom
);
119 /// @brief Unmount all FAT volumes.
121 /// Any pending write operations will be flushed to the storage medium.
122 void mfat_unmount(void);
124 /// @brief Select which partition to use.
125 /// @param partition_no The partition number.
126 /// @returns zero (0) on success, or -1 on failure.
127 int mfat_select_partition(int partition_no
);
129 /// @brief Flush pending data updates to storage.
130 void mfat_sync(void);
132 /// @brief Obtain information about a open file.
133 /// @param fd The file descriptor.
134 /// @param stat Pointer to a stat structure into which information is placed concerning the file.
135 /// @returns zero (0) on success, or -1 on failure.
136 int mfat_fstat(int fd
, mfat_stat_t
* stat
);
138 /// @brief Obtain information about a file.
139 /// @param path The path to the file.
140 /// @param stat Pointer to a stat structure into which information is placed concerning the file.
141 /// @returns zero (0) on success, or -1 on failure.
142 int mfat_stat(const char* path
, mfat_stat_t
* stat
);
144 /// @brief Open a file.
145 /// @param path The path to the file.
146 /// @param oflag The open flags (OR of MFAT_O_* flags).
147 /// @returns a non-negative integer representing the lowest numbered unused file descriptor, or -1
149 /// @note Be aware that valid file descriptors are in the range 0..N-1, where N is the maximum
150 /// number of file descriptors (defined at compile time). This is in contrast to most POSIX
151 /// systems where 0, 1 and 2 are usually reserved for stdin, stdout and stderr, respectively.
152 int mfat_open(const char* path
, int oflag
);
154 /// @brief Close a file descriptor.
155 /// @param fd The file descriptor.
156 /// @returns zero (0) on success, or -1 on failure.
157 int mfat_close(int fd
);
159 /// @brief Read from a file.
160 /// @param fd The file descriptor.
161 /// @param buf Buffer to read data into.
162 /// @param nbyte Number of bytes to read.
163 /// @returns a non-negative integer indicating the number of bytes actually read if the operation
164 /// was succesful, zero (0) if the seek offset was at the end of the file when the function was
165 /// called, or -1 on failure.
166 int64_t mfat_read(int fd
, void* buf
, uint32_t nbyte
);
168 /// @brief Write to a file.
169 /// @param fd The file descriptor.
170 /// @param buf Buffer that contains the data to write.
171 /// @param nbyte Number of bytes to write.
172 /// @returns a non-negative integer indicating the number of bytes actually written if the operation
173 /// was succesful, or -1 on failure.
174 int64_t mfat_write(int fd
, const void* buf
, uint32_t nbyte
);
176 /// @brief Reposition read/write file offset.
177 /// @param fd The file descriptor.
178 /// @param offset The offset.
179 /// @param whence How the offset is interpreted.
180 /// @returns the resulting offset location as measured in bytes from the beginning of the file if
181 /// the operation was successful, or -1 on failure.
182 /// @note It is possible to query the current file position with mfat_lseek(fd, 0, MFAT_SEEK_CUR).
183 int64_t mfat_lseek(int fd
, int64_t offset
, int whence
);