KallistiOS git master
Independent SDK for the Sega Dreamcast
Loading...
Searching...
No Matches
vmufs.h
Go to the documentation of this file.
1/* KallistiOS ##version##
2
3 dc/vmufs.h
4 Copyright (C) 2003 Megan Potter
5
6*/
7
8/** \file dc/vmufs.h
9 \brief Low-level VMU filesystem driver.
10 \ingroup vfs_vmu
11
12 The VMU filesystem driver mounts itself on /vmu of the VFS. Each memory card
13 has its own subdirectory off of that directory (i.e, /vmu/a1 for slot 1 of
14 the first controller). VMUs themselves have no subdirectories, so the driver
15 itself is fairly simple.
16
17 Files on a VMU must be multiples of 512 bytes in size, and should have a
18 header attached so that they show up in the BIOS menu.
19
20 \author Megan Potter
21 \see dc/vmu_pkg.h
22 \see dc/fs_vmu.h
23*/
24
25#ifndef __DC_VMUFS_H
26#define __DC_VMUFS_H
27
28#include <stdint.h>
29#include <kos/cdefs.h>
30__BEGIN_DECLS
31
32#include <dc/maple.h>
33
34/** \addtogroup vfs_vmu
35 @{
36*/
37
38#define VMU_BLOCK_SIZE 512
39#define VMU_FILENAME_SIZE 12
40
41/** \brief BCD timestamp, used several places in the vmufs.
42 \headerfile dc/vmufs.h
43*/
44typedef struct {
45 uint8_t cent; /**< \brief Century (0-99) */
46 uint8_t year; /**< \brief Year, within century (0-99) */
47 uint8_t month; /**< \brief Month of the year (1-12) */
48 uint8_t day; /**< \brief Day of the month (1-31) */
49 uint8_t hour; /**< \brief Hour of the day (0-23) */
50 uint8_t min; /**< \brief Minutes (0-59) */
51 uint8_t sec; /**< \brief Seconds (0-59) */
52 uint8_t dow; /**< \brief Day of week (0 = Mon, ..., 6 = Sun) */
54
55_Static_assert(sizeof(vmu_timestamp_t) == 8, "Invalid vmu_timestamp_t size");
56
57/* \cond */
58/* Special markers values in the FAT */
59#define VMU_FAT_UNALLOCATED 0xfffc
60#define VMU_FAT_LAST_IN_FILE 0xfffa
61/* \endcond */
62
63/** \brief VMU FS Root block layout.
64 \headerfile dc/vmufs.h
65*/
66typedef struct {
67 uint8_t magic[16]; /**< \brief All should contain 0x55 */
68 uint8_t use_custom; /**< \brief 0 = standard, 1 = custom */
69 uint8_t custom_color[4];/**< \brief blue, green, red, alpha */
70 uint8_t pad1[27]; /**< \brief All zeros */
71 vmu_timestamp_t timestamp; /**< \brief BCD timestamp */
72 uint8_t pad2[8]; /**< \brief All zeros */
73 uint8_t unk1[6]; /**< \brief ??? */
74 uint16_t fat_loc; /**< \brief FAT location */
75 uint16_t fat_size; /**< \brief FAT size in blocks */
76 uint16_t dir_loc; /**< \brief Directory location */
77 uint16_t dir_size; /**< \brief Directory size in blocks */
78 uint16_t icon_shape; /**< \brief Icon shape for this VMS */
79 uint16_t blk_cnt; /**< \brief Number of user blocks */
80 uint8_t unk2[430]; /**< \brief ??? */
82
83_Static_assert(sizeof(vmu_root_t) == VMU_BLOCK_SIZE, "Invalid vmu_root_t size");
84
85/** \defgroup vmu_filetypes Types
86 \brief VMU File types
87
88 These mark whether a vmu_dir_t is empty, contains a data file, or a game.
89
90 \sa vmu_dir_t::filetype
91
92 @{
93*/
94#define VMU_FILE_NONE 0x00 /**< \brief No file in the entry */
95#define VMU_FILE_DATA 0x33 /**< \brief Is a data file */
96#define VMU_FILE_GAME 0xcc /**< \brief Is a VMU game file */
97/** @} */
98
99/** \defgroup vmu_copyprotect VMU Copy Protection
100 \brief VMU Copy Protection Options
101
102 These mark whether a vmu_dir_t is copy protected or not.
103
104 \sa vmu_dir_t::copyprotect
105
106 @{
107*/
108#define VMU_FILE_COPYABLE 0x00
109#define VMU_FILE_PROTECTED 0xff
110/** @} */
111
112/** \brief VMU FS Directory entries, 32 bytes each.
113 \headerfile dc/vmufs.h
114
115 \note
116 vmu_dir_t::dirty should always be zero when written out to the VMU. What
117 this lets us do, though, is conserve on flash writes. If you only want to
118 modify one single file (which is the standard case) then re-writing all
119 of the dir blocks is a big waste. Instead, you should set the dirty flag
120 on the in-mem copy of the directory, and writing it back out will only
121 flush the containing block back to the VMU, setting it back to zero
122 in the process. Loaded blocks should always have zero here (though we
123 enforce that in the code to make sure) so it will be non-dirty by
124 default.
125*/
126typedef struct {
127 uint8_t filetype; /**< \brief 0x00 = no file; 0x33 = data; 0xcc = a game */
128 uint8_t copyprotect; /**< \brief 0x00 = copyable; 0xff = copy protected */
129 uint16_t firstblk; /**< \brief Location of the first block in the file */
130 char filename[VMU_FILENAME_SIZE] __attribute__ ((nonstring));
131 /**< \brief Note: there is no null terminator */
132 vmu_timestamp_t timestamp; /**< \brief File time */
133 uint16_t filesize; /**< \brief Size of the file in blocks */
134 uint16_t hdroff; /**< \brief Offset of header, in blocks from start of file */
135 uint8_t dirty; /**< \brief See header notes */
136 uint8_t pad1[3]; /**< \brief All zeros */
137} vmu_dir_t;
138
139_Static_assert(sizeof(vmu_dir_t) == 32, "Invalid vmu_dir_t size");
140
141/* ****************** Low level functions ******************** */
142
143/** \brief Fill in the date on a vmu_dir_t for writing.
144
145 \param d The directory to fill in the date on.
146*/
148
149/** \brief Reads a selected VMU's root block.
150
151 This function assumes the mutex is held.
152
153 \param dev The VMU to read from.
154 \param root_buf A buffer to hold the root block. You must allocate
155 this yourself before calling.
156 \retval -1 On failure.
157 \retval 0 On success.
158*/
160
161/** \brief Writes a selected VMU's root block.
162
163 This function assumes the mutex is held.
164
165 \param dev The VMU to write to.
166 \param root_buf The root block to write.
167 \retval -1 On failure.
168 \retval 0 On success.
169*/
170int vmufs_root_write(maple_device_t *dev, const vmu_root_t *root_buf);
171
172/** \brief Given a VMU's root block, return the amount of space in bytes
173 required to hold its directory.
174
175 \param root_buf The root block to check.
176 \return The amount of space, in bytes, needed.
177*/
178int vmufs_dir_blocks(const vmu_root_t *root_buf);
179
180/** \brief Given a VMU's root block, return the amount of space in bytes
181 required to hold its FAT.
182
183 \param root_buf The root block to check.
184 \return The amount of space, in bytes, needed.
185*/
186int vmufs_fat_blocks(const vmu_root_t *root_buf);
187
188/** \brief Given a selected VMU's root block, read its directory.
189
190 This function reads the directory of a given VMU root block. It assumes the
191 mutex is held. There must be at least the number of bytes returned by
192 vmufs_dir_blocks() available in the buffer for this to succeed.
193
194 \param dev The VMU to read.
195 \param root_buf The VMU's root block.
196 \param dir_buf The buffer to hold the directory. You must have
197 allocated this yourself.
198 \return 0 on success, <0 on failure.
199*/
200int vmufs_dir_read(maple_device_t *dev, const vmu_root_t *root_buf,
201 vmu_dir_t *dir_buf);
202
203/** \brief Given a selected VMU's root block and dir blocks, write the dirty
204 dir blocks back to the VMU. Assumes the mutex is held.
205
206 \param dev The VMU to write to.
207 \param root The VMU's root block.
208 \param dir_buf The VMU's directory structure.
209 \return 0 on success, <0 on failure.
210*/
212 vmu_dir_t *dir_buf);
213
214/** \brief Given a selected VMU's root block, read its FAT.
215
216 This function reads the FAT of a VMU, given its root block. It assumes the
217 mutex is held. There must be at least the number of bytes returned by
218 vmufs_fat_blocks() available in the buffer for this to succeed.
219
220 \param dev The VMU to read from.
221 \param root The VMU's root block.
222 \param fat_buf The buffer to store the FAT into. You must
223 pre-allocate this.
224 \return 0 on success, <0 on failure.
225*/
226int vmufs_fat_read(maple_device_t *dev, const vmu_root_t *root, uint16_t *fat_buf);
227
228/** \brief Given a selected VMU's root block and its FAT, write the FAT blocks
229 back to the VMU.
230
231 This function assumes the mutex is held.
232
233 \param dev The VMU to write to.
234 \param root The VMU's root block.
235 \param fat_buf The buffer to write to the FAT.
236 \return 0 on success, <0 on failure.
237*/
238int vmufs_fat_write(maple_device_t *dev, const vmu_root_t *root, uint16_t *fat_buf);
239
240/** \brief Given a previously-read directory, locate a file by filename.
241
242 \param root The VMU root block.
243 \param dir The VMU directory.
244 \param fn The file to find (only checked up to 12 chars).
245 \return The index into the directory array on success, or
246 <0 on failure.
247*/
248int vmufs_dir_find(const vmu_root_t *root, const vmu_dir_t *dir, const char *fn);
249
250/** \brief Given a previously-read directory, add a new dirent to the dir.
251
252 Another file with the same name should not exist (delete it first if it
253 does). This function will not check for dupes!
254
255 \param root The VMU root block.
256 \param dir The VMU directory.
257 \param newdirent The new entry to add.
258 \return 0 on success, or <0 on failure. */
259int vmufs_dir_add(const vmu_root_t *root, vmu_dir_t *dir, const vmu_dir_t *newdirent);
260
261/** \brief Given a pointer to a directory struct and a previously loaded FAT,
262 load the indicated file from the VMU.
263
264 An appropriate amount of space must have been allocated previously in the
265 buffer. Assumes the mutex is held.
266
267 \param dev The VMU to read from.
268 \param fat The FAT of the VMU.
269 \param dirent The entry to read.
270 \param outbuf A buffer to write the data into. You must allocate
271 this yourself with the appropriate amount of space.
272 \return 0 on success, <0 on failure.
273*/
274int vmufs_file_read(maple_device_t *dev, const uint16_t *fat, const vmu_dir_t *dirent, void *outbuf);
275
276/** \brief Given a pointer to a mostly-filled directory struct and a previously
277 loaded directory and FAT, write the indicated file to the VMU.
278
279 The named file should not exist in the directory already. The directory and
280 FAT will _not_ be sync'd back to the VMU, this must be done manually.
281 Assumes the mutex is held.
282
283 \param dev The VMU to write to.
284 \param root The VMU root block.
285 \param fat The FAT of the VMU.
286 \param dir The directory of the VMU.
287 \param newdirent The new entry to write.
288 \param filebuf The new file data.
289 \param size The size of the file in blocks (512-bytes each).
290 \return 0 on success, <0 on failure.
291*/
292int vmufs_file_write(maple_device_t *dev, const vmu_root_t *root, uint16_t *fat,
293 vmu_dir_t *dir, vmu_dir_t *newdirent, const void *filebuf, int size);
294
295/** \brief Given a previously-read FAT and directory, delete the named file.
296
297 No changes are made to the VMU itself, just the in-memory structs.
298
299 \param root The VMU root block.
300 \param fat The FAT to be modified.
301 \param dir The directory to be modified.
302 \param fn The file name to be deleted.
303 \retval 0 On success.
304 \retval -1 If fn is not found.
305*/
306int vmufs_file_delete(const vmu_root_t *root, uint16_t *fat, vmu_dir_t *dir, const char *fn);
307
308/** \brief Given a previously-read FAT, return the number of blocks available
309 to write out new file data.
310
311 \param root The VMU root block.
312 \param fat The FAT to be examined.
313 \return The number of blocks available.
314*/
315int vmufs_fat_free(const vmu_root_t *root, const uint16_t *fat);
316
317/** \brief Given a previously-read directory, return the number of dirents
318 available for new files.
319
320 \param root The VMU root block.
321 \param dir The directory in question.
322 \return The number of entries available.
323*/
324int vmufs_dir_free(const vmu_root_t *root, const vmu_dir_t *dir);
325
326/** \brief Lock the vmufs mutex.
327
328 This should be done before you attempt any low-level ops.
329
330 \retval 0 On success (no error conditions defined).
331*/
333
334/** \brief Unlock the vmufs mutex.
335
336 This should be done once you're done with any low-level ops.
337
338 \retval 0 On success (no error conditions defined).
339*/
341
342
343/* ****************** Higher level functions ******************** */
344
345/** \brief Read the directory from a VMU.
346
347 The output buffer will be allocated for you using malloc(), and the number
348 of entries will be returned. On failure, outbuf will not contain a dangling
349 buffer that needs to be freed (no further action required).
350
351 \param dev The VMU to read from.
352 \param outbuf A buffer that will be allocated where the directory
353 data will be placed.
354 \param outcnt The number of entries in outbuf.
355 \return 0 on success, or <0 on failure. */
356int vmufs_readdir(maple_device_t *dev, vmu_dir_t **outbuf, int *outcnt);
357
358/** \brief Read a file from the VMU.
359
360 The output buffer will be allocated for you using malloc(), and the size of
361 the file will be returned. On failure, outbuf and outsize will not be
362 written to.
363
364 \param dev The VMU to read from.
365 \param fn The name of the file to read.
366 \param outbuf A buffer that will be allocated where the file data
367 will be placed.
368 \param outsize Storage for the size of the file, in bytes.
369 \return 0 on success, or <0 on failure.
370*/
371int vmufs_read(maple_device_t *dev, const char *fn, void **outbuf, int *outsize);
372
373/** \brief Read a file from the VMU, using a pre-read dirent.
374
375 This function is faster to use than vmufs_read() if you already have done
376 the lookup, since it won't need to do that.
377
378 \param dev The VMU to read from.
379 \param dirent The entry to read.
380 \param outbuf A buffer that will be allocated where the file data
381 will be placed.
382 \param outsize Storage for the size of the file, in bytes.
383 \return 0 on success, <0 on failure.
384*/
385int vmufs_read_dirent(maple_device_t *dev, const vmu_dir_t *dirent, void **outbuf, int *outsize);
386
387/* Flags for vmufs_write */
388#define VMUFS_OVERWRITE 1 /**< \brief Overwrite existing files */
389#define VMUFS_VMUGAME 2 /**< \brief This file is a VMU game */
390#define VMUFS_NOCOPY 4 /**< \brief Set the no-copy flag */
391
392/** \brief Write a file to the VMU.
393
394 If the named file already exists, then the function checks 'flags'. If
395 VMUFS_OVERWRITE is set, then the old file is deleted first before the new
396 one is written (this all happens atomically). On partial failure, some data
397 blocks may have been written, but in general the card should not be damaged.
398
399 \param dev The VMU to write to.
400 \param fn The filename to write.
401 \param inbuf The data to write to the file.
402 \param insize The size of the file in bytes.
403 \param flags Flags for the write (i.e, VMUFS_OVERWRITE,
404 VMUFS_VMUGAME, VMUFS_NOCOPY).
405 \return 0 on success, or <0 for failure.
406*/
407int vmufs_write(maple_device_t *dev, const char *fn, void *inbuf, int insize, int flags);
408
409/** \brief Delete a file from the VMU.
410
411 \retval 0 On success.
412 \retval -1 If the file is not found.
413 \retval -2 On other failure.
414*/
415int vmufs_delete(maple_device_t *dev, const char *fn);
416
417/** \brief Return the number of user blocks free for file writing.
418
419 You should check this number before attempting to write.
420
421 \return The number of blocks free for writing.
422*/
424
425
426/** \brief Initialize vmufs.
427
428 Must be called before anything else is useful.
429
430 \retval 0 On success (no error conditions defined).
431*/
432int vmufs_init(void);
433
434/** \brief Shutdown vmufs.
435
436 Must be called after everything is finished.
437*/
439
440/** @} */
441
442__END_DECLS
443
444#endif /* __DC_VMUFS_H */
Various common macros used throughout the codebase.
int vmufs_dir_free(const vmu_root_t *root, const vmu_dir_t *dir)
Given a previously-read directory, return the number of dirents available for new files.
int vmufs_root_read(maple_device_t *dev, vmu_root_t *root_buf)
Reads a selected VMU's root block.
int vmufs_fat_read(maple_device_t *dev, const vmu_root_t *root, uint16_t *fat_buf)
Given a selected VMU's root block, read its FAT.
#define VMU_BLOCK_SIZE
Definition vmufs.h:38
int vmufs_shutdown(void)
Shutdown vmufs.
int vmufs_dir_find(const vmu_root_t *root, const vmu_dir_t *dir, const char *fn)
Given a previously-read directory, locate a file by filename.
int vmufs_fat_blocks(const vmu_root_t *root_buf)
Given a VMU's root block, return the amount of space in bytes required to hold its FAT.
int vmufs_read_dirent(maple_device_t *dev, const vmu_dir_t *dirent, void **outbuf, int *outsize)
Read a file from the VMU, using a pre-read dirent.
int vmufs_mutex_lock(void)
Lock the vmufs mutex.
int vmufs_file_delete(const vmu_root_t *root, uint16_t *fat, vmu_dir_t *dir, const char *fn)
Given a previously-read FAT and directory, delete the named file.
int vmufs_dir_add(const vmu_root_t *root, vmu_dir_t *dir, const vmu_dir_t *newdirent)
Given a previously-read directory, add a new dirent to the dir.
int vmufs_dir_read(maple_device_t *dev, const vmu_root_t *root_buf, vmu_dir_t *dir_buf)
Given a selected VMU's root block, read its directory.
int vmufs_fat_free(const vmu_root_t *root, const uint16_t *fat)
Given a previously-read FAT, return the number of blocks available to write out new file data.
int vmufs_write(maple_device_t *dev, const char *fn, void *inbuf, int insize, int flags)
Write a file to the VMU.
int vmufs_delete(maple_device_t *dev, const char *fn)
Delete a file from the VMU.
int vmufs_readdir(maple_device_t *dev, vmu_dir_t **outbuf, int *outcnt)
Read the directory from a VMU.
int vmufs_free_blocks(maple_device_t *dev)
Return the number of user blocks free for file writing.
int vmufs_dir_blocks(const vmu_root_t *root_buf)
Given a VMU's root block, return the amount of space in bytes required to hold its directory.
#define VMU_FILENAME_SIZE
Definition vmufs.h:39
int vmufs_read(maple_device_t *dev, const char *fn, void **outbuf, int *outsize)
Read a file from the VMU.
int vmufs_dir_write(maple_device_t *dev, const vmu_root_t *root, vmu_dir_t *dir_buf)
Given a selected VMU's root block and dir blocks, write the dirty dir blocks back to the VMU.
void vmufs_dir_fill_time(vmu_dir_t *d)
Fill in the date on a vmu_dir_t for writing.
int vmufs_init(void)
Initialize vmufs.
int vmufs_file_write(maple_device_t *dev, const vmu_root_t *root, uint16_t *fat, vmu_dir_t *dir, vmu_dir_t *newdirent, const void *filebuf, int size)
Given a pointer to a mostly-filled directory struct and a previously loaded directory and FAT,...
int vmufs_file_read(maple_device_t *dev, const uint16_t *fat, const vmu_dir_t *dirent, void *outbuf)
Given a pointer to a directory struct and a previously loaded FAT, load the indicated file from the V...
int vmufs_mutex_unlock(void)
Unlock the vmufs mutex.
int vmufs_fat_write(maple_device_t *dev, const vmu_root_t *root, uint16_t *fat_buf)
Given a selected VMU's root block and its FAT, write the FAT blocks back to the VMU.
int vmufs_root_write(maple_device_t *dev, const vmu_root_t *root_buf)
Writes a selected VMU's root block.
Maple Bus driver interface.
POSIX directory entry structure.
Definition dirent.h:62
One maple device.
Definition maple.h:289
VMU FS Directory entries, 32 bytes each.
Definition vmufs.h:126
uint8_t dirty
See header notes.
Definition vmufs.h:135
uint8_t copyprotect
0x00 = copyable; 0xff = copy protected
Definition vmufs.h:128
uint16_t filesize
Size of the file in blocks.
Definition vmufs.h:133
uint16_t firstblk
Location of the first block in the file.
Definition vmufs.h:129
uint8_t filetype
0x00 = no file; 0x33 = data; 0xcc = a game
Definition vmufs.h:127
vmu_timestamp_t timestamp
File time.
Definition vmufs.h:132
uint16_t hdroff
Offset of header, in blocks from start of file.
Definition vmufs.h:134
VMU FS Root block layout.
Definition vmufs.h:66
uint16_t dir_size
Directory size in blocks.
Definition vmufs.h:77
uint16_t icon_shape
Icon shape for this VMS.
Definition vmufs.h:78
uint16_t blk_cnt
Number of user blocks.
Definition vmufs.h:79
uint16_t fat_loc
FAT location.
Definition vmufs.h:74
uint8_t use_custom
0 = standard, 1 = custom
Definition vmufs.h:68
uint16_t fat_size
FAT size in blocks.
Definition vmufs.h:75
vmu_timestamp_t timestamp
BCD timestamp.
Definition vmufs.h:71
uint16_t dir_loc
Directory location.
Definition vmufs.h:76
BCD timestamp, used several places in the vmufs.
Definition vmufs.h:44
uint8_t year
Year, within century (0-99)
Definition vmufs.h:46
uint8_t min
Minutes (0-59)
Definition vmufs.h:50
uint8_t sec
Seconds (0-59)
Definition vmufs.h:51
uint8_t hour
Hour of the day (0-23)
Definition vmufs.h:49
uint8_t month
Month of the year (1-12)
Definition vmufs.h:47
uint8_t dow
Day of week (0 = Mon, ..., 6 = Sun)
Definition vmufs.h:52
uint8_t day
Day of the month (1-31)
Definition vmufs.h:48
uint8_t cent
Century (0-99)
Definition vmufs.h:45
char magic[6]
Definition wizard.c:80