2006-07-14 04:42:37 +02:00
|
|
|
/*
|
|
|
|
libfat.c
|
|
|
|
Simple functionality for startup, mounting and unmounting of FAT-based devices.
|
2009-05-30 18:22:09 +02:00
|
|
|
|
2006-07-14 04:42:37 +02:00
|
|
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
2009-05-30 18:22:09 +02:00
|
|
|
|
2006-07-14 04:42:37 +02:00
|
|
|
Redistribution and use in source and binary forms, with or without modification,
|
|
|
|
are permitted provided that the following conditions are met:
|
|
|
|
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
this list of conditions and the following disclaimer in the documentation and/or
|
|
|
|
other materials provided with the distribution.
|
|
|
|
3. The name of the author may not be used to endorse or promote products derived
|
|
|
|
from this software without specific prior written permission.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
|
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
|
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
|
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/iosupport.h>
|
2007-01-11 12:23:18 +01:00
|
|
|
#include <unistd.h>
|
2008-05-10 21:35:18 +02:00
|
|
|
#include <string.h>
|
2006-07-14 04:42:37 +02:00
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
#include "partition.h"
|
|
|
|
#include "fatfile.h"
|
2006-08-13 11:43:38 +02:00
|
|
|
#include "fatdir.h"
|
2008-05-23 21:37:46 +02:00
|
|
|
#include "lock.h"
|
2008-11-20 06:22:28 +01:00
|
|
|
#include "mem_allocate.h"
|
|
|
|
#include "disc.h"
|
2006-07-14 04:42:37 +02:00
|
|
|
|
2008-11-20 06:22:28 +01:00
|
|
|
static const devoptab_t dotab_fat = {
|
2006-07-14 04:42:37 +02:00
|
|
|
"fat",
|
|
|
|
sizeof (FILE_STRUCT),
|
|
|
|
_FAT_open_r,
|
|
|
|
_FAT_close_r,
|
|
|
|
_FAT_write_r,
|
|
|
|
_FAT_read_r,
|
|
|
|
_FAT_seek_r,
|
|
|
|
_FAT_fstat_r,
|
|
|
|
_FAT_stat_r,
|
|
|
|
_FAT_link_r,
|
|
|
|
_FAT_unlink_r,
|
2006-08-14 13:59:25 +02:00
|
|
|
_FAT_chdir_r,
|
|
|
|
_FAT_rename_r,
|
|
|
|
_FAT_mkdir_r,
|
|
|
|
sizeof (DIR_STATE_STRUCT),
|
|
|
|
_FAT_diropen_r,
|
|
|
|
_FAT_dirreset_r,
|
|
|
|
_FAT_dirnext_r,
|
2007-10-25 14:52:08 +02:00
|
|
|
_FAT_dirclose_r,
|
2008-11-20 06:22:28 +01:00
|
|
|
_FAT_statvfs_r,
|
|
|
|
_FAT_ftruncate_r,
|
|
|
|
_FAT_fsync_r,
|
2010-03-21 12:09:34 +01:00
|
|
|
NULL, /* Device data */
|
|
|
|
NULL,
|
|
|
|
NULL
|
2006-07-14 04:42:37 +02:00
|
|
|
};
|
|
|
|
|
2009-05-18 00:16:35 +02:00
|
|
|
bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage) {
|
2008-11-20 06:22:28 +01:00
|
|
|
PARTITION* partition;
|
|
|
|
devoptab_t* devops;
|
|
|
|
char* nameCopy;
|
2009-05-30 18:22:09 +02:00
|
|
|
|
2009-10-17 22:29:48 +02:00
|
|
|
if(!name || !interface)
|
|
|
|
return false;
|
|
|
|
|
2009-05-30 17:54:52 +02:00
|
|
|
if(!interface->startup())
|
|
|
|
return false;
|
|
|
|
|
2009-10-17 22:29:48 +02:00
|
|
|
if(!interface->isInserted())
|
2009-05-30 17:54:52 +02:00
|
|
|
return false;
|
|
|
|
|
2008-11-20 06:22:28 +01:00
|
|
|
devops = _FAT_mem_allocate (sizeof(devoptab_t) + strlen(name) + 1);
|
|
|
|
if (!devops) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Use the space allocated at the end of the devoptab struct for storing the name
|
|
|
|
nameCopy = (char*)(devops+1);
|
|
|
|
|
|
|
|
// Initialize the file system
|
2009-05-18 00:16:35 +02:00
|
|
|
partition = _FAT_partition_constructor (interface, cacheSize, SectorsPerPage, startSector);
|
2008-11-20 06:22:28 +01:00
|
|
|
if (!partition) {
|
|
|
|
_FAT_mem_free (devops);
|
|
|
|
return false;
|
|
|
|
}
|
2009-05-30 18:22:09 +02:00
|
|
|
|
2008-11-20 06:22:28 +01:00
|
|
|
// Add an entry for this device to the devoptab table
|
|
|
|
memcpy (devops, &dotab_fat, sizeof(dotab_fat));
|
|
|
|
strcpy (nameCopy, name);
|
|
|
|
devops->name = nameCopy;
|
|
|
|
devops->deviceData = partition;
|
2009-05-30 18:22:09 +02:00
|
|
|
|
2008-11-20 06:22:28 +01:00
|
|
|
AddDevice (devops);
|
2009-05-30 18:22:09 +02:00
|
|
|
|
2008-11-20 06:22:28 +01:00
|
|
|
return true;
|
|
|
|
}
|
2008-05-10 21:35:18 +02:00
|
|
|
|
2008-11-20 06:22:28 +01:00
|
|
|
bool fatMountSimple (const char* name, const DISC_INTERFACE* interface) {
|
2009-05-18 00:16:35 +02:00
|
|
|
return fatMount (name, interface, 0, DEFAULT_CACHE_PAGES, DEFAULT_SECTORS_PAGE);
|
2008-11-20 06:22:28 +01:00
|
|
|
}
|
2006-07-14 04:42:37 +02:00
|
|
|
|
2008-11-20 06:22:28 +01:00
|
|
|
void fatUnmount (const char* name) {
|
|
|
|
devoptab_t *devops;
|
|
|
|
PARTITION* partition;
|
2009-05-30 18:22:09 +02:00
|
|
|
|
2009-10-17 22:29:48 +02:00
|
|
|
if(!name)
|
|
|
|
return;
|
|
|
|
|
2008-11-20 06:22:28 +01:00
|
|
|
devops = (devoptab_t*)GetDeviceOpTab (name);
|
|
|
|
if (!devops) {
|
|
|
|
return;
|
|
|
|
}
|
2009-05-30 18:22:09 +02:00
|
|
|
|
2008-11-20 06:22:28 +01:00
|
|
|
// Perform a quick check to make sure we're dealing with a libfat controlled device
|
|
|
|
if (devops->open_r != dotab_fat.open_r) {
|
|
|
|
return;
|
|
|
|
}
|
2009-05-30 18:22:09 +02:00
|
|
|
|
2009-05-30 17:54:52 +02:00
|
|
|
if (RemoveDevice (name) == -1) {
|
2008-11-20 06:22:28 +01:00
|
|
|
return;
|
|
|
|
}
|
2009-05-30 18:22:09 +02:00
|
|
|
|
2008-11-20 06:22:28 +01:00
|
|
|
partition = (PARTITION*)devops->deviceData;
|
|
|
|
_FAT_partition_destructor (partition);
|
|
|
|
_FAT_mem_free (devops);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
|
|
|
|
int i;
|
|
|
|
int defaultDevice = -1;
|
|
|
|
const DISC_INTERFACE *disc;
|
|
|
|
|
2009-05-30 18:22:09 +02:00
|
|
|
for (i = 0;
|
|
|
|
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
|
2008-11-20 06:22:28 +01:00
|
|
|
i++)
|
|
|
|
{
|
|
|
|
disc = _FAT_disc_interfaces[i].getInterface();
|
2009-05-30 17:54:52 +02:00
|
|
|
if (fatMount (_FAT_disc_interfaces[i].name, disc, 0, cacheSize, DEFAULT_SECTORS_PAGE)) {
|
2008-11-20 06:22:28 +01:00
|
|
|
// The first device to successfully mount is set as the default
|
|
|
|
if (defaultDevice < 0) {
|
|
|
|
defaultDevice = i;
|
2008-05-10 21:35:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-05-30 18:22:09 +02:00
|
|
|
|
2008-11-20 06:22:28 +01:00
|
|
|
if (defaultDevice < 0) {
|
|
|
|
// None of our devices mounted
|
|
|
|
return false;
|
|
|
|
}
|
2009-05-30 18:22:09 +02:00
|
|
|
|
2006-07-14 04:42:37 +02:00
|
|
|
if (setAsDefaultDevice) {
|
2008-11-20 06:22:28 +01:00
|
|
|
char filePath[MAXPATHLEN * 2];
|
|
|
|
strcpy (filePath, _FAT_disc_interfaces[defaultDevice].name);
|
|
|
|
strcat (filePath, ":/");
|
|
|
|
#ifdef ARGV_MAGIC
|
2009-05-30 18:22:09 +02:00
|
|
|
if ( __system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 && strrchr( __system_argv->argv[0], '/' )!=NULL ) {
|
2008-11-20 06:22:28 +01:00
|
|
|
// Check the app's path against each of our mounted devices, to see
|
|
|
|
// if we can support it. If so, change to that path.
|
2009-05-30 18:22:09 +02:00
|
|
|
for (i = 0;
|
|
|
|
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
|
2008-11-20 06:22:28 +01:00
|
|
|
i++)
|
|
|
|
{
|
2009-05-30 18:22:09 +02:00
|
|
|
if ( !strncasecmp( __system_argv->argv[0], _FAT_disc_interfaces[i].name,
|
|
|
|
strlen(_FAT_disc_interfaces[i].name)))
|
2008-11-20 06:22:28 +01:00
|
|
|
{
|
|
|
|
char *lastSlash;
|
|
|
|
strcpy(filePath, __system_argv->argv[0]);
|
|
|
|
lastSlash = strrchr( filePath, '/' );
|
|
|
|
|
|
|
|
if ( NULL != lastSlash) {
|
|
|
|
if ( *(lastSlash - 1) == ':') lastSlash++;
|
|
|
|
*lastSlash = 0;
|
|
|
|
}
|
2008-05-23 12:37:33 +02:00
|
|
|
}
|
|
|
|
}
|
2008-05-10 21:35:18 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
chdir (filePath);
|
2006-07-14 04:42:37 +02:00
|
|
|
}
|
2008-05-23 21:37:46 +02:00
|
|
|
|
2006-07-14 04:42:37 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-07-16 09:37:24 +02:00
|
|
|
bool fatInitDefault (void) {
|
2008-05-10 21:35:18 +02:00
|
|
|
return fatInit (DEFAULT_CACHE_PAGES, true);
|
2006-07-16 09:37:24 +02:00
|
|
|
}
|
|
|
|
|
2009-10-17 22:29:48 +02:00
|
|
|
void fatGetVolumeLabel (const char* name, char *label) {
|
|
|
|
devoptab_t *devops;
|
|
|
|
PARTITION* partition;
|
|
|
|
char *buf;
|
|
|
|
int namelen,i;
|
|
|
|
|
|
|
|
if(!name || !label)
|
|
|
|
return;
|
|
|
|
|
|
|
|
namelen = strlen(name);
|
2010-02-11 11:08:16 +01:00
|
|
|
buf=(char*)_FAT_mem_allocate(sizeof(char)*namelen+2);
|
2009-10-17 22:29:48 +02:00
|
|
|
strcpy(buf,name);
|
|
|
|
|
|
|
|
if (name[namelen-1] == '/') {
|
|
|
|
buf[namelen-1]='\0';
|
|
|
|
namelen--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name[namelen-1] != ':') {
|
|
|
|
buf[namelen]=':';
|
|
|
|
buf[namelen+1]='\0';
|
|
|
|
}
|
2006-07-14 04:42:37 +02:00
|
|
|
|
2009-10-17 22:29:48 +02:00
|
|
|
devops = (devoptab_t*)GetDeviceOpTab(buf);
|
|
|
|
|
|
|
|
for(i=0;buf[i]!='\0' && buf[i]!=':';i++);
|
|
|
|
if (!devops || strncasecmp(buf,devops->name,i)) {
|
2010-03-21 12:09:34 +01:00
|
|
|
_FAT_mem_free(buf);
|
2009-10-17 22:29:48 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-03-21 12:09:34 +01:00
|
|
|
_FAT_mem_free(buf);
|
2009-10-17 22:29:48 +02:00
|
|
|
|
|
|
|
// Perform a quick check to make sure we're dealing with a libfat controlled device
|
|
|
|
if (devops->open_r != dotab_fat.open_r) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
partition = (PARTITION*)devops->deviceData;
|
|
|
|
|
|
|
|
if(!_FAT_directory_getVolumeLabel(partition, label)) {
|
|
|
|
strncpy(label,partition->label,11);
|
|
|
|
label[11]='\0';
|
|
|
|
}
|
|
|
|
if(!strncmp(label, "NO NAME", 7)) label[0]='\0';
|
|
|
|
}
|