diff --git a/source/fatdir.c b/source/fatdir.c index a0561c5..293006b 100644 --- a/source/fatdir.c +++ b/source/fatdir.c @@ -62,6 +62,7 @@ #include "directory.h" #include "bit_ops.h" #include "filetime.h" +#include "lock.h" int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) { @@ -70,9 +71,11 @@ int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) { DIR_ENTRY dirEntry; // Get the partition this file is on + _FAT_lock(); partition = _FAT_partition_getPartitionFromPath (path); if (partition == NULL) { + _FAT_unlock(); r->_errno = ENODEV; return -1; } @@ -82,12 +85,14 @@ int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) { path = strchr (path, ':') + 1; } if (strchr (path, ':') != NULL) { + _FAT_unlock(); r->_errno = EINVAL; return -1; } // Search for the file on the disc if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, NULL)) { + _FAT_unlock(); r->_errno = ENOENT; return -1; } @@ -95,6 +100,7 @@ int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) { // Fill in the stat struct _FAT_directory_entryStat (partition, &dirEntry, st); + _FAT_unlock(); return 0; } @@ -112,15 +118,18 @@ int _FAT_unlink_r (struct _reent *r, const char *path) { bool errorOccured = false; // Get the partition this directory is on + _FAT_lock(); partition = _FAT_partition_getPartitionFromPath (path); if (partition == NULL) { + _FAT_unlock(); r->_errno = ENODEV; return -1; } // Make sure we aren't trying to write to a read-only disc if (partition->readOnly) { + _FAT_unlock(); r->_errno = EROFS; return -1; } @@ -130,12 +139,14 @@ int _FAT_unlink_r (struct _reent *r, const char *path) { path = strchr (path, ':') + 1; } if (strchr (path, ':') != NULL) { + _FAT_unlock(); r->_errno = EINVAL; return -1; } // Search for the file on the disc if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, NULL)) { + _FAT_unlock(); r->_errno = ENOENT; return -1; } @@ -150,6 +161,7 @@ int _FAT_unlink_r (struct _reent *r, const char *path) { while (nextEntry) { if (!_FAT_directory_isDot (&dirContents)) { // The directory had something in it that isn't a reference to itself or it's parent + _FAT_unlock(); r->_errno = EPERM; return -1; } @@ -177,6 +189,7 @@ int _FAT_unlink_r (struct _reent *r, const char *path) { errorOccured = true; } + _FAT_unlock(); if (errorOccured) { return -1; } else { @@ -188,9 +201,11 @@ int _FAT_chdir_r (struct _reent *r, const char *path) { PARTITION* partition = NULL; // Get the partition this directory is on + _FAT_lock(); partition = _FAT_partition_getPartitionFromPath (path); if (partition == NULL) { + _FAT_unlock(); r->_errno = ENODEV; return -1; } @@ -200,12 +215,14 @@ int _FAT_chdir_r (struct _reent *r, const char *path) { path = strchr (path, ':') + 1; } if (strchr (path, ':') != NULL) { + _FAT_unlock(); r->_errno = EINVAL; return -1; } // Set the default device to match this one if (!_FAT_partition_setDefaultPartition (partition)) { + _FAT_unlock(); r->_errno = ENOENT; return -1; } @@ -213,9 +230,11 @@ int _FAT_chdir_r (struct _reent *r, const char *path) { // Try changing directory if (_FAT_directory_chdir (partition, path)) { // Successful + _FAT_unlock(); return 0; } else { // Failed + _FAT_unlock(); r->_errno = ENOTDIR; return -1; } @@ -229,21 +248,25 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) { u32 dirCluster; // Get the partition this directory is on + _FAT_lock(); partition = _FAT_partition_getPartitionFromPath (oldName); if (partition == NULL) { + _FAT_unlock(); r->_errno = ENODEV; return -1; } // Make sure the same partition is used for the old and new names if (partition != _FAT_partition_getPartitionFromPath (newName)) { + _FAT_unlock(); r->_errno = EXDEV; return -1; } // Make sure we aren't trying to write to a read-only disc if (partition->readOnly) { + _FAT_unlock(); r->_errno = EROFS; return -1; } @@ -253,6 +276,7 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) { oldName = strchr (oldName, ':') + 1; } if (strchr (oldName, ':') != NULL) { + _FAT_unlock(); r->_errno = EINVAL; return -1; } @@ -260,18 +284,21 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) { newName = strchr (newName, ':') + 1; } if (strchr (newName, ':') != NULL) { + _FAT_unlock(); r->_errno = EINVAL; return -1; } // Search for the file on the disc if (!_FAT_directory_entryFromPath (partition, &oldDirEntry, oldName, NULL)) { + _FAT_unlock(); r->_errno = ENOENT; return -1; } // Make sure there is no existing file / directory with the new name if (_FAT_directory_entryFromPath (partition, &newDirEntry, newName, NULL)) { + _FAT_unlock(); r->_errno = EEXIST; return -1; } @@ -288,6 +315,7 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) { // Recycling newDirEntry, since it needs to be recreated anyway if (!_FAT_directory_entryFromPath (partition, &newDirEntry, newName, pathEnd) || !_FAT_directory_isDirectory(&newDirEntry)) { + _FAT_unlock(); r->_errno = ENOTDIR; return -1; } @@ -304,22 +332,26 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) { // Write the new entry if (!_FAT_directory_addEntry (partition, &newDirEntry, dirCluster)) { + _FAT_unlock(); r->_errno = ENOSPC; return -1; } // Remove the old entry if (!_FAT_directory_removeEntry (partition, &oldDirEntry)) { + _FAT_unlock(); r->_errno = EIO; return -1; } // Flush any sectors in the disc cache if (!_FAT_cache_flush (partition->cache)) { + _FAT_unlock(); r->_errno = EIO; return -1; } + _FAT_unlock(); return 0; } @@ -330,10 +362,12 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) { const char* pathEnd; u32 parentCluster, dirCluster; u8 newEntryData[DIR_ENTRY_DATA_SIZE]; - + + _FAT_lock(); partition = _FAT_partition_getPartitionFromPath (path); if (partition == NULL) { + _FAT_unlock(); r->_errno = ENODEV; return -1; } @@ -343,6 +377,7 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) { path = strchr (path, ':') + 1; } if (strchr (path, ':') != NULL) { + _FAT_unlock(); r->_errno = EINVAL; return -1; } @@ -352,12 +387,14 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) { // Make sure it doesn't exist if (fileExists) { + _FAT_unlock(); r->_errno = EEXIST; return -1; } if (partition->readOnly) { // We can't write to a read-only partition + _FAT_unlock(); r->_errno = EROFS; return -1; } @@ -373,6 +410,7 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) { // Recycling dirEntry, since it needs to be recreated anyway if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, pathEnd) || !_FAT_directory_isDirectory(&dirEntry)) { + _FAT_unlock(); r->_errno = ENOTDIR; return -1; } @@ -396,6 +434,7 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) { dirCluster = _FAT_fat_linkFreeClusterCleared (partition, CLUSTER_FREE); if (!_FAT_fat_isValidCluster(partition, dirCluster)) { // No space left on disc for the cluster + _FAT_unlock(); r->_errno = ENOSPC; return -1; } @@ -404,6 +443,7 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) { // Write the new directory's entry to it's parent if (!_FAT_directory_addEntry (partition, &dirEntry, parentCluster)) { + _FAT_unlock(); r->_errno = ENOSPC; return -1; } @@ -432,10 +472,12 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) { // Flush any sectors in the disc cache if (!_FAT_cache_flush(partition->cache)) { + _FAT_unlock(); r->_errno = EIO; return -1; } + _FAT_unlock(); return 0; } @@ -445,9 +487,11 @@ int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf) u32 freeClusterCount; // Get the partition of the requested path + _FAT_lock(); partition = _FAT_partition_getPartitionFromPath (path); if (partition == NULL) { + _FAT_unlock(); r->_errno = ENODEV; return -1; } @@ -476,6 +520,7 @@ int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf) // Maximum filename length. buf->f_namemax = MAX_FILENAME_LENGTH; + _FAT_unlock(); return 0; } @@ -484,9 +529,11 @@ DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path) DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct); bool fileExists; + _FAT_lock(); state->partition = _FAT_partition_getPartitionFromPath (path); if (state->partition == NULL) { + _FAT_unlock(); r->_errno = ENODEV; return NULL; } @@ -496,6 +543,7 @@ DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path) path = strchr (path, ':') + 1; } if (strchr (path, ':') != NULL) { + _FAT_unlock(); r->_errno = EINVAL; return NULL; } @@ -503,12 +551,14 @@ DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path) fileExists = _FAT_directory_entryFromPath (state->partition, &dirEntry, path, NULL); if (!fileExists) { + _FAT_unlock(); r->_errno = ENOENT; return NULL; } // Make sure it is a directory if (! _FAT_directory_isDirectory (&dirEntry)) { + _FAT_unlock(); r->_errno = ENOTDIR; return NULL; } @@ -522,6 +572,7 @@ DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path) // We are now using this entry state->inUse = true; + _FAT_unlock(); return (DIR_ITER*) state; } @@ -529,7 +580,9 @@ int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState) { DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct); // Make sure we are still using this entry + _FAT_lock(); if (!state->inUse) { + _FAT_unlock(); r->_errno = EBADF; return -1; } @@ -538,6 +591,7 @@ int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState) { state->validEntry = _FAT_directory_getFirstEntry (state->partition, &(state->currentEntry), state->startCluster); + _FAT_unlock(); return 0; } @@ -545,13 +599,16 @@ int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct); // Make sure we are still using this entry + _FAT_lock(); if (!state->inUse) { + _FAT_unlock(); r->_errno = EBADF; return -1; } // Make sure there is another file to report on if (! state->validEntry) { + _FAT_unlock(); r->_errno = ENOENT; return -1; } @@ -567,6 +624,7 @@ int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct state->validEntry = _FAT_directory_getNextEntry (state->partition, &(state->currentEntry)); + _FAT_unlock(); return 0; } @@ -574,7 +632,9 @@ int _FAT_dirclose_r (struct _reent *r, DIR_ITER *dirState) { DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct); // We are no longer using this entry + _FAT_lock(); state->inUse = false; + _FAT_unlock(); return 0; } diff --git a/source/fatfile.c b/source/fatfile.c index 8472f85..d411de7 100644 --- a/source/fatfile.c +++ b/source/fatfile.c @@ -75,6 +75,7 @@ #include "file_allocation_table.h" #include "bit_ops.h" #include "filetime.h" +#include "lock.h" int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode) { PARTITION* partition = NULL; @@ -127,16 +128,19 @@ int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags } // Search for the file on the disc + _FAT_lock(); fileExists = _FAT_directory_entryFromPath (partition, &dirEntry, path, NULL); // The file shouldn't exist if we are trying to create it if ((flags & O_CREAT) && (flags & O_EXCL) && fileExists) { + _FAT_unlock(); r->_errno = EEXIST; return -1; } // It should not be a directory if we're openning a file, if (fileExists && _FAT_directory_isDirectory(&dirEntry)) { + _FAT_unlock(); r->_errno = EISDIR; return -1; } @@ -146,6 +150,7 @@ int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags if (flags & O_CREAT) { if (partition->readOnly) { // We can't write to a read-only partition + _FAT_unlock(); r->_errno = EROFS; return -1; } @@ -161,6 +166,7 @@ int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags // Recycling dirEntry, since it needs to be recreated anyway if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, pathEnd) || !_FAT_directory_isDirectory(&dirEntry)) { + _FAT_unlock(); r->_errno = ENOTDIR; return -1; } @@ -178,11 +184,13 @@ int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags u16_to_u8array (dirEntry.entryData, DIR_ENTRY_cDate, _FAT_filetime_getDateFromRTC()); if (!_FAT_directory_addEntry (partition, &dirEntry, dirCluster)) { + _FAT_unlock(); r->_errno = ENOSPC; return -1; } } else { // file doesn't exist, and we aren't creating it + _FAT_unlock(); r->_errno = ENOENT; return -1; } @@ -200,6 +208,7 @@ int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags // Make sure we aren't trying to write to a read-only file if (file->write && !_FAT_directory_isWritable(&dirEntry)) { + _FAT_unlock(); r->_errno = EROFS; return -1; } @@ -243,6 +252,7 @@ int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags file->inUse = true; partition->openFileCount += 1; + _FAT_unlock(); return (int) file; } @@ -251,7 +261,9 @@ int _FAT_close_r (struct _reent *r, int fd) { FILE_STRUCT* file = (FILE_STRUCT*) fd; u8 dirEntryData[DIR_ENTRY_DATA_SIZE]; + _FAT_lock(); if (!file->inUse) { + _FAT_unlock(); r->_errno = EBADF; return -1; } @@ -283,13 +295,16 @@ int _FAT_close_r (struct _reent *r, int fd) { // Flush any sectors in the disc cache if (!_FAT_cache_flush(file->partition->cache)) { + _FAT_unlock(); r->_errno = EIO; return -1; } + } file->inUse = false; file->partition->openFileCount -= 1; + _FAT_unlock(); return 0; } @@ -310,14 +325,18 @@ int _FAT_read_r (struct _reent *r, int fd, char *ptr, int len) { bool flagNoError = true; // Make sure we can actually read from the file + _FAT_lock(); if ((file == NULL) || !file->inUse || !file->read) { + _FAT_unlock(); r->_errno = EBADF; return -1; } // Don't try to read if the read pointer is past the end of file if (file->currentPosition >= file->filesize || file->startCluster == CLUSTER_FREE) { - return -1; + r->_errno = EOVERFLOW; + _FAT_unlock(); + return 0; } // Don't read past end of file @@ -328,6 +347,7 @@ int _FAT_read_r (struct _reent *r, int fd, char *ptr, int len) { // Short circuit cases where len is 0 (or less) if (len <= 0) { + _FAT_unlock(); return 0; } @@ -451,6 +471,8 @@ int _FAT_read_r (struct _reent *r, int fd, char *ptr, int len) { // Update file information file->rwPosition = position; file->currentPosition += len; + + _FAT_unlock(); return len; } @@ -468,7 +490,7 @@ static bool _FAT_file_extend_r (struct _reent *r, FILE_STRUCT* file) { u8 zeroBuffer [BYTES_PER_READ] = {0}; u32 tempNextCluster; - + position.byte = file->filesize % BYTES_PER_READ; position.sector = (file->filesize % partition->bytesPerCluster) / BYTES_PER_READ; // It is assumed that there is always a startCluster @@ -571,13 +593,16 @@ int _FAT_write_r (struct _reent *r,int fd, const char *ptr, int len) { bool flagAppending = false; // Make sure we can actually write to the file + _FAT_lock(); if ((file == NULL) || !file->inUse || !file->write) { + _FAT_unlock(); r->_errno = EBADF; return -1; } // Short circuit cases where len is 0 (or less) if (len <= 0) { + _FAT_unlock(); return 0; } @@ -590,6 +615,7 @@ int _FAT_write_r (struct _reent *r,int fd, const char *ptr, int len) { tempNextCluster = _FAT_fat_linkFreeCluster (partition, CLUSTER_FREE); if (!_FAT_fat_isValidCluster(partition, tempNextCluster)) { // Couldn't get a cluster, so abort immediately + _FAT_unlock(); r->_errno = ENOSPC; return -1; } @@ -612,6 +638,7 @@ int _FAT_write_r (struct _reent *r,int fd, const char *ptr, int len) { // If the write pointer is past the end of the file, extend the file to that size if (file->currentPosition > file->filesize) { if (!_FAT_file_extend_r (r, file)) { + _FAT_unlock(); return -1; } } @@ -777,6 +804,8 @@ int _FAT_write_r (struct _reent *r,int fd, const char *ptr, int len) { file->filesize = file->currentPosition; } } + + _FAT_unlock(); return len; } @@ -791,8 +820,10 @@ int _FAT_seek_r (struct _reent *r, int fd, int pos, int dir) { int clusCount; int position; + _FAT_lock(); if ((file == NULL) || (file->inUse == false)) { // invalid file + _FAT_unlock(); r->_errno = EBADF; return -1; } @@ -810,16 +841,19 @@ int _FAT_seek_r (struct _reent *r, int fd, int pos, int dir) { position = file->filesize + pos; break; default: + _FAT_unlock(); r->_errno = EINVAL; return -1; } if ((pos > 0) && (position < 0)) { r->_errno = EOVERFLOW; + _FAT_unlock(); return -1; } if (position < 0) { + _FAT_unlock(); r->_errno = EINVAL; return -1; } @@ -855,6 +889,7 @@ int _FAT_seek_r (struct _reent *r, int fd, int pos, int dir) { file->rwPosition.sector = partition->sectorsPerCluster; file->rwPosition.byte = 0; } else { + _FAT_unlock(); r->_errno = EINVAL; return -1; } @@ -866,6 +901,7 @@ int _FAT_seek_r (struct _reent *r, int fd, int pos, int dir) { // Save position file->currentPosition = position; + _FAT_unlock(); return position; } @@ -878,8 +914,10 @@ int _FAT_fstat_r (struct _reent *r, int fd, struct stat *st) { DIR_ENTRY fileEntry; + _FAT_lock(); if ((file == NULL) || (file->inUse == false)) { // invalid file + _FAT_unlock(); r->_errno = EBADF; return -1; } @@ -891,6 +929,7 @@ int _FAT_fstat_r (struct _reent *r, int fd, struct stat *st) { fileEntry.dataEnd = file->dirEntryEnd; if (!_FAT_directory_entryFromPosition (partition, &fileEntry)) { + _FAT_unlock(); r->_errno = EIO; return -1; } @@ -902,6 +941,7 @@ int _FAT_fstat_r (struct _reent *r, int fd, struct stat *st) { st->st_ino = (ino_t)(file->startCluster); // The file serial number is the start cluster st->st_size = file->filesize; // File size + _FAT_unlock(); return 0; } diff --git a/source/libfat.c b/source/libfat.c index 2848d01..ec756a5 100644 --- a/source/libfat.c +++ b/source/libfat.c @@ -52,6 +52,7 @@ #include "partition.h" #include "fatfile.h" #include "fatdir.h" +#include "lock.h" #ifdef GBA #define DEFAULT_CACHE_PAGES 2 @@ -127,6 +128,9 @@ bool fatInit (u32 cacheSize, bool setAsDefaultDevice) { #endif chdir (filePath); } + + _FAT_lock_init(); + return true; }