@ -27,19 +27,21 @@
* This file is part of the Arduino Sd2Card Library
*/
# include "Marlin.h"
# include "MarlinConfig.h"
# if ENABLED(SDSUPPORT)
# include "SdBaseFile.h"
//------------------------------------------------------------------------------
// pointer to cwd directory
SdBaseFile * SdBaseFile : : cwd_ = 0 ;
# include "Marlin.h"
SdBaseFile * SdBaseFile : : cwd_ = 0 ; // Pointer to Current Working Directory
// callback function for date/time
void ( * SdBaseFile : : dateTime_ ) ( uint16_t * date , uint16_t * time ) = 0 ;
//------------------------------------------------------------------------------
// add a cluster to a file
bool SdBaseFile : : addCluster ( ) {
if ( ! vol_ - > allocContiguous ( 1 , & curCluster_ ) ) goto FAIL ;
if ( ! vol_ - > allocContiguous ( 1 , & curCluster_ ) ) return false ;
// if first cluster of file link to directory entry
if ( firstCluster_ = = 0 ) {
@ -47,20 +49,17 @@ bool SdBaseFile::addCluster() {
flags_ | = F_FILE_DIR_DIRTY ;
}
return true ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
// Add a cluster to a directory file and zero the cluster.
// return with first block of cluster in the cache
bool SdBaseFile : : addDirCluster ( ) {
uint32_t block ;
// max folder size
if ( fileSize_ / sizeof ( dir_t ) > = 0xFFFF ) goto FAIL ;
if ( fileSize_ / sizeof ( dir_t ) > = 0xFFFF ) return false ;
if ( ! addCluster ( ) ) goto FAIL ;
if ( ! vol_ - > cacheFlush ( ) ) goto FAIL ;
if ( ! addCluster ( ) ) return false ;
if ( ! vol_ - > cacheFlush ( ) ) return false ;
block = vol_ - > clusterStartBlock ( curCluster_ ) ;
@ -72,29 +71,25 @@ bool SdBaseFile::addDirCluster() {
// zero rest of cluster
for ( uint8_t i = 1 ; i < vol_ - > blocksPerCluster_ ; i + + ) {
if ( ! vol_ - > writeBlock ( block + i , vol_ - > cacheBuffer_ . data ) ) goto FAIL ;
if ( ! vol_ - > writeBlock ( block + i , vol_ - > cacheBuffer_ . data ) ) return false ;
}
// Increase directory file size by cluster size
fileSize_ + = 512UL < < vol_ - > clusterSizeShift_ ;
return true ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
// cache a file's directory entry
// return pointer to cached entry or null for failure
dir_t * SdBaseFile : : cacheDirEntry ( uint8_t action ) {
if ( ! vol_ - > cacheRawBlock ( dirBlock_ , action ) ) goto FAI L;
if ( ! vol_ - > cacheRawBlock ( dirBlock_ , action ) ) return NUL L;
return vol_ - > cache ( ) - > dir + dirIndex_ ;
FAIL :
return 0 ;
}
//------------------------------------------------------------------------------
/** Close a file and force cached data and directory information
/**
* Close a file and force cached data and directory information
* to be written to the storage device .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
* Reasons for failure include no file is open or an I / O error .
*/
bool SdBaseFile : : close ( ) {
@ -102,41 +97,40 @@ bool SdBaseFile::close() {
type_ = FAT_FILE_TYPE_CLOSED ;
return rtn ;
}
//------------------------------------------------------------------------------
/** Check for contiguous file and return its raw block range.
/**
* Check for contiguous file and return its raw block range .
*
* \ param [ out ] bgnBlock the first block address for the file .
* \ param [ out ] endBlock the last block address for the file .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
* Reasons for failure include file is not contiguous , file has zero length
* or an I / O error occurred .
*/
bool SdBaseFile : : contiguousRange ( uint32_t * bgnBlock , uint32_t * endBlock ) {
// error if no blocks
if ( firstCluster_ = = 0 ) goto FAIL ;
if ( firstCluster_ = = 0 ) return false ;
for ( uint32_t c = firstCluster_ ; ; c + + ) {
uint32_t next ;
if ( ! vol_ - > fatGet ( c , & next ) ) goto FAIL ;
if ( ! vol_ - > fatGet ( c , & next ) ) return false ;
// check for contiguous
if ( next ! = ( c + 1 ) ) {
// error if not end of chain
if ( ! vol_ - > isEOC ( next ) ) goto FAIL ;
if ( ! vol_ - > isEOC ( next ) ) return false ;
* bgnBlock = vol_ - > clusterStartBlock ( firstCluster_ ) ;
* endBlock = vol_ - > clusterStartBlock ( c )
+ vol_ - > blocksPerCluster_ - 1 ;
return true ;
}
}
FAIL :
return false ;
}
//------------------------------------------------------------------------------
/** Create and open a new contiguous file of a specified size.
/**
* Create and open a new contiguous file of a specified size .
*
* \ note This function only supports short DOS 8.3 names .
* See open ( ) for more information .
@ -145,20 +139,18 @@ bool SdBaseFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) {
* \ param [ in ] path A path with a valid DOS 8.3 file name .
* \ param [ in ] size The desired file size .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
* Reasons for failure include \ a path contains
* an invalid DOS 8.3 file name , the FAT volume has not been initialized ,
* a file is already open , the file already exists , the root
* directory is full or an I / O error .
*
*/
bool SdBaseFile : : createContiguous ( SdBaseFile * dirFile ,
const char * path , uint32_t size ) {
bool SdBaseFile : : createContiguous ( SdBaseFile * dirFile , const char * path , uint32_t size ) {
uint32_t count ;
// don't allow zero length file
if ( size = = 0 ) goto FAIL ;
if ( ! open ( dirFile , path , O_CREAT | O_EXCL | O_RDWR ) ) goto FAIL ;
if ( size = = 0 ) return false ;
if ( ! open ( dirFile , path , O_CREAT | O_EXCL | O_RDWR ) ) return false ;
// calculate number of clusters needed
count = ( ( size - 1 ) > > ( vol_ - > clusterSizeShift_ + 9 ) ) + 1 ;
@ -166,7 +158,7 @@ bool SdBaseFile::createContiguous(SdBaseFile* dirFile,
// allocate clusters
if ( ! vol_ - > allocContiguous ( count , & firstCluster_ ) ) {
remove ( ) ;
goto FAIL ;
return false ;
}
fileSize_ = size ;
@ -174,34 +166,31 @@ bool SdBaseFile::createContiguous(SdBaseFile* dirFile,
flags_ | = F_FILE_DIR_DIRTY ;
return sync ( ) ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
/** Return a file's directory entry.
/**
* Return a file ' s directory entry .
*
* \ param [ out ] dir Location for return of the file ' s directory entry .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
*/
bool SdBaseFile : : dirEntry ( dir_t * dir ) {
dir_t * p ;
// make sure fields on SD are correct
if ( ! sync ( ) ) goto FAIL ;
if ( ! sync ( ) ) return false ;
// read entry
p = cacheDirEntry ( SdVolume : : CACHE_FOR_READ ) ;
if ( ! p ) goto FAIL ;
if ( ! p ) return false ;
// copy to caller's struct
memcpy ( dir , p , sizeof ( dir_t ) ) ;
return true ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
/** Format the name field of \a dir into the 13 byte array
/**
* Format the name field of \ a dir into the 13 byte array
* \ a name in standard 8.3 short name format .
*
* \ param [ in ] dir The directory structure containing the name .
@ -216,8 +205,9 @@ void SdBaseFile::dirName(const dir_t& dir, char* name) {
}
name [ j ] = 0 ;
}
//------------------------------------------------------------------------------
/** Test for the existence of a file in a directory
/**
* Test for the existence of a file in a directory
*
* \ param [ in ] name Name of the file to be tested for .
*
@ -232,7 +222,7 @@ bool SdBaseFile::exists(const char* name) {
SdBaseFile file ;
return file . open ( this , name , O_READ ) ;
}
//------------------------------------------------------------------------------
/**
* Get a string from a file .
*
@ -275,15 +265,15 @@ int16_t SdBaseFile::fgets(char* str, int16_t num, char* delim) {
str [ n ] = ' \0 ' ;
return n ;
}
//------------------------------------------------------------------------------
/** Get a file's name
/**
* Get a file ' s name
*
* \ param [ out ] name An array of 13 characters for the file ' s name .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
*/
bool SdBaseFile : : getFilename ( char * name ) {
bool SdBaseFile : : getFilename ( char * const name ) {
if ( ! isOpen ( ) ) return false ;
if ( isRoot ( ) ) {
@ -299,14 +289,14 @@ bool SdBaseFile::getFilename(char* name) {
dirName ( * p , name ) ;
return true ;
}
//------------------------------------------------------------------------------
void SdBaseFile : : getpos ( filepos_t * pos ) {
pos - > position = curPosition_ ;
pos - > cluster = curCluster_ ;
}
//------------------------------------------------------------------------------
/** List directory contents.
/**
* List directory contents .
*
* \ param [ in ] pr Print stream for list .
*
@ -333,7 +323,7 @@ void SdBaseFile::ls(uint8_t flags, uint8_t indent) {
}
}
}
//------------------------------------------------------------------------------
// saves 32 bytes on stack for ls recursion
// return 0 - EOF, 1 - normal file, or 2 - directory
int8_t SdBaseFile : : lsPrintNext ( uint8_t flags , uint8_t indent ) {
@ -383,41 +373,33 @@ int8_t SdBaseFile::lsPrintNext(uint8_t flags, uint8_t indent) {
MYSERIAL . println ( ) ;
return DIR_IS_FILE ( & dir ) ? 1 : 2 ;
}
//------------------------------------------------------------------------------
// f ormat directory name field from a 8.3 name string
// F ormat directory name field from a 8.3 name string
bool SdBaseFile : : make83Name ( const char * str , uint8_t * name , const char * * ptr ) {
uint8_t c ;
uint8_t n = 7 ; // max index for part before dot
uint8_t i = 0 ;
// blank fill name and extension
while ( i < 11 ) name [ i + + ] = ' ' ;
i = 0 ;
while ( * str ! = ' \0 ' & & * str ! = ' / ' ) {
c = * str + + ;
if ( c = = ' . ' ) {
if ( n = = 10 ) goto FAIL ; // only one dot allowed
n = 10 ; // max index for full 8.3 name
i = 8 ; // place for extension
uint8_t n = 7 , // Max index until a dot is found
i = 11 ;
while ( i ) name [ - - i ] = ' ' ; // Set whole FILENAME.EXT to spaces
while ( * str & & * str ! = ' / ' ) { // For each character, until nul or '/'
uint8_t c = * str + + ; // Get char and advance
if ( c = = ' . ' ) { // For a dot...
if ( n = = 10 ) return false ; // Already moved the max index? fail!
n = 10 ; // Move the max index for full 8.3 name
i = 8 ; // Move up to the extension place
}
else {
// illegal FAT characters
// Fail for illegal characters
PGM_P p = PSTR ( " |<>^+=?/[];,* \" \\ " ) ;
uint8_t b ;
while ( ( b = pgm_read_byte ( p + + ) ) ) if ( b = = c ) goto FAIL ;
// check size and only allow ASCII printable characters
if ( i > n | | c < 0x21 | | c = = 0x7F ) goto FAIL ;
// only upper case allowed in 8.3 names - convert lower to upper
name [ i + + ] = ( c < ' a ' | | c > ' z ' ) ? ( c ) : ( c + ( ' A ' - ' a ' ) ) ;
while ( uint8_t b = pgm_read_byte ( p + + ) ) if ( b = = c ) return false ;
if ( i > n | | c < 0x21 | | c = = 0x7F ) return false ; // Check size, non-printable characters
name [ i + + ] = ( c < ' a ' | | c > ' z ' ) ? ( c ) : ( c + ( ' A ' - ' a ' ) ) ; // Uppercase required for 8.3 name
}
}
* ptr = str ;
// must have a file name, extension is optional
return name [ 0 ] ! = ' ' ;
FAIL :
return false ;
* ptr = str ; // Set passed pointer to the end
return name [ 0 ] ! = ' ' ; // Return true if any name was set
}
//------------------------------------------------------------------------------
/** Make a new directory.
/**
* Make a new directory .
*
* \ param [ in ] parent An open SdFat instance for the directory that will contain
* the new directory .
@ -426,8 +408,7 @@ bool SdBaseFile::make83Name(const char* str, uint8_t* name, const char** ptr) {
*
* \ param [ in ] pFlag Create missing parent directories if true .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
* Reasons for failure include this file is already open , \ a parent is not a
* directory , \ a path is invalid or already exists in \ a parent .
*/
@ -437,56 +418,53 @@ bool SdBaseFile::mkdir(SdBaseFile* parent, const char* path, bool pFlag) {
SdBaseFile * sub = & dir1 ;
SdBaseFile * start = parent ;
if ( ! parent | | isOpen ( ) ) goto FAIL ;
if ( ! parent | | isOpen ( ) ) return false ;
if ( * path = = ' / ' ) {
while ( * path = = ' / ' ) path + + ;
if ( ! parent - > isRoot ( ) ) {
if ( ! dir2 . openRoot ( parent - > vol_ ) ) goto FAIL ;
if ( ! dir2 . openRoot ( parent - > vol_ ) ) return false ;
parent = & dir2 ;
}
}
while ( 1 ) {
if ( ! make83Name ( path , dname , & path ) ) goto FAIL ;
if ( ! make83Name ( path , dname , & path ) ) return false ;
while ( * path = = ' / ' ) path + + ;
if ( ! * path ) break ;
if ( ! sub - > open ( parent , dname , O_READ ) ) {
if ( ! pFlag | | ! sub - > mkdir ( parent , dname ) ) {
goto FAIL ;
}
if ( ! pFlag | | ! sub - > mkdir ( parent , dname ) )
return false ;
}
if ( parent ! = start ) parent - > close ( ) ;
parent = sub ;
sub = parent ! = & dir1 ? & dir1 : & dir2 ;
}
return mkdir ( parent , dname ) ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
bool SdBaseFile : : mkdir ( SdBaseFile * parent , const uint8_t dname [ 11 ] ) {
uint32_t block ;
dir_t d ;
dir_t * p ;
if ( ! parent - > isDir ( ) ) goto FAIL ;
if ( ! parent - > isDir ( ) ) return false ;
// create a normal file
if ( ! open ( parent , dname , O_CREAT | O_EXCL | O_RDWR ) ) goto FAIL ;
if ( ! open ( parent , dname , O_CREAT | O_EXCL | O_RDWR ) ) return false ;
// convert file to directory
flags_ = O_READ ;
type_ = FAT_FILE_TYPE_SUBDIR ;
// allocate and zero first cluster
if ( ! addDirCluster ( ) ) goto FAIL ;
if ( ! addDirCluster ( ) ) return false ;
// force entry to SD
if ( ! sync ( ) ) goto FAIL ;
if ( ! sync ( ) ) return false ;
// cache entry - should already be in cache due to sync() call
p = cacheDirEntry ( SdVolume : : CACHE_FOR_WRITE ) ;
if ( ! p ) goto FAIL ;
if ( ! p ) return false ;
// change directory entry attribute
p - > attributes = DIR_ATT_DIRECTORY ;
@ -498,7 +476,7 @@ bool SdBaseFile::mkdir(SdBaseFile* parent, const uint8_t dname[11]) {
// cache block for '.' and '..'
block = vol_ - > clusterStartBlock ( firstCluster_ ) ;
if ( ! vol_ - > cacheRawBlock ( block , SdVolume : : CACHE_FOR_WRITE ) ) goto FAIL ;
if ( ! vol_ - > cacheRawBlock ( block , SdVolume : : CACHE_FOR_WRITE ) ) return false ;
// copy '.' to block
memcpy ( & vol_ - > cache ( ) - > dir [ 0 ] , & d , sizeof ( d ) ) ;
@ -518,25 +496,24 @@ bool SdBaseFile::mkdir(SdBaseFile* parent, const uint8_t dname[11]) {
// write first block
return vol_ - > cacheFlush ( ) ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
/** Open a file in the current working directory.
/**
* Open a file in the current working directory .
*
* \ param [ in ] path A path with a valid 8.3 DOS name for a file to be opened .
*
* \ param [ in ] oflag Values for \ a oflag are constructed by a bitwise - inclusive
* OR of open flags . see SdBaseFile : : open ( SdBaseFile * , const char * , uint8_t ) .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
*/
bool SdBaseFile : : open ( const char * path , uint8_t oflag ) {
return open ( cwd_ , path , oflag ) ;
}
//------------------------------------------------------------------------------
/** Open a file or directory by name.
/**
* Open a file or directory by name .
*
* \ param [ in ] dirFile An open SdFat instance for the directory containing the
* file to be opened .
@ -580,8 +557,7 @@ bool SdBaseFile::open(const char* path, uint8_t oflag) {
* \ note Directory files must be opened read only . Write and truncation is
* not allowed for directory files .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
* Reasons for failure include this file is already open , \ a dirFile is not
* a directory , \ a path is invalid , the file does not exist
* or can ' t be opened in the access mode specified by oflag .
@ -589,40 +565,33 @@ bool SdBaseFile::open(const char* path, uint8_t oflag) {
bool SdBaseFile : : open ( SdBaseFile * dirFile , const char * path , uint8_t oflag ) {
uint8_t dname [ 11 ] ;
SdBaseFile dir1 , dir2 ;
SdBaseFile * parent = dirFile ;
SdBaseFile * sub = & dir1 ;
SdBaseFile * parent = dirFile , * sub = & dir1 ;
if ( ! dirFile ) goto FAIL ;
if ( ! dirFile | | isOpen ( ) ) return false ;
// error if already open
if ( isOpen ( ) ) goto FAIL ;
if ( * path = = ' / ' ) {
while ( * path = = ' / ' ) path + + ;
if ( ! dirFile - > isRoot ( ) ) {
if ( ! dir2 . openRoot ( dirFile - > vol_ ) ) goto FAIL ;
parent = & dir2 ;
if ( * path = = ' / ' ) { // Path starts with '/'
if ( ! dirFile - > isRoot ( ) ) { // Is the passed dirFile the root?
if ( ! dir2 . openRoot ( dirFile - > vol_ ) ) return false ; // Get the root in dir2, if possible
parent = & dir2 ; // Change 'parent' to point at the root dir
}
while ( * path = = ' / ' ) path + + ; // Skip all leading slashes
}
while ( 1 ) {
if ( ! make83Name ( path , dname , & path ) ) goto FAIL ;
for ( ; ; ) {
if ( ! make83Name ( path , dname , & path ) ) return false ;
while ( * path = = ' / ' ) path + + ;
if ( ! * path ) break ;
if ( ! sub - > open ( parent , dname , O_READ ) ) goto FAIL ;
if ( ! sub - > open ( parent , dname , O_READ ) ) return false ;
if ( parent ! = dirFile ) parent - > close ( ) ;
parent = sub ;
sub = parent ! = & dir1 ? & dir1 : & dir2 ;
}
return open ( parent , dname , oflag ) ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
// open with filename in dname
bool SdBaseFile : : open ( SdBaseFile * dirFile ,
const uint8_t dname [ 11 ] , uint8_t oflag ) {
bool emptyFound = false ;
bool fileFound = false ;
bool SdBaseFile : : open ( SdBaseFile * dirFile , const uint8_t dname [ 11 ] , uint8_t oflag ) {
bool emptyFound = false , fileFound = false ;
uint8_t index ;
dir_t * p ;
@ -634,7 +603,7 @@ bool SdBaseFile::open(SdBaseFile* dirFile,
while ( dirFile - > curPosition_ < dirFile - > fileSize_ ) {
index = 0XF & ( dirFile - > curPosition_ > > 5 ) ;
p = dirFile - > readDirCache ( ) ;
if ( ! p ) goto FAIL ;
if ( ! p ) return false ;
if ( p - > name [ 0 ] = = DIR_NAME_FREE | | p - > name [ 0 ] = = DIR_NAME_DELETED ) {
// remember first empty slot
@ -653,21 +622,21 @@ bool SdBaseFile::open(SdBaseFile* dirFile,
}
if ( fileFound ) {
// don't open existing file if O_EXCL
if ( oflag & O_EXCL ) goto FAIL ;
if ( oflag & O_EXCL ) return false ;
}
else {
// don't create unless O_CREAT and O_WRITE
if ( ! ( oflag & O_CREAT ) | | ! ( oflag & O_WRITE ) ) goto FAIL ;
if ( ! ( oflag & O_CREAT ) | | ! ( oflag & O_WRITE ) ) return false ;
if ( emptyFound ) {
index = dirIndex_ ;
p = cacheDirEntry ( SdVolume : : CACHE_FOR_WRITE ) ;
if ( ! p ) goto FAIL ;
if ( ! p ) return false ;
}
else {
if ( dirFile - > type_ = = FAT_FILE_TYPE_ROOT_FIXED ) goto FAIL ;
if ( dirFile - > type_ = = FAT_FILE_TYPE_ROOT_FIXED ) return false ;
// add and zero cluster for dirFile - first cluster is in cache for write
if ( ! dirFile - > addDirCluster ( ) ) goto FAIL ;
if ( ! dirFile - > addDirCluster ( ) ) return false ;
// use first entry in cluster
p = dirFile - > vol_ - > cache ( ) - > dir ;
@ -692,15 +661,14 @@ bool SdBaseFile::open(SdBaseFile* dirFile,
p - > lastWriteTime = p - > creationTime ;
// write entry to SD
if ( ! dirFile - > vol_ - > cacheFlush ( ) ) goto FAIL ;
if ( ! dirFile - > vol_ - > cacheFlush ( ) ) return false ;
}
// open entry in cache
return openCachedEntry ( index , oflag ) ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
/** Open a file by index.
/**
* Open a file by index .
*
* \ param [ in ] dirFile An open SdFat instance for the directory .
*
@ -719,29 +687,27 @@ bool SdBaseFile::open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag) {
vol_ = dirFile - > vol_ ;
// error if already open
if ( isOpen ( ) | | ! dirFile ) goto FAIL ;
if ( isOpen ( ) | | ! dirFile ) return false ;
// don't open existing file if O_EXCL - user call error
if ( oflag & O_EXCL ) goto FAIL ;
if ( oflag & O_EXCL ) return false ;
// seek to location of entry
if ( ! dirFile - > seekSet ( 32 * index ) ) goto FAIL ;
if ( ! dirFile - > seekSet ( 32 * index ) ) return false ;
// read entry into cache
p = dirFile - > readDirCache ( ) ;
if ( ! p ) goto FAIL ;
if ( ! p ) return false ;
// error if empty slot or '.' or '..'
if ( p - > name [ 0 ] = = DIR_NAME_FREE | |
p - > name [ 0 ] = = DIR_NAME_DELETED | | p - > name [ 0 ] = = ' . ' ) {
goto FAIL ;
return false ;
}
// open cached entry
return openCachedEntry ( index & 0XF , oflag ) ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
// open a cached directory entry. Assumes vol_ is initialized
bool SdBaseFile : : openCachedEntry ( uint8_t dirIndex , uint8_t oflag ) {
// location of entry in cache
@ -768,9 +734,9 @@ bool SdBaseFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) {
if ( ! vol_ - > chainSize ( firstCluster_ , & fileSize_ ) ) goto FAIL ;
type_ = FAT_FILE_TYPE_SUBDIR ;
}
else {
else
goto FAIL ;
}
// save open flags for read/write
flags_ = oflag & F_OFLAG ;
@ -779,12 +745,14 @@ bool SdBaseFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) {
curPosition_ = 0 ;
if ( ( oflag & O_TRUNC ) & & ! truncate ( 0 ) ) return false ;
return oflag & O_AT_END ? seekEnd ( 0 ) : true ;
FAIL :
type_ = FAT_FILE_TYPE_CLOSED ;
return false ;
}
//------------------------------------------------------------------------------
/** Open the next file or subdirectory in a directory.
/**
* Open the next file or subdirectory in a directory .
*
* \ param [ in ] dirFile An open SdFat instance for the directory containing the
* file to be opened .
@ -799,10 +767,10 @@ bool SdBaseFile::openNext(SdBaseFile* dirFile, uint8_t oflag) {
dir_t * p ;
uint8_t index ;
if ( ! dirFile ) goto FAIL ;
if ( ! dirFile ) return false ;
// error if already open
if ( isOpen ( ) ) goto FAIL ;
if ( isOpen ( ) ) return false ;
vol_ = dirFile - > vol_ ;
@ -811,10 +779,10 @@ bool SdBaseFile::openNext(SdBaseFile* dirFile, uint8_t oflag) {
// read entry into cache
p = dirFile - > readDirCache ( ) ;
if ( ! p ) goto FAIL ;
if ( ! p ) return false ;
// done if last entry
if ( p - > name [ 0 ] = = DIR_NAME_FREE ) goto FAIL ;
if ( p - > name [ 0 ] = = DIR_NAME_FREE ) return false ;
// skip empty slot or '.' or '..'
if ( p - > name [ 0 ] = = DIR_NAME_DELETED | | p - > name [ 0 ] = = ' . ' ) {
@ -825,16 +793,16 @@ bool SdBaseFile::openNext(SdBaseFile* dirFile, uint8_t oflag) {
return openCachedEntry ( index , oflag ) ;
}
}
FAIL :
return false ;
}
//------------------------------------------------------------------------------
/** Open a directory's parent directory.
#if 0
/**
* Open a directory ' s parent directory .
*
* \ param [ in ] dir Parent of this directory will be opened . Must not be root .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
*/
bool SdBaseFile : : openParent ( SdBaseFile * dir ) {
dir_t entry ;
@ -844,14 +812,14 @@ bool SdBaseFile::openParent(SdBaseFile* dir) {
uint32_t cluster ;
uint32_t lbn ;
// error if already open or dir is root or dir is not a directory
if ( isOpen ( ) | | ! dir | | dir - > isRoot ( ) | | ! dir - > isDir ( ) ) goto FAIL ;
if ( isOpen ( ) | | ! dir | | dir - > isRoot ( ) | | ! dir - > isDir ( ) ) return false ;
vol_ = dir - > vol_ ;
// position to '..'
if ( ! dir - > seekSet ( 32 ) ) goto FAIL ;
if ( ! dir - > seekSet ( 32 ) ) return false ;
// read '..' entry
if ( dir - > read ( & entry , sizeof ( entry ) ) ! = 32 ) goto FAIL ;
if ( dir - > read ( & entry , sizeof ( entry ) ) ! = 32 ) return false ;
// verify it is '..'
if ( entry . name [ 0 ] ! = ' . ' | | entry . name [ 1 ] ! = ' . ' ) goto FAIL ;
if ( entry . name [ 0 ] ! = ' . ' | | entry . name [ 1 ] ! = ' . ' ) return false ;
// start cluster for '..'
cluster = entry . firstClusterLow ;
cluster | = ( uint32_t ) entry . firstClusterHigh < < 16 ;
@ -859,43 +827,42 @@ bool SdBaseFile::openParent(SdBaseFile* dir) {
// start block for '..'
lbn = vol_ - > clusterStartBlock ( cluster ) ;
// first block of parent dir
if ( ! vol_ - > cacheRawBlock ( lbn , SdVolume : : CACHE_FOR_READ ) ) {
goto FAIL ;
}
if ( ! vol_ - > cacheRawBlock ( lbn , SdVolume : : CACHE_FOR_READ ) ) return false ;
p = & vol_ - > cacheBuffer_ . dir [ 1 ] ;
// verify name for '../..'
if ( p - > name [ 0 ] ! = ' . ' | | p - > name [ 1 ] ! = ' . ' ) goto FAIL ;
if ( p - > name [ 0 ] ! = ' . ' | | p - > name [ 1 ] ! = ' . ' ) return false ;
// '..' is pointer to first cluster of parent. open '../..' to find parent
if ( p - > firstClusterHigh = = 0 & & p - > firstClusterLow = = 0 ) {
if ( ! file . openRoot ( dir - > volume ( ) ) ) goto FAIL ;
}
else if ( ! file . openCachedEntry ( 1 , O_READ ) ) {
goto FAIL ;
if ( ! file . openRoot ( dir - > volume ( ) ) ) return false ;
}
else if ( ! file . openCachedEntry ( 1 , O_READ ) )
return false ;
// search for parent in '../..'
do {
if ( file . readDir ( & entry , NULL ) ! = 32 ) goto FAIL ;
if ( file . readDir ( & entry , NULL ) ! = 32 ) return false ;
c = entry . firstClusterLow ;
c | = ( uint32_t ) entry . firstClusterHigh < < 16 ;
} while ( c ! = cluster ) ;
// open parent
return open ( & file , file . curPosition ( ) / 32 - 1 , O_READ ) ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
/** Open a volume's root directory.
# endif
/**
* Open a volume ' s root directory .
*
* \ param [ in ] vol The FAT volume containing the root directory to be opened .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
* Reasons for failure include the file is already open , the FAT volume has
* not been initialized or it a FAT12 volume .
*/
bool SdBaseFile : : openRoot ( SdVolume * vol ) {
// error if file is already open
if ( isOpen ( ) ) goto FAIL ;
if ( isOpen ( ) ) return false ;
if ( vol - > fatType ( ) = = 16 | | ( FAT12_SUPPORT & & vol - > fatType ( ) = = 12 ) ) {
type_ = FAT_FILE_TYPE_ROOT_FIXED ;
@ -905,29 +872,25 @@ bool SdBaseFile::openRoot(SdVolume* vol) {
else if ( vol - > fatType ( ) = = 32 ) {
type_ = FAT_FILE_TYPE_ROOT32 ;
firstCluster_ = vol - > rootDirStart ( ) ;
if ( ! vol - > chainSize ( firstCluster_ , & fileSize_ ) ) goto FAIL ;
if ( ! vol - > chainSize ( firstCluster_ , & fileSize_ ) ) return false ;
}
else {
// volume is not initialized, invalid, or FAT12 without support
else // volume is not initialized, invalid, or FAT12 without support
return false ;
}
vol_ = vol ;
// read only
flags_ = O_READ ;
// set to start of file
curCluster_ = 0 ;
curPosition_ = 0 ;
curCluster_ = curPosition_ = 0 ;
// root has no directory entry
dirBlock_ = 0 ;
dirIndex_ = 0 ;
dirBlock_ = dirIndex_ = 0 ;
return true ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
/** Return the next available byte without consuming it.
/**
* Return the next available byte without consuming it .
*
* \ return The byte if no error and not at eof else - 1 ;
*/
@ -939,50 +902,24 @@ int SdBaseFile::peek() {
return c ;
}
//------------------------------------------------------------------------------
/** %Print the name field of a directory entry in 8.3 format.
* \ param [ in ] pr Print stream for output .
* \ param [ in ] dir The directory structure containing the name .
* \ param [ in ] width Blank fill name if length is less than \ a width .
* \ param [ in ] printSlash Print ' / ' after directory names if true .
*/
void SdBaseFile : : printDirName ( const dir_t & dir ,
uint8_t width , bool printSlash ) {
uint8_t w = 0 ;
for ( uint8_t i = 0 ; i < 11 ; i + + ) {
if ( dir . name [ i ] = = ' ' ) continue ;
if ( i = = 8 ) {
MYSERIAL . write ( ' . ' ) ;
w + + ;
}
MYSERIAL . write ( dir . name [ i ] ) ;
w + + ;
}
if ( DIR_IS_SUBDIR ( & dir ) & & printSlash ) {
MYSERIAL . write ( ' / ' ) ;
w + + ;
}
while ( w < width ) {
MYSERIAL . write ( ' ' ) ;
w + + ;
}
}
//------------------------------------------------------------------------------
// print uint8_t with width 2
static void print2u ( uint8_t v ) {
if ( v < 10 ) MYSERIAL . write ( ' 0 ' ) ;
MYSERIAL . print ( v , DEC ) ;
}
//------------------------------------------------------------------------------
/** %Print a directory date field to Serial.
/**
* % Print a directory date field to Serial .
*
* Format is yyyy - mm - dd .
*
* \ param [ in ] fatDate The date field from a directory entry .
*/
//------------------------------------------------------------------------------
/** %Print a directory date field.
/**
* % Print a directory date field .
*
* Format is yyyy - mm - dd .
*
@ -997,8 +934,9 @@ void SdBaseFile::printFatDate(uint16_t fatDate) {
print2u ( FAT_DAY ( fatDate ) ) ;
}
//------------------------------------------------------------------------------
/** %Print a directory time field.
/**
* % Print a directory time field .
*
* Format is hh : mm : ss .
*
@ -1012,11 +950,11 @@ void SdBaseFile::printFatTime(uint16_t fatTime) {
MYSERIAL . write ( ' : ' ) ;
print2u ( FAT_SECOND ( fatTime ) ) ;
}
//------------------------------------------------------------------------------
/** Print a file's name to Serial
/**
* Print a file ' s name to Serial
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
*/
bool SdBaseFile : : printName ( ) {
char name [ FILENAME_LENGTH ] ;
@ -1024,8 +962,9 @@ bool SdBaseFile::printName() {
MYSERIAL . print ( name ) ;
return true ;
}
//------------------------------------------------------------------------------
/** Read the next byte from a file.
/**
* Read the next byte from a file .
*
* \ return For success read returns the next byte in the file as an int .
* If an error occurs or end of file is reached - 1 is returned .
@ -1034,8 +973,9 @@ int16_t SdBaseFile::read() {
uint8_t b ;
return read ( & b , 1 ) = = 1 ? b : - 1 ;
}
//------------------------------------------------------------------------------
/** Read data from a file starting at the current position.
/**
* Read data from a file starting at the current position .
*
* \ param [ out ] buf Pointer to the location that will receive the data .
*
@ -1050,12 +990,11 @@ int16_t SdBaseFile::read() {
*/
int16_t SdBaseFile : : read ( void * buf , uint16_t nbyte ) {
uint8_t * dst = reinterpret_cast < uint8_t * > ( buf ) ;
uint16_t offset ;
uint16_t toRead ;
uint16_t offset , toRead ;
uint32_t block ; // raw device block number
// error if not open or write only
if ( ! isOpen ( ) | | ! ( flags_ & O_READ ) ) goto FAIL ;
if ( ! isOpen ( ) | | ! ( flags_ & O_READ ) ) return - 1 ;
// max bytes left in file
NOMORE ( nbyte , fileSize_ - curPosition_ ) ;
@ -1071,14 +1010,10 @@ int16_t SdBaseFile::read(void* buf, uint16_t nbyte) {
uint8_t blockOfCluster = vol_ - > blockOfCluster ( curPosition_ ) ;
if ( offset = = 0 & & blockOfCluster = = 0 ) {
// start of new cluster
if ( curPosition_ = = 0 ) {
// use first cluster in file
curCluster_ = firstCluster_ ;
}
else {
// get next cluster from FAT
if ( ! vol_ - > fatGet ( curCluster_ , & curCluster_ ) ) goto FAIL ;
}
if ( curPosition_ = = 0 )
curCluster_ = firstCluster_ ; // use first cluster in file
else if ( ! vol_ - > fatGet ( curCluster_ , & curCluster_ ) ) // get next cluster from FAT
return - 1 ;
}
block = vol_ - > clusterStartBlock ( curCluster_ ) + blockOfCluster ;
}
@ -1089,11 +1024,11 @@ int16_t SdBaseFile::read(void* buf, uint16_t nbyte) {
// no buffering needed if n == 512
if ( n = = 512 & & block ! = vol_ - > cacheBlockNumber ( ) ) {
if ( ! vol_ - > readBlock ( block , dst ) ) goto FAIL ;
if ( ! vol_ - > readBlock ( block , dst ) ) return - 1 ;
}
else {
// read block to cache and copy data to caller
if ( ! vol_ - > cacheRawBlock ( block , SdVolume : : CACHE_FOR_READ ) ) goto FAIL ;
if ( ! vol_ - > cacheRawBlock ( block , SdVolume : : CACHE_FOR_READ ) ) return - 1 ;
uint8_t * src = vol_ - > cache ( ) - > data + offset ;
memcpy ( dst , src , n ) ;
}
@ -1102,8 +1037,6 @@ int16_t SdBaseFile::read(void* buf, uint16_t nbyte) {
toRead - = n ;
}
return nbyte ;
FAIL :
return - 1 ;
}
/**
@ -1155,30 +1088,29 @@ int8_t SdBaseFile::readDir(dir_t* dir, char* longFilename) {
}
}
//------------------------------------------------------------------------------
// Read next directory entry into the cache
// Assumes file is correctly positioned
dir_t * SdBaseFile : : readDirCache ( ) {
uint8_t i ;
// error if not directory
if ( ! isDir ( ) ) goto FAIL ;
if ( ! isDir ( ) ) return 0 ;
// index of entry in cache
i = ( curPosition_ > > 5 ) & 0XF ;
// use read to locate and cache block
if ( read ( ) < 0 ) goto FAIL ;
if ( read ( ) < 0 ) return 0 ;
// advance to next entry
curPosition_ + = 31 ;
// return pointer to entry
return vol_ - > cache ( ) - > dir + i ;
FAIL :
return 0 ;
}
//------------------------------------------------------------------------------
/** Remove a file.
/**
* Remove a file .
*
* The directory entry and all data for the file are deleted .
*
@ -1186,19 +1118,18 @@ dir_t* SdBaseFile::readDirCache() {
* file that has a long name . For example if a file has the long name
* " New Text Document.txt " you should not delete the 8.3 name " NEWTEX~1.TXT " .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
* Reasons for failure include the file read - only , is a directory ,
* or an I / O error occurred .
*/
bool SdBaseFile : : remove ( ) {
dir_t * d ;
// free any clusters - will fail if read-only or directory
if ( ! truncate ( 0 ) ) goto FAIL ;
if ( ! truncate ( 0 ) ) return false ;
// cache directory entry
d = cacheDirEntry ( SdVolume : : CACHE_FOR_WRITE ) ;
if ( ! d ) goto FAIL ;
if ( ! d ) return false ;
// mark entry deleted
d - > name [ 0 ] = DIR_NAME_DELETED ;
@ -1209,11 +1140,10 @@ bool SdBaseFile::remove() {
// write entry to SD
return vol_ - > cacheFlush ( ) ;
return true ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
/** Remove a file.
/**
* Remove a file .
*
* The directory entry and all data for the file are deleted .
*
@ -1224,28 +1154,23 @@ bool SdBaseFile::remove() {
* file that has a long name . For example if a file has the long name
* " New Text Document.txt " you should not delete the 8.3 name " NEWTEX~1.TXT " .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
* Reasons for failure include the file is a directory , is read only ,
* \ a dirFile is not a directory , \ a path is not found
* or an I / O error occurred .
*/
bool SdBaseFile : : remove ( SdBaseFile * dirFile , const char * path ) {
SdBaseFile file ;
if ( ! file . open ( dirFile , path , O_WRITE ) ) goto FAIL ;
return file . remove ( ) ;
FAIL :
// can't set iostate - static function
return false ;
return file . open ( dirFile , path , O_WRITE ) ? file . remove ( ) : false ;
}
//------------------------------------------------------------------------------
/** Rename a file or subdirectory.
/**
* Rename a file or subdirectory .
*
* \ param [ in ] dirFile Directory for the new path .
* \ param [ in ] newPath New path name for the file / directory .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
* Reasons for failure include \ a dirFile is not open or is not a directory
* file , newPath is invalid or already exists , or an I / O error occurs .
*/
@ -1256,15 +1181,15 @@ bool SdBaseFile::rename(SdBaseFile* dirFile, const char* newPath) {
dir_t * d ;
// must be an open file or subdirectory
if ( ! ( isFile ( ) | | isSubDir ( ) ) ) goto FAIL ;
if ( ! ( isFile ( ) | | isSubDir ( ) ) ) return false ;
// can't move file
if ( vol_ ! = dirFile - > vol_ ) goto FAIL ;
if ( vol_ ! = dirFile - > vol_ ) return false ;
// sync() and cache directory entry
sync ( ) ;
d = cacheDirEntry ( SdVolume : : CACHE_FOR_WRITE ) ;
if ( ! d ) goto FAIL ;
if ( ! d ) return false ;
// save directory entry
memcpy ( & entry , d , sizeof ( entry ) ) ;
@ -1295,7 +1220,7 @@ bool SdBaseFile::rename(SdBaseFile* dirFile, const char* newPath) {
// cache new directory entry
d = cacheDirEntry ( SdVolume : : CACHE_FOR_WRITE ) ;
if ( ! d ) goto FAIL ;
if ( ! d ) return false ;
// copy all but name field to new directory entry
memcpy ( & d - > attributes , & entry . attributes , sizeof ( entry ) - sizeof ( d - > name ) ) ;
@ -1304,31 +1229,30 @@ bool SdBaseFile::rename(SdBaseFile* dirFile, const char* newPath) {
if ( dirCluster ) {
// get new dot dot
uint32_t block = vol_ - > clusterStartBlock ( dirCluster ) ;
if ( ! vol_ - > cacheRawBlock ( block , SdVolume : : CACHE_FOR_READ ) ) goto FAIL ;
if ( ! vol_ - > cacheRawBlock ( block , SdVolume : : CACHE_FOR_READ ) ) return false ;
memcpy ( & entry , & vol_ - > cache ( ) - > dir [ 1 ] , sizeof ( entry ) ) ;
// free unused cluster
if ( ! vol_ - > freeChain ( dirCluster ) ) goto FAIL ;
if ( ! vol_ - > freeChain ( dirCluster ) ) return false ;
// store new dot dot
block = vol_ - > clusterStartBlock ( firstCluster_ ) ;
if ( ! vol_ - > cacheRawBlock ( block , SdVolume : : CACHE_FOR_WRITE ) ) goto FAIL ;
if ( ! vol_ - > cacheRawBlock ( block , SdVolume : : CACHE_FOR_WRITE ) ) return false ;
memcpy ( & vol_ - > cache ( ) - > dir [ 1 ] , & entry , sizeof ( entry ) ) ;
}
return vol_ - > cacheFlush ( ) ;
restore :
d = cacheDirEntry ( SdVolume : : CACHE_FOR_WRITE ) ;
if ( ! d ) goto FAIL ;
if ( ( d = cacheDirEntry ( SdVolume : : CACHE_FOR_WRITE ) ) ) {
// restore entry
d - > name [ 0 ] = entry . name [ 0 ] ;
vol_ - > cacheFlush ( ) ;
FAIL :
}
return false ;
}
//------------------------------------------------------------------------------
/** Remove a directory file.
/**
* Remove a directory file .
*
* The directory file will be removed only if it is empty and is not the
* root directory . rmdir ( ) follows DOS and Windows and ignores the
@ -1338,37 +1262,35 @@ restore:
* directory that has a long name . For example if a directory has the
* long name " New folder " you should not delete the 8.3 name " NEWFOL~1 " .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
* Reasons for failure include the file is not a directory , is the root
* directory , is not empty , or an I / O error occurred .
*/
bool SdBaseFile : : rmdir ( ) {
// must be open subdirectory
if ( ! isSubDir ( ) ) goto FAIL ;
if ( ! isSubDir ( ) ) return false ;
rewind ( ) ;
// make sure directory is empty
while ( curPosition_ < fileSize_ ) {
dir_t * p = readDirCache ( ) ;
if ( ! p ) goto FAIL ;
if ( ! p ) return false ;
// done if past last used entry
if ( p - > name [ 0 ] = = DIR_NAME_FREE ) break ;
// skip empty slot, '.' or '..'
if ( p - > name [ 0 ] = = DIR_NAME_DELETED | | p - > name [ 0 ] = = ' . ' ) continue ;
// error not empty
if ( DIR_IS_FILE_OR_SUBDIR ( p ) ) goto FAIL ;
if ( DIR_IS_FILE_OR_SUBDIR ( p ) ) return false ;
}
// convert empty directory to normal file for remove
type_ = FAT_FILE_TYPE_NORMAL ;
flags_ | = O_WRITE ;
return remove ( ) ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
/** Recursively delete a directory and all contained files.
/**
* Recursively delete a directory and all contained files .
*
* This is like the Unix / Linux ' rm - rf * ' if called with the root directory
* hence the name .
@ -1380,8 +1302,7 @@ bool SdBaseFile::rmdir() {
* \ note This function should not be used to delete the 8.3 version of
* a directory that has a long name . See remove ( ) and rmdir ( ) .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
*/
bool SdBaseFile : : rmRfStar ( ) {
uint32_t index ;
@ -1392,7 +1313,7 @@ bool SdBaseFile::rmRfStar() {
index = curPosition_ / 32 ;
dir_t * p = readDirCache ( ) ;
if ( ! p ) goto FAIL ;
if ( ! p ) return false ;
// done if past last entry
if ( p - > name [ 0 ] = = DIR_NAME_FREE ) break ;
@ -1403,31 +1324,30 @@ bool SdBaseFile::rmRfStar() {
// skip if part of long file name or volume label in root
if ( ! DIR_IS_FILE_OR_SUBDIR ( p ) ) continue ;
if ( ! f . open ( this , index , O_READ ) ) goto FAIL ;
if ( ! f . open ( this , index , O_READ ) ) return false ;
if ( f . isSubDir ( ) ) {
// recursively delete
if ( ! f . rmRfStar ( ) ) goto FAIL ;
if ( ! f . rmRfStar ( ) ) return false ;
}
else {
// ignore read-only
f . flags_ | = O_WRITE ;
if ( ! f . remove ( ) ) goto FAIL ;
if ( ! f . remove ( ) ) return false ;
}
// position to next entry if required
if ( curPosition_ ! = ( 32 * ( index + 1 ) ) ) {
if ( ! seekSet ( 32 * ( index + 1 ) ) ) goto FAIL ;
if ( ! seekSet ( 32 * ( index + 1 ) ) ) return false ;
}
}
// don't try to delete root
if ( ! isRoot ( ) ) {
if ( ! rmdir ( ) ) goto FAIL ;
if ( ! rmdir ( ) ) return false ;
}
return true ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
/** Create a file object and open it in the current working directory.
/**
* Create a file object and open it in the current working directory .
*
* \ param [ in ] path A path with a valid 8.3 DOS name for a file to be opened .
*
@ -1439,64 +1359,54 @@ SdBaseFile::SdBaseFile(const char* path, uint8_t oflag) {
writeError = false ;
open ( path , oflag ) ;
}
//------------------------------------------------------------------------------
/** Sets a file's position.
/**
* Sets a file ' s position .
*
* \ param [ in ] pos The new position in bytes from the beginning of the file .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
*/
bool SdBaseFile : : seekSet ( uint32_t pos ) {
uint32_t nCur ;
uint32_t nNew ;
bool SdBaseFile : : seekSet ( const uint32_t pos ) {
uint32_t nCur , nNew ;
// error if file not open or seek past end of file
if ( ! isOpen ( ) | | pos > fileSize_ ) goto FAIL ;
if ( ! isOpen ( ) | | pos > fileSize_ ) return false ;
if ( type_ = = FAT_FILE_TYPE_ROOT_FIXED ) {
curPosition_ = pos ;
goto don e;
return tru e;
}
if ( pos = = 0 ) {
// set position to start of file
curCluster_ = 0 ;
curPosition_ = 0 ;
goto done ;
curCluster_ = curPosition_ = 0 ; // set position to start of file
return true ;
}
// calculate cluster index for cur and new position
nCur = ( curPosition_ - 1 ) > > ( vol_ - > clusterSizeShift_ + 9 ) ;
nNew = ( pos - 1 ) > > ( vol_ - > clusterSizeShift_ + 9 ) ;
if ( nNew < nCur | | curPosition_ = = 0 ) {
// must follow chain from first cluster
curCluster_ = firstCluster_ ;
}
else {
// advance from curPosition
nNew - = nCur ;
}
while ( nNew - - ) {
if ( ! vol_ - > fatGet ( curCluster_ , & curCluster_ ) ) goto FAIL ;
}
curPosition_ = pos ;
if ( nNew < nCur | | curPosition_ = = 0 )
curCluster_ = firstCluster_ ; // must follow chain from first cluster
else
nNew - = nCur ; // advance from curPosition
done :
return tru e;
while ( nNew - - )
if ( ! vol_ - > fatGet ( curCluster_ , & curCluster_ ) ) return false ;
FAIL :
return fals e;
curPosition_ = pos ;
return true ;
}
//------------------------------------------------------------------------------
void SdBaseFile : : setpos ( filepos_t * pos ) {
curPosition_ = pos - > position ;
curCluster_ = pos - > cluster ;
}
//------------------------------------------------------------------------------
/** The sync() call causes all modified data and directory fields
/**
* The sync ( ) call causes all modified data and directory fields
* to be written to the storage device .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
* Reasons for failure include a call to sync ( ) before a file has been
* opened or an I / O error .
*/
@ -1530,8 +1440,9 @@ bool SdBaseFile::sync() {
writeError = true ;
return false ;
}
//------------------------------------------------------------------------------
/** Copy a file's timestamps
/**
* Copy a file ' s timestamps
*
* \ param [ in ] file File to copy timestamps from .
*
@ -1539,21 +1450,20 @@ bool SdBaseFile::sync() {
* Modify and access timestamps may be overwritten if a date time callback
* function has been set by dateTimeCallback ( ) .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
*/
bool SdBaseFile : : timestamp ( SdBaseFile * file ) {
dir_t * d ;
dir_t dir ;
// get timestamps
if ( ! file - > dirEntry ( & dir ) ) goto FAIL ;
if ( ! file - > dirEntry ( & dir ) ) return false ;
// update directory fields
if ( ! sync ( ) ) goto FAIL ;
if ( ! sync ( ) ) return false ;
d = cacheDirEntry ( SdVolume : : CACHE_FOR_WRITE ) ;
if ( ! d ) goto FAIL ;
if ( ! d ) return false ;
// copy timestamps
d - > lastAccessDate = dir . lastAccessDate ;
@ -1565,12 +1475,10 @@ bool SdBaseFile::timestamp(SdBaseFile* file) {
// write back entry
return vol_ - > cacheFlush ( ) ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
/** Set a file's timestamps in its directory entry.
/**
* Set a file ' s timestamps in its directory entry .
*
* \ param [ in ] flags Values for \ a flags are constructed by a bitwise - inclusive
* OR of flags from the following list
@ -1600,13 +1508,11 @@ bool SdBaseFile::timestamp(SdBaseFile* file) {
* Modify and access timestamps may be overwritten if a date time callback
* function has been set by dateTimeCallback ( ) .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
*/
bool SdBaseFile : : timestamp ( uint8_t flags , uint16_t year , uint8_t month ,
uint8_t day , uint8_t hour , uint8_t minute , uint8_t second ) {
uint16_t dirDate ;
uint16_t dirTime ;
uint16_t dirDate , dirTime ;
dir_t * d ;
if ( ! isOpen ( )
@ -1619,13 +1525,13 @@ bool SdBaseFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
| | hour > 23
| | minute > 59
| | second > 59 ) {
goto FAIL ;
return false ;
}
// update directory entry
if ( ! sync ( ) ) goto FAIL ;
if ( ! sync ( ) ) return false ;
d = cacheDirEntry ( SdVolume : : CACHE_FOR_WRITE ) ;
if ( ! d ) goto FAIL ;
if ( ! d ) return false ;
dirDate = FAT_DATE ( year , month , day ) ;
dirTime = FAT_TIME ( hour , minute , second ) ;
@ -1643,28 +1549,26 @@ bool SdBaseFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
d - > lastWriteTime = dirTime ;
}
return vol_ - > cacheFlush ( ) ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
/** Truncate a file to a specified length. The current file position
/**
* Truncate a file to a specified length . The current file position
* will be maintained if it is less than or equal to \ a length otherwise
* it will be set to end of file .
*
* \ param [ in ] length The desired length for the file .
*
* \ return The value one , true , is returned for success and
* the value zero , false , is returned for failure .
* \ return true for success , false for failure .
* Reasons for failure include file is read only , file is a directory ,
* \ a length is greater than the current file size or an I / O error occurs .
*/
bool SdBaseFile : : truncate ( uint32_t length ) {
uint32_t newPos ;
// error if not a normal file or read-only
if ( ! isFile ( ) | | ! ( flags_ & O_WRITE ) ) goto FAIL ;
if ( ! isFile ( ) | | ! ( flags_ & O_WRITE ) ) return false ;
// error if length is greater than current size
if ( length > fileSize_ ) goto FAIL ;
if ( length > fileSize_ ) return false ;
// fileSize and length are zero - nothing to do
if ( fileSize_ = = 0 ) return true ;
@ -1673,23 +1577,23 @@ bool SdBaseFile::truncate(uint32_t length) {
newPos = curPosition_ > length ? length : curPosition_ ;
// position to last cluster in truncated file
if ( ! seekSet ( length ) ) goto FAIL ;
if ( ! seekSet ( length ) ) return false ;
if ( length = = 0 ) {
// free all clusters
if ( ! vol_ - > freeChain ( firstCluster_ ) ) goto FAIL ;
if ( ! vol_ - > freeChain ( firstCluster_ ) ) return false ;
firstCluster_ = 0 ;
}
else {
uint32_t toFree ;
if ( ! vol_ - > fatGet ( curCluster_ , & toFree ) ) goto FAIL ;
if ( ! vol_ - > fatGet ( curCluster_ , & toFree ) ) return false ;
if ( ! vol_ - > isEOC ( toFree ) ) {
// free extra clusters
if ( ! vol_ - > freeChain ( toFree ) ) goto FAIL ;
if ( ! vol_ - > freeChain ( toFree ) ) return false ;
// current cluster is end of chain
if ( ! vol_ - > fatPutEOC ( curCluster_ ) ) goto FAIL ;
if ( ! vol_ - > fatPutEOC ( curCluster_ ) ) return false ;
}
}
fileSize_ = length ;
@ -1697,16 +1601,14 @@ bool SdBaseFile::truncate(uint32_t length) {
// need to update directory entry
flags_ | = F_FILE_DIR_DIRTY ;
if ( ! sync ( ) ) goto FAIL ;
if ( ! sync ( ) ) return false ;
// set file to correct position
return seekSet ( newPos ) ;
FAIL :
return false ;
}
//------------------------------------------------------------------------------
/** Write data to an open file.
/**
* Write data to an open file .
*
* \ note Data is moved to the cache but may not be written to the
* storage device until sync ( ) is called .
@ -1816,11 +1718,9 @@ int16_t SdBaseFile::write(const void* buf, uint16_t nbyte) {
writeError = true ;
return - 1 ;
}
//------------------------------------------------------------------------------
// suppress cpplint warnings with NOLINT comment
# if ALLOW_DEPRECATED_FUNCTIONS && !defined(DOXYGEN)
void ( * SdBaseFile : : oldDateTime_ ) ( uint16_t & date , uint16_t & time ) = 0 ; // NOLINT
# endif // ALLOW_DEPRECATED_FUNCTIONS
# if ALLOW_DEPRECATED_FUNCTIONS
void ( * SdBaseFile : : oldDateTime_ ) ( uint16_t & date , uint16_t & time ) = 0 ;
# endif
# endif // SDSUPPORT