/* | |
* 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 */ | |