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.
1222 lines
27 KiB
C
1222 lines
27 KiB
C
/*
|
|
* FreeRTOS+FAT SL V1.0.1 (C) 2014 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 standard GPL open source license, or a commercial license. The
|
|
* standard GPL license (unlike the modified GPL license under which FreeRTOS
|
|
* itself is distributed) requires that all software statically linked with
|
|
* FreeRTOS+FAT SL is also distributed under the same GPL V2 license terms.
|
|
* 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 "dir.h"
|
|
#include "util.h"
|
|
#include "volume.h"
|
|
#include "drv.h"
|
|
#include "fat.h"
|
|
#include "file.h"
|
|
|
|
#include "../../version/ver_fat_sl.h"
|
|
#if VER_FAT_SL_MAJOR != 5 || VER_FAT_SL_MINOR != 2
|
|
#error Incompatible FAT_SL version number!
|
|
#endif
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_findfilewc
|
|
*
|
|
* internal function to finding file in directory entry with or without
|
|
* wildcard
|
|
*
|
|
* INPUTS
|
|
*
|
|
* name - filename
|
|
* ext - fileextension
|
|
* pos - where to start searching, and contains current position
|
|
* pde - store back the directory entry pointer
|
|
* wc - wildcard checking?
|
|
*
|
|
* RETURNS
|
|
*
|
|
* 0 - if file was not found
|
|
* 1 - if file was found
|
|
*
|
|
***************************************************************************/
|
|
unsigned char _f_findfilewc ( char * name, char * ext, F_POS * pos, F_DIRENTRY * * pde, unsigned char wc )
|
|
{
|
|
while ( pos->cluster < F_CLUSTER_RESERVED )
|
|
{
|
|
for ( ; pos->sector < pos->sectorend ; pos->sector++ )
|
|
{
|
|
F_DIRENTRY * de = (F_DIRENTRY *)( gl_sector + sizeof( F_DIRENTRY ) * pos->pos );
|
|
|
|
if ( _f_readglsector( pos->sector ) )
|
|
{
|
|
return 0; /*not found*/
|
|
}
|
|
|
|
for ( ; pos->pos < F_SECTOR_SIZE / sizeof( F_DIRENTRY ) ; de++, pos->pos++ )
|
|
{
|
|
unsigned char b, ok;
|
|
|
|
if ( !de->name[0] )
|
|
{
|
|
return 0; /*empty*/
|
|
}
|
|
|
|
if ( (unsigned char)( de->name[0] ) == 0xe5 )
|
|
{
|
|
continue; /*deleted*/
|
|
}
|
|
|
|
if ( de->attr & F_ATTR_VOLUME )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( wc )
|
|
{
|
|
for ( b = 0, ok = 1 ; b < sizeof( de->name ) ; b++ )
|
|
{
|
|
if ( name[b] == '*' )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ( name[b] != '?' )
|
|
{
|
|
if ( de->name[b] != name[b] )
|
|
{
|
|
ok = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ok )
|
|
{
|
|
for ( b = 0, ok = 1 ; b < sizeof( de->ext ) ; b++ )
|
|
{
|
|
if ( ext[b] == '*' )
|
|
{
|
|
if ( pde )
|
|
{
|
|
*pde = de;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
if ( ext[b] != '?' )
|
|
{
|
|
if ( de->ext[b] != ext[b] )
|
|
{
|
|
ok = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ok )
|
|
{
|
|
if ( pde )
|
|
{
|
|
*pde = de;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for ( b = 0, ok = 1 ; b < sizeof( de->name ) ; b++ )
|
|
{
|
|
if ( de->name[b] != name[b] )
|
|
{
|
|
ok = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( ok )
|
|
{
|
|
for ( b = 0, ok = 1 ; b < sizeof( de->ext ) ; b++ )
|
|
{
|
|
if ( de->ext[b] != ext[b] )
|
|
{
|
|
ok = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( ok )
|
|
{
|
|
if ( pde )
|
|
{
|
|
*pde = de;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pos->pos = 0;
|
|
}
|
|
|
|
if ( !pos->cluster )
|
|
{
|
|
if ( gl_volume.mediatype == F_FAT32_MEDIA )
|
|
{
|
|
pos->cluster = gl_volume.bootrecord.rootcluster;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
{
|
|
unsigned long nextcluster;
|
|
gl_volume.fatsector = (unsigned long)-1;
|
|
if ( _f_getclustervalue( pos->cluster, &nextcluster ) )
|
|
{
|
|
return 0; /*not found*/
|
|
}
|
|
|
|
if ( nextcluster >= F_CLUSTER_RESERVED )
|
|
{
|
|
return 0; /*eof*/
|
|
}
|
|
|
|
_f_clustertopos( nextcluster, pos );
|
|
}
|
|
} /* _f_findfilewc */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_getfilename
|
|
*
|
|
* create a complete filename from name and extension
|
|
*
|
|
* INPUTS
|
|
*
|
|
* dest - where to store filename
|
|
* name - name of the file
|
|
* ext - extension of the file
|
|
*
|
|
***************************************************************************/
|
|
static void _f_getfilename ( char * dest, char * name, char * ext )
|
|
{
|
|
unsigned char a, len;
|
|
|
|
for ( len = a = F_MAXNAME ; a ; a--, len-- )
|
|
{
|
|
if ( name[a - 1] != ' ' )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
for ( a = 0 ; a < len ; a++ )
|
|
{
|
|
*dest++ = *name++;
|
|
}
|
|
|
|
|
|
for ( len = a = F_MAXEXT ; a ; a--, len-- )
|
|
{
|
|
if ( ext[a - 1] != ' ' )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( len )
|
|
{
|
|
*dest++ = '.';
|
|
}
|
|
|
|
for ( a = 0 ; a < len ; a++ )
|
|
{
|
|
*dest++ = *ext++;
|
|
}
|
|
|
|
*dest = 0; /*terminateit*/
|
|
} /* _f_getfilename */
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_getdecluster
|
|
*
|
|
* get a directory entry structure start cluster value
|
|
*
|
|
* INPUTS
|
|
*
|
|
* de - directory entry
|
|
*
|
|
* RETURNS
|
|
*
|
|
* directory entry cluster value
|
|
*
|
|
***************************************************************************/
|
|
unsigned long _f_getdecluster ( F_DIRENTRY * de )
|
|
{
|
|
unsigned long cluster;
|
|
|
|
if ( gl_volume.mediatype == F_FAT32_MEDIA )
|
|
{
|
|
cluster = _f_getword( &de->clusterhi );
|
|
cluster <<= 16;
|
|
cluster |= _f_getword( &de->clusterlo );
|
|
return cluster;
|
|
}
|
|
|
|
return _f_getword( &de->clusterlo );
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_setdecluster
|
|
*
|
|
* set a directory entry structure start cluster value
|
|
*
|
|
* INPUTS
|
|
*
|
|
* de - directory entry
|
|
* cluster - value of the start cluster
|
|
*
|
|
***************************************************************************/
|
|
void _f_setdecluster ( F_DIRENTRY * de, unsigned long cluster )
|
|
{
|
|
_f_setword( &de->clusterlo, (unsigned short)( cluster & 0xffff ) );
|
|
if ( gl_volume.mediatype == F_FAT32_MEDIA )
|
|
{
|
|
_f_setword( &de->clusterhi, (unsigned short)( cluster >> 16 ) );
|
|
}
|
|
else
|
|
{
|
|
_f_setword( &de->clusterhi, (unsigned short)0 );
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_findpath
|
|
*
|
|
* finding out if path is valid in F_NAME and
|
|
* correct path info with absolute path (removes relatives)
|
|
*
|
|
* INPUTS
|
|
*
|
|
* fsname - filled structure with path,drive
|
|
* pos - where to start searching, and contains current position
|
|
*
|
|
* RETURNS
|
|
*
|
|
* 0 - if path was not found or invalid
|
|
* 1 - if path was found
|
|
*
|
|
***************************************************************************/
|
|
unsigned char _f_findpath ( F_NAME * fsname, F_POS * pos )
|
|
{
|
|
char * path = fsname->path;
|
|
char * mpath = path;
|
|
F_DIRENTRY * de;
|
|
|
|
_f_clustertopos( 0, pos );
|
|
|
|
for ( ; *path ; )
|
|
{
|
|
char name[F_MAXNAME];
|
|
char ext[F_MAXEXT];
|
|
|
|
unsigned char len = _f_setnameext( path, name, ext );
|
|
|
|
if ( ( pos->cluster == 0 ) && ( len == 1 ) && ( name[0] == '.' ) )
|
|
{
|
|
_f_clustertopos( 0, pos );
|
|
}
|
|
else
|
|
{
|
|
if ( !_f_findfilewc( name, ext, pos, &de, 0 ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( !( de->attr & F_ATTR_DIR ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
_f_clustertopos( _f_getdecluster( de ), pos );
|
|
}
|
|
|
|
|
|
if ( name[0] == '.' )
|
|
{
|
|
if ( len == 1 )
|
|
{
|
|
path += len;
|
|
|
|
if ( !( *path ) )
|
|
{
|
|
if ( mpath != fsname->path )
|
|
{
|
|
mpath--; /*if we are now at the top*/
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
path++;
|
|
continue;
|
|
}
|
|
|
|
if ( name[1] != '.' )
|
|
{
|
|
return 0; /*invalid name*/
|
|
}
|
|
|
|
if ( len != 2 )
|
|
{
|
|
return 0; /*invalid name !*/
|
|
}
|
|
|
|
path += len;
|
|
|
|
if ( mpath == fsname->path )
|
|
{
|
|
return 0; /*we are in the top*/
|
|
}
|
|
|
|
mpath--; /*no on separator*/
|
|
for ( ; ; )
|
|
{
|
|
if ( mpath == fsname->path )
|
|
{
|
|
break; /*we are now at the top*/
|
|
}
|
|
|
|
mpath--;
|
|
if ( *mpath == '/' )
|
|
{
|
|
mpath++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !( *path ) )
|
|
{
|
|
if ( mpath != fsname->path )
|
|
{
|
|
mpath--; /*if we are now at the top*/
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
path++;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if ( path == mpath ) /*if no was dots just step*/
|
|
{
|
|
path += len;
|
|
mpath += len;
|
|
}
|
|
else
|
|
{
|
|
unsigned char a;
|
|
for ( a = 0 ; a < len ; a++ )
|
|
{
|
|
*mpath++ = *path++; /*copy if in different pos*/
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !( *path ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
path++;
|
|
*mpath++ = '/'; /*add separator*/
|
|
}
|
|
|
|
*mpath = 0; /*terminate it*/
|
|
return 1;
|
|
} /* _f_findpath */
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_getcwd
|
|
*
|
|
* getting a current working directory of current drive
|
|
*
|
|
* INPUTS
|
|
*
|
|
* buffer - where to store current working folder
|
|
* maxlen - buffer length (possible size is F_MAXPATH)
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char fn_getcwd ( char * buffer, unsigned char maxlen, char root )
|
|
{
|
|
unsigned char a;
|
|
|
|
if ( !maxlen )
|
|
{
|
|
return F_NO_ERROR;
|
|
}
|
|
|
|
maxlen--; /*need for termination*/
|
|
if ( root && maxlen )
|
|
{
|
|
*buffer++ = '/';
|
|
maxlen--;
|
|
}
|
|
|
|
for ( a = 0 ; a < maxlen ; a++ )
|
|
{
|
|
char ch = gl_volume.cwd[a];
|
|
buffer[a] = ch;
|
|
if ( !ch )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
buffer[a] = 0; /*add terminator at the end*/
|
|
|
|
return F_NO_ERROR;
|
|
} /* fn_getcwd */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_findfirst
|
|
*
|
|
* find a file(s) or directory(s) in directory
|
|
*
|
|
* INPUTS
|
|
*
|
|
* filename - filename (with or without wildcards)
|
|
* find - where to store found file information
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char fn_findfirst ( const char * filename, F_FIND * find )
|
|
{
|
|
unsigned char ret;
|
|
|
|
if ( _f_setfsname( filename, &find->findfsname ) )
|
|
{
|
|
return F_ERR_INVALIDNAME; /*invalid name*/
|
|
}
|
|
|
|
if ( _f_checkname( find->findfsname.filename, find->findfsname.fileext ) )
|
|
{
|
|
return F_ERR_INVALIDNAME; /*invalid name, wildcard is ok*/
|
|
}
|
|
|
|
|
|
ret = _f_getvolume();
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( !_f_findpath( &find->findfsname, &find->pos ) )
|
|
{
|
|
return F_ERR_INVALIDDIR; /*search for path*/
|
|
}
|
|
|
|
return fn_findnext( find );
|
|
} /* fn_findfirst */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_findnext
|
|
*
|
|
* find further file(s) or directory(s) in directory
|
|
*
|
|
* INPUTS
|
|
*
|
|
* find - where to store found file information (findfirst should call 1st)
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char fn_findnext ( F_FIND * find )
|
|
{
|
|
F_DIRENTRY * de;
|
|
unsigned char a;
|
|
unsigned char ret;
|
|
|
|
ret = _f_getvolume();
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( !_f_findfilewc( find->findfsname.filename, find->findfsname.fileext, &find->pos, &de, 1 ) )
|
|
{
|
|
return F_ERR_NOTFOUND;
|
|
}
|
|
|
|
for ( a = 0 ; a < F_MAXNAME ; a++ )
|
|
{
|
|
find->name[a] = de->name[a];
|
|
}
|
|
|
|
for ( a = 0 ; a < F_MAXEXT ; a++ )
|
|
{
|
|
find->ext[a] = de->ext[a];
|
|
}
|
|
|
|
_f_getfilename( find->filename, (char *)de->name, (char *)de->ext );
|
|
|
|
find->attr = de->attr;
|
|
find->cdate = _f_getword( &de->cdate );
|
|
find->ctime = _f_getword( &de->ctime );
|
|
find->filesize = (long)_f_getlong( &de->filesize );
|
|
find->cluster = _f_getdecluster( de );
|
|
find->pos.pos++; /*goto next position*/
|
|
|
|
return 0;
|
|
} /* fn_findnext */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_chdir
|
|
*
|
|
* change current working directory
|
|
*
|
|
* INPUTS
|
|
*
|
|
* dirname - new working directory name
|
|
*
|
|
* RETURNS
|
|
*
|
|
* 0 - if successfully
|
|
* other - if any error
|
|
*
|
|
***************************************************************************/
|
|
unsigned char fn_chdir ( const char * dirname )
|
|
{
|
|
F_POS pos;
|
|
F_NAME fsname;
|
|
unsigned char len;
|
|
unsigned char a;
|
|
unsigned char ret;
|
|
|
|
ret = _f_setfsname( dirname, &fsname );
|
|
|
|
if ( ret == 1 )
|
|
{
|
|
return F_ERR_INVALIDNAME; /*invalid name*/
|
|
}
|
|
|
|
if ( _f_checknamewc( fsname.filename, fsname.fileext ) )
|
|
{
|
|
return F_ERR_INVALIDNAME; /*invalid name*/
|
|
}
|
|
|
|
ret = _f_getvolume();
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
for ( len = 0 ; fsname.path[len] ; )
|
|
{
|
|
len++;
|
|
}
|
|
|
|
if ( len && ( ( fsname.filename[0] != 32 ) || ( fsname.fileext[0] != 32 ) ) )
|
|
{
|
|
fsname.path[len++] = '/';
|
|
}
|
|
|
|
_f_getfilename( fsname.path + len, fsname.filename, fsname.fileext );
|
|
|
|
if ( !( _f_findpath( &fsname, &pos ) ) )
|
|
{
|
|
return F_ERR_NOTFOUND;
|
|
}
|
|
|
|
for ( a = 0 ; a < F_MAXPATH ; a++ )
|
|
{
|
|
gl_volume.cwd[a] = fsname.path[a];
|
|
}
|
|
|
|
return F_NO_ERROR;
|
|
} /* fn_chdir */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_initentry
|
|
*
|
|
* init directory entry, this function is called if a new entry is coming
|
|
*
|
|
* INPUTS
|
|
*
|
|
* de - directory entry which needs to be initialized
|
|
* name - fil ename (8)
|
|
* ext - file extension (3)
|
|
*
|
|
***************************************************************************/
|
|
static void _f_initentry ( F_DIRENTRY * de, char * name, char * ext )
|
|
{
|
|
unsigned short date;
|
|
unsigned short time;
|
|
|
|
psp_memset( de, 0, sizeof( F_DIRENTRY ) ); /*reset all entries*/
|
|
|
|
psp_memcpy( de->name, name, sizeof( de->name ) );
|
|
psp_memcpy( de->ext, ext, sizeof( de->ext ) );
|
|
|
|
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*/
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _f_addentry
|
|
*
|
|
* Add a new directory entry into driectory list
|
|
*
|
|
* INPUTS
|
|
*
|
|
* fs_name - filled structure what to add into directory list
|
|
* pos - where directory cluster chains starts
|
|
* pde - F_DIRENTRY pointer where to store the entry where it was added
|
|
*
|
|
* RETURNS
|
|
*
|
|
* 0 - if successfully added
|
|
* other - if any error (see FS_xxx errorcodes)
|
|
*
|
|
***************************************************************************/
|
|
unsigned char _f_addentry ( F_NAME * fsname, F_POS * pos, F_DIRENTRY * * pde )
|
|
{
|
|
unsigned char ret;
|
|
unsigned short date;
|
|
unsigned short time;
|
|
|
|
if ( !fsname->filename[0] )
|
|
{
|
|
return F_ERR_INVALIDNAME;
|
|
}
|
|
|
|
if ( fsname->filename[0] == '.' )
|
|
{
|
|
return F_ERR_INVALIDNAME;
|
|
}
|
|
|
|
while ( pos->cluster < F_CLUSTER_RESERVED )
|
|
{
|
|
for ( ; pos->sector < pos->sectorend ; pos->sector++ )
|
|
{
|
|
F_DIRENTRY * de = (F_DIRENTRY *)( gl_sector + sizeof( F_DIRENTRY ) * pos->pos );
|
|
|
|
ret = _f_readglsector( pos->sector );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
for ( ; pos->pos < F_SECTOR_SIZE / sizeof( F_DIRENTRY ) ; de++, pos->pos++ )
|
|
{
|
|
if ( ( !de->name[0] ) || ( (unsigned char)( de->name[0] ) == 0xe5 ) )
|
|
{
|
|
_f_initentry( de, fsname->filename, fsname->fileext );
|
|
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 ( pde )
|
|
{
|
|
*pde = de;
|
|
}
|
|
|
|
return F_NO_ERROR;
|
|
}
|
|
}
|
|
|
|
pos->pos = 0;
|
|
}
|
|
|
|
if ( !pos->cluster )
|
|
{
|
|
if ( gl_volume.mediatype == F_FAT32_MEDIA )
|
|
{
|
|
pos->cluster = gl_volume.bootrecord.rootcluster;
|
|
}
|
|
else
|
|
{
|
|
return F_ERR_NOMOREENTRY;
|
|
}
|
|
}
|
|
|
|
{
|
|
unsigned long cluster;
|
|
|
|
gl_volume.fatsector = (unsigned long)-1;
|
|
ret = _f_getclustervalue( pos->cluster, &cluster ); /*try to get next cluster*/
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( cluster < F_CLUSTER_RESERVED )
|
|
{
|
|
_f_clustertopos( cluster, pos );
|
|
}
|
|
else
|
|
{
|
|
ret = _f_alloccluster( &cluster ); /*get a new one*/
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( cluster < F_CLUSTER_RESERVED )
|
|
{
|
|
if ( gl_file.mode != F_FILE_CLOSE )
|
|
{
|
|
return F_ERR_NOMOREENTRY;
|
|
}
|
|
|
|
_f_clustertopos( cluster, &gl_file.pos );
|
|
|
|
ret = _f_setclustervalue( gl_file.pos.cluster, F_CLUSTER_LAST );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = _f_setclustervalue( pos->cluster, gl_file.pos.cluster );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = _f_writefatsector();
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
gl_volume.fatsector = (unsigned long)-1;
|
|
psp_memset( gl_sector, 0, F_SECTOR_SIZE );
|
|
while ( gl_file.pos.sector < gl_file.pos.sectorend )
|
|
{
|
|
ret = _f_writeglsector( gl_file.pos.sector );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
gl_file.pos.sector++;
|
|
}
|
|
|
|
_f_clustertopos( gl_file.pos.cluster, pos );
|
|
}
|
|
else
|
|
{
|
|
return F_ERR_NOMOREENTRY;
|
|
}
|
|
}
|
|
}
|
|
} /* _f_addentry */
|
|
|
|
return F_ERR_NOMOREENTRY;
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_mkdir
|
|
*
|
|
* making a new directory
|
|
*
|
|
* INPUTS
|
|
*
|
|
* dirname - new directory name
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char fn_mkdir ( const char * dirname )
|
|
{
|
|
F_POS posdir;
|
|
F_POS pos;
|
|
F_DIRENTRY * de;
|
|
F_NAME fsname;
|
|
unsigned long cluster;
|
|
unsigned char ret;
|
|
|
|
#if F_FILE_CHANGED_EVENT
|
|
ST_FILE_CHANGED fc;
|
|
#endif
|
|
|
|
if ( _f_setfsname( dirname, &fsname ) )
|
|
{
|
|
return F_ERR_INVALIDNAME; /*invalid name*/
|
|
}
|
|
|
|
if ( _f_checknamewc( fsname.filename, fsname.fileext ) )
|
|
{
|
|
return F_ERR_INVALIDNAME; /*invalid name*/
|
|
}
|
|
|
|
ret = _f_getvolume();
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ( !_f_findpath( &fsname, &posdir ) )
|
|
{
|
|
return F_ERR_INVALIDDIR;
|
|
}
|
|
|
|
pos = posdir;
|
|
|
|
if ( fsname.filename[0] == '.' )
|
|
{
|
|
return F_ERR_NOTFOUND;
|
|
}
|
|
|
|
if ( _f_findfilewc( fsname.filename, fsname.fileext, &pos, &de, 0 ) )
|
|
{
|
|
return F_ERR_DUPLICATED;
|
|
}
|
|
|
|
pos = posdir;
|
|
|
|
gl_volume.fatsector = (unsigned long)-1;
|
|
ret = _f_alloccluster( &cluster );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = _f_addentry( &fsname, &pos, &de );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
de->attr |= F_ATTR_DIR; /*set as directory*/
|
|
|
|
#if F_FILE_CHANGED_EVENT
|
|
if ( f_filechangedevent )
|
|
{
|
|
fc.action = FACTION_ADDED;
|
|
fc.flags = FFLAGS_DIR_NAME | FFLAGS_ATTRIBUTES | FFLAGS_SIZE | FFLAGS_LAST_WRITE;
|
|
fc.attr = de->attr;
|
|
fc.ctime = _f_getword( de->ctime );
|
|
fc.cdate = _f_getword( de->cdate );
|
|
fc.filesize = _f_getlong( de->filesize );
|
|
}
|
|
|
|
#endif
|
|
|
|
if ( gl_file.mode != F_FILE_CLOSE )
|
|
{
|
|
return F_ERR_LOCKED;
|
|
}
|
|
|
|
_f_clustertopos( cluster, &gl_file.pos );
|
|
_f_setdecluster( de, cluster ); /*new dir*/
|
|
|
|
(void)_f_writeglsector( (unsigned long)-1 ); /*write actual directory sector*/
|
|
|
|
|
|
de = (F_DIRENTRY *)gl_sector;
|
|
|
|
_f_initentry( de, ". ", " " );
|
|
de->attr = F_ATTR_DIR; /*set as directory*/
|
|
_f_setdecluster( de, cluster ); /*current*/
|
|
de++;
|
|
|
|
_f_initentry( de, ".. ", " " );
|
|
de->attr = F_ATTR_DIR; /*set as directory*/
|
|
_f_setdecluster( de, posdir.cluster ); /*parent*/
|
|
de++;
|
|
|
|
psp_memset( de, 0, ( F_SECTOR_SIZE - 2 * sizeof( F_DIRENTRY ) ) );
|
|
|
|
|
|
ret = _f_writeglsector( gl_file.pos.sector );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
gl_file.pos.sector++;
|
|
psp_memset( gl_sector, 0, ( 2 * sizeof( F_DIRENTRY ) ) );
|
|
while ( gl_file.pos.sector < gl_file.pos.sectorend )
|
|
{
|
|
ret = _f_writeglsector( gl_file.pos.sector );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
gl_file.pos.sector++;
|
|
}
|
|
|
|
gl_volume.fatsector = (unsigned long)-1;
|
|
ret = _f_setclustervalue( gl_file.pos.cluster, F_CLUSTER_LAST );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = _f_writefatsector();
|
|
#if F_FILE_CHANGED_EVENT
|
|
if ( f_filechangedevent && !ret )
|
|
{
|
|
fc.action = FACTION_ADDED;
|
|
fc.flags = FFLAGS_DIR_NAME;
|
|
|
|
if ( !_f_createfullname( fc.filename, sizeof( fc.filename ), fsname.path, fsname.filename, fsname.fileext ) )
|
|
{
|
|
f_filechangedevent( &fc );
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
return ret;
|
|
} /* fn_mkdir */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* fn_rmdir
|
|
*
|
|
* Remove directory, only could be removed if empty
|
|
*
|
|
* INPUTS
|
|
*
|
|
* dirname - which directory needed to be removed
|
|
*
|
|
* RETURNS
|
|
*
|
|
* error code or zero if successful
|
|
*
|
|
***************************************************************************/
|
|
unsigned char fn_rmdir ( const char * dirname )
|
|
{
|
|
unsigned char ret;
|
|
F_POS pos;
|
|
F_DIRENTRY * de;
|
|
F_NAME fsname;
|
|
unsigned long dirsector;
|
|
unsigned char a;
|
|
|
|
if ( _f_setfsname( dirname, &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; /*not a directory*/
|
|
}
|
|
|
|
dirsector = gl_volume.actsector;
|
|
|
|
if ( gl_file.mode != F_FILE_CLOSE )
|
|
{
|
|
return F_ERR_LOCKED;
|
|
}
|
|
|
|
_f_clustertopos( _f_getdecluster( de ), &gl_file.pos );
|
|
|
|
for ( ; ; )
|
|
{
|
|
F_DIRENTRY * de2;
|
|
char ch = 0;
|
|
|
|
ret = _f_getcurrsector();
|
|
if ( ret == F_ERR_EOF )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
de2 = (F_DIRENTRY *)gl_sector;
|
|
for ( a = 0 ; a < ( F_SECTOR_SIZE / sizeof( F_DIRENTRY ) ) ; a++, de2++ )
|
|
{
|
|
ch = de2->name[0];
|
|
if ( !ch )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ( (unsigned char)ch == 0xe5 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( ch == '.' )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
return F_ERR_NOTEMPTY; /*something is there*/
|
|
}
|
|
|
|
if ( !ch )
|
|
{
|
|
break;
|
|
}
|
|
|
|
gl_file.pos.sector++;
|
|
}
|
|
|
|
ret = _f_readglsector( dirsector );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
de->name[0] = (unsigned char)0xe5;
|
|
|
|
ret = _f_writeglsector( dirsector );
|
|
if ( ret )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
gl_volume.fatsector = (unsigned long)-1;
|
|
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_DIR_NAME;
|
|
|
|
if ( !_f_createfullname( fc.filename, sizeof( fc.filename ), fsname.path, fsname.filename, fsname.fileext ) )
|
|
{
|
|
f_filechangedevent( &fc );
|
|
}
|
|
}
|
|
|
|
#endif
|
|
return ret;
|
|
} /* fn_rmdir */
|
|
|
|
|