You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1493 lines
33 KiB
C
1493 lines
33 KiB
C
/*
|
|
* FreeRTOS+FAT FS V1.0.0 (C) 2013 HCC Embedded
|
|
*
|
|
* The FreeRTOS+FAT SL license terms are different to the FreeRTOS license
|
|
* terms.
|
|
*
|
|
* FreeRTOS+FAT SL uses a dual license model that allows the software to be used
|
|
* under a pure GPL open source license (as opposed to the modified GPL licence
|
|
* under which FreeRTOS is distributed) or a commercial license. Details of
|
|
* both license options follow:
|
|
*
|
|
* - Open source licensing -
|
|
* FreeRTOS+FAT SL is a free download and may be used, modified, evaluated and
|
|
* distributed without charge provided the user adheres to version two of the
|
|
* GNU General Public License (GPL) and does not remove the copyright notice or
|
|
* this text. The GPL V2 text is available on the gnu.org web site, and on the
|
|
* following URL: http://www.FreeRTOS.org/gpl-2.0.txt.
|
|
*
|
|
* - Commercial licensing -
|
|
* Businesses and individuals who for commercial or other reasons cannot comply
|
|
* with the terms of the GPL V2 license must obtain a commercial license before
|
|
* incorporating FreeRTOS+FAT SL into proprietary software for distribution in
|
|
* any form. Commercial licenses can be purchased from
|
|
* http://shop.freertos.org/fat_sl and do not require any source files to be
|
|
* changed.
|
|
*
|
|
* FreeRTOS+FAT SL is distributed in the hope that it will be useful. You
|
|
* cannot use FreeRTOS+FAT SL unless you agree that you use the software 'as
|
|
* is'. FreeRTOS+FAT SL is provided WITHOUT ANY WARRANTY; without even the
|
|
* implied warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A
|
|
* PARTICULAR PURPOSE. Real Time Engineers Ltd. and HCC Embedded disclaims all
|
|
* conditions and terms, be they implied, expressed, or statutory.
|
|
*
|
|
* http://www.FreeRTOS.org
|
|
* http://www.FreeRTOS.org/FreeRTOS-Plus
|
|
*
|
|
*/
|
|
|
|
#include "../../api/fat_sl.h"
|
|
#include "../../psp/include/psp_string.h"
|
|
|
|
#include "util.h"
|
|
#include "volume.h"
|
|
#include "drv.h"
|
|
#include "fat.h"
|
|
#include "dir.h"
|
|
#include "file.h"
|
|
|
|
#include "../../version/ver_fat_sl.h"
|
|
#if VER_FAT_SL_MAJOR != 3 || VER_FAT_SL_MINOR != 2
|
|
#error Incompatible FAT_SL version number!
|
|
#endif
|
|
|
|
static unsigned char _f_emptywritebuffer ( void );
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_filelength
|
|
*
|
|
* Get a file length
|
|
*
|
|
* INPUTS
|
|
*
|
|
* filename - file whose length is needed
|
|
*
|
|
* RETURNS
|
|
*
|
|
* length of the file
|
|
*
|
|
***************************************************************************/
|
|
|
|
long fn_filelength ( const char * filename )
|
|
{
|
|
F_POS pos;
|
|
F_DIRENTRY * de;
|
|
F_NAME fsname;
|
|
|
|
if ( _f_setfsname( filename, &fsname ) )
|
|
{
|
|
return 0; /*invalid name*/
|
|
}
|
|
|
|
if ( _f_checknamewc( fsname.filename, fsname.fileext ) )
|
|
{
|
|
return 0; /*invalid name*/
|
|
}
|
|
|
|
if ( _f_getvolume() )
|
|
{
|
|
return 0; /*can't get the size*/
|
|
}
|
|
|
|
if ( !_f_findpath( &fsname, &pos ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( !_f_findfilewc( fsname.filename, fsname.fileext, &pos, &de, 0 ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( de->attr & F_ATTR_DIR )
|
|
{
|
|
return 0; /*directory*/
|
|
}
|
|
|
|
return (long)_f_getlong( &de->filesize );
|
|
} /* fn_filelength */
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_emptywritebuffer
|
|
*
|
|
* empty write buffer if it contains unwritten data
|
|
*
|
|
* RETURNS
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
|
|
|
|
static unsigned char _f_emptywritebuffer ( void )
|
|
{
|
|
unsigned char ret;
|
|
|
|
ret = _f_writeglsector( gl_file.pos.sector );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
gl_file.modified = 0;
|
|
|
|
gl_file.pos.sector++;
|
|
|
|
if ( gl_file.pos.sector >= gl_file.pos.sectorend )
|
|
{
|
|
unsigned long value;
|
|
|
|
gl_volume.fatsector = (unsigned long)-1;
|
|
ret = _f_getclustervalue( gl_file.pos.cluster, &value );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( ( value >= 2 ) && ( value < F_CLUSTER_RESERVED ) ) /*we are in chain*/
|
|
{
|
|
gl_file.prevcluster = gl_file.pos.cluster;
|
|
_f_clustertopos( value, &gl_file.pos ); /*go to next cluster*/
|
|
}
|
|
else
|
|
{
|
|
unsigned long nextcluster;
|
|
|
|
ret = _f_alloccluster( &nextcluster );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = _f_setclustervalue( nextcluster, F_CLUSTER_LAST );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = _f_setclustervalue( gl_file.pos.cluster, nextcluster );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
gl_file.prevcluster = gl_file.pos.cluster;
|
|
|
|
_f_clustertopos( nextcluster, &gl_file.pos );
|
|
|
|
return _f_writefatsector();
|
|
}
|
|
}
|
|
|
|
|
|
return F_NO_ERROR;
|
|
} /* _f_emptywritebuffer */
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_extend
|
|
*
|
|
* Extend file to a certain size
|
|
*
|
|
***************************************************************************/
|
|
static unsigned char _f_extend ( long size )
|
|
{
|
|
unsigned long _size;
|
|
unsigned char rc;
|
|
|
|
size -= gl_file.filesize;
|
|
_size = (unsigned long)size;
|
|
|
|
rc = _f_getcurrsector();
|
|
if ( rc )
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
psp_memset( gl_sector + gl_file.relpos, 0, ( F_SECTOR_SIZE - gl_file.relpos ) );
|
|
|
|
if ( gl_file.relpos + _size > F_SECTOR_SIZE )
|
|
{
|
|
_size -= ( F_SECTOR_SIZE - gl_file.relpos );
|
|
while ( _size )
|
|
{
|
|
if ( _f_emptywritebuffer() )
|
|
{
|
|
return F_ERR_WRITE;
|
|
}
|
|
|
|
psp_memset( gl_sector, 0, F_SECTOR_SIZE );
|
|
_size -= ( _size > F_SECTOR_SIZE ? F_SECTOR_SIZE : _size );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_size += gl_file.relpos;
|
|
}
|
|
|
|
gl_file.modified = 1;
|
|
gl_file.filesize += size;
|
|
gl_file.abspos = gl_file.filesize & ( ~( F_SECTOR_SIZE - 1 ) );
|
|
gl_file.relpos = _size;
|
|
|
|
return F_NO_ERROR;
|
|
} /* _f_extend */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_fseek
|
|
*
|
|
* subfunction for f_seek it moves position into given offset and read
|
|
* the current sector
|
|
*
|
|
* INPUTS
|
|
* offset - position from start
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
static unsigned char _f_fseek ( long offset )
|
|
{
|
|
unsigned long cluster;
|
|
unsigned long tmp;
|
|
unsigned char ret = F_NO_ERROR;
|
|
long remain;
|
|
|
|
if ( offset < 0 )
|
|
{
|
|
offset = 0;
|
|
}
|
|
|
|
if ( ( (unsigned long) offset <= gl_file.filesize )
|
|
&& ( (unsigned long) offset >= gl_file.abspos )
|
|
&& ( (unsigned long) offset < gl_file.abspos + F_SECTOR_SIZE ) )
|
|
{
|
|
gl_file.relpos = (unsigned short)( offset - gl_file.abspos );
|
|
}
|
|
else
|
|
{
|
|
if ( gl_file.modified )
|
|
{
|
|
ret = _f_writeglsector( (unsigned long)-1 );
|
|
if ( ret )
|
|
{
|
|
gl_file.mode = F_FILE_CLOSE; /*cant accessed any more*/
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
if ( gl_file.startcluster )
|
|
{
|
|
gl_file.abspos = 0;
|
|
gl_file.relpos = 0;
|
|
gl_file.prevcluster = 0;
|
|
gl_file.pos.cluster = gl_file.startcluster;
|
|
remain = gl_file.filesize;
|
|
|
|
tmp = gl_volume.bootrecord.sector_per_cluster;
|
|
tmp *= F_SECTOR_SIZE; /* set to cluster size */
|
|
|
|
/*calc cluster*/
|
|
gl_volume.fatsector = (unsigned long)-1;
|
|
while ( (unsigned long)offset >= tmp )
|
|
{
|
|
ret = _f_getclustervalue( gl_file.pos.cluster, &cluster );
|
|
if ( ret )
|
|
{
|
|
gl_file.mode = F_FILE_CLOSE;
|
|
return ret;
|
|
}
|
|
|
|
if ( (long) tmp >= remain )
|
|
{
|
|
break;
|
|
}
|
|
|
|
remain -= tmp;
|
|
offset -= tmp;
|
|
gl_file.abspos += tmp;
|
|
if ( cluster >= F_CLUSTER_RESERVED )
|
|
{
|
|
break;
|
|
}
|
|
|
|
gl_file.prevcluster = gl_file.pos.cluster;
|
|
gl_file.pos.cluster = cluster;
|
|
}
|
|
|
|
_f_clustertopos( gl_file.pos.cluster, &gl_file.pos );
|
|
if ( remain && offset )
|
|
{
|
|
while ( ( offset > (long) F_SECTOR_SIZE )
|
|
&& ( remain > (long) F_SECTOR_SIZE ) )
|
|
{
|
|
gl_file.pos.sector++;
|
|
offset -= F_SECTOR_SIZE;
|
|
remain -= F_SECTOR_SIZE;
|
|
gl_file.abspos += F_SECTOR_SIZE;
|
|
}
|
|
}
|
|
|
|
if ( remain < offset )
|
|
{
|
|
gl_file.relpos = (unsigned short)remain;
|
|
ret = _f_extend( gl_file.filesize + offset - remain );
|
|
}
|
|
else
|
|
{
|
|
gl_file.relpos = (unsigned short)offset;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
} /* _f_fseek */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_open
|
|
*
|
|
* open a file for reading/writing/appending
|
|
*
|
|
* INPUTS
|
|
*
|
|
* filename - which file need to be opened
|
|
* mode - string how to open ("r"-read, "w"-write, "w+"-overwrite, "a"-append
|
|
*
|
|
* RETURNS
|
|
*
|
|
* F_FILE pointer if successfully
|
|
* 0 - if any error
|
|
*
|
|
***************************************************************************/
|
|
F_FILE * fn_open ( const char * filename, const char * mode )
|
|
{
|
|
F_DIRENTRY * de;
|
|
F_NAME fsname;
|
|
unsigned short date;
|
|
unsigned short time;
|
|
unsigned char m_mode = F_FILE_CLOSE;
|
|
|
|
if ( mode[1] == 0 )
|
|
{
|
|
if ( mode[0] == 'r' )
|
|
{
|
|
m_mode = F_FILE_RD;
|
|
}
|
|
|
|
if ( mode[0] == 'w' )
|
|
{
|
|
m_mode = F_FILE_WR;
|
|
}
|
|
|
|
if ( mode[0] == 'a' )
|
|
{
|
|
m_mode = F_FILE_A;
|
|
}
|
|
}
|
|
|
|
if ( ( mode[1] == '+' ) && ( mode[2] == 0 ) )
|
|
{
|
|
if ( mode[0] == 'r' )
|
|
{
|
|
m_mode = F_FILE_RDP;
|
|
}
|
|
|
|
if ( mode[0] == 'w' )
|
|
{
|
|
m_mode = F_FILE_WRP;
|
|
}
|
|
|
|
if ( mode[0] == 'a' )
|
|
{
|
|
m_mode = F_FILE_AP;
|
|
}
|
|
|
|
}
|
|
|
|
if ( m_mode == F_FILE_CLOSE )
|
|
{
|
|
return 0; /*invalid mode*/
|
|
}
|
|
|
|
if ( _f_setfsname( filename, &fsname ) )
|
|
{
|
|
return 0; /*invalid name*/
|
|
}
|
|
|
|
if ( _f_checknamewc( fsname.filename, fsname.fileext ) )
|
|
{
|
|
return 0; /*invalid name*/
|
|
}
|
|
|
|
if ( fsname.filename[0] == '.' )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( _f_getvolume() )
|
|
{
|
|
return 0; /*cant open any*/
|
|
}
|
|
|
|
if ( gl_file.mode != F_FILE_CLOSE )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
psp_memset( &gl_file, 0, 21 );
|
|
|
|
if ( !_f_findpath( &fsname, &gl_file.dirpos ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
switch ( m_mode )
|
|
{
|
|
case F_FILE_RDP: /*r*/
|
|
case F_FILE_RD: /*r*/
|
|
if ( !_f_findfilewc( fsname.filename, fsname.fileext, &gl_file.dirpos, &de, 0 ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( de->attr & F_ATTR_DIR )
|
|
{
|
|
return 0; /*directory*/
|
|
}
|
|
|
|
gl_file.startcluster = _f_getdecluster( de );
|
|
|
|
if ( gl_file.startcluster )
|
|
{
|
|
_f_clustertopos( gl_file.startcluster, &gl_file.pos );
|
|
gl_file.filesize = _f_getlong( &de->filesize );
|
|
gl_file.abspos = (unsigned long) (-1 * (long) F_SECTOR_SIZE);
|
|
if ( _f_fseek( 0 ) )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#if F_FILE_CHANGED_EVENT
|
|
if ( m_mode == F_FILE_RDP )
|
|
{
|
|
_f_createfullname( gl_file.filename, sizeof( gl_file.filename ), fsname.path, fsname.filename, fsname.fileext );
|
|
}
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case F_FILE_AP:
|
|
case F_FILE_A: /*a*/
|
|
psp_memcpy( &( gl_file.pos ), &( gl_file.dirpos ), sizeof( F_POS ) );
|
|
if ( _f_findfilewc( fsname.filename, fsname.fileext, &gl_file.dirpos, &de, 0 ) )
|
|
{
|
|
if ( de->attr & ( F_ATTR_DIR | F_ATTR_READONLY ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
gl_file.startcluster = _f_getdecluster( de );
|
|
gl_file.filesize = _f_getlong( &de->filesize );
|
|
|
|
if ( gl_file.startcluster )
|
|
{
|
|
_f_clustertopos( gl_file.startcluster, &gl_file.pos );
|
|
gl_file.abspos = (unsigned long) (-1 * (long) F_SECTOR_SIZE); /*forcing seek to read 1st sector! abspos=0;*/
|
|
if ( _f_fseek( (long)gl_file.filesize ) )
|
|
{
|
|
gl_file.mode = F_FILE_CLOSE;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
psp_memcpy( &( gl_file.dirpos ), &( gl_file.pos ), sizeof( F_POS ) );
|
|
_f_clustertopos( gl_file.dirpos.cluster, &gl_file.pos );
|
|
|
|
if ( _f_addentry( &fsname, &gl_file.dirpos, &de ) )
|
|
{
|
|
return 0; /*couldnt be added*/
|
|
}
|
|
|
|
de->attr |= F_ATTR_ARC; /*set as archiv*/
|
|
if ( _f_writeglsector( (unsigned long)-1 ) )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#if F_FILE_CHANGED_EVENT
|
|
_f_createfullname( gl_file.filename, sizeof( gl_file.filename ), fsname.path, fsname.filename, fsname.fileext );
|
|
#endif
|
|
break;
|
|
|
|
|
|
case F_FILE_WR: /*w*/
|
|
case F_FILE_WRP: /*w+*/
|
|
_f_clustertopos( gl_file.dirpos.cluster, &gl_file.pos );
|
|
if ( _f_findfilewc( fsname.filename, fsname.fileext, &gl_file.pos, &de, 0 ) )
|
|
{
|
|
unsigned long cluster = _f_getdecluster( de ); /*exist*/
|
|
|
|
if ( de->attr & ( F_ATTR_DIR | F_ATTR_READONLY ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
psp_memcpy( &( gl_file.dirpos ), &( gl_file.pos ), sizeof( F_POS ) );
|
|
|
|
_f_setlong( de->filesize, 0 ); /*reset size;*/
|
|
de->attr |= F_ATTR_ARC; /*set as archiv*/
|
|
_f_setword( de->clusterlo, 0 ); /*no points anywhere*/
|
|
_f_setword( de->clusterhi, 0 );
|
|
|
|
if ( gl_volume.mediatype == F_FAT32_MEDIA )
|
|
{
|
|
f_igettimedate( &time, &date );
|
|
_f_setword( &de->crtdate, date ); /*if there is realtime clock then creation date could be set from*/
|
|
_f_setword( &de->crttime, time ); /*if there is realtime clock then creation time could be set from*/
|
|
_f_setword( &de->lastaccessdate, date ); /*if there is realtime clock then creation date could be set from*/
|
|
}
|
|
|
|
if ( _f_writeglsector( (unsigned long)-1 ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( _f_removechain( cluster ) )
|
|
{
|
|
return 0; /*remove */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( _f_addentry( &fsname, &gl_file.dirpos, &de ) )
|
|
{
|
|
return 0; /*couldnt be added*/
|
|
}
|
|
|
|
psp_memset( &gl_file, 0, 21 );
|
|
de->attr |= F_ATTR_ARC; /*set as archiv*/
|
|
if ( _f_writeglsector( (unsigned long)-1 ) )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#if F_FILE_CHANGED_EVENT
|
|
_f_createfullname( gl_file.filename, sizeof( gl_file.filename ), fsname.path, fsname.filename, fsname.fileext );
|
|
#endif
|
|
|
|
break;
|
|
|
|
default:
|
|
return 0; /*invalid mode*/
|
|
} /* switch */
|
|
|
|
if ( ( m_mode != F_FILE_RD ) && ( gl_file.startcluster == 0 ) )
|
|
{
|
|
gl_volume.fatsector = (unsigned long)-1;
|
|
if ( _f_alloccluster( &( gl_file.startcluster ) ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
_f_clustertopos( gl_file.startcluster, &gl_file.pos );
|
|
if ( _f_setclustervalue( gl_file.startcluster, F_CLUSTER_LAST ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( _f_writefatsector() )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
gl_file.mode = m_mode; /* lock it */
|
|
return (F_FILE *)1;
|
|
} /* fn_open */
|
|
|
|
|
|
/****************************************************************************
|
|
* _f_updatefileentry
|
|
* Updated a file directory entry or removes the entry
|
|
* and the fat chain belonging to it.
|
|
***************************************************************************/
|
|
static unsigned char _f_updatefileentry ( int remove )
|
|
{
|
|
F_DIRENTRY * de;
|
|
unsigned short date;
|
|
unsigned short time;
|
|
|
|
de = (F_DIRENTRY *)( gl_sector + sizeof( F_DIRENTRY ) * gl_file.dirpos.pos );
|
|
if ( _f_readglsector( gl_file.dirpos.sector ) || remove )
|
|
{
|
|
_f_setdecluster( de, 0 );
|
|
_f_setlong( &de->filesize, 0 );
|
|
(void)_f_writeglsector( (unsigned long)-1 );
|
|
(void)_f_removechain( gl_file.startcluster );
|
|
return F_ERR_WRITE;
|
|
}
|
|
|
|
_f_setdecluster( de, gl_file.startcluster );
|
|
_f_setlong( &de->filesize, gl_file.filesize );
|
|
f_igettimedate( &time, &date );
|
|
_f_setword( &de->cdate, date ); /*if there is realtime clock then creation date could be set from*/
|
|
_f_setword( &de->ctime, time ); /*if there is realtime clock then creation time could be set from*/
|
|
if ( gl_volume.mediatype == F_FAT32_MEDIA )
|
|
{
|
|
_f_setword( &de->lastaccessdate, date ); /*if there is realtime clock then creation date could be set from*/
|
|
}
|
|
|
|
return _f_writeglsector( (unsigned long)-1 );
|
|
} /* _f_updatefileentry */
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_close
|
|
*
|
|
* close a previously opened file
|
|
*
|
|
* INPUTS
|
|
*
|
|
* filehandle - which file needs to be closed
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char fn_close ( F_FILE * f )
|
|
{
|
|
unsigned char ret;
|
|
|
|
#if F_FILE_CHANGED_EVENT
|
|
unsigned char mode;
|
|
#endif
|
|
|
|
if ( !f )
|
|
{
|
|
return F_ERR_NOTOPEN;
|
|
}
|
|
|
|
ret = _f_getvolume();
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( gl_file.mode == F_FILE_CLOSE )
|
|
{
|
|
return F_ERR_NOTOPEN;
|
|
}
|
|
|
|
else if ( gl_file.mode == F_FILE_RD )
|
|
{
|
|
gl_file.mode = F_FILE_CLOSE;
|
|
return F_NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
#if F_FILE_CHANGED_EVENT
|
|
mode = f->mode;
|
|
#endif
|
|
gl_file.mode = F_FILE_CLOSE;
|
|
|
|
if ( gl_file.modified )
|
|
{
|
|
if ( _f_writeglsector( (unsigned long)-1 ) )
|
|
{
|
|
(void)_f_updatefileentry( 1 );
|
|
return F_ERR_WRITE;
|
|
}
|
|
}
|
|
|
|
ret = _f_updatefileentry( 0 );
|
|
|
|
#if F_FILE_CHANGED_EVENT
|
|
if ( f_filechangedevent && !ret )
|
|
{
|
|
ST_FILE_CHANGED fc;
|
|
if ( ( mode == F_FILE_WR ) || ( mode == F_FILE_WRP ) )
|
|
{
|
|
fc.action = FACTION_ADDED;
|
|
fc.flags = FFLAGS_FILE_NAME;
|
|
}
|
|
else if ( ( mode == F_FILE_A ) || ( mode == F_FILE_RDP ) )
|
|
{
|
|
fc.action = FACTION_MODIFIED;
|
|
fc.flags = FFLAGS_FILE_NAME | FFLAGS_SIZE;
|
|
}
|
|
|
|
strcpy( fc.filename, f->filename );
|
|
if ( f->filename[0] )
|
|
{
|
|
f_filechangedevent( &fc );
|
|
}
|
|
|
|
f->filename[0] = '\0';
|
|
}
|
|
|
|
#endif /* if F_FILE_CHANGED_EVENT */
|
|
return ret;
|
|
}
|
|
} /* fn_close */
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_flush
|
|
*
|
|
* flush a previously opened file
|
|
*
|
|
* INPUTS
|
|
*
|
|
* filehandle - which file needs to be closed
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char fn_flush ( F_FILE * f )
|
|
{
|
|
unsigned char ret;
|
|
|
|
if ( !f )
|
|
{
|
|
return F_ERR_NOTOPEN;
|
|
}
|
|
|
|
ret = _f_getvolume();
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( gl_file.mode == F_FILE_CLOSE )
|
|
{
|
|
return F_ERR_NOTOPEN;
|
|
}
|
|
else if ( gl_file.mode != F_FILE_RD )
|
|
{
|
|
if ( gl_file.modified )
|
|
{
|
|
if ( _f_writeglsector( (unsigned long)-1 ) )
|
|
{
|
|
(void)_f_updatefileentry( 1 );
|
|
return F_ERR_WRITE;
|
|
}
|
|
}
|
|
|
|
return _f_updatefileentry( 0 );
|
|
}
|
|
|
|
return F_NO_ERROR;
|
|
} /* fn_flush */
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_read
|
|
*
|
|
* read data from file
|
|
*
|
|
* INPUTS
|
|
*
|
|
* buf - where the store data
|
|
* size - size of items to be read
|
|
* _size_t - number of items need to be read
|
|
* filehandle - file where to read from
|
|
*
|
|
* RETURNS
|
|
*
|
|
* with the number of read bytes
|
|
*
|
|
***************************************************************************/
|
|
long fn_read ( void * buf, long size, long _size_st, F_FILE * f )
|
|
{
|
|
char * buffer = (char *)buf;
|
|
long retsize;
|
|
|
|
if ( !f )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( ( gl_file.mode & ( F_FILE_RD | F_FILE_RDP | F_FILE_WRP | F_FILE_AP ) ) == 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
retsize = size;
|
|
size *= _size_st;
|
|
_size_st = retsize;
|
|
retsize = 0;
|
|
|
|
if ( _f_getvolume() )
|
|
{
|
|
return 0; /*cant read any*/
|
|
}
|
|
|
|
if ( size + gl_file.relpos + gl_file.abspos >= gl_file.filesize ) /*read len longer than the file*/
|
|
{
|
|
size = (long)( ( gl_file.filesize ) - ( gl_file.relpos ) - ( gl_file.abspos ) ); /*calculate new size*/
|
|
}
|
|
|
|
if ( size <= 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( _f_getcurrsector() )
|
|
{
|
|
gl_file.mode = F_FILE_CLOSE; /*no more read allowed*/
|
|
return 0;
|
|
}
|
|
|
|
for( ; ; )
|
|
{
|
|
unsigned long rdsize = (unsigned long)size;
|
|
|
|
if ( gl_file.relpos == F_SECTOR_SIZE )
|
|
{
|
|
unsigned char ret;
|
|
|
|
gl_file.abspos += gl_file.relpos;
|
|
gl_file.relpos = 0;
|
|
|
|
if ( gl_file.modified )
|
|
{
|
|
ret = _f_writeglsector( (unsigned long)-1 ); /*empty write buffer */
|
|
if ( ret )
|
|
{
|
|
gl_file.mode = F_FILE_CLOSE; /*no more read allowed*/
|
|
return retsize;
|
|
}
|
|
}
|
|
|
|
gl_file.pos.sector++; /*goto next*/
|
|
|
|
ret = _f_getcurrsector();
|
|
if ( ( ret == F_ERR_EOF ) && ( !size ) )
|
|
{
|
|
return retsize;
|
|
}
|
|
|
|
if ( ret )
|
|
{
|
|
gl_file.mode = F_FILE_CLOSE; /*no more read allowed*/
|
|
return retsize;
|
|
}
|
|
}
|
|
|
|
if ( !size )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ( rdsize >= F_SECTOR_SIZE - gl_file.relpos )
|
|
{
|
|
rdsize = (unsigned long)( F_SECTOR_SIZE - gl_file.relpos );
|
|
}
|
|
|
|
psp_memcpy( buffer, gl_sector + gl_file.relpos, rdsize ); /*always less than 512*/
|
|
|
|
buffer += rdsize;
|
|
gl_file.relpos += rdsize;
|
|
size -= rdsize;
|
|
retsize += rdsize;
|
|
}
|
|
|
|
return retsize / _size_st;
|
|
} /* fn_read */
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_write
|
|
*
|
|
* write data into file
|
|
*
|
|
* INPUTS
|
|
*
|
|
* buf - where the store data
|
|
* size - size of items to be read
|
|
* size_t - number of items need to be read
|
|
* filehandle - file where to read from
|
|
*
|
|
* RETURNS
|
|
*
|
|
* with the number of read bytes
|
|
*
|
|
***************************************************************************/
|
|
|
|
long fn_write ( const void * buf, long size, long _size_st, F_FILE * f )
|
|
{
|
|
char * buffer = (char *)buf;
|
|
long retsize;
|
|
long ret = 0;
|
|
|
|
if ( !f )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( ( gl_file.mode & ( F_FILE_WR | F_FILE_A | F_FILE_RDP | F_FILE_WRP | F_FILE_AP ) ) == 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
retsize = size;
|
|
size *= _size_st;
|
|
_size_st = retsize;
|
|
retsize = 0;
|
|
|
|
if ( _f_getvolume() )
|
|
{
|
|
return 0; /*can't write*/
|
|
}
|
|
|
|
if ( ( gl_file.mode ) & ( F_FILE_A | F_FILE_AP ) )
|
|
{
|
|
if ( _f_fseek( (long)gl_file.filesize ) )
|
|
{
|
|
gl_file.mode = F_FILE_CLOSE;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if ( _f_getcurrsector() )
|
|
{
|
|
gl_file.mode = F_FILE_CLOSE;
|
|
return 0;
|
|
}
|
|
|
|
for( ; ; )
|
|
{
|
|
unsigned long wrsize = (unsigned long)size;
|
|
|
|
if ( gl_file.relpos == F_SECTOR_SIZE )
|
|
{ /*now full*/
|
|
if ( gl_file.modified )
|
|
{
|
|
if ( _f_emptywritebuffer() )
|
|
{
|
|
gl_file.mode = F_FILE_CLOSE;
|
|
if ( _f_updatefileentry( 0 ) == 0 )
|
|
{
|
|
return retsize;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gl_file.pos.sector++; /*goto next*/
|
|
}
|
|
|
|
gl_file.abspos += gl_file.relpos;
|
|
gl_file.relpos = 0;
|
|
|
|
if ( wrsize && ( wrsize < F_SECTOR_SIZE ) )
|
|
{
|
|
ret = _f_getcurrsector();
|
|
|
|
if ( ret )
|
|
{
|
|
if ( ret != F_ERR_EOF )
|
|
{
|
|
gl_file.mode = F_FILE_CLOSE; /*no more read allowed*/
|
|
return retsize;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !size )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ( wrsize >= F_SECTOR_SIZE - gl_file.relpos )
|
|
{
|
|
wrsize = (unsigned long)( F_SECTOR_SIZE - gl_file.relpos );
|
|
}
|
|
|
|
|
|
psp_memcpy( gl_sector + gl_file.relpos, buffer, wrsize );
|
|
gl_file.modified = 1; /*sector is modified*/
|
|
|
|
buffer += wrsize;
|
|
gl_file.relpos += wrsize;
|
|
size -= wrsize;
|
|
retsize += wrsize;
|
|
|
|
if ( gl_file.filesize < gl_file.abspos + gl_file.relpos )
|
|
{
|
|
gl_file.filesize = gl_file.abspos + gl_file.relpos;
|
|
}
|
|
}
|
|
|
|
return retsize / _size_st;
|
|
} /* fn_write */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_seek
|
|
*
|
|
* moves position into given offset in given file
|
|
*
|
|
* INPUTS
|
|
*
|
|
* filehandle - F_FILE structure which file position needed to be modified
|
|
* offset - relative position
|
|
* whence - where to calculate position (F_SEEK_SET,F_SEEK_CUR,F_SEEK_END)
|
|
*
|
|
* RETURNS
|
|
*
|
|
* 0 - if successfully
|
|
* other - if any error
|
|
*
|
|
***************************************************************************/
|
|
|
|
|
|
unsigned char fn_seek ( F_FILE * f, long offset, unsigned char whence )
|
|
{
|
|
unsigned char ret;
|
|
|
|
if ( !f )
|
|
{
|
|
return F_ERR_NOTOPEN;
|
|
}
|
|
|
|
if ( ( gl_file.mode & ( F_FILE_RD | F_FILE_WR | F_FILE_A | F_FILE_RDP | F_FILE_WRP | F_FILE_AP ) ) == 0 )
|
|
{
|
|
return F_ERR_NOTOPEN;
|
|
}
|
|
|
|
ret = _f_getvolume();
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( whence == F_SEEK_CUR )
|
|
{
|
|
return _f_fseek( (long)( gl_file.abspos + gl_file.relpos + offset ) );
|
|
}
|
|
else if ( whence == F_SEEK_END )
|
|
{
|
|
return _f_fseek( (long)( gl_file.filesize + offset ) );
|
|
}
|
|
else if ( whence == F_SEEK_SET )
|
|
{
|
|
return _f_fseek( offset );
|
|
}
|
|
|
|
return F_ERR_NOTUSEABLE;
|
|
} /* fn_seek */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_tell
|
|
*
|
|
* Tells the current position of opened file
|
|
*
|
|
* INPUTS
|
|
*
|
|
* filehandle - which file needs the position
|
|
*
|
|
* RETURNS
|
|
*
|
|
* position in the file from start
|
|
*
|
|
***************************************************************************/
|
|
|
|
long fn_tell ( F_FILE * f )
|
|
{
|
|
if ( !f )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( ( gl_file.mode & ( F_FILE_RD | F_FILE_WR | F_FILE_A | F_FILE_RDP | F_FILE_WRP | F_FILE_AP ) ) == 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return (long)( gl_file.abspos + gl_file.relpos );
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_eof
|
|
*
|
|
* Tells if the current position is end of file or not
|
|
*
|
|
* INPUTS
|
|
*
|
|
* filehandle - which file needs the checking
|
|
*
|
|
* RETURNS
|
|
*
|
|
* 0 - if not EOF
|
|
* other - if EOF or invalid file handle
|
|
*
|
|
***************************************************************************/
|
|
|
|
unsigned char fn_eof ( F_FILE * f )
|
|
{
|
|
if ( !f )
|
|
{
|
|
return F_ERR_NOTOPEN; /*if error*/
|
|
}
|
|
|
|
if ( gl_file.abspos + gl_file.relpos < gl_file.filesize )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return F_ERR_EOF; /*EOF*/
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_rewind
|
|
*
|
|
* set the fileposition in the opened file to the begining
|
|
*
|
|
* INPUTS
|
|
*
|
|
* filehandle - which file needs to be rewinded
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
|
|
unsigned char fn_rewind ( F_FILE * filehandle )
|
|
{
|
|
return fn_seek( filehandle, 0L, F_SEEK_SET );
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_putc
|
|
*
|
|
* write a character into file
|
|
*
|
|
* INPUTS
|
|
*
|
|
* ch - what to write into file
|
|
* filehandle - file where to write
|
|
*
|
|
* RETURNS
|
|
*
|
|
* with the number of written bytes (1-success, 0-not successfully)
|
|
*
|
|
***************************************************************************/
|
|
|
|
int fn_putc ( int ch, F_FILE * filehandle )
|
|
{
|
|
unsigned char tmpch = (unsigned char)ch;
|
|
|
|
if ( fn_write( &tmpch, 1, 1, filehandle ) )
|
|
{
|
|
return ch;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_getc
|
|
*
|
|
* get a character from file
|
|
*
|
|
* INPUTS
|
|
*
|
|
* filehandle - file where to read from
|
|
*
|
|
* RETURNS
|
|
*
|
|
* with the read character or -1 if read was not successfully
|
|
*
|
|
***************************************************************************/
|
|
int fn_getc ( F_FILE * filehandle )
|
|
{
|
|
unsigned char ch;
|
|
|
|
if ( !fn_read( &ch, 1, 1, filehandle ) )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return (int)ch;
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_delete
|
|
*
|
|
* delete a file
|
|
*
|
|
* INPUTS
|
|
*
|
|
* filename - file which wanted to be deleted (with or without path)
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char fn_delete ( const char * filename )
|
|
{
|
|
F_POS pos;
|
|
F_DIRENTRY * de;
|
|
F_NAME fsname;
|
|
unsigned char ret;
|
|
|
|
if ( _f_setfsname( filename, &fsname ) )
|
|
{
|
|
return F_ERR_INVALIDNAME; /*invalid name*/
|
|
}
|
|
|
|
if ( _f_checknamewc( fsname.filename, fsname.fileext ) )
|
|
{
|
|
return F_ERR_INVALIDNAME; /*invalid name*/
|
|
}
|
|
|
|
if ( fsname.filename[0] == '.' )
|
|
{
|
|
return F_ERR_NOTFOUND;
|
|
}
|
|
|
|
ret = _f_getvolume();
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( !( _f_findpath( &fsname, &pos ) ) )
|
|
{
|
|
return F_ERR_INVALIDDIR;
|
|
}
|
|
|
|
if ( !_f_findfilewc( fsname.filename, fsname.fileext, &pos, &de, 0 ) )
|
|
{
|
|
return F_ERR_NOTFOUND;
|
|
}
|
|
|
|
if ( de->attr & F_ATTR_DIR )
|
|
{
|
|
return F_ERR_INVALIDDIR; /*directory*/
|
|
}
|
|
|
|
if ( de->attr & F_ATTR_READONLY )
|
|
{
|
|
return F_ERR_ACCESSDENIED; /*readonly*/
|
|
}
|
|
|
|
if ( ( gl_file.mode != F_FILE_CLOSE ) && ( gl_file.dirpos.sector == pos.sector ) && ( gl_file.dirpos.pos == pos.pos ) )
|
|
{
|
|
return F_ERR_LOCKED;
|
|
}
|
|
|
|
de->name[0] = (unsigned char)0xe5; /*removes it*/
|
|
ret = _f_writeglsector( (unsigned long)-1 );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = _f_removechain( _f_getdecluster( de ) );
|
|
|
|
#if F_FILE_CHANGED_EVENT
|
|
if ( f_filechangedevent && !ret )
|
|
{
|
|
ST_FILE_CHANGED fc;
|
|
fc.action = FACTION_REMOVED;
|
|
fc.flags = FFLAGS_FILE_NAME;
|
|
|
|
if ( !_f_createfullname( fc.filename, sizeof( fc.filename ), fsname.path, fsname.filename, fsname.fileext ) )
|
|
{
|
|
f_filechangedevent( &fc );
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
return ret;
|
|
} /* fn_delete */
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_seteof
|
|
*
|
|
* Set end of file
|
|
*
|
|
* INPUT: f - file pointer
|
|
* filesize - required new size
|
|
* RETURN: F_NO_ERROR - on success
|
|
* other if error
|
|
*
|
|
***************************************************************************/
|
|
unsigned char _f_seteof ( F_FILE * f, long filesize )
|
|
{
|
|
unsigned char rc = F_NO_ERROR;
|
|
|
|
if ( !f )
|
|
{
|
|
return F_ERR_NOTOPEN; /*if error*/
|
|
}
|
|
|
|
if ( ( unsigned long) filesize < gl_file.filesize )
|
|
{
|
|
rc = _f_fseek( filesize );
|
|
if ( rc == F_NO_ERROR )
|
|
{
|
|
unsigned long cluster;
|
|
rc = _f_getclustervalue( gl_file.pos.cluster, &cluster );
|
|
if ( rc == F_NO_ERROR )
|
|
{
|
|
if ( cluster != F_CLUSTER_LAST )
|
|
{
|
|
rc = _f_removechain( cluster );
|
|
if ( rc )
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
rc = _f_setclustervalue( gl_file.pos.cluster, F_CLUSTER_LAST );
|
|
if ( rc )
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
rc = _f_writefatsector();
|
|
if ( rc )
|
|
{
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
gl_file.filesize = (unsigned long)filesize;
|
|
}
|
|
}
|
|
}
|
|
else if ( (unsigned long) filesize > gl_file.filesize )
|
|
{
|
|
rc = _f_fseek( filesize );
|
|
}
|
|
|
|
return rc;
|
|
} /* _f_seteof */
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_seteof
|
|
*
|
|
* Set end of file
|
|
*
|
|
* INPUT: f - file pointer
|
|
* filesize - required new size
|
|
* RETURN: F_NO_ERROR - on success
|
|
* other if error
|
|
*
|
|
***************************************************************************/
|
|
unsigned char fn_seteof ( F_FILE * f )
|
|
{
|
|
unsigned char rc = F_NO_ERROR;
|
|
|
|
rc = _f_seteof( f, ( gl_file.abspos + gl_file.relpos ) );
|
|
|
|
return rc;
|
|
} /* fn_seteof */
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_truncate
|
|
*
|
|
* Open a file and set end of file
|
|
*
|
|
* INPUT: filename - name of the file
|
|
* filesize - required new size
|
|
* RETURN: NULL on error, otherwise file pointer
|
|
*
|
|
***************************************************************************/
|
|
F_FILE * fn_truncate ( const char * filename, long filesize )
|
|
{
|
|
F_FILE * f = fn_open( filename, "r+" );
|
|
unsigned char rc;
|
|
|
|
if ( f != NULL )
|
|
{
|
|
rc = _f_fseek( (long)gl_file.filesize );
|
|
if ( rc == F_NO_ERROR )
|
|
{
|
|
rc = _f_seteof( f, filesize );
|
|
}
|
|
|
|
if ( rc )
|
|
{
|
|
fn_close( f );
|
|
f = NULL;
|
|
}
|
|
}
|
|
|
|
return f;
|
|
} /* fn_truncate */
|
|
|