Simple interface for Mbed Cloud Client

Dependents:  

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