Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers esfs.c Source File

esfs.c

00001 /*
00002  * Copyright (c) 2016 ARM Limited. All rights reserved.
00003  * SPDX-License-Identifier: Apache-2.0
00004  * Licensed under the Apache License, Version 2.0 (the License); you may
00005  * not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  * http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
00012  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 
00018 
00019 // ----------------------------------------------------------- Includes -----------------------------------------------------------
00020 
00021 #ifdef MBED_CLOUD_CLIENT_USER_CONFIG_FILE
00022 #include MBED_CLOUD_CLIENT_USER_CONFIG_FILE
00023 #endif
00024 
00025 
00026 #include "pal.h"
00027 #include "esfs.h"
00028 #include "esfs_file_name.h"
00029 
00030 #include "mbed-trace/mbed_trace.h"
00031 
00032 
00033 #include <string.h>  // For memcmp and strncat
00034 
00035 
00036 
00037 // --------------------------------------------------------- Definitions ----------------------------------------------------------
00038 
00039 
00040 #define TRACE_GROUP                     "esfs"  // Maximum 4 characters
00041 
00042 // We do not really know what other uses (if any) the file system card will have.
00043 // We will assume that it may contain other files and we will keep all ESFS files in one directory.
00044 // A future enhancement could be to put files that are not to be removed at factory reset in a separate directory.
00045 #if !defined(ESFS_WORKING_DIRECTORY)
00046 #define ESFS_WORKING_DIRECTORY          "WORKING"
00047 #endif
00048 
00049 #if !defined(ESFS_BACKUP_DIRECTORY)
00050 #define ESFS_BACKUP_DIRECTORY           "BACKUP"
00051 #endif
00052 
00053 #define FACTORY_RESET_DIR               "FR"
00054 #define FACTORY_RESET_FILE              "fr_on"
00055 
00056 // We choose a size that does not take up too much stack, but minimizes the number of reads.
00057 #define ESFS_READ_CHUNK_SIZE_IN_BYTES   (64)
00058 
00059 #define ESFS_BITS_IN_BYTE               (8)
00060 #define ESFS_AES_BLOCK_SIZE_BYTES       (16)
00061 #define ESFS_AES_IV_SIZE_BYTES          (16)
00062 #define ESFS_AES_COUNTER_INDEX_IN_IV    ESFS_AES_NONCE_SIZE_BYTES
00063 #define ESFS_AES_COUNTER_SIZE_BYTES     (8)
00064 #define ESFS_AES_KEY_SIZE_BYTES         (16)
00065 #define ESFS_AES_KEY_SIZE_BITS          (ESFS_AES_KEY_SIZE_BYTES * ESFS_BITS_IN_BYTE)
00066 
00067 // Defines the size in bytes of buffers for AES encryption / decryption.
00068 // In case we have to encrypt / decrypt a bigger amount of bytes, we loop over the buffer
00069 // and encrypt / decrypt up to ESFS_AES_BUF_SIZE_BYTES bytes on each step
00070 #define ESFS_AES_BUF_SIZE_BYTES         (256)
00071 
00072 // This should be incremented when the file format changes
00073 #define ESFS_FILE_FORMAT_VERSION        (1)
00074 
00075 #define ESFS_FILE_COPY_CHUNK_SIZE       (256)
00076 
00077 #define MAX_FULL_PATH_SIZE (PAL_MAX_FOLDER_DEPTH_CHAR + \
00078                             1 + \
00079                             PAL_MAX(sizeof(ESFS_BACKUP_DIRECTORY), sizeof(ESFS_WORKING_DIRECTORY)) + \
00080                             PAL_MAX(sizeof(FACTORY_RESET_DIR) + sizeof(FACTORY_RESET_FILE), ESFS_QUALIFIED_FILE_NAME_LENGTH))
00081 
00082 static bool esfs_initialize = false;
00083 
00084 
00085 
00086 // -------------------------------------------------- Functions Implementation ----------------------------------------------------
00087 
00088 
00089 //      ---------------------------------------------------------------
00090 //                              Helper Functions
00091 //      ---------------------------------------------------------------
00092 
00093 
00094 esfs_result_e esfs_init(void)
00095 {
00096     esfs_result_e result = ESFS_SUCCESS;
00097     tr_info("esfs_init - enter");
00098     if (!esfs_initialize)
00099     {
00100         palStatus_t pal_result = PAL_SUCCESS;
00101         esfs_file_t file_handle = {0};
00102         char dir_path[MAX_FULL_PATH_SIZE] = { 0 };
00103 
00104         pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, dir_path);
00105         if (pal_result != PAL_SUCCESS)
00106         {
00107             tr_err("esfs_init() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result);
00108             result = ESFS_ERROR;
00109             goto errorExit;
00110         }
00111 
00112         strncat(dir_path, "/" ESFS_WORKING_DIRECTORY, sizeof(ESFS_WORKING_DIRECTORY));
00113 
00114         //Looping on first file system operation to work around IOTMORF-914 - sd-driver initialization
00115         for(int i=0 ; i<100; i++)
00116         {
00117             // Create the esfs subfolder working
00118             pal_result = pal_fsMkDir(dir_path);
00119             if ((pal_result == PAL_SUCCESS) || (pal_result == PAL_ERR_FS_NAME_ALREADY_EXIST))
00120             {
00121                 break;
00122             }
00123             tr_err("esfs_init() %d", i);
00124             pal_osDelay(50);
00125 
00126         }
00127 
00128         if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NAME_ALREADY_EXIST))
00129         {
00130                 tr_err("esfs_init() - pal_fsMkDir() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result);
00131                 result = ESFS_ERROR;
00132                 goto errorExit;
00133         }
00134 
00135         pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, dir_path);
00136         if (pal_result != PAL_SUCCESS)
00137         {
00138 
00139             tr_err("esfs_init() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result);
00140             result = ESFS_ERROR;
00141             goto errorExit;
00142         }
00143 
00144         strncat(dir_path, "/" ESFS_BACKUP_DIRECTORY, sizeof(ESFS_BACKUP_DIRECTORY));
00145 
00146         // Create the directory ESFS_BACKUP_DIRECTORY
00147         pal_result = pal_fsMkDir(dir_path);
00148         if (pal_result != PAL_SUCCESS)
00149         {
00150             // Any error apart from file exist returns error.
00151             if (pal_result != PAL_ERR_FS_NAME_ALREADY_EXIST)
00152             {
00153                 tr_err("esfs_init() - pal_fsMkDir() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result);
00154                 result = ESFS_ERROR;
00155                 goto errorExit;
00156             }
00157         }
00158 
00159         // create the correct path for factory reset file fr_on
00160         strncat(dir_path, "/" FACTORY_RESET_DIR "/" FACTORY_RESET_FILE, sizeof(FACTORY_RESET_DIR) + sizeof(FACTORY_RESET_FILE));
00161         pal_result = pal_fsFopen(dir_path, PAL_FS_FLAG_READONLY, &(file_handle.file));
00162         // (res == PAL_SUCCESS) : flag file can be opened for reading --> file \FR\fr_on found
00163         //                        previous factory reset failed during execution
00164         // (res == PAL_ERR_FS_NO_FILE) : flag file was not found --> good scenario
00165         // (res != PAL_ERR_FS_NO_FILE) : file system problem
00166         if (pal_result == PAL_SUCCESS)
00167         {
00168             //  Close the file before factory reset
00169             pal_result = pal_fsFclose(&(file_handle.file));
00170             if (pal_result != PAL_SUCCESS)
00171             {
00172                 tr_err("esfs_init() - unexpected filesystem behavior pal_fsFclose() failed with pal_status = 0x%x", (unsigned int)pal_result);
00173                 result = ESFS_ERROR;
00174                 goto errorExit;
00175             }
00176             // previous factory reset failed during execution - therefore we call this factory_reset again
00177             result = esfs_factory_reset();
00178             if (result != ESFS_SUCCESS)
00179             {
00180                 tr_err("esfs_init() - esfs_factory_reset() failed with esfs_result_e = 0x%x", result);
00181                 result = ESFS_ERROR;
00182                 goto errorExit;
00183             }
00184         } else if (pal_result != PAL_ERR_FS_NO_FILE)
00185         {
00186             tr_err("esfs_init() - unexpected filesystem behavior pal_fsFopen() failed with pal_status = 0x%x", (unsigned int)pal_result);
00187             result = ESFS_ERROR;
00188             goto errorExit;
00189         }
00190 
00191         esfs_initialize = true;
00192     }
00193     return ESFS_SUCCESS;
00194 
00195 errorExit:
00196     return result;
00197 
00198 }
00199 
00200 esfs_result_e esfs_finalize(void)
00201 {
00202     esfs_initialize = false;
00203     tr_info("esfs_finalize - enter");
00204     return ESFS_SUCCESS;
00205 }
00206 
00207 // Validate that a file handle has been initialized by create or open.
00208 // Parameters : file_handle - [IN] A pointer to a file handle for which we calculate the size.
00209 // Return     : ESFS_SUCCESS on success. Error code otherwise
00210 static esfs_result_e esfs_validate(esfs_file_t *file_handle)
00211 {
00212     if(file_handle && file_handle->blob_name_length > 0)
00213     {
00214         return ESFS_SUCCESS;
00215     }
00216     else
00217     {
00218         return ESFS_ERROR;
00219     }
00220 }
00221 
00222 
00223 //Function   : esfs_not_encrypted_file_header_size
00224 //
00225 //Description: This function returns the size in bytes of the file header without the metadata values part.
00226 //             This is actually the non-encrypted part of the file header.
00227 //             It is useful for calculation the file pointer position for AES encryption / decryption which starts only from the
00228 //             encrypted part of the file.
00229 //
00230 //Parameters : file_handle - [IN] A pointer to a file handle for which we calculate the size.
00231 //
00232 //Return     : The size in bytes of the non-encrypted part of the file header
00233 static size_t esfs_not_encrypted_file_header_size(esfs_file_t *file_handle)
00234 {
00235     esfs_tlv_properties_t *tlv_properties = &(file_handle->tlv_properties);
00236 
00237     return ( file_handle->blob_name_length         +                                              // Name length field
00238              sizeof(file_handle->blob_name_length) +                                              // Name field
00239              sizeof(uint16_t)                      +                                              // Version field
00240              sizeof(uint16_t)                      +                                              // Mode field
00241              (((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) ? ESFS_AES_NONCE_SIZE_BYTES : 0) + // Nonce field [non mandatory field] 
00242              sizeof(tlv_properties->number_of_items)                                    +         // Metadata number of elements field
00243              (tlv_properties->number_of_items * sizeof(tlv_properties->tlv_items[0]))             // Metadata tlv headers
00244            );
00245 }
00246 
00247 // Returns the size in bytes of the file header.
00248 // This can only be called after the header has been read.
00249 // Parameters :
00250 // file_handle - [IN] A pointer to a file handle for which we calculate the size.
00251 static size_t esfs_file_header_size(esfs_file_t *file_handle)
00252 {
00253     size_t metadata_size = 0;
00254     esfs_tlv_properties_t *tlv_properties = &file_handle->tlv_properties;
00255 
00256     for(int i = 0; i < tlv_properties->number_of_items; i++)
00257     {
00258         metadata_size += tlv_properties->tlv_items[i].length_in_bytes;
00259     }
00260 
00261     return esfs_not_encrypted_file_header_size(file_handle) + metadata_size;
00262 }
00263 
00264 // Helper function to calculate the cmac on data that is written.
00265 // Parameters :
00266 // pbuf        - [IN] A pointer to a buffer
00267 // num_bytes   - [IN] number of bytes that we request to write.
00268 // file_handle - [IN] A pointer to a file handle for which we calculate the size.
00269 // Return     : ESFS_SUCCESS on success. Error code otherwise
00270 static esfs_result_e esfs_fwrite_and_calc_cmac(const void *pbuf, size_t num_bytes, esfs_file_t *file_handle)
00271 {
00272     palStatus_t res = pal_CMACUpdate(file_handle->signature_ctx, pbuf, num_bytes);
00273     if(res != PAL_SUCCESS)
00274     {
00275         tr_err("esfs_fwrite_and_calc_cmac() - pal_CMACUpdate failed with result = 0x%x", (unsigned int)res);
00276         return ESFS_ERROR;
00277     }
00278 
00279     size_t num_bytes_written;
00280     res = pal_fsFwrite(&file_handle->file, pbuf, num_bytes, &num_bytes_written);
00281     if(res != PAL_SUCCESS || num_bytes != num_bytes_written)
00282     {
00283         tr_err("esfs_fwrite_and_calc_cmac() - pal_fsFwrite failed, status = 0x%x, written bytes = %zu, expected = %zu",
00284                 (unsigned int)res, num_bytes_written, num_bytes);
00285         return ESFS_ERROR;
00286     }
00287 
00288     return ESFS_SUCCESS;
00289 }
00290 
00291 
00292 // Helper function to start a cmac run.
00293 // Moves the file position to the start of the file.
00294 // Parameters :
00295 // file_handle - [IN] A pointer to a file handle.
00296 // If successful it creates a cmac context which must be destroyed with a call to esfs_cmac_finish
00297 // Return     : ESFS_SUCCESS on success. Error code otherwise.
00298 static esfs_result_e esfs_cmac_start(esfs_file_t *file_handle)
00299 {
00300     unsigned char key[ESFS_CMAC_SIZE_IN_BYTES];
00301 
00302     // Get CMAC key from PAL
00303     palStatus_t res = pal_osGetDeviceKey(palOsStorageSignatureKey128Bit , &key[0], ESFS_CMAC_SIZE_IN_BYTES);
00304     if(res != PAL_SUCCESS)
00305     {
00306         tr_err("esfs_start_cmac() - pal_osGetDeviceKey() failed with pal_status = 0x%x", (unsigned int)res);
00307         return  ESFS_ERROR;
00308     }
00309 
00310     // Start CMAC with the key. Initializes signature_ctx
00311     res = pal_CMACStart(&file_handle->signature_ctx, &key[0], 128, PAL_CIPHER_ID_AES);
00312     if(res != PAL_SUCCESS)
00313     {
00314         tr_err("esfs_start_cmac() - pal_CMACStart() failed with pal_status = 0x%x", (unsigned int)res);
00315         return  ESFS_ERROR;
00316     }
00317 
00318     // Seek to the start of the file
00319     res = pal_fsFseek(&file_handle->file, 0, PAL_FS_OFFSET_SEEKSET);
00320     if(res != PAL_SUCCESS)
00321     {
00322         tr_err("esfs_start_cmac() - pal_fsFseek() failed with pal status 0x%x", (unsigned int)res);
00323 
00324         // Clean up the cmac context
00325         size_t num_bytes;
00326         // Ignore error. Sets file_handle->signature_ctx to 0 on success
00327         (void)pal_CMACFinish(&file_handle->signature_ctx, &key[0], &num_bytes);
00328         return  ESFS_ERROR;
00329     }
00330 
00331     return  ESFS_SUCCESS;
00332 }
00333 
00334 // Helper function to read and calculate the cmac on data that is read.
00335 // The function will not update the cmac if there is no CMAC context in the file handle.
00336 // Updates the file position.
00337 // Parameters :
00338 // file_handle    - [IN]   A pointer to a file handle for which we calculate the cmac.
00339 // pbuf           - [OUT]  A pointer to a buffer containing the data that is read.
00340 // num_bytes      - [IN]   number of bytes that we request to read.
00341 // num_bytes_read - [OUT]  A pointer to a location in which will be written the number of bytes actually read.
00342 // Return     : ESFS_SUCCESS on success. Error code otherwise
00343 static esfs_result_e esfs_cmac_read(esfs_file_t *file_handle, void *pbuf, size_t num_bytes, size_t *num_bytes_read)
00344 {
00345     palStatus_t res = pal_fsFread(&file_handle->file, pbuf, num_bytes, num_bytes_read);
00346     if(res != PAL_SUCCESS)
00347     {
00348         tr_err("esfs_cmac_read() - pal_fsFread failed with status = 0x%x", (unsigned int)res);
00349         return ESFS_ERROR;
00350     }
00351 
00352     // Update the CMAC only if there is a context. (It is allowed to read the file without calculating CMAC if
00353     // it does not need to checked.)
00354     if(file_handle->signature_ctx)
00355     {
00356         res = pal_CMACUpdate(file_handle->signature_ctx, pbuf, *num_bytes_read);
00357         if(res != PAL_SUCCESS)
00358         {
00359             tr_err("esfs_cmac_read() - pal_CMACUpdate failed with status = 0x%x", (unsigned int)res);
00360             return ESFS_ERROR;
00361         }
00362     }
00363 
00364     return ESFS_SUCCESS;
00365 }
00366 
00367 
00368 // Helper function to skip past a part of the file while calculating the cmac on the skipped data.
00369 // Updates the file position.
00370 // Parameters :
00371 // file_handle - [IN]   A pointer to a file handle.
00372 // to          - [IN]   The absolute position from the start of the file to which skip.
00373 //                      It must be greater than the current position and no longer that the file size.
00374 // Return     : ESFS_SUCCESS on success. Error code otherwise.
00375 static esfs_result_e esfs_cmac_skip_to(esfs_file_t *file_handle, int32_t to)
00376 {
00377     // Get current position
00378     int32_t current_pos;
00379     palStatus_t res = pal_fsFtell(&file_handle->file, &current_pos);
00380     if (res != PAL_SUCCESS)
00381     {
00382         tr_err("esfs_cmac_skip_to() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res);
00383         return  ESFS_ERROR;
00384     }
00385 
00386     // Iterate over the rest of file in chunks to calculate the cmac
00387     // buffer will contain only data read form the file
00388     for (int32_t i = to - current_pos; i > 0; i -= ESFS_READ_CHUNK_SIZE_IN_BYTES)
00389     {
00390         // Read a chunk
00391         // Here we read the file as is - plain text or encrypted
00392         uint8_t buffer[ESFS_READ_CHUNK_SIZE_IN_BYTES];
00393         size_t num_bytes;
00394         esfs_result_e res = esfs_cmac_read(file_handle, buffer, PAL_MIN(i, ESFS_READ_CHUNK_SIZE_IN_BYTES), &num_bytes);
00395         if (res != ESFS_SUCCESS || num_bytes == 0)
00396         {
00397             tr_err("esfs_cmac_skip_to() failed  num_bytes bytes = %zu", num_bytes);
00398             return  ESFS_ERROR;
00399         }
00400      }
00401     return  ESFS_SUCCESS;
00402 }
00403 
00404 // Helper function to terminate a cmac run and return the resulting cmac.
00405 // Parameters :
00406 // file_handle - [IN]   A pointer to a file handle for which we calculate the cmac.
00407 // pcmac       - [OUT]  A pointer to a buffer into which the cmac will be written. It must be at least ESFS_CMAC_SIZE_IN_BYTES.
00408 // Return     : ESFS_SUCCESS on success. Error code otherwise
00409 static esfs_result_e esfs_cmac_finish(esfs_file_t *file_handle, unsigned char *pcmac)
00410 {
00411     size_t num_bytes;
00412 
00413     // Sets file_handle->signature_ctx to 0 on success
00414     palStatus_t res = pal_CMACFinish(&file_handle->signature_ctx, pcmac, &num_bytes);
00415     if(res != PAL_SUCCESS)
00416     {
00417         tr_err("esfs_finish_cmac() - pal_CMACFinish() failed with pal_status = 0x%x", (unsigned int)res);
00418         return  ESFS_ERROR;
00419     }
00420     return  ESFS_SUCCESS;
00421 }
00422 
00423 // Helper function to compare the passed cmac against the one in the file and to the one in the file descriptor
00424 // and then return the file position in the passed value.
00425 // Updates the file position.
00426 // Parameters :
00427 // file_handle - [IN]   A pointer to a file handle for which we check the cmac.
00428 // pcmac       - [IN]   A pointer to a buffer containing the cmac that will be compared. It must be at least ESFS_CMAC_SIZE_IN_BYTES.
00429 // position    - [IN]   The absolute position from the start of the file to which we restore the file position.
00430 // Return     : ESFS_SUCCESS on success. Error code otherwise.
00431 static esfs_result_e esfs_cmac_check_and_restore(esfs_file_t *file_handle, unsigned char *pcmac, int32_t position)
00432 {
00433     // Read the signature from the file
00434     unsigned char file_cmac[ESFS_CMAC_SIZE_IN_BYTES];
00435     size_t num_bytes;
00436     palStatus_t res = pal_fsFread(&file_handle->file, &file_cmac[0], ESFS_CMAC_SIZE_IN_BYTES, &num_bytes);
00437     if (res != PAL_SUCCESS || num_bytes != ESFS_CMAC_SIZE_IN_BYTES)
00438     {
00439         tr_err("esfs_cmac_check_and_restore() - pal_fsFread() failed with pal result = 0x%x and num_bytes bytes = %zu", (unsigned int)res, num_bytes);
00440         return ESFS_ERROR;
00441     }
00442     // Compare the cmac that we read from the file with the one that is passed and check it against
00443     // the one recorded in esfs_open in order to verify that the file is the same as the one that was opened.
00444     if(memcmp(&file_cmac[0], pcmac, ESFS_CMAC_SIZE_IN_BYTES) != 0 ||
00445             memcmp(&file_cmac[0], &file_handle->cmac[0], ESFS_CMAC_SIZE_IN_BYTES) != 0)
00446     {
00447         tr_err("esfs_cmac_check_and_restore() - cmac that we read from the file does not match the one that we calculated");
00448         return ESFS_CMAC_DOES_NOT_MATCH;
00449     }
00450 
00451     // Set the file position to the byte indicated by position.
00452     res = pal_fsFseek(&file_handle->file, position, PAL_FS_OFFSET_SEEKSET);
00453     if(res != PAL_SUCCESS)
00454     {
00455         tr_err("esfs_cmac_check_and_restore() - pal_fsFseek() failed with pal status 0x%x", (unsigned int)res);
00456         return ESFS_ERROR;
00457     }
00458 
00459     return  ESFS_SUCCESS;
00460 }
00461 
00462 //Function   : esfs_memcpy_reverse
00463 //
00464 //Description: This function copies the first <len_bytes> bytes from input buffer <src_ptr> to output buffer <dest_ptr> in
00465 //             reversed order (e.g. '1' '2' '3' data array will be copied as '3' '2' '1').
00466 //             Note: The function assumes that the memory areas of the input buffers src_ptr and dest_ptr do not overlap.
00467 //
00468 //Parameters : dest_ptr  - [IN / OUT] A pointer to the destination buffer to which bytes will be copied.
00469 //             src_ptr   - [IN]       A pointer to the source buffer from which bytes will be copied.
00470 //             len_bytes - [IN]       Number of bytes to be copied.
00471 //
00472 //Return     : A pointer to the output buffer <dest_ptr>
00473 static void *esfs_memcpy_reverse(void *dest_ptr, const void *src_ptr, uint32_t len_bytes)
00474 {
00475     uint8_t       *tmp_dest_ptr = (uint8_t *)dest_ptr;
00476     const uint8_t *tmp_src_ptr  = (const uint8_t *)src_ptr;
00477 
00478 
00479     // Make the reverse copy
00480     while(len_bytes > 0)
00481     {
00482         *(tmp_dest_ptr++) = *(tmp_src_ptr + len_bytes - 1);
00483         len_bytes--;
00484     }
00485 
00486     return dest_ptr;
00487 }
00488 
00489 //Function   : esfs_calc_file_pos_for_aes
00490 //
00491 //Description: This function calculates the file position for the purpose of AES encrypt / decrypt:
00492 //             The returned position is relative to the beginning of the encrypted data.
00493 //             The file is encrypted starting from the meta data part (the meta data values).
00494 //
00495 //Parameters : file_handle - [IN]  A pointer to a file handle on which we calculate the position.
00496 //             position    - [OUT] A pointer to size_t to be filled in with the returned position.
00497 //
00498 //Return     : ESFS_SUCCESS on success. Error code otherwise
00499 static esfs_result_e esfs_calc_file_pos_for_aes(esfs_file_t *file_handle, size_t *position)
00500 {
00501     palStatus_t pal_status = PAL_SUCCESS;
00502 
00503     size_t non_encrypt_size = 0;
00504 
00505 
00506     *position = 0;
00507 
00508     // Get current position inside the file
00509     pal_status = pal_fsFtell( &(file_handle->file), (int32_t *)position );
00510 
00511     if(pal_status != PAL_SUCCESS)
00512     {
00513         tr_err("esfs_calc_file_pos_for_aes() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)pal_status);
00514         return ESFS_ERROR;
00515     }
00516 
00517     // Calculate non_encrypt_size to be subtracted from position
00518     non_encrypt_size = esfs_not_encrypted_file_header_size(file_handle);
00519 
00520     if(*position < non_encrypt_size)
00521     {
00522         tr_err("esfs_calc_file_pos_for_aes() - Error. Position is in non encrypted part.");
00523         return ESFS_ERROR;
00524     }
00525 
00526 
00527     *position -= non_encrypt_size;
00528 
00529 
00530     return ESFS_SUCCESS;
00531 }
00532 
00533 
00534 //Function   : esfs_set_counter_in_iv_by_file_pos
00535 //
00536 //Description: This function fills in the last 8 bytes of the IV [iv128_arr] with the counter calculated according to
00537 //             the input position.
00538 //
00539 //Parameters : position  - [IN]     The position in the file when count starts from the encrypted data part (the meta data values).
00540 //             iv128_arr - [IN/OUT] A 16 bytes buffer holding the IV.
00541 //                                  First 8 bytes contain the NONCE, and last 8 bytes will be filled in with the counter.
00542 //
00543 //Return     : ESFS_SUCCESS on success. Error code otherwise
00544 static void esfs_set_counter_in_iv_by_file_pos(size_t position, uint8_t *iv128_arr)
00545 {
00546     uint64_t counter = 0;
00547 
00548 
00549     // Calculate counter part of IV
00550     counter = (uint64_t)(position / ESFS_AES_BLOCK_SIZE_BYTES);
00551 
00552 
00553     // Copy the counter part to the IV
00554 #if BIG__ENDIAN == 1
00555     memcpy(iv128_arr + ESFS_AES_COUNTER_INDEX_IN_IV, &counter, ESFS_AES_COUNTER_SIZE_BYTES);
00556 #else
00557     esfs_memcpy_reverse(iv128_arr + ESFS_AES_COUNTER_INDEX_IN_IV, &counter, ESFS_AES_COUNTER_SIZE_BYTES);
00558 #endif
00559 }
00560 
00561 
00562 //Function   : esfs_aes_enc_dec_by_file_pos
00563 //
00564 //Description: This function encrypts / decrypts data using AES-CTR.
00565 //             This is the basic function used for AES encrypt / decrypt.
00566 //             Due to the nature of AES-CTR which works on blocks, special handling is required in case the data in the file is not
00567 //             on block boundaries. In this case we encrypt / decrypt this "partial block data" in a temporal buffer after copying
00568 //             the data to the corresponding index inside this buffer. The rest of the data is being encrypted / decrypted normally.
00569 //
00570 //Parameters : aes_ctx     - [IN]  The per-initiated AES context.
00571 //             buf_in      - [IN]  A buffer containing to data to be encrypted / decrypted.
00572 //             buf_out     - [OUT] A buffer to be filled in with the encrypted / decrypted data.
00573 //             len_bytes   - [IN]  Number of bytes to encrypt / decrypt.
00574 //             position    - [IN]  The position in the file when count starts from the encrypted data part (the meta data values).
00575 //             nonce64_ptr - [IN]  An 8 bytes buffer holding the NONCE part of the IV.
00576 //
00577 //Return     : ESFS_SUCCESS on success. Error code otherwise
00578 static esfs_result_e esfs_aes_enc_dec_by_file_pos( palAesHandle_t  aes_ctx,
00579                                                    const uint8_t  *buf_in,
00580                                                    uint8_t        *buf_out,
00581                                                    size_t          len_bytes,
00582                                                    size_t          position,
00583                                                    uint8_t        *nonce64_ptr
00584                                                  )
00585 {
00586     palStatus_t pal_status = PAL_SUCCESS;
00587 
00588     uint8_t prev_remainder     = 0;  // Size in bytes of partial block PREVIOUSLY encrypted / decrypted
00589     uint8_t partial_block_size = 0;  // Size in bytes of partial block for NEXT encrypt / decrypt
00590 
00591     uint8_t partial_block_size_temp = 0;
00592 
00593     uint8_t partial_block_in[ESFS_AES_BLOCK_SIZE_BYTES]  = {0}; // Will contain data for next partial encrypt / decrypt
00594     uint8_t partial_block_out[ESFS_AES_BLOCK_SIZE_BYTES] = {0};
00595 
00596     uint8_t iv_arr[ESFS_AES_IV_SIZE_BYTES] = {0};   // Will contain nonce [bytes 0 - 7] and counter [bytes 8 - 15]
00597 
00598 
00599 //    -------- partial_block_in:  Size = block_size [16 bytes]
00600 //    |
00601 //    |
00602 //   \|/
00603 //
00604 //    -----------------------------------------------------------------------------------------
00605 //    |                      |                                            |                   |
00606 //    |  0  ...           0  |         Data copied form buf_in            |  0  ...        0  |
00607 //    |                      |                                            |                   |
00608 //    -----------------------------------------------------------------------------------------
00609 //               ^                               ^                                ^
00610 //               |                               |                                |
00611 //               |                               |                                |
00612 //               |                               |                                |
00613 //        Size: prev_remainder                   |                          Size: might be 0
00614 //                                               |
00615 //                                               |
00616 //                                       Size: partial_block_size
00617 //                                       (might consume the buffer till its end)
00618 
00619 
00620     prev_remainder = (position % ESFS_AES_BLOCK_SIZE_BYTES);
00621 
00622     partial_block_size_temp = ESFS_AES_BLOCK_SIZE_BYTES - prev_remainder;
00623     partial_block_size      = PAL_MIN(partial_block_size_temp, len_bytes);
00624 
00625     // Prepare partial_block_in: Copy data for next encrypt / decrypt from buf_in to partial_block_in
00626     memcpy(partial_block_in + prev_remainder, buf_in, partial_block_size);
00627 
00628     // Prepare iv_arr: Copy nonce into bytes [0 - 7] of IV buffer
00629     memcpy(iv_arr, nonce64_ptr, ESFS_AES_NONCE_SIZE_BYTES);
00630 
00631     // Prepare iv_arr: Set counter in bytes [8 - 15] of IV buffer
00632     esfs_set_counter_in_iv_by_file_pos(position, iv_arr);
00633 
00634 
00635     // Encrypt / decrypt partial block [run on entire block, and copy later only desired part)
00636     pal_status = pal_aesCTRWithZeroOffset(aes_ctx, partial_block_in, partial_block_out, ESFS_AES_BLOCK_SIZE_BYTES, iv_arr);
00637 
00638     if(pal_status != PAL_SUCCESS)
00639     {
00640         tr_err("esfs_aes_enc_dec_by_file_pos() - pal_aesCTRWithZeroOffset() failed with pal_status = 0x%x", (unsigned int)pal_status);
00641         return ESFS_ERROR;
00642     }
00643 
00644     // Copy partial_block_out to buf_out
00645     memcpy(buf_out, partial_block_out + prev_remainder, partial_block_size);
00646 
00647 
00648     // Encrypt / decrypt the rest of the data
00649     if(len_bytes > partial_block_size)
00650     {
00651         // Set updated counter in bytes [8 - 15] of IV buffer
00652         esfs_set_counter_in_iv_by_file_pos(position + partial_block_size, iv_arr);
00653 
00654         pal_status = pal_aesCTRWithZeroOffset(aes_ctx, buf_in + partial_block_size, buf_out + partial_block_size, len_bytes - partial_block_size, iv_arr);
00655 
00656         if(pal_status != PAL_SUCCESS)
00657         {
00658             tr_err("esfs_aes_enc_dec_by_file_pos() - pal_aesCTRWithZeroOffset() failed with pal_status = 0x%x", (unsigned int)pal_status);
00659             return ESFS_ERROR;
00660         }
00661     }
00662 
00663 
00664     return ESFS_SUCCESS;
00665 }
00666 
00667 
00668 //Function   : esfs_read_and_decrypt
00669 //
00670 //Description: This function reads encrypted data from a file, decrypts it, and writes it into a buffer.
00671 //
00672 //Parameters : file_handle    - [IN]  A pointer to a file handle from which we read data.
00673 //             buffer         - [IN]  The buffer to fill in with decrypted file data.
00674 //             bytes_to_read  - [IN]  Number of bytes to read from the file.
00675 //             read_bytes_ptr - [OUT] A pointer to size_t to be filled in with number of bytes actually read from the file.
00676 //
00677 //Return     : ESFS_SUCCESS on success. Error code otherwise
00678 static esfs_result_e esfs_read_and_decrypt(esfs_file_t *file_handle, void *buffer, size_t bytes_to_read, size_t *read_bytes_ptr)
00679 {
00680     esfs_result_e result     = ESFS_SUCCESS;
00681 
00682     size_t position = 0;
00683 
00684 
00685     // Get file pointer position for AES - Must be done before calling pal_fsFread() which modifies the file pointer position
00686     result = esfs_calc_file_pos_for_aes(file_handle, &position);
00687 
00688     if(result != ESFS_SUCCESS)
00689     {
00690         tr_err("esfs_read_and_decrypt() - esfs_calc_file_pos_for_aes() failed with status = 0x%x", result);
00691         return result;
00692     }
00693 
00694 
00695     // Read file's encrypted data into buffer
00696     result = esfs_cmac_read(file_handle, buffer, bytes_to_read, read_bytes_ptr );
00697 
00698     if((result != ESFS_SUCCESS) || (*read_bytes_ptr != bytes_to_read))
00699     {
00700         tr_err("esfs_read_and_decrypt() - esfs_cmac_read() failed with ESFS_status = 0x%x", (unsigned int)result);
00701         return ESFS_ERROR;
00702     }
00703 
00704 
00705     // AES decrypt in-place - decrypt the encrypted data inside buffer, into buffer [out parameter]
00706     result = esfs_aes_enc_dec_by_file_pos(file_handle->aes_ctx, buffer, buffer, bytes_to_read, position, file_handle->nonce);
00707 
00708     if(result != ESFS_SUCCESS)
00709     {
00710         tr_err("esfs_read_and_decrypt() - esfs_aes_enc_dec_by_file_pos() failed with status = 0x%x", (unsigned int)result);
00711         return result;
00712     }
00713 
00714 
00715     return ESFS_SUCCESS;
00716 }
00717 
00718 
00719 //Function   : esfs_encrypt_fwrite_and_calc_cmac
00720 //
00721 //Description: This function takes a plain text buffer, encrypts it, writes the encrypted data to a file, and updates the
00722 //             CMAC signature.
00723 //
00724 //             Since we cannot modify the data of the input buffer (const), this operation cannot be done in-place, so we need
00725 //             to use another buffer for the encryption result. In order to avoid dynamically allocation, we use a buffer
00726 //             of size ESFS_AES_BUF_SIZE_BYTES statically allocated on the stack. This forces us to encrypt and write in a loop -
00727 //             each iteration encrypts and writes maximum size of ESFS_AES_BUF_SIZE_BYTES bytes.
00728 //
00729 //Parameters : buffer         - [IN]     The buffer to encrypt and write to the file.
00730 //             bytes_to_write - [IN]     The number of bytes to write.
00731 //             file_handle    - [IN]     A pointer to a file handle to which we write the data.
00732 //
00733 //Return     : ESFS_SUCCESS on success. Error code otherwise
00734 static esfs_result_e esfs_encrypt_fwrite_and_calc_cmac(const void *buffer, size_t bytes_to_write, esfs_file_t *file_handle)
00735 {
00736     esfs_result_e result = ESFS_SUCCESS;
00737 
00738     size_t position    = 0;
00739     size_t remaining_bytes_to_write = bytes_to_write;
00740 
00741     const uint8_t *buffer_tmp_ptr = (uint8_t *)buffer;  // Will point to the next reading point in buffer as we read it
00742 
00743     uint8_t encrypted_data[ESFS_AES_BUF_SIZE_BYTES] = {0}; // Will hold encrypted data to be written to the file
00744 
00745 
00746     if(buffer == NULL)
00747     {
00748         tr_err("esfs_encrypt_fwrite_and_calc_cmac() - Bad arguments error. Input buffer is NULL.");
00749         return ESFS_ERROR;
00750     }
00751 
00752 
00753     // Get file pointer position for AES - Must be done before calling esfs_fwrite_and_calc_cmac() which modifies the file pointer position
00754     result = esfs_calc_file_pos_for_aes(file_handle, &position);
00755 
00756     if(result != ESFS_SUCCESS)
00757     {
00758         tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_calc_file_pos_for_aes failed with result=0x%x", result);
00759         return result;
00760     }
00761 
00762 
00763     // On every iteration in the loop, encrypt ESFS_AES_BUF_SIZE_BYTES bytes, and write them to the file
00764     while(remaining_bytes_to_write >= ESFS_AES_BUF_SIZE_BYTES)
00765     {
00766         // AES encrypt into encrypted_data
00767         result = esfs_aes_enc_dec_by_file_pos(file_handle->aes_ctx, buffer_tmp_ptr, encrypted_data, ESFS_AES_BUF_SIZE_BYTES, position, file_handle->nonce);
00768 
00769         if(result != ESFS_SUCCESS)
00770         {
00771             tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_aes_enc_dec_by_file_pos failed with result=0x%x", result);
00772             return result;
00773         }
00774 
00775         // Write the encrypted data to the file
00776         result = esfs_fwrite_and_calc_cmac(encrypted_data, ESFS_AES_BUF_SIZE_BYTES, file_handle);
00777 
00778         if((result != ESFS_SUCCESS))
00779         {
00780             tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_fwrite_and_calc_cmac() status = 0x%x", (unsigned int)result);
00781 
00782             // esfs_fwrite_and_calc_cmac() failed so we cannot be sure of the state of the file - mark the file as invalid
00783             file_handle->file_invalid = 1;
00784 
00785             return ESFS_ERROR;
00786         }
00787 
00788         position       += ESFS_AES_BUF_SIZE_BYTES;
00789         buffer_tmp_ptr += ESFS_AES_BUF_SIZE_BYTES;
00790 
00791         remaining_bytes_to_write -= ESFS_AES_BUF_SIZE_BYTES;
00792     }
00793 
00794 
00795     // AES encrypt the leftover of buffer
00796     if(remaining_bytes_to_write > 0)
00797     {
00798         // AES encrypt into encrypted_data
00799         result = esfs_aes_enc_dec_by_file_pos(file_handle->aes_ctx, buffer_tmp_ptr, encrypted_data, remaining_bytes_to_write, position, file_handle->nonce);
00800 
00801         if(result != ESFS_SUCCESS)
00802         {
00803             tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_aes_enc_dec_by_file_pos failed with result=0x%x", result);
00804             return result;
00805         }
00806 
00807 
00808         // Write the encrypted data to the file
00809         result = esfs_fwrite_and_calc_cmac(encrypted_data, remaining_bytes_to_write, file_handle);
00810 
00811         if((result != ESFS_SUCCESS))
00812         {
00813             tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_fwrite_and_calc_cmac() status = 0x%x", (unsigned int)result);
00814 
00815             // esfs_fwrite_and_calc_cmac() failed so we cannot be sure of the state of the file - mark the file as invalid
00816             file_handle->file_invalid = 1;
00817 
00818             return ESFS_ERROR;
00819         }
00820     }
00821 
00822     return ESFS_SUCCESS;
00823 }
00824 
00825 
00826 esfs_result_e esfs_reset(void)
00827 {
00828     esfs_result_e result = ESFS_SUCCESS;
00829     palStatus_t pal_result = PAL_SUCCESS;
00830     char dir_path[MAX_FULL_PATH_SIZE] = { 0 };
00831     tr_info("esfs_reset - enter");
00832     pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, dir_path);
00833     if (pal_result != PAL_SUCCESS)
00834     {
00835         tr_err("esfs_reset() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result);
00836         result = ESFS_ERROR;
00837         goto errorExit;
00838     }
00839 
00840     strncat(dir_path, "/" ESFS_WORKING_DIRECTORY, sizeof(ESFS_WORKING_DIRECTORY));
00841 
00842     // delete the files in working dir
00843     pal_result = pal_fsRmFiles(dir_path);
00844     // the use case is that esfs folder may not exist
00845     if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH))
00846     {
00847         tr_err("esfs_reset() - pal_fsRmFiles(ESFS_WORKING_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result);
00848         result = ESFS_ERROR;
00849         goto errorExit;
00850     }
00851 
00852     // delete working directory
00853     pal_result = pal_fsRmDir(dir_path);
00854     if (pal_result != PAL_SUCCESS)
00855     {
00856         // Any error apart from dir not exist returns error.
00857         if ((pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH))
00858         {
00859             tr_err("esfs_reset() - pal_fsRmDir(ESFS_WORKING_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result);
00860             result = ESFS_ERROR;
00861             goto errorExit;
00862         }
00863     }
00864 
00865     pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, dir_path);
00866     if (pal_result != PAL_SUCCESS)
00867     {
00868 
00869         tr_err("esfs_reset() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result);
00870         result = ESFS_ERROR;
00871         goto errorExit;
00872     }
00873 
00874     strncat(dir_path, "/" ESFS_BACKUP_DIRECTORY, sizeof(ESFS_BACKUP_DIRECTORY));
00875 
00876     // delete the files in backup dir
00877     pal_result = pal_fsRmFiles(dir_path);
00878     // the use case is that esfs folder may not exist
00879     if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH))
00880     {
00881         tr_err("esfs_reset() - pal_fsRmFiles(ESFS_BACKUP_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result);
00882         result = ESFS_ERROR;
00883         goto errorExit;
00884     }
00885 
00886     pal_result = pal_fsRmDir(dir_path);
00887     if (pal_result != PAL_SUCCESS)
00888     {
00889         // Any error apart from dir not exist returns error.
00890         if ((pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH))
00891         {
00892             tr_err("esfs_reset() - pal_fsRmDir(ESFS_BACKUP_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result);
00893             result = ESFS_ERROR;
00894             goto errorExit;
00895         }
00896     }
00897 
00898     if (esfs_finalize() != ESFS_SUCCESS)
00899     {
00900         tr_err("esfs_reset() - esfs_finalize() failed");
00901         result = ESFS_ERROR;
00902         goto errorExit;
00903     }
00904 
00905     if (esfs_init() != ESFS_SUCCESS)
00906     {
00907         tr_err("esfs_reset() - esfs_init() failed");
00908         result = ESFS_ERROR;
00909         goto errorExit;
00910     }
00911 
00912     return ESFS_SUCCESS;
00913 
00914 errorExit:
00915     return result;
00916 }
00917 
00918 
00919 esfs_result_e esfs_factory_reset(void) {
00920     palStatus_t   pal_result = PAL_SUCCESS;
00921     esfs_result_e result = ESFS_SUCCESS;
00922     esfs_file_t file_handle = { 0 };
00923     char working_dir_path[MAX_FULL_PATH_SIZE] = { 0 };
00924     char full_path_backup_dir[MAX_FULL_PATH_SIZE] = { 0 };
00925     bool is_single_partition = true;
00926     
00927     tr_info("esfs_factory_reset - enter");
00928     pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_backup_dir);
00929     if (pal_result != PAL_SUCCESS)
00930     {
00931         tr_err("esfs_factory_reset() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result);
00932         return ESFS_ERROR;
00933     }
00934 
00935     strncat(full_path_backup_dir, "/" ESFS_BACKUP_DIRECTORY "/" FACTORY_RESET_DIR, sizeof(ESFS_BACKUP_DIRECTORY) + sizeof(FACTORY_RESET_DIR));
00936     // Create the factory reset subfolder - FR
00937     pal_result = pal_fsMkDir(full_path_backup_dir);
00938     if (pal_result != PAL_SUCCESS)
00939     {
00940         // Any error apart from file exist returns error.
00941         if (pal_result != PAL_ERR_FS_NAME_ALREADY_EXIST)
00942         {
00943             tr_err("esfs_factory_reset() - pal_fsMkDir(ESFS_BACKUP_DIRECTORY/FACTORY_RESET_DIR) failed with pal_status = 0x%x", (unsigned int)pal_result);
00944             result = ESFS_ERROR;
00945             goto errorExit;
00946         }
00947     }
00948 
00949     strncat(full_path_backup_dir, "/" FACTORY_RESET_FILE, sizeof(FACTORY_RESET_FILE));
00950     // Create the fr_on flag file
00951     pal_result = pal_fsFopen(full_path_backup_dir, PAL_FS_FLAG_READWRITEEXCLUSIVE, &(file_handle.file));
00952 
00953     // (res == PAL_SUCCESS) : factory reset is called on the first time
00954     // (res == PAL_ERR_FS_NAME_ALREADY_EXIST) : factory reset is called again after it was failed 
00955     // on the first time and therefore the file exists
00956     if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NAME_ALREADY_EXIST))
00957     {
00958         tr_err("esfs_factory_reset() - unexpected filesystem behavior pal_fsFopen() failed with pal_status = 0x%x", (unsigned int)pal_result);
00959         result = ESFS_ERROR;
00960         goto errorExit;
00961     }
00962 
00963     // close the file only if we opened it
00964     if (pal_result == PAL_SUCCESS)
00965     {
00966         pal_result = pal_fsFclose(&(file_handle.file));
00967         if (pal_result != PAL_SUCCESS)
00968         {
00969             tr_err("esfs_factory_reset() - unexpected filesystem behavior pal_fsFclose() failed with pal_status = 0x%x", (unsigned int)pal_result);
00970             result = ESFS_ERROR;
00971             goto errorExit;
00972         }
00973     }
00974 
00975     pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, working_dir_path);
00976     if (pal_result != PAL_SUCCESS)
00977     {
00978         tr_err("esfs_factory_reset() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result);
00979         result = ESFS_ERROR;
00980         goto errorExit;
00981     }
00982 
00983     // Check if there is a single partition by comparing the primary and secondary mount points.
00984     // This is the only reliable way to do it, since the logic that determines the number of partitions is
00985     // hidden behind the PAL API.
00986     pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_backup_dir);
00987     if (pal_result != PAL_SUCCESS)
00988     {
00989         tr_err("esfs_factory_reset() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result);
00990         result = ESFS_ERROR;
00991         goto errorExit;
00992     }
00993     is_single_partition = (strcmp(working_dir_path,full_path_backup_dir) == 0);
00994 
00995     strncat(working_dir_path, "/" ESFS_WORKING_DIRECTORY, sizeof(ESFS_WORKING_DIRECTORY));
00996 
00997     // We can only format the working folder if it is dedicated for exclusive use of esfs and
00998     // it is not the only partition that exists. The assumption here is that if it is the only partition,
00999     // then the backup folder is also on that partition. In that case, formatting would remove the backup partition,
01000     // which we do not want to do!
01001     if (pal_fsIsPrivatePartition(PAL_FS_PARTITION_PRIMARY) && !is_single_partition)
01002     {
01003         pal_result = pal_fsFormat(PAL_FS_PARTITION_PRIMARY);
01004         if (pal_result != PAL_SUCCESS)
01005         {
01006             tr_err("esfs_factory_reset() - pal_fsFormat() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result);
01007             result = ESFS_ERROR;
01008             goto errorExit;
01009         }
01010         pal_result = pal_fsMkDir(working_dir_path);
01011         if (pal_result != PAL_SUCCESS)
01012         {
01013             tr_err("esfs_factory_reset() - pal_fsMkDir(ESFS_WORKING_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result);
01014             result = ESFS_ERROR;
01015             goto errorExit;
01016         }
01017     }
01018     else
01019     {
01020         // delete the files in working dir
01021         pal_result = pal_fsRmFiles(working_dir_path);
01022         // the use case is that esfs folder may not exist
01023         if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH))
01024         {
01025             tr_err("esfs_factory_reset() - pal_fsRmFiles(ESFS_WORKING_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result);
01026             result = ESFS_ERROR;
01027             goto errorExit;
01028         }
01029     }
01030 
01031     pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_backup_dir);
01032     if (pal_result != PAL_SUCCESS)
01033     {
01034         tr_err("esfs_factory_reset() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result);
01035         return ESFS_ERROR;
01036     }
01037     strncat(full_path_backup_dir, "/" ESFS_BACKUP_DIRECTORY, sizeof(ESFS_BACKUP_DIRECTORY));
01038 
01039     pal_result = pal_fsCpFolder(full_path_backup_dir, working_dir_path);
01040 
01041     if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NO_FILE))
01042     {
01043         tr_err("esfs_factory_reset() - pal_fsCpFolder() from backup to working failed with pal_status = 0x%x", (unsigned int)pal_result);
01044         result = ESFS_ERROR;
01045         goto errorExit;
01046     }
01047 
01048     strncat(full_path_backup_dir, "/" FACTORY_RESET_DIR "/" FACTORY_RESET_FILE, sizeof(FACTORY_RESET_DIR) + sizeof(FACTORY_RESET_FILE));
01049     // delete the flag file because factory reset flow ended successfully 
01050     pal_result = pal_fsUnlink(full_path_backup_dir);
01051     if (pal_result != PAL_SUCCESS)
01052     {
01053         tr_err("esfs_factory_reset() - pal_fsUnlink(ESFS_BACKUP_DIRECTORY/FACTORY_RESET_DIR/FACTORY_RESET_FILE) failed with pal_status = 0x%x", (unsigned int)pal_result);
01054         result = ESFS_ERROR;
01055         goto errorExit;
01056      }
01057 
01058     return ESFS_SUCCESS;
01059 
01060 errorExit:
01061     return result;
01062 }
01063 
01064 // Internal function to read header information and check its' validity.
01065 // Checks the name given against the name written in the file.
01066 // Checks the version.
01067 // Initializes some fields of file_handle: blob_name_length, esf_mode
01068 // Assumes that the read position is at the start of the file.
01069 // CMAC is calculated.
01070 // Parameters :
01071 // name         [IN]  A pointer to an array of binary data that uniquely identifies the file.
01072 // name_length  [IN]  size in bytes of the name. The minimum is 1 and the maximum is ESFS_MAX_NAME_LENGTH.
01073 // file_handle  [IN]  A pointer to a file handle on which we calculate the position.
01074 // return esf_success - name matches;
01075 //                        ESFS_HASH_CONFLICT - name does not match
01076 //                        ESFS_WRONG_FILE_VERSION - version does not match
01077 //                        ESFS_ERROR - other problem
01078 // On ESFS_SUCCESS or ESFS_HASH_CONFLICT the read position is set after the name.
01079 // On failure the position is undefined.
01080 static esfs_result_e esfs_check_file_validity(const uint8_t* name, size_t name_length, esfs_file_t *file_handle)
01081 {
01082     esfs_result_e result = ESFS_ERROR;
01083 
01084     // Read the version
01085     uint16_t version;
01086     size_t num_bytes;
01087     result  = esfs_cmac_read(file_handle, &version , sizeof(version), &num_bytes);
01088     if (result != ESFS_SUCCESS || num_bytes != sizeof(version))
01089     {
01090         tr_err("esfs_check_file_validity() - esfs_cmac_read() failed with ESFS result = 0x%x and num_bytes bytes = %zu",
01091             (unsigned int)result, num_bytes);
01092         goto errorExit;
01093     }
01094     // Check that the files version is the same as the source code version.
01095     if(version != ESFS_FILE_FORMAT_VERSION)
01096     {
01097         tr_err("esfs_check_file_validity() - invalid version: failed with version = %u instead of %u", (unsigned int)version, (unsigned int)ESFS_FILE_FORMAT_VERSION);
01098         result = ESFS_INVALID_FILE_VERSION;
01099         goto errorExit;
01100     }
01101 
01102     // Read the mode
01103     result = esfs_cmac_read(file_handle, (void *)( &file_handle->esfs_mode ), sizeof(file_handle->esfs_mode), &num_bytes);
01104     if (result != ESFS_SUCCESS || num_bytes != sizeof(file_handle->esfs_mode))
01105     {
01106         tr_err("esfs_check_file_validity() mode -  failed num_bytes bytes = %zu", num_bytes);
01107         goto errorExit;
01108     }
01109     // The mode is not used further in the opening process, so no further checks need be performed as cmac check will detect any
01110     // tampering.
01111 
01112     // Read the name length
01113     result = esfs_cmac_read(file_handle, (void *)( &file_handle->blob_name_length ), sizeof(file_handle->blob_name_length), &num_bytes);
01114     if (result != ESFS_SUCCESS || num_bytes != sizeof(file_handle->blob_name_length))
01115     {
01116         tr_err("esfs_check_file_validity() name length- esfs_cmac_read() failed with  result = 0x%x and num_bytes bytes = %zu",
01117             (unsigned int)result, num_bytes);
01118         goto errorExit;
01119     }
01120     // Check that the name in the file is the same length as the one given. It cannot be greater than ESFS_MAX_NAME_LENGTH
01121     // because that is checked on entry to the function.
01122     if (name_length != file_handle->blob_name_length)
01123     {
01124         tr_err("esfs_check_file_validity() - name length conflict");
01125         // The hash of the name conflicts with the hash of another name.
01126         result = ESFS_HASH_CONFLICT;
01127         goto errorExit;
01128     }
01129     // Check the name chunk by chunk
01130     for (int i = name_length; i > 0; i -= ESFS_READ_CHUNK_SIZE_IN_BYTES)
01131     {
01132         // Read a chunk
01133         char buffer[ESFS_READ_CHUNK_SIZE_IN_BYTES];
01134         result = esfs_cmac_read(file_handle, (void *)buffer, PAL_MIN(i, ESFS_READ_CHUNK_SIZE_IN_BYTES), &num_bytes);
01135         if (result != ESFS_SUCCESS || num_bytes == 0)
01136         {
01137             tr_err("esfs_check_file_validity() - read name failed with ESFS result = 0x%x and num_bytes bytes = %zu",
01138                 (unsigned int)result, num_bytes);
01139             goto errorExit;
01140         }
01141         // Check that the chunk matches
01142         //tr_info("Comparing %s (%d bytes) name_length=%d", name, (int )num_bytes,(int )name_length);
01143         if (memcmp(buffer, name, num_bytes) != 0)
01144         {
01145             tr_err("esfs_check_file_validity() - esfs hash conflict : The hash of the name conflicts with the hash of another name");
01146             // The hash of the name conflicts with the hash of another name.
01147             result = ESFS_HASH_CONFLICT;
01148             goto errorExit;
01149         }
01150         // Advance past what we just checked.
01151         name += num_bytes;
01152     }
01153     return ESFS_SUCCESS;
01154 errorExit:
01155     return result;
01156 }
01157 
01158 // Internal function to check the name against the name written in the file.
01159 // Assume that the read position is set to before the name length.
01160 // Parameters :
01161 //             fd -      [IN]  A pointer to a file descriptor.
01162 //             file_size [OUT] A pointer to a value into which the file size is returned.
01163 // return esf_success - name matches;
01164 //                        ESFS_HASH_CONFLICT - name does not match ;
01165 //                        ESFS_ERROR - other problem
01166 // On ESFS_SUCCESS or ESFS_HASH_CONFLICT the read position is set after the name.
01167 // On failure the position is undefined.
01168 
01169 // Helper function
01170 // Restores current position unless it fails.
01171 // On failure the position is undefined.
01172 static palStatus_t esfs_get_physical_file_size(palFileDescriptor_t* fd, int32_t *file_size)
01173 {
01174     palStatus_t res;
01175 
01176     // Get current position
01177     int32_t current_pos;
01178     res = pal_fsFtell(fd, &current_pos);
01179     if (res != PAL_SUCCESS)
01180     {
01181         tr_err("esfs_get_physical_file_size() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res);
01182         goto errorExit;
01183     }
01184     // Seek to end of file
01185     res = pal_fsFseek(fd, 0, PAL_FS_OFFSET_SEEKEND);
01186     if (res != PAL_SUCCESS)
01187     {
01188         tr_err("esfs_get_physical_file_size() - pal_fsFseek() failed with pal_status = 0x%x", (unsigned int)res);
01189         goto errorExit;
01190     }
01191     // Get new position
01192     res = pal_fsFtell(fd, file_size);
01193     if (res != PAL_SUCCESS)
01194     {
01195         tr_err("esfs_get_physical_file_size() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res);
01196         goto errorExit;
01197     }
01198     // Restore old position
01199     res = pal_fsFseek(fd, current_pos, PAL_FS_OFFSET_SEEKSET);
01200     if (res != PAL_SUCCESS)
01201     {
01202         tr_err("esfs_get_physical_file_size() - pal_fsFseek() failed with pal_status = 0x%x", (unsigned int)res);
01203         goto errorExit;
01204     }
01205 
01206 errorExit:
01207     return res;
01208 }
01209 
01210 // Copy one file to another.
01211 // Parameters :
01212 //             src_file  - [IN] A pointer to a string containing the source file name.
01213 //             src_file  - [IN] A pointer to a string containing the destination file name.
01214 // Return     : ESFS_SUCCESS on success. Error code otherwise
01215 static esfs_result_e esfs_copy_file(const char *src_file, const char *dst_file)
01216 {
01217     bool is_src_file_opened = false;
01218     bool is_dst_file_opened = false;
01219     esfs_file_t file_handle = { 0 };
01220     esfs_file_t file_handle_copy = { 0 };
01221     esfs_result_e result = ESFS_ERROR;
01222     palStatus_t res = PAL_SUCCESS;
01223     size_t bytes_to_read = ESFS_FILE_COPY_CHUNK_SIZE;
01224     size_t num_bytes_read = 0;
01225     size_t num_bytes_write = 0;
01226     uint8_t buffer[ESFS_FILE_COPY_CHUNK_SIZE] = {0};
01227     int32_t file_size = 0;
01228     int32_t copied_bytes = 0;
01229     // Open src file read only mode
01230     res = pal_fsFopen(src_file, PAL_FS_FLAG_READONLY, &(file_handle.file));
01231     if (res != PAL_SUCCESS)
01232     {
01233         // File cannot be opened so return an error
01234         tr_err("esfs_copy_file() - pal_fsFopen() src file failed with pal_status = 0x%x", (unsigned int)res);
01235         result = ESFS_NOT_EXISTS;
01236         goto errorExit;
01237     }
01238     is_src_file_opened = true;
01239     // Open for reading and writing exclusively, If the file already exists, trunced file
01240     res = pal_fsFopen(dst_file, PAL_FS_FLAG_READWRITETRUNC, &(file_handle_copy.file));
01241     if (res != PAL_SUCCESS)
01242     {
01243         // File cannot be opened so return an error
01244         tr_err("esfs_copy_file() - pal_fsFopen() dst file failed with pal_status = 0x%x", (unsigned int)res);
01245         result = ESFS_ERROR;
01246         goto errorExit;
01247     }
01248     is_dst_file_opened = true;
01249 
01250     res = esfs_get_physical_file_size(&(file_handle.file), &file_size);
01251     if (res != PAL_SUCCESS)
01252     {
01253         tr_err("esfs_copy_file() - esfs_get_physical_file_size() failed with pal_status = 0x%x", (unsigned int)res);
01254         result = ESFS_ERROR;
01255         goto errorExit;
01256     }
01257     while (copied_bytes < file_size)
01258     {
01259         if (copied_bytes + (int32_t)bytes_to_read > file_size)
01260         {
01261             bytes_to_read = file_size - copied_bytes;
01262         }
01263         res = pal_fsFread(&(file_handle.file), buffer, bytes_to_read, &num_bytes_read);
01264         if (res != PAL_SUCCESS)
01265         {
01266             tr_err("esfs_copy_file() - pal_fsFread() failed with pal_status = 0x%x", (unsigned int)res);
01267             result = ESFS_ERROR;
01268             goto errorExit;
01269         }
01270 
01271         res = pal_fsFwrite(&(file_handle_copy.file), buffer, bytes_to_read, &num_bytes_write);
01272         if ((res != PAL_SUCCESS) || (num_bytes_write != bytes_to_read))
01273         {
01274             tr_err("esfs_copy_file() - pal_fsFwrite() failed with pal result = 0x%x and num_bytes_write bytes = %zu",
01275                 (unsigned int)res, num_bytes_write);
01276             result = ESFS_ERROR;
01277             goto errorExit;
01278         }
01279 
01280         copied_bytes += bytes_to_read;
01281             
01282     }
01283 
01284 
01285     res = pal_fsFclose(&(file_handle.file));
01286     if (res != PAL_SUCCESS)
01287     {
01288         tr_err("esfs_copy_file() - pal_fsFclose() for src file failed with pal_status = 0x%x", (unsigned int)res);
01289         result = ESFS_ERROR;
01290         goto errorExit;
01291     }
01292     res = pal_fsFclose(&(file_handle_copy.file));
01293     if (res != PAL_SUCCESS)
01294     {
01295         tr_err("esfs_copy_file() - pal_fsFclose() for dst file failed with pal_status = 0x%x", (unsigned int)res);
01296         result = ESFS_ERROR;
01297         goto errorExit;
01298     }
01299     return ESFS_SUCCESS;
01300 
01301 errorExit:
01302     if (is_src_file_opened)
01303     {
01304         // we will not delete the src file
01305         pal_fsFclose(&(file_handle.file));
01306     }
01307 
01308     if (is_dst_file_opened)
01309     {
01310         pal_fsFclose(&(file_handle_copy.file));
01311         // Clean up if possible. Ignore return value.
01312         (void)pal_fsUnlink(dst_file);
01313     }
01314     return result;
01315 }
01316 
01317 
01318 
01319 
01320 // Internal function to create a new file and open it for writing.
01321 // Does not return error if file exists.
01322 // Keep all the conditions that allow the file creation in a single function, esfs_create, while the
01323 // esfs_create_internal will concentrate on file creation mechanics.
01324 // Parameters:
01325 // name          - [IN]    A pointer to an array of binary data that uniquely identifies the file.
01326 // name_length   - [IN]    size in bytes of the name. The minimum is 1 and the maximum is ESFS_MAX_NAME_LENGTH.
01327 // meta_data     - [IN]    A pointer to an array of TLVs structures with meta_data_qty members
01328 // meta_data_qty - [IN]    number of tlvs in the array pointed by meta_data parameter. Minimum is 0 maximum is ESFS_MAX_TYPE_LENGTH_VALUES
01329 // esfs_mode     - [IN]    a bit map combination of values from enum EsfsMode.
01330 // file_handle   - [IN/OUT]  Pointer to the handle data structure into which to write the new handle.
01331 // returns ESFS_SUCCESS The file handle can be used in other esfs functions. It must be closed to release it.
01332 //          ESFS_ERROR - other problem
01333 static esfs_result_e esfs_create_internal( const uint8_t *name,
01334                                            size_t name_length,
01335                                            const esfs_tlv_item_t *meta_data,
01336                                            size_t meta_data_qty,
01337                                            uint16_t esfs_mode,
01338                                            esfs_file_t *file_handle,
01339                                            const char* full_path_to_create
01340                                         )
01341 {
01342     esfs_result_e result = ESFS_ERROR;
01343 
01344     int32_t position = 0;
01345     size_t i;
01346     uint16_t file_created = 0;
01347     uint16_t cmac_created = 0;
01348     uint16_t u16 = ESFS_FILE_FORMAT_VERSION;
01349 
01350 
01351     // Create the file.
01352     // Note that we always overwrite any previous file.
01353     palStatus_t res = pal_fsFopen(full_path_to_create, PAL_FS_FLAG_READWRITETRUNC, &file_handle->file);
01354     if(res != PAL_SUCCESS)
01355     {
01356         // more informative message will be written after hash conflict will be implemented
01357         tr_err("esfs_create_internal() - pal_fsFopen() failed with status 0x%x", (unsigned int)res);
01358         goto errorExit;
01359     }
01360     file_created = 1;
01361 
01362     if(esfs_cmac_start(file_handle) != ESFS_SUCCESS)
01363     {
01364         goto errorExit;
01365     }
01366     cmac_created = 1;
01367 
01368     // Write the version
01369     if(esfs_fwrite_and_calc_cmac(&u16, sizeof(u16), file_handle) != ESFS_SUCCESS)
01370     {
01371         tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for esfs version failed");
01372         result = ESFS_ERROR;
01373         goto errorExit;
01374     }
01375 
01376     // Write the mode
01377     if(esfs_fwrite_and_calc_cmac(&esfs_mode, sizeof(esfs_mode), file_handle) != ESFS_SUCCESS)
01378     {
01379         tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for esfs_mode failed");
01380         result = ESFS_ERROR;
01381         goto errorExit;
01382     }
01383 
01384     // Header
01385     // Write the name length
01386     u16 = (uint16_t)name_length;
01387     if(esfs_fwrite_and_calc_cmac(&u16, sizeof(u16), file_handle) != ESFS_SUCCESS)
01388     {
01389         tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for name_length failed");
01390         result = ESFS_ERROR;
01391         goto errorExit;
01392     }
01393 
01394     // Write the name
01395     if(esfs_fwrite_and_calc_cmac(name, name_length, file_handle) != ESFS_SUCCESS)
01396     {
01397         tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for name failed.");
01398         result = ESFS_ERROR;
01399         goto errorExit;
01400     }
01401 
01402     // Write the AES nonce, whether the file is encrypted or not. This ensures that the file format is the same
01403     // whether encrypted or not.
01404     if ((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0)
01405     {
01406         if(esfs_fwrite_and_calc_cmac((void *)(file_handle->nonce), ESFS_AES_NONCE_SIZE_BYTES, file_handle) != ESFS_SUCCESS)
01407         {
01408             tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for AES nonce failed");
01409             result = ESFS_ERROR;
01410             goto errorExit;
01411         }
01412     }
01413 
01414     // Write the Metadata header
01415     // Write the number of items of meta data
01416     u16 = (uint16_t)meta_data_qty;
01417     if(esfs_fwrite_and_calc_cmac(&u16,sizeof(u16), file_handle) != ESFS_SUCCESS)
01418     {
01419         tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for number of items of meta data failed");
01420         result = ESFS_ERROR;
01421         goto errorExit;
01422     }
01423 
01424     // If there is meta data
01425     if(meta_data_qty != 0)
01426     {
01427         res = pal_fsFtell(&file_handle->file, &position);
01428         if(res != PAL_SUCCESS)
01429         {
01430             tr_err("esfs_create_internal() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res);
01431             result = ESFS_ERROR;
01432             goto errorExit;
01433         }
01434         position += (sizeof(file_handle->tlv_properties.tlv_items[0]) * meta_data_qty);
01435         for(i = 0; i < meta_data_qty; i++ )
01436         {
01437             file_handle->tlv_properties.tlv_items[i].type = meta_data[i].type;
01438             file_handle->tlv_properties.tlv_items[i].length_in_bytes = meta_data[i].length_in_bytes;
01439             file_handle->tlv_properties.tlv_items[i].position = (uint16_t)position;
01440             // Increment position for next iteration
01441             position += meta_data[i].length_in_bytes;
01442         }
01443 
01444         // Write the metadata items
01445         result = esfs_fwrite_and_calc_cmac(&file_handle->tlv_properties.tlv_items[0], sizeof(file_handle->tlv_properties.tlv_items[0])*meta_data_qty, file_handle);
01446         if(result != ESFS_SUCCESS)
01447         {
01448             tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for meta data items failed with esfs result = 0x%x", result);
01449             result = ESFS_ERROR;
01450             goto errorExit;
01451         }
01452 
01453         // Set the number_of_items field here since it is in use later in this function
01454         // when we calculate the file header size
01455         file_handle->tlv_properties.number_of_items = meta_data_qty;
01456 
01457         // Write the Metadata data values
01458         // If encrypted esfs is requested (by the esfs_mode argument), then this part should be encrypted
01459         for(i = 0; i < meta_data_qty; i++ )
01460         {
01461             if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0)
01462             {
01463                 result = esfs_encrypt_fwrite_and_calc_cmac(meta_data[i].value, meta_data[i].length_in_bytes, file_handle);
01464             }
01465             else
01466             {
01467                 result = esfs_fwrite_and_calc_cmac(meta_data[i].value, meta_data[i].length_in_bytes, file_handle);
01468             }
01469 
01470             if(result != ESFS_SUCCESS)
01471             {
01472                 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for meta data item values failed with esfs result = 0x%x", result);
01473                 result = ESFS_ERROR;
01474                 goto errorExit;
01475             }
01476         }
01477     }
01478 
01479     file_handle->file_flag = ESFS_WRITE;
01480 
01481     return ESFS_SUCCESS;
01482 
01483 errorExit:
01484 
01485     if(file_created)
01486     {
01487         pal_fsFclose(&file_handle->file);
01488         // Clean up if possible. Ignore return value.
01489         (void)pal_fsUnlink(full_path_to_create);
01490     }
01491     if(cmac_created)
01492     {
01493         uint8_t key[ESFS_CMAC_SIZE_IN_BYTES];
01494         // Clean up cmac. Ignore error.
01495         (void)esfs_cmac_finish(file_handle, &key[0]);
01496     }
01497 
01498     return result;
01499 }
01500 
01501 //      ---------------------------------------------------------------
01502 //                              API Functions
01503 //      ---------------------------------------------------------------
01504 
01505 
01506 esfs_result_e esfs_create(const uint8_t *name, size_t name_length, const esfs_tlv_item_t *meta_data, size_t meta_data_qty, uint16_t esfs_mode, esfs_file_t *file_handle)
01507 {
01508 
01509     palStatus_t   res    = PAL_SUCCESS;
01510     esfs_result_e result = ESFS_ERROR;
01511 
01512     bool is_aes_ctx_created = false;
01513 
01514 
01515     // Verify that the structure is always packed to six bytes, since we read and write it as a whole.
01516     PAL_ASSERT_STATIC(sizeof(esfs_tlvItem_t) == 6);
01517 
01518     // Verify that the array is always packed without padding, since we read and write it as a whole.
01519     PAL_ASSERT_STATIC(sizeof(esfs_tlvItem_t[ESFS_MAX_TYPE_LENGTH_VALUES]) == ESFS_MAX_TYPE_LENGTH_VALUES * sizeof(esfs_tlvItem_t));
01520 
01521     tr_info("esfs_create - enter");
01522 
01523     // Check parameters
01524     if (!file_handle || !name || name_length == 0 || name_length > ESFS_MAX_NAME_LENGTH || meta_data_qty > ESFS_MAX_TYPE_LENGTH_VALUES)
01525     {
01526         tr_err("esfs_create() failed with bad parameters");
01527         result = ESFS_INVALID_PARAMETER;
01528         goto errorExit;
01529     }
01530 
01531     // Check the metadata parameter
01532     for(size_t meta_data_index = 0; meta_data_index < meta_data_qty; meta_data_index++ )
01533     {
01534         if ((!meta_data[meta_data_index].value) || (meta_data[meta_data_index].length_in_bytes == 0))
01535         {
01536             tr_err("esfs_create() failed with bad parameters for metadata");
01537             result = ESFS_INVALID_PARAMETER;
01538             goto errorExit;
01539         }
01540     }
01541 
01542     // If esfs is in encryption mode, make the required initializations
01543     if((esfs_mode & ESFS_ENCRYPTED) != 0)
01544     {
01545         // ** Create AES context for AES encryption
01546         res = pal_initAes( &(file_handle->aes_ctx) );
01547 
01548         if(res != PAL_SUCCESS)
01549         {
01550             tr_err("esfs_create() - pal_initAes() failed with pal status 0x%x", (unsigned int)res);
01551             result = ESFS_ERROR ;
01552             goto errorExit;
01553         }
01554 
01555         is_aes_ctx_created = true;
01556 
01557         // ** Get AES key from PAL
01558         // Note: On each call, PAL should return the same 128 bits key
01559         uint8_t aes_key[ESFS_AES_KEY_SIZE_BYTES]; // For AES encryption
01560         res = pal_osGetDeviceKey(palOsStorageEncryptionKey128Bit, aes_key, ESFS_AES_KEY_SIZE_BYTES);
01561 
01562         if(res != PAL_SUCCESS)
01563         {
01564             tr_err("esfs_create() - pal_osGetDeviceKey() failed with pal status 0x%x", (unsigned int)res);
01565             result = ESFS_ERROR ;
01566             goto errorExit;
01567         }
01568 
01569         // ** Assign generated AES key to AES context
01570         res = pal_setAesKey( file_handle->aes_ctx,
01571                              aes_key,
01572                              ESFS_AES_KEY_SIZE_BITS,
01573                              PAL_KEY_TARGET_ENCRYPTION
01574                            );
01575 
01576         if(res != PAL_SUCCESS)
01577         {
01578             tr_err("esfs_create() - pal_setAesKey() failed with pal status 0x%x", (unsigned int)res);
01579             result = ESFS_ERROR ;
01580             goto errorExit;
01581         }
01582 
01583         // ** Generate the AES nonce for AES usage
01584         res = pal_osRandomBuffer(file_handle->nonce, ESFS_AES_NONCE_SIZE_BYTES);
01585 
01586         if(res != PAL_SUCCESS)
01587         {
01588             tr_err("esfs_create() - pal_osRandomBuffer() failed with pal status 0x%x", (unsigned int)res);
01589             result = ESFS_ERROR ;
01590             goto errorExit;
01591         }
01592     }
01593 
01594     // We set the blob_name_length field here because it is in use later in this function when we calculate the file header size.
01595     // Since this field is also used to check the file handle validity [ esfs_validate() ] we set it to zero on an error exit.
01596     file_handle->blob_name_length = name_length;
01597 
01598     file_handle->esfs_mode = esfs_mode;
01599 
01600     file_handle->file_invalid = 0;
01601 
01602     file_handle->tlv_properties.number_of_items = 0;
01603 
01604     // Indicate that there is not a signature context yet.
01605     file_handle->signature_ctx = 0;
01606 
01607     file_handle->data_size = 0;
01608 
01609     if (esfs_get_name_from_blob(name, name_length, file_handle->short_file_name, ESFS_FILE_NAME_LENGTH) != ESFS_SUCCESS)
01610     {
01611         tr_err("esfs_create() - esfs_get_name_from_blob() failed");
01612         goto errorExit;
01613     }
01614 
01615     // Put working file name in file_full_path
01616     char file_full_path[MAX_FULL_PATH_SIZE];
01617     res = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, file_full_path);
01618     if (res != PAL_SUCCESS)
01619     {
01620         tr_err("esfs_create() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)res);
01621         result = ESFS_ERROR;
01622         goto errorExit;
01623     }
01624     strncat(file_full_path, "/" ESFS_WORKING_DIRECTORY "/", sizeof(ESFS_WORKING_DIRECTORY) + 1);
01625     strncat(file_full_path, file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1);
01626 
01627 
01628     // Check if the file exists in the working directory (not acceptable)
01629     // Note that this is just a check. We will only actually open the file later (in esfs_create_internal()).
01630     res = pal_fsFopen(file_full_path, PAL_FS_FLAG_READONLY, &file_handle->file);
01631     if (res == PAL_SUCCESS)
01632     {
01633         result = ESFS_EXISTS;
01634         file_handle->esfs_mode = 0;
01635         // result can be ESFS_HASH_CONFLICT or ESFS_WRONG_FILE_VERSION
01636         // Check if there is a different name in the file
01637         // Check that the name written inside the file is the same as that given. If not
01638         // you should choose a different name.
01639         esfs_result_e check_result = esfs_check_file_validity(name, name_length, file_handle);
01640         if (check_result == ESFS_HASH_CONFLICT || check_result == ESFS_INVALID_FILE_VERSION)
01641         {
01642             result = check_result;
01643         }
01644         pal_fsFclose(&file_handle->file);
01645         tr_err("esfs_create() - pal_fsFopen() for working dir file failed");
01646         goto errorExit;
01647     }
01648 
01649     // If factory reset file then we make some checks
01650     if (esfs_mode & (uint16_t)ESFS_FACTORY_VAL)
01651     {
01652         // Put backup folder name in file_full_path
01653         res = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, file_full_path);
01654         if (res != PAL_SUCCESS)
01655         {
01656             tr_err("esfs_create() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)res);
01657             result = ESFS_ERROR;
01658             goto errorExit;
01659         }
01660         strncat(file_full_path, "/" ESFS_BACKUP_DIRECTORY, sizeof(ESFS_BACKUP_DIRECTORY));
01661 
01662         // Create the esfs subfolder for backup
01663         res = pal_fsMkDir(file_full_path);
01664         if (res != PAL_SUCCESS)
01665         {
01666             // Any error apart from file exist returns error.
01667             if (res != PAL_ERR_FS_NAME_ALREADY_EXIST)
01668             {
01669                 tr_err("esfs_create() - pal_fsMkDir() for backup dir failed with pal status 0x%x", (unsigned int)res);
01670                 goto errorExit;
01671             }
01672         }
01673 
01674         // Put backup file name in file_full_path
01675         strcat(file_full_path, "/");
01676         strncat(file_full_path, file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1);
01677 
01678         // Check if the file exists in esfs backup directory (acceptable unless there is a hash conflict for the name)
01679         res = pal_fsFopen(file_full_path, PAL_FS_FLAG_READONLY, &file_handle->file);
01680         if (res == PAL_SUCCESS)
01681         {
01682             file_handle->esfs_mode = 0;
01683             // result can be ESFS_HASH_CONFLICT or ESFS_WRONG_FILE_VERSION
01684             // Check if there is a different name in the file
01685             // Check that the name written inside the file is the same as that given. If not
01686             // you should choose a different name.
01687             esfs_result_e check_result = esfs_check_file_validity(name, name_length, file_handle);
01688 
01689             // Close the file.
01690             pal_fsFclose(&file_handle->file);
01691 
01692             if (check_result == ESFS_HASH_CONFLICT || check_result == ESFS_INVALID_FILE_VERSION)
01693             {
01694                 tr_err("esfs_create() - esfs_check_file_validity() failed with status 0x%x", check_result);
01695                 result = check_result;
01696                 goto errorExit;
01697             }
01698             // It is OK for it to exist, so continue.
01699         }
01700     }
01701 
01702     // Now we actually create the new file.
01703     // file_full_path contains the correct location (working/backup)
01704     result = esfs_create_internal(
01705                                     name,
01706                                     name_length,
01707                                     meta_data,
01708                                     meta_data_qty,
01709                                     esfs_mode,
01710                                     file_handle,
01711                                     // Working or backup
01712                                     file_full_path
01713                                 );
01714     if(result != ESFS_SUCCESS)
01715     {
01716         goto errorExit;
01717     }
01718 
01719     return ESFS_SUCCESS;
01720 
01721 errorExit:
01722 
01723     // Invalidate blob_name_length filed since it is used to check the file handle validity  [ esfs_validate() ]
01724     if(file_handle != NULL)
01725     {
01726         file_handle->blob_name_length = 0;
01727     }
01728 
01729     if(is_aes_ctx_created)
01730     {
01731         pal_freeAes( &(file_handle->aes_ctx) );
01732     }
01733     return result;
01734 }
01735 
01736 esfs_result_e esfs_open(const uint8_t *name, size_t name_length, uint16_t *esfs_mode, esfs_file_t *file_handle)
01737 {
01738     esfs_result_e result = ESFS_ERROR;
01739     uint16_t file_opened = 0;
01740     uint16_t cmac_created = 0;
01741     bool is_aes_ctx_created = false;
01742     palStatus_t res = PAL_SUCCESS;
01743 
01744     tr_info("esfs_open - enter");
01745     // Check parameters
01746     if(!file_handle || !name || name_length == 0 || name_length > ESFS_MAX_NAME_LENGTH)
01747     {
01748         tr_err("esfs_open() failed with bad parameters");
01749         result = ESFS_INVALID_PARAMETER;
01750         goto errorExit;
01751     }
01752 
01753     char working_dir_path[MAX_FULL_PATH_SIZE];
01754     res = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, working_dir_path);
01755     if (res != PAL_SUCCESS)
01756     {
01757         tr_err("esfs_open() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)res);
01758         return ESFS_ERROR;
01759     }
01760 
01761     strncat(working_dir_path, "/" ESFS_WORKING_DIRECTORY "/", sizeof(ESFS_WORKING_DIRECTORY) + 1);
01762 
01763     // This is used to esfs_validate the file handle so we set it to zero here and only when open
01764     // succeeds to the real value.
01765     file_handle->blob_name_length = 0;
01766 
01767     file_handle->file_invalid = 0;
01768 
01769     memset(&file_handle->cmac[0], 0, sizeof(file_handle->cmac));
01770 
01771     if(esfs_get_name_from_blob(name, name_length, file_handle->short_file_name, ESFS_FILE_NAME_LENGTH) != ESFS_SUCCESS)
01772     {
01773         tr_err("esfs_open() - esfs_get_name_from_blob() failed");
01774         result = ESFS_ERROR;
01775         goto errorExit;
01776     }
01777 
01778     strncat(working_dir_path, file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1);
01779 
01780    // Open the file read only
01781     res = pal_fsFopen(working_dir_path, PAL_FS_FLAG_READONLY, &file_handle->file);
01782     if(res != PAL_SUCCESS)
01783     {
01784         // tr_err("esfs_open() - pal_fsFopen() for working dir file failed with pal_status = 0x%x", (unsigned int)res);
01785         // File cannot be opened so return an error
01786         result = ESFS_NOT_EXISTS;
01787         goto errorExit;
01788     }
01789 
01790      file_opened = 1;
01791 
01792      if(esfs_cmac_start(file_handle) != ESFS_SUCCESS)
01793      {
01794          goto errorExit;
01795      }
01796      cmac_created = 1;
01797 
01798     // Check that the name written inside the file is the same as that given
01799     // Note: After this call, the read position will be set to the point after the "Name Blob"
01800     result = esfs_check_file_validity(name, name_length, file_handle);
01801     if(result != ESFS_SUCCESS)
01802     {
01803         // the requested file not exists, but exists file with the same short name
01804         if (result == ESFS_HASH_CONFLICT)
01805         {
01806              result = ESFS_NOT_EXISTS;          
01807         }                       
01808         tr_err("esfs_open() - esfs_check_file_validity() failed with status = 0x%x", result);
01809         // File cannot be opened so return an error
01810         goto errorExit;
01811     }
01812 
01813     if (esfs_mode)
01814     {
01815         *esfs_mode = file_handle->esfs_mode;    // file_handle->esfs_mode was set by esfs_check_file_validity()
01816     }
01817 
01818     // If esfs is in encryption mode, make the required initializations
01819     if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0)
01820     {
01821         // ** Create AES context for AES decryption
01822         res = pal_initAes( &(file_handle->aes_ctx) );
01823 
01824         if(res != PAL_SUCCESS)
01825         {
01826             tr_err("esfs_open() - pal_initAes() failed with status 0x%x", (unsigned int)res);
01827             result = ESFS_ERROR ;
01828             goto errorExit;
01829         }
01830 
01831         is_aes_ctx_created = true;
01832 
01833         // ** Get AES key from PAL
01834         // Note: On each call, PAL should return the same 128 bits key
01835         uint8_t aes_key[ESFS_AES_KEY_SIZE_BYTES];
01836         res = pal_osGetDeviceKey(palOsStorageEncryptionKey128Bit, aes_key, ESFS_AES_KEY_SIZE_BYTES);
01837 
01838         if(res != PAL_SUCCESS)
01839         {
01840             tr_err("esfs_open() - pal_osGetDeviceKey() failed with status 0x%x", (unsigned int)res);
01841             result = ESFS_ERROR ;
01842             goto errorExit;
01843         }
01844 
01845         // ** Assign generated AES key to AES context
01846         res = pal_setAesKey( file_handle->aes_ctx,
01847                              aes_key,
01848                              ESFS_AES_KEY_SIZE_BITS,
01849                              PAL_KEY_TARGET_ENCRYPTION
01850                            );
01851 
01852         if(res != PAL_SUCCESS)
01853         {
01854             tr_err("esfs_open() - pal_setAesKey() failed with status 0x%x", (unsigned int)res);
01855             result = ESFS_ERROR;
01856             goto errorExit;
01857         }
01858 
01859     }
01860 
01861     size_t num_bytes;
01862 
01863     // ** Read the AES nonce into file_handle->nonce
01864     if ((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0)
01865     {
01866         result = esfs_cmac_read(file_handle, &file_handle->nonce[0], ESFS_AES_NONCE_SIZE_BYTES, &num_bytes);
01867         if((result != ESFS_SUCCESS) || (num_bytes != ESFS_AES_NONCE_SIZE_BYTES))
01868         {
01869             tr_err("esfs_open() - esfs_cmac_read() (AES nonce) failed with ESFS result = 0x%x and num_bytes bytes = %zu",
01870                 (unsigned int)result, num_bytes);
01871             result = ESFS_ERROR;
01872             goto errorExit;
01873         }
01874     }
01875 
01876     file_handle->tlv_properties.number_of_items = 0;
01877 
01878     // Read the number of items of meta data
01879     uint16_t meta_data_qty;
01880     result = esfs_cmac_read(file_handle, (void *)( &meta_data_qty ), sizeof(meta_data_qty), &num_bytes);
01881     if(result != ESFS_SUCCESS || num_bytes != sizeof(meta_data_qty) || meta_data_qty > ESFS_MAX_TYPE_LENGTH_VALUES)
01882     {
01883         tr_err("esfs_open() - esfs_cmac_read() (number of items of meta data) failed with ESFS result = 0x%x and num_bytes bytes = %zu",
01884             (unsigned int)result, num_bytes);
01885         result = ESFS_ERROR;
01886         goto errorExit;
01887     }
01888 
01889     // Read the metadata properties if there are any
01890     if(meta_data_qty != 0)
01891     {
01892         result = esfs_cmac_read( file_handle,
01893                            (void *) ( &(file_handle->tlv_properties.tlv_items[0]) ),
01894                            (sizeof(file_handle->tlv_properties.tlv_items[0]) * meta_data_qty),
01895                            &num_bytes
01896                          );
01897 
01898         if(result != ESFS_SUCCESS || num_bytes != sizeof(file_handle->tlv_properties.tlv_items[0])*meta_data_qty)
01899         {
01900             tr_err("esfs_open() - esfs_cmac_read() (metadata properties) failed with ESFS result = 0x%x and num_bytes bytes = %zu",
01901                 (unsigned int)result, num_bytes);
01902             goto errorExit;
01903         }
01904 
01905         // Skip to the start of the data by calculating the last metadata position plus its length
01906         esfs_tlvItem_t *ptypeLengthValueItem = &file_handle->tlv_properties.tlv_items[meta_data_qty - 1];
01907 
01908         if(esfs_cmac_skip_to(file_handle, ptypeLengthValueItem->position + ptypeLengthValueItem->length_in_bytes) != ESFS_SUCCESS)
01909         {
01910             tr_err("esfs_open() - esfs_cmac_skip_to() failed.");
01911             result = ESFS_ERROR;
01912             goto errorExit;
01913         }
01914     }
01915 
01916     file_handle->tlv_properties.number_of_items = meta_data_qty;
01917 
01918     // We are at the start of the data section
01919     file_handle->current_read_pos = 0;
01920 
01921     // Get current position
01922     int32_t current_pos;
01923     res = pal_fsFtell(&file_handle->file, &current_pos);
01924     if (res != PAL_SUCCESS)
01925     {
01926         tr_err("esfs_open() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res);
01927         goto errorExit;
01928     }
01929 
01930     // get the whole file size and store it in the handle
01931     res = esfs_get_physical_file_size(&file_handle->file, &file_handle->file_size);
01932     if (res != PAL_SUCCESS)
01933     {
01934         tr_err("esfs_open() - esfs_open() failed with status 0x%x", (unsigned int)res);
01935         result = ESFS_ERROR;
01936         goto errorExit;
01937     }
01938 
01939     // Skip to the end of the file while calculating the cmac
01940     if(esfs_cmac_skip_to(file_handle, file_handle->file_size - ESFS_CMAC_SIZE_IN_BYTES) != ESFS_SUCCESS)
01941     {
01942         tr_err("esfs_open() - esfs_cmac_skip_to() failed.");
01943         result = ESFS_ERROR;
01944         goto errorExit;
01945     }
01946 
01947     // Terminate cmac calculation and get it.
01948     unsigned char cmac[ESFS_CMAC_SIZE_IN_BYTES];
01949     if(esfs_cmac_finish(file_handle, &cmac[0]) != ESFS_SUCCESS)
01950     {
01951         tr_err("esfs_open() - esfs_finish_cmac() failed");
01952         goto errorExit;
01953     }
01954     cmac_created = 0;
01955 
01956     // save the CMAC in the file descriptor. We will use this to check that the file has not
01957     // changed when esfs_read() or read_meta_data() is called.
01958     memcpy(&file_handle->cmac[0],&cmac[0],sizeof(file_handle->cmac));
01959 
01960     // Check the cmac and set the file position to the start of the data
01961     if(esfs_cmac_check_and_restore(file_handle, &cmac[0], current_pos) != ESFS_SUCCESS)
01962     {
01963         tr_err("esfs_open() - cmac that we read from the file does not match the one that we calculated");
01964         result = ESFS_CMAC_DOES_NOT_MATCH;
01965         goto errorExit;
01966     }
01967 
01968     // Calculate the size of the data only, by getting the file size and deducting the header and cmac
01969     file_handle->data_size =  file_handle->file_size - esfs_file_header_size(file_handle);
01970 
01971     // We deduct the cmac bytes at the end of the file since they are not part of the data
01972     file_handle->data_size -= ESFS_CMAC_SIZE_IN_BYTES;
01973 
01974     file_handle->file_flag = ESFS_READ;
01975     file_handle->blob_name_length = name_length;
01976 
01977     return ESFS_SUCCESS;
01978 
01979 errorExit:
01980     if(file_opened)
01981     {
01982         pal_fsFclose(&file_handle->file);
01983     }
01984     if(is_aes_ctx_created)
01985     {
01986         pal_freeAes( &(file_handle->aes_ctx) );
01987     }
01988     if(cmac_created)
01989     {
01990         // Clean up cmac. Ignore error.
01991         (void)esfs_cmac_finish(file_handle, &cmac[0]);
01992     }
01993 
01994     return result;
01995 }
01996 
01997 esfs_result_e esfs_write(esfs_file_t *file_handle, const void *buffer, size_t bytes_to_write)
01998 {
01999     esfs_result_e result = ESFS_ERROR;
02000 
02001     tr_info("esfs_write - enter");
02002     if((esfs_validate(file_handle) != ESFS_SUCCESS) || (!buffer) || (bytes_to_write == 0))
02003     {
02004         tr_err("esfs_write() failed with bad parameters");
02005         return ESFS_INVALID_PARAMETER;
02006     }
02007 
02008     if(file_handle->file_flag == ESFS_READ)
02009     {
02010         tr_err("esfs_write() write failed - file is opened for read only");
02011         result = ESFS_FILE_OPEN_FOR_READ;
02012         goto errorExit;
02013     }
02014     else
02015     {
02016         // Write data
02017         // If encrypted esfs is requested (file_handle->esfs_mode), then this part should be encrypted
02018 
02019         // The data should be encrypted if the encrypted esfs is requested by the esfs_mode argument
02020         if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0)
02021         {
02022             result = esfs_encrypt_fwrite_and_calc_cmac(buffer, bytes_to_write, file_handle);
02023         }
02024         else
02025         {
02026             result = esfs_fwrite_and_calc_cmac(buffer, bytes_to_write, file_handle);
02027         }
02028 
02029         if(result != ESFS_SUCCESS)
02030         {
02031             tr_err("esfs_write() - esfs_fwrite_and_calc_cmac()/esfs_encrypt_fwrite_and_calc_cmac() for data failed with esfs result = 0x%x", result);
02032             // Since the write failed, we cannot be sure of the state of the file, so we mark it as invalid.
02033             file_handle->file_invalid = 1;
02034             result = ESFS_ERROR;
02035             goto errorExit;
02036         }
02037     }
02038 
02039     file_handle->data_size += bytes_to_write;
02040 
02041     return ESFS_SUCCESS;
02042 
02043 errorExit:
02044     return result;
02045 }
02046 
02047 esfs_result_e esfs_read(esfs_file_t *file_handle, void *buffer, size_t bytes_to_read, size_t *read_bytes)
02048 {
02049     esfs_result_e result = ESFS_ERROR;
02050     uint16_t cmac_created = 0;
02051     size_t remaining_bytes = 0;
02052     palStatus_t res = PAL_SUCCESS;
02053 
02054     tr_info("esfs_read - enter");
02055     if(esfs_validate(file_handle) != ESFS_SUCCESS || read_bytes == NULL || !buffer)
02056     {
02057         result = ESFS_INVALID_PARAMETER;
02058         goto errorExit;
02059     }
02060 
02061     if(file_handle->file_flag != ESFS_READ)
02062     {
02063         result = ESFS_FILE_OPEN_FOR_WRITE;
02064         goto errorExit;
02065     }
02066     // Save file position
02067     int32_t position;
02068     res = pal_fsFtell(&file_handle->file, &position);
02069     if(res != PAL_SUCCESS)
02070     {
02071         tr_err("esfs_read() - pal_fsFtell() failed with pal status 0x%x", (unsigned int)res);
02072         goto errorExit;
02073     }
02074 
02075     // Limit how many bytes we can actually read depending on the size of the data section.
02076     remaining_bytes = file_handle->data_size - file_handle->current_read_pos;
02077     bytes_to_read = PAL_MIN(remaining_bytes, bytes_to_read);
02078 
02079     if(esfs_cmac_start(file_handle) != ESFS_SUCCESS)
02080     {
02081         goto errorExit;
02082     }
02083     cmac_created = 1;
02084 
02085     if(esfs_cmac_skip_to(file_handle, position) != ESFS_SUCCESS)
02086     {
02087         goto errorExit;
02088     }
02089 
02090     // Read data
02091     // If required according to esfs_mode, the read data will be decrypted
02092     size_t num_bytes;
02093     if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0)
02094     {
02095         if(esfs_read_and_decrypt(file_handle, buffer, bytes_to_read, &num_bytes) != ESFS_SUCCESS)
02096         {
02097             goto errorExit;
02098         }
02099     }
02100     else
02101     {
02102         if(esfs_cmac_read(file_handle, buffer, bytes_to_read, &num_bytes ) != ESFS_SUCCESS)
02103         {
02104             goto errorExit;
02105         }
02106     }
02107 
02108     *read_bytes = num_bytes;
02109 
02110     if(esfs_cmac_skip_to(file_handle ,file_handle->file_size - ESFS_CMAC_SIZE_IN_BYTES) != ESFS_SUCCESS)
02111     {
02112         goto errorExit;
02113     }
02114 
02115     unsigned char cmac[ESFS_CMAC_SIZE_IN_BYTES];
02116     if(esfs_cmac_finish(file_handle, &cmac[0]) != ESFS_SUCCESS)
02117     {
02118         tr_err("esfs_read() - esfs_finish_cmac() failed");
02119         goto errorExit;
02120     }
02121     cmac_created = 0;
02122 
02123     // Check the cmac and set to the byte after the end of the data being read.
02124     if(esfs_cmac_check_and_restore(file_handle, &cmac[0], position + num_bytes) != ESFS_SUCCESS)
02125     {
02126         tr_err("esfs_read() - cmac that we read from the file does not match the one that we calculated");
02127         result = ESFS_CMAC_DOES_NOT_MATCH;
02128         goto errorExit;
02129     }
02130 
02131     // Update the current position
02132     file_handle->current_read_pos += num_bytes;
02133 
02134     return ESFS_SUCCESS;
02135 
02136 errorExit:
02137     tr_err("esfs_read errorExit result=0x%x", result);
02138     if(cmac_created)
02139     {
02140         // Clean up cmac. Ignore error and resulting cmac.
02141         (void)esfs_cmac_finish(file_handle, &cmac[0]);
02142     }
02143 
02144     return result;
02145 }
02146 
02147 esfs_result_e esfs_seek(esfs_file_t *file_handle, int32_t offset, esfs_seek_origin_e whence, uint32_t *position)
02148 {
02149     esfs_result_e result = ESFS_ERROR;
02150     palStatus_t res = PAL_SUCCESS;
02151     tr_info("esfs_seek - enter");
02152     if(esfs_validate(file_handle) != ESFS_SUCCESS)
02153     {
02154         tr_err("esfs_seek() failed with bad parameters");
02155         return ESFS_INVALID_PARAMETER;
02156     }
02157 
02158     if(file_handle->file_flag != ESFS_READ)
02159     {
02160         tr_err("esfs_seek() seek failed - file is opened for write only");
02161         result = ESFS_FILE_OPEN_FOR_WRITE;
02162         goto errorExit;
02163     }
02164     pal_fsOffset_t pal_whence;
02165     // ESFS whence enum values are in sync with those of pal
02166     if(whence == ESFS_SEEK_SET)
02167     {
02168         if(offset > (int32_t)file_handle->data_size || offset < 0)
02169         {
02170             tr_err("esfs_seek() failed with bad parameters in offset calculation : ESFS_SEEK_SET");
02171             result = ESFS_INVALID_PARAMETER;
02172             goto errorExit;
02173         }
02174         // Add the offset to the start of the data
02175         offset += esfs_file_header_size(file_handle);
02176         pal_whence = PAL_FS_OFFSET_SEEKSET;
02177     }
02178     else if(whence == ESFS_SEEK_END)
02179     {
02180         if(offset < -(int32_t)file_handle->data_size || offset > 0)
02181         {
02182             tr_err("esfs_seek() failed with bad parameters in offset calculation : ESFS_SEEK_END");
02183             result = ESFS_INVALID_PARAMETER;
02184             goto errorExit;
02185         }
02186         // Deduct the cmac size from the offset because it is located after the data section.
02187         offset -= ESFS_CMAC_SIZE_IN_BYTES;
02188         pal_whence = PAL_FS_OFFSET_SEEKEND;
02189     }
02190     else if(whence == ESFS_SEEK_CUR)
02191     {
02192         if(offset + file_handle->current_read_pos > (int32_t)file_handle->data_size || offset + (int32_t)file_handle->current_read_pos < 0)
02193         {
02194             tr_err("esfs_seek() failed with bad parameters in offset calculation : ESFS_SEEK_CUR");
02195             result = ESFS_INVALID_PARAMETER;
02196             goto errorExit;
02197         }
02198         pal_whence = PAL_FS_OFFSET_SEEKCUR;
02199     }
02200     else
02201     {
02202         tr_err("esfs_seek() failed with bad parameters - wrong whence");
02203         result = ESFS_INVALID_PARAMETER;
02204         goto errorExit;
02205     }
02206     res = pal_fsFseek(&file_handle->file, offset, pal_whence);
02207     if(res != PAL_SUCCESS)
02208     {
02209         tr_err("esfs_seek() - pal_fsFseek() failed with pal status 0x%x", (unsigned int)res);
02210         goto errorExit;
02211     }
02212     // Get current position if position is not NULL
02213     if(position)
02214     {
02215         res = pal_fsFtell(&file_handle->file, (int32_t *)position);
02216         if(res != PAL_SUCCESS)
02217         {
02218             tr_err("esfs_seek() - pal_fsFtell() failed with pal status 0x%x", (unsigned int)res);
02219             goto errorExit;
02220         }
02221 
02222         // Ignore the file header data
02223         *position -= esfs_file_header_size(file_handle);
02224 
02225         // Update the current position
02226         file_handle->current_read_pos = *position;
02227     }
02228 
02229     return ESFS_SUCCESS;
02230 
02231 errorExit:
02232     return result;
02233 }
02234 
02235 
02236 esfs_result_e esfs_file_size(esfs_file_t *file_handle, size_t *size_in_bytes)
02237 {
02238     esfs_result_e result = ESFS_ERROR;
02239 
02240     tr_info("esfs_file_size - enter");
02241     if((esfs_validate(file_handle) != ESFS_SUCCESS) || (!size_in_bytes))
02242     {
02243         tr_err("esfs_file_size() failed with bad parameters");
02244         result = ESFS_INVALID_PARAMETER;
02245         goto errorExit;
02246     }
02247 
02248     *size_in_bytes = file_handle->data_size;
02249 
02250     return ESFS_SUCCESS;
02251 
02252 errorExit:
02253     return result;
02254 }
02255 
02256 esfs_result_e esfs_close(esfs_file_t *file_handle)
02257 {
02258     uint16_t failed_to_write_CMAC = 0;
02259     uint16_t file_esfs_mode = 0;
02260     esfs_file_flag_e esfs_file_flag;
02261     char esfs_short_file_name[ESFS_QUALIFIED_FILE_NAME_LENGTH] = {0};
02262     esfs_result_e result = ESFS_ERROR;
02263     char full_path_working_dir[MAX_FULL_PATH_SIZE];
02264     palStatus_t res = PAL_SUCCESS;
02265 
02266     tr_info("esfs_close - enter");
02267     if(esfs_validate(file_handle) != ESFS_SUCCESS)
02268     {
02269         tr_err("esfs_close() failed with bad parameters");
02270         result = ESFS_INVALID_PARAMETER;
02271         goto errorExit;
02272     }
02273 
02274     res = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_working_dir);
02275     if (res != PAL_SUCCESS)
02276     {
02277         tr_err("esfs_close() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)res);
02278         result = ESFS_ERROR;
02279         goto errorExit;
02280     }
02281 
02282     strncat(full_path_working_dir, "/" ESFS_WORKING_DIRECTORY "/", sizeof(ESFS_WORKING_DIRECTORY) + 1);
02283 
02284 
02285     // Close AES context if needed
02286     if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0)
02287     {
02288         pal_freeAes( &(file_handle->aes_ctx) );
02289     }
02290  
02291     esfs_file_flag = file_handle->file_flag;
02292     file_esfs_mode = file_handle->esfs_mode;
02293     strncpy(esfs_short_file_name, file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1);
02294 
02295     if(file_handle->file_flag == ESFS_WRITE)
02296     {
02297         unsigned char cmac[ESFS_CMAC_SIZE_IN_BYTES];
02298         // Finish signature calculation
02299         if(esfs_cmac_finish(file_handle, &cmac[0]) != ESFS_SUCCESS)
02300         {
02301             tr_err("esfs_close() - esfs_cmac_finish() failed");
02302             goto errorExit;
02303         }
02304         // Write signature
02305         size_t bytes_written;
02306         res = pal_fsFwrite(&file_handle->file, &cmac[0], sizeof(cmac), &bytes_written);
02307         if(res != PAL_SUCCESS || sizeof(cmac) != bytes_written)
02308         {
02309             tr_err("esfs_close() - pal_fsFwrite() (signature) failed with pal result = 0x%x and bytes_written bytes = %zu",
02310                 (unsigned int)res, bytes_written);
02311             // mark the file invalid on a failed write
02312             file_handle->file_invalid = 1;
02313             // Continue so that we delete the file, but we should return failure later
02314             failed_to_write_CMAC = 1;
02315         }
02316     }
02317 
02318     res = pal_fsFclose(&file_handle->file);
02319     if(res == PAL_SUCCESS)
02320     {
02321         // Remove a file that is invalid. It may have become invalid due to a failed write.
02322         if(file_handle->file_invalid)
02323         {
02324             strncat(full_path_working_dir,file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1);
02325 
02326             res = pal_fsUnlink(full_path_working_dir);
02327             if(res != PAL_SUCCESS)
02328             {
02329                 tr_err("esfs_close() - pal_fsUnlink() failed with pal status 0x%x", (unsigned int)res);
02330                 goto errorExit;
02331             }
02332         }
02333     }
02334     else
02335     {
02336         tr_err("esfs_close() - pal_fsFclose() failed with pal status 0x%x", (unsigned int)res);
02337         goto errorExit;
02338     }
02339 
02340     if(failed_to_write_CMAC)
02341     {
02342         goto errorExit;
02343     }
02344 
02345 
02346     if ((file_esfs_mode & ESFS_FACTORY_VAL) && (esfs_file_flag == ESFS_WRITE) && !(file_handle->file_invalid))
02347     {
02348         char full_path_backup_dir[MAX_FULL_PATH_SIZE] = { 0 };
02349 
02350         res = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_backup_dir);
02351         if (res != PAL_SUCCESS)
02352         {
02353             tr_err("esfs_close() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)res);
02354             result = ESFS_ERROR;
02355             goto errorExit;
02356         }
02357 
02358         strncat(full_path_backup_dir, "/" ESFS_BACKUP_DIRECTORY "/", sizeof(ESFS_BACKUP_DIRECTORY) + 1);
02359 
02360         strncat(full_path_working_dir, esfs_short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH -1);
02361         strncat(full_path_backup_dir, esfs_short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1);
02362 
02363         if (esfs_copy_file(full_path_backup_dir, full_path_working_dir) != ESFS_SUCCESS)
02364         {
02365             tr_err("esfs_close() - esfs_copy_file() failed");
02366             goto errorExit;
02367         }
02368     }
02369 
02370     return ESFS_SUCCESS;
02371 errorExit:
02372     return result;
02373 }
02374 
02375 esfs_result_e esfs_delete(const uint8_t *name, size_t name_length)
02376 {
02377 
02378     palStatus_t pal_result = PAL_SUCCESS;
02379     char working_dir_path[MAX_FULL_PATH_SIZE] = { 0 };
02380     char short_file_name[ESFS_QUALIFIED_FILE_NAME_LENGTH];
02381     esfs_result_e result = ESFS_ERROR;
02382 
02383     tr_info("esfs_delete - enter");
02384     // Check parameters
02385     if(!name || name_length == 0)
02386     {
02387         tr_err("esfs_delete() failed with bad parameters");
02388         result = ESFS_INVALID_PARAMETER;
02389         goto errorExit;
02390     }
02391     if(esfs_get_name_from_blob(name, name_length, short_file_name, ESFS_FILE_NAME_LENGTH ) != ESFS_SUCCESS)
02392     {
02393         tr_err("esfs_delete() - esfs_get_name_from_blob() failed");
02394         goto errorExit;
02395     }
02396     tr_info("esfs_delete %s", short_file_name);
02397 
02398     pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, working_dir_path);
02399     if (pal_result != PAL_SUCCESS)
02400     {
02401         tr_err("esfs_delete() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result);
02402         result = ESFS_ERROR;
02403         goto errorExit;
02404     }
02405 
02406     strncat(working_dir_path, "/" ESFS_WORKING_DIRECTORY "/", sizeof(ESFS_WORKING_DIRECTORY) + 1);
02407 
02408     // We do not verify that name is the actual name in the file because currently we do not allow the situation of hash
02409     // clash to arise.
02410 
02411     strncat(working_dir_path,short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1);
02412 
02413     tr_info("esfs_delete %s", working_dir_path);
02414     pal_result = pal_fsUnlink(working_dir_path);
02415 
02416     if ((pal_result == PAL_ERR_FS_NO_FILE) || (pal_result == PAL_ERR_FS_NO_PATH))
02417     {
02418         tr_err("esfs_delete() - pal_fsUnlink() failed with pal status 0x%x", (unsigned int)pal_result);
02419         result = ESFS_NOT_EXISTS;
02420         goto errorExit;
02421     }
02422     else if (pal_result != PAL_SUCCESS)
02423     {
02424         tr_err("esfs_delete() - pal_fsUnlink() failed with pal status 0x%x", (unsigned int)pal_result);
02425         goto errorExit;
02426     }
02427 
02428     return ESFS_SUCCESS;
02429 errorExit:
02430     return result;
02431 }
02432 
02433 esfs_result_e esfs_get_meta_data_properties(esfs_file_t *file_handle, esfs_tlv_properties_t **meta_data_properties)
02434 {
02435     esfs_result_e result = ESFS_ERROR;
02436     tr_info("esfs_get_meta_data_properties - enter");
02437     if((esfs_validate(file_handle) != ESFS_SUCCESS) || (!meta_data_properties))
02438     {
02439         tr_err("esfs_get_meta_data_properties() failed with bad parameters");
02440         result = ESFS_INVALID_PARAMETER;
02441         goto errorExit;
02442     }
02443 
02444     if (file_handle->file_flag != ESFS_READ)
02445     {
02446         tr_err("esfs_get_meta_data_properties() failed - file is opened for write only");
02447         result = ESFS_FILE_OPEN_FOR_WRITE;
02448         goto errorExit;
02449     }
02450 
02451     *meta_data_properties = &file_handle->tlv_properties;
02452     return ESFS_SUCCESS;
02453 errorExit:
02454     return result;
02455 }
02456 
02457 
02458 esfs_result_e esfs_read_meta_data(esfs_file_t *file_handle, uint32_t index, esfs_tlv_item_t *meta_data)
02459 {
02460     esfs_result_e result = ESFS_ERROR;
02461     bool is_read_error = false;
02462     uint16_t cmac_created = 0;
02463     int32_t offset_to_restore = 0;
02464     palStatus_t res = PAL_SUCCESS;
02465 
02466     tr_info("esfs_read_meta_data - enter");
02467     if(esfs_validate(file_handle) != ESFS_SUCCESS || index >= ESFS_MAX_TYPE_LENGTH_VALUES || !meta_data || (file_handle->tlv_properties.tlv_items[index].length_in_bytes == 0))
02468     {
02469         tr_err("esfs_read_meta_data() failed with bad parameters");
02470         result = ESFS_INVALID_PARAMETER;
02471         goto errorExit;
02472     }
02473 
02474     if(file_handle->file_flag != ESFS_READ)
02475     {
02476         tr_err("esfs_read_meta_data() failed - file is opened for write only");
02477         result = ESFS_FILE_OPEN_FOR_WRITE;
02478         goto errorExit;
02479     }
02480     // Get current file position
02481     int32_t current_pos;
02482     res = pal_fsFtell(&file_handle->file, &current_pos);
02483     if(res != PAL_SUCCESS)
02484     {
02485         tr_err("esfs_read_meta_data() - pal_fsFtell() failed with pal status 0x%x", (unsigned int)res);
02486         goto errorExit;
02487     }
02488 
02489     // Start the cmac calculation and position to the start of the file
02490     if(esfs_cmac_start(file_handle) != ESFS_SUCCESS)
02491     {
02492         goto errorExit;
02493     }
02494     cmac_created = 1;
02495 
02496     // Skip to the meta-data position while calculating the cmac
02497     if(esfs_cmac_skip_to(file_handle, file_handle->tlv_properties.tlv_items[index].position) != ESFS_SUCCESS)
02498     {
02499         tr_err("esfs_read_meta_data() - pal_fsFseek() failed with pal status 0x%x", (unsigned int)res);
02500         goto errorExit;
02501     }
02502 
02503     // Read data
02504     // If required according to esfs_mode, the read data will be decrypted
02505     size_t num_bytes;
02506     if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0)
02507     {
02508         if(esfs_read_and_decrypt( file_handle,
02509                                   meta_data->value,
02510                                   file_handle->tlv_properties.tlv_items[index].length_in_bytes,
02511                                   &num_bytes
02512                                 ) != ESFS_SUCCESS)
02513         {
02514             is_read_error = true;
02515         }
02516     }
02517     else
02518     {
02519         if(esfs_cmac_read(file_handle, meta_data->value, file_handle->tlv_properties.tlv_items[index].length_in_bytes, &num_bytes ) != ESFS_SUCCESS)
02520         {
02521             is_read_error = true;
02522         }
02523     }
02524 
02525     if(is_read_error || (num_bytes != file_handle->tlv_properties.tlv_items[index].length_in_bytes))
02526     {
02527         tr_err("esfs_read_meta_data() - read data failed is_read_error = %s and num_bytes  = %zu",
02528             is_read_error ? "true" : "false", num_bytes);
02529         goto errorExit;
02530     }
02531 
02532     // Skip to the end of the data section of the file.
02533     if(esfs_cmac_skip_to(file_handle ,file_handle->file_size - ESFS_CMAC_SIZE_IN_BYTES) != ESFS_SUCCESS)
02534     {
02535         goto errorExit;
02536     }
02537 
02538     // Return the cmac
02539     unsigned char cmac[ESFS_CMAC_SIZE_IN_BYTES];
02540     if(esfs_cmac_finish(file_handle, &cmac[0]) != ESFS_SUCCESS)
02541     {
02542         tr_err("esfs_read() - esfs_finish_cmac() failed");
02543         goto errorExit;
02544     }
02545     cmac_created = 0;
02546 
02547     // Before restoring old position, make sure offset_to_restore is not a negative number
02548     offset_to_restore = current_pos;
02549     if(offset_to_restore < 0)
02550     {
02551         tr_err("esfs_read_meta_data() failed - current_pos is negative");
02552         goto errorExit;
02553     }
02554 
02555     // Check the cmac and restore the file position to the saved position
02556     if(esfs_cmac_check_and_restore(file_handle, &cmac[0], offset_to_restore) != ESFS_SUCCESS)
02557     {
02558         tr_err("esfs_read_meta_data() - cmac that we read from the file does not match the one that we calculated");
02559         result = ESFS_CMAC_DOES_NOT_MATCH;
02560         goto errorExit;
02561     }
02562 
02563     // Update meta_data fields
02564     meta_data->type = file_handle->tlv_properties.tlv_items[index].type;
02565     meta_data->length_in_bytes = file_handle->tlv_properties.tlv_items[index].length_in_bytes;
02566 
02567     return ESFS_SUCCESS;
02568 
02569 errorExit:
02570     if(cmac_created)
02571     {
02572         // Clean up cmac. Ignore error.
02573         (void)esfs_cmac_finish(file_handle, &cmac[0]);
02574     }
02575     return result;
02576 }