Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers fs_port_fatfs.c Source File

fs_port_fatfs.c

Go to the documentation of this file.
00001 /**
00002  * @file fs_port_fatfs.c
00003  * @brief File system abstraction layer (FatFs)
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU General Public License
00011  * as published by the Free Software Foundation; either version 2
00012  * of the License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software Foundation,
00021  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00022  *
00023  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00024  * @version 1.7.6
00025  **/
00026 
00027 //Dependencies
00028 #include <string.h>
00029 #include "fs_port.h"
00030 #include "error.h"
00031 #include "debug.h"
00032 
00033 //FatFs specific headers
00034 #include "ff.h"
00035 
00036 //File system objects
00037 static FATFS fs;
00038 static FIL fileTable[FS_MAX_FILES];
00039 static DIR dirTable[FS_MAX_DIRS];
00040 
00041 //Mutex that protects critical sections
00042 static OsMutex fsMutex;
00043 
00044 
00045 /**
00046  * @brief File system initialization
00047  * @return Error code
00048  **/
00049 
00050 error_t fsInit(void)
00051 {
00052    FRESULT res;
00053 
00054    //Clear file system objects
00055    memset(fileTable, 0, sizeof(fileTable));
00056    memset(dirTable, 0, sizeof(dirTable));
00057 
00058    //Create a mutex to protect critical sections
00059    if(!osCreateMutex(&fsMutex))
00060    {
00061       //Failed to create mutex
00062       return ERROR_OUT_OF_RESOURCES;
00063    }
00064 
00065 //Revision 0.09b or lower?
00066 #if (_FATFS == 124 || _FATFS == 126 || _FATFS == 8085 || _FATFS == 8255 || \
00067    _FATFS == 8237 || _FATFS == 6502 || _FATFS == 4004 || _FATFS == 82786)
00068    //Mount file system
00069    res = f_mount(0, &fs);
00070 //Revision 0.10 or higher?
00071 #else
00072    //Mount file system
00073    res = f_mount(&fs, "", 1);
00074 #endif
00075 
00076    //Failed to mount file system?
00077    if(res != FR_OK)
00078    {
00079       //Clean up side effects
00080       osDeleteMutex(&fsMutex);
00081       //Report an error
00082       return ERROR_FAILURE;
00083    }
00084 
00085    //Successful processing
00086    return NO_ERROR;
00087 }
00088 
00089 
00090 /**
00091  * @brief Check whether a file exists
00092  * @param[in] path NULL-terminated string specifying the filename
00093  * @return The function returns TRUE if the file exists. Otherwise FALSE is returned
00094  **/
00095 
00096 bool_t fsFileExists(const char_t *path)
00097 {
00098    FRESULT res;
00099    FILINFO fno;
00100 
00101 //Long filename support?
00102 #if (_USE_LFN != 0)
00103    fno.lfname = NULL;
00104    fno.lfsize = 0;
00105 #endif
00106 
00107    //Make sure the pathname is valid
00108    if(path == NULL)
00109       return FALSE;
00110 
00111 #if (_FS_REENTRANT == 0)
00112    //Enter critical section
00113    osAcquireMutex(&fsMutex);
00114 #endif
00115 
00116    //Check whether the file exists
00117    res = f_stat(path, &fno);
00118 
00119 #if (_FS_REENTRANT == 0)
00120    //Leave critical section
00121    osReleaseMutex(&fsMutex);
00122 #endif
00123 
00124    //Any error to report?
00125    if(res != FR_OK)
00126       return FALSE;
00127 
00128    //Valid file?
00129    if(fno.fattrib & AM_DIR)
00130       return FALSE;
00131    else
00132       return TRUE;
00133 }
00134 
00135 
00136 /**
00137  * @brief Retrieve the size of the specified file
00138  * @param[in] path NULL-terminated string specifying the filename
00139  * @param[out] size Size of the file in bytes
00140  * @return Error code
00141  **/
00142 
00143 error_t fsGetFileSize(const char_t *path, uint32_t *size)
00144 {
00145    FRESULT res;
00146    FILINFO fno;
00147 
00148 //Long filename support?
00149 #if (_USE_LFN != 0)
00150    fno.lfname = NULL;
00151    fno.lfsize = 0;
00152 #endif
00153 
00154    //Check parameters
00155    if(path == NULL || size == NULL)
00156       return ERROR_INVALID_PARAMETER;
00157 
00158 #if (_FS_REENTRANT == 0)
00159    //Enter critical section
00160    osAcquireMutex(&fsMutex);
00161 #endif
00162 
00163    //Retrieve information about the specified file
00164    res = f_stat(path, &fno);
00165 
00166 #if (_FS_REENTRANT == 0)
00167    //Leave critical section
00168    osReleaseMutex(&fsMutex);
00169 #endif
00170 
00171    //Any error to report?
00172    if(res != FR_OK)
00173       return ERROR_FAILURE;
00174    //Valid file?
00175    if(fno.fattrib & AM_DIR)
00176       return ERROR_FAILURE;
00177 
00178    //Return the size of the file
00179    *size = fno.fsize;
00180 
00181    //Successful processing
00182    return NO_ERROR;
00183 }
00184 
00185 
00186 /**
00187  * @brief Rename the specified file
00188  * @param[in] oldPath NULL-terminated string specifying the pathname of the file to be renamed
00189  * @param[in] newPath NULL-terminated string specifying the new filename
00190  * @return Error code
00191  **/
00192 
00193 error_t fsRenameFile(const char_t *oldPath, const char_t *newPath)
00194 {
00195    FRESULT res;
00196 
00197    //Check parameters
00198    if(oldPath == NULL || newPath == NULL)
00199       return ERROR_INVALID_PARAMETER;
00200 
00201 #if (_FS_REENTRANT == 0)
00202    //Enter critical section
00203    osAcquireMutex(&fsMutex);
00204 #endif
00205 
00206    //Rename the specified file
00207    res = f_rename(oldPath, newPath);
00208 
00209 #if (_FS_REENTRANT == 0)
00210    //Leave critical section
00211    osReleaseMutex(&fsMutex);
00212 #endif
00213 
00214    //Any error to report?
00215    if(res != FR_OK)
00216       return ERROR_FAILURE;
00217 
00218    //Successful processing
00219    return NO_ERROR;
00220 }
00221 
00222 
00223 /**
00224  * @brief Delete a file
00225  * @param[in] path NULL-terminated string specifying the filename
00226  * @return Error code
00227  **/
00228 
00229 error_t fsDeleteFile(const char_t *path)
00230 {
00231    FRESULT res;
00232 
00233    //Make sure the pathname is valid
00234    if(path == NULL)
00235       return ERROR_INVALID_PARAMETER;
00236 
00237 #if (_FS_REENTRANT == 0)
00238    //Enter critical section
00239    osAcquireMutex(&fsMutex);
00240 #endif
00241 
00242    //Delete the specified file
00243    res = f_unlink(path);
00244 
00245 #if (_FS_REENTRANT == 0)
00246    //Leave critical section
00247    osReleaseMutex(&fsMutex);
00248 #endif
00249 
00250    //Any error to report?
00251    if(res != FR_OK)
00252       return ERROR_FAILURE;
00253 
00254    //Successful processing
00255    return NO_ERROR;
00256 }
00257 
00258 
00259 /**
00260  * @brief Open the specified file for reading or writing
00261  * @param[in] path NULL-terminated string specifying the filename
00262  * @param[in] mode Type of access permitted (FS_FILE_MODE_READ,
00263  *   FS_FILE_MODE_WRITE or FS_FILE_MODE_CREATE)
00264  * @return File handle
00265  **/
00266 
00267 FsFile *fsOpenFile(const char_t *path, uint_t mode)
00268 {
00269    uint_t i;
00270    uint_t flags;
00271    FRESULT res;
00272 
00273    //File pointer
00274    FsFile *file = NULL;
00275 
00276    //Make sure the pathname is valid
00277    if(path == NULL)
00278       return NULL;
00279 
00280    //Enter critical section
00281    osAcquireMutex(&fsMutex);
00282 
00283    //Loop through the file objects
00284    for(i = 0; i < FS_MAX_FILES; i++)
00285    {
00286       //Unused file object found?
00287       if(fileTable[i].fs == NULL)
00288       {
00289          //Default access mode
00290          flags = 0;
00291 
00292          //Check access mode
00293          if(mode & FS_FILE_MODE_READ)
00294             flags |= FA_READ;
00295          if(mode & FS_FILE_MODE_WRITE)
00296             flags |= FA_WRITE;
00297          if(mode & FS_FILE_MODE_CREATE)
00298             flags |= FA_OPEN_ALWAYS;
00299          if(mode & FS_FILE_MODE_TRUNC)
00300             flags |= FA_CREATE_ALWAYS;
00301 
00302          //Open the specified file
00303          res = f_open(&fileTable[i], path, flags);
00304 
00305          //Check status code
00306          if(res == FR_OK)
00307             file = &fileTable[i];
00308 
00309          //Stop immediately
00310          break;
00311       }
00312    }
00313 
00314    //Leave critical section
00315    osReleaseMutex(&fsMutex);
00316    //Return a handle to the file
00317    return file;
00318 }
00319 
00320 
00321 /**
00322  * @brief Move to specified position in file
00323  * @param[in] file Handle that identifies the file
00324  * @param[in] offset Number of bytes to move from origin
00325  * @param[in] origin Position used as reference for the offset (FS_SEEK_SET,
00326  *   FS_SEEK_CUR or FS_SEEK_END)
00327  * @return Error code
00328  **/
00329 
00330 error_t fsSeekFile(FsFile *file, int_t offset, uint_t origin)
00331 {
00332    FRESULT res;
00333 
00334    //Make sure the file pointer is valid
00335    if(file == NULL)
00336       return ERROR_INVALID_PARAMETER;
00337 
00338 #if (_FS_REENTRANT == 0)
00339    //Enter critical section
00340    osAcquireMutex(&fsMutex);
00341 #endif
00342 
00343    //Offset is relative to the current file pointer position?
00344    if(origin == FS_SEEK_CUR)
00345       offset += f_tell((FIL *) file);
00346    //Offset is relative to the end of the file?
00347    else if(origin == FS_SEEK_END)
00348       offset += f_size((FIL *) file);
00349 
00350    //Move read/write pointer
00351    res = f_lseek((FIL *) file, offset);
00352 
00353 #if (_FS_REENTRANT == 0)
00354    //Leave critical section
00355    osReleaseMutex(&fsMutex);
00356 #endif
00357 
00358    //Any error to report?
00359    if(res != FR_OK)
00360       return ERROR_FAILURE;
00361 
00362    //Successful processing
00363    return NO_ERROR;
00364 }
00365 
00366 
00367 /**
00368  * @brief Write data to the specified file
00369  * @param[in] file Handle that identifies the file to be written
00370  * @param[in] data Pointer to a buffer containing the data to be written
00371  * @param[in] length Number of data bytes to write
00372  * @return Error code
00373  **/
00374 
00375 error_t fsWriteFile(FsFile *file, void *data, size_t length)
00376 {
00377    UINT n;
00378    FRESULT res;
00379 
00380    //Make sure the file pointer is valid
00381    if(file == NULL)
00382       return ERROR_INVALID_PARAMETER;
00383 
00384 #if (_FS_REENTRANT == 0)
00385    //Enter critical section
00386    osAcquireMutex(&fsMutex);
00387 #endif
00388 
00389    //Write data
00390    res = f_write((FIL *) file, data, length, &n);
00391 
00392 #if (_FS_REENTRANT == 0)
00393    //Leave critical section
00394    osReleaseMutex(&fsMutex);
00395 #endif
00396 
00397    //Any error to report?
00398    if(res != FR_OK)
00399       return ERROR_FAILURE;
00400 
00401    //Sanity check
00402    if(n != length)
00403       return ERROR_FAILURE;
00404 
00405    //Successful processing
00406    return NO_ERROR;
00407 }
00408 
00409 
00410 /**
00411  * @brief Read data from the specified file
00412  * @param[in] file Handle that identifies the file to be read
00413  * @param[in] data Pointer to the buffer where to copy the data
00414  * @param[in] size Size of the buffer, in bytes
00415  * @param[out] length Number of data bytes that have been read
00416  * @return Error code
00417  **/
00418 
00419 error_t fsReadFile(FsFile *file, void *data, size_t size, size_t *length)
00420 {
00421    UINT n;
00422    FRESULT res;
00423 
00424    //No data has been read yet
00425    *length = 0;
00426 
00427    //Make sure the file pointer is valid
00428    if(file == NULL)
00429       return ERROR_INVALID_PARAMETER;
00430 
00431 #if (_FS_REENTRANT == 0)
00432    //Enter critical section
00433    osAcquireMutex(&fsMutex);
00434 #endif
00435 
00436    //Read data
00437    res = f_read((FIL *) file, data, size, &n);
00438 
00439 #if (_FS_REENTRANT == 0)
00440    //Leave critical section
00441    osReleaseMutex(&fsMutex);
00442 #endif
00443 
00444    //Any error to report?
00445    if(res != FR_OK)
00446       return ERROR_FAILURE;
00447 
00448    //End of file?
00449    if(!n)
00450       return ERROR_END_OF_FILE;
00451 
00452    //Total number of data that have been read
00453    *length = n;
00454    //Successful processing
00455    return NO_ERROR;
00456 }
00457 
00458 
00459 /**
00460  * @brief Close a file
00461  * @param[in] file Handle that identifies the file to be closed
00462  **/
00463 
00464 void fsCloseFile(FsFile *file)
00465 {
00466    //Make sure the file pointer is valid
00467    if(file != NULL)
00468    {
00469       //Enter critical section
00470       osAcquireMutex(&fsMutex);
00471 
00472       //Close the specified file
00473       f_close((FIL *) file);
00474       //Mark the corresponding entry as free
00475       ((FIL *) file)->fs = NULL;
00476 
00477       //Leave critical section
00478       osReleaseMutex(&fsMutex);
00479    }
00480 }
00481 
00482 
00483 /**
00484  * @brief Check whether a directory exists
00485  * @param[in] path NULL-terminated string specifying the directory path
00486  * @return The function returns TRUE if the directory exists. Otherwise FALSE is returned
00487  **/
00488 
00489 bool_t fsDirExists(const char_t *path)
00490 {
00491    FRESULT res;
00492    FILINFO fno;
00493 
00494 //Long filename support?
00495 #if (_USE_LFN != 0)
00496    fno.lfname = NULL;
00497    fno.lfsize = 0;
00498 #endif
00499 
00500    //Make sure the pathname is valid
00501    if(path == NULL)
00502       return FALSE;
00503 
00504    //Root directory?
00505    if(!strcmp(path, "/"))
00506       return TRUE;
00507 
00508 #if (_FS_REENTRANT == 0)
00509    //Enter critical section
00510    osAcquireMutex(&fsMutex);
00511 #endif
00512 
00513    //Check whether the file exists
00514    res = f_stat(path, &fno);
00515 
00516 #if (_FS_REENTRANT == 0)
00517    //Leave critical section
00518    osReleaseMutex(&fsMutex);
00519 #endif
00520 
00521    //Any error to report?
00522    if(res != FR_OK)
00523       return FALSE;
00524 
00525    //Valid directory?
00526    if(fno.fattrib & AM_DIR)
00527       return TRUE;
00528    else
00529       return FALSE;
00530 }
00531 
00532 
00533 /**
00534  * @brief Create a directory
00535  * @param[in] path NULL-terminated string specifying the directory path
00536  * @return Error code
00537  **/
00538 
00539 error_t fsCreateDir(const char_t *path)
00540 {
00541    FRESULT res;
00542 
00543    //Make sure the pathname is valid
00544    if(path == NULL)
00545       return ERROR_INVALID_PARAMETER;
00546 
00547 #if (_FS_REENTRANT == 0)
00548    //Enter critical section
00549    osAcquireMutex(&fsMutex);
00550 #endif
00551 
00552    //Create a new directory
00553    res = f_mkdir(path);
00554 
00555 #if (_FS_REENTRANT == 0)
00556    //Leave critical section
00557    osReleaseMutex(&fsMutex);
00558 #endif
00559 
00560    //Any error to report?
00561    if(res != FR_OK)
00562       return ERROR_FAILURE;
00563 
00564    //Successful processing
00565    return NO_ERROR;
00566 }
00567 
00568 
00569 /**
00570  * @brief Remove a directory
00571  * @param[in] path NULL-terminated string specifying the directory path
00572  * @return Error code
00573  **/
00574 
00575 error_t fsRemoveDir(const char_t *path)
00576 {
00577    FRESULT res;
00578 
00579    //Make sure the pathname is valid
00580    if(path == NULL)
00581       return ERROR_INVALID_PARAMETER;
00582 
00583 #if (_FS_REENTRANT == 0)
00584    //Enter critical section
00585    osAcquireMutex(&fsMutex);
00586 #endif
00587 
00588    //Remove the specified directory
00589    res = f_unlink(path);
00590 
00591 #if (_FS_REENTRANT == 0)
00592    //Leave critical section
00593    osReleaseMutex(&fsMutex);
00594 #endif
00595 
00596    //Any error to report?
00597    if(res != FR_OK)
00598       return ERROR_FAILURE;
00599 
00600    //Successful processing
00601    return NO_ERROR;
00602 }
00603 
00604 
00605 /**
00606  * @brief Open a directory stream
00607  * @param[in] path NULL-terminated string specifying the directory path
00608  * @return Directory handle
00609  **/
00610 
00611 FsDir *fsOpenDir(const char_t *path)
00612 {
00613    uint_t i;
00614    FRESULT res;
00615 
00616    //Directory pointer
00617    FsDir *dir = NULL;
00618 
00619    //Make sure the pathname is valid
00620    if(path == NULL)
00621       return NULL;
00622 
00623    //Enter critical section
00624    osAcquireMutex(&fsMutex);
00625 
00626    //Loop through the directory objects
00627    for(i = 0; i < FS_MAX_DIRS; i++)
00628    {
00629       //Unused directory object found?
00630       if(dirTable[i].fs == NULL)
00631       {
00632          //Open the specified directory
00633          res = f_opendir(&dirTable[i], path);
00634 
00635          //Check status code
00636          if(res == FR_OK)
00637             dir = &dirTable[i];
00638 
00639          //Stop immediately
00640          break;
00641       }
00642    }
00643 
00644    //Leave critical section
00645    osReleaseMutex(&fsMutex);
00646    //Return a handle to the directory
00647    return dir;
00648 }
00649 
00650 
00651 /**
00652  * @brief Read an entry from the specified directory stream
00653  * @param[in] dir Handle that identifies the directory
00654  * @param[out] dirEntry Pointer to a directory entry
00655  * @return Error code
00656  **/
00657 
00658 error_t fsReadDir(FsDir *dir, FsDirEntry *dirEntry)
00659 {
00660    FRESULT res;
00661    FILINFO fno;
00662    char_t *fn;
00663    size_t n;
00664 
00665 //Long filename support?
00666 #if (_USE_LFN != 0)
00667    char_t lfn[_MAX_LFN + 1];
00668    fno.lfname = lfn;
00669    fno.lfsize = sizeof(lfn);
00670 #endif
00671 
00672    //Make sure the directory pointer is valid
00673    if(dir == NULL)
00674       return ERROR_INVALID_PARAMETER;
00675 
00676 #if (_FS_REENTRANT == 0)
00677    //Enter critical section
00678    osAcquireMutex(&fsMutex);
00679 #endif
00680 
00681    //Read the specified directory
00682    res = f_readdir((DIR *) dir, &fno);
00683 
00684 #if (_FS_REENTRANT == 0)
00685    //Leave critical section
00686    osReleaseMutex(&fsMutex);
00687 #endif
00688 
00689    //Any error to report?
00690    if(res != FR_OK)
00691       return ERROR_FAILURE;
00692 
00693    //End of the directory stream?
00694    if(fno.fname[0] == '\0')
00695       return ERROR_END_OF_STREAM;
00696 
00697 //Long filename support?
00698 #if (_USE_LFN != 0)
00699    fn = (*fno.lfname != '\0') ? fno.lfname : fno.fname;
00700 #else
00701    fn = fno.fname;
00702 #endif
00703 
00704    //File attributes
00705    dirEntry->attributes = fno.fattrib;
00706    //File size
00707    dirEntry->size = fno.fsize;
00708    //Last modified date
00709    dirEntry->modified.year = 1980 + ((fno.fdate >> 9) & 0x7F);
00710    dirEntry->modified.month = (fno.fdate >> 5) & 0x0F;
00711    dirEntry->modified.day = fno.fdate & 0x1F;
00712    dirEntry->modified.dayOfWeek = 0;
00713    //Last modified time
00714    dirEntry->modified.hours = (fno.ftime >> 11) & 0x1F;
00715    dirEntry->modified.minutes = (fno.ftime >> 5) & 0x3F;
00716    dirEntry->modified.seconds = (fno.ftime & 0x1F) * 2;
00717    dirEntry->modified.milliseconds = 0;
00718 
00719    //Make sure the date is valid
00720    dirEntry->modified.month = MAX(dirEntry->modified.month, 1);
00721    dirEntry->modified.month = MIN(dirEntry->modified.month, 12);
00722    dirEntry->modified.day = MAX(dirEntry->modified.day, 1);
00723    dirEntry->modified.day = MIN(dirEntry->modified.day, 31);
00724 
00725    //Retrieve the length of the file name
00726    n = strlen(fn);
00727    //Limit the number of characters to be copied
00728    n = MIN(n, FS_MAX_NAME_LEN);
00729 
00730    //Copy file name
00731    strncpy(dirEntry->name, fn, n);
00732    //Properly terminate the string with a NULL character
00733    dirEntry->name[n] = '\0';
00734 
00735    //Successful processing
00736    return NO_ERROR;
00737 }
00738 
00739 
00740 /**
00741  * @brief Close a directory stream
00742  * @param[in] dir Handle that identifies the directory to be closed
00743  **/
00744 
00745 void fsCloseDir(FsDir *dir)
00746 {
00747    //Make sure the directory pointer is valid
00748    if(dir != NULL)
00749    {
00750       //Enter critical section
00751       osAcquireMutex(&fsMutex);
00752 
00753 #if (_FATFS == 80960)
00754       //Close the specified directory
00755       f_closedir((DIR *) dir);
00756 #endif
00757       //Mark the corresponding entry as free
00758       ((DIR *) dir)->fs = NULL;
00759 
00760       //Leave critical section
00761       osReleaseMutex(&fsMutex);
00762    }
00763 }
00764