Transition FileX to Eclipse Fundation

This commit is contained in:
TiejunZhou
2024-01-02 07:35:14 +00:00
commit 14884808b5
406 changed files with 143803 additions and 0 deletions
+156
View File
@@ -0,0 +1,156 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_attributes_read PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function first attempts to find the specified directory. If */
/* found, the attribute read request is valid and the directory entry */
/* will be read in order to pickup the directory's attributes. */
/* Otherwise, if the directory is not found, the appropriate error */
/* code is returned to the caller. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* directory_name Directory name pointer */
/* attributes_ptr Return attributes pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_search Search for the file name in */
/* the directory structure */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_attributes_read(FX_MEDIA *media_ptr, CHAR *directory_name, UINT *attributes_ptr)
{
UINT status;
FX_DIR_ENTRY dir_entry;
#ifdef TX_ENABLE_EVENT_TRACE
TX_TRACE_BUFFER_ENTRY *trace_event;
ULONG trace_timestamp;
#endif
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_attributes_reads++;
#endif
/* Setup pointer to media name buffer. */
dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Clear the short name string. */
dir_entry.fx_dir_entry_short_name[0] = 0;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_ATTRIBUTES_READ, media_ptr, directory_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, &trace_event, &trace_timestamp)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Search the system for the supplied file name. */
status = _fx_directory_search(media_ptr, directory_name, &dir_entry, FX_NULL, FX_NULL);
/* Determine if the search was successful. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Check to make sure the found entry is a file. */
if ((dir_entry.fx_dir_entry_attributes & (UCHAR)(FX_DIRECTORY)) == 0)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the not a file error code. */
return(FX_NOT_DIRECTORY);
}
/* Place the current attributes into the destination. */
*attributes_ptr = (UINT)dir_entry.fx_dir_entry_attributes;
/* Update the trace event with the attributes read. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_DIRECTORY_ATTRIBUTES_READ, 0, 0, dir_entry.fx_dir_entry_attributes, 0)
/* Release media protection. */
FX_UNPROTECT
/* File attribute read is complete, return successful status. */
return(FX_SUCCESS);
}
+193
View File
@@ -0,0 +1,193 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
#include "fx_fault_tolerant.h"
#endif /* FX_ENABLE_FAULT_TOLERANT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_attributes_set PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function first attempts to find the specified directory. If */
/* found, the attribute set request is valid and the directory will */
/* be modified with the new attributes. Otherwise, if the directory */
/* is not found, the appropriate error code is returned to the caller. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* directory_name Directory name pointer */
/* attributes New dir attributes */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_write Write the new directory entry */
/* _fx_directory_search Search for the file name in */
/* the directory structure */
/* _fx_fault_tolerant_transaction_start Start fault tolerant */
/* transaction */
/* _fx_fault_tolerant_transaction_end End fault tolerant transaction*/
/* _fx_fault_tolerant_recover Recover FAT chain */
/* _fx_fault_tolerant_reset_log_file Reset the log file */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_attributes_set(FX_MEDIA *media_ptr, CHAR *directory_name, UINT attributes)
{
UINT status;
FX_DIR_ENTRY dir_entry;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_attributes_sets++;
#endif
/* Setup pointer to media name buffer. */
dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Clear the short name string. */
dir_entry.fx_dir_entry_short_name[0] = 0;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_ATTRIBUTES_SET, media_ptr, directory_name, attributes, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Check for write protect at the media level (set by driver). */
if (media_ptr -> fx_media_driver_write_protect)
{
/* Release media protection. */
FX_UNPROTECT
/* Return write protect error. */
return(FX_WRITE_PROTECT);
}
/* Search the system for the supplied file name. */
status = _fx_directory_search(media_ptr, directory_name, &dir_entry, FX_NULL, FX_NULL);
/* Determine if the search was successful. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Check to make sure the found entry is a directory. */
if ((dir_entry.fx_dir_entry_attributes & (UCHAR)(FX_DIRECTORY)) == 0)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the not a file error code. */
return(FX_NOT_DIRECTORY);
}
/* Place the new attributes in the directory entry. Make sure that the
directory bit of the attributes is never changed. */
dir_entry.fx_dir_entry_attributes = (UCHAR)(attributes | FX_DIRECTORY);
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Start transaction. */
_fx_fault_tolerant_transaction_start(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Now write out the directory entry. */
status = _fx_directory_entry_write(media_ptr, &dir_entry);
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Check for a bad status. If the return status is not FX_SUCCESS, finish
the fault tolerant transaction without flushing the logs. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
}
else
{
/* End transaction. */
status = _fx_fault_tolerant_transaction_end(media_ptr);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* File attribute set is complete, return status. */
return(status);
}
+711
View File
@@ -0,0 +1,711 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
#include "fx_fault_tolerant.h"
#endif /* FX_ENABLE_FAULT_TOLERANT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_create PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function first attempts to find the specified directory. */
/* If found, the create request is invalid and an error is returned */
/* to the caller. After the file name verification is made, a search */
/* for a free directory entry will be made. If nothing is available, */
/* an error will be returned to the caller. Otherwise, if all is */
/* okay, an empty directory will be created. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* directory_name Directory name */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_write Write the new directory entry */
/* _fx_directory_name_extract Pickup next part of name */
/* _fx_directory_search Search for the file name in */
/* the directory structure */
/* _fx_directory_free_search Search for a free directory */
/* entry */
/* _fx_utility_FAT_flush Flush written FAT entries */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* _fx_utility_FAT_entry_write Write a FAT entry */
/* _fx_utility_logical_sector_flush Flush the written log sector */
/* _fx_utility_logical_sector_read Read logical sector */
/* _fx_fault_tolerant_transaction_start Start fault tolerant */
/* transaction */
/* _fx_fault_tolerant_transaction_end End fault tolerant transaction*/
/* _fx_fault_tolerant_recover Recover FAT chain */
/* _fx_fault_tolerant_reset_log_file Reset the log file */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_create(FX_MEDIA *media_ptr, CHAR *directory_name)
{
UINT status;
ULONG FAT_index;
ULONG FAT_value;
UINT sectors;
ULONG total_clusters;
CHAR *work_ptr;
ULONG64 logical_sector;
ULONG i;
FX_DIR_ENTRY dir_entry;
FX_DIR_ENTRY sub_dir_entry;
FX_DIR_ENTRY search_directory;
FX_INT_SAVE_AREA
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_creates++;
#endif
/* Determine if the supplied name is less than the maximum supported name size. The
maximum name (FX_MAX_LONG_NAME_LEN) is defined in fx_api.h. */
i = 0;
work_ptr = (CHAR *)directory_name;
while (*work_ptr && (i < FX_MAX_LONG_NAME_LEN))
{
/* Determine if the character designates a new path. */
if ((*work_ptr == '\\') || (*work_ptr == '/'))
{
/* Yes, reset the name size. */
i = 0;
}
/* Check for leading spaces. */
else if ((*work_ptr != ' ') || (i != 0))
{
/* No leading spaces, increment the name size. */
i++;
}
/* Move to the next character. */
work_ptr++;
}
/* Determine if the supplied name is valid. */
if ((i == 0) || (i >= FX_MAX_LONG_NAME_LEN))
{
/* Return an invalid name value. */
return(FX_INVALID_NAME);
}
/* Setup pointer to media name buffer. */
dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Setup search directory pointer to another media name buffer. */
search_directory.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 2;
/* Clear the short name string. */
dir_entry.fx_dir_entry_short_name[0] = 0;
/* Clear the search short name string. */
search_directory.fx_dir_entry_short_name[0] = 0;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_CREATE, media_ptr, directory_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Check for write protect at the media level (set by driver). */
if (media_ptr -> fx_media_driver_write_protect)
{
/* Release media protection. */
FX_UNPROTECT
/* Return write protect error. */
return(FX_WRITE_PROTECT);
}
/* Make sure there is at least one cluster remaining for the new file. */
if (!media_ptr -> fx_media_available_clusters)
{
/* Release media protection. */
FX_UNPROTECT
/* Return a no-space error. */
return(FX_NO_MORE_SPACE);
}
/* Search the system for the supplied directory name. */
status = _fx_directory_search(media_ptr, directory_name, &dir_entry, &search_directory, &work_ptr);
/* Determine if the search was successful. */
if (status == FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Directory found - Return the error code. */
return(FX_ALREADY_CREATED);
}
/* Determine if there is anything left after the name. */
if (_fx_directory_name_extract(work_ptr, &dir_entry.fx_dir_entry_name[0]))
{
/* Release media protection. */
FX_UNPROTECT
/* Extra information after the file name, return an invalid name
error. */
return(FX_INVALID_PATH);
}
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Start transaction. */
_fx_fault_tolerant_transaction_start(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Find a free slot for the new directory. */
status = _fx_directory_free_search(media_ptr, &search_directory, &dir_entry);
/* Determine if the search was successful. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Now allocate a cluster for our new sub-directory entry. */
FAT_index = media_ptr -> fx_media_cluster_search_start;
total_clusters = media_ptr -> fx_media_total_clusters;
/* Loop to find the first available cluster. */
do
{
/* Make sure we don't go past the FAT table. */
if (!total_clusters)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Something is wrong with the media - the desired clusters were
not found in the FAT table. */
return(FX_NO_MORE_SPACE);
}
/* Read FAT entry. */
status = _fx_utility_FAT_entry_read(media_ptr, FAT_index, &FAT_value);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
/* Decrement the total cluster count. */
total_clusters--;
/* Determine if the FAT entry is free. */
if (FAT_value == FX_FREE_CLUSTER)
{
/* Move cluster search pointer forward. */
media_ptr -> fx_media_cluster_search_start = FAT_index + 1;
/* Determine if this needs to be wrapped. */
if (media_ptr -> fx_media_cluster_search_start >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
{
/* Wrap the search to the beginning FAT entry. */
media_ptr -> fx_media_cluster_search_start = FX_FAT_ENTRY_START;
}
/* Break this loop. */
break;
}
else
{
/* FAT entry is not free... Advance the FAT index. */
FAT_index++;
/* Determine if we need to wrap the FAT index around. */
if (FAT_index >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
{
/* Wrap the search to the beginning FAT entry. */
FAT_index = FX_FAT_ENTRY_START;
}
}
} while (FX_TRUE);
/* Decrease the number of available clusters for the media. */
media_ptr -> fx_media_available_clusters--;
/* Defer the writing of the FAT entry until the directory's first sector
has been properly written. If a power loss occurs prior to writing
the FAT entry, it will not result in a lost cluster. */
/* Populate the directory entry. */
/* Isolate the file name. */
_fx_directory_name_extract(work_ptr, &dir_entry.fx_dir_entry_name[0]);
/* Lockout interrupts for time/date access. */
FX_DISABLE_INTS
/* Set time and date stamps. */
dir_entry.fx_dir_entry_time = _fx_system_time;
dir_entry.fx_dir_entry_date = _fx_system_date;
/* Restore interrupts. */
FX_RESTORE_INTS
/* Set the attributes for the file. */
dir_entry.fx_dir_entry_attributes = FX_DIRECTORY;
/* Set file size to 0. */
dir_entry.fx_dir_entry_file_size = 0;
/* Set the cluster to EOF. */
dir_entry.fx_dir_entry_cluster = FAT_index;
/* Is there a leading dot? */
if (dir_entry.fx_dir_entry_name[0] == '.')
{
/* Yes, toggle the hidden attribute bit. */
dir_entry.fx_dir_entry_attributes |= FX_HIDDEN;
}
/* In previous versions, the new directory was written here. It
is now at the bottom of the file - after the FAT and the initial
sub-directory is written out. This makes the directory create
more fault tolerant. */
/* Calculate the first sector of the sub-directory file. */
logical_sector = ((ULONG) media_ptr -> fx_media_data_sector_start) +
(((ULONG64) FAT_index - FX_FAT_ENTRY_START) *
((ULONG) media_ptr -> fx_media_sectors_per_cluster));
/* Pickup the number of sectors for the initial sub-directory cluster. */
sectors = media_ptr -> fx_media_sectors_per_cluster;
/* Read the first logical sector associated with the allocated
cluster. */
status = _fx_utility_logical_sector_read(media_ptr, logical_sector,
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
/* Determine if an error occurred. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return error code. */
return(status);
}
/* Clear the entire first sector of the new sub-directory cluster. */
work_ptr = (CHAR *)media_ptr -> fx_media_memory_buffer;
i = 0;
while (i < media_ptr -> fx_media_bytes_per_sector)
{
/* Clear 4 bytes. */
*((ULONG *)work_ptr) = (ULONG)0;
/* Increment pointer. */
work_ptr = work_ptr + sizeof(ULONG);
/* Increment counter. */
i = i + (ULONG)sizeof(ULONG);
}
#ifdef FX_ENABLE_FAULT_TOLERANT
if (media_ptr -> fx_media_fault_tolerant_enabled == FX_TRUE)
{
/* Write back. */
status = _fx_utility_logical_sector_write(media_ptr, logical_sector,
media_ptr -> fx_media_memory_buffer, (ULONG)1, FX_DIRECTORY_SECTOR);
/* Determine if an error occurred. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
/* Release media protection. */
FX_UNPROTECT
/* Return error code. */
return(status);
}
/* Force flush the internal logical sector cache. */
status = _fx_utility_logical_sector_flush(media_ptr, logical_sector, sectors, FX_TRUE);
/* Determine if the write was successful. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Determine if there are more sectors to clear in the first cluster of the new
sub-directory. */
if (sectors > 1)
{
/* Yes, invalidate all cached sectors that are contained in the newly allocated first
cluster of the directory. */
#ifdef FX_ENABLE_FAULT_TOLERANT
if (media_ptr -> fx_media_fault_tolerant_enabled == FX_FALSE)
#endif /* FX_ENABLE_FAULT_TOLERANT */
{
/* Flush the internal logical sector cache. */
status = _fx_utility_logical_sector_flush(media_ptr, logical_sector + 1, ((ULONG64)(sectors - 1)), FX_TRUE);
/* Determine if the write was successful. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
}
/* Clear all additional sectors of new sub-directory. */
sectors--;
while (sectors)
{
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of driver write sector(s) requests. */
media_ptr -> fx_media_driver_write_requests++;
#endif
/* Build Write request to the driver. */
media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
media_ptr -> fx_media_driver_buffer = media_ptr -> fx_media_memory_buffer;
#ifdef FX_DRIVER_USE_64BIT_LBA
media_ptr -> fx_media_driver_logical_sector = logical_sector + ((ULONG)sectors);
#else
media_ptr -> fx_media_driver_logical_sector = (ULONG)logical_sector + ((ULONG)sectors);
#endif
media_ptr -> fx_media_driver_sectors = 1;
media_ptr -> fx_media_driver_sector_type = FX_DIRECTORY_SECTOR;
/* Set the system write flag since we are writing a directory sector. */
media_ptr -> fx_media_driver_system_write = FX_TRUE;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, ((ULONG)logical_sector) + ((ULONG)sectors), 1, media_ptr -> fx_media_memory_buffer, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Invoke the driver to write the sector. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Clear the system write flag. */
media_ptr -> fx_media_driver_system_write = FX_FALSE;
/* Determine if an error occurred. */
if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return error code. */
return(media_ptr -> fx_media_driver_status);
}
/* Decrease the number of sectors to clear. */
sectors--;
}
}
/* Now setup the first sector with the initial sub-directory information. */
/* Copy the base directory entry to the sub-directory entry. */
sub_dir_entry = dir_entry;
/* Setup pointer to media name buffer. */
sub_dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + (FX_MAX_LONG_NAME_LEN * 3);
/* Set the directory entry name to all blanks. */
work_ptr = &sub_dir_entry.fx_dir_entry_name[0];
for (i = 0; i < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); i++)
{
*work_ptr++ = ' ';
}
sub_dir_entry.fx_dir_entry_long_name_present = 0;
/* Now build the "." directory entry. */
sub_dir_entry.fx_dir_entry_name[0] = '.';
sub_dir_entry.fx_dir_entry_name[1] = 0;
sub_dir_entry.fx_dir_entry_log_sector = logical_sector;
sub_dir_entry.fx_dir_entry_byte_offset = 0;
/* Write the directory's first entry. */
status = _fx_directory_entry_write(media_ptr, &sub_dir_entry);
/* Check for error condition. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return error status. */
return(status);
}
/* Now build the ".." directory entry. */
/* Determine if the search directory is the root. */
if (search_directory.fx_dir_entry_name[0])
{
/* Previous directory is not the root directory. */
/* Copy into the working directory entry. */
sub_dir_entry = search_directory;
/* Copy the date and time from the actual sub-directory. */
sub_dir_entry.fx_dir_entry_time = dir_entry.fx_dir_entry_time;
sub_dir_entry.fx_dir_entry_date = dir_entry.fx_dir_entry_date;
/* Adjust pointer to media name buffer. */
sub_dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + (FX_MAX_LONG_NAME_LEN * 3);
/* Change the name to ".." */
work_ptr = &sub_dir_entry.fx_dir_entry_name[0];
for (i = 0; i < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); i++)
{
*work_ptr++ = ' ';
}
sub_dir_entry.fx_dir_entry_name[0] = '.';
sub_dir_entry.fx_dir_entry_name[1] = '.';
sub_dir_entry.fx_dir_entry_name[2] = 0;
sub_dir_entry.fx_dir_entry_long_name_present = 0;
/* Set file size to 0. */
sub_dir_entry.fx_dir_entry_file_size = 0;
/* Change the logical sector for this entry. */
sub_dir_entry.fx_dir_entry_log_sector = logical_sector;
}
else
{
/* Just modify the current directory since the parent
directory is the root. */
sub_dir_entry.fx_dir_entry_name[1] = '.';
sub_dir_entry.fx_dir_entry_name[2] = 0;
/* Clear the cluster to indicate the root directory. */
sub_dir_entry.fx_dir_entry_cluster = 0;
}
/* Setup the byte offset. */
sub_dir_entry.fx_dir_entry_byte_offset = FX_DIR_ENTRY_SIZE;
/* Write the directory's second entry. */
status = _fx_directory_entry_write(media_ptr, &sub_dir_entry);
/* Check for error condition. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return error status. */
return(status);
}
/* Write an EOF in the found FAT entry. */
status = _fx_utility_FAT_entry_write(media_ptr, FAT_index, media_ptr -> fx_media_fat_last);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
#ifdef FX_FAULT_TOLERANT
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
#endif
/* Now write out the new directory entry. */
status = _fx_directory_entry_write(media_ptr, &dir_entry);
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
/* End transaction. */
status = _fx_fault_tolerant_transaction_end(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Directory create is complete, return status. */
return(status);
}
+106
View File
@@ -0,0 +1,106 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_directory.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_default_get PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function returns the pointer of the last path provided to the */
/* fx_directory_default_set function. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* return_path_name Destination string pointer */
/* address */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_default_get(FX_MEDIA *media_ptr, CHAR **return_path_name)
{
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_default_gets++;
#endif
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_DEFAULT_GET, media_ptr, return_path_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Return the last pointer supplied to the set default directory function. */
*return_path_name = media_ptr -> fx_media_default_path.fx_path_string;
/* Release media protection. */
FX_UNPROTECT
/* Return successful status. */
return(FX_SUCCESS);
}
+114
View File
@@ -0,0 +1,114 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_directory.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_default_get_copy PORTABLE C */
/* 6.1.6 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function copies the last path provided to the */
/* fx_directory_default_set function into the specified buffer. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* return_path_name_buffer Destination buffer for name */
/* return_path_name_buffer_size Size of buffer pointed to by */
/* return_path_name_buffer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), verified */
/* memcpy usage, */
/* resulting in version 6.1 */
/* 04-02-2021 William E. Lamie Modified comment(s), verified */
/* memcpy usage, */
/* resulting in version 6.1.6 */
/* */
/**************************************************************************/
UINT _fx_directory_default_get_copy(FX_MEDIA *media_ptr, CHAR *return_path_name_buffer, UINT return_path_name_buffer_size)
{
UINT status;
CHAR *return_path_name;
UINT path_name_length_with_null_terminator;
/* Get the pointer to the path. */
status = _fx_directory_default_get(media_ptr, &return_path_name);
if (status == FX_SUCCESS)
{
/* Get the length of the path. */
path_name_length_with_null_terminator = _fx_utility_string_length_get(return_path_name, FX_MAXIMUM_PATH) + 1;
/* Can it fit in the user's buffer? */
if (path_name_length_with_null_terminator <= return_path_name_buffer_size)
{
/* Copy the path name into the user's buffer. */
_fx_utility_memory_copy((UCHAR *) return_path_name, (UCHAR *) return_path_name_buffer, path_name_length_with_null_terminator); /* Use case of memcpy is verified. */
}
else
{
/* Buffer is too small. Return error. */
return(FX_BUFFER_ERROR);
}
}
/* Return successful status. */
return(status);
}
+422
View File
@@ -0,0 +1,422 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_file.h"
#include "fx_utility.h"
#include "fx_directory.h"
#ifndef FX_NO_LOCAL_PATH
FX_LOCAL_PATH_SETUP
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_default_set PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the default directory of the media to the path */
/* specified by the caller. If this path is not found, an error code */
/* is returned. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* new_path_name New path to set current */
/* working directory to */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_search Search for the directory name */
/* in the directory structure */
/* _fx_utility_absolute_path_get Get absolute path */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_default_set(FX_MEDIA *media_ptr, CHAR *new_path_name)
{
UINT status;
FX_DIR_ENTRY dir_entry;
CHAR *path_string_ptr;
UINT path_string_capacity;
FX_PATH *path_ptr;
UINT i;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_default_sets++;
#endif
/* Setup pointer to media name buffer. */
dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Clear the short name string. */
dir_entry.fx_dir_entry_short_name[0] = 0;
/* Clear the long name string. */
dir_entry.fx_dir_entry_name[0] = (CHAR)0;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_DEFAULT_SET, media_ptr, new_path_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Setup the path string pointer to the start of the current path. */
path_string_ptr = &(media_ptr -> fx_media_default_path.fx_path_string[0]);
/* Look for a root directory selection. */
if ((!new_path_name) || (((new_path_name[0] == '\\') || (new_path_name[0] == '/')) && (new_path_name[1] == (CHAR)0)))
{
/* Set the media current working directory to the root. */
media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name[0] = (CHAR) 0;
media_ptr -> fx_media_default_path.fx_path_string[0] = (CHAR) 0;
media_ptr -> fx_media_default_path.fx_path_string[FX_MAXIMUM_PATH - 2] = (CHAR) 0;
}
else
{
/* Search the system for the supplied path and directory name. */
status = _fx_directory_search(media_ptr, new_path_name, &dir_entry, FX_NULL, FX_NULL);
/* Determine if the search failed or if the entry found is not a
directory. */
if ((status != FX_SUCCESS) || (!(dir_entry.fx_dir_entry_attributes & FX_DIRECTORY)))
{
/* Release media protection. */
FX_UNPROTECT
/* Invalid Path - Return the error code. */
return(FX_INVALID_PATH);
}
/* Now update the current path string. */
/* Setup the path string's capacity. */
path_string_capacity = FX_MAXIMUM_PATH - 1;
/* Determine if the new path is relative from the current path. */
if ((new_path_name[0] != '\\') && (new_path_name[0] != '/'))
{
/* Yes, a relative path was found. */
/* First check for a local path pointer stored in the thread control block.
This is only available in ThreadX Version 4 and above. */
#ifndef FX_NO_LOCAL_PATH
if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
{
CHAR *saved_name_ptr;
/* First, save the name pointer of the default path. */
saved_name_ptr = media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name;
/* Setup the default path pointer to the local path. */
path_ptr = (FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr;
/* Copy the local path to the default path. */
media_ptr -> fx_media_default_path = *path_ptr;
/* Restore the name pointer of the default path. */
media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name = saved_name_ptr;
/* Set the path pointer to the default pointer. */
path_ptr = &media_ptr -> fx_media_default_path;
}
else
{
/* Setup the default path to the global media path. */
path_ptr = &media_ptr -> fx_media_default_path;
}
#else
/* Setup the default path to the global media path. */
path_ptr = &media_ptr -> fx_media_default_path;
#endif
/* First, check the current path for string overflow. If this is set,
don't attempt to update the current path with relative information.
The path won't be valid again until a complete path is given. */
if (path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] == '*')
{
/* Yes, don't update the string, just finish the path set processing. */
/* Determine if we are at the root directory. */
if (!dir_entry.fx_dir_entry_cluster)
{
/* Set the current directory back to the root directory. */
path_ptr -> fx_path_directory.fx_dir_entry_name[0] = (CHAR) 0;
/* Set name to NULL. */
dir_entry.fx_dir_entry_name[0] = (CHAR) 0;
/* Clear the current path string. */
path_ptr -> fx_path_string[0] = (CHAR)0;
/* Clear the overflow flag in the current path string... just in
case! */
path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] = (CHAR)0;
}
/* Copy the new directory entry into the media control block. */
path_ptr -> fx_path_directory = dir_entry;
/* Copy the name into the path name buffer. */
for (i = 0; dir_entry.fx_dir_entry_name[i]; i++)
{
path_ptr -> fx_path_name_buffer[i] = dir_entry.fx_dir_entry_name[i];
}
/* Reassign the pointer. */
path_ptr -> fx_path_directory.fx_dir_entry_name = path_ptr -> fx_path_name_buffer;
/* Release media protection. */
FX_UNPROTECT
/* Default directory set is complete, return status. */
return(FX_SUCCESS);
}
/* Move the current path starting pointer to the end of the current
path string. */
while ((path_string_capacity) && (*path_string_ptr != FX_NULL))
{
path_string_ptr++;
path_string_capacity--;
}
/* If room, place the \ character in the path string. */
if (path_string_capacity)
{
/* There is room, place the directory marker in the string. */
*path_string_ptr++ = '\\';
path_string_capacity--;
}
}
else
{
/* Setup the default path pointer. */
/* First check for a local path pointer stored in the thread control block.
This is only available in ThreadX Version 4 and above. */
#ifndef FX_NO_LOCAL_PATH
if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
{
CHAR *saved_name_ptr;
/* First, save the name pointer of the default path. */
saved_name_ptr = media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name;
/* Setup the default path pointer to the local path. */
path_ptr = (FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr;
/* Copy the local path to the default path. */
media_ptr -> fx_media_default_path = *path_ptr;
/* Restore the name pointer of the default path. */
media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name = saved_name_ptr;
/* Set the path pointer to the default pointer. */
path_ptr = &media_ptr -> fx_media_default_path;
}
else
{
/* Setup the default path to the global media path. */
path_ptr = &media_ptr -> fx_media_default_path;
}
#else
/* Setup the default path to the global media path. */
path_ptr = &media_ptr -> fx_media_default_path;
#endif
/* Complete path name given. Check to see if we need to clear an
overflow character from a previous current path string update. */
if (path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] == '*')
{
path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] = (CHAR)0;
}
}
/* Copy what we can into the current path. */
while (*new_path_name)
{
/* Determine if there is a ".." character sequence that specifies the
previous path. */
if ((*new_path_name == '.') && (*(new_path_name + 1) == '.'))
{
/* Yes, a backward path is found. The current path pointer
must be moved back to just after the previous \ character. */
/* Skip the current \0 that is at the end of the current path. */
path_string_capacity = path_string_capacity + 2;
path_string_ptr = path_string_ptr - 2;
while (path_string_capacity <= (FX_MAXIMUM_PATH - 1))
{
/* Move the current path pointer backwards until
a \ character is found. */
if ((*path_string_ptr == '\\') || (*path_string_ptr == '/'))
{
/* Yes, we have successfully backed up one directory. */
break;
}
/* Backup another character. */
path_string_capacity++;
path_string_ptr--;
}
/* Adjust the new directory pointer past the .. characters */
new_path_name = new_path_name + 2;
}
else
{
/* Normal characters that need to be copied into the current path. */
if (path_string_capacity)
{
/* Copy character from the new path into the current path string. */
*path_string_ptr++ = *new_path_name++;
path_string_capacity--;
}
else
{
/* No more room in the current path string! */
break;
}
}
}
/* Determine if there is still room in the current path string. */
if (path_string_capacity)
{
/* Yes, there is still room, place a NULL character at the
end of the path. */
*path_string_ptr = (CHAR)FX_NULL;
}
else
{
/* No more room. Determine if the entire path was successfully
copied into the current path. */
if (*new_path_name)
{
/* No, we couldn't fit the entire path. Place a "*" character
at the end to indicate that we had overflow. Note that
the path is kept just the the directory default get call, so
the new default path is valid. */
path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] = '*';
}
}
/* Determine if we are at the root directory. */
if (!dir_entry.fx_dir_entry_cluster)
{
/* Set the current directory back to the root directory. */
dir_entry.fx_dir_entry_name[0] = (CHAR)0;
path_ptr -> fx_path_name_buffer[0] = (CHAR)0;
}
/* Copy the new directory entry into the media control block. */
path_ptr -> fx_path_directory = dir_entry;
/* Copy the name. */
for (i = 0; dir_entry.fx_dir_entry_name[i]; i++)
{
path_ptr -> fx_path_name_buffer[i] = dir_entry.fx_dir_entry_name[i];
}
/* Reassign the pointer. */
path_ptr -> fx_path_directory.fx_dir_entry_name = path_ptr -> fx_path_name_buffer;
}
/* Release media protection. */
FX_UNPROTECT
/* Default directory set is complete, return status. */
return(FX_SUCCESS);
}
+451
View File
@@ -0,0 +1,451 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
#include "fx_fault_tolerant.h"
#endif /* FX_ENABLE_FAULT_TOLERANT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_delete PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function first attempts to find the specified directory. */
/* If found, the directory is examined to make sure it is empty. If */
/* the directory is not empty, an error code is returned to the */
/* caller. Otherwise, the directory will be deleted and its clusters */
/* will be made available. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* directory_name Directory name to delete */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_read Read a directory entry */
/* _fx_directory_entry_write Write the new directory entry */
/* _fx_directory_search Search for the file name in */
/* the directory structure */
/* _fx_utility_logical_sector_flush Flush the written log sector */
/* _fx_utility_FAT_entry_read Read FAT entries to calculate */
/* the sub-directory size */
/* _fx_utility_FAT_entry_write Write FAT entry */
/* _fx_utility_FAT_flush Flush FAT cache */
/* _fx_fault_tolerant_transaction_start Start fault tolerant */
/* transaction */
/* _fx_fault_tolerant_transaction_end End fault tolerant transaction*/
/* _fx_fault_tolerant_recover Recover FAT chain */
/* _fx_fault_tolerant_reset_log_file Reset the log file */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_delete(FX_MEDIA *media_ptr, CHAR *directory_name)
{
UINT status;
ULONG cluster, next_cluster;
ULONG i, directory_size;
FX_DIR_ENTRY dir_entry;
FX_DIR_ENTRY search_directory;
FX_DIR_ENTRY search_entry;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_deletes++;
#endif
/* Setup pointer to media name buffer. */
dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Setup search pointer to media name buffer. */
search_directory.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 2;
/* Setup search entry pointer to media name buffer. */
search_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 3;
/* Clear the short name string of the three file names that will be worked with. */
dir_entry.fx_dir_entry_short_name[0] = 0;
search_directory.fx_dir_entry_short_name[0] = 0;
search_entry.fx_dir_entry_short_name[0] = 0;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_DELETE, media_ptr, directory_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Start transaction. */
_fx_fault_tolerant_transaction_start(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Check for write protect at the media level (set by driver). */
if (media_ptr -> fx_media_driver_write_protect)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return write protect error. */
return(FX_WRITE_PROTECT);
}
/* Search the system for the supplied directory name. */
status = _fx_directory_search(media_ptr, directory_name, &dir_entry, FX_NULL, FX_NULL);
/* Determine if the search was successful. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Check to make sure the found entry is a directory. */
if (!(dir_entry.fx_dir_entry_attributes & (UCHAR)(FX_DIRECTORY)))
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the not a directory error code. */
return(FX_NOT_DIRECTORY);
}
/* Check if the entry is read only */
if (dir_entry.fx_dir_entry_attributes & (UCHAR)(FX_READ_ONLY))
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the not a directory error code. */
return(FX_WRITE_PROTECT);
}
/* Copy the directory entry to the search directory structure for
looking at the specified sub-directory contents. */
search_directory = dir_entry;
/* Ensure that the search directory's last search cluster is cleared. */
search_directory.fx_dir_entry_last_search_cluster = 0;
/* Calculate the directory size by counting the allocated
clusters for it. */
i = 0;
cluster = search_directory.fx_dir_entry_cluster;
while (cluster < media_ptr -> fx_media_fat_reserved)
{
/* Increment the cluster count. */
i++;
/* Read the next FAT entry. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
/* Check the return status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(FX_FAT_READ_ERROR);
}
cluster = next_cluster;
}
/* Now we can calculate the directory size. */
directory_size = (((ULONG)media_ptr -> fx_media_bytes_per_sector) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster) * i) /
(ULONG)FX_DIR_ENTRY_SIZE;
/* Also save this in the directory entry so we don't have to
calculate it later. */
search_directory.fx_dir_entry_file_size = directory_size;
/* Make sure the new name is not in the current directory. */
/* The first two entries are skipped because they are just part of the sub-directory. */
i = 2;
do
{
/* Read an entry from the directory. */
status = _fx_directory_entry_read(media_ptr, &search_directory, &i, &search_entry);
/* Check for error status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return error condition. */
return(status);
}
/* Determine if this is the last directory entry. */
if (search_entry.fx_dir_entry_name[0] == FX_DIR_ENTRY_DONE)
{
break;
}
/* Determine if this is an empty entry. */
if ((UCHAR)search_entry.fx_dir_entry_name[0] != (UCHAR)FX_DIR_ENTRY_FREE)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return error status. */
return(FX_DIR_NOT_EMPTY);
}
i++;
} while (i < directory_size);
/* At this point, we are going to delete the empty directory. */
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
/* Invalidate the directory search saved information. */
media_ptr -> fx_media_last_found_name[0] = FX_NULL;
#endif
/* Mark the sub-directory entry as available. */
dir_entry.fx_dir_entry_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
dir_entry.fx_dir_entry_short_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
/* Now write out the directory entry. */
status = _fx_directory_entry_write(media_ptr, &dir_entry);
/* Determine if the write was successful. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Walk through the directory's clusters and release them. */
cluster = search_directory.fx_dir_entry_cluster;
while (cluster < media_ptr -> fx_media_fat_reserved)
{
/* Increment the cluster count. */
i++;
/* Read the next FAT entry. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
/* Check the return status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(FX_FAT_READ_ERROR);
}
/* Release the current cluster. */
status = _fx_utility_FAT_entry_write(media_ptr, cluster, FX_FREE_CLUSTER);
/* Check the return status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
/* Increment the number of available clusters for the media. */
media_ptr -> fx_media_available_clusters++;
/* Copy next cluster to current cluster. */
cluster = next_cluster;
}
#ifdef FX_FAULT_TOLERANT
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
#endif
/* Flush the logical sector cache. */
status = _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64)(media_ptr -> fx_media_sectors_per_FAT), FX_FALSE);
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
/* End transaction. */
status = _fx_fault_tolerant_transaction_end(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Directory delete is complete, return status. */
return(status);
}
+722
View File
@@ -0,0 +1,722 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_entry_read PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function reads the supplied directory entry from the supplied */
/* source directory. If the supplied directory entry is NULL, then */
/* the root directory is assumed. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* source_dir Source directory entry */
/* entry_ptr Directory entry number */
/* destination_ptr Pointer to destination for */
/* the directory entry */
/* */
/* OUTPUT */
/* */
/* return status */
/* *entry_ptr should point to the 8:3 entry if it is a long name */
/* */
/* CALLS */
/* */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* _fx_utility_logical_sector_read Read directory sector */
/* _fx_utility_16_unsigned_read Read a UINT from memory */
/* _fx_utility_32_unsigned_read Read a ULONG from memory */
/* */
/* CALLED BY */
/* */
/* FileX System Functions */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_entry_read(FX_MEDIA *media_ptr, FX_DIR_ENTRY *source_dir,
ULONG *entry_ptr, FX_DIR_ENTRY *destination_ptr)
{
UINT i, j, card, dotflag, get_short_name;
UINT number_of_lfns;
UINT status;
ULONG cluster, next_cluster = 0;
UINT relative_cluster;
UINT relative_sector;
ULONG logical_sector;
ULONG byte_offset;
ULONG bytes_per_cluster;
UCHAR *read_ptr;
CHAR *short_name_ptr;
ULONG entry = *entry_ptr;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of directory entry read requests. */
media_ptr -> fx_media_directory_entry_reads++;
#endif
/* Extended port-specific processing macro, which is by default defined to white space. */
FX_DIRECTORY_ENTRY_READ_EXTENSION
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_DIR_ENTRY_READ, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Calculate the byte offset of this directory entry. */
byte_offset = entry * FX_DIR_ENTRY_SIZE;
/* Determine if a sub-directory or FAT32 root directory is specified. */
if ((source_dir) || (media_ptr -> fx_media_32_bit_FAT))
{
/* Yes, a sub-directory is present. */
/* Calculate the number of bytes per cluster. */
bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster);
/* Check for invalid value. */
if (bytes_per_cluster == 0)
{
/* Invalid media, return error. */
return(FX_MEDIA_INVALID);
}
/* Now determine the relative cluster in the sub-directory file. */
relative_cluster = (UINT)(byte_offset / bytes_per_cluster);
/* Calculate the byte offset within the cluster. */
byte_offset = byte_offset % bytes_per_cluster;
/* Now figure out the relative sector within the cluster. */
relative_sector = (UINT)(byte_offset / ((ULONG)media_ptr -> fx_media_bytes_per_sector));
/* Read the directory sector into the internal memory buffer. */
/* Determine if there is a sub-directory. */
if (source_dir)
{
/* Determine if this source directory has valid information from the previous call. */
if ((source_dir -> fx_dir_entry_last_search_cluster) &&
(source_dir -> fx_dir_entry_last_search_relative_cluster <= relative_cluster) &&
(source_dir -> fx_dir_entry_last_search_log_sector == source_dir -> fx_dir_entry_log_sector) &&
(source_dir -> fx_dir_entry_last_search_byte_offset == source_dir -> fx_dir_entry_byte_offset))
{
/* Use the previous information to start the search. */
cluster = source_dir -> fx_dir_entry_last_search_cluster;
/* Setup the relative cluster index to the saved relative cluster. */
i = source_dir -> fx_dir_entry_last_search_relative_cluster;
/* Clear the search cluster. It will be updated prior to successful return. */
source_dir -> fx_dir_entry_last_search_cluster = 0;
}
else
{
/* Nothing from the previous directory read, just setup the starting cluster to the
beginning of the sub-directory. */
cluster = source_dir -> fx_dir_entry_cluster;
/* Setup the relative cluster index to zero. */
i = 0;
}
}
else
{
/* No, setup the starting cluster to the FAT32 root cluster. */
cluster = media_ptr -> fx_media_root_cluster_32;
/* Setup the relative cluster index to zero. */
i = 0;
}
/* Loop to position to the appropriate cluster. */
while (i < relative_cluster)
{
/* Check the value of the new cluster - it must be a valid cluster number
or something is really wrong! */
if ((cluster < FX_FAT_ENTRY_START) || (cluster >= media_ptr -> fx_media_fat_reserved))
{
/* Send error message back to caller. */
return(FX_FILE_CORRUPT);
}
/* Read the next cluster. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
/* There is a potential for loop, but hardly anything can be done */
/* Check for I/O error. */
if (status != FX_SUCCESS)
{
/* Return error code. */
return(status);
}
/* Setup the actual cluster. */
cluster = next_cluster;
/* Increment the relative cluster number. */
i++;
}
/* At this point, the directory data sector needs to be read. */
logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG)cluster - FX_FAT_ENTRY_START) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
relative_sector;
/* Read the logical directory sector. */
status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
/* Determine if an error occurred. */
if (status != FX_SUCCESS)
{
/* Return error code. */
return(status);
}
/* Calculate the byte offset within this sector. */
byte_offset = byte_offset % media_ptr -> fx_media_bytes_per_sector;
}
else
{
/* Read the entry from the root directory. */
/* Determine which sector the requested root directory entry is in. */
logical_sector = (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
(ULONG)media_ptr -> fx_media_root_sector_start;
/* Read the logical directory sector. */
status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
/* Determine if an error occurred. */
if (status != FX_SUCCESS)
{
/* Return error code. */
return(status);
}
/* Set the cluster and relative variables (not used in this case) to avoid any compiler
warnings. */
relative_cluster = relative_sector = cluster = 0;
/* Now calculate the byte offset into this sector. */
byte_offset = byte_offset -
((logical_sector - (ULONG)media_ptr -> fx_media_root_sector_start) *
media_ptr -> fx_media_bytes_per_sector);
}
/* Setup a pointer into the buffer. */
read_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
/* Save the logical sector and byte offset in the returned directory entry. */
destination_ptr -> fx_dir_entry_log_sector = logical_sector;
destination_ptr -> fx_dir_entry_byte_offset = byte_offset;
/* Clear the short file name information. */
destination_ptr -> fx_dir_entry_long_name_shorted = 0;
destination_ptr -> fx_dir_entry_short_name[0] = 0;
/* Setup short name pointer. */
short_name_ptr = destination_ptr -> fx_dir_entry_name;
/* Check if long file name exists. */
get_short_name = 0;
if ((*(read_ptr + 11) == (UCHAR)FX_LONG_NAME) && (*read_ptr != (UCHAR)FX_DIR_ENTRY_FREE))
{
/* Collate the long name. */
/* Pickup the file name length. */
i = (((UINT)(*read_ptr & (UCHAR)0x1f) - 1) * FX_LONG_NAME_ENTRY_LEN) & 0xFFFFFFFF;
/* Save the number of LFN entries. */
number_of_lfns = (UINT)(*read_ptr & (UCHAR)0x1f);
/* Check the file name size. */
if (i >= (FX_MAX_LONG_NAME_LEN - 1))
{
/* Name is too big, shorten it. */
get_short_name = 1;
destination_ptr -> fx_dir_entry_long_name_shorted = (UINT)(*read_ptr & (UCHAR)0x1f);
}
else
{
/* Size of name is fine, save pointer to short file name. */
short_name_ptr = destination_ptr -> fx_dir_entry_short_name;
/* Loop to make sure the long file name is NULL terminated. */
j = i + FX_LONG_NAME_ENTRY_LEN + 1;
do
{
/* Place a NULL in the long name. */
destination_ptr -> fx_dir_entry_name[i] = 0;
/* Position to the next entry. */
i++;
} while ((i < j) && (i < FX_MAX_LONG_NAME_LEN));
}
/* Loop to pickup the rest of the name. */
do
{
/* Get the lower 5 bit containing the cardinality. */
card = (UINT)(*read_ptr & (UCHAR)0x1f) - 1;
/* For simplicity no checksum or cardinality checking is done */
if (get_short_name == 0)
{
/* Loop to pickup name. */
for (i = 1, j = 0; i < FX_DIR_ENTRY_SIZE; i += 2)
{
if ((i == 11) || (i == 26))
{
continue;
}
/* i = 12, 27 is not generated due to +=2 */
if (i == 13)
{
i = 12;
continue; /* this time next unicode is byte offset 14*/
}
/* Determine if there is an actual unicode character present. */
if (read_ptr[i + 1])
{
/* Extended byte is non-zero, make sure both bytes of the unicode entry are not
all ones, since this is a normal case. */
if ((read_ptr[i + 1] != (UCHAR)0xFF) || (read_ptr[i] != (UCHAR)0xFF))
{
/* Name is an actual unicode name, shorten it. */
get_short_name = 1;
/* Save the number of directory entries the LFN has. This will be
used later when updating the 8.3 portion of the LFN. */
destination_ptr -> fx_dir_entry_long_name_shorted = number_of_lfns;
/* Setup short name pointer. */
short_name_ptr = destination_ptr -> fx_dir_entry_name;
}
}
/* Determine if the character is NULL. */
if ((read_ptr[i] == FX_NULL) || (read_ptr[i] == (UCHAR)0xFF))
{
continue;
}
/* Determine if the name is too big. */
if ((card * 13 + j) >= (FX_MAX_LONG_NAME_LEN - 1))
{
/* Name is actually too big, shorten it. */
get_short_name = 1;
/* Save the number of directory entries the LFN has. This will be
used later when updating the 8.3 portion of the LFN. */
destination_ptr -> fx_dir_entry_long_name_shorted = number_of_lfns;
/* Also reposition the short name pointer. */
short_name_ptr = destination_ptr -> fx_dir_entry_name;
break;
}
/* Each entry contains 13 unicode and first byte ASCII, second byte is extended. */
destination_ptr -> fx_dir_entry_name[13 * card + j] = (CHAR)read_ptr[i];
j++;
}
}
/* Determine if a new sector needs to be read. */
if (byte_offset + FX_DIR_ENTRY_SIZE >= media_ptr -> fx_media_bytes_per_sector)
{
/* Determine if a sub-directory or FAT32 root directory is specified. */
if ((source_dir) || (media_ptr -> fx_media_32_bit_FAT))
{
/* Determine the next sector of the directory entry. */
if (relative_sector < (media_ptr -> fx_media_sectors_per_cluster - 1))
{
/* More sectors in this cluster. */
/* Simply increment the logical sector. */
logical_sector++;
/* Increment the relative sector. */
relative_sector++;
}
else
{
/* We need to move to the next cluster. */
/* Pickup the next cluster. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
/* Check for I/O error. */
if (status != FX_SUCCESS)
{
/* Return error code. */
return(status);
}
/* Copy next cluster to the current cluster. */
cluster = next_cluster;
/* Check the value of the new cluster - it must be a valid cluster number
or something is really wrong! */
if ((cluster < FX_FAT_ENTRY_START) || (cluster >= media_ptr -> fx_media_fat_reserved))
{
/* Send error message back to caller. */
return(FX_FILE_CORRUPT);
}
/* Now increment the relative cluster. */
relative_cluster++;
/* Setup the relative sector (this is zero for subsequent cluster. */
relative_sector = 0;
/* Calculate the next logical sector. */
logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG)cluster - FX_FAT_ENTRY_START) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster));
}
}
else
{
/* Non-FAT 32 root directory. */
/* Advance to the next sector. */
logical_sector++;
/* Determine if the logical sector is valid. */
if (logical_sector >= (ULONG)(media_ptr -> fx_media_root_sector_start + media_ptr -> fx_media_root_sectors))
{
/* Trying to read past root directory - send error message back to caller. */
return(FX_FILE_CORRUPT);
}
}
/* Read the new sector. */
status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
/* Check I/O status. */
if (status != FX_SUCCESS)
{
return(status);
}
/* Set the byte offset to 0 for new sector. */
byte_offset = 0;
}
else
{
/* Calculate the new byte offset. */
byte_offset += FX_DIR_ENTRY_SIZE;
}
/* Calculate the next read pointer. */
read_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT) byte_offset;
/* Move to the next entry. */
entry++;
} while (card > 0);
/* Set flag indicating long file name is present. */
destination_ptr -> fx_dir_entry_long_name_present = 1;
}
else
{
/* No long file name is present. */
get_short_name = 1;
}
/* Determine if we need to clear the long name flag. */
if (get_short_name == 1)
{
/* Clear the long name flag. */
destination_ptr -> fx_dir_entry_long_name_present = 0;
}
/* Pickup the short file name. */
short_name_ptr[0] = 0;
dotflag = 0;
for (i = 0, j = 0; i < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); i++)
{
/* Check for a NULL. */
if ((CHAR)read_ptr[i] == 0)
{
break;
}
/* Check for a dot. This happens for the first two directory entries, no
extra dot is needed. */
if ((CHAR)read_ptr[i] == '.')
{
dotflag = 2;
}
/* Check for a space. */
if ((CHAR)read_ptr[i] == ' ')
{
/* Put a dot if a character comes after space. */
if (dotflag == 0)
{
dotflag = 1;
}
continue;
}
/* Check for the main short file name size. */
if (i == FX_DIR_NAME_SIZE)
{
/* Check to see if we need to insert a dot. */
if (dotflag == 0)
{
dotflag = 1;
}
}
/* Check to see if we need to add a dot. */
if (dotflag == 1)
{
/* Add dot to short file name. */
short_name_ptr[j++] = '.';
dotflag = 2; /* no more dot for spaces */
}
/* Copy a character. */
short_name_ptr[j] = (CHAR)read_ptr[i];
/* Increment size. */
j++;
}
/* Determine if a long file name is present and its associated short file
name is actually free. */
if ((destination_ptr -> fx_dir_entry_long_name_present) && (((UCHAR)short_name_ptr[0]) == (UCHAR)FX_DIR_ENTRY_FREE))
{
/* Yes, the short file name is really free even though long file name entries directly precede it.
In this case, simply place the free directory marker at the front of the long file name. */
destination_ptr -> fx_dir_entry_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
short_name_ptr[0] = (CHAR)0;
}
/* Determine if the short name pointer is NULL while the read pointer is
non-NULL. */
if ((short_name_ptr[0] == 0) && (read_ptr[0] == ' '))
{
/* This condition can occur with an all blank volume name. Simply
copy the volume name to the short name in this case. */
for (j = 0; j < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); j++)
{
/* Copy a byte of the volume name. */
short_name_ptr[j] = (CHAR)read_ptr[j];
}
}
/* Set end of string to null. */
short_name_ptr[j] = 0;
/* Load up the destination directory entry. */
read_ptr += (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE);
/* Copy the attribute into the destination. */
destination_ptr -> fx_dir_entry_attributes = *read_ptr++;
/* Pickup the reserved byte. */
destination_ptr -> fx_dir_entry_reserved = *read_ptr++;
/* Check for an undocumented NT file name feature for optimizing the storage
of all lower case file names that otherwise are valid 8.3 file names. The
following reserved bit definitions are present:
BIT3 - set if 8.3 is all in lower case and no extended filename.
BIT4 - set for file, clear for directory entry if no extended filename.
This is true for all NT systems. Prior to NT follows MSDOS FAT documentation and
is set to 0x00, all bits cleared. Therefore if BIT3 is set force lowercase. */
if ((get_short_name) && (destination_ptr -> fx_dir_entry_reserved & 0x08))
{
/* Microsoft undocumented NT file name feature... convert short name to lower
case. */
for (j = 0; j <= (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE) && (short_name_ptr[j] != 0x00); j++)
{
/* Determine if an upper case character is present. */
if ((short_name_ptr[j] >= 'A') && (short_name_ptr[j] <= 'Z'))
{
/* Yes, an upper case character is present. Force it to lower case. */
short_name_ptr[j] = (CHAR)(short_name_ptr[j] + 32);
}
}
}
/* Pickup the created time in milliseconds. */
destination_ptr -> fx_dir_entry_created_time_ms = *read_ptr++;
/* Pickup the created time. */
destination_ptr -> fx_dir_entry_created_time = _fx_utility_16_unsigned_read(read_ptr);
read_ptr = read_ptr + 2; /* Always 2 bytes */
/* Pickup the created date. */
destination_ptr -> fx_dir_entry_created_date = _fx_utility_16_unsigned_read(read_ptr);
read_ptr = read_ptr + 2; /* Always 2 bytes */
/* Pickup the last accessed date. */
destination_ptr -> fx_dir_entry_last_accessed_date = _fx_utility_16_unsigned_read(read_ptr);
read_ptr = read_ptr + 2; /* Always 2 bytes */
/* read the upper 2 bytes of starting cluster - required only for 32 bit FAT */
if (media_ptr -> fx_media_32_bit_FAT)
{
/* FAT32 only. */
destination_ptr -> fx_dir_entry_cluster = _fx_utility_16_unsigned_read(read_ptr);
destination_ptr -> fx_dir_entry_cluster <<= 16;
}
else
{
/* Not required for non FAT32. */
destination_ptr -> fx_dir_entry_cluster = 0;
}
/* Advance the read pointer. */
read_ptr = read_ptr + 2; /* Always 2 bytes */
/* Copy the time into the destination. */
destination_ptr -> fx_dir_entry_time = _fx_utility_16_unsigned_read(read_ptr);
read_ptr = read_ptr + 2; /* Always 2 bytes */
/* Copy the date into the destination. */
destination_ptr -> fx_dir_entry_date = _fx_utility_16_unsigned_read(read_ptr);
read_ptr = read_ptr + 2; /* Always 2 bytes */
/* Copy the starting cluster into the destination. */
destination_ptr -> fx_dir_entry_cluster += _fx_utility_16_unsigned_read(read_ptr);
read_ptr = read_ptr + 2; /* Always 2 bytes */
/* Copy the file size into the destination. */
destination_ptr -> fx_dir_entry_file_size = _fx_utility_32_unsigned_read(read_ptr);
/* Clear the destination search specific fields. */
destination_ptr -> fx_dir_entry_last_search_cluster = 0;
destination_ptr -> fx_dir_entry_last_search_relative_cluster = 0;
destination_ptr -> fx_dir_entry_last_search_log_sector = 0;
destination_ptr -> fx_dir_entry_last_search_byte_offset = 0;
/* Remember the entry number. */
destination_ptr -> fx_dir_entry_number = entry;
/* Return entry number. */
*entry_ptr = entry;
/* Determine if we should remember the last cluster and relative cluster. */
if (source_dir)
{
/* Yes, remember the last cluster and relative cluster for a subsequent call
to read a directory entry. */
source_dir -> fx_dir_entry_last_search_cluster = cluster;
source_dir -> fx_dir_entry_last_search_relative_cluster = relative_cluster;
/* Also remember several other items that are unique to the directory... just to verify that the
search information can be used. */
source_dir -> fx_dir_entry_last_search_log_sector = source_dir -> fx_dir_entry_log_sector;
source_dir -> fx_dir_entry_last_search_byte_offset = source_dir -> fx_dir_entry_byte_offset;
}
/* Return success to the caller. */
return(FX_SUCCESS);
}
File diff suppressed because it is too large Load Diff
+136
View File
@@ -0,0 +1,136 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_utility.h"
#ifndef FX_NO_LOCAL_PATH
FX_LOCAL_PATH_SETUP
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_first_entry_find PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function returns the first directory entry of the current */
/* working directory. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* directory_name Destination for directory */
/* name */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_next_entry_find Find next directory entry */
/* */
/* CALLED BY */
/* */
/* FileX System Functions */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_first_entry_find(FX_MEDIA *media_ptr, CHAR *directory_name)
{
UINT status;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_first_entry_finds++;
#endif
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_FIRST_ENTRY_FIND, media_ptr, directory_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Determine if a local path is in effect at this point. */
#ifndef FX_NO_LOCAL_PATH
if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
{
/* Yes, there is a local path. Set the current entry to zero. */
((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_current_entry = 0;
}
else
{
/* Use global default directory. Set the current entry to 0 in
order to pickup the first entry. */
media_ptr -> fx_media_default_path.fx_path_current_entry = 0;
}
#else
/* Set the current entry to 0 in order to pickup the first entry. */
media_ptr -> fx_media_default_path.fx_path_current_entry = 0;
#endif
/* Release media protection. */
FX_UNPROTECT
/* Call the next directory entry to pickup the first entry. */
status = _fx_directory_next_entry_find(media_ptr, directory_name);
/* Return status to the caller. */
return(status);
}
@@ -0,0 +1,146 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_utility.h"
#ifndef FX_NO_LOCAL_PATH
FX_LOCAL_PATH_SETUP
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_first_full_entry_find PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function returns the first directory entry of the current */
/* working directory and selected information about the entry. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* directory_name Destination for directory */
/* name */
/* attributes Destination for attributes */
/* size Destination for size */
/* year Destination for year */
/* month Destination for month */
/* day Destination for day */
/* hour Destination for hour */
/* minute Destination for minute */
/* second Destination for second */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_next_full_entry_find Find next full directory entry*/
/* */
/* CALLED BY */
/* */
/* FileX System Functions */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_first_full_entry_find(FX_MEDIA *media_ptr,
CHAR *directory_name, UINT *attributes, ULONG *size,
UINT *year, UINT *month, UINT *day, UINT *hour, UINT *minute, UINT *second)
{
UINT status;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_first_full_entry_finds++;
#endif
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_FIRST_FULL_ENTRY_FIND, media_ptr, directory_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Determine if a local path is in effect at this point. */
#ifndef FX_NO_LOCAL_PATH
if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
{
/* Yes, there is a local path. Set the current entry to zero. */
((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_current_entry = 0;
}
else
{
/* Use global default directory. Set the current entry to 0 in
order to pickup the first entry. */
media_ptr -> fx_media_default_path.fx_path_current_entry = 0;
}
#else
/* Set the current entry to 0 in order to pickup the first entry. */
media_ptr -> fx_media_default_path.fx_path_current_entry = 0;
#endif
/* Release media protection. */
FX_UNPROTECT
/* Call the next directory full entry service to pickup the first entry. */
status = _fx_directory_next_full_entry_find(media_ptr, directory_name, attributes,
size, year, month, day, hour, minute, second);
/* Return status to the caller. */
return(status);
}
+770
View File
@@ -0,0 +1,770 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_free_search PORTABLE C */
/* 6.1.12 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function searches the media for a free directory entry. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* directory_ptr Pointer to directory to */
/* search in */
/* entry_ptr Pointer to directory entry */
/* record */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_read Read entries from directory */
/* _fx_directory_entry_write Write entries to directory */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* _fx_utility_FAT_entry_write Write a FAT entry */
/* _fx_utility_FAT_flush Flush written FAT entries */
/* _fx_utility_logical_sector_flush Flush logical sector cache */
/* _fx_utility_logical_sector_read Read logical sector */
/* _fx_utility_logical_sector_write Write logical sector */
/* */
/* CALLED BY */
/* */
/* FileX System Functions */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 07-29-2022 Bhupendra Naphade Modified comment(s), */
/* updated available cluster */
/* check for sub directory, */
/* resulting in version 6.1.12 */
/* */
/**************************************************************************/
UINT _fx_directory_free_search(FX_MEDIA *media_ptr, FX_DIR_ENTRY *directory_ptr, FX_DIR_ENTRY *entry_ptr)
{
ULONG i, j;
UCHAR *work_ptr;
UINT status, total_entries;
ULONG entry_sector, entry_offset;
ULONG FAT_index, FAT_value;
ULONG cluster, total_clusters, clusters_needed;
ULONG first_new_cluster, last_cluster, clusters;
ULONG directory_index;
ULONG directory_entries;
ULONG logical_sector;
FX_DIR_ENTRY *search_dir_ptr;
ULONG free_entry_start;
UINT sectors;
FX_INT_SAVE_AREA
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of directory free entry search requests. */
media_ptr -> fx_media_directory_free_searches++;
#endif
/* Initialize the entry sector values. */
entry_sector = entry_offset = 0;
/* Set the long file name flag to false. */
entry_ptr -> fx_dir_entry_long_name_present = 0;
/* Are there leading dots? */
if (entry_ptr -> fx_dir_entry_name[0] == '.')
{
/* Is there more than 1 dot? */
if (entry_ptr -> fx_dir_entry_name[1] == '.')
{
/* Yes, consider the name invalid. */
return(FX_INVALID_NAME);
}
}
/* Determine if a long file name is present. */
for (i = 0, j = 0; entry_ptr -> fx_dir_entry_name[i]; i++)
{
/* Check for upper-case characters. */
if ((entry_ptr -> fx_dir_entry_name[i] >= 'A') && (entry_ptr -> fx_dir_entry_name[i] <= 'Z'))
{
continue;
}
/* Check for numeric characters. */
else if ((entry_ptr -> fx_dir_entry_name[i] >= '0') && (entry_ptr -> fx_dir_entry_name[i] <= '9'))
{
continue;
}
/* Check for any lower-case characters. */
else if ((entry_ptr -> fx_dir_entry_name[i] >= 'a') && (entry_ptr -> fx_dir_entry_name[i] <= 'z'))
{
entry_ptr -> fx_dir_entry_long_name_present = 1;
}
/* Check for a space in the middle of the name. */
else if (entry_ptr -> fx_dir_entry_name[i] == ' ')
{
entry_ptr -> fx_dir_entry_long_name_present = 1;
}
/* Check for a dot in the name. */
else if (entry_ptr -> fx_dir_entry_name[i] == '.')
{
/* Determine if this is the first dot detected. */
if (j == 0)
{
/* First dot, remember where it was. */
j = i;
/* Determine if this is a leading dot. */
if (i == 0)
{
/* Leading dot detected, treat as a long filename. */
entry_ptr -> fx_dir_entry_long_name_present = 1;
}
}
else
{
/* Second dot detected, must have a long file name. */
entry_ptr -> fx_dir_entry_long_name_present = 1;
}
}
/* Check for a special 0xE5 character. */
else if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] == (UCHAR)0xE5)
{
entry_ptr -> fx_dir_entry_long_name_present = 1;
}
/* Check for code point value greater than 127. */
else if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] > (UCHAR)127)
{
continue;
}
/* Check for any special characters. */
else if ((entry_ptr -> fx_dir_entry_name[i] == '~') ||
(entry_ptr -> fx_dir_entry_name[i] == '-') ||
(entry_ptr -> fx_dir_entry_name[i] == '_') ||
(entry_ptr -> fx_dir_entry_name[i] == '}') ||
(entry_ptr -> fx_dir_entry_name[i] == '{') ||
(entry_ptr -> fx_dir_entry_name[i] == '(') ||
(entry_ptr -> fx_dir_entry_name[i] == ')') ||
(entry_ptr -> fx_dir_entry_name[i] == '`') ||
(entry_ptr -> fx_dir_entry_name[i] == '\'') ||
(entry_ptr -> fx_dir_entry_name[i] == '!') ||
(entry_ptr -> fx_dir_entry_name[i] == '#') ||
(entry_ptr -> fx_dir_entry_name[i] == '$') ||
(entry_ptr -> fx_dir_entry_name[i] == '&') ||
(entry_ptr -> fx_dir_entry_name[i] == '@') ||
(entry_ptr -> fx_dir_entry_name[i] == '^') ||
(entry_ptr -> fx_dir_entry_name[i] == '%'))
{
continue;
}
/* Check for long filename special characters. */
else if ((entry_ptr -> fx_dir_entry_name[i] == '+') ||
(entry_ptr -> fx_dir_entry_name[i] == ',') ||
(entry_ptr -> fx_dir_entry_name[i] == ';') ||
(entry_ptr -> fx_dir_entry_name[i] == '=') ||
(entry_ptr -> fx_dir_entry_name[i] == '[') ||
(entry_ptr -> fx_dir_entry_name[i] == ']'))
{
entry_ptr -> fx_dir_entry_long_name_present = 1;
}
/* Something is wrong with the supplied name. */
else
{
return(FX_INVALID_NAME);
}
}
/* Determine if a dot was found. */
if (j != 0)
{
/* Yes, Determine if the extension exceeds a 3 character extension. */
if ((i - j) > 4)
{
/* Yes, long file name is present. */
entry_ptr -> fx_dir_entry_long_name_present = 1;
}
}
/* Calculate the total entries needed. */
if ((i <= 12) && (entry_ptr -> fx_dir_entry_long_name_present == 0))
{
/* Initialize the total entries to 1. */
total_entries = 1;
/* Check for special instance of long file name. */
if ((j >= 9) || ((i - j) >= 9))
{
/* The dot is after 8 character or there is no dot and the name
is greater than 8 character. */
entry_ptr -> fx_dir_entry_long_name_present = 1;
total_entries = 2;
}
}
else
{
/* Long file name is present, calculate how many entries are needed
to represent it. */
if (i % 13 == 0)
{
/* Exact fit, just add one for the 8.3 short name. */
total_entries = i / 13 + 1;
}
else
{
/* Non-exact fit, add two for 8.3 short name and overlap. */
total_entries = i / 13 + 2;
}
}
/* Determine if the search is in the root directory or in a
sub-directory. Note: the directory search function clears the
first character of the name for the root directory. */
if (directory_ptr -> fx_dir_entry_name[0])
{
/* Search for a free entry in a sub-directory. */
/* Pickup the number of entries in this directory. This was placed
into the unused file size field. */
directory_entries = (ULONG)directory_ptr -> fx_dir_entry_file_size;
/* Point the search directory pointer to this entry. */
search_dir_ptr = directory_ptr;
/* Ensure that the search directory's last search cluster is cleared. */
search_dir_ptr -> fx_dir_entry_last_search_cluster = 0;
/* Set the initial index to 2, since the first two directory entries are
always allocated. */
directory_index = 2;
}
else
{
/* Find a free entry in the root directory. */
/* Setup the number of directory entries. */
directory_entries = (ULONG)media_ptr -> fx_media_root_directory_entries;
/* Set the search pointer to NULL since we are working off of the
root directory. */
search_dir_ptr = FX_NULL;
/* Set the initial index to 0, since the first entry of the root directory is valid. */
directory_index = 0;
}
/* Loop through entries in the search directory. Yes, this is a
linear search! */
free_entry_start = directory_entries;
do
{
/* Read an entry from the directory. */
status = _fx_directory_entry_read(media_ptr, search_dir_ptr, &directory_index, entry_ptr);
/* Check for error status. */
if (status != FX_SUCCESS)
{
return(status);
}
/* Determine if this is an empty entry. */
if ((((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry_ptr -> fx_dir_entry_short_name[0] == 0)) ||
((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_DONE))
{
/* Determine how many entries are needed. */
if (total_entries > 1)
{
/* Multiple entries are needed for long file names. Mark this
entry as free. */
if (entry_ptr -> fx_dir_entry_name[0] == FX_DIR_ENTRY_DONE)
{
entry_ptr -> fx_dir_entry_long_name_present = 0;
entry_ptr -> fx_dir_entry_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
entry_ptr -> fx_dir_entry_name[1] = (CHAR)0;
/* Write out the directory entry. */
status = _fx_directory_entry_write(media_ptr, entry_ptr);
if(status != FX_SUCCESS)
{
return(status);
}
/* Note that for long names we need to avoid holes in the middle,
i.e. entries must be logically contiguous. */
}
}
/* Determine if we are at the first free entry. */
if (free_entry_start == directory_entries)
{
/* Remember the start of the free entry. */
free_entry_start = directory_index;
entry_sector = (ULONG)entry_ptr -> fx_dir_entry_log_sector;
entry_offset = entry_ptr -> fx_dir_entry_byte_offset;
}
/* Determine if there are enough free entries to satisfy the request. */
if ((directory_index - free_entry_start + 1) >= total_entries)
{
/* Found an empty slot. Most pertinent information is already
in the entry structure. */
/* Setup the the sector and the offset. */
entry_ptr -> fx_dir_entry_log_sector = entry_sector;
entry_ptr -> fx_dir_entry_byte_offset = entry_offset;
/* Initialize the additional directory entries. */
entry_ptr -> fx_dir_entry_reserved = 0;
entry_ptr -> fx_dir_entry_created_time_ms = 0;
/* Lockout interrupts for time/date access. */
FX_DISABLE_INTS
entry_ptr -> fx_dir_entry_created_time = _fx_system_time;
entry_ptr -> fx_dir_entry_created_date = _fx_system_date;
entry_ptr -> fx_dir_entry_last_accessed_date = _fx_system_date;
/* Restore interrupts. */
FX_RESTORE_INTS
/* Determine if a long file name is present. */
if (total_entries == 1)
{
entry_ptr -> fx_dir_entry_long_name_present = 0;
}
else
{
entry_ptr -> fx_dir_entry_long_name_present = 1;
}
/* Return a successful completion. */
return(FX_SUCCESS);
}
}
else
{
/* Reset the free entry start. */
free_entry_start = directory_entries;
}
/* Move to the next entry. */
directory_index++;
/* Determine if we have exceeded the number of entries in the current directory. */
if (directory_index >= directory_entries)
{
/* Calculate how many sectors we need for the new directory entry. */
sectors = ((total_entries * FX_DIR_ENTRY_SIZE) + (media_ptr -> fx_media_bytes_per_sector - 1))/
media_ptr -> fx_media_bytes_per_sector;
/* Now calculate how many clusters we need for the new directory entry. */
clusters_needed = (sectors + (media_ptr -> fx_media_sectors_per_cluster - 1)) / media_ptr -> fx_media_sectors_per_cluster;
/* Not enough empty entries were found. If the specified directory is a sub-directory,
attempt to allocate another cluster to it. */
if (((search_dir_ptr) || (media_ptr -> fx_media_32_bit_FAT)) && (media_ptr -> fx_media_available_clusters >= clusters_needed))
{
/* Search for the additional clusters we need. */
first_new_cluster = 0;
total_clusters = media_ptr -> fx_media_total_clusters;
last_cluster = 0;
FAT_index = media_ptr -> fx_media_cluster_search_start;
clusters = clusters_needed;
/* Loop to find the needed clusters. */
while (clusters)
{
/* Decrease the cluster count. */
clusters--;
/* Loop to find the first available cluster. */
do
{
/* Make sure we stop looking after one pass through the FAT table. */
if (!total_clusters)
{
/* Something is wrong with the media - the desired clusters were
not found in the FAT table. */
return(FX_NO_MORE_SPACE);
}
/* Read FAT entry. */
status = _fx_utility_FAT_entry_read(media_ptr, FAT_index, &FAT_value);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
/* Return the bad status. */
return(status);
}
/* Decrement the total cluster count. */
total_clusters--;
/* Determine if the FAT entry is free. */
if (FAT_value == FX_FREE_CLUSTER)
{
/* Move cluster search pointer forward. */
media_ptr -> fx_media_cluster_search_start = FAT_index + 1;
/* Determine if this needs to be wrapped. */
if (media_ptr -> fx_media_cluster_search_start >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
{
/* Wrap the search to the beginning FAT entry. */
media_ptr -> fx_media_cluster_search_start = FX_FAT_ENTRY_START;
}
/* Break this loop. */
break;
}
else
{
/* FAT entry is not free... Advance the FAT index. */
FAT_index++;
/* Determine if we need to wrap the FAT index around. */
if (FAT_index >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
{
/* Wrap the search to the beginning FAT entry. */
FAT_index = FX_FAT_ENTRY_START;
}
}
} while (FX_TRUE);
/* We found an available cluster. We now need to clear all of entries in
each of the cluster's sectors. */
/* Calculate the logical sector of this cluster. */
logical_sector = ((ULONG) media_ptr -> fx_media_data_sector_start) +
((((ULONG) FAT_index) - FX_FAT_ENTRY_START) *
((ULONG) media_ptr -> fx_media_sectors_per_cluster));
/* Pickup the number of sectors for the next directory cluster. */
sectors = media_ptr -> fx_media_sectors_per_cluster;
/* Read the logical sector just for cache reasons. */
status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
/* Check the return value. */
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
/* Clear the entire first sector of the new sub-directory cluster. */
work_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer;
i = 0;
while (i < media_ptr -> fx_media_bytes_per_sector)
{
/* Clear 4 bytes. */
*((ULONG *)work_ptr) = (ULONG)0;
/* Increment pointer. */
work_ptr = work_ptr + sizeof(ULONG);
/* Increment counter. */
i = i + (ULONG)sizeof(ULONG);
}
/* Write the logical sector to ensure the zeros are written. */
status = _fx_utility_logical_sector_write(media_ptr, (ULONG64) logical_sector,
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
/* Determine if the write was successful. */
if (status != FX_SUCCESS)
{
/* Return the error code. */
return(status);
}
/* Determine if there are more sectors to clear in the first cluster of the new
sub-directory. */
if (sectors > 1)
{
/* Yes, invalidate all cached sectors that are contained in the newly allocated first
cluster of the directory. */
/* Flush the internal logical sector cache. */
status = _fx_utility_logical_sector_flush(media_ptr, (ULONG64) (logical_sector + 1), (ULONG64) (sectors - 1), FX_TRUE);
/* Determine if the flush was successful. */
if (status != FX_SUCCESS)
{
/* Return the error code. */
return(status);
}
/* Clear all additional sectors of new sub-directory. */
sectors--;
while (sectors)
{
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of driver write sector(s) requests. */
media_ptr -> fx_media_driver_write_requests++;
#endif
/* Build Write request to the driver. */
media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
media_ptr -> fx_media_driver_buffer = media_ptr -> fx_media_memory_buffer;
media_ptr -> fx_media_driver_logical_sector = (ULONG)logical_sector + ((ULONG)sectors);
media_ptr -> fx_media_driver_sectors = 1;
media_ptr -> fx_media_driver_sector_type = FX_DIRECTORY_SECTOR;
/* Set the system write flag since we are writing a directory sector. */
media_ptr -> fx_media_driver_system_write = FX_TRUE;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, ((ULONG)logical_sector) + ((ULONG)sectors), 1, media_ptr -> fx_media_memory_buffer, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Invoke the driver to write the sector. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Clear the system write flag. */
media_ptr -> fx_media_driver_system_write = FX_FALSE;
/* Determine if an error occurred. */
if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
{
/* Return error code. */
return(media_ptr -> fx_media_driver_status);
}
/* Decrease the number of sectors to clear. */
sectors--;
}
}
/* Determine if we have found the first new cluster yet. */
if (first_new_cluster == 0)
{
/* Remember the first new cluster. */
first_new_cluster = FAT_index;
}
/* Check for a valid last cluster to link. */
if (last_cluster)
{
/* Normal condition - link the last cluster with the new
found cluster. */
status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, FAT_index);
/* Check for a bad FAT write status. */
if (status != FX_SUCCESS)
{
/* Return the bad status. */
return(status);
}
}
/* Otherwise, remember the new FAT index as the last. */
last_cluster = FAT_index;
/* Move to the next FAT entry. */
FAT_index = media_ptr -> fx_media_cluster_search_start;
}
/* Place an end-of-file marker on the last cluster. */
status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, media_ptr -> fx_media_fat_last);
/* Check for a bad FAT write status. */
if (status != FX_SUCCESS)
{
/* Return the bad status. */
return(status);
}
#ifdef FX_FAULT_TOLERANT
/* Ensure the new FAT chain is properly written to the media. */
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
#endif
/* Now the new cluster needs to be linked to the sub-directory. */
if (search_dir_ptr)
{
cluster = search_dir_ptr -> fx_dir_entry_cluster;
}
else
{
cluster = media_ptr -> fx_media_root_cluster_32;
}
/* Initialize loop variables. */
last_cluster = 0;
i = 0;
/* Follow the link of FAT entries. */
while (cluster < media_ptr -> fx_media_fat_reserved)
{
/* Read the current cluster entry from the FAT. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &FAT_value);
i++;
/* Check the return value. */
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
/* Determine if the FAT read was invalid. */
if ((cluster < FX_FAT_ENTRY_START) || (cluster == FAT_value) || (i > media_ptr -> fx_media_total_clusters))
{
/* Return the bad status. */
return(FX_FAT_READ_ERROR);
}
/* Save the last valid cluster. */
last_cluster = cluster;
/* Setup for the next cluster. */
cluster = FAT_value;
}
/* Decrease the available clusters in the media. */
media_ptr -> fx_media_available_clusters = media_ptr -> fx_media_available_clusters - clusters_needed;
/* Increase the number of directory entries. */
directory_entries = directory_entries + ((clusters_needed * media_ptr -> fx_media_sectors_per_cluster) * media_ptr -> fx_media_bytes_per_sector) / FX_DIR_ENTRY_SIZE;
/* Determine if we need to reset the free entry start since we changed the
number of directory entries. If the last entry was not free, then we
should definitely reset the free entry start. */
if (!(((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR) FX_DIR_ENTRY_FREE) && (entry_ptr -> fx_dir_entry_short_name[0] == 0)))
{
/* Reset the free entry start to indicate we haven't found a starting free entry yet. */
free_entry_start = directory_entries;
}
/* Update the directory size field. */
directory_ptr -> fx_dir_entry_file_size = directory_entries;
/* Defer the update of the FAT entry and the last cluster of the current
directory entry until after the new cluster is initialized and written out. */
/* Determine if a FAT32 is present. */
if ((media_ptr -> fx_media_32_bit_FAT) && (search_dir_ptr == FX_NULL))
{
/* Change root directory entry count - FAT32 has a variable sized root directory. */
media_ptr -> fx_media_root_directory_entries = directory_entries;
}
/* At this point, link up the last cluster with the new cluster. */
status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, first_new_cluster);
/* Check the return value. */
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
#ifdef FX_FAULT_TOLERANT
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
#endif
}
}
} while (directory_index < directory_entries);
/* Return FX_NO_MORE_SPACE status to the caller. */
return(FX_NO_MORE_SPACE);
}
+235
View File
@@ -0,0 +1,235 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_information_get PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function first attempts to find the specified directory name. */
/* If found, the complete file parameters are placed in all non-NULL */
/* return parameters. If the file name is not found, the appropriate */
/* error code is returned to the caller. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* directory_name Directory name pointer */
/* attributes Pointer to attributes */
/* size Pointer to size */
/* year Pointer to year */
/* month Pointer to month */
/* day Pointer to day */
/* hour Pointer to hour */
/* minute Pointer to minute */
/* second Pointer to second */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_search Search for the file name in */
/* the directory structure */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), verified */
/* memcpy usage, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_information_get(FX_MEDIA *media_ptr, CHAR *directory_name,
UINT *attributes, ULONG *size,
UINT *year, UINT *month, UINT *day,
UINT *hour, UINT *minute, UINT *second)
{
UINT status;
FX_DIR_ENTRY dir_entry;
ULONG open_count;
FX_FILE *search_ptr;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_information_gets++;
#endif
/* Setup pointer to media name buffer. */
dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Clear the short name string. */
dir_entry.fx_dir_entry_short_name[0] = 0;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_INFORMATION_GET, media_ptr, directory_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Search the system for the supplied directory name. */
status = _fx_directory_search(media_ptr, directory_name, &dir_entry, FX_NULL, FX_NULL);
/* Determine if the search was successful. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Check the list of open files for others open for writing. */
open_count = media_ptr -> fx_media_opened_file_count;
search_ptr = media_ptr -> fx_media_opened_file_list;
while (open_count)
{
/* Look at each opened file to see if the same file is opened
for writing. */
if ((search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector == dir_entry.fx_dir_entry_log_sector) &&
(search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset == dir_entry.fx_dir_entry_byte_offset) &&
(search_ptr -> fx_file_open_mode))
{
/* The file has been opened for writing by a previous call. Use the information used by
the writer instead of what is currently on the media. */
_fx_utility_memory_copy((UCHAR *)&search_ptr -> fx_file_dir_entry, (UCHAR *)&dir_entry, sizeof(FX_DIR_ENTRY)); /* Use case of memcpy is verified. */
break;
}
/* Adjust the pointer and decrement the search count. */
search_ptr = search_ptr -> fx_file_opened_next;
open_count--;
}
/* Check to see if attributes are required. */
if (attributes)
{
/* Pickup the attributes. */
*attributes = dir_entry.fx_dir_entry_attributes;
}
/* Check to see if the size is required. */
if (size)
{
/* Pickup the size. */
*size = (ULONG)dir_entry.fx_dir_entry_file_size;
}
/* Check to see if the year is required. */
if (year)
{
/* Pickup the year. */
*year = ((dir_entry.fx_dir_entry_date >> FX_YEAR_SHIFT) & FX_YEAR_MASK) +
FX_BASE_YEAR;
}
/* Check to see if the month is required. */
if (month)
{
/* Pickup the month. */
*month = (dir_entry.fx_dir_entry_date >> FX_MONTH_SHIFT) & FX_MONTH_MASK;
}
/* Check to see if the day is required. */
if (day)
{
/* Pickup the day. */
*day = dir_entry.fx_dir_entry_date & FX_DAY_MASK;
}
/* Check to see if the hour is required. */
if (hour)
{
/* Pickup the hour. */
*hour = (dir_entry.fx_dir_entry_time >> FX_HOUR_SHIFT) & FX_HOUR_MASK;
}
/* Check to see if the minute is required. */
if (minute)
{
/* Pickup the minute. */
*minute = (dir_entry.fx_dir_entry_time >> FX_MINUTE_SHIFT) & FX_MINUTE_MASK;
}
/* Check to see if the second is required. */
if (second)
{
/* Pickup the second. */
*second = (dir_entry.fx_dir_entry_time & FX_SECOND_MASK) * 2;
}
/* Release media protection. */
FX_UNPROTECT
/* Directory information get is complete, return successful status. */
return(FX_SUCCESS);
}
+114
View File
@@ -0,0 +1,114 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_file.h"
#include "fx_utility.h"
#include "fx_directory.h"
#ifndef FX_NO_LOCAL_PATH
FX_LOCAL_PATH_SETUP
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_local_path_clear PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function clears the local default directory of the media so */
/* any path relative operations will start using the media's global */
/* default path again. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_local_path_clear(FX_MEDIA *media_ptr)
{
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_local_path_clears++;
#endif
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
#ifdef FX_NO_LOCAL_PATH
/* Error, return to caller. */
return(FX_NOT_IMPLEMENTED);
#else
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_LOCAL_PATH_CLEAR, media_ptr, 0, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Clear this thread's local path pointer. */
_tx_thread_current_ptr -> tx_thread_filex_ptr = FX_NULL;
/* Local default directory clear is complete, return status. */
return(FX_SUCCESS);
#endif
}
+129
View File
@@ -0,0 +1,129 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_file.h"
#include "fx_utility.h"
#include "fx_directory.h"
#ifndef FX_NO_LOCAL_PATH
FX_LOCAL_PATH_SETUP
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_local_path_get PORTABLE C */
/* 6.1.5 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function returns a pointer to the local default directory */
/* for this thread. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* return_path_name Return local path name */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 03-02-2021 William E. Lamie Modified comment(s), */
/* resulting in version 6.1.5 */
/* */
/**************************************************************************/
UINT _fx_directory_local_path_get(FX_MEDIA *media_ptr, CHAR **return_path_name)
{
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_local_path_gets++;
#endif
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
#ifdef FX_NO_LOCAL_PATH
FX_PARAMETER_NOT_USED(return_path_name);
/* Error, return to caller. */
return(FX_NOT_IMPLEMENTED);
#else
/* Determine if there is a local path. */
if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
{
/* Return a pointer to the current local directory path string. */
*return_path_name = ((FX_LOCAL_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_string;
}
else
{
/* Just set the return value to FX_NULL to indicate there is no
local path setup. */
*return_path_name = FX_NULL;
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_LOCAL_PATH_GET, media_ptr, return_path_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Local default directory has been returned, return status. */
return(FX_SUCCESS);
#endif
}
@@ -0,0 +1,123 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_file.h"
#include "fx_utility.h"
#include "fx_directory.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_local_path_get_copy PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function copies the local default directory for this thread */
/* into the specified buffer. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* return_path_name_buffer Destination buffer for name */
/* return_path_name_buffer_size Size of buffer pointed to by */
/* return_path_name_buffer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), verified */
/* memcpy usage, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_local_path_get_copy(FX_MEDIA *media_ptr, CHAR *return_path_name_buffer, UINT return_path_name_buffer_size)
{
UINT status;
CHAR *return_path_name;
UINT path_name_length_with_null_terminator;
/* Get the pointer to the path. */
status = _fx_directory_local_path_get(media_ptr, &return_path_name);
if (status == FX_SUCCESS)
{
/* Was a path set? */
if (return_path_name != FX_NULL)
{
/* Get the length of the path. */
path_name_length_with_null_terminator = _fx_utility_string_length_get(return_path_name, FX_MAXIMUM_PATH) + 1;
/* Can it fit in the user's buffer? */
if (path_name_length_with_null_terminator <= return_path_name_buffer_size)
{
/* Copy the path name into the user's buffer. */
_fx_utility_memory_copy((UCHAR *) return_path_name, (UCHAR *) return_path_name_buffer, path_name_length_with_null_terminator); /* Use case of memcpy is verified. */
}
else
{
/* Buffer is too small. Return error. */
return(FX_BUFFER_ERROR);
}
}
else
{
/* Set zero-length string. */
return_path_name_buffer[0] = '\0';
}
}
/* Return status. */
return(status);
}
@@ -0,0 +1,117 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_file.h"
#include "fx_utility.h"
#include "fx_directory.h"
#ifndef FX_NO_LOCAL_PATH
FX_LOCAL_PATH_SETUP
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_local_path_restore PORTABLE C */
/* 6.1.5 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function restores the local default directory of the media to */
/* the previous path specified by the caller. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* local_path_ptr Local path control block ptr */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 03-02-2021 William E. Lamie Modified comment(s), */
/* resulting in version 6.1.5 */
/* */
/**************************************************************************/
UINT _fx_directory_local_path_restore(FX_MEDIA *media_ptr, FX_LOCAL_PATH *local_path_ptr)
{
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_local_path_restores++;
#endif
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
#ifdef FX_NO_LOCAL_PATH
FX_PARAMETER_NOT_USED(local_path_ptr);
/* Error, return to caller. */
return(FX_NOT_IMPLEMENTED);
#else
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_LOCAL_PATH_RESTORE, media_ptr, local_path_ptr, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Setup thread control block to use this local path pointer. */
_tx_thread_current_ptr -> tx_thread_filex_ptr = (VOID *)local_path_ptr;
/* Default directory restore is complete, return status. */
return(FX_SUCCESS);
#endif
}
+451
View File
@@ -0,0 +1,451 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_file.h"
#include "fx_utility.h"
#include "fx_directory.h"
#ifndef FX_NO_LOCAL_PATH
FX_LOCAL_PATH_SETUP
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_local_path_set PORTABLE C */
/* 6.1.5 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the local default directory of the media to the */
/* path specified by the caller. If this path is not found, an error */
/* code is returned. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* local_path Local path control block ptr */
/* new_path_name New path to set current local */
/* working directory to */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_search Search for the directory name */
/* in the directory structure */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 03-02-2021 William E. Lamie Modified comment(s), */
/* resulting in version 6.1.5 */
/* */
/**************************************************************************/
UINT _fx_directory_local_path_set(FX_MEDIA *media_ptr, FX_LOCAL_PATH *local_path_ptr, CHAR *new_path_name)
{
#ifndef FX_NO_LOCAL_PATH
UINT status;
CHAR *path_string_ptr;
UINT path_string_capacity;
FX_PATH *path_ptr;
UINT i, j;
#endif
FX_DIR_ENTRY dir_entry;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_local_path_sets++;
#endif
/* Setup pointer to a name buffer. */
dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Setup the local path name buffer pointer. */
local_path_ptr -> fx_path_directory.fx_dir_entry_name = local_path_ptr -> fx_path_name_buffer;
/* Clear the short name string. */
dir_entry.fx_dir_entry_short_name[0] = (CHAR)0;
/* Clear the long name string. */
dir_entry.fx_dir_entry_name[0] = (CHAR)0;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
#ifdef FX_NO_LOCAL_PATH
FX_PARAMETER_NOT_USED(new_path_name);
/* Error, return to caller. */
return(FX_NOT_IMPLEMENTED);
#else
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_LOCAL_PATH_SET, media_ptr, local_path_ptr, new_path_name, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Look for a root directory selection. */
if ((!new_path_name) || (((new_path_name[0] == '\\') || (new_path_name[0] == '/')) && (new_path_name[1] == (CHAR)0)))
{
/* Set the default local directory to the root. */
local_path_ptr -> fx_path_directory.fx_dir_entry_name[0] = (CHAR)0;
local_path_ptr -> fx_path_string[0] = (CHAR)0;
local_path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] = (CHAR)0;
/* Setup thread control block to use this local path pointer. */
_tx_thread_current_ptr -> tx_thread_filex_ptr = (VOID *)local_path_ptr;
}
else
{
/* Search the system for the supplied path and directory name. */
status = _fx_directory_search(media_ptr, new_path_name, &dir_entry, FX_NULL, FX_NULL);
/* Determine if the search failed or if the entry found is not a
directory. */
if ((status != FX_SUCCESS) || (!(dir_entry.fx_dir_entry_attributes & FX_DIRECTORY)))
{
/* Release media protection. */
FX_UNPROTECT
/* Invalid Path - Return the error code. */
return(FX_INVALID_PATH);
}
/* Now update the current path string. */
/* Setup the path string pointer to the start of the current path. */
path_string_ptr = &(local_path_ptr -> fx_path_string[0]);
/* Setup the path string's capacity. */
path_string_capacity = FX_MAXIMUM_PATH - 1;
/* Determine if the new path is relative from the current path. */
if ((new_path_name[0] != '\\') && (new_path_name[0] != '/'))
{
/* Yes, a relative path was found. */
/* Setup the default path pointer to the local path. */
path_ptr = local_path_ptr;
/* Determine if the local path is different than the current local path. */
if (local_path_ptr != (FX_LOCAL_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr)
{
/* Yes, there is a difference. */
/* Should we copy from the default media path or from the previous default
path. */
if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
{
/* There is a local path so copy the relative path info from it. */
i = 0;
do
{
/* Copy from previous local to new local path. */
local_path_ptr -> fx_path_string[i] =
((FX_LOCAL_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_string[i];
/* Determine if we are done. */
if (local_path_ptr -> fx_path_string[i] == 0)
{
/* Are we not at the end of the string? */
if (i < (FX_MAXIMUM_PATH - 1))
{
/* Yes, break the loop. */
break;
}
}
/* Move to the next character. */
i++;
} while (i < FX_MAXIMUM_PATH);
}
else
{
/* No local path, so copy the relative path information from the media
default. */
i = 0;
do
{
/* Copy from the media default to new local path. */
local_path_ptr -> fx_path_string[i] =
media_ptr -> fx_media_default_path.fx_path_string[i];
/* Determine if we are done. */
if (local_path_ptr -> fx_path_string[i] == 0)
{
/* Are we not at the end of the string? */
if (i < (FX_MAXIMUM_PATH - 1))
{
/* Yes, break the loop. */
break;
}
}
/* Move to the next character. */
i++;
} while (i < FX_MAXIMUM_PATH);
}
}
/* First, check the current path for string overflow. If this is set,
don't attempt to update the current path with relative information.
The path won't be valid again until a complete path is given. */
if (path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] == '*')
{
/* Yes, don't update the string, just finish the path set processing. */
/* Determine if we are at the root directory. */
if (!dir_entry.fx_dir_entry_cluster)
{
/* Set the current directory back to the root directory. */
dir_entry.fx_dir_entry_name[0] = (CHAR)0;
/* Clear the current path string. */
path_ptr -> fx_path_string[0] = (CHAR)0;
/* Clear the overflow flag in the current path string... just in
case! */
path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] = (CHAR)0;
}
/* Copy the new directory entry into the media control block. */
path_ptr -> fx_path_directory = dir_entry;
/* Reset the local path name buffer pointer, since it was clobbered earlier. */
local_path_ptr -> fx_path_directory.fx_dir_entry_name = local_path_ptr -> fx_path_name_buffer;
/* Copy the directory name entry to the local path name area. */
for (j = 0; j < FX_MAX_LONG_NAME_LEN; j++)
{
/* Copy the name buffer. */
local_path_ptr -> fx_path_directory.fx_dir_entry_name[j] = dir_entry.fx_dir_entry_name[j];
}
/* Setup thread control block to use this local path pointer. */
_tx_thread_current_ptr -> tx_thread_filex_ptr = (VOID *)local_path_ptr;
/* Release media protection. */
FX_UNPROTECT
/* Default directory set is complete, return status. */
return(FX_SUCCESS);
}
/* Move the current path starting pointer to the end of the current
path string. */
while ((path_string_capacity) && (*path_string_ptr != FX_NULL))
{
path_string_ptr++;
path_string_capacity--;
}
/* If room, place the \ character in the path string. */
if (path_string_capacity)
{
/* There is room, place the directory marker in the string. */
*path_string_ptr++ = '\\';
path_string_capacity--;
}
}
else
{
/* Setup the default path pointer. */
/* Setup the default path pointer to the local path. */
path_ptr = local_path_ptr;
/* Complete path name given. Check to see if we need to clear an
overflow character from a previous current path string update. */
if (path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] == '*')
{
path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] = (CHAR)0;
}
}
/* Copy what we can into the current path. */
while (*new_path_name)
{
/* Determine if there is a ".." character sequence that specifies the
previous path. */
if ((*new_path_name == '.') && (*(new_path_name + 1) == '.'))
{
/* Yes, a backward path is found. The current path pointer
must be moved back to just after the previous \ character. */
/* Skip the current \0 that is at the end of the current path. */
path_string_capacity = path_string_capacity + 2;
path_string_ptr = path_string_ptr - 2;
while (path_string_capacity <= (FX_MAXIMUM_PATH - 1))
{
/* Move the current path pointer backwards until
a \ character is found. */
if ((*path_string_ptr == '\\') || (*path_string_ptr == '/'))
{
/* Yes, we have successfully backed up one directory. */
break;
}
/* Backup another character. */
path_string_capacity++;
path_string_ptr--;
}
/* Adjust the new directory pointer past the .. characters */
new_path_name = new_path_name + 2;
}
else
{
/* Normal characters that need to be copied into the current path. */
if (path_string_capacity)
{
/* Copy character from the new path into the current path string. */
*path_string_ptr++ = *new_path_name++;
path_string_capacity--;
}
else
{
/* No more room in the current path string! */
break;
}
}
}
/* Determine if there is still room in the current path string. */
if (path_string_capacity)
{
/* Yes, there is still room, place a NULL character at the
end of the path. */
*path_string_ptr = (CHAR)FX_NULL;
}
else
{
/* No more room. Determine if the entire path was successfully
copied into the current path. */
if (*new_path_name)
{
/* No, we couldn't fit the entire path. Place a "*" character
at the end to indicate that we had overflow. Note that
the path is kept just the the directory default get call, so
the new default path is valid. */
path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] = '*';
}
}
/* Determine if we are at the root directory. */
if (!dir_entry.fx_dir_entry_cluster)
{
/* Set the current directory back to the root directory. */
dir_entry.fx_dir_entry_name[0] = (CHAR)0;
local_path_ptr -> fx_path_name_buffer[0] = (CHAR)0;
}
/* Copy the new directory entry into the media control block. */
path_ptr -> fx_path_directory = dir_entry;
/* Reset the local path name buffer pointer, since it was clobbered earlier. */
local_path_ptr -> fx_path_directory.fx_dir_entry_name = local_path_ptr -> fx_path_name_buffer;
/* Copy the directory name entry to the local path name area. */
for (j = 0; j < FX_MAX_LONG_NAME_LEN; j++)
{
/* Copy the name buffer. */
local_path_ptr -> fx_path_directory.fx_dir_entry_name[j] = dir_entry.fx_dir_entry_name[j];
}
/* Setup thread control block to use this local path pointer. */
_tx_thread_current_ptr -> tx_thread_filex_ptr = (VOID *)local_path_ptr;
}
/* Release media protection. */
FX_UNPROTECT
/* Default directory set is complete, return status. */
return(FX_SUCCESS);
#endif
}
+85
View File
@@ -0,0 +1,85 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_directory.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_long_name_get PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function gets the long file name via the supplied short file */
/* name. If there is no long file name, the short file name will be */
/* returned. */
/* */
/* Note, this API is deprecated as fx_directory_long_name_get_extended */
/* should be used. The maximum written size to long_file_name could be */
/* FX_MAX_LONG_NAME_LEN. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* short_file_name Pointer to short (8.3) name */
/* long_file_name Pointer to long (max 255) name*/
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_long_name_get_extended Actual long name get service */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_long_name_get(FX_MEDIA *media_ptr, CHAR *short_file_name, CHAR *long_file_name)
{
/* Call the extended version with maximum long name length. */
return(_fx_directory_long_name_get_extended(media_ptr, short_file_name, long_file_name, FX_MAX_LONG_NAME_LEN));
}
@@ -0,0 +1,139 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_directory.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_long_name_get_extended PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function gets the long file name via the supplied short file */
/* name. If there is no long file name, the short file name will be */
/* returned. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* short_file_name Pointer to short (8.3) name */
/* long_file_name Pointer to long (max 255) name*/
/* long_file_name_buffer_length Buffer length for long name */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_search Search for the file name in */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_long_name_get_extended(FX_MEDIA *media_ptr, CHAR *short_file_name, CHAR *long_file_name, UINT long_file_name_buffer_length)
{
UINT status;
UINT i;
FX_DIR_ENTRY dir_entry;
/* Setup pointer to media name buffer. */
dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Clear the short name string. */
dir_entry.fx_dir_entry_short_name[0] = 0;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_LONG_NAME_GET, media_ptr, short_file_name, long_file_name, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Search the system for the supplied short directory name. */
status = _fx_directory_search(media_ptr, short_file_name, &dir_entry, FX_NULL, FX_NULL);
/* Determine if the search was successful. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Copy the long name portion into the destination string. */
i = 0;
while ((i < (FX_MAX_LONG_NAME_LEN - 1)) && (dir_entry.fx_dir_entry_name[i]) && (i < (long_file_name_buffer_length - 1)))
{
/* Copy a character of the long name into the destination name. */
long_file_name[i] = dir_entry.fx_dir_entry_name[i];
/* Move to next character. */
i++;
}
/* Ensure the long file name is NULL terminated. */
long_file_name[i] = FX_NULL;
/* Check if the buffer is too short for the name. */
if ((i == (long_file_name_buffer_length - 1)) && (dir_entry.fx_dir_entry_name[i]))
{
/* Buffer too short, return error. */
status = FX_BUFFER_ERROR;
}
/* Release media protection. */
FX_UNPROTECT
/* Return the completion status. */
return(status);
}
+161
View File
@@ -0,0 +1,161 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_name_extract PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function extracts the file name from the supplied input */
/* string. If there is nothing left after the extracted name, a NULL */
/* is returned to the caller. Otherwise, if something is left, a */
/* pointer to it is returned. */
/* */
/* INPUT */
/* */
/* source_ptr Source string pointer */
/* dest_ptr Destination string pointer */
/* */
/* OUTPUT */
/* */
/* Pointer to Next Name (if multiple directories) */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* FileX System Functions */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
CHAR *_fx_directory_name_extract(CHAR *source_ptr, CHAR *dest_ptr)
{
UINT i;
/* Set the destination string to NULL. */
dest_ptr[0] = 0;
/* Is a backslash present? */
if ((*source_ptr == '\\') || (*source_ptr == '/'))
{
/* Advance the string pointer. */
source_ptr++;
}
/* Loop to remove any leading spaces. */
while (*source_ptr == ' ')
{
/* Position past leading space. */
source_ptr++;
}
/* Loop to extract the name. */
i = 0;
while (*source_ptr)
{
/* If another backslash is present, break the loop. */
if ((*source_ptr == '\\') || (*source_ptr == '/'))
{
break;
}
/* Long name can be at most 255 characters, but are further limited by the
FX_MAX_LONG_NAME_LEN define. */
if (i == FX_MAX_LONG_NAME_LEN - 1)
{
break;
}
/* Store the character. */
dest_ptr[i] = *source_ptr++;
/* Increment the character counter. */
i++;
}
/* NULL-terminate the string. */
dest_ptr[i] = 0;
/* Determine if we can backup to the previous character. */
if (i)
{
/* Yes, we can move backwards. */
i--;
}
/* Get rid of trailing blanks in the destination string. */
while (dest_ptr[i] == ' ')
{
/* Set this entry to NULL. */
dest_ptr[i] = 0;
/* Backup to the next character. Since leading spaces have been removed,
we know that the index is always greater than 1. */
i--;
}
/* Determine if the source string is now at the end. */
if (*source_ptr == 0)
{
/* Yes, return a NULL pointer. */
source_ptr = FX_NULL;
}
/* Return the last pointer position in the source. */
return(source_ptr);
}
+143
View File
@@ -0,0 +1,143 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_name_test PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function first attempts to find the specified directory name. */
/* If found, the attributes are checked to see if the entry is a */
/* directory. If not, the appropriate error code is returned to the */
/* caller. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* directory_name Directory name pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_search Search for the file name in */
/* the directory structure */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_name_test(FX_MEDIA *media_ptr, CHAR *directory_name)
{
UINT status;
FX_DIR_ENTRY dir_entry;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_name_tests++;
#endif
/* Setup pointer to media name buffer. */
dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Clear the short name string. */
dir_entry.fx_dir_entry_short_name[0] = 0;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_NAME_TEST, media_ptr, directory_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Search the system for the supplied directory name. */
status = _fx_directory_search(media_ptr, directory_name, &dir_entry, FX_NULL, FX_NULL);
/* Determine if the search was successful. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Check to see if the entry is a directory. */
if (!(dir_entry.fx_dir_entry_attributes & (UCHAR)FX_DIRECTORY))
{
/* Release media protection. */
FX_UNPROTECT
/* Return the not a directory error code. */
return(FX_NOT_DIRECTORY);
}
/* Release media protection. */
FX_UNPROTECT
/* Directory name test is complete, return successful status. */
return(FX_SUCCESS);
}
+437
View File
@@ -0,0 +1,437 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_utility.h"
#ifndef FX_NO_LOCAL_PATH
FX_LOCAL_PATH_SETUP
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_next_entry_find PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function returns the name of the next entry in the current */
/* working directory. The function that returns the first name in the */
/* current directory must be called prior to this function. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* directory_name Destination for directory */
/* name */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_read Read entries from root dir */
/* _fx_utility_FAT_entry_read Read FAT entries to calculate */
/* the sub-directory size */
/* */
/* CALLED BY */
/* */
/* Application Code and */
/* FileX System Functions */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_next_entry_find(FX_MEDIA *media_ptr, CHAR *directory_name)
{
ULONG i;
UINT status;
UINT temp_status;
ULONG cluster, next_cluster = 0;
ULONG64 directory_size;
FX_DIR_ENTRY entry;
FX_DIR_ENTRY *search_dir_ptr;
FX_PATH *path_ptr;
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
UINT index;
CHAR *path_string_ptr = FX_NULL;
#endif
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_next_entry_finds++;
#endif
/* Setup pointer to media name buffer. */
entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Clear the short name string. */
entry.fx_dir_entry_short_name[0] = 0;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_NEXT_ENTRY_FIND, media_ptr, directory_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* First check for a local path pointer stored in the thread control block. This
is only available in ThreadX Version 4 and above. */
#ifndef FX_NO_LOCAL_PATH
if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
{
/* Setup the default path pointer. */
path_ptr = (FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr;
/* Determine if we are at the root directory. */
if (path_ptr -> fx_path_directory.fx_dir_entry_name[0])
{
/* No, we are not at the root directory. */
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
/* Setup pointer to the path. */
path_string_ptr = ((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_string;
#endif
/* Set the internal pointer to the search directory as well. */
search_dir_ptr = &(path_ptr -> fx_path_directory);
}
else
{
/* The current default directory is the root so just set the
search directory pointer to NULL. */
search_dir_ptr = FX_NULL;
}
}
else
#endif
/* Set the initial search directory to the current working
directory - if there is one. */
if (media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name[0])
{
/* Setup the path pointer to the global media path. */
path_ptr = &media_ptr -> fx_media_default_path;
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
/* Setup pointer to the path. */
path_string_ptr = media_ptr -> fx_media_default_path.fx_path_string;
#endif
/* Set the internal pointer to the search directory as well. */
search_dir_ptr = &(path_ptr -> fx_path_directory);
}
else
{
/* Setup the path pointer to the global media path. */
path_ptr = &media_ptr -> fx_media_default_path;
/* The current default directory is the root so just set the
search directory pointer to NULL. */
search_dir_ptr = FX_NULL;
}
/* Calculate the directory size. */
if (search_dir_ptr)
{
/* Determine the directory size. */
if (path_ptr -> fx_path_current_entry != 0)
{
/* Pickup the previously saved directory size. */
directory_size = search_dir_ptr -> fx_dir_entry_file_size;
}
else
{
/* This should only be done on the first time into next directory find. */
/* Ensure that the search directory's last search cluster is cleared. */
search_dir_ptr -> fx_dir_entry_last_search_cluster = 0;
/* Calculate the directory size by counting the allocated
clusters for it. */
i = 0;
cluster = search_dir_ptr -> fx_dir_entry_cluster;
while (cluster < media_ptr -> fx_media_fat_reserved)
{
/* Increment the cluster count. */
i++;
/* Read the next FAT entry. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
/* Check the return status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
{
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(FX_FAT_READ_ERROR);
}
cluster = next_cluster;
}
/* Now we can calculate the directory size. */
directory_size = (((ULONG64)media_ptr -> fx_media_bytes_per_sector) *
((ULONG64)media_ptr -> fx_media_sectors_per_cluster) * i) /
(ULONG64)FX_DIR_ENTRY_SIZE;
/* Save how many entries there are in the directory. */
search_dir_ptr -> fx_dir_entry_file_size = directory_size;
}
}
else
{
/* Directory size is the number of entries in the root directory. */
directory_size = (ULONG)media_ptr -> fx_media_root_directory_entries;
}
/* Preset status with an error return. */
status = FX_NO_MORE_ENTRIES;
/* Determine if the current entry is inside of the directory's range. */
while (path_ptr -> fx_path_current_entry < directory_size)
{
/* Read an entry from the directory. */
temp_status = _fx_directory_entry_read(media_ptr, search_dir_ptr,
&(path_ptr -> fx_path_current_entry), &entry);
/* Check for error status. */
if (temp_status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return error status. */
return(temp_status);
}
/* Check to see if the entry has something in it. */
if (((UCHAR)entry.fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry.fx_dir_entry_short_name[0] == 0))
{
/* Current entry is free, skip to next entry and continue the loop. */
path_ptr -> fx_path_current_entry++;
continue;
}
else if ((UCHAR)entry.fx_dir_entry_name[0] != (UCHAR)FX_DIR_ENTRY_DONE)
{
/* A valid directory entry is present. */
/* Copy the name into the destination. */
for (i = 0; entry.fx_dir_entry_name[i]; i++)
{
*directory_name = entry.fx_dir_entry_name[i];
directory_name++;
}
/* Place a NULL at the end of the directory name. */
*directory_name = (CHAR)0;
/* Increment the current entry for the media. */
path_ptr -> fx_path_current_entry++;
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
{
UINT v, j;
/* If a subsequent search for the same name is done, it will find it immediately. */
/* Set the index of the saved name string. */
v = 0;
/* First, build the full path and name. */
if (path_string_ptr)
{
/* Copy the path into the destination. */
while ((v < (FX_MAX_LAST_NAME_LEN - 1)) && (path_string_ptr[v]))
{
/* Copy one character. */
media_ptr -> fx_media_last_found_name[v] = path_string_ptr[v];
/* Move to next character. */
v++;
}
}
/* We know there is room at this point, place a directory separator character. */
media_ptr -> fx_media_last_found_name[v++] = '/';
/* Now append the name to the path. */
j = 0;
while ((v < FX_MAX_LAST_NAME_LEN) && (entry.fx_dir_entry_name[j]))
{
/* Copy one character. */
media_ptr -> fx_media_last_found_name[v] = entry.fx_dir_entry_name[j];
/* Move to next character. */
v++;
j++;
}
/* Null terminate the last name string. */
if (v < FX_MAX_LAST_NAME_LEN)
{
/* Null terminate. */
media_ptr -> fx_media_last_found_name[v] = FX_NULL;
}
else
{
/* The string is too big, NULL the string so it won't be used in searching. */
media_ptr -> fx_media_last_found_name[0] = FX_NULL;
}
/* Determine if there is a search pointer. */
if (search_dir_ptr)
{
/* Yes, there is a search directory pointer so save it! */
media_ptr -> fx_media_last_found_directory = *search_dir_ptr;
/* Indicate the search directory is valid. */
media_ptr -> fx_media_last_found_directory_valid = FX_TRUE;
}
else
{
/* Indicate the search directory is not valid. */
media_ptr -> fx_media_last_found_directory_valid = FX_FALSE;
}
/* Copy the directory entry. */
media_ptr -> fx_media_last_found_entry = entry;
/* Setup the last found directory entry to point at the last found internal file name. */
media_ptr -> fx_media_last_found_entry.fx_dir_entry_name = media_ptr -> fx_media_last_found_file_name;
/* Copy the actual directory name into the cached directory name. */
for (index = 0; index < FX_MAX_LONG_NAME_LEN; index++)
{
/* Copy character into the cached directory name. */
media_ptr -> fx_media_last_found_file_name[index] = entry.fx_dir_entry_name[index];
/* See if we have copied the NULL termination character. */
if (entry.fx_dir_entry_name[index] == (CHAR)FX_NULL)
{
/* Check to see if we use the break to get out of the loop. */
if (v < (FX_MAX_LONG_NAME_LEN - 1))
{
/* Yes, not at the end of the string, break. */
break;
}
}
}
}
#endif
/* Set return status to success. */
status = FX_SUCCESS;
/* Get out of the loop. */
break;
}
else
{
/* Set the error code. */
status = FX_NO_MORE_ENTRIES;
/* Get out of the loop. */
break;
}
}
/* Release media protection. */
FX_UNPROTECT
/* Return status to the caller. */
return(status);
}
@@ -0,0 +1,515 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_utility.h"
#ifndef FX_NO_LOCAL_PATH
FX_LOCAL_PATH_SETUP
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_next_full_entry_find PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function returns the name of the next entry in the current */
/* working directory and various information about the name. The */
/* function that returns the first name in the current directory must */
/* be called prior to this function. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* directory_name Destination for directory */
/* name */
/* attributes Destination for attributes */
/* size Destination for size */
/* year Destination for year */
/* month Destination for month */
/* day Destination for day */
/* hour Destination for hour */
/* minute Destination for minute */
/* second Destination for second */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_read Read entries from root dir */
/* _fx_utility_FAT_entry_read Read FAT entries */
/* */
/* CALLED BY */
/* */
/* Application Code and */
/* FileX System Functions */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_next_full_entry_find(FX_MEDIA *media_ptr,
CHAR *directory_name, UINT *attributes, ULONG *size,
UINT *year, UINT *month, UINT *day, UINT *hour, UINT *minute, UINT *second)
{
ULONG i;
UINT status;
UINT temp_status;
ULONG cluster, next_cluster = 0;
ULONG64 directory_size;
FX_DIR_ENTRY entry;
FX_DIR_ENTRY *search_dir_ptr;
FX_PATH *path_ptr;
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
UINT index;
CHAR *path_string_ptr = FX_NULL;
#endif
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_next_full_entry_finds++;
#endif
/* Setup pointer to media name buffer. */
entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Clear the short name string. */
entry.fx_dir_entry_short_name[0] = 0;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_NEXT_FULL_ENTRY_FIND, media_ptr, directory_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* First check for a local path pointer stored in the thread control block. This
is only available in ThreadX Version 4 and above. */
#ifndef FX_NO_LOCAL_PATH
if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
{
/* Setup the default path pointer. */
path_ptr = (FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr;
/* Determine if we are at the root directory. */
if (path_ptr -> fx_path_directory.fx_dir_entry_name[0])
{
/* No, we are not at the root directory. */
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
/* Setup pointer to the path. */
path_string_ptr = ((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_string;
#endif
/* Set the internal pointer to the search directory as well. */
search_dir_ptr = &path_ptr -> fx_path_directory;
}
else
{
/* The current default directory is the root so just set the
search directory pointer to NULL. */
search_dir_ptr = FX_NULL;
}
}
else
#endif
/* Set the initial search directory to the current working
directory - if there is one. */
if (media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name[0])
{
/* Setup the path pointer to the global media path. */
path_ptr = &media_ptr -> fx_media_default_path;
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
/* Setup pointer to the path. */
path_string_ptr = media_ptr -> fx_media_default_path.fx_path_string;
#endif
/* Set the internal pointer to the search directory as well. */
search_dir_ptr = &path_ptr -> fx_path_directory;
}
else
{
/* Setup the path pointer to the global media path. */
path_ptr = &media_ptr -> fx_media_default_path;
/* The current default directory is the root so just set the
search directory pointer to NULL. */
search_dir_ptr = FX_NULL;
}
/* Calculate the directory size. */
if (search_dir_ptr)
{
/* Determine the directory size. */
if (path_ptr -> fx_path_current_entry != 0)
{
/* Pickup the previously saved directory size. */
directory_size = search_dir_ptr -> fx_dir_entry_file_size;
}
else
{
/* This should only be done on the first time into next directory find. */
/* Ensure that the search directory's last search cluster is cleared. */
search_dir_ptr -> fx_dir_entry_last_search_cluster = 0;
/* Calculate the directory size by counting the allocated
clusters for it. */
i = 0;
cluster = search_dir_ptr -> fx_dir_entry_cluster;
while (cluster < media_ptr -> fx_media_fat_reserved)
{
/* Increment the cluster count. */
i++;
/* Read the next FAT entry. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
/* Check the return status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
{
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(FX_FAT_READ_ERROR);
}
cluster = next_cluster;
}
/* Now we can calculate the directory size. */
directory_size = (((ULONG64) media_ptr -> fx_media_bytes_per_sector) *
((ULONG64) media_ptr -> fx_media_sectors_per_cluster) * i)
/ (ULONG64) FX_DIR_ENTRY_SIZE;
/* Save how many entries there are in the directory. */
search_dir_ptr -> fx_dir_entry_file_size = directory_size;
}
}
else
{
/* Directory size is the number of entries in the root directory. */
directory_size = (ULONG)media_ptr -> fx_media_root_directory_entries;
}
/* Preset status with an error return. */
status = FX_NO_MORE_ENTRIES;
/* Determine if the current entry is inside of the directory's range. */
while (path_ptr -> fx_path_current_entry < directory_size)
{
/* Read an entry from the directory. */
temp_status = _fx_directory_entry_read(media_ptr, search_dir_ptr,
&(path_ptr -> fx_path_current_entry), &entry);
/* Check for error status. */
if (temp_status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return error status. */
return(temp_status);
}
/* Check to see if the entry has something in it. */
if (((UCHAR)entry.fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry.fx_dir_entry_short_name[0] == 0))
{
/* Current entry is free, skip to next entry and continue the loop. */
path_ptr -> fx_path_current_entry++;
continue;
}
/* Determine if a valid directory entry is present. */
else if ((UCHAR)entry.fx_dir_entry_name[0] != (UCHAR)FX_DIR_ENTRY_DONE)
{
/* A valid directory entry is present. */
/* Copy the name into the destination. */
for (i = 0; entry.fx_dir_entry_name[i]; i++)
{
*directory_name = entry.fx_dir_entry_name[i];
directory_name++;
}
/* Place a NULL at the end of the directory name. */
*directory_name = (CHAR)0;
/* Determine if the entry's attributes are required. */
if (attributes)
{
/* Pickup the entry's attributes. */
*attributes = entry.fx_dir_entry_attributes;
}
/* Determine if the entry's size is required. */
if (size)
{
/* Pickup the entry's size. */
*size = (ULONG)entry.fx_dir_entry_file_size;
}
/* Determine if the entry's year is required. */
if (year)
{
/* Pickup the entry's year. */
*year = ((entry.fx_dir_entry_date >> FX_YEAR_SHIFT) & FX_YEAR_MASK) + FX_BASE_YEAR;
}
/* Determine if the entry's month is required. */
if (month)
{
/* Pickup the entry's month. */
*month = (entry.fx_dir_entry_date >> FX_MONTH_SHIFT) & FX_MONTH_MASK;
}
/* Determine if the entry's day is required. */
if (day)
{
/* Pickup the entry's day. */
*day = entry.fx_dir_entry_date & FX_DAY_MASK;
}
/* Determine if the entry's hour is required. */
if (hour)
{
/* Pickup the entry's hour. */
*hour = (entry.fx_dir_entry_time >> FX_HOUR_SHIFT) & FX_HOUR_MASK;
}
/* Determine if the entry's minute is required. */
if (minute)
{
/* Pickup the entry's minute. */
*minute = (entry.fx_dir_entry_time >> FX_MINUTE_SHIFT) & FX_MINUTE_MASK;
}
/* Determine if the entry's second is required. */
if (second)
{
/* Pickup the entry's second. */
*second = (entry.fx_dir_entry_time & FX_SECOND_MASK) * 2;
}
/* Increment the current entry for the media. */
path_ptr -> fx_path_current_entry++;
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
{
UINT v, j;
/* If a subsequent search for the same name is done, it will find it immediately. */
/* Set the index of the saved name string. */
v = 0;
/* First, build the full path and name. */
if (path_string_ptr)
{
/* Copy the path into the destination. */
while ((v < (FX_MAX_LAST_NAME_LEN - 1)) && (path_string_ptr[v]))
{
/* Copy one character. */
media_ptr -> fx_media_last_found_name[v] = path_string_ptr[v];
/* Move to next character. */
v++;
}
}
/* We know there is room at this point, place a directory separator character. */
media_ptr -> fx_media_last_found_name[v++] = '/';
/* Now append the name to the path. */
j = 0;
while ((v < FX_MAX_LAST_NAME_LEN) && (entry.fx_dir_entry_name[j]))
{
/* Copy one character. */
media_ptr -> fx_media_last_found_name[v] = entry.fx_dir_entry_name[j];
/* Move to next character. */
v++;
j++;
}
/* Null terminate the last name string. */
if (v < FX_MAX_LAST_NAME_LEN)
{
/* Null terminate. */
media_ptr -> fx_media_last_found_name[v] = FX_NULL;
}
else
{
/* The string is too big, NULL the string so it won't be used in searching. */
media_ptr -> fx_media_last_found_name[0] = FX_NULL;
}
/* Determine if there is a search pointer. */
if (search_dir_ptr)
{
/* Yes, there is a search directory pointer so save it! */
media_ptr -> fx_media_last_found_directory = *search_dir_ptr;
/* Indicate the search directory is valid. */
media_ptr -> fx_media_last_found_directory_valid = FX_TRUE;
}
else
{
/* Indicate the search directory is not valid. */
media_ptr -> fx_media_last_found_directory_valid = FX_FALSE;
}
/* Copy the directory entry. */
media_ptr -> fx_media_last_found_entry = entry;
/* Setup the last found directory entry to point at the last found internal file name. */
media_ptr -> fx_media_last_found_entry.fx_dir_entry_name = media_ptr -> fx_media_last_found_file_name;
/* Copy the actual directory name into the cached directory name. */
for (index = 0; index < FX_MAX_LONG_NAME_LEN; index++)
{
/* Copy character into the cached directory name. */
media_ptr -> fx_media_last_found_file_name[index] = entry.fx_dir_entry_name[index];
/* See if we have copied the NULL termination character. */
if (entry.fx_dir_entry_name[index] == (CHAR)FX_NULL)
{
/* Check to see if we use the break to get out of the loop. */
if (v < (FX_MAX_LONG_NAME_LEN - 1))
{
/* Yes, not at the end of the string, break. */
break;
}
}
}
}
#endif
/* Set return status to success. */
status = FX_SUCCESS;
/* Get out of the loop. */
break;
}
else
{
/* Set the error code. */
status = FX_NO_MORE_ENTRIES;
/* Get out of the loop. */
break;
}
}
/* Release media protection. */
FX_UNPROTECT
/* Return status to the caller. */
return(status);
}
+486
View File
@@ -0,0 +1,486 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
#include "fx_fault_tolerant.h"
#endif /* FX_ENABLE_FAULT_TOLERANT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_rename PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function first attempts to find the specified directory. */
/* If found, the rename request is valid and the directory will be */
/* changed to the new name. Otherwise, if the directory is not found, */
/* the appropriate error code is returned to the caller. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* old_directory_name Old file directory pointer */
/* new_directory_name New file directory pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_write Write the new directory entry */
/* _fx_directory_free_search Search for a free directory */
/* entry */
/* _fx_directory_name_extract Extract directory name */
/* _fx_directory_search Search for the file name in */
/* the directory structure */
/* _fx_fault_tolerant_transaction_start Start fault tolerant */
/* transaction */
/* _fx_fault_tolerant_transaction_end End fault tolerant transaction*/
/* _fx_fault_tolerant_recover Recover FAT chain */
/* _fx_fault_tolerant_reset_log_file Reset the log file */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_rename(FX_MEDIA *media_ptr, CHAR *old_directory_name, CHAR *new_directory_name)
{
UINT status;
FX_DIR_ENTRY old_dir_entry;
FX_DIR_ENTRY new_dir_entry;
FX_DIR_ENTRY search_directory;
CHAR *new_name_ptr;
ULONG i;
CHAR *work_ptr;
CHAR alpha, beta;
#ifdef FX_RENAME_PATH_INHERIT
UINT j;
#endif
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_directory_renames++;
#endif
/* Setup pointers to media name buffers. */
old_dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
new_dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 2;
search_directory.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 3;
/* Clear the short name strings. */
old_dir_entry.fx_dir_entry_short_name[0] = 0;
new_dir_entry.fx_dir_entry_short_name[0] = 0;
search_directory.fx_dir_entry_short_name[0] = 0;
/* Determine if the supplied name is less than the maximum supported name size. The
maximum name (FX_MAX_LONG_NAME_LEN) is defined in fx_api.h. */
i = 0;
work_ptr = (CHAR *)new_directory_name;
while (*work_ptr && (i < FX_MAX_LONG_NAME_LEN))
{
/* Determine if the character designates a new path. */
if ((*work_ptr == '\\') || (*work_ptr == '/'))
{
/* Yes, reset the name size. */
i = 0;
}
/* Check for leading spaces. */
else if ((*work_ptr != ' ') || (i != 0))
{
/* No leading spaces, increment the name size. */
i++;
}
/* Move to the next character. */
work_ptr++;
}
/* Determine if the supplied name is valid. */
if ((i == 0) || (i >= FX_MAX_LONG_NAME_LEN))
{
/* Return an invalid name value. */
return(FX_INVALID_NAME);
}
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_RENAME, media_ptr, old_directory_name, new_directory_name, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Start transaction. */
_fx_fault_tolerant_transaction_start(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Check for write protect at the media level (set by driver). */
if (media_ptr -> fx_media_driver_write_protect)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return write protect error. */
return(FX_WRITE_PROTECT);
}
/* Search the system for the supplied directory name. */
status = _fx_directory_search(media_ptr, old_directory_name, &old_dir_entry, &search_directory, FX_NULL);
/* Determine if the search was successful. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Check to make sure the found entry is a directory. */
if (!(old_dir_entry.fx_dir_entry_attributes & (UCHAR)(FX_DIRECTORY)))
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the not a directory error code. */
return(FX_NOT_DIRECTORY);
}
#ifdef FX_RENAME_PATH_INHERIT
/* Determine if the source directory name has a path and the target directory name does not. */
if (((old_directory_name[0] == '/') || (old_directory_name[0] == '\\')) && (new_directory_name[0] != '/') && (new_directory_name[0] != '\\'))
{
/* In this case, we need to prepend the path of the old directory name to that of the new directory name. */
/* Setup pointer to the rename buffer. */
work_ptr = (CHAR *)media_ptr -> fx_media_rename_buffer;
/* First, copy the path of the old directory name. */
i = 0;
j = 0;
while ((old_directory_name[i]) && (i < FX_MAXIMUM_PATH))
{
/* Copy a character into the rename buffer. */
*work_ptr++ = old_directory_name[i];
/* Determine if this character is directory separator. */
if ((old_directory_name[i] == '/') || (old_directory_name[i] == '\\'))
{
/* Yes, directory separator has been found - remember the index. */
j = i;
}
/* Move to next position in the old directory name. */
i++;
}
/* At this point, we have the path stored in the rename buffer. */
/* Position past the last slash or backslash. */
j++;
/* Reset the working pointer to the position after the last directory separator. */
work_ptr = (CHAR *)&(media_ptr -> fx_media_rename_buffer[j]);
/* Now copy the new directory name into the rename buffer. */
i = 0;
while ((new_directory_name[i]) && (j < FX_MAXIMUM_PATH))
{
/* Copy a character into the rename buffer. */
*work_ptr++ = new_directory_name[i];
/* Move to next character. */
i++;
j++;
}
/* Determine if the path was successfully prepended. */
if (new_directory_name[i])
{
/* No, there was not enough room in the destination buffer. */
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the invalid path error code. */
return(FX_INVALID_PATH);
}
/* Place a NULL at the end of the string. */
*work_ptr = (CHAR)FX_NULL;
/* At this point, we have successfully prepended the path in the new directory name, override
the new directory name so it is used from now on. */
new_directory_name = (CHAR *)media_ptr -> fx_media_rename_buffer;
}
#endif
/* Search the media for the new directory name - including any supplied path. */
status = _fx_directory_search(media_ptr, new_directory_name, &new_dir_entry, &search_directory, &new_name_ptr);
/* Determine if the search found anything. */
if (status == FX_SUCCESS)
{
/* Determine if the new name simply has an ASCII case change. If so, simply let the processing
continue. */
i = 0;
do
{
/* Pickup an old name and new name character and convert to upper case if necessary. */
alpha = old_directory_name[i];
if ((alpha >= 'a') && (alpha <= 'z'))
{
/* Lower case, convert to upper case! */
alpha = (CHAR)((INT)alpha - 0x20);
}
beta = new_directory_name[i];
if ((beta >= 'a') && (beta <= 'z'))
{
/* Lower case, convert to upper case! */
beta = (CHAR)((INT)beta - 0x20);
}
/* Now compare the characters. */
if ((alpha != beta) || (alpha == 0))
{
/* Get out of this loop! */
break;
}
/* Move to next character. */
i++;
} while (i < (FX_MAXIMUM_PATH-1));
/* Now determine if the names match. */
if (alpha != beta)
{
/* Yes, the directory name already exists in the target location. */
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(FX_ALREADY_CREATED);
}
}
/* Make sure the name is valid. */
if (_fx_directory_name_extract(new_name_ptr, &new_dir_entry.fx_dir_entry_name[0]))
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection */
FX_UNPROTECT
/* Return the error code */
return(FX_INVALID_NAME);
}
/* Look for a free slot in the target directory. */
status = _fx_directory_free_search(media_ptr, &search_directory, &new_dir_entry);
/* Was a free slot found? */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* No, release protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Extract the new directory name. */
_fx_directory_name_extract(new_name_ptr, &new_dir_entry.fx_dir_entry_name[0]);
/* Determine if the name was a long directory name. */
if (new_dir_entry.fx_dir_entry_long_name_present)
{
/* Yes, clear the short directory name to force a new one. */
new_dir_entry.fx_dir_entry_short_name[0] = 0;
}
/* Setup new attributes for the new directory entry. */
new_dir_entry.fx_dir_entry_attributes = old_dir_entry.fx_dir_entry_attributes;
new_dir_entry.fx_dir_entry_cluster = old_dir_entry.fx_dir_entry_cluster;
new_dir_entry.fx_dir_entry_file_size = old_dir_entry.fx_dir_entry_file_size;
/* Save the reserved field. */
new_dir_entry.fx_dir_entry_reserved = old_dir_entry.fx_dir_entry_reserved;
/* Set time and date stamps. */
new_dir_entry.fx_dir_entry_created_time_ms = old_dir_entry.fx_dir_entry_created_time_ms;
new_dir_entry.fx_dir_entry_created_time = old_dir_entry.fx_dir_entry_created_time;
new_dir_entry.fx_dir_entry_created_date = old_dir_entry.fx_dir_entry_created_date;
new_dir_entry.fx_dir_entry_last_accessed_date = old_dir_entry.fx_dir_entry_last_accessed_date;
new_dir_entry.fx_dir_entry_time = old_dir_entry.fx_dir_entry_time;
new_dir_entry.fx_dir_entry_date = old_dir_entry.fx_dir_entry_date;
/* Is there a leading dot? */
if (new_dir_entry.fx_dir_entry_name[0] == '.')
{
/* Yes, toggle the hidden attribute bit. */
new_dir_entry.fx_dir_entry_attributes |= FX_HIDDEN;
}
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
/* Invalidate the directory cache. */
media_ptr -> fx_media_last_found_name[0] = FX_NULL;
#endif
/* Now write out the directory entry. */
status = _fx_directory_entry_write(media_ptr, &new_dir_entry);
/* Determine if the write was successful. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Set the old directory entry to free. */
old_dir_entry.fx_dir_entry_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
old_dir_entry.fx_dir_entry_short_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
/* Now wipe out the old directory entry. */
status = _fx_directory_entry_write(media_ptr, &old_dir_entry);
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
/* End transaction. */
status = _fx_fault_tolerant_transaction_end(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Directory rename is complete, return status. */
return(status);
}
+936
View File
@@ -0,0 +1,936 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_utility.h"
#ifndef FX_NO_LOCAL_PATH
FX_LOCAL_PATH_SETUP
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_search PORTABLE C */
/* 6.1.10 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function searches the media for the supplied name. The search */
/* routine will find files as well as directory names. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* name_ptr Name pointer */
/* entry_ptr Pointer to directory entry */
/* record */
/* last_dir_ptr Pointer to destination for */
/* the last directory entry */
/* last_name_ptr Pointer to the last name */
/* token that was searched for */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_name_extract Extract directory name from */
/* input string */
/* _fx_directory_entry_read Read entries from root dir */
/* _fx_utility_FAT_entry_read Read FAT entries to calculate */
/* the sub-directory size */
/* */
/* CALLED BY */
/* */
/* FileX System Functions */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), and */
/* added conditional to */
/* disable media search cache, */
/* resulting in version 6.1 */
/* 06-02-2021 Bhupendra Naphade Modified comment(s), and */
/* added check for */
/* volume label, */
/* resulting in version 6.1.7 */
/* 01-31-2022 William E. Lamie Modified comment(s), and */
/* fixed path compare, */
/* resulting in version 6.1.10 */
/* */
/**************************************************************************/
UINT _fx_directory_search(FX_MEDIA *media_ptr, CHAR *name_ptr, FX_DIR_ENTRY *entry_ptr,
FX_DIR_ENTRY *last_dir_ptr, CHAR **last_name_ptr)
{
ULONG i, n;
UINT found;
UINT status;
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
UINT v, j;
#endif /* FX_MEDIA_DISABLE_SEARCH_CACHE */
ULONG cluster, next_cluster = 0;
ULONG64 directory_size;
CHAR *dir_name_ptr;
CHAR *work_ptr;
CHAR *source_name_ptr;
CHAR *destination_name_ptr;
FX_DIR_ENTRY search_dir;
FX_DIR_ENTRY *search_dir_ptr;
CHAR *name, alpha, name_alpha;
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
UINT index;
CHAR *path_ptr = FX_NULL;
CHAR *original_name = name_ptr;
#endif
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of directory search requests. */
media_ptr -> fx_media_directory_searches++;
#endif
/* Setup pointer to media name buffer. */
name = media_ptr -> fx_media_name_buffer;
/* Setup the last directory, if required. */
if (last_dir_ptr)
{
/* Set the first character of the directory entry to NULL to
indicate root or no directory. */
last_dir_ptr -> fx_dir_entry_name[0] = 0;
}
/* Determine if the file name has a full directory path. */
if ((*name_ptr == '\\') || (*name_ptr == '/'))
{
/* Directory name has full path, set the search pointer to NULL. */
search_dir_ptr = FX_NULL;
}
else
{
/* Set the initial search directory to the current working
directory - if there is one. */
/* First check for a local path pointer stored in the thread control block. This
is only available in ThreadX Version 4 and above. */
#ifndef FX_NO_LOCAL_PATH
if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
{
/* Determine if the local directory is not the root directory. */
if (((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_directory.fx_dir_entry_name[0])
{
/* Start at the current working directory of the media. */
search_dir = ((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_directory;
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
/* Setup pointer to the path. */
path_ptr = ((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_string;
#endif
/* Set the internal pointer to the search directory as well. */
search_dir_ptr = &search_dir;
}
else
{
/* We are searching in the root directory. */
search_dir_ptr = FX_NULL;
}
}
else
#endif
if (media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name[0])
{
/* Start at the current working directory of the media. */
search_dir = media_ptr -> fx_media_default_path.fx_path_directory;
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
/* Setup pointer to the path. */
path_ptr = media_ptr -> fx_media_default_path.fx_path_string;
#endif
/* Set the internal pointer to the search directory as well. */
search_dir_ptr = &search_dir;
}
else
{
/* The current default directory is the root so just set the
search directory pointer to NULL. */
search_dir_ptr = FX_NULL;
}
}
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
/* Determine if there is a previously found directory entry. */
if (media_ptr -> fx_media_last_found_name[0])
{
UINT match;
CHAR *temp_ptr, beta;
/* Yes, there is a previously found directory in our cache. */
/* Initialize the index. */
v = 0;
/* Determine if there is a full path. */
if ((*name_ptr == '\\') || (*name_ptr == '/'))
{
/* Yes, the full path is in the name buffer. Simply compare with what is in
the last search buffer. */
while ((v < (FX_MAX_LAST_NAME_LEN - 1)) && (name_ptr[v]))
{
/* Pickup the respective name characters. */
alpha = name_ptr[v];
beta = media_ptr -> fx_media_last_found_name[v];
/* Ensure directory markers are the same. */
if (alpha == '\\')
{
alpha = '/';
}
if (beta == '\\')
{
beta = '/';
}
/* Is the name the same? */
if (alpha != beta)
{
/* Break out of loop! */
break;
}
/* Move to next character. */
v++;
}
/* Determine if we have a match. */
if (name_ptr[v] != media_ptr -> fx_media_last_found_name[v])
{
match = FX_FALSE;
}
else
{
match = FX_TRUE;
}
}
else
{
/* Default to found. */
match = FX_TRUE;
/* Determine if there is a default path to compare with. */
if (path_ptr)
{
/* Yes, compare the current path with what is contained in the last
found buffer. Note that the last found name must have at least one
path separator as well as room for at least one character for a name. */
while ((v < (FX_MAX_LAST_NAME_LEN - 1)) && (path_ptr[v]))
{
/* Pickup the respective name characters. */
alpha = media_ptr -> fx_media_last_found_name[v];
beta = path_ptr[v];
/* Ensure directory markers are the same. */
if (alpha == '\\')
{
alpha = '/';
}
if (beta == '\\')
{
beta = '/';
}
/* Is the name the same? */
if (alpha != beta)
{
/* Break out of loop! */
break;
}
/* Move to next character. */
v++;
}
/* Determine if we don't have a match... The relative path must be exhausted. */
if (path_ptr[v])
{
match = FX_FALSE;
}
}
/* Determine if we still have a match. */
if (match)
{
/* Now examine the rest of the last name and the newly supplied
input name. */
/* Determine if a valid directory separator is present. */
if ((media_ptr -> fx_media_last_found_name[v] != '\\') &&
(media_ptr -> fx_media_last_found_name[v] != '/'))
{
/* Set match to false - invalid directory path separator. */
match = FX_FALSE;
}
else
{
/* Position past the next directory separator in the
last name string. */
v++;
}
/* Yes, the full path is in the name buffer. Simply compare with what is in
the last search buffer. */
j = 0;
while ((v < (FX_MAX_LAST_NAME_LEN - 1)) && (name_ptr[j]) && (match))
{
/* Pickup the respective name characters. */
alpha = name_ptr[j];
beta = media_ptr -> fx_media_last_found_name[v];
/* Ensure directory markers are the same. */
if (alpha == '\\')
{
alpha = '/';
}
if (beta == '\\')
{
beta = '/';
}
/* Is the name the same? */
if (alpha != beta)
{
/* Break out of loop! */
break;
}
/* Move to next character. */
v++;
j++;
}
/* Avoid accessing fx_media_last_found_name out of bounds. */
if (v >= 256)
{
match = FX_FALSE;
}
else if ((match) && (name_ptr[j] != media_ptr -> fx_media_last_found_name[v]))
{
/* We don't have a match. */
match = FX_FALSE;
}
}
}
/* Now determine if we actually found a match. */
if (match)
{
/* Save the directory entry name pointer. */
temp_ptr = entry_ptr -> fx_dir_entry_name;
/* Copy the saved directory entry. */
*entry_ptr = media_ptr -> fx_media_last_found_entry;
/* Restore the directory entry name pointer. */
entry_ptr -> fx_dir_entry_name = temp_ptr;
/* Copy the directory name into the destination directory name. */
for (index = 0; index < FX_MAX_LONG_NAME_LEN; index++)
{
/* Copy character into the destination. */
temp_ptr[index] = media_ptr -> fx_media_last_found_file_name[index];
/* See if we have copied the NULL termination character. */
if (temp_ptr[index] == (CHAR)FX_NULL)
{
/* Determine if we should break here or at the top of the loop. */
if (index < (FX_MAX_LONG_NAME_LEN - 1))
{
/* Yes, break out of the loop early. */
break;
}
}
}
/* Determine if there is a search directory to copy. */
if ((last_dir_ptr) && (media_ptr -> fx_media_last_found_directory_valid))
{
/* Yes, there was a search directory... and one is requested in this request as well.
Simply copy it into the destination. */
/* First, save the name pointer from the list directory pointer. */
destination_name_ptr = last_dir_ptr -> fx_dir_entry_name;
/* Copy the entire directory entry structure. */
*last_dir_ptr = media_ptr -> fx_media_last_found_directory;
/* Restore the original name buffer pointer. */
last_dir_ptr -> fx_dir_entry_name = destination_name_ptr;
/* Pickup pointer to name to copy. */
source_name_ptr = media_ptr -> fx_media_last_found_directory.fx_dir_entry_name;
/* Loop to copy the name into the last directory name buffer. */
for (n = 0; n < FX_MAX_LONG_NAME_LEN; n++)
{
/* Copy a character. */
destination_name_ptr[n] = source_name_ptr[n];
/* See if we have copied the NULL termination character. */
if (source_name_ptr[n] == (CHAR)FX_NULL)
{
/* Determine if we should break here or at the top of the loop. */
if (n < (FX_MAX_LONG_NAME_LEN - 1))
{
/* Yes, break out of the loop early. */
break;
}
}
}
}
/* Return the last name pointer, if required. */
if (last_name_ptr)
{
/* Just set the last name to initial name string. */
*last_name_ptr = temp_ptr;
}
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of directory search cache hits. */
media_ptr -> fx_media_directory_search_cache_hits++;
#endif
/* Return success. */
return(FX_SUCCESS);
}
}
/* Not a sequential search, invalidate the saved information. */
media_ptr -> fx_media_last_found_name[0] = FX_NULL;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_DIR_CACHE_MISS, media_ptr, media_ptr -> fx_media_directory_searches - media_ptr -> fx_media_directory_search_cache_hits, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
#else
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_DIR_CACHE_MISS, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
#endif
#endif
/* Loop to traverse the directory paths to find the specified file. */
do
{
/* Remember the last name pointer, if required. */
if (last_name_ptr)
{
/* Just set the last name to initial name string. */
*last_name_ptr = name_ptr;
}
/* Extract file name. */
name_ptr = _fx_directory_name_extract(name_ptr, name);
/* Calculate the directory size. */
if (search_dir_ptr)
{
/* Ensure that the search directory's last search cluster is cleared. */
search_dir_ptr -> fx_dir_entry_last_search_cluster = 0;
/* Calculate the directory size by counting the allocated
clusters for it. */
i = 0;
cluster = search_dir_ptr -> fx_dir_entry_cluster;
while (cluster < media_ptr -> fx_media_fat_reserved)
{
/* Increment the cluster count. */
i++;
/* Read the next FAT entry. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
/* Check the return status. */
if (status != FX_SUCCESS)
{
/* Return the bad status. */
return(status);
}
/* Check for error situation. */
if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
{
/* Return the bad status. */
return(FX_FAT_READ_ERROR);
}
cluster = next_cluster;
}
/* Now we can calculate the directory size. */
directory_size = (((ULONG64) media_ptr -> fx_media_bytes_per_sector) *
((ULONG64) media_ptr -> fx_media_sectors_per_cluster) * i)
/ (ULONG64) FX_DIR_ENTRY_SIZE;
/* Also save this in the directory entry so we don't have to
calculate it later. */
search_dir_ptr -> fx_dir_entry_file_size = directory_size;
/* If required, copy the last search directory entry into the
destination. */
if (last_dir_ptr)
{
/* Copy the last search directory into the destination. */
/* First, save the name pointer from the list directory pointer. */
destination_name_ptr = last_dir_ptr -> fx_dir_entry_name;
/* Copy the entire directory entry structure. */
*last_dir_ptr = *search_dir_ptr;
/* Restore the original name buffer pointer. */
last_dir_ptr -> fx_dir_entry_name = destination_name_ptr;
/* Pickup pointer to name to copy. */
source_name_ptr = search_dir_ptr -> fx_dir_entry_name;
/* Loop to copy the name into the last directory name buffer. */
for (n = 0; n < FX_MAX_LONG_NAME_LEN; n++)
{
/* Copy a character. */
destination_name_ptr[n] = source_name_ptr[n];
/* See if we have copied the NULL termination character. */
if (source_name_ptr[n] == (CHAR) FX_NULL)
{
/* Determine if we should break here or at the top of the loop. */
if (n < (FX_MAX_LONG_NAME_LEN - 1))
{
/* Yes, break out of the loop early. */
break;
}
}
}
}
}
else
{
/* Directory size is the number of entries in the root directory. */
directory_size = (ULONG)media_ptr -> fx_media_root_directory_entries;
}
/* Loop through entries in the directory. Yes, this is a
linear search! */
i = 0;
found = FX_FALSE;
do
{
/* Read an entry from the directory. */
status = _fx_directory_entry_read(media_ptr, search_dir_ptr, &i, entry_ptr);
i++;
/* Check for error status. */
if (status != FX_SUCCESS)
{
return(status);
}
/* Determine if this is the last directory entry. */
if ((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_DONE)
{
break;
}
/* Determine if the entry is a volume label entry */
if ((entry_ptr -> fx_dir_entry_attributes & FX_VOLUME))
{
continue;
}
/* Determine if this is an empty entry. */
if (((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry_ptr -> fx_dir_entry_short_name[0] == 0))
{
continue;
}
/* Compare the input name and extension with the directory
entry. */
work_ptr = &name[0];
dir_name_ptr = &(entry_ptr -> fx_dir_entry_name[0]);
/* Loop to compare names. */
do
{
/* Pickup character of directory name. */
alpha = *dir_name_ptr;
/* Pickup character of name. */
name_alpha = *work_ptr;
/* Determine if its case needs to be changed. */
if ((alpha >= 'a') && (alpha <= 'z'))
{
/* Yes, make upper case. */
alpha = (CHAR)((INT)alpha - 0x20);
}
/* Determine if its case needs to be changed. */
if ((name_alpha >= 'a') && (name_alpha <= 'z'))
{
/* Yes, make upper case. */
name_alpha = (CHAR)((INT)name_alpha - 0x20);
}
/* Compare name with directory name. */
if (alpha != name_alpha)
{
/* The names don't match, get out of the loop. */
break;
}
/* Otherwise, increment the name pointers. */
work_ptr++;
dir_name_ptr++;
} while (*dir_name_ptr);
/* Determine if the requested name has been found. If so,
return success to the caller. */
if ((*dir_name_ptr == 0) && (*work_ptr == *dir_name_ptr))
{
/* Yes, the name was located. All pertinent directory
information is in the directory entry field. */
found = FX_TRUE;
}
/* Determine if there is a short name to check. */
else if (entry_ptr -> fx_dir_entry_short_name[0] != 0)
{
/* Yes, check for the short part of the name. */
/* Compare the input name and extension with the directory entry. */
work_ptr = &name[0];
dir_name_ptr = &(entry_ptr -> fx_dir_entry_short_name[0]);
/* Loop to compare names. */
do
{
/* Pickup character of directory name. */
alpha = *dir_name_ptr;
/* Pickup character of name. */
name_alpha = *work_ptr;
/* Determine if its case needs to be changed. */
if ((name_alpha >= 'a') && (name_alpha <= 'z'))
{
/* Yes, make upper case. */
name_alpha = (CHAR)((INT)name_alpha - 0x20);
}
/* Compare name with directory name. */
if (alpha != name_alpha)
{
/* The names don't match, get out of the loop. */
break;
}
/* Otherwise, move the name pointers and increment the
count. */
work_ptr++;
dir_name_ptr++;
} while (*dir_name_ptr);
/* Determine if the names match. */
if ((*dir_name_ptr == 0) && (*work_ptr == *dir_name_ptr))
{
/* Yes, the name was located. All pertinent directory
information is in the directory entry field. */
found = FX_TRUE;
}
}
} while ((i < directory_size) && (!found));
/* Now determine if we have a match. */
if (!found)
{
/* Return a "not found" status to the caller. */
return(FX_NOT_FOUND);
}
/* Determine if the found entry is indeed a sub-directory. */
if (entry_ptr -> fx_dir_entry_attributes & FX_DIRECTORY)
{
/* Move the directory search pointer to this entry. */
search_dir = *entry_ptr;
search_dir_ptr = &search_dir;
/* Ensure that the search directory's last search cluster is cleared. */
search_dir_ptr -> fx_dir_entry_last_search_cluster = 0;
/* Now determine if the new search directory is the root
directory. */
if (!search_dir_ptr -> fx_dir_entry_cluster)
{
/* This is a backward link to the root directory. Make
sure this is indicated in the search directory
information. */
search_dir_ptr -> fx_dir_entry_name[0] = 0;
/* Determine if we need to remember this in the last
directory searched return area. */
if (last_dir_ptr)
{
/* Yes, return this value to the caller. */
/* First, save the name pointer from the list directory pointer. */
destination_name_ptr = last_dir_ptr -> fx_dir_entry_name;
/* Copy the entire directory entry structure. */
*last_dir_ptr = *search_dir_ptr;
/* Restore the original name buffer pointer. */
last_dir_ptr -> fx_dir_entry_name = destination_name_ptr;
/* Pickup pointer to name to copy. */
source_name_ptr = search_dir_ptr -> fx_dir_entry_name;
/* Loop to copy the name into the last directory name buffer. */
for (n = 0; n < FX_MAX_LONG_NAME_LEN; n++)
{
/* Copy a character. */
destination_name_ptr[n] = source_name_ptr[n];
}
}
/* Set the search directory pointer to NULL to indicate
we are at the root directory. */
search_dir_ptr = FX_NULL;
}
}
else
{
/* This is not a directory, we better return not found
since we can't continue the search. */
if (name_ptr)
{
/* Return not-found status to caller. */
return(FX_NOT_FOUND);
}
}
} while (name_ptr);
/* If you reach this point, the directory is found absolutely, since !found will return directly in the loop above. */
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
/* At this point, cache the found information. If a subsequent search for the same name is done,
it will return immediately. */
/* Set the index of the saved name string. */
v= 0;
/* First, build the full path and name. */
if ((*original_name != '\\') && (*original_name != '/') && (path_ptr))
{
/* Copy the path into the destination. */
while ((v< (FX_MAX_LAST_NAME_LEN - 1)) && (path_ptr[v]))
{
/* Copy one character. */
media_ptr -> fx_media_last_found_name[v] = path_ptr[v];
/* Move to next character. */
v++;
}
}
/* Now see if there is no directory path symbol in the name itself. */
if ((*original_name != '\\') && (*original_name != '/'))
{
/* If there is room, place a directory separator character. */
if (v < (FX_MAX_LAST_NAME_LEN - 1))
{
media_ptr -> fx_media_last_found_name[v++] = '/';
}
}
/* Now append the name to the path. */
j = 0;
while ((v < FX_MAX_LAST_NAME_LEN) && (original_name[j]))
{
/* Copy one character. */
media_ptr -> fx_media_last_found_name[v] = original_name[j];
/* Move to next character. */
v++;
j++;
}
/* Null terminate the last name string. */
if (v< FX_MAX_LAST_NAME_LEN)
{
/* Null terminate. */
media_ptr -> fx_media_last_found_name[v] = FX_NULL;
}
else
{
/* The string is too big, NULL the string so it won't be used in searching. */
media_ptr -> fx_media_last_found_name[0] = FX_NULL;
}
/* Determine if there is a search pointer. */
if (search_dir_ptr)
{
/* Yes, there is a search directory pointer so save it! */
media_ptr -> fx_media_last_found_directory = *search_dir_ptr;
/* Indicate the search directory is valid. */
media_ptr -> fx_media_last_found_directory_valid = FX_TRUE;
}
else
{
/* Indicate the search directory is not valid. */
media_ptr -> fx_media_last_found_directory_valid = FX_FALSE;
}
/* Copy the directory entry. */
media_ptr -> fx_media_last_found_entry = *entry_ptr;
/* Setup the directory entry for the last found internal file name. */
media_ptr -> fx_media_last_found_entry.fx_dir_entry_name = media_ptr -> fx_media_last_found_file_name;
/* Copy the actual directory name into the cached directory name. */
for (index = 0; index < FX_MAX_LONG_NAME_LEN; index++)
{
/* Copy character into the cached directory name. */
media_ptr -> fx_media_last_found_file_name[index] = entry_ptr -> fx_dir_entry_name[index];
/* See if we have copied the NULL termination character. */
if (entry_ptr -> fx_dir_entry_name[index] == (CHAR)FX_NULL)
{
/* Check to see if we use the break to get out of the loop. */
if (index < (FX_MAX_LONG_NAME_LEN - 1))
{
/* Yes, not at the end of the string, break. */
break;
}
}
}
#endif
return(FX_SUCCESS);
}
+85
View File
@@ -0,0 +1,85 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_directory.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_short_name_get PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function gets the short file name via the supplied long file */
/* name. If the long file name is really a short file name, the short */
/* file name will be returned. */
/* */
/* Note, this API is deprecated as fx_directory_short_name_get_extended*/
/* should be used. The maximum written size to short_file_name could */
/* be FX_MAX_SHORT_NAME_LEN. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* long_file_name Pointer to long (max 255) name*/
/* short_file_name Pointer to short (8.3) name */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_short_name_get_extended Actual short name get service */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_short_name_get(FX_MEDIA *media_ptr, CHAR *long_file_name, CHAR *short_file_name)
{
/* Call the extended version with maximum short name length. */
return(_fx_directory_short_name_get_extended(media_ptr, long_file_name, short_file_name, FX_MAX_SHORT_NAME_LEN));
}
@@ -0,0 +1,170 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_directory.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_short_name_get_extended PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function gets the short file name via the supplied long file */
/* name. If the long file name is really a short file name, the short */
/* file name will be returned. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* long_file_name Pointer to long (max 255) name*/
/* short_file_name Pointer to short (8.3) name */
/* short_file_name_length Buffer length for short name */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_search Search for the file name in */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_directory_short_name_get_extended(FX_MEDIA *media_ptr, CHAR *long_file_name, CHAR *short_file_name, UINT short_file_name_length)
{
UINT status;
UINT i;
FX_DIR_ENTRY dir_entry;
/* Setup pointer to media name buffer. */
dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Clear the short name string. */
dir_entry.fx_dir_entry_short_name[0] = 0;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_SHORT_NAME_GET, media_ptr, long_file_name, short_file_name, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Search the system for the supplied short directory name. */
status = _fx_directory_search(media_ptr, long_file_name, &dir_entry, FX_NULL, FX_NULL);
/* Determine if the search was successful. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Determine if there is a short name. */
if (dir_entry.fx_dir_entry_short_name[0])
{
/* Yes, there is a short name. Copy the short file name portion into the destination string. */
i = 0;
while ((i < (FX_MAX_SHORT_NAME_LEN - 1)) && (dir_entry.fx_dir_entry_short_name[i]) && (i < (short_file_name_length - 1)))
{
/* Copy a character of the long file name into the destination name. */
short_file_name[i] = dir_entry.fx_dir_entry_short_name[i];
/* Move to next character. */
i++;
}
/* Ensure the short file name is NULL terminated. */
short_file_name[i] = FX_NULL;
/* Check if the buffer is too short for the name. */
if ((i == (short_file_name_length - 1)) && (dir_entry.fx_dir_entry_short_name[i]))
{
/* Buffer too short, return error. */
status = FX_BUFFER_ERROR;
}
}
else
{
/* There is no long file name, simply copy the long file name into the short file name destination. */
i = 0;
while ((i < (FX_MAX_SHORT_NAME_LEN - 1)) && (dir_entry.fx_dir_entry_name[i]) && (i < (short_file_name_length - 1)))
{
/* Copy a character of the file name into the destination name. */
short_file_name[i] = dir_entry.fx_dir_entry_name[i];
/* Move to next character. */
i++;
}
/* Ensure the short file name is NULL terminated. */
short_file_name[i] = FX_NULL;
/* Check if the buffer is too short for the name. */
if ((i == (short_file_name_length - 1)) && (dir_entry.fx_dir_entry_name[i]))
{
/* Buffer too short, return error. */
status = FX_BUFFER_ERROR;
}
}
/* Release media protection. */
FX_UNPROTECT
/* Return the completion status. */
return(status);
}
+113
View File
@@ -0,0 +1,113 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_utility.h"
#include "fx_fault_tolerant.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_add_FAT_log PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function converts FAT write into log entry and add it into */
/* log file. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* cluster Cluster entry number */
/* value Next cluster value */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_16_unsigned_write Write a USHORT from memory */
/* _fx_utility_32_unsigned_write Write a UINT from memory */
/* */
/* CALLED BY */
/* */
/* _fx_utility_FAT_entry_write */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_add_FAT_log(FX_MEDIA *media_ptr, ULONG cluster, ULONG value)
{
ULONG file_size;
FX_FAULT_TOLERANT_FAT_LOG *fat_log;
/* Increment the size of the log file. */
file_size = media_ptr -> fx_media_fault_tolerant_file_size + FX_FAULT_TOLERANT_FAT_LOG_ENTRY_SIZE;
/* Check whether log file exceeds the buffer. */
if (file_size > media_ptr -> fx_media_fault_tolerant_memory_buffer_size)
{
/* Log file exceeds the size of the log buffer. This is a failure. */
return(FX_NO_MORE_SPACE);
}
/* Set log pointer. */
fat_log = (FX_FAULT_TOLERANT_FAT_LOG *)(media_ptr -> fx_media_fault_tolerant_memory_buffer +
media_ptr -> fx_media_fault_tolerant_file_size);
/* Set log type. */
_fx_utility_16_unsigned_write((UCHAR *)&fat_log -> fx_fault_tolerant_FAT_log_type,
FX_FAULT_TOLERANT_FAT_LOG_TYPE);
/* Size of log. */
_fx_utility_16_unsigned_write((UCHAR *)&fat_log -> fx_fault_tolerant_FAT_log_size,
FX_FAULT_TOLERANT_FAT_LOG_ENTRY_SIZE);
/* Set cluster and value. */
_fx_utility_32_unsigned_write((UCHAR *)&fat_log -> fx_fault_tolerant_FAT_log_cluster, cluster);
_fx_utility_32_unsigned_write((UCHAR *)&fat_log -> fx_fault_tolerant_FAT_log_value, value);
/* Update log information. */
media_ptr -> fx_media_fault_tolerant_file_size = (USHORT)file_size;
media_ptr -> fx_media_fault_tolerant_total_logs += 1;
return(FX_SUCCESS);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
@@ -0,0 +1,30 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_utility.h"
#include "fx_fault_tolerant.h"
@@ -0,0 +1,30 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_utility.h"
#include "fx_fault_tolerant.h"
+132
View File
@@ -0,0 +1,132 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_utility.h"
#include "fx_fault_tolerant.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_add_dir_log PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function converts directory entry write into log entry and add */
/* it into log file. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* logical_sector Original sector to write to */
/* offset Offset in original sector */
/* data Data of log */
/* data_size Size of data */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_16_unsigned_write Write a USHORT from memory */
/* _fx_utility_32_unsigned_write Write a ULONG from memory */
/* _fx_utility_64_unsigned_write Write a ULONG64 from memory */
/* memcpy Memory Copy */
/* */
/* CALLED BY */
/* */
/* _fx_directory_entry_write */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), verified */
/* memcpy usage, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_add_dir_log(FX_MEDIA *media_ptr, ULONG64 logical_sector, ULONG offset,
UCHAR *data, ULONG data_size)
{
ULONG file_size;
FX_FAULT_TOLERANT_DIR_LOG *dir_log;
/* Increment the size of the log file. */
file_size = media_ptr -> fx_media_fault_tolerant_file_size + data_size + FX_FAULT_TOLERANT_DIR_LOG_ENTRY_SIZE;
/* Check whether log file exceeds the buffer. */
if (file_size > media_ptr -> fx_media_fault_tolerant_memory_buffer_size)
{
/* Log file exceeds the size of the log buffer. This is a failure. */
return(FX_NO_MORE_SPACE);
}
/* Any data to write? */
if (data_size == 0)
{
/* No. Just return. */
return FX_SUCCESS;
}
/* Set log pointer. */
dir_log = (FX_FAULT_TOLERANT_DIR_LOG *)(media_ptr -> fx_media_fault_tolerant_memory_buffer +
media_ptr -> fx_media_fault_tolerant_file_size);
/* Set log type. */
_fx_utility_16_unsigned_write((UCHAR *)&dir_log -> fx_fault_tolerant_dir_log_type,
FX_FAULT_TOLERANT_DIR_LOG_TYPE);
/* Size of log. */
_fx_utility_16_unsigned_write((UCHAR *)&dir_log -> fx_fault_tolerant_dir_log_size,
data_size + FX_FAULT_TOLERANT_DIR_LOG_ENTRY_SIZE);
/* Set sector and offset. */
_fx_utility_64_unsigned_write((UCHAR *)&dir_log -> fx_fault_tolerant_dir_log_sector, logical_sector);
_fx_utility_32_unsigned_write((UCHAR *)&dir_log -> fx_fault_tolerant_dir_log_offset, offset);
memcpy(media_ptr -> fx_media_fault_tolerant_memory_buffer + /* Use case of memcpy is verified. */
media_ptr -> fx_media_fault_tolerant_file_size + FX_FAULT_TOLERANT_DIR_LOG_ENTRY_SIZE,
data, data_size);
/* Update log information. */
media_ptr -> fx_media_fault_tolerant_file_size = (USHORT)file_size;
media_ptr -> fx_media_fault_tolerant_total_logs += 1;
return(FX_SUCCESS);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
+268
View File
@@ -0,0 +1,268 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_utility.h"
#include "fx_fault_tolerant.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_apply_logs PORTABLE C */
/* 6.2.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function applies changes to the file system. The changes are */
/* already recorded in the fault tolerant log file. Therefore this */
/* function reads the content of the log entries and apply these */
/* changes to the file system. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_logical_sector_write Write a logical sector */
/* _fx_utility_logical_sector_read Read a logical sector */
/* _fx_utility_16_unsigned_read Read a USHORT from memory */
/* _fx_utility_32_unsigned_read Read a ULONG from memory */
/* _fx_utility_64_unsigned_read Read a ULONG64 from memory */
/* _fx_utility_FAT_entry_write Write a FAT entry */
/* _fx_fault_tolerant_cleanup_FAT_chain Cleanup FAT chain */
/* memcpy Memory Copy */
/* _fx_utility_FAT_flush Flush written FAT entries */
/* _fx_utility_logical_sector_flush Flush written logical sectors */
/* */
/* CALLED BY */
/* */
/* _fx_fault_tolerant_enable */
/* _fx_fault_tolerant_transaction_end */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), verified */
/* memcpy usage, */
/* resulting in version 6.1 */
/* 10-31-2022 Tiejun Zhou Modified comment(s), fixed */
/* overflow in log size check, */
/* resulting in version 6.2.0 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_apply_logs(FX_MEDIA *media_ptr)
{
UINT status;
ULONG64 log_sector;
ULONG remaining_logs;
ULONG copy_size;
ULONG copy_offset;
UCHAR *current_ptr;
ULONG size;
USHORT log_type;
ULONG log_len;
FX_FAULT_TOLERANT_LOG_HEADER *log_header;
FX_FAULT_TOLERANT_FAT_CHAIN *FAT_chain;
FX_FAULT_TOLERANT_LOG_CONTENT *log_content;
FX_FAULT_TOLERANT_FAT_LOG *fat_log;
FX_FAULT_TOLERANT_DIR_LOG *dir_log;
/* Set log header, FAT chain and log content pointer. */
log_header = (FX_FAULT_TOLERANT_LOG_HEADER *)media_ptr -> fx_media_fault_tolerant_memory_buffer;
FAT_chain = (FX_FAULT_TOLERANT_FAT_CHAIN *)(media_ptr -> fx_media_fault_tolerant_memory_buffer + FX_FAULT_TOLERANT_FAT_CHAIN_OFFSET);
log_content = (FX_FAULT_TOLERANT_LOG_CONTENT *)(media_ptr -> fx_media_fault_tolerant_memory_buffer +
FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET);
/* Find the size of the log file. */
size = _fx_utility_16_unsigned_read((UCHAR *)&log_header -> fx_fault_tolerant_log_header_total_size);
/* Extended port-specific processing macro, which is by default defined to white space. */
FX_FAULT_TOLERANT_APPLY_LOGS_EXTENSION
size -= FX_FAULT_TOLERANT_LOG_CONTENT_HEADER_SIZE;
/* Find the number of log entries. */
remaining_logs = _fx_utility_16_unsigned_read((UCHAR *)&log_content -> fx_fault_tolerant_log_content_count);
/* Get start address of logs. */
current_ptr = (UCHAR *)log_content + FX_FAULT_TOLERANT_LOG_CONTENT_HEADER_SIZE;
/* Loop through all the logs to apply the changes. */
while (remaining_logs)
{
/* Obtain log type of this entry. */
log_type = (USHORT)_fx_utility_16_unsigned_read(current_ptr);
/* Read log length. */
log_len = _fx_utility_16_unsigned_read(current_ptr + 2);
/* Validate log entry size. */
if (log_len > size)
{
/* Something wrong with log file. */
return(FX_FILE_CORRUPT);
}
/* Reduce the total log file size. */
size -= log_len;
/* Process log entry by type. */
switch (log_type)
{
case FX_FAULT_TOLERANT_FAT_LOG_TYPE:
/* This is a FAT log. */
fat_log = (FX_FAULT_TOLERANT_FAT_LOG *)current_ptr;
/* Write FAT entry. */
status = _fx_utility_FAT_entry_write(media_ptr,
_fx_utility_32_unsigned_read((UCHAR *)&fat_log -> fx_fault_tolerant_FAT_log_cluster),
_fx_utility_32_unsigned_read((UCHAR *)&fat_log -> fx_fault_tolerant_FAT_log_value));
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
break;
case FX_FAULT_TOLERANT_DIR_LOG_TYPE:
/* This is a DIR log. */
dir_log = (FX_FAULT_TOLERANT_DIR_LOG *)current_ptr;
log_sector = _fx_utility_64_unsigned_read((UCHAR *)&dir_log -> fx_fault_tolerant_dir_log_sector);
/* Get the destination sector. */
status = _fx_utility_logical_sector_read(media_ptr,
log_sector,
media_ptr -> fx_media_memory_buffer,
((ULONG) 1), FX_DATA_SECTOR);
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
/* Set copy information. */
copy_offset = _fx_utility_32_unsigned_read((UCHAR *)&dir_log -> fx_fault_tolerant_dir_log_offset);
copy_size = log_len - FX_FAULT_TOLERANT_DIR_LOG_ENTRY_SIZE;
if (((ULONG64)copy_offset + (ULONG64)copy_size) > (ULONG64)(media_ptr -> fx_media_memory_size))
{
return(FX_FILE_CORRUPT);
}
/* Copy data into destination sector. */
memcpy(media_ptr -> fx_media_memory_buffer + copy_offset, /* Use case of memcpy is verified. */
current_ptr + FX_FAULT_TOLERANT_DIR_LOG_ENTRY_SIZE, copy_size);
/* Write back the current logical sector. */
status = _fx_utility_logical_sector_write(media_ptr,
log_sector,
media_ptr -> fx_media_memory_buffer,
((ULONG) 1), FX_DIRECTORY_SECTOR);
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
break;
default:
/* Wrong type. */
return(FX_SECTOR_INVALID);
}
/* Decrement the remaining log counter. */
remaining_logs--;
/* Move to start position of next log entry. */
current_ptr += log_len;
}
/* Check whether or not to process FAT chain. */
if (FAT_chain -> fx_fault_tolerant_FAT_chain_flag & FX_FAULT_TOLERANT_FLAG_FAT_CHAIN_VALID)
{
/* Free old link of FAT. */
status = _fx_fault_tolerant_cleanup_FAT_chain(media_ptr, FX_FAULT_TOLERANT_FAT_CHAIN_CLEANUP);
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
}
/* Flush the internal logical sector cache. */
status = _fx_utility_logical_sector_flush(media_ptr, 1, (ULONG64) media_ptr -> fx_media_total_sectors, FX_FALSE);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
/* Return the bad status. */
return(status);
}
/* Flush FAT table. */
#ifdef FX_FAULT_TOLERANT
/* Ensure the new FAT chain is properly written to the media. */
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
#endif
/* Return success. */
return(FX_SUCCESS);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
@@ -0,0 +1,103 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_fault_tolerant.h"
#include "fx_utility.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_calculate_checksum PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calculates checksum for consecutive data. The size */
/* of the log file is required to be 4-byte aligned. Therefore this */
/* checksum routine is able to perform 4-byte access. */
/* */
/* INPUT */
/* */
/* data Pointer to data */
/* len Data length */
/* */
/* OUTPUT */
/* */
/* Computed checksum value */
/* */
/* CALLS */
/* */
/* _fx_utility_32_unsigned_read Read a UINT from memory */
/* */
/* CALLED BY */
/* */
/* _fx_fault_tolerant_enable */
/* _fx_fault_tolerant_cleanup_FAT_chain */
/* _fx_fault_tolerant_reset_log_file */
/* _fx_fault_tolerant_set_FAT_chain */
/* _fx_fault_tolerant_transaction_end */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
USHORT _fx_fault_tolerant_calculate_checksum(UCHAR *data, UINT len)
{
ULONG checksum = 0;
ULONG long_value;
while (len >= 4)
{
/* Read first long value. */
long_value = _fx_utility_32_unsigned_read(data);
/* Calculate checksum. */
checksum += (long_value >> 16) + (long_value & 0xFFFF);
/* Decrease length. */
len -= sizeof(ULONG);
data += sizeof(ULONG);
}
/* Trim high 16 bits of checksum. */
checksum = (checksum & 0xFFFF) + (checksum >> 16);
checksum = (checksum & 0xFFFF) + (checksum >> 16);
return((USHORT)((~checksum) & 0xFFFF));
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
@@ -0,0 +1,356 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_utility.h"
#include "fx_fault_tolerant.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_utility_FAT_entry_multiple_sectors_check PORTABLE C */
/* 6.2.0 */
/* AUTHOR */
/* */
/* Tiejun Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks whether the FAT entry spans multiple sectors. */
/* It is only possible when the file system is FAT12. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* cluster Cluster entry number */
/* */
/* OUTPUT */
/* */
/* FX_TRUE FAT entry spans two sectors */
/* FX_FALSE FAT entry in one sector */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _fx_fault_tolerant_cleanup_FAT_chain */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-31-2022 Tiejun Zhou Initial Version 6.2.0 */
/* */
/**************************************************************************/
static UINT _fx_utility_FAT_entry_multiple_sectors_check(FX_MEDIA *media_ptr, ULONG cluster)
{
ULONG byte_offset;
ULONG FAT_sector;
/* Check FAT format. */
if (!media_ptr -> fx_media_12_bit_FAT)
{
/* Not FAT12. The FAT entry will be in one sector. */
return(FX_FALSE);
}
/* File system is FAT12. */
/* Calculate the byte offset to the cluster entry. */
byte_offset = (((ULONG)cluster << 1) + cluster) >> 1;
/* Calculate the FAT sector the requested FAT entry resides in. */
FAT_sector = (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
(ULONG)media_ptr -> fx_media_reserved_sectors;
/* Now calculate the byte offset into this FAT sector. */
byte_offset = byte_offset -
((FAT_sector - (ULONG)media_ptr -> fx_media_reserved_sectors) *
media_ptr -> fx_media_bytes_per_sector);
/* Determine if we are now past the end of the FAT buffer in memory. */
if (byte_offset == (ULONG)(media_ptr -> fx_media_bytes_per_sector - 1))
{
/* Yes, we are past the end of the FAT buffer. */
return(FX_TRUE);
}
else
{
/* No, we are not past the end of the FAT buffer. */
return(FX_FALSE);
}
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_cleanup_FAT_chain PORTABLE C */
/* 6.2.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function cleans up FAT chain. In order to prevent failures */
/* during the link-list walk, and to improve efficiency, this function */
/* frees the FAT entry chain in sections. For each section, it frees */
/* FAT entry from the last entry in the chain and works backwards. */
/* Using this method, if the system fails in the middle of the free */
/* operation, the head is preserved, and fault tolerant module can */
/* "redo" this operation next time it starts up. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* operation Recover a failure operation or*/
/* cleanup old FAT chain */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* _fx_utility_FAT_entry_write Write a FAT entry */
/* _fx_utility_16_unsigned_write Write a USHORT from memory */
/* _fx_utility_32_unsigned_write Write a ULONG from memory */
/* _fx_utility_32_unsigned_read Read a ULONG from memory */
/* _fx_utility_FAT_flush Flush written FAT entries */
/* _fx_fault_tolerant_calculate_checksum Compute Checksum of data */
/* _fx_fault_tolerant_write_log_file Write log file */
/* _fx_utility_FAT_entry_multiple_sectors_check */
/* Check sectors for FAT entry */
/* */
/* CALLED BY */
/* */
/* _fx_fault_tolerant_apply_logs */
/* _fx_fault_tolerant_recover */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 10-31-2022 Tiejun Zhou Modified comment(s), */
/* fixed FAT entry span two */
/* sectors for FAT12, */
/* resulting in version 6.2.0 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_cleanup_FAT_chain(FX_MEDIA *media_ptr, UINT operation)
{
UINT status;
ULONG current_cluster;
ULONG next_cluster = 0;
ULONG head_cluster;
ULONG tail_cluster;
ULONG cache_count;
ULONG cache_max = FX_FAULT_TOLERANT_CACHE_SIZE >> 2;
ULONG *cache_ptr = media_ptr -> fx_media_fault_tolerant_cache;
ULONG next_session;
USHORT checksum;
ULONG i;
FX_FAULT_TOLERANT_FAT_CHAIN *FAT_chain;
ULONG FAT_sector;
ULONG last_FAT_sector;
/* Set FAT chain pointer. */
FAT_chain = (FX_FAULT_TOLERANT_FAT_CHAIN *)(media_ptr -> fx_media_fault_tolerant_memory_buffer + FX_FAULT_TOLERANT_FAT_CHAIN_OFFSET);
/* Get head and tail cluster. */
if (operation == FX_FAULT_TOLERANT_FAT_CHAIN_RECOVER)
{
/* Recover phase. Cleanup (remove) new FAT chain. */
head_cluster = _fx_utility_32_unsigned_read((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_head_new);
}
else
{
/* Cleanup phase. Cleanup (remove) old FAT chain. */
head_cluster = _fx_utility_32_unsigned_read((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_head_original);
}
/* At this point, the head_cluster points to the cluster chain that is to be removed. */
/* Tail cluster points to the back of the origianal FAT chain where the new chain is attached to.
The remove process terminates once this cluster is encountered. */
tail_cluster = _fx_utility_32_unsigned_read((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_insertion_back);
/* Are there any clusters to free? */
if ((head_cluster < FX_FAT_ENTRY_START) || (head_cluster >= media_ptr -> fx_media_fat_reserved))
{
return(FX_SUCCESS);
}
/* To optimize the deletion process of a long FAT chain, the deletion is done in sessions. During one session,
a set of FAT entries are removed. If one session is interrupted, after restart the deletion process resumes and
picks up from where it left.
During one deletion session, all FAT entries are between head_cluster(inclusive) and next_session (exclusive).
*/
next_session = _fx_utility_32_unsigned_read((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_next_deletion);
/* Loop to cleanup all FAT entries. */
while ((head_cluster >= FX_FAT_ENTRY_START) && (head_cluster < media_ptr -> fx_media_fat_reserved))
{
/* Initialize. */
current_cluster = head_cluster;
cache_count = 0;
/* Loop from head cluster to find entries to cleanup and store this information into cache. */
do
{
/* Get the next FAT entry. */
status = _fx_utility_FAT_entry_read(media_ptr, current_cluster, &next_cluster);
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
/* Whether or not the cluster is occupied. */
if (next_cluster == FX_FREE_CLUSTER)
{
/* Current cluster has already been released. */
break;
}
/* Cache the FAT list. */
cache_ptr[cache_count++] = current_cluster;
/* Check whether FAT entry spans multiple sectors. */
if (_fx_utility_FAT_entry_multiple_sectors_check(media_ptr, current_cluster))
{
if (head_cluster == next_session || next_session == FX_FREE_CLUSTER)
{
next_session = next_cluster;
}
break;
}
/* Move to next cluster. */
current_cluster = next_cluster;
} while ((next_cluster >= FX_FAT_ENTRY_START) &&
(next_cluster < media_ptr -> fx_media_fat_reserved) &&
(next_cluster != tail_cluster) &&
(cache_count < cache_max));
/* Get next session. */
if (cache_count == cache_max)
{
next_session = next_cluster;
}
/* Update head cluster and next session into log file. */
_fx_utility_32_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_next_deletion, next_session);
if (operation == FX_FAULT_TOLERANT_FAT_CHAIN_RECOVER)
{
_fx_utility_32_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_head_new, head_cluster);
}
else
{
_fx_utility_32_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_head_original, head_cluster);
}
/* Update checksum. */
_fx_utility_16_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_checksumm, 0);
checksum = _fx_fault_tolerant_calculate_checksum((UCHAR *)FAT_chain, FX_FAULT_TOLERANT_FAT_CHAIN_SIZE);
_fx_utility_16_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_checksumm, checksum);
/* Flush the fault tolerant log into the file system. */
_fx_fault_tolerant_write_log_file(media_ptr, 0);
/* Loop to free FAT in cache from back to front. */
if (cache_count > 0)
{
/* Get sector of last FAT entry. */
last_FAT_sector = _fx_utility_FAT_sector_get(media_ptr, cache_ptr[cache_count - 1]);
i = cache_count;
while (i > 0)
{
i--;
/* Get sector of current FAT entry. */
FAT_sector = _fx_utility_FAT_sector_get(media_ptr, cache_ptr[i]);
if (FAT_sector != last_FAT_sector)
{
/* Current FAT entry is located in different sector. Force flush. */
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
/* Update sector of current FAT entry. */
last_FAT_sector = FAT_sector;
}
/* Free current_cluster. */
status = _fx_utility_FAT_entry_write(media_ptr, cache_ptr[i], FX_FREE_CLUSTER);
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
}
/* Increase the available clusters in the media control block. */
media_ptr -> fx_media_available_clusters += cache_count;
}
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
/* Get head cluster. */
if (head_cluster == next_session)
{
break;
}
head_cluster = next_session;
}
return(FX_SUCCESS);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
@@ -0,0 +1,233 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_utility.h"
#include "fx_directory.h"
#include "fx_fault_tolerant.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_create_log_file PORTABLE C */
/* 6.1.11 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function finds an available cluster used by log file. Then it */
/* sets the cluster number to boot sector. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* _fx_utility_FAT_entry_write Write a FAT entry */
/* _fx_utility_FAT_flush Flush written FAT entries */
/* _fx_utility_32_unsigned_write Write a ULONG from memory */
/* _fx_utility_logical_sector_read Read a logical sector */
/* */
/* CALLED BY */
/* */
/* _fx_fault_tolerant_enable */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 01-31-2022 Bhupendra Naphade Modified comment(s), replaced */
/* sector size constant, */
/* resulting in version 6.1.10 */
/* 04-25-2022 William E. Lamie Modified comment(s), */
/* resulting in version 6.1.11 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_create_log_file(FX_MEDIA *media_ptr)
{
ULONG clusters;
ULONG FAT_index;
ULONG FAT_value = 0;
UINT found;
UINT status;
UINT i;
/* Yes. Create a log file. */
/* First find a free cluster. */
if (media_ptr -> fx_media_available_clusters < media_ptr -> fx_media_fault_tolerant_clusters)
{
/* Out of disk space. */
return(FX_NO_MORE_SPACE);
}
/* Now we need to find the consecutive clusters. */
clusters = media_ptr -> fx_media_fault_tolerant_clusters;
FAT_index = FX_FAT_ENTRY_START;
found = FX_FALSE;
while (FAT_index <= (media_ptr -> fx_media_total_clusters - clusters + FX_FAT_ENTRY_START))
{
/* Determine if enough consecutive FAT entries are available. */
i = 0;
do
{
/* Read a FAT entry. */
status = _fx_utility_FAT_entry_read(media_ptr, (FAT_index + i), &FAT_value);
/* Check for a successful status. */
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
/* Determine if the entry is free. */
if (FAT_value != FX_FREE_CLUSTER)
{
break;
}
/* Otherwise, increment the consecutive FAT indices. */
i++;
} while (i < clusters);
/* Determine if we found enough FAT entries. */
if (i >= clusters)
{
/* Yes, we have found enough FAT entries - set the found
flag and get out of this loop. */
found = FX_TRUE;
break;
}
else
{
/* Position to the next possibly free FAT entry. */
FAT_index = FAT_index + i + 1;
}
}
/* Determine if we found enough consecutive clusters to satisfy the
request. */
if (!found)
{
/* Not enough contiguous space on the media. Return error status. */
return(FX_NO_MORE_SPACE);
}
/* Update the link pointers in the new clusters. */
for (i = 0; i < (clusters - 1); i++)
{
/* Update the cluster links. Since the allocation is
sequential, we just have to link each FAT entry to the
next one. */
status = _fx_utility_FAT_entry_write(media_ptr, FAT_index + i, FAT_index + i + 1);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
}
/* Now place an EOF in the last cluster entry. */
status = _fx_utility_FAT_entry_write(media_ptr, FAT_index + clusters - 1, media_ptr -> fx_media_fat_last);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
#ifdef FX_FAULT_TOLERANT
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
#endif /* FX_FAULT_TOLERANT */
/* Write start cluster for the file tolerant log file into the boot sector. */
_fx_utility_32_unsigned_write(media_ptr -> fx_media_fault_tolerant_memory_buffer + FX_FAULT_TOLERANT_BOOT_INDEX, FAT_index);
/* Write the boot sector. */
media_ptr -> fx_media_driver_request = FX_DRIVER_BOOT_WRITE;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
media_ptr -> fx_media_driver_buffer = media_ptr -> fx_media_fault_tolerant_memory_buffer;
media_ptr -> fx_media_driver_sectors = 1;
media_ptr -> fx_media_driver_sector_type = FX_BOOT_SECTOR;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_BOOT_WRITE, media_ptr, media_ptr -> fx_media_fault_tolerant_memory_buffer, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Invoke the driver to read the boot sector. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Determine if the boot sector was read correctly. */
if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
{
/* Return the boot sector error status. */
return(FX_BOOT_ERROR);
}
/* Set the start cluster. */
media_ptr -> fx_media_fault_tolerant_start_cluster = FAT_index;
/* Decrease available cluster. */
media_ptr -> fx_media_available_clusters =
media_ptr -> fx_media_available_clusters - clusters;
/* Return success. */
return(FX_SUCCESS);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
+500
View File
@@ -0,0 +1,500 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_utility.h"
#include "fx_directory.h"
#include "fx_fault_tolerant.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_enable PORTABLE C */
/* 6.2.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function enables the FileX Fault Tolerant feature. It first */
/* searches for a valid log file. A valid log file indicates the */
/* previous write operation failed, and appropriate action now must */
/* be taken to restore the integrity of the file system. Once the */
/* recovery effort is completed, the file system is properly restored. */
/* An empty log file indicates the previous write operation was */
/* successfully completed and no action needs to be taken at this */
/* point. If the file system does not have a log file, or the */
/* checksum is not valid, it is an indication either the file system */
/* is not under the protection of FileX Fault Tolerant. A new log */
/* file is created. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* memory_buffer Pointer to memory buffer. */
/* memory_size Size of memory buffer. */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_fault_tolerant_calculate_checksum Compute Checksum of data */
/* _fx_fault_tolerant_apply_logs Apply logs into file system */
/* _fx_fault_tolerant_recover Recover FAT chain */
/* _fx_fault_tolerant_reset_log_file Reset the log file */
/* _fx_fault_tolerant_read_log_file Read log file to cache */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* _fx_utility_16_unsigned_read Read a USHORT from memory */
/* _fx_utility_32_unsigned_read Read a ULONG from memory */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 10-31-2022 Tiejun Zhou Modified comment(s), */
/* fixed memory buffer when */
/* cache is disabled, */
/* resulting in version 6.2.0 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_enable(FX_MEDIA *media_ptr, VOID *memory_buffer, UINT memory_size)
{
ULONG start_cluster;
ULONG FAT_value;
UINT status;
ULONG checksum;
ULONG total_size;
FX_FAULT_TOLERANT_LOG_HEADER *log_header;
FX_FAULT_TOLERANT_FAT_CHAIN *FAT_chain;
ULONG cluster_number;
ULONG i, j;
ULONG FAT_entry, FAT_sector, FAT_read_sectors;
ULONG bytes_in_buffer;
ULONG clusters;
ULONG bytes_per_sector;
ULONG bytes_per_cluster;
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Calculate clusters needed for fault tolerant log. */
bytes_per_sector = media_ptr -> fx_media_bytes_per_sector;
bytes_per_cluster = bytes_per_sector * media_ptr -> fx_media_sectors_per_cluster;
if (bytes_per_cluster == 0)
{
/* Release media protection. */
FX_UNPROTECT
return(FX_MEDIA_INVALID);
}
clusters = (FX_FAULT_TOLERANT_MAXIMUM_LOG_FILE_SIZE + bytes_per_cluster - 1) / bytes_per_cluster;
media_ptr -> fx_media_fault_tolerant_clusters = clusters;
/* Check buffer size requirement. */
if (memory_size < bytes_per_sector)
{
/* Release media protection. */
FX_UNPROTECT
return(FX_NOT_ENOUGH_MEMORY);
}
if (media_ptr -> fx_media_FAT32_additional_info_sector)
{
/* A 32-bit FAT is present. Read directly into the logical sector
cache memory to optimize I/O on larger devices. Since we are looking for
values of zero, endian issues are not important. */
/* Force update the available cluster. */
#ifndef FX_DISABLE_CACHE
/* Invalidate the current logical sector cache. */
_fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64) (media_ptr -> fx_media_total_sectors), FX_TRUE);
/* Reset the memory pointer. */
media_ptr -> fx_media_memory_buffer = media_ptr -> fx_media_sector_cache[0].fx_cached_sector_memory_buffer;
#endif /* FX_DISABLE_CACHE */
/* Reset the available cluster. */
media_ptr -> fx_media_available_clusters = 0;
/* Loop through all FAT sectors in the primary FAT. The first two entries are
examined in this loop, but they are always unavailable. */
cluster_number = 0;
#ifndef FX_DISABLE_CACHE
for (i = 0; i < media_ptr -> fx_media_sectors_per_FAT; i = i + media_ptr -> fx_media_sector_cache_size)
{
/* Calculate the starting next FAT sector. */
FAT_sector = media_ptr -> fx_media_reserved_sectors + i;
/* Calculate how many sectors to read. */
FAT_read_sectors = media_ptr -> fx_media_sectors_per_FAT - i;
/* Determine if there is not enough memory to read the remaining FAT sectors. */
if (FAT_read_sectors > media_ptr -> fx_media_sector_cache_size)
{
FAT_read_sectors = media_ptr -> fx_media_sector_cache_size;
}
#else
/* Reset the buffer sector. */
media_ptr -> fx_media_memory_buffer_sector = (ULONG64)-1;
for (i = 0; i < media_ptr -> fx_media_sectors_per_FAT; i++)
{
/* Calculate the starting next FAT sector. */
FAT_sector = media_ptr -> fx_media_reserved_sectors + i;
/* Calculate how many sectors to read. */
FAT_read_sectors = 1;
#endif /* FX_DISABLE_CACHE */
/* Read the FAT sectors directly from the driver. */
media_ptr -> fx_media_driver_request = FX_DRIVER_READ;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
media_ptr -> fx_media_driver_buffer = media_ptr -> fx_media_memory_buffer;
media_ptr -> fx_media_driver_logical_sector = FAT_sector;
media_ptr -> fx_media_driver_sectors = FAT_read_sectors;
media_ptr -> fx_media_driver_sector_type = FX_FAT_SECTOR;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_READ, media_ptr, FAT_sector, FAT_read_sectors, media_ptr -> fx_media_memory_buffer, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Invoke the driver to read the FAT sectors. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Determine if the read was successful. */
if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
return(FX_FAT_READ_ERROR);
}
/* Calculate the number of bytes in the buffer. */
bytes_in_buffer = (media_ptr -> fx_media_bytes_per_sector * FAT_read_sectors);
/* Walk through the sector cache memory to search for available clusters and the first
available if not already found. */
for (j = 0; j < bytes_in_buffer;)
{
/* Pickup 32-bit FAT entry. */
FAT_entry = *((ULONG *)&(media_ptr -> fx_media_memory_buffer[j]));
/* Advance to next FAT entry. */
j = j + 4;
/* Determine if the FAT entry is free. */
if (FAT_entry == FX_FREE_CLUSTER)
{
/* Entry is free, increment available clusters. */
media_ptr -> fx_media_available_clusters++;
/* Determine if the starting free cluster has been found yet. */
if (media_ptr -> fx_media_cluster_search_start == 0)
{
/* Remember the first free cluster to start further searches from. */
media_ptr -> fx_media_cluster_search_start = cluster_number;
}
}
/* Increment the cluster number. */
cluster_number++;
/* Determine if we have reviewed all FAT entries. */
if (cluster_number >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
{
/* Yes, we have looked at all the FAT entries. */
/* Ensure that the outer loop terminates as well. */
i = media_ptr -> fx_media_sectors_per_FAT;
break;
}
}
}
}
/* Store memory buffer and size. */
media_ptr -> fx_media_fault_tolerant_memory_buffer = (UCHAR *)memory_buffer;
if (memory_size > (clusters * bytes_per_cluster))
{
media_ptr -> fx_media_fault_tolerant_memory_buffer_size = clusters * bytes_per_cluster;
}
else
{
media_ptr -> fx_media_fault_tolerant_memory_buffer_size = memory_size / bytes_per_sector * bytes_per_sector;
}
/* Read the boot sector from the device. */
media_ptr -> fx_media_driver_request = FX_DRIVER_BOOT_READ;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
media_ptr -> fx_media_driver_buffer = (UCHAR *)memory_buffer;
media_ptr -> fx_media_driver_sectors = 1;
media_ptr -> fx_media_driver_sector_type = FX_BOOT_SECTOR;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_BOOT_READ, media_ptr, memory_buffer, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Invoke the driver to read the boot sector. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Determine if the boot sector was read correctly. */
if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the boot sector error status. */
return(FX_BOOT_ERROR);
}
/* Check whether the boot index is used. */
start_cluster = _fx_utility_32_unsigned_read((UCHAR *)memory_buffer + FX_FAULT_TOLERANT_BOOT_INDEX);
if (start_cluster != 0)
{
/* The location of the fault tolerant log file is found. Need to verify the integrity of the log file. */
if ((start_cluster >= FX_FAT_ENTRY_START) && (start_cluster < media_ptr -> fx_media_fat_reserved))
{
/* Check whether this cluster is used. */
for (i = 0; i < clusters; i++)
{
/* Read FAT entry. */
status = _fx_utility_FAT_entry_read(media_ptr, start_cluster + i, &FAT_value);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
if (i < clusters - 1)
{
if (FAT_value != (start_cluster + i + 1))
{
/* Mark invalid. */
start_cluster = 0;
break;
}
}
else if (FAT_value != media_ptr -> fx_media_fat_last)
{
/* Mark invalid. */
start_cluster = 0;
break;
}
}
/* Is this FAT entry occupied by log file? */
if (start_cluster)
{
/* Set the start cluster. */
media_ptr -> fx_media_fault_tolerant_start_cluster = start_cluster;
/* Read log file from file system to memory. */
status = _fx_fault_tolerant_read_log_file(media_ptr);
/* Check for good completion status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Set log header and FAT chain pointer. */
log_header = (FX_FAULT_TOLERANT_LOG_HEADER *)media_ptr -> fx_media_fault_tolerant_memory_buffer;
FAT_chain = (FX_FAULT_TOLERANT_FAT_CHAIN *)(media_ptr -> fx_media_fault_tolerant_memory_buffer +
FX_FAULT_TOLERANT_FAT_CHAIN_OFFSET);
/* Verify ID field. */
if (_fx_utility_32_unsigned_read((UCHAR *)&log_header -> fx_fault_tolerant_log_header_id) == FX_FAULT_TOLERANT_ID)
{
/* Calculate checksum of log header. */
checksum = _fx_fault_tolerant_calculate_checksum((UCHAR *)log_header,
FX_FAULT_TOLERANT_LOG_HEADER_SIZE);
if (checksum == 0)
{
/* Fault tolerant log file is valid. */
/* Initialize file size. */
total_size = _fx_utility_16_unsigned_read((UCHAR *)&log_header -> fx_fault_tolerant_log_header_total_size);
media_ptr -> fx_media_fault_tolerant_file_size = total_size;
/* Verify the checksum of the FAT chain. */
checksum = _fx_fault_tolerant_calculate_checksum((UCHAR *)FAT_chain,
FX_FAULT_TOLERANT_FAT_CHAIN_SIZE);
if (checksum == 0)
{
/* Checksum of FAT chain is correct. */
if (total_size > (FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET + FX_FAULT_TOLERANT_LOG_HEADER_SIZE))
{
/* Log content is present. */
/* Now verify the checksum of log content. */
checksum = _fx_fault_tolerant_calculate_checksum((media_ptr -> fx_media_fault_tolerant_memory_buffer +
FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET),
(total_size - FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET));
if (checksum == 0)
{
/* Checksum of log content is correct. */
/* Extended port-specific processing macro, which is by default defined to white space. */
FX_FAULT_TOLERANT_ENABLE_EXTENSION
/* This is the situation where the log file contains log entries. This is an indication
that previous write operation did not complete successfully. Need to apply the log entries
to recover the previous write operation, effectively to finish up the previous write operation. */
status = _fx_fault_tolerant_apply_logs(media_ptr);
}
}
else
{
/* Extended port-specific processing macro, which is by default defined to white space. */
FX_FAULT_TOLERANT_ENABLE_EXTENSION
/* The log file does not contain log content but the FAT chain operation information is present.
This is the situation where the FAT chain has been modified but the rest of the content of these
clusters are not updated yet. In this situation, the previous FAT chain operation needs to be
reverted to restore the file system back to its state prior to the write operation. */
status = _fx_fault_tolerant_recover(media_ptr);
}
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
}
}
}
}
}
else
{
/* Not a valid cluster number. Set the flag to create a new log file. */
start_cluster = 0;
}
}
/* Check whether or not to create a log file. */
if (start_cluster == 0)
{
/* Create log file. */
status = _fx_fault_tolerant_create_log_file(media_ptr);
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
}
/* Reset log file. */
status = _fx_fault_tolerant_reset_log_file(media_ptr);
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Mark fault tolerant feature is enabled. */
media_ptr -> fx_media_fault_tolerant_enabled = FX_TRUE;
/* Reset the transaction count. */
media_ptr -> fx_media_fault_tolerant_transaction_count = 0;
/* Initialize the sector number of cached FAT entries. */
media_ptr -> fx_media_fault_tolerant_cached_FAT_sector = 0;
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(FX_SUCCESS);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
+167
View File
@@ -0,0 +1,167 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_utility.h"
#include "fx_fault_tolerant.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_read_FAT PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function reads value of a FAT entry from log file if it */
/* exists. During file or directory operations with Fault Tolerant */
/* protection, intermediate operations are written to the fault */
/* tolerant log files. Therefore, FAT-entry read should search for */
/* fault tolerant log before the request can be passed to normal FAT */
/* entry read routine. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* cluster Cluster entry number */
/* value Pointer to value for the entry*/
/* log_type FAT or bitmap */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_16_unsigned_read Read a USHORT from memory */
/* _fx_utility_32_unsigned_read Read a ULONG from memory */
/* */
/* CALLED BY */
/* */
/* _fx_utility_FAT_entry_read */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_read_FAT(FX_MEDIA *media_ptr, ULONG cluster, ULONG *value, ULONG log_type)
{
ULONG logs_remaining;
UCHAR *current_ptr;
UCHAR found = FX_FALSE;
ULONG size;
USHORT type;
ULONG log_len;
FX_FAULT_TOLERANT_FAT_LOG *fat_log;
/* Get fault tolerant data. */
logs_remaining = media_ptr -> fx_media_fault_tolerant_total_logs;
/* Any redo logs? */
if (logs_remaining == 0)
{
/* No. Just return. */
return(FX_READ_CONTINUE);
}
/* Get size of all logs. */
size = media_ptr -> fx_media_fault_tolerant_file_size - FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET;
/* Get the first log pointer. */
current_ptr = media_ptr -> fx_media_fault_tolerant_memory_buffer +
FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET +
FX_FAULT_TOLERANT_LOG_CONTENT_HEADER_SIZE;
/* Loop throught all FAT logs. */
while (logs_remaining)
{
/* Check log type. */
type = (USHORT)_fx_utility_16_unsigned_read(current_ptr);
/* Get log length. */
log_len = _fx_utility_16_unsigned_read(current_ptr + 2);
/* Validate the size value. */
if (log_len > size)
{
/* Log file is corrupted. Nothing can be done. Return.*/
return(FX_FILE_CORRUPT);
}
size -= log_len;
/* Check log type. */
if (type == log_type)
{
/* This is the log with same type . */
/* Get the log pointer. */
fat_log = (FX_FAULT_TOLERANT_FAT_LOG *)current_ptr;
/* Is this FAT log entry the one looking for? */
if (_fx_utility_32_unsigned_read((UCHAR *)&fat_log -> fx_fault_tolerant_FAT_log_cluster) == cluster)
{
/* Yes, it is. */
*value = _fx_utility_32_unsigned_read((UCHAR *)&fat_log -> fx_fault_tolerant_FAT_log_value);
/* Do not return since there may be more than one log for this cluster. */
found = FX_TRUE;
}
}
/* Decrease the logs_remaining counter. */
logs_remaining--;
/* Get next log pointer. */
current_ptr += log_len;
}
if (found != FX_TRUE)
{
/* Pass the request to FAT entry read. */
return(FX_READ_CONTINUE);
}
/* Return success. */
return(FX_SUCCESS);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
@@ -0,0 +1,178 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_utility.h"
#include "fx_fault_tolerant.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_read_directory_sector PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function handles directory sector read requests. During file or*/
/* directory operations with Fault Tolerant protection, intermediate */
/* operations are written to the fault tolerant log files. Therefore, */
/* sector read should search for fault tolerant log before the request */
/* can be passed to normal directory entry read routine. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* logical_sector Logical sector number */
/* buffer_ptr Pointer of receiving buffer */
/* sectors Number of sectors to read */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_16_unsigned_read Read a USHORT from memory */
/* _fx_utility_32_unsigned_read Read a ULONG from memory */
/* memcpy Memory Copy */
/* */
/* CALLED BY */
/* */
/* _fx_utility_logical_sector_read */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), verified */
/* memcpy usage, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_read_directory_sector(FX_MEDIA *media_ptr, ULONG64 logical_sector,
VOID *buffer_ptr, ULONG64 sectors)
{
ULONG logs_remaining;
ULONG copy_offset;
ULONG copy_size;
UCHAR *current_ptr;
UCHAR *current_buffer_ptr;
ULONG size;
USHORT type;
ULONG log_len;
ULONG64 log_sector;
FX_FAULT_TOLERANT_DIR_LOG *dir_log;
/* Get fault tolerant data. */
logs_remaining = media_ptr -> fx_media_fault_tolerant_total_logs;
/* Any redo logs? */
if (logs_remaining == 0)
{
/* No. Just return. */
return(FX_SUCCESS);
}
/* Get size of all logs. */
size = media_ptr -> fx_media_fault_tolerant_file_size - FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET;
/* Get the first log pointer. */
current_ptr = media_ptr -> fx_media_fault_tolerant_memory_buffer +
FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET +
FX_FAULT_TOLERANT_LOG_CONTENT_HEADER_SIZE;
/* Loop throught all FAT logs. */
while (logs_remaining)
{
/* Check log type. */
type = (USHORT)_fx_utility_16_unsigned_read(current_ptr);
/* Get log length. */
log_len = _fx_utility_16_unsigned_read(current_ptr + 2);
/* Validate the size value. */
if (log_len > size)
{
/* Log file is corrupted. Nothing can be done. Return.*/
return(FX_FILE_CORRUPT);
}
size -= log_len;
/* Check log type. */
if (type == FX_FAULT_TOLERANT_DIR_LOG_TYPE)
{
/* Get the log pointer. */
dir_log = (FX_FAULT_TOLERANT_DIR_LOG *)current_ptr;
/* Get the sector of log. */
log_sector = _fx_utility_64_unsigned_read((UCHAR *)&dir_log -> fx_fault_tolerant_dir_log_sector);
/* Is this log sector in the range of sectors to read? */
if ((log_sector >= logical_sector) && (log_sector < logical_sector + sectors))
{
/* Yes. Update the content in this sector. */
current_buffer_ptr = ((UCHAR *)buffer_ptr) + (log_sector - logical_sector) *
media_ptr -> fx_media_bytes_per_sector;
/* Set copy information. */
copy_offset = _fx_utility_32_unsigned_read((UCHAR *)&dir_log -> fx_fault_tolerant_dir_log_offset);
copy_size = log_len - FX_FAULT_TOLERANT_DIR_LOG_ENTRY_SIZE;
if ((copy_offset + copy_size) > media_ptr -> fx_media_bytes_per_sector)
{
return(FX_FILE_CORRUPT);
}
/* Copy data into destination sector. */
memcpy(current_buffer_ptr + copy_offset, /* Use case of memcpy is verified. */
current_ptr + FX_FAULT_TOLERANT_DIR_LOG_ENTRY_SIZE, copy_size);
}
}
/* Decrease the logs_remaining counter. */
logs_remaining--;
/* Move to start position of next log entry. */
current_ptr += log_len;
}
/* Return success. */
return(FX_SUCCESS);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
@@ -0,0 +1,93 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_utility.h"
#include "fx_fault_tolerant.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_read_log_file PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function reads the entire log file from file system into the */
/* fault tolerant cache. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_logical_sector_read Read a logical sector */
/* */
/* CALLED BY */
/* */
/* _fx_fault_tolerant_enable */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_read_log_file(FX_MEDIA *media_ptr)
{
UINT status;
ULONG sectors;
ULONG start_sector;
/* Calculate count of sectors to read. */
sectors = media_ptr -> fx_media_fault_tolerant_memory_buffer_size / media_ptr -> fx_media_bytes_per_sector;
/* Calculate the start sector of log file. */
start_sector = (media_ptr -> fx_media_fault_tolerant_start_cluster - FX_FAT_ENTRY_START) *
media_ptr -> fx_media_sectors_per_cluster +
media_ptr -> fx_media_data_sector_start;
status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) start_sector,
media_ptr -> fx_media_fault_tolerant_memory_buffer,
sectors, FX_DATA_SECTOR);
/* Return the status. */
return(status);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
+159
View File
@@ -0,0 +1,159 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_utility.h"
#include "fx_fault_tolerant.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_recover PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is called after the FAT chain is been updated but */
/* the rest of the write operation fails. At this point, there is */
/* need to undo the FAT chain operation, which includes: */
/* (1) Remove newly allocated FAT entries; */
/* (2) Restore the origianl FAT chain removed during the FAT chain */
/* update; */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_fault_tolerant_cleanup_FAT_chain Cleanup FAT chain */
/* _fx_utility_32_unsigned_read Read a ULONG from memory */
/* _fx_utility_FAT_entry_write Write a FAT entry */
/* _fx_utility_FAT_flush Flush written FAT entries */
/* */
/* CALLED BY */
/* */
/* _fx_directory_attributes_set */
/* _fx_directory_create */
/* _fx_directory_delete */
/* _fx_directory_rename */
/* _fx_file_allocate */
/* _fx_file_attributes_set */
/* _fx_file_best_effort_allocate */
/* _fx_file_create */
/* _fx_file_delete */
/* _fx_file_rename */
/* _fx_file_truncate */
/* _fx_file_truncate_release */
/* _fx_file_write */
/* _fx_unicode_directory_create */
/* _fx_unicode_file_create */
/* _fx_fault_tolerant_enable */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_recover(FX_MEDIA *media_ptr)
{
UINT status;
ULONG insertion_front;
ULONG origianl_head_cluster;
FX_FAULT_TOLERANT_FAT_CHAIN *FAT_chain;
/* Set fault tolerant state to IDLE. */
media_ptr -> fx_media_fault_tolerant_state = FX_FAULT_TOLERANT_STATE_IDLE;
/* Set FAT chain pointer. */
FAT_chain = (FX_FAULT_TOLERANT_FAT_CHAIN *)(media_ptr -> fx_media_fault_tolerant_memory_buffer + FX_FAULT_TOLERANT_FAT_CHAIN_OFFSET);
/* Whether or not the supplied FAT chain is valid. */
if (!(FAT_chain -> fx_fault_tolerant_FAT_chain_flag & FX_FAULT_TOLERANT_FLAG_FAT_CHAIN_VALID))
{
/* Invalid, which indiates the FAT chain has been cleaned up already. In this case, just return. */
return(FX_SUCCESS);
}
/* Set FAT chain pointer. */
FAT_chain = (FX_FAULT_TOLERANT_FAT_CHAIN *)(media_ptr -> fx_media_fault_tolerant_memory_buffer + FX_FAULT_TOLERANT_FAT_CHAIN_OFFSET);
/* Recover FAT chain. */
status = _fx_fault_tolerant_cleanup_FAT_chain(media_ptr, FX_FAULT_TOLERANT_FAT_CHAIN_RECOVER);
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
/* Now, link the front of the insertion point back to the origianl FAT chain. */
insertion_front = _fx_utility_32_unsigned_read((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_insertion_front);
origianl_head_cluster = _fx_utility_32_unsigned_read((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_head_original);
if (insertion_front != FX_FREE_CLUSTER)
{
/* Front of the insertion point exists. Link the origianl chain back to the front of the insertion point. */
status = _fx_utility_FAT_entry_write(media_ptr, insertion_front, origianl_head_cluster);
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
}
/* New FAT chain is always linked by FAT entries. */
/* Flush FAT table. */
#ifdef FX_FAULT_TOLERANT
/* Ensure the new FAT chain is properly written to the media. */
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
#endif
/* Return success. */
return(FX_SUCCESS);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
@@ -0,0 +1,142 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_utility.h"
#include "fx_directory.h"
#include "fx_fault_tolerant.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_reset_log_file PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function removes all log entries from the log file, and */
/* it to its initial state. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_16_unsigned_write Write a USHORT from memory */
/* _fx_utility_32_unsigned_write Write a ULONG from memory */
/* _fx_fault_tolerant_calculate_checksum Compute Checksum of data */
/* _fx_fault_tolerant_write_log_file Write log file */
/* */
/* CALLED BY */
/* */
/* _fx_directory_attributes_set */
/* _fx_directory_create */
/* _fx_directory_delete */
/* _fx_directory_rename */
/* _fx_file_allocate */
/* _fx_file_attributes_set */
/* _fx_file_best_effort_allocate */
/* _fx_file_create */
/* _fx_file_delete */
/* _fx_file_rename */
/* _fx_file_truncate */
/* _fx_file_truncate_release */
/* _fx_file_write */
/* _fx_unicode_directory_create */
/* _fx_unicode_file_create */
/* _fx_fault_tolerant_enable */
/* _fx_fault_tolerant_transaction_end */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_reset_log_file(FX_MEDIA *media_ptr)
{
UINT status;
USHORT checksum;
FX_FAULT_TOLERANT_LOG_HEADER *log_header;
FX_FAULT_TOLERANT_FAT_CHAIN *FAT_chain;
FX_FAULT_TOLERANT_LOG_CONTENT *log_content;
/* Set log header, FAT chain and log content pointer. */
log_header = (FX_FAULT_TOLERANT_LOG_HEADER *)media_ptr -> fx_media_fault_tolerant_memory_buffer;
FAT_chain = (FX_FAULT_TOLERANT_FAT_CHAIN *)(media_ptr -> fx_media_fault_tolerant_memory_buffer +
FX_FAULT_TOLERANT_FAT_CHAIN_OFFSET);
log_content = (FX_FAULT_TOLERANT_LOG_CONTENT *)(media_ptr -> fx_media_fault_tolerant_memory_buffer +
FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET);
/* Reset the log file header. */
_fx_utility_32_unsigned_write((UCHAR *)&log_header -> fx_fault_tolerant_log_header_id, FX_FAULT_TOLERANT_ID);
_fx_utility_16_unsigned_write((UCHAR *)&log_header -> fx_fault_tolerant_log_header_total_size,
(FX_FAULT_TOLERANT_LOG_HEADER_SIZE + FX_FAULT_TOLERANT_FAT_CHAIN_SIZE));
_fx_utility_16_unsigned_write((UCHAR *)&log_header -> fx_fault_tolerant_log_header_checksum, 0);
log_header -> fx_fault_tolerant_log_header_version_major = FX_FAULT_TOLERANT_VERSION_MAJOR;
log_header -> fx_fault_tolerant_log_header_version_minor = FX_FAULT_TOLERANT_VERSION_MINOR;
_fx_utility_16_unsigned_write((UCHAR *)&log_header -> fx_fault_tolerant_log_header_reserved, 0);
checksum = _fx_fault_tolerant_calculate_checksum((UCHAR *)log_header, FX_FAULT_TOLERANT_LOG_HEADER_SIZE);
_fx_utility_16_unsigned_write((UCHAR *)&log_header -> fx_fault_tolerant_log_header_checksum, checksum);
/* Reset the undo log section. */
_fx_utility_16_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_checksumm, 0xFFFF);
FAT_chain -> fx_fault_tolerant_FAT_chain_flag = 0;
FAT_chain -> fx_fault_tolerant_FAT_chain_reserved = 0;
_fx_utility_32_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_insertion_front, 0);
_fx_utility_32_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_head_new, 0);
_fx_utility_32_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_head_original, 0);
_fx_utility_32_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_insertion_back, 0);
_fx_utility_32_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_next_deletion, 0);
/* Reset log content header. */
_fx_utility_16_unsigned_write((UCHAR *)&log_content -> fx_fault_tolerant_log_content_checksum, 0xFFFF);
_fx_utility_16_unsigned_write((UCHAR *)&log_content -> fx_fault_tolerant_log_content_count, 0xFFFF);
/* No matter success or fail, close this transaction. */
media_ptr -> fx_media_fault_tolerant_state = FX_FAULT_TOLERANT_STATE_IDLE;
/* Write the log header and FAT chain. */
status = _fx_fault_tolerant_write_log_file(media_ptr, 0);
/* Return the status. */
return(status);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
@@ -0,0 +1,125 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_utility.h"
#include "fx_fault_tolerant.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_set_FAT_chain PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets data of FAT chain. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* use_bitmap Whether or not the orignal */
/* FAT chain uses bitmap */
/* insertion_front Previous cluster of head */
/* new_head_cluster Head cluster of new chain */
/* origianl_head_cluster Head cluster of the original */
/* chain */
/* insertion_back next cluster of chain tail */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_16_unsigned_write Write a USHORT from memory */
/* _fx_utility_32_unsigned_write Write a ULONG from memory */
/* _fx_fault_tolerant_calculate_checksum Compute Checksum of data */
/* _fx_fault_tolerant_write_log_file Write log file */
/* */
/* CALLED BY */
/* */
/* _fx_file_allocate */
/* _fx_file_best_effort_allocate */
/* _fx_file_delete */
/* _fx_file_truncate_release */
/* _fx_file_write */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_set_FAT_chain(FX_MEDIA *media_ptr, UINT use_bitmap, ULONG insertion_front,
ULONG new_head_cluster, ULONG original_head_cluster,
ULONG insertion_back)
{
UINT status;
USHORT checksum;
UCHAR flag = FX_FAULT_TOLERANT_FLAG_FAT_CHAIN_VALID;
FX_FAULT_TOLERANT_FAT_CHAIN *FAT_chain;
/* Set FAT chain pointer. */
FAT_chain = (FX_FAULT_TOLERANT_FAT_CHAIN *)(media_ptr -> fx_media_fault_tolerant_memory_buffer + FX_FAULT_TOLERANT_FAT_CHAIN_OFFSET);
/* Parameters not used. Avoid compiler warnings. */
FX_PARAMETER_NOT_USED(use_bitmap);
/* Reset checksum first. */
_fx_utility_16_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_checksumm, 0);
/* Set clusters. */
_fx_utility_32_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_insertion_front, insertion_front);
_fx_utility_32_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_head_new, new_head_cluster);
_fx_utility_32_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_head_original, original_head_cluster);
_fx_utility_32_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_insertion_back, insertion_back);
_fx_utility_32_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_next_deletion, FX_FREE_CLUSTER);
/* Set flag and reserved. */
FAT_chain -> fx_fault_tolerant_FAT_chain_flag = flag;
FAT_chain -> fx_fault_tolerant_FAT_chain_reserved = (UCHAR)0;
/* Calculate checksum. */
checksum = _fx_fault_tolerant_calculate_checksum((UCHAR *)FAT_chain, FX_FAULT_TOLERANT_FAT_CHAIN_SIZE);
_fx_utility_16_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_checksumm, checksum);
/* Write the log header and FAT chain. */
status = _fx_fault_tolerant_write_log_file(media_ptr, 0);
/* Return the status. */
return(status);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
@@ -0,0 +1,207 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_fault_tolerant.h"
#include "fx_utility.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_transaction_end PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function completes a file system update operation protected */
/* by fault tolerant. This function first computes the checksum */
/* for the log entries, flush the log file to the file system (a */
/* necessary step to record vital information for the file system to */
/* recover, in case the update operation fails midway). After the */
/* log entries are written to the physical medium, the actualy file */
/* system changes (FAT table, directory entries) are applied. */
/* */
/* If the file system changes are successfully applied, the log */
/* entries can be removed. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_16_unsigned_write Write a USHORT from memory */
/* _fx_fault_tolerant_apply_logs Apply logs into file system */
/* _fx_fault_tolerant_calculate_checksum Compute Checksum of data */
/* _fx_fault_tolerant_write_log_file Write log file */
/* _fx_fault_tolerant_reset_log_file Reset the log file */
/* */
/* CALLED BY */
/* */
/* _fx_directory_attributes_set */
/* _fx_directory_create */
/* _fx_directory_delete */
/* _fx_directory_rename */
/* _fx_file_allocate */
/* _fx_file_attributes_set */
/* _fx_file_best_effort_allocate */
/* _fx_file_create */
/* _fx_file_delete */
/* _fx_file_rename */
/* _fx_file_truncate */
/* _fx_file_truncate_release */
/* _fx_file_write */
/* _fx_unicode_directory_create */
/* _fx_unicode_file_create */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_transaction_end(FX_MEDIA *media_ptr)
{
ULONG relative_sector;
UINT status;
USHORT checksum;
UINT offset;
FX_FAULT_TOLERANT_LOG_HEADER *log_header;
FX_FAULT_TOLERANT_LOG_CONTENT *log_content;
/* Is fault tolerant enabled? */
if (media_ptr -> fx_media_fault_tolerant_enabled == FX_FALSE)
{
return(FX_SUCCESS);
}
/* Decrease the transaction. */
media_ptr -> fx_media_fault_tolerant_transaction_count--;
/* Is transaction finished? */
if (media_ptr -> fx_media_fault_tolerant_transaction_count != 0)
{
return(FX_SUCCESS);
}
/* Close this transaction. */
media_ptr -> fx_media_fault_tolerant_state = FX_FAULT_TOLERANT_STATE_IDLE;
/* Set log header and FAT chain pointer. */
log_header = (FX_FAULT_TOLERANT_LOG_HEADER *)media_ptr -> fx_media_fault_tolerant_memory_buffer;
log_content = (FX_FAULT_TOLERANT_LOG_CONTENT *)(media_ptr -> fx_media_fault_tolerant_memory_buffer +
FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET);
/* Reset checksum field and update log entry counter field. */
_fx_utility_16_unsigned_write((UCHAR *)&log_content -> fx_fault_tolerant_log_content_checksum, 0);
_fx_utility_16_unsigned_write((UCHAR *)&log_content -> fx_fault_tolerant_log_content_count,
media_ptr -> fx_media_fault_tolerant_total_logs);
/* Now calculate the checksum of log content. */
checksum = _fx_fault_tolerant_calculate_checksum((media_ptr -> fx_media_fault_tolerant_memory_buffer +
FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET),
(media_ptr -> fx_media_fault_tolerant_file_size -
FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET));
/* Record checksum field of log content. */
_fx_utility_16_unsigned_write((UCHAR *)&log_content -> fx_fault_tolerant_log_content_checksum, checksum);
/* Record log header. */
_fx_utility_16_unsigned_write((UCHAR *)&log_header -> fx_fault_tolerant_log_header_total_size,
media_ptr -> fx_media_fault_tolerant_file_size);
_fx_utility_16_unsigned_write((UCHAR *)&log_header -> fx_fault_tolerant_log_header_checksum, 0);
/* Calculate checksum of the header. */
checksum = _fx_fault_tolerant_calculate_checksum((UCHAR *)log_header, FX_FAULT_TOLERANT_LOG_HEADER_SIZE);
/* Record checksum field of the header. */
_fx_utility_16_unsigned_write((UCHAR *)&log_header -> fx_fault_tolerant_log_header_checksum, checksum);
/* Flush log content and flush first sector at last. The first sector contains size of total log file.
* The log file will contain wrong value of size when it is interrupted after first sector flushed to file system. */
relative_sector = 1;
offset = media_ptr -> fx_media_bytes_per_sector;
while (offset < media_ptr -> fx_media_fault_tolerant_file_size)
{
/* Write back the log. */
status = _fx_fault_tolerant_write_log_file(media_ptr, relative_sector);
/* Check for good completion status. */
if (status != FX_SUCCESS)
{
/* Error. */
return(status);
}
/* Increase relative sector and offset. */
relative_sector++;
offset += media_ptr -> fx_media_bytes_per_sector;
}
/* Flush first sector. */
status = _fx_fault_tolerant_write_log_file(media_ptr, 0);
/* Check for good completion status. */
if (status != FX_SUCCESS)
{
/* Error. */
return(status);
}
/* At this pointer, the vital information has been flushed to the physical medium.
Update the file system (FAT table, directory entry) using information recorded in the
log file. */
status = _fx_fault_tolerant_apply_logs(media_ptr);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
/* Return the bad status. */
return(status);
}
/* The file system has been updated successfully. Remove and reset the fault tolerant
log file. */
status = _fx_fault_tolerant_reset_log_file(media_ptr);
return(status);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
@@ -0,0 +1,105 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOUCE_CODE
#include "fx_api.h"
#include "fx_fault_tolerant.h"
#if defined(FX_ENABLE_FAULT_TOLERANT) && defined(FX_FAULT_TOLERANT_TRANSACTION_FAIL_FUNCTION)
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_transaction_fail PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function cleans up resources created by fault tolerant when */
/* transaction fails. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _fx_directory_attributes_set */
/* _fx_directory_create */
/* _fx_directory_delete */
/* _fx_directory_rename */
/* _fx_file_allocate */
/* _fx_file_attributes_set */
/* _fx_file_best_effort_allocate */
/* _fx_file_create */
/* _fx_file_delete */
/* _fx_file_rename */
/* _fx_file_truncate */
/* _fx_file_truncate_release */
/* _fx_file_write */
/* _fx_unicode_directory_create */
/* _fx_unicode_file_create */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_transaction_fail(FX_MEDIA *media_ptr)
{
/* Check whether fault tolerant is enabled or not. */
if (media_ptr -> fx_media_fault_tolerant_enabled == FX_TRUE)
{
/* Yes. Decrease the counter for transaction. */
media_ptr -> fx_media_fault_tolerant_transaction_count--;
/* Is this the last transaction? */
if (media_ptr -> fx_media_fault_tolerant_transaction_count == 0)
{
/* Yes. Perform recover and reset the log file. */
_fx_fault_tolerant_recover(media_ptr);
_fx_fault_tolerant_reset_log_file(media_ptr);
}
}
return(FX_SUCCESS);
}
#endif
@@ -0,0 +1,115 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_fault_tolerant.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_transaction_start PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is called at the beginning of an update to FileX */
/* file, directory entry, or FAT table. It resets fault tolerant */
/* internal state information. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _fx_directory_attributes_set */
/* _fx_directory_create */
/* _fx_directory_delete */
/* _fx_directory_rename */
/* _fx_file_allocate */
/* _fx_file_attributes_set */
/* _fx_file_best_effort_allocate */
/* _fx_file_create */
/* _fx_file_delete */
/* _fx_file_rename */
/* _fx_file_truncate */
/* _fx_file_truncate_release */
/* _fx_file_write */
/* _fx_unicode_directory_create */
/* _fx_unicode_file_create */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_transaction_start(FX_MEDIA *media_ptr)
{
/* Is fault tolerant enabled? */
if (media_ptr -> fx_media_fault_tolerant_enabled == FX_TRUE)
{
/* Is this a new transaction? */
if (media_ptr -> fx_media_fault_tolerant_transaction_count == 0)
{
/* Yes. Initialize data. */
media_ptr -> fx_media_fault_tolerant_file_size = FX_FAULT_TOLERANT_LOG_HEADER_SIZE +
FX_FAULT_TOLERANT_FAT_CHAIN_SIZE +
FX_FAULT_TOLERANT_LOG_CONTENT_HEADER_SIZE;
/* Reset total logs. */
media_ptr -> fx_media_fault_tolerant_total_logs = 0;
/* Set state of fault tolerant. */
media_ptr -> fx_media_fault_tolerant_state = FX_FAULT_TOLERANT_STATE_STARTED;
}
/* Increase the transaction. */
media_ptr -> fx_media_fault_tolerant_transaction_count++;
}
return(FX_SUCCESS);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
@@ -0,0 +1,112 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Fault Tolerant */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
#include "fx_api.h"
#include "fx_utility.h"
#include "fx_directory.h"
#include "fx_fault_tolerant.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_write_log_file PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function writes data of one sector of fault tolerant data */
/* from memory to log file in file system. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* relative_sector Relative sector number of the */
/* log file to write to */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_logical_sector_write Write a logical sector */
/* _fx_utility_logical_sector_flush Flush written logical sectors */
/* */
/* CALLED BY */
/* */
/* _fx_fault_tolerant_cleanup_FAT_chain */
/* _fx_fault_tolerant_reset_log_file */
/* _fx_fault_tolerant_set_FAT_chain */
/* _fx_fault_tolerant_transaction_end */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_write_log_file(FX_MEDIA *media_ptr, ULONG relative_sector)
{
UINT status;
ULONG start_sector;
/* Calculate the start sector of log file. */
start_sector = (media_ptr -> fx_media_fault_tolerant_start_cluster - FX_FAT_ENTRY_START) *
media_ptr -> fx_media_sectors_per_cluster +
media_ptr -> fx_media_data_sector_start;
/* Write sector directly. */
status = _fx_utility_logical_sector_write(media_ptr, (ULONG64) (start_sector + relative_sector),
media_ptr -> fx_media_fault_tolerant_memory_buffer +
media_ptr -> fx_media_bytes_per_sector * relative_sector,
((ULONG) 1), FX_DATA_SECTOR);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
/* Return the bad status. */
return(status);
}
/* Flush the internal logical sector cache. */
status = _fx_utility_logical_sector_flush(media_ptr, (ULONG64) start_sector, ((ULONG64) 1), FX_FALSE);
FX_FAULT_TOLERANT_WRITE_LOG_FILE_EXTENSION
/* Return the status. */
return(status);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
+84
View File
@@ -0,0 +1,84 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_file.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_allocate PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function attempts to allocate the number of consecutive */
/* clusters required to satisfy the user's request. If there are */
/* enough clusters, the clusters are allocated and linked to the file. */
/* Otherwise, if there are not enough consecutive clusters, an error */
/* code is returned to the caller. */
/* */
/* INPUT */
/* */
/* file_ptr File control block pointer */
/* size Number of bytes to allocate */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_file_extended_allocate Allocate the clusters */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), and */
/* Added conditional to */
/* disable one line function, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
#ifndef FX_DISABLE_ONE_LINE_FUNCTION
UINT _fx_file_allocate(FX_FILE *file_ptr, ULONG size)
{
return(_fx_file_extended_allocate(file_ptr, (ULONG64)size));
}
#endif /* FX_DISABLE_ONE_LINE_FUNCTION */
+158
View File
@@ -0,0 +1,158 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_attributes_read PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function first attempts to find the specified file. If found, */
/* the attribute read request is valid and the directory entry will be */
/* in order to pickup the file's attributes. Otherwise, if the file */
/* is not found, the appropriate error code is returned to the caller. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* file_name File name pointer */
/* attributes_ptr Return attributes pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_search Search for the file name in */
/* the directory structure */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_file_attributes_read(FX_MEDIA *media_ptr, CHAR *file_name, UINT *attributes_ptr)
{
UINT status;
FX_DIR_ENTRY dir_entry;
#ifdef TX_ENABLE_EVENT_TRACE
TX_TRACE_BUFFER_ENTRY *trace_event;
ULONG trace_timestamp;
#endif
UCHAR not_a_file_attr;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_file_attributes_reads++;
#endif
/* Setup pointer to media name buffer. */
dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Clear the short name string. */
dir_entry.fx_dir_entry_short_name[0] = 0;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
not_a_file_attr = FX_DIRECTORY | FX_VOLUME;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_ATTRIBUTES_READ, media_ptr, file_name, 0, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Search the system for the supplied file name. */
status = _fx_directory_search(media_ptr, file_name, &dir_entry, FX_NULL, FX_NULL);
/* Determine if the search was successful. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Check to make sure the found entry is a file. */
if (dir_entry.fx_dir_entry_attributes & not_a_file_attr)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the not a file error code. */
return(FX_NOT_A_FILE);
}
/* Place the current attributes into the destination. */
*attributes_ptr = (UINT)dir_entry.fx_dir_entry_attributes;
/* Update the trace event with the attributes read. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_ATTRIBUTES_READ, 0, 0, dir_entry.fx_dir_entry_attributes, 0)
/* Release media protection. */
FX_UNPROTECT
/* File attribute read is complete, return successful status. */
return(FX_SUCCESS);
}
+221
View File
@@ -0,0 +1,221 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
#include "fx_fault_tolerant.h"
#endif /* FX_ENABLE_FAULT_TOLERANT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_attributes_set PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function first attempts to find the specified file. If found, */
/* the attribute set request is valid and the directory entry will be */
/* modified with the new attributes. Otherwise, if the file is not */
/* found, the appropriate error code is returned to the caller. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* file_name File name pointer */
/* attributes New file attributes */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_write Write the new directory entry */
/* _fx_directory_search Search for the file name in */
/* the directory structure */
/* _fx_fault_tolerant_transaction_start Start fault tolerant */
/* transaction */
/* _fx_fault_tolerant_transaction_end End fault tolerant transaction*/
/* _fx_fault_tolerant_recover Recover FAT chain */
/* _fx_fault_tolerant_reset_log_file Reset the log file */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_file_attributes_set(FX_MEDIA *media_ptr, CHAR *file_name, UINT attributes)
{
UINT status;
ULONG open_count;
FX_FILE *search_ptr;
FX_DIR_ENTRY dir_entry;
UCHAR not_a_file_attr;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_file_attributes_sets++;
#endif
/* Setup pointer to media name buffer. */
dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Clear the short name string. */
dir_entry.fx_dir_entry_short_name[0] = 0;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
not_a_file_attr = FX_DIRECTORY | FX_VOLUME;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_ATTRIBUTES_SET, media_ptr, file_name, attributes, 0, FX_TRACE_FILE_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Check for write protect at the media level (set by driver). */
if (media_ptr -> fx_media_driver_write_protect)
{
/* Release media protection. */
FX_UNPROTECT
/* Return write protect error. */
return(FX_WRITE_PROTECT);
}
/* Search the system for the supplied file name. */
status = _fx_directory_search(media_ptr, file_name, &dir_entry, FX_NULL, FX_NULL);
/* Determine if the search was successful. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Check to make sure the found entry is a file. */
if (dir_entry.fx_dir_entry_attributes & not_a_file_attr)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the not a file error code. */
return(FX_NOT_A_FILE);
}
/* Search the opened files to see if this file is currently
opened. */
open_count = media_ptr -> fx_media_opened_file_count;
search_ptr = media_ptr -> fx_media_opened_file_list;
while (open_count)
{
/* Look at each opened file to see if the same file is opened. */
if ((search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector == dir_entry.fx_dir_entry_log_sector) &&
(search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset == dir_entry.fx_dir_entry_byte_offset))
{
/* Release media protection. */
FX_UNPROTECT
/* The file is currently open. */
return(FX_ACCESS_ERROR);
}
/* Adjust the pointer and decrement the search count. */
search_ptr = search_ptr -> fx_file_opened_next;
open_count--;
}
/* Place the new attributes in the directory entry. */
dir_entry.fx_dir_entry_attributes = (UCHAR)attributes;
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Start transaction. */
_fx_fault_tolerant_transaction_start(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Now write out the directory entry. */
status = _fx_directory_entry_write(media_ptr, &dir_entry);
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
/* End transaction. */
status = _fx_fault_tolerant_transaction_end(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* File attribute set is complete, return status. */
return(status);
}
+97
View File
@@ -0,0 +1,97 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_file.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_best_effort_allocate PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function attempts to allocate the number of consecutive */
/* clusters required to satisfy the user's request. If there are not */
/* enough clusters, the largest set of clusters are allocated and */
/* linked to the file. If there are no free clusters, an error */
/* code is returned to the caller. */
/* */
/* INPUT */
/* */
/* file_ptr File control block pointer */
/* size Number of bytes to allocate */
/* actual_size_allocated Number of bytes allocated */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_file_extended_best_effort_allocate */
/* Allocate the largest set of */
/* clusters */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_file_best_effort_allocate(FX_FILE *file_ptr, ULONG size, ULONG *actual_size_allocated)
{
UINT status;
ULONG64 temp_actual_size_allocated;
/* Call actual best effort file allocate service. */
status = _fx_file_extended_best_effort_allocate(file_ptr, (ULONG64)size, &temp_actual_size_allocated);
/* Check status. */
if (status == FX_SUCCESS)
{
*actual_size_allocated = (ULONG)temp_actual_size_allocated;
}
/* Return status to the caller. */
return(status);
}
+186
View File
@@ -0,0 +1,186 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_file.h"
#include "fx_utility.h"
#include "fx_directory.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_close PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function closes the specified file. If the file was written */
/* to this function will also write the directory entry (with the new */
/* size and time/date stamp) out to disk. */
/* */
/* INPUT */
/* */
/* file_ptr File control block pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_write Write the directory entry */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_file_close(FX_FILE *file_ptr)
{
UINT status;
FX_MEDIA *media_ptr;
FX_INT_SAVE_AREA
/* First, determine if the file is still open. */
if (file_ptr -> fx_file_id != FX_FILE_ID)
{
/* Return the file not open error status. */
return(FX_NOT_OPEN);
}
/* Setup a pointer to the associated media. */
media_ptr = file_ptr -> fx_file_media_ptr;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_file_closes++;
#endif
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_CLOSE, file_ptr, file_ptr -> fx_file_current_file_size, 0, 0, FX_TRACE_FILE_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* If trace is enabled, unregister this object. */
FX_TRACE_OBJECT_UNREGISTER(file_ptr)
/* Remove this file from the opened list for the media. */
/* See if the file is the only one on the open list for this media. */
if (file_ptr == file_ptr -> fx_file_opened_next)
{
/* Only opened file, just set the opened list to NULL. */
media_ptr -> fx_media_opened_file_list = FX_NULL;
}
else
{
/* Otherwise, not the only opened file, link-up the neighbors. */
(file_ptr -> fx_file_opened_next) -> fx_file_opened_previous =
file_ptr -> fx_file_opened_previous;
(file_ptr -> fx_file_opened_previous) -> fx_file_opened_next =
file_ptr -> fx_file_opened_next;
/* See if we have to update the opened list head pointer. */
if (media_ptr -> fx_media_opened_file_list == file_ptr)
{
/* Yes, move the head pointer to the next opened file. */
media_ptr -> fx_media_opened_file_list = file_ptr -> fx_file_opened_next;
}
}
/* Decrement the opened file counter. */
media_ptr -> fx_media_opened_file_count--;
/* Finally, Indicate that this file is closed. */
file_ptr -> fx_file_id = FX_FILE_CLOSED_ID;
/* Check to see if this file needs to have its directory entry written
back to the media. */
if ((file_ptr -> fx_file_open_mode == FX_OPEN_FOR_WRITE) &&
(file_ptr -> fx_file_modified))
{
/* Lockout interrupts for time/date access. */
FX_DISABLE_INTS
/* Set the new time and date. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_time = _fx_system_time;
file_ptr -> fx_file_dir_entry.fx_dir_entry_date = _fx_system_date;
/* Set the last access date. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_last_accessed_date = _fx_system_date;
/* Restore interrupts. */
FX_RESTORE_INTS
/* Copy the new file size into the directory entry. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =
file_ptr -> fx_file_current_file_size;
/* Write the directory entry to the media. */
status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
/* Check for a good status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Error writing the directory. */
return(status);
}
}
/* Release media protection. */
FX_UNPROTECT
/* Return status to the caller. */
return(FX_SUCCESS);
}
+303
View File
@@ -0,0 +1,303 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
#include "fx_fault_tolerant.h"
#endif /* FX_ENABLE_FAULT_TOLERANT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_create PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function first attempts to find the specified file. If found, */
/* the create request is invalid and an error is returned to the */
/* caller. After the file name verification is made, a search for a */
/* free directory entry will be made. If nothing is available, an */
/* error will be returned to the caller. Otherwise, if all is okay, a */
/* file of 0 bytes will be created. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* file_name File name */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_write Write the new directory entry */
/* _fx_directory_name_extract Extract directory name */
/* _fx_directory_search Search for the file name in */
/* the directory structure */
/* _fx_directory_free_search Search for a free directory */
/* entry */
/* _fx_fault_tolerant_transaction_start Start fault tolerant */
/* transaction */
/* _fx_fault_tolerant_transaction_end End fault tolerant transaction*/
/* _fx_fault_tolerant_recover Recover FAT chain */
/* _fx_fault_tolerant_reset_log_file Reset the log file */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_file_create(FX_MEDIA *media_ptr, CHAR *file_name)
{
FX_INT_SAVE_AREA
UINT status;
CHAR *name_ptr;
UINT i;
CHAR *work_ptr;
FX_DIR_ENTRY dir_entry;
FX_DIR_ENTRY search_directory;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_file_creates++;
#endif
/* Determine if the supplied name is less than the maximum supported name size. The
maximum name (FX_MAX_LONG_NAME_LEN) is defined in fx_api.h. */
i = 0;
work_ptr = (CHAR *)file_name;
while (*work_ptr)
{
/* Determine if the character designates a new path. */
if ((*work_ptr == '\\') || (*work_ptr == '/'))
{
/* Yes, reset the name size. */
i = 0;
}
/* Check for leading spaces. */
else if ((*work_ptr != ' ') || (i != 0))
{
/* No leading spaces, increment the name size. */
i++;
}
/* Move to the next character. */
work_ptr++;
}
/* Determine if the supplied name is valid. */
if ((i == 0) || (i >= FX_MAX_LONG_NAME_LEN))
{
/* Return an invalid name value. */
return(FX_INVALID_NAME);
}
/* Setup pointer to media name buffer. */
dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Setup another pointer to another media name buffer. */
search_directory.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 2;
/* Clear the short name strings. */
dir_entry.fx_dir_entry_short_name[0] = 0;
search_directory.fx_dir_entry_short_name[0] = 0;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_CREATE, media_ptr, file_name, 0, 0, FX_TRACE_FILE_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Start transaction. */
_fx_fault_tolerant_transaction_start(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Check for write protect at the media level (set by driver). */
if (media_ptr -> fx_media_driver_write_protect)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return write protect error. */
return(FX_WRITE_PROTECT);
}
/* Search the system for the supplied file name. */
status = _fx_directory_search(media_ptr, file_name, &dir_entry, &search_directory, &name_ptr);
/* Determine if the search was successful. */
if (status == FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* File found - Return the error code. */
return(FX_ALREADY_CREATED);
}
/* Determine if there is anything left after the name. */
if (_fx_directory_name_extract(name_ptr, &dir_entry.fx_dir_entry_name[0]))
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Extra information after the file name, return an invalid path
error. */
return(FX_INVALID_PATH);
}
/* Find a free slot for the new file. */
status = _fx_directory_free_search(media_ptr, &search_directory, &dir_entry);
/* Determine if the search was successful. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Populate the directory entry. */
/* Isolate the file name. */
_fx_directory_name_extract(name_ptr, &dir_entry.fx_dir_entry_name[0]);
/* Disable interrupts for time/date access. */
FX_DISABLE_INTS
/* Set time and date stamps. */
dir_entry.fx_dir_entry_time = _fx_system_time;
dir_entry.fx_dir_entry_date = _fx_system_date;
/* Restore interrupts. */
FX_RESTORE_INTS
/* Set the attributes for the file. */
dir_entry.fx_dir_entry_attributes = FX_ARCHIVE;
/* Set file size to 0. */
dir_entry.fx_dir_entry_file_size = 0;
/* Set the cluster to NULL. */
dir_entry.fx_dir_entry_cluster = FX_NULL;
/* Is there a leading dot? */
if (dir_entry.fx_dir_entry_name[0] == '.')
{
/* Yes, toggle the hidden attribute bit. */
dir_entry.fx_dir_entry_attributes |= FX_HIDDEN;
}
/* Now write out the directory entry. */
status = _fx_directory_entry_write(media_ptr, &dir_entry);
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
/* End transaction. */
status = _fx_fault_tolerant_transaction_end(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* File create is complete, return status. */
return(status);
}
+137
View File
@@ -0,0 +1,137 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_directory.h"
#include "fx_file.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_date_time_set PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the specified file's date and time with the */
/* values provided. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* file_name File name pointer */
/* year Year */
/* month Month */
/* day Day */
/* hour Hour */
/* minute Minute */
/* second Second */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_search Search for the file name in */
/* the directory structure */
/* _fx_directory_entry_write Write the directory entry */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_file_date_time_set(FX_MEDIA *media_ptr, CHAR *file_name,
UINT year, UINT month, UINT day, UINT hour, UINT minute, UINT second)
{
UINT status;
FX_DIR_ENTRY dir_entry;
/* Setup pointer to media name buffer. */
dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Clear the short name string. */
dir_entry.fx_dir_entry_short_name[0] = 0;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_DATE_TIME_SET, media_ptr, file_name, year, month, FX_TRACE_FILE_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Search the system for the supplied directory name. */
status = _fx_directory_search(media_ptr, file_name, &dir_entry, FX_NULL, FX_NULL);
/* Determine if the search was successful. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Set the new time and date. */
dir_entry.fx_dir_entry_time = (hour << FX_HOUR_SHIFT) | (minute << FX_MINUTE_SHIFT) | (second / 2);
dir_entry.fx_dir_entry_date = ((year - FX_BASE_YEAR) << FX_YEAR_SHIFT) | (month << FX_MONTH_SHIFT) | day;
/* Write the directory entry to the media. */
status = _fx_directory_entry_write(media_ptr, &dir_entry);
/* Release media protection. */
FX_UNPROTECT
/* Directory information write is complete, return status. */
return(status);
}
+382
View File
@@ -0,0 +1,382 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
#include "fx_fault_tolerant.h"
#endif /* FX_ENABLE_FAULT_TOLERANT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_delete PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function first attempts to find the specified file. If found, */
/* the delete request is valid and all of its clusters will be */
/* released and its directory entry will be marked as available. */
/* Otherwise, if the file is not found, the appropriate error code is */
/* returned to the caller. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* file_name File name pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_write Write the new directory entry */
/* _fx_directory_search Search for the file name in */
/* the directory structure */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* _fx_utility_FAT_entry_write Write a FAT entry */
/* _fx_utility_FAT_flush Flush written FAT entries */
/* _fx_fault_tolerant_transaction_start Start fault tolerant */
/* transaction */
/* _fx_fault_tolerant_transaction_end End fault tolerant transaction*/
/* _fx_fault_tolerant_recover Recover FAT chain */
/* _fx_fault_tolerant_reset_log_file Reset the log file */
/* _fx_fault_tolerant_set_FAT_chain Set data of FAT chain */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_file_delete(FX_MEDIA *media_ptr, CHAR *file_name)
{
UINT status;
ULONG cluster;
ULONG contents;
ULONG open_count;
FX_FILE *search_ptr;
ULONG cluster_count;
FX_DIR_ENTRY dir_entry;
UCHAR not_a_file_attr;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_file_deletes++;
#endif
/* Setup pointer to media name buffer. */
dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
/* Clear the short name string. */
dir_entry.fx_dir_entry_short_name[0] = 0;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_DELETE, media_ptr, file_name, 0, 0, FX_TRACE_FILE_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Start transaction. */
_fx_fault_tolerant_transaction_start(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Check for write protect at the media level (set by driver). */
if (media_ptr -> fx_media_driver_write_protect)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return write protect error. */
return(FX_WRITE_PROTECT);
}
/* Search the system for the supplied file name. */
status = _fx_directory_search(media_ptr, file_name, &dir_entry, FX_NULL, FX_NULL);
/* Determine if the search was successful. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
not_a_file_attr = FX_DIRECTORY | FX_VOLUME;
/* Check to make sure the found entry is a file. */
if (dir_entry.fx_dir_entry_attributes & not_a_file_attr)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the not a file error code. */
return(FX_NOT_A_FILE);
}
/* Check if the entry is read only */
if (dir_entry.fx_dir_entry_attributes & (UCHAR)(FX_READ_ONLY))
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the not a directory error code. */
return(FX_WRITE_PROTECT);
}
/* Search the opened files to see if this file is currently
opened. */
open_count = media_ptr -> fx_media_opened_file_count;
search_ptr = media_ptr -> fx_media_opened_file_list;
while (open_count)
{
/* Look at each opened file to see if the same file is opened. */
if ((search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector == dir_entry.fx_dir_entry_log_sector) &&
(search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset == dir_entry.fx_dir_entry_byte_offset))
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* The file is currently open. */
return(FX_ACCESS_ERROR);
}
/* Adjust the pointer and decrement the search count. */
search_ptr = search_ptr -> fx_file_opened_next;
open_count--;
}
/* Pickup the starting cluster of the file. */
cluster = dir_entry.fx_dir_entry_cluster;
/* At this point, make the directory entry invalid in order to delete the file. */
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
/* Invalidate the directory search saved information. */
media_ptr -> fx_media_last_found_name[0] = FX_NULL;
#endif
/* Mark the directory entry as available, while leaving the other
information for the sake of posterity. */
dir_entry.fx_dir_entry_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
dir_entry.fx_dir_entry_short_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
/* Now write out the directory entry. */
status = _fx_directory_entry_write(media_ptr, &dir_entry);
/* Determine if the write was successful. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Now that the directory entry is no longer valid and pointing at the chain of clusters,
walk the chain of allocated FAT entries and mark each of them as free. */
cluster_count = 0;
#ifdef FX_ENABLE_FAULT_TOLERANT
if (media_ptr -> fx_media_fault_tolerant_enabled)
{
/* Note: Directory entries are already written to log files. FAT chain is updated as the last step.
Since there are no others FAT entries written to the log. Therefore there is no need to set
the flag FX_FRAULT_TOLERANT_STATE_SET_FAT_CHAIN here. */
status = _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, 0,
media_ptr -> fx_media_fat_last, cluster, media_ptr -> fx_media_fat_last);
/* Determine if the write was successful. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
}
else
{
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Follow the link of FAT entries. */
while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
{
/* Increment the number of clusters. */
cluster_count++;
/* Read the current cluster entry from the FAT. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
/* Check the return value. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
if ((cluster == contents) || (cluster_count > media_ptr -> fx_media_total_clusters))
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(FX_FAT_READ_ERROR);
}
/* Make the current cluster available. */
status = _fx_utility_FAT_entry_write(media_ptr, cluster, FX_FREE_CLUSTER);
/* Check the return value. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Setup for the next cluster. */
cluster = contents;
}
#ifdef FX_ENABLE_FAULT_TOLERANT
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Update the free clusters in the media control block. */
media_ptr -> fx_media_available_clusters =
media_ptr -> fx_media_available_clusters + cluster_count;
#ifdef FX_FAULT_TOLERANT
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
#endif
#ifdef FX_ENABLE_FAULT_TOLERANT
/* End transaction. */
status = _fx_fault_tolerant_transaction_end(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* File delete is complete, return status. */
return(status);
}
+543
View File
@@ -0,0 +1,543 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_file.h"
#include "fx_utility.h"
#include "fx_directory.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
#include "fx_fault_tolerant.h"
#endif /* FX_ENABLE_FAULT_TOLERANT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_extended_allocate PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function attempts to allocate the number of consecutive */
/* clusters required to satisfy the user's request. If there are */
/* enough clusters, the clusters are allocated and linked to the file. */
/* Otherwise, if there are not enough consecutive clusters, an error */
/* code is returned to the caller. */
/* */
/* INPUT */
/* */
/* file_ptr File control block pointer */
/* size Number of bytes to allocate */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_write Update directory entry */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* _fx_utility_FAT_entry_write Write a FAT entry */
/* _fx_utility_FAT_flush Flush written FAT entries */
/* _fx_utility_logical_sector_flush Flush the written log sector */
/* _fx_fault_tolerant_transaction_start Start fault tolerant */
/* transaction */
/* _fx_fault_tolerant_transaction_end End fault tolerant transaction*/
/* _fx_fault_tolerant_recover Recover FAT chain */
/* _fx_fault_tolerant_reset_log_file Reset the log file */
/* _fx_fault_tolerant_set_FAT_chain Set data of FAT chain */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_file_extended_allocate(FX_FILE *file_ptr, ULONG64 size)
{
UINT status;
ULONG i;
UINT found;
ULONG bytes_per_cluster;
ULONG FAT_index;
ULONG FAT_value;
ULONG clusters;
FX_MEDIA *media_ptr;
#ifdef TX_ENABLE_EVENT_TRACE
TX_TRACE_BUFFER_ENTRY *trace_event;
ULONG trace_timestamp;
#endif
/* First, determine if the file is still open. */
if (file_ptr -> fx_file_id != FX_FILE_ID)
{
/* Return the file not open error status. */
return(FX_NOT_OPEN);
}
/* Setup pointer to media structure. */
media_ptr = file_ptr -> fx_file_media_ptr;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_file_allocates++;
#endif
/* Make sure this file is open for writing. */
if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
{
/* Return the access error exception - a write was attempted from
a file opened for reading! */
return(FX_ACCESS_ERROR);
}
/* Determine if the requested allocation is for zero bytes. */
if (size == 0)
{
/* Return a successful completion - nothing needs to be done. */
return(FX_SUCCESS);
}
/* Setup pointer to associated media control block. */
media_ptr = file_ptr -> fx_file_media_ptr;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_ALLOCATE, file_ptr, size, file_ptr -> fx_file_current_available_size, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
/* Protect against other threads accessing the media. */
FX_PROTECT
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Start transaction. */
_fx_fault_tolerant_transaction_start(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Check for write protect at the media level (set by driver). */
if (media_ptr -> fx_media_driver_write_protect)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return write protect error. */
return(FX_WRITE_PROTECT);
}
/* Calculate the number of bytes per cluster. */
bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster);
/* Check for invalid value. */
if (bytes_per_cluster == 0)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Invalid media, return error. */
return(FX_MEDIA_INVALID);
}
/* Calculate the number of consecutive clusters needed to satisfy this
request. */
clusters = (ULONG)(((size + bytes_per_cluster - 1) / bytes_per_cluster));
/* Determine if cluster count is 0. */
if (clusters == 0)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Size overflow when rounding to the next cluster, return an error status. */
return(FX_NO_MORE_SPACE);
}
/* Determine if there are enough available clusters on the media. */
if (clusters > media_ptr -> fx_media_available_clusters)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Not enough clusters, return an error status. */
return(FX_NO_MORE_SPACE);
}
/* Determine if the requested file allocation would exceed the physical limit of the file. */
if (((file_ptr -> fx_file_current_available_size + (((ULONG64) clusters) * ((ULONG64) bytes_per_cluster))) < file_ptr -> fx_file_current_available_size) ||
((file_ptr -> fx_file_current_available_size + (((ULONG64) clusters) * ((ULONG64) bytes_per_cluster))) > 0xFFFFFFFFULL))
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the no more space error, since the new file size would be larger than
the 32-bit field to represent it in the file's directory entry. */
return(FX_NO_MORE_SPACE);
}
/* Now we need to find the consecutive clusters. */
FAT_index = FX_FAT_ENTRY_START;
found = FX_FALSE;
while (FAT_index <= (media_ptr -> fx_media_total_clusters - clusters + FX_FAT_ENTRY_START))
{
/* Determine if enough consecutive FAT entries are available. */
i = 0;
do
{
/* Read a FAT entry. */
status = _fx_utility_FAT_entry_read(media_ptr, (FAT_index + i), &FAT_value);
/* Check for a successful status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Determine if the entry is free. */
if (FAT_value != FX_FREE_CLUSTER)
{
break;
}
/* Otherwise, increment the consecutive FAT indices. */
i++;
} while (i < clusters);
/* Determine if we found enough FAT entries. */
if (i >= clusters)
{
/* Yes, we have found enough FAT entries - set the found
flag and get out of this loop. */
found = FX_TRUE;
break;
}
else
{
/* Position to the next possibly free FAT entry. */
FAT_index = FAT_index + i + 1;
}
}
/* Determine if we found enough consecutive clusters to satisfy the
request. */
if (found)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
if (media_ptr -> fx_media_fault_tolerant_enabled)
{
/* Record the action that is about to take place. This information
would aid the undo process should fault condition happens. */
media_ptr -> fx_media_fault_tolerant_state |= FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN;
_fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, file_ptr -> fx_file_last_physical_cluster,
FAT_index, media_ptr -> fx_media_fat_last, media_ptr -> fx_media_fat_last);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Update the link pointers in the new clusters. */
for (i = 0; i < (clusters - 1); i++)
{
/* Update the cluster links. Since the allocation is
sequential, we just have to link each FAT entry to the
next one. */
status = _fx_utility_FAT_entry_write(media_ptr, FAT_index + i, FAT_index + i + 1);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
}
/* Now place an EOF in the last cluster entry. */
status = _fx_utility_FAT_entry_write(media_ptr, FAT_index + clusters - 1, media_ptr -> fx_media_fat_last);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
#ifdef FX_FAULT_TOLERANT
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
#endif
/* Actually link up the new clusters to the file. */
/* Determine if there are already clusters allocated for this file. */
if (file_ptr -> fx_file_total_clusters)
{
/* Linkup the last cluster. */
status = _fx_utility_FAT_entry_write(media_ptr,
file_ptr -> fx_file_last_physical_cluster, FAT_index);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Determine if we are adding a sector after a write filled the previously
allocated cluster exactly. */
if ((file_ptr -> fx_file_current_relative_sector >=
(media_ptr -> fx_media_sectors_per_cluster - 1)) &&
(file_ptr -> fx_file_current_logical_offset >=
media_ptr -> fx_media_bytes_per_sector))
{
/* Yes, we need to adjust all of the pertinent file parameters for
access into this newly allocated cluster. */
file_ptr -> fx_file_current_physical_cluster = FAT_index;
file_ptr -> fx_file_current_relative_cluster++;
file_ptr -> fx_file_current_relative_sector = 0;
file_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG64)(FAT_index - FX_FAT_ENTRY_START)) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster));
file_ptr -> fx_file_current_logical_offset = 0;
}
}
else
{
/* These new clusters are also the first! Setup the initial
file parameters. */
file_ptr -> fx_file_first_physical_cluster = FAT_index;
file_ptr -> fx_file_current_physical_cluster = file_ptr -> fx_file_first_physical_cluster;
file_ptr -> fx_file_current_relative_cluster = 0;
file_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG64)(file_ptr -> fx_file_first_physical_cluster - FX_FAT_ENTRY_START)) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster));
file_ptr -> fx_file_current_logical_offset = 0;
file_ptr -> fx_file_current_file_offset = 0;
/* Update the first cluster in the directory entry. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster = FAT_index;
}
/* Remember the last physical cluster. */
file_ptr -> fx_file_last_physical_cluster = FAT_index + clusters - 1;
/* Check for wrap-around when updating the available size. */
/* Update the available size. */
file_ptr -> fx_file_current_available_size =
file_ptr -> fx_file_current_available_size + (bytes_per_cluster * clusters);
/* Increment the total clusters for this file. */
file_ptr -> fx_file_total_clusters =
file_ptr -> fx_file_total_clusters + clusters;
/* Decrease the available clusters on the media. */
media_ptr -> fx_media_available_clusters =
media_ptr -> fx_media_available_clusters - clusters;
#if defined(FX_UPDATE_FILE_SIZE_ON_ALLOCATE) || defined(FX_ENABLE_FAULT_TOLERANT)
/* Set the file size the current size plus what what was added. */
file_ptr -> fx_file_current_file_size += size;
/* Copy the new file size into the directory entry. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_current_file_size;
#endif
#ifdef FX_ENABLE_FAULT_TOLERANT
if (media_ptr -> fx_media_fault_tolerant_enabled)
{
/* Clear undo phase. */
media_ptr -> fx_media_fault_tolerant_state &= (UCHAR)(~FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN & 0xff);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Update the trace event with the new size. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_ALLOCATE, 0, 0, 0, file_ptr -> fx_file_current_file_size);
/* Write the directory entry to the media. */
status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
/* Check for a good status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
}
else
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Not enough contiguous space on the media. Return error status. */
return(FX_NO_MORE_SPACE);
}
#ifdef FX_FAULT_TOLERANT
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
#endif
/* Flush the internal logical sector cache. */
status = _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64)(media_ptr -> fx_media_sectors_per_FAT), FX_FALSE);
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
if (media_ptr -> fx_media_fault_tolerant_enabled)
{
/* Copy the new file size into the directory entry. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_current_file_size;
}
/* End transaction. */
status = _fx_fault_tolerant_transaction_end(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return status to the caller. */
return(status);
}
@@ -0,0 +1,583 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_file.h"
#include "fx_utility.h"
#include "fx_directory.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
#include "fx_fault_tolerant.h"
#endif /* FX_ENABLE_FAULT_TOLERANT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_extended_best_effort_allocate PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function attempts to allocate the number of consecutive */
/* clusters required to satisfy the user's request. If there are not */
/* enough clusters, the largest set of clusters are allocated and */
/* linked to the file. If there are no free clusters, an error */
/* code is returned to the caller. */
/* */
/* INPUT */
/* */
/* file_ptr File control block pointer */
/* size Number of bytes to allocate */
/* actual_size_allocated Number of bytes allocated */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_write Update directory entry */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* _fx_utility_FAT_entry_write Write a FAT entry */
/* _fx_utility_FAT_flush Flush written FAT entries */
/* _fx_utility_logical_sector_flush Flush the written log sector */
/* _fx_fault_tolerant_transaction_start Start fault tolerant */
/* transaction */
/* _fx_fault_tolerant_transaction_end End fault tolerant transaction*/
/* _fx_fault_tolerant_recover Recover FAT chain */
/* _fx_fault_tolerant_reset_log_file Reset the log file */
/* _fx_fault_tolerant_set_FAT_chain Set data of FAT chain */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_file_extended_best_effort_allocate(FX_FILE *file_ptr, ULONG64 size, ULONG64 *actual_size_allocated)
{
UINT status;
ULONG i;
UINT found;
ULONG bytes_per_cluster;
ULONG FAT_index, start_FAT_index;
ULONG FAT_value;
ULONG clusters, maximum_clusters;
FX_MEDIA *media_ptr;
#ifdef TX_ENABLE_EVENT_TRACE
TX_TRACE_BUFFER_ENTRY *trace_event;
ULONG trace_timestamp;
#endif
/* First, determine if the file is still open. */
if (file_ptr -> fx_file_id != FX_FILE_ID)
{
/* Return the file not open error status. */
return(FX_NOT_OPEN);
}
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Setup pointer to media structure. */
media_ptr = file_ptr -> fx_file_media_ptr;
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_file_best_effort_allocates++;
#endif
/* Make sure this file is open for writing. */
if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
{
/* Return the access error exception - a write was attempted from
a file opened for reading! */
return(FX_ACCESS_ERROR);
}
/* Determine if the requested allocation is for zero bytes. */
if (size == 0)
{
/* Return a size allocated of zero. */
*actual_size_allocated = 0;
/* Return a successful completion - nothing needs to be done. */
return(FX_SUCCESS);
}
/* Setup pointer to associated media control block. */
media_ptr = file_ptr -> fx_file_media_ptr;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_BEST_EFFORT_ALLOCATE, file_ptr, size, 0, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
/* Protect against other threads accessing the media. */
FX_PROTECT
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Start transaction. */
_fx_fault_tolerant_transaction_start(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Check for write protect at the media level (set by driver). */
if (media_ptr -> fx_media_driver_write_protect)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return write protect error. */
return(FX_WRITE_PROTECT);
}
/* Calculate the number of bytes per cluster. */
bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster);
/* Check for invalid value. */
if (bytes_per_cluster == 0)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Invalid media, return error. */
return(FX_MEDIA_INVALID);
}
/* Calculate the number of consecutive clusters needed to satisfy this
request. */
clusters = (ULONG)(((size + bytes_per_cluster - 1) / bytes_per_cluster));
/* Determine if cluster count is 0. */
if (clusters == 0)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Size overflow when rounding to the next cluster, return an error status. */
return(FX_NO_MORE_SPACE);
}
/* Determine if there are no available clusters on the media. */
if (!media_ptr -> fx_media_available_clusters)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return a size allocated of zero, since no clusters were available. */
*actual_size_allocated = 0;
/* Not enough clusters, return an error status. */
return(FX_NO_MORE_SPACE);
}
/* Determine if the requested file allocation would exceed the physical limit of the file. */
if (((file_ptr -> fx_file_current_available_size + (((ULONG64) clusters) * ((ULONG64) bytes_per_cluster))) < file_ptr -> fx_file_current_available_size) ||
((file_ptr -> fx_file_current_available_size + (((ULONG64) clusters) * ((ULONG64) bytes_per_cluster))) > 0xFFFFFFFFULL))
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the no more space error, since the new file size would be larger than
the 32-bit field to represent it in the file's directory entry. */
return(FX_NO_MORE_SPACE);
}
/* Now we need to find the consecutive clusters. */
found = FX_FALSE;
FAT_index = FX_FAT_ENTRY_START;
maximum_clusters = 0;
start_FAT_index = FAT_index;
while (FAT_index < (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
{
/* Determine if enough consecutive FAT entries are available. */
i = 0;
do
{
/* Read a FAT entry. */
status = _fx_utility_FAT_entry_read(media_ptr, (FAT_index + i), &FAT_value);
/* Check for a successful status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Determine if the entry is free. */
if (FAT_value != FX_FREE_CLUSTER)
{
break;
}
/* Otherwise, increment the consecutive FAT indices. */
i++;
} while ((i < clusters) && ((FAT_index + i) < media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START));
/* Determine if a new maximum number of clusters has been found. */
if (i > maximum_clusters)
{
/* Yes, remember the maximum number of clusters and the starting
cluster. */
maximum_clusters = i;
start_FAT_index = FAT_index;
}
/* Determine if we found enough FAT entries. */
if (i >= clusters)
{
/* Yes, we have found enough FAT entries - set the found
flag and get out of this loop. */
found = FX_TRUE;
break;
}
else
{
/* Position to the next possibly free FAT entry. */
FAT_index = FAT_index + i + 1;
}
}
/* Determine if the total request could not be satisfied, but a partial allocation
could be satisfied. */
if (maximum_clusters)
{
/* Yes, there was at least one cluster. Prepare to return this
to the caller. */
FAT_index = start_FAT_index;
clusters = maximum_clusters;
found = FX_TRUE;
}
/* Determine if we found enough consecutive clusters to satisfy the
request. */
if (found)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
if (media_ptr -> fx_media_fault_tolerant_enabled)
{
/* Record the FAT chain being applied to the file system. This information aids
recovery effort if fault happens. */
media_ptr -> fx_media_fault_tolerant_state |= FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN;
_fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, file_ptr -> fx_file_last_physical_cluster,
FAT_index, media_ptr -> fx_media_fat_last, media_ptr -> fx_media_fat_last);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Update the link pointers in the new clusters. */
for (i = 0; i < (clusters - 1); i++)
{
/* Update the cluster links. Since the allocation is
sequential, we just have to link each FAT entry to the
next one. */
status = _fx_utility_FAT_entry_write(media_ptr, FAT_index + i, FAT_index + i + 1);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
}
/* Now place an EOF in the last cluster entry. */
status = _fx_utility_FAT_entry_write(media_ptr, FAT_index + clusters - 1, media_ptr -> fx_media_fat_last);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
#ifdef FX_FAULT_TOLERANT
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
#endif
/* Actually link up the new clusters to the file. */
/* Determine if there are already clusters allocated for this file. */
if (file_ptr -> fx_file_total_clusters)
{
/* Linkup the last cluster. */
status = _fx_utility_FAT_entry_write(media_ptr,
file_ptr -> fx_file_last_physical_cluster, FAT_index);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Determine if we are adding a sector after a write filled the previously
allocated cluster exactly. */
if ((file_ptr -> fx_file_current_relative_sector >=
(media_ptr -> fx_media_sectors_per_cluster - 1)) &&
(file_ptr -> fx_file_current_logical_offset >=
media_ptr -> fx_media_bytes_per_sector))
{
/* Yes, we need to adjust all of the pertinent file parameters for
access into this newly allocated cluster. */
file_ptr -> fx_file_current_physical_cluster = FAT_index;
file_ptr -> fx_file_current_relative_cluster++;
file_ptr -> fx_file_current_relative_sector = 0;
file_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG64)(FAT_index - FX_FAT_ENTRY_START)) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster));
file_ptr -> fx_file_current_logical_offset = 0;
}
}
else
{
/* These new clusters are also the first! Setup the initial
file parameters. */
file_ptr -> fx_file_first_physical_cluster = FAT_index;
file_ptr -> fx_file_current_physical_cluster = file_ptr -> fx_file_first_physical_cluster;
file_ptr -> fx_file_current_relative_cluster = 0;
file_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG64)(file_ptr -> fx_file_first_physical_cluster - FX_FAT_ENTRY_START)) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster));
file_ptr -> fx_file_current_logical_offset = 0;
file_ptr -> fx_file_current_file_offset = 0;
/* Setup the consecutive clusters at the beginning of the file. */
file_ptr -> fx_file_consecutive_cluster = clusters;
/* Update the first cluster in the directory entry. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster = FAT_index;
#ifdef FX_ENABLE_FAULT_TOLERANT
if (media_ptr -> fx_media_fault_tolerant_enabled)
{
/* Clear undo phase. */
media_ptr -> fx_media_fault_tolerant_state &= (UCHAR)(~FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN & 0xff);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
}
/* Remember the last physical cluster. */
file_ptr -> fx_file_last_physical_cluster = FAT_index + clusters - 1;
/* Update the available size. */
/* Normal condition, update the available size. */
file_ptr -> fx_file_current_available_size =
file_ptr -> fx_file_current_available_size + bytes_per_cluster * clusters;
/* Increment the total clusters for this file. */
file_ptr -> fx_file_total_clusters =
file_ptr -> fx_file_total_clusters + clusters;
/* Decrease the available clusters on the media. */
media_ptr -> fx_media_available_clusters =
media_ptr -> fx_media_available_clusters - clusters;
/* Return the actual size allocated. */
*actual_size_allocated = ((ULONG64)clusters) * bytes_per_cluster;
#if defined(FX_UPDATE_FILE_SIZE_ON_ALLOCATE) || defined(FX_ENABLE_FAULT_TOLERANT)
/* Set the file size the current size plus what what was added. */
if (size < *actual_size_allocated)
{
file_ptr -> fx_file_current_file_size += size;
}
else
{
file_ptr -> fx_file_current_file_size += *actual_size_allocated;
}
/* Copy the new file size into the directory entry. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_current_file_size;
#endif
/* Update the trace event with the bytes allocated. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_BEST_EFFORT_ALLOCATE, 0, 0, *actual_size_allocated, 0);
/* Write the directory entry to the media. */
status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
/* Check for a good status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
}
else
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return a size allocated of zero, since no clusters were available. */
*actual_size_allocated = 0;
/* Not enough contiguous space on the media. Return error status. */
return(FX_NO_MORE_SPACE);
}
#ifdef FX_FAULT_TOLERANT
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
#endif
/* Flush the internal logical sector cache. */
status = _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64) (media_ptr -> fx_media_sectors_per_FAT), FX_FALSE);
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
/* End transaction. */
status = _fx_fault_tolerant_transaction_end(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return status to the caller. */
return(status);
}
+163
View File
@@ -0,0 +1,163 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_extended_relative_seek PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function positions the internal file pointers to the specified */
/* byte relative offset such that the next read or write operation is */
/* performed there. */
/* */
/* INPUT */
/* */
/* file_ptr File control block pointer */
/* byte_offset Byte offset of the seek */
/* seek_from Direction for relative seek, */
/* legal values are: */
/* */
/* FX_SEEK_BEGIN */
/* FX_SEEK_END */
/* FX_SEEK_FORWARD */
/* FX_SEEK_BACK */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_file_extended_seek Seek to specified position */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_file_extended_relative_seek(FX_FILE *file_ptr, ULONG64 byte_offset, UINT seek_from)
{
#ifndef FX_MEDIA_STATISTICS_DISABLE
FX_MEDIA *media_ptr;
/* First, determine if the file is still open. */
if (file_ptr -> fx_file_id != FX_FILE_ID)
{
/* Return the file not open error status. */
return(FX_NOT_OPEN);
}
/* Setup pointer to media structure. */
media_ptr = file_ptr -> fx_file_media_ptr;
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_file_relative_seeks++;
#endif
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_RELATIVE_SEEK, file_ptr, byte_offset, seek_from, file_ptr -> fx_file_current_file_offset, FX_TRACE_FILE_EVENTS, 0, 0)
/* Determine if seeking from the beginning is requested. */
if (seek_from == FX_SEEK_BEGIN)
{
/* Yes, use the base file seek routine to seek from the beginning of
the file. */
return(_fx_file_extended_seek(file_ptr, byte_offset));
}
/* Otherwise, determine if seeking from the end is requested. */
else if (seek_from == FX_SEEK_END)
{
/* Yes, seek from the end of the file. */
/* Determine if the requested seek offset is greater than
the file size. */
if (byte_offset >= file_ptr -> fx_file_current_file_size)
{
/* Yes, just seek to the beginning of the file. */
return(_fx_file_extended_seek(file_ptr, ((ULONG64) 0)));
}
else
{
/* Logically seek from the end of the file. */
return(_fx_file_extended_seek(file_ptr, file_ptr -> fx_file_current_file_size - byte_offset));
}
}
/* Otherwise, determine if seeking from the current position is requested. */
else if (seek_from == FX_SEEK_FORWARD)
{
/* Yes, just seek ahead from the current file position. */
return(_fx_file_extended_seek(file_ptr, file_ptr -> fx_file_current_file_offset + byte_offset));
}
/* Otherwise, seeking backward from the current position is assumed. */
else
{
/* Determine if the backward offset is greater than the current file offset. */
if (byte_offset >= file_ptr -> fx_file_current_file_offset)
{
/* Yes, just position the file to the beginning. */
return(_fx_file_extended_seek(file_ptr, ((ULONG64) 0)));
}
else
{
/* Seek backward relative to the current position. */
return(_fx_file_extended_seek(file_ptr, file_ptr -> fx_file_current_file_offset - byte_offset));
}
}
}
+300
View File
@@ -0,0 +1,300 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_extended_seek PORTABLE C */
/* 6.1.7 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function positions the internal file pointers to the specified */
/* byte offset such that the next read or write operation will be */
/* performed there. If the byte offset is greater than the size, the */
/* file pointers will be positioned to the end of the file. */
/* */
/* INPUT */
/* */
/* file_ptr File control block pointer */
/* byte_offset Byte offset into the file */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 06-02-2021 Bhupendra Naphade Modified comment(s), fixed */
/* relative cluster logic, */
/* resulting in version 6.1.7 */
/* */
/**************************************************************************/
UINT _fx_file_extended_seek(FX_FILE *file_ptr, ULONG64 byte_offset)
{
UINT status;
ULONG cluster;
ULONG contents = 0;
ULONG bytes_per_cluster;
ULONG last_cluster;
ULONG cluster_count;
ULONG64 bytes_remaining;
FX_MEDIA *media_ptr;
/* First, determine if the file is still open. */
if (file_ptr -> fx_file_id != FX_FILE_ID)
{
/* Return the file not open error status. */
return(FX_NOT_OPEN);
}
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Setup pointer to media structure. */
media_ptr = file_ptr -> fx_file_media_ptr;
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_file_seeks++;
#endif
/* Setup pointer to associated media control block. */
media_ptr = file_ptr -> fx_file_media_ptr;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_SEEK, file_ptr, byte_offset, file_ptr -> fx_file_current_file_offset, 0, FX_TRACE_FILE_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Check if we actually have to do anything. */
if (byte_offset == file_ptr -> fx_file_current_file_offset)
{
/* Release media protection. */
FX_UNPROTECT
/* Seek is complete, return successful status. */
return(FX_SUCCESS);
}
/* Calculate the number of bytes per cluster. */
bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster);
/* Check for invalid value. */
if (bytes_per_cluster == 0)
{
/* Release media protection. */
FX_UNPROTECT
/* Invalid media, return error. */
return(FX_MEDIA_INVALID);
}
/* See if we need to adjust the byte offset. */
if (byte_offset > file_ptr -> fx_file_current_file_size)
{
/* Adjust the byte offset down to the file size. */
byte_offset = file_ptr -> fx_file_current_file_size;
}
/* Check if the desired position within the leading consecutive clusters. */
if (byte_offset >= (ULONG64)file_ptr -> fx_file_consecutive_cluster * (ULONG64)bytes_per_cluster)
{
/* At this point, we are ready to walk list of clusters to setup the
seek position of this file. */
/* check if byte_offset is greater than where we were left off earlier */
if ((ULONG64)file_ptr -> fx_file_current_relative_cluster * (ULONG64)bytes_per_cluster < byte_offset)
{
cluster = file_ptr -> fx_file_current_physical_cluster;
bytes_remaining = byte_offset -
file_ptr -> fx_file_current_relative_cluster * bytes_per_cluster;
cluster_count = file_ptr -> fx_file_current_relative_cluster;
}
else
{
cluster = file_ptr -> fx_file_first_physical_cluster +
(file_ptr -> fx_file_consecutive_cluster - 1);
bytes_remaining = byte_offset -
(file_ptr -> fx_file_consecutive_cluster - 1) * bytes_per_cluster;
cluster_count = (file_ptr -> fx_file_consecutive_cluster - 1);
}
/* Follow the link of FAT entries. */
while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
{
/* Increment the number of clusters. */
cluster_count++;
/* Read the current cluster entry from the FAT. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
/* Check the return value. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Save the last valid cluster. */
last_cluster = cluster;
/* Setup for the next cluster. */
cluster = contents;
/* Determine if this is the last written cluster. */
if (bytes_remaining > bytes_per_cluster)
{
/* Still more seeking, just decrement the working byte offset. */
bytes_remaining = bytes_remaining - bytes_per_cluster;
}
else
{
/* Remember this cluster number. */
file_ptr -> fx_file_current_physical_cluster = last_cluster;
/* Remember the relative cluster. */
file_ptr -> fx_file_current_relative_cluster = cluster_count - 1;
/* If the remaining bytes exactly fits the cluster size, check for
a possible adjustment to the next cluster. */
if ((bytes_remaining == bytes_per_cluster) &&
(cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
{
/* We need to position to next allocated cluster. */
file_ptr -> fx_file_current_physical_cluster = cluster;
file_ptr -> fx_file_current_relative_cluster++;
/* Clear the remaining bytes. */
bytes_remaining = 0;
}
/* This is the cluster that contains the seek position. */
break;
}
}
/* Check for errors in traversal of the FAT chain. */
if (byte_offset > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count)))
{
/* Release media protection. */
FX_UNPROTECT
/* This is an error that suggests a corrupt file. */
return(FX_FILE_CORRUPT);
}
}
else
{
/* we should directly access the desired cluster */
file_ptr -> fx_file_current_relative_cluster = (ULONG)(byte_offset / bytes_per_cluster);
file_ptr -> fx_file_current_physical_cluster =
file_ptr -> fx_file_first_physical_cluster + file_ptr -> fx_file_current_relative_cluster;
bytes_remaining = byte_offset % bytes_per_cluster;
}
/* Determine if the remaining bytes fit exactly into the cluster size. */
if (bytes_remaining == bytes_per_cluster)
{
/* Position to the end of the cluster. */
file_ptr -> fx_file_current_logical_sector = (ULONG)(((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
((bytes_remaining - 1) / (ULONG)media_ptr -> fx_media_bytes_per_sector));
file_ptr -> fx_file_current_relative_sector = (UINT)(((bytes_remaining - 1) / (ULONG)media_ptr -> fx_media_bytes_per_sector));
file_ptr -> fx_file_current_file_offset = byte_offset;
file_ptr -> fx_file_current_logical_offset = media_ptr -> fx_media_bytes_per_sector;
}
else
{
/* Position the pointers to the new offset. */
file_ptr -> fx_file_current_logical_sector = (ULONG)(((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
(bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
file_ptr -> fx_file_current_relative_sector = (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
file_ptr -> fx_file_current_file_offset = byte_offset;
file_ptr -> fx_file_current_logical_offset = (ULONG)(bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector));
}
/* Release media protection. */
FX_UNPROTECT
/* Seek is complete, return successful status. */
return(FX_SUCCESS);
}
+347
View File
@@ -0,0 +1,347 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
#include "fx_fault_tolerant.h"
#endif /* FX_ENABLE_FAULT_TOLERANT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_extended_truncate PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the file to the specified size, if smaller than */
/* the current file size. If the new file size is less than the */
/* current file read/write position, the internal file pointers will */
/* also be modified. */
/* */
/* INPUT */
/* */
/* file_ptr File control block pointer */
/* size New size of the file in bytes */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* _fx_fault_tolerant_transaction_start Start fault tolerant */
/* transaction */
/* _fx_fault_tolerant_transaction_end End fault tolerant transaction*/
/* _fx_fault_tolerant_recover Recover FAT chain */
/* _fx_fault_tolerant_reset_log_file Reset the log file */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_file_extended_truncate(FX_FILE *file_ptr, ULONG64 size)
{
UINT status;
ULONG cluster;
ULONG contents = 0;
ULONG bytes_per_cluster;
ULONG last_cluster;
ULONG cluster_count;
ULONG64 bytes_remaining;
FX_MEDIA *media_ptr;
#ifndef FX_DONT_UPDATE_OPEN_FILES
ULONG open_count;
FX_FILE *search_ptr;
#endif
#ifdef TX_ENABLE_EVENT_TRACE
TX_TRACE_BUFFER_ENTRY *trace_event;
ULONG trace_timestamp;
#endif
/* First, determine if the file is still open. */
if (file_ptr -> fx_file_id != FX_FILE_ID)
{
/* Return the file not open error status. */
return(FX_NOT_OPEN);
}
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Setup pointer to media structure. */
media_ptr = file_ptr -> fx_file_media_ptr;
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_file_truncates++;
#endif
/* Setup pointer to associated media control block. */
media_ptr = file_ptr -> fx_file_media_ptr;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_TRUNCATE, file_ptr, size, file_ptr -> fx_file_current_file_size, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Make sure this file is open for writing. */
if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the access error exception - a write was attempted from
a file opened for reading! */
return(FX_ACCESS_ERROR);
}
/* Check for write protect at the media level (set by driver). */
if (media_ptr -> fx_media_driver_write_protect)
{
/* Release media protection. */
FX_UNPROTECT
/* Return write protect error. */
return(FX_WRITE_PROTECT);
}
/* Setup the new file size - if less than the current size. */
if (size < file_ptr -> fx_file_current_file_size)
{
/* Setup the new size. */
file_ptr -> fx_file_current_file_size = size;
/* Set the modified flag as well. */
file_ptr -> fx_file_modified = FX_TRUE;
/* Update the trace event with the truncated size. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_TRUNCATE, 0, 0, 0, size)
}
else
{
/* Update the trace event with the truncated size. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_TRUNCATE, 0, 0, 0, file_ptr -> fx_file_current_file_size)
/* Release media protection. */
FX_UNPROTECT
/* Just return, the new size is larger than the current size. */
return(FX_SUCCESS);
}
#ifndef FX_DONT_UPDATE_OPEN_FILES
/* Search the opened files list to see if the same file is opened for reading. */
open_count = media_ptr -> fx_media_opened_file_count;
search_ptr = media_ptr -> fx_media_opened_file_list;
while (open_count)
{
/* Is this file the same file opened for reading? */
if ((search_ptr != file_ptr) &&
(search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector) &&
(search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset))
{
/* Yes, the same file is opened for reading. */
/* Setup the new file size. */
search_ptr -> fx_file_current_file_size = size;
search_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = size;
}
/* Adjust the pointer and decrement the search count. */
search_ptr = search_ptr -> fx_file_opened_next;
open_count--;
}
#endif
/* Now check to see if the read/write internal file pointers need
to be adjusted. */
if (file_ptr -> fx_file_current_file_offset > file_ptr -> fx_file_current_file_size)
{
/* Calculate the number of bytes per cluster. */
bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster);
/* At this point, we are ready to walk list of clusters to setup the
seek position of this file. */
cluster = file_ptr -> fx_file_first_physical_cluster;
bytes_remaining = size;
last_cluster = 0;
cluster_count = 0;
/* Follow the link of FAT entries. */
while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
{
/* Increment the number of clusters. */
cluster_count++;
/* Read the current cluster entry from the FAT. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
/* Check the return value. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Save the last valid cluster. */
last_cluster = cluster;
/* Setup for the next cluster. */
cluster = contents;
/* Determine if this is the last written cluster. */
if (bytes_remaining >= bytes_per_cluster)
{
/* Still more seeking, just decrement the working byte offset. */
bytes_remaining = bytes_remaining - bytes_per_cluster;
}
else
{
/* This is the cluster that contains the seek position. */
break;
}
}
/* Check for errors in traversal of the FAT chain. */
if (size > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count)))
{
/* Release media protection. */
FX_UNPROTECT
/* This is an error that suggests a corrupt file. */
return(FX_FILE_CORRUPT);
}
/* Position the pointers to the new offset. */
file_ptr -> fx_file_current_physical_cluster = last_cluster;
file_ptr -> fx_file_current_relative_cluster = cluster_count - 1;
file_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
(bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector);
file_ptr -> fx_file_current_relative_sector = (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
file_ptr -> fx_file_current_file_offset = size;
file_ptr -> fx_file_current_logical_offset = (ULONG)bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector);
}
#ifdef FX_ENABLE_FAULT_TOLERANT
if (media_ptr -> fx_media_fault_tolerant_enabled)
{
/* Start transaction. */
_fx_fault_tolerant_transaction_start(media_ptr);
/* Copy the new file size into the directory entry. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_current_file_size;
/* Write the directory entry to the media. */
status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
/* Check for a good status. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
/* Release media protection. */
FX_UNPROTECT
/* Error writing the directory. */
return(status);
}
/* End transaction. */
status = _fx_fault_tolerant_transaction_end(media_ptr);
/* Check for a good status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Error writing the directory. */
return(status);
}
/* Update maximum size used if necessary. */
if (size < file_ptr -> fx_file_maximum_size_used)
{
file_ptr -> fx_file_maximum_size_used = size;
}
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Truncate is complete, return successful status. */
return(FX_SUCCESS);
}
@@ -0,0 +1,814 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
#include "fx_fault_tolerant.h"
#endif /* FX_ENABLE_FAULT_TOLERANT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_extended_truncate_release PORTABLE C */
/* 6.1.3 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the file to the specified size, if smaller than */
/* the current file size. If the new file size is less than the */
/* current file read/write position, the internal file pointers will */
/* also be modified. Any unused clusters are released back to the */
/* media. */
/* */
/* INPUT */
/* */
/* file_ptr File control block pointer */
/* size New size of the file in bytes */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_write Write directory entry */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* _fx_utility_FAT_entry_write Write a FAT entry */
/* _fx_utility_FAT_flush Flush written FAT entries */
/* _fx_fault_tolerant_transaction_start Start fault tolerant */
/* transaction */
/* _fx_fault_tolerant_transaction_end End fault tolerant transaction*/
/* _fx_fault_tolerant_recover Recover FAT chain */
/* _fx_fault_tolerant_reset_log_file Reset the log file */
/* _fx_fault_tolerant_set_FAT_chain Set data of FAT chain */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 12-31-2020 William E. Lamie Modified comment(s), fixed */
/* available cluster issue, */
/* resulting in version 6.1.3 */
/* */
/**************************************************************************/
UINT _fx_file_extended_truncate_release(FX_FILE *file_ptr, ULONG64 size)
{
UINT status;
ULONG cluster;
ULONG contents;
ULONG bytes_per_cluster;
ULONG last_cluster;
ULONG cluster_count;
ULONG64 bytes_remaining;
FX_MEDIA *media_ptr;
#ifndef FX_DONT_UPDATE_OPEN_FILES
ULONG open_count;
FX_FILE *search_ptr;
#endif
#ifdef TX_ENABLE_EVENT_TRACE
TX_TRACE_BUFFER_ENTRY *trace_event;
ULONG trace_timestamp;
#endif
/* First, determine if the file is still open. */
if (file_ptr -> fx_file_id != FX_FILE_ID)
{
/* Return the file not open error status. */
return(FX_NOT_OPEN);
}
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Setup pointer to media structure. */
media_ptr = file_ptr -> fx_file_media_ptr;
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_file_truncate_releases++;
#endif
/* Setup pointer to associated media control block. */
media_ptr = file_ptr -> fx_file_media_ptr;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_TRUNCATE_RELEASE, file_ptr, size, file_ptr -> fx_file_current_file_size, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
/* Protect against other threads accessing the media. */
FX_PROTECT
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Start transaction. */
_fx_fault_tolerant_transaction_start(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Make sure this file is open for writing. */
if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the access error exception - a write was attempted from
a file opened for reading! */
return(FX_ACCESS_ERROR);
}
/* Check for write protect at the media level (set by driver). */
if (media_ptr -> fx_media_driver_write_protect)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return write protect error. */
return(FX_WRITE_PROTECT);
}
/* Calculate the number of bytes per cluster. */
bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster);
/* Check for invalid value. */
if (bytes_per_cluster == 0)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Invalid media, return error. */
return(FX_MEDIA_INVALID);
}
/* Setup the new file available size - if less than the current available size. */
if (size < file_ptr -> fx_file_current_available_size)
{
/* Yes, the file needs to be truncated. */
/* Update the available file size. */
file_ptr -> fx_file_current_available_size = ((size + bytes_per_cluster - 1) / bytes_per_cluster) * bytes_per_cluster;
/* Is the new available size less than the actual file size? */
if (size < file_ptr -> fx_file_current_file_size)
{
/* Setup the new file size. */
file_ptr -> fx_file_current_file_size = size;
/* Set the modified flag. */
file_ptr -> fx_file_modified = FX_TRUE;
/* Copy the new file size into the directory entry. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = size;
/* Set the first cluster to NULL. */
if (size == 0)
{
/* Yes, the first cluster needs to be cleared since the entire
file is going to be truncated. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster = FX_NULL;
}
/* Write the directory entry to the media. */
status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
/* Check for a good status. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Error writing the directory. */
return(status);
}
}
/* Update the trace event with the truncated size. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_TRUNCATE_RELEASE, 0, 0, 0, file_ptr -> fx_file_current_file_size)
}
else
{
/* Update the trace event with the truncated size. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_TRUNCATE_RELEASE, 0, 0, 0, file_ptr -> fx_file_current_file_size)
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Just return, the truncate size is larger than the available size. */
return(FX_SUCCESS);
}
/* Calculate the number of bytes per cluster. */
bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster);
/* Now check to see if the read/write internal file pointers need
to be adjusted. */
if (file_ptr -> fx_file_current_file_offset > file_ptr -> fx_file_current_file_size)
{
/* At this point, we are ready to walk list of clusters to setup the
seek position of this file. */
cluster = file_ptr -> fx_file_first_physical_cluster;
bytes_remaining = size;
last_cluster = 0;
cluster_count = 0;
/* Follow the link of FAT entries. */
while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
{
/* Increment the number of clusters. */
cluster_count++;
/* Read the current cluster entry from the FAT. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
/* Check the return value. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Save the last valid cluster. */
last_cluster = cluster;
/* Setup for the next cluster. */
cluster = contents;
/* Determine if this is the last written cluster. */
if (bytes_remaining >= bytes_per_cluster)
{
/* Still more seeking, just decrement the working byte offset. */
bytes_remaining = bytes_remaining - bytes_per_cluster;
}
else
{
/* This is the cluster that contains the seek position. */
break;
}
}
/* Check for errors in traversal of the FAT chain. */
if (size > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count)))
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* This is an error that suggests a corrupt file. */
return(FX_FILE_CORRUPT);
}
/* Position the pointers to the new offset. */
file_ptr -> fx_file_current_physical_cluster = last_cluster;
file_ptr -> fx_file_current_relative_cluster = cluster_count - 1;
file_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
(bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector);
file_ptr -> fx_file_current_relative_sector = (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
file_ptr -> fx_file_current_file_offset = size;
file_ptr -> fx_file_current_logical_offset = (ULONG)bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector);
}
/* Determine how many clusters are actually in-use now. */
cluster_count = (ULONG) (file_ptr -> fx_file_current_available_size + (((ULONG64) bytes_per_cluster) - ((ULONG64) 1)))/bytes_per_cluster;
/* Save the number of clusters in-use. */
file_ptr -> fx_file_total_clusters = cluster_count;
/* At this point, we are ready to walk list of clusters to find the clusters
that can be released. */
cluster = file_ptr -> fx_file_first_physical_cluster;
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Is this the last used cluster? */
if ((cluster_count == 0) && (media_ptr -> fx_media_fault_tolerant_enabled))
{
/* Set undo log. */
status = _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, FX_FREE_CLUSTER,
media_ptr -> fx_media_fat_last, cluster, media_ptr -> fx_media_fat_last);
/* Determine if the write was successful. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
file_ptr -> fx_file_last_physical_cluster = cluster;
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Follow the link of FAT entries. */
while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
{
/* Read the current cluster entry from the FAT. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
/* Check the return value. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Determine if are more clusters to release. */
if (cluster_count > 0)
{
/* Decrement the number of clusters. */
cluster_count--;
/* Is this the last used cluster? */
if (cluster_count == 0)
{
{
#ifdef FX_ENABLE_FAULT_TOLERANT
if (media_ptr -> fx_media_fault_tolerant_enabled)
{
/* Set undo phase. */
media_ptr -> fx_media_fault_tolerant_state |= FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN;
/* Read the current cluster entry from the FAT. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
/* Check the return value. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Set undo log. */
status = _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, cluster,
media_ptr -> fx_media_fat_last, contents, media_ptr -> fx_media_fat_last);
/* Determine if the write was successful. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Yes, it should be designated as last cluster. */
status = _fx_utility_FAT_entry_write(media_ptr, cluster, media_ptr -> fx_media_fat_last);
/* Check the return value. */
if (status)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
#ifdef FX_ENABLE_FAULT_TOLERANT
if (media_ptr -> fx_media_fault_tolerant_enabled)
{
/* Clear undo phase. */
media_ptr -> fx_media_fault_tolerant_state &= (UCHAR)(~FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN & 0xff);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
}
file_ptr -> fx_file_last_physical_cluster = cluster;
#ifdef FX_FAULT_TOLERANT
/* Flush the cached individual FAT entries. */
status = _fx_utility_FAT_flush(media_ptr);
/* Check the return value. */
if (status)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
#endif
}
}
else
{
/* This is a cluster after the clusters used by the file, release
it back to the media. */
#ifdef FX_ENABLE_FAULT_TOLERANT
if (media_ptr -> fx_media_fault_tolerant_enabled == FX_FALSE)
{
#endif /* FX_ENABLE_FAULT_TOLERANT */
status = _fx_utility_FAT_entry_write(media_ptr, cluster, FX_FREE_CLUSTER);
/* Check the return value. */
if (status)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Increment the number of available clusters. */
media_ptr -> fx_media_available_clusters++;
#ifdef FX_ENABLE_FAULT_TOLERANT
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
}
/* Setup for the next cluster. */
cluster = contents;
}
/* Determine if we need to adjust the number of leading consecutive clusters. */
if (file_ptr -> fx_file_consecutive_cluster > file_ptr -> fx_file_total_clusters)
{
/* Adjust the leading consecutive cluster count. */
file_ptr -> fx_file_consecutive_cluster = file_ptr -> fx_file_total_clusters;
}
/* Determine if the file available size has been truncated to zero. */
if (file_ptr -> fx_file_current_available_size == 0)
{
/* Yes, the first cluster has already been released. Update the file info
to indicate the file has no clusters. */
file_ptr -> fx_file_last_physical_cluster = 0;
file_ptr -> fx_file_first_physical_cluster = 0;
file_ptr -> fx_file_current_physical_cluster = 0;
file_ptr -> fx_file_current_logical_sector = 0;
file_ptr -> fx_file_current_relative_cluster = 0;
file_ptr -> fx_file_current_relative_sector = 0;
file_ptr -> fx_file_current_available_size = 0;
file_ptr -> fx_file_consecutive_cluster = 1;
}
#ifndef FX_DONT_UPDATE_OPEN_FILES
/* Search the opened files list to see if the same file is opened for reading. */
open_count = media_ptr -> fx_media_opened_file_count;
search_ptr = media_ptr -> fx_media_opened_file_list;
while (open_count)
{
/* Is this file the same file opened for reading? */
if ((search_ptr != file_ptr) &&
(search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector) &&
(search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset))
{
/* Yes, the same file is opened for reading. */
/* Setup the new file size. */
search_ptr -> fx_file_current_file_size = size;
/* Setup the new total clusters. */
search_ptr -> fx_file_total_clusters = file_ptr -> fx_file_total_clusters;
/* Copy the directory entry. */
search_ptr -> fx_file_dir_entry.fx_dir_entry_cluster = file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster;
search_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size;
search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector = file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector;
search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset = file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset;
/* Setup the other file parameters. */
search_ptr -> fx_file_last_physical_cluster = file_ptr -> fx_file_last_physical_cluster;
search_ptr -> fx_file_first_physical_cluster = file_ptr -> fx_file_first_physical_cluster;
search_ptr -> fx_file_current_available_size = file_ptr -> fx_file_current_available_size;
search_ptr -> fx_file_consecutive_cluster = file_ptr -> fx_file_consecutive_cluster;
/* Determine if the truncated file is smaller than the current file offset. */
if (search_ptr -> fx_file_current_file_offset > size)
{
/* Yes, the current file parameters need to be changed since the file was
truncated to a position prior to the current file position. */
/* Calculate the number of bytes per cluster. */
bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster);
/* At this point, we are ready to walk list of clusters to setup the
seek position of this file. */
cluster = search_ptr -> fx_file_first_physical_cluster;
bytes_remaining = size;
last_cluster = 0;
cluster_count = 0;
/* Follow the link of FAT entries. */
while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
{
/* Increment the number of clusters. */
cluster_count++;
/* Read the current cluster entry from the FAT. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
/* Check the return value. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Save the last valid cluster. */
last_cluster = cluster;
/* Setup for the next cluster. */
cluster = contents;
/* Determine if this is the last written cluster. */
if (bytes_remaining >= bytes_per_cluster)
{
/* Still more seeking, just decrement the working byte offset. */
bytes_remaining = bytes_remaining - bytes_per_cluster;
}
else
{
/* This is the cluster that contains the seek position. */
break;
}
}
/* Check for errors in traversal of the FAT chain. */
if (size > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count)))
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* This is an error that suggests a corrupt file. */
return(FX_FILE_CORRUPT);
}
/* Position the pointers to the new offset. */
/* Determine if there is at least one cluster. */
if (cluster_count)
{
/* Calculate real file parameters. */
search_ptr -> fx_file_current_physical_cluster = last_cluster;
search_ptr -> fx_file_current_relative_cluster = cluster_count - 1;
search_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG64)search_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
(bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector);
search_ptr -> fx_file_current_relative_sector = (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
search_ptr -> fx_file_current_file_offset = size;
search_ptr -> fx_file_current_logical_offset = (ULONG)bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector);
}
else
{
/* Calculate zero-length file parameters. */
search_ptr -> fx_file_current_physical_cluster = 0;
search_ptr -> fx_file_current_relative_cluster = 0;
search_ptr -> fx_file_current_logical_sector = 0;
search_ptr -> fx_file_current_relative_sector = 0;
search_ptr -> fx_file_current_file_offset = 0;
search_ptr -> fx_file_current_logical_offset = 0;
}
}
}
/* Adjust the pointer and decrement the search count. */
search_ptr = search_ptr -> fx_file_opened_next;
open_count--;
}
#endif
#ifdef FX_FAULT_TOLERANT
/* Flush the cached individual FAT entries */
status = _fx_utility_FAT_flush(media_ptr);
/* Check the return value. */
if (status)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
#endif
#ifdef FX_ENABLE_FAULT_TOLERANT
if (media_ptr -> fx_media_fault_tolerant_enabled &&
(media_ptr -> fx_media_fault_tolerant_state & FX_FAULT_TOLERANT_STATE_STARTED))
{
/* Copy the new file size into the directory entry. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_current_file_size;
}
/* Write the directory entry to the media. */
status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
/* Check for a good status. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
/* Release media protection. */
FX_UNPROTECT
/* Error writing the directory. */
return(status);
}
/* End transaction. */
status = _fx_fault_tolerant_transaction_end(media_ptr);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
/* Update maximum size used if necessary. */
if (size < file_ptr -> fx_file_maximum_size_used)
{
file_ptr -> fx_file_maximum_size_used = size;
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Truncate is complete, return successful status. */
return(FX_SUCCESS);
}
+543
View File
@@ -0,0 +1,543 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_open PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function first attempts to find the specified file. If found, */
/* the open request is validated and the file is opened. During the */
/* opening process, all of the FAT entries for this file are examined */
/* for their integrity. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* file_ptr File control block pointer */
/* file_name Name pointer */
/* open_type Type of open requested */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_search Search for the file name in */
/* the directory structure */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), and */
/* added conditional to */
/* disable fast open and */
/* consecutive detect, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_file_open(FX_MEDIA *media_ptr, FX_FILE *file_ptr, CHAR *file_name, UINT open_type)
{
UINT status;
#ifndef FX_DISABLE_CONSECUTIVE_DETECT
UINT leading_consecutive;
#endif /* FX_DISABLE_CONSECUTIVE_DETECT */
ULONG cluster;
ULONG contents = 0;
ULONG open_count;
FX_FILE *tail_ptr;
FX_FILE *search_ptr;
ULONG bytes_per_cluster;
UINT last_cluster;
ULONG cluster_count;
ULONG64 bytes_available;
ULONG64 bytes_remaining;
ULONG fat_last;
#ifndef FX_DISABLE_FAST_OPEN
UINT fast_open;
#endif /* FX_DISABLE_FAST_OPEN */
UCHAR not_a_file_attr;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_file_opens++;
#endif
/* Clear the notify function. */
file_ptr -> fx_file_write_notify = FX_NULL;
/* Determine the type of FAT and setup variables accordingly. */
if (media_ptr -> fx_media_32_bit_FAT)
{
fat_last = FX_LAST_CLUSTER_1_32;
not_a_file_attr = FX_DIRECTORY | FX_VOLUME;
}
else
{
fat_last = FX_LAST_CLUSTER_1;
not_a_file_attr = FX_DIRECTORY | FX_VOLUME;
}
#ifndef FX_DISABLE_FAST_OPEN
/* Determine if a fast open is selected. */
if (open_type == FX_OPEN_FOR_READ_FAST)
{
/* Yes, convert the open type to a standard read. */
open_type = FX_OPEN_FOR_READ;
/* Set the open fast flag. */
fast_open = FX_TRUE;
}
else
{
/* A fast open is not selected, set the flag to false. */
fast_open = FX_FALSE;
}
#endif /* FX_DISABLE_FAST_OPEN */
/* If trace is enabled, register this object. */
FX_TRACE_OBJECT_REGISTER(FX_TRACE_OBJECT_TYPE_FILE, file_ptr, file_name, 0, 0)
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_OPEN, media_ptr, file_ptr, file_name, open_type, FX_TRACE_FILE_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Setup file name pointer. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_name = file_ptr -> fx_file_name_buffer;
file_ptr -> fx_file_dir_entry.fx_dir_entry_short_name[0] = 0;
/* Search the system for the supplied file name. */
status = _fx_directory_search(media_ptr, file_name, &(file_ptr -> fx_file_dir_entry), FX_NULL, FX_NULL);
/* Determine if the search was successful. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Check to make sure the found entry is a file. */
if (file_ptr -> fx_file_dir_entry.fx_dir_entry_attributes & not_a_file_attr)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the not a file error code. */
return(FX_NOT_A_FILE);
}
#ifdef FX_SINGLE_OPEN_LEGACY
/* Check to make sure the access is okay. */
if (open_type == FX_OPEN_FOR_READ)
{
/* Check the list of open files for others open for writing. */
open_count = media_ptr -> fx_media_opened_file_count;
search_ptr = media_ptr -> fx_media_opened_file_list;
while (open_count)
{
/* Look at each opened file to see if the same file is opened
for writing. */
if ((search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector) &&
(search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset) &&
(search_ptr -> fx_file_open_mode))
{
/* Release media protection. */
FX_UNPROTECT
/* The file has been opened for writing by a previous call. */
return(FX_ACCESS_ERROR);
}
/* Adjust the pointer and decrement the search count. */
search_ptr = search_ptr -> fx_file_opened_next;
open_count--;
}
}
else
#else
if (open_type == FX_OPEN_FOR_WRITE)
#endif
{
/* A open for write request is present, check the file attributes
and the list of open files for any other open instance of
this file. */
if (media_ptr -> fx_media_driver_write_protect)
{
/* Release media protection. */
FX_UNPROTECT
/* Return write protect error. */
return(FX_WRITE_PROTECT);
}
if (file_ptr -> fx_file_dir_entry.fx_dir_entry_attributes & (UCHAR)(FX_READ_ONLY))
{
/* Release media protection. */
FX_UNPROTECT
/* Return the not a file error code. */
return(FX_ACCESS_ERROR);
}
/* Also search the opened files to see if this file is currently
opened. */
open_count = media_ptr -> fx_media_opened_file_count;
search_ptr = media_ptr -> fx_media_opened_file_list;
while (open_count)
{
/* Look at each opened file to see if the same file is already opened. */
#ifdef FX_SINGLE_OPEN_LEGACY
if ((search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector) &&
(search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset))
#else
/* Look at each opened file to see if the same file is already opened
for writing. */
if ((search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector) &&
(search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset) &&
(search_ptr -> fx_file_open_mode == FX_OPEN_FOR_WRITE))
#endif
{
/* Release media protection. */
FX_UNPROTECT
/* The file is currently open. */
return(FX_ACCESS_ERROR);
}
/* Adjust the pointer and decrement the search count. */
search_ptr = search_ptr -> fx_file_opened_next;
open_count--;
}
}
/* At this point, we are ready to walk list of clusters to setup the
initial condition of this file as well as to verify its integrity. */
cluster = file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster;
bytes_remaining = file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size;
bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster);
file_ptr -> fx_file_current_physical_cluster = 0;
/* Check for invalid value. */
if (bytes_per_cluster == 0)
{
/* Release media protection. */
FX_UNPROTECT
/* Invalid media, return error. */
return(FX_MEDIA_INVALID);
}
last_cluster = 0;
cluster_count = 0;
#ifndef FX_DISABLE_CONSECUTIVE_DETECT
leading_consecutive = 1;
#endif /* FX_DISABLE_CONSECUTIVE_DETECT */
file_ptr -> fx_file_consecutive_cluster = 1;
#ifndef FX_DISABLE_FAST_OPEN
/* Determine if the file is being open for reading with the fast option. */
if (fast_open)
{
/* Calculate the bytes available. */
bytes_available = ((bytes_remaining + bytes_per_cluster - 1) / bytes_per_cluster) * bytes_per_cluster;
}
else
#endif /* FX_DISABLE_FAST_OPEN */
{
/* Follow the link of FAT entries. */
while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
{
/* Increment the number of clusters. */
cluster_count++;
/* Read the current cluster entry from the FAT. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
/* Check the return value. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Determine if the cluster is invalid (points to itself) or the count exceeds the total number of clusters. */
if ((cluster == contents) || (cluster_count > media_ptr -> fx_media_total_clusters))
{
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(FX_FAT_READ_ERROR);
}
#ifndef FX_DISABLE_CONSECUTIVE_DETECT
/* Check if present and next clusters are consecutive */
if (cluster + 1 == contents)
{
/* Determine if clusters are consecutive so far. */
if (leading_consecutive)
{
/* Yes, increment the number of leading consecutive clusters. */
file_ptr -> fx_file_consecutive_cluster++;
}
}
else
{
/* The clusters are no longer consecutive, clear the consecutive flag. */
leading_consecutive = 0;
}
#endif /* FX_DISABLE_CONSECUTIVE_DETECT */
/* Save the last valid cluster. */
last_cluster = cluster;
/* Setup for the next cluster. */
cluster = contents;
/* Determine if this is the last written cluster. We need to remember this
for open for writing. */
if (bytes_remaining > bytes_per_cluster)
{
/* Still more written clusters, just decrement the counter. */
bytes_remaining = bytes_remaining - bytes_per_cluster;
}
else if (!file_ptr -> fx_file_current_physical_cluster)
{
/* Remember this cluster number. */
file_ptr -> fx_file_current_physical_cluster = last_cluster;
/* Remember the relative cluster. */
file_ptr -> fx_file_current_relative_cluster = cluster_count - 1;
/* If the remaining bytes exactly fits the cluster size, check for
a possible adjustment to the next cluster. */
if ((bytes_remaining == bytes_per_cluster) &&
(cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
{
/* We need to position to next allocated cluster. */
file_ptr -> fx_file_current_physical_cluster = cluster;
file_ptr -> fx_file_current_relative_cluster++;
/* Clear the remaining bytes. */
bytes_remaining = 0;
}
}
}
/* Determine if the number of clusters is large enough to support the
specified file size. */
bytes_available = ((ULONG64)media_ptr -> fx_media_bytes_per_sector) *
((ULONG64)media_ptr -> fx_media_sectors_per_cluster) *
((ULONG64)cluster_count);
/* Check the bytes available in the cluster chain against the directory entry file size. */
if ((bytes_available < file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size) ||
((cluster_count) && (contents < fat_last)))
{
/* File is corrupt, release media protection. */
FX_UNPROTECT
/* Return a corrupt file error status. */
return(FX_FILE_CORRUPT);
}
}
/* The file is okay, populate the file control block and complete the
file open process. */
file_ptr -> fx_file_id = FX_FILE_ID;
file_ptr -> fx_file_name = file_ptr -> fx_file_name_buffer;
file_ptr -> fx_file_media_ptr = media_ptr;
file_ptr -> fx_file_open_mode = open_type;
file_ptr -> fx_file_modified = FX_FALSE;
file_ptr -> fx_file_total_clusters = cluster_count;
file_ptr -> fx_file_first_physical_cluster = file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster;
file_ptr -> fx_file_last_physical_cluster = last_cluster;
file_ptr -> fx_file_current_file_size = file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size;
file_ptr -> fx_file_current_available_size = bytes_available;
file_ptr -> fx_file_disable_burst_cache = FX_FALSE;
/* Set the current settings based on how the file was opened. */
if (open_type == FX_OPEN_FOR_READ)
{
/* Position the pointers to the beginning of the file. */
file_ptr -> fx_file_current_physical_cluster = file_ptr -> fx_file_first_physical_cluster;
file_ptr -> fx_file_current_relative_cluster = 0;
file_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG64)(file_ptr -> fx_file_first_physical_cluster - FX_FAT_ENTRY_START)) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster));
file_ptr -> fx_file_current_relative_sector = 0;
file_ptr -> fx_file_current_logical_offset = 0;
file_ptr -> fx_file_current_file_offset = 0;
}
else
{
/* Open for writing - position the pointers to the end of the file. */
/* Determine if the remaining bytes fit exactly into the cluster size. */
if (bytes_remaining == bytes_per_cluster)
{
/* Position to the end of the cluster. */
file_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
((ULONG)(((bytes_remaining - 1) / (ULONG)media_ptr -> fx_media_bytes_per_sector)));
file_ptr -> fx_file_current_relative_sector = (ULONG)(((bytes_remaining - 1) / (ULONG)media_ptr -> fx_media_bytes_per_sector));
file_ptr -> fx_file_current_file_offset = file_ptr -> fx_file_current_file_size;
file_ptr -> fx_file_current_logical_offset = media_ptr -> fx_media_bytes_per_sector;
}
else
{
/* Position file parameters at end of last cluster allocation. */
file_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
((ULONG)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector)));
file_ptr -> fx_file_current_relative_sector = (ULONG)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
file_ptr -> fx_file_current_file_offset = file_ptr -> fx_file_current_file_size;
file_ptr -> fx_file_current_logical_offset = (ULONG)bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector);
}
}
#ifdef FX_ENABLE_FAULT_TOLERANT
/* By default, the whole file is used. */
file_ptr -> fx_file_maximum_size_used = file_ptr -> fx_file_current_file_size;
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Place newly opened file on the list of open files for
this media. First, check for an empty list. */
if (media_ptr -> fx_media_opened_file_list)
{
/* Pickup tail pointer. */
tail_ptr = (media_ptr -> fx_media_opened_file_list) -> fx_file_opened_previous;
/* Place the new file in the list. */
(media_ptr -> fx_media_opened_file_list) -> fx_file_opened_previous = file_ptr;
tail_ptr -> fx_file_opened_next = file_ptr;
/* Setup this file's opened links. */
file_ptr -> fx_file_opened_previous = tail_ptr;
file_ptr -> fx_file_opened_next = media_ptr -> fx_media_opened_file_list;
}
else
{
/* The opened media list is empty. Add the media to empty list. */
media_ptr -> fx_media_opened_file_list = file_ptr;
file_ptr -> fx_file_opened_next = file_ptr;
file_ptr -> fx_file_opened_previous = file_ptr;
}
/* Increment the opened file counter. */
media_ptr -> fx_media_opened_file_count++;
/* Release media protection. */
FX_UNPROTECT
/* Open is complete, return successful status. */
return(FX_SUCCESS);
}
+441
View File
@@ -0,0 +1,441 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_file.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_read PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function reads the specified number of bytes (or as many as */
/* possible into the buffer supplied by the caller. The actual number */
/* of bytes and the status of the read operation is returned to the */
/* caller. In addition, various internal file pointers in the file */
/* control block are also updated. */
/* */
/* INPUT */
/* */
/* file_ptr File control block pointer */
/* buffer_ptr Buffer pointer */
/* request_size Number of bytes requested */
/* actual_size Pointer to variable for the */
/* number of bytes read */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* _fx_utility_logical_sector_read Read a logical sector */
/* _fx_utility_memory_copy Fast memory copy routine */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), verified */
/* memcpy usage, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_file_read(FX_FILE *file_ptr, VOID *buffer_ptr, ULONG request_size, ULONG *actual_size)
{
UINT status;
ULONG bytes_remaining, i;
ULONG copy_bytes;
UCHAR *destination_ptr;
ULONG cluster, next_cluster;
UINT sectors;
FX_MEDIA *media_ptr;
#ifdef TX_ENABLE_EVENT_TRACE
TX_TRACE_BUFFER_ENTRY *trace_event;
ULONG trace_timestamp;
#endif
/* First, determine if the file is still open. */
if (file_ptr -> fx_file_id != FX_FILE_ID)
{
/* Return the file not open error status. */
return(FX_NOT_OPEN);
}
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Setup pointer to media structure. */
media_ptr = file_ptr -> fx_file_media_ptr;
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_file_reads++;
#endif
/* Setup pointer to associated media control block. */
media_ptr = file_ptr -> fx_file_media_ptr;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_READ, file_ptr, buffer_ptr, request_size, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Next, determine if there is any more bytes to read in the file. */
if (file_ptr -> fx_file_current_file_offset >=
file_ptr -> fx_file_current_file_size)
{
/* Release media protection. */
FX_UNPROTECT
/* The file is at the end, return the proper status and set the
actual size to 0. */
*actual_size = 0;
return(FX_END_OF_FILE);
}
/* At this point there is something to read. */
/* Setup local buffer pointer. */
destination_ptr = (UCHAR *)buffer_ptr;
/* Determine if there are less bytes left in the file than that specified
by the request. If so, adjust the requested size. */
if ((ULONG64)request_size >
(file_ptr -> fx_file_current_file_size - file_ptr -> fx_file_current_file_offset))
{
/* Adjust the bytes remaining to what's available. */
request_size = (ULONG)(file_ptr -> fx_file_current_file_size - file_ptr -> fx_file_current_file_offset);
}
/* Setup the remaining number of bytes to read. */
bytes_remaining = request_size;
/* Loop to read all of the bytes. */
while (bytes_remaining)
{
/* Determine if a beginning or ending partial read is required. */
if ((file_ptr -> fx_file_current_logical_offset) ||
(bytes_remaining < media_ptr -> fx_media_bytes_per_sector))
{
/* A partial sector read is required. */
/* Read the current logical sector. */
status = _fx_utility_logical_sector_read(media_ptr,
file_ptr -> fx_file_current_logical_sector,
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
/* Check for good completion status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Copy the appropriate number of bytes into the destination buffer. */
copy_bytes = media_ptr -> fx_media_bytes_per_sector -
file_ptr -> fx_file_current_logical_offset;
/* Check to see if only a portion of the read sector needs to be
copied. */
if (copy_bytes > bytes_remaining)
{
/* Adjust the number of bytes to copy. */
copy_bytes = bytes_remaining;
}
/* Actually perform the memory copy. */
_fx_utility_memory_copy(((UCHAR *)media_ptr -> fx_media_memory_buffer) + /* Use case of memcpy is verified. */
file_ptr -> fx_file_current_logical_offset,
destination_ptr, copy_bytes);
/* Increment the logical sector byte offset. */
file_ptr -> fx_file_current_logical_offset =
file_ptr -> fx_file_current_logical_offset + copy_bytes;
/* Adjust the remaining bytes to read. */
bytes_remaining = bytes_remaining - copy_bytes;
/* Adjust the pointer to the destination buffer. */
destination_ptr = destination_ptr + copy_bytes;
}
else
{
/* Attempt to read multiple sectors directly into the destination
buffer. */
/* Calculate the number of whole sectors to read directly into
the destination buffer. */
sectors = (UINT)(bytes_remaining / media_ptr -> fx_media_bytes_per_sector);
next_cluster = cluster = file_ptr -> fx_file_current_physical_cluster;
for (i = (media_ptr -> fx_media_sectors_per_cluster -
file_ptr -> fx_file_current_relative_sector); i < sectors; i += media_ptr -> fx_media_sectors_per_cluster)
{
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
/* Determine if an error is present. */
if ((status != FX_SUCCESS) || (next_cluster < FX_FAT_ENTRY_START) ||
(next_cluster > media_ptr -> fx_media_fat_reserved))
{
/* Release media protection. */
FX_UNPROTECT
/* Send error message back to caller. */
if (status != FX_SUCCESS)
{
return(status);
}
else
{
return(FX_FILE_CORRUPT);
}
}
if (next_cluster != cluster + 1)
{
break;
}
else
{
cluster = next_cluster;
}
}
if (i < sectors)
{
sectors = i;
}
/* Determine if this is a single sector read request. If so, read the sector so it will
come from the internal cache. */
if (sectors == 1)
{
/* Read the current logical sector. */
status = _fx_utility_logical_sector_read(media_ptr,
file_ptr -> fx_file_current_logical_sector,
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
/* Check for good completion status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Actually perform the memory copy. */
_fx_utility_memory_copy((UCHAR *)media_ptr -> fx_media_memory_buffer, destination_ptr, media_ptr -> fx_media_bytes_per_sector); /* Use case of memcpy is verified. */
}
else
{
/* Multiple sector read request. Read all the sectors at once. */
/* Perform the data read directly into the user's buffer of
the appropriate number of sectors. */
media_ptr -> fx_media_disable_burst_cache = file_ptr -> fx_file_disable_burst_cache;
status = _fx_utility_logical_sector_read(media_ptr, file_ptr -> fx_file_current_logical_sector,
destination_ptr, (ULONG) sectors, FX_DATA_SECTOR);
media_ptr -> fx_media_disable_burst_cache = FX_FALSE;
/* Check for good completion status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
}
/* Now adjust the various file pointers. */
/* Increment the current logical sector. Subtract one from
the sector count because we are going to use the logical
offset to do additional sector/cluster arithmetic below. */
file_ptr -> fx_file_current_logical_sector =
file_ptr -> fx_file_current_logical_sector +
(sectors - 1);
/* Move the relative sector and cluster as well. */
file_ptr -> fx_file_current_relative_cluster = file_ptr -> fx_file_current_relative_cluster +
(file_ptr -> fx_file_current_relative_sector + (sectors - 1)) /
media_ptr -> fx_media_sectors_per_cluster;
file_ptr -> fx_file_current_relative_sector =
(file_ptr -> fx_file_current_relative_sector +
(sectors - 1)) % media_ptr -> fx_media_sectors_per_cluster;
/* Increment the logical sector byte offset. */
file_ptr -> fx_file_current_logical_offset =
media_ptr -> fx_media_bytes_per_sector;
file_ptr -> fx_file_current_physical_cluster = cluster;
/* Adjust the remaining bytes. */
bytes_remaining = bytes_remaining -
(((ULONG)media_ptr -> fx_media_bytes_per_sector) * sectors);
/* Adjust the pointer to the destination buffer. */
destination_ptr = destination_ptr +
(((ULONG)media_ptr -> fx_media_bytes_per_sector) * sectors);
}
/* At this point, we have either read a partial sector or have successfully
read one or more whole sectors. Determine if we are at the end of
the current logical sector. */
if (file_ptr -> fx_file_current_logical_offset >=
media_ptr -> fx_media_bytes_per_sector)
{
/* Determine if we are at the exact physical end of the file at the end of reading. */
if ((bytes_remaining == 0) && ((file_ptr -> fx_file_current_file_offset + (ULONG64)request_size) >=
file_ptr -> fx_file_current_available_size))
{
/* Skip the following file parameter adjustments. The next write will
detect the logical offset out of the range of the sector and reset
all of the pertinent information. */
break;
}
/* We need to move to the next logical sector, but first
determine if the next logical sector is within the same
cluster. */
/* Increment the current relative sector in the cluster. */
file_ptr -> fx_file_current_relative_sector++;
/* Determine if this is in a new cluster. */
if (file_ptr -> fx_file_current_relative_sector >=
media_ptr -> fx_media_sectors_per_cluster)
{
/* Read the FAT entry of the current cluster to find
the next cluster. */
status = _fx_utility_FAT_entry_read(media_ptr,
file_ptr -> fx_file_current_physical_cluster, &next_cluster);
/* Determine if an error is present. */
if ((status != FX_SUCCESS) || (next_cluster < FX_FAT_ENTRY_START) ||
(next_cluster > media_ptr -> fx_media_fat_reserved))
{
/* Release media protection. */
FX_UNPROTECT
/* Send error message back to caller. */
if (status != FX_SUCCESS)
{
return(status);
}
else
{
return(FX_FILE_CORRUPT);
}
}
/* Otherwise, we have a new cluster. Save it in the file
control block and calculate a new logical sector value. */
file_ptr -> fx_file_current_physical_cluster = next_cluster;
file_ptr -> fx_file_current_relative_cluster++;
file_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
((((ULONG64)next_cluster) - FX_FAT_ENTRY_START) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster));
file_ptr -> fx_file_current_relative_sector = 0;
}
else
{
/* Still within the same cluster so just increment the
logical sector. */
file_ptr -> fx_file_current_logical_sector++;
}
/* In either case, we are now positioned at a new sector so
clear the logical sector offset. */
file_ptr -> fx_file_current_logical_offset = 0;
}
}
/* Adjust the current file offset accordingly. */
file_ptr -> fx_file_current_file_offset =
file_ptr -> fx_file_current_file_offset + (ULONG64)request_size;
/* Store the number of bytes actually read. */
*actual_size = request_size;
/* Update the trace event with the bytes read. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_READ, 0, 0, 0, request_size)
/* Update the last accessed date. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_last_accessed_date = _fx_system_date;
/* Release media protection. */
FX_UNPROTECT
/* Return a successful status to the caller. */
return(FX_SUCCESS);
}
+90
View File
@@ -0,0 +1,90 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_file.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_relative_seek PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function positions the internal file pointers to the specified */
/* byte relative offset such that the next read or write operation is */
/* performed there. */
/* */
/* INPUT */
/* */
/* file_ptr File control block pointer */
/* byte_offset Byte offset of the seek */
/* seek_from Direction for relative seek, */
/* legal values are: */
/* */
/* FX_SEEK_BEGIN */
/* FX_SEEK_END */
/* FX_SEEK_FORWARD */
/* FX_SEEK_BACK */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_file_extended_relative_seek Seek to specified position */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), and */
/* Added conditional to */
/* disable one line function, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
#ifndef FX_DISABLE_ONE_LINE_FUNCTION
UINT _fx_file_relative_seek(FX_FILE *file_ptr, ULONG byte_offset, UINT seek_from)
{
return(_fx_file_extended_relative_seek(file_ptr, (ULONG64)byte_offset, seek_from));
}
#endif /* FX_DISABLE_ONE_LINE_FUNCTION */
+550
View File
@@ -0,0 +1,550 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_file.h"
#include "fx_utility.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
#include "fx_fault_tolerant.h"
#endif /* FX_ENABLE_FAULT_TOLERANT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_rename PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function first attempts to find the specified file. If found, */
/* the rename request is valid and the directory entry will be changed */
/* to the new file name. Otherwise, if the file is not found, the */
/* appropriate error code is returned to the caller. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* old_file_name Old file name pointer */
/* new_file_name New file name pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_write Write the new directory entry */
/* _fx_directory_free_search Search for a free directory */
/* entry in target directory */
/* _fx_directory_name_extract Extract the new filename */
/* _fx_directory_search Search for the file name in */
/* the directory structure */
/* _fx_fault_tolerant_transaction_start Start fault tolerant */
/* transaction */
/* _fx_fault_tolerant_transaction_end End fault tolerant transaction*/
/* _fx_fault_tolerant_recover Recover FAT chain */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_file_rename(FX_MEDIA *media_ptr, CHAR *old_file_name, CHAR *new_file_name)
{
ULONG i;
CHAR *work_ptr;
CHAR alpha, beta;
UINT status;
#ifndef FX_DONT_UPDATE_OPEN_FILES
ULONG open_count;
FX_FILE *search_ptr;
#endif
CHAR *new_name_ptr;
FX_DIR_ENTRY old_dir_entry, new_dir_entry;
FX_DIR_ENTRY search_directory;
#ifdef FX_RENAME_PATH_INHERIT
UINT j;
#endif
UCHAR not_a_file_attr;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_file_renames++;
#endif
/* Setup pointers to media name buffers. */
old_dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
new_dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 2;
search_directory.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 3;
/* Clear the short name strings. */
old_dir_entry.fx_dir_entry_short_name[0] = 0;
new_dir_entry.fx_dir_entry_short_name[0] = 0;
search_directory.fx_dir_entry_short_name[0] = 0;
/* Determine if the supplied name is less than the maximum supported name size. The
maximum name (FX_MAX_LONG_NAME_LEN) is defined in fx_api.h. */
i = 0;
work_ptr = (CHAR *)new_file_name;
while (*work_ptr)
{
/* Determine if the character designates a new path. */
if ((*work_ptr == '\\') || (*work_ptr == '/'))
{
/* Yes, reset the name size. */
i = 0;
}
/* Check for leading spaces. */
else if ((*work_ptr != ' ') || (i != 0))
{
/* No leading spaces, increment the name size. */
i++;
}
/* Move to the next character. */
work_ptr++;
}
/* Determine if the supplied name is valid. */
if ((i == 0) || (i >= FX_MAX_LONG_NAME_LEN))
{
/* Return an invalid name value. */
return(FX_INVALID_NAME);
}
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_RENAME, media_ptr, old_file_name, new_file_name, 0, FX_TRACE_FILE_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Start transaction. */
_fx_fault_tolerant_transaction_start(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Check for write protect at the media level (set by driver). */
if (media_ptr -> fx_media_driver_write_protect)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return write protect error. */
return(FX_WRITE_PROTECT);
}
/* Search the system for the supplied file name. */
status = _fx_directory_search(media_ptr, old_file_name, &old_dir_entry, &search_directory, FX_NULL);
/* Determine if the search was successful. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
not_a_file_attr = FX_DIRECTORY | FX_VOLUME;
/* Check to make sure the found entry is a file. */
if (old_dir_entry.fx_dir_entry_attributes & not_a_file_attr)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the not a file error code. */
return(FX_NOT_A_FILE);
}
#ifdef FX_RENAME_PATH_INHERIT
/* Determine if the source file name has a path and the target file name does not. */
if (((old_file_name[0] == '/') || (old_file_name[0] == '\\')) && (new_file_name[0] != '/') && (new_file_name[0] != '\\'))
{
/* In this case, we need to prepend the path of the old file name to that of the new file name. */
/* Setup pointer to the rename buffer. */
work_ptr = (CHAR *)media_ptr -> fx_media_rename_buffer;
/* First, copy the path of the old file name. */
i = 0;
j = 0;
while ((old_file_name[i]) && (i < FX_MAXIMUM_PATH))
{
/* Copy a character into the rename buffer. */
*work_ptr++ = old_file_name[i];
/* Determine if this character is directory separator. */
if ((old_file_name[i] == '/') || (old_file_name[i] == '\\'))
{
/* Yes, directory separator has been found - remember the index. */
j = i;
}
/* Move to next position in the old file name. */
i++;
}
/* At this point, we have the path stored in the rename buffer. */
/* Position past the last slash or backslash. */
j++;
/* Reset the working pointer to the position after the last directory separator. */
work_ptr = (CHAR *)&(media_ptr -> fx_media_rename_buffer[j]);
/* Now copy the new file name into the rename buffer. */
i = 0;
while ((new_file_name[i]) && (j < FX_MAXIMUM_PATH))
{
/* Copy a character into the rename buffer. */
*work_ptr++ = new_file_name[i];
/* Move to next character. */
i++;
j++;
}
/* Determine if the path was successfully prepended. */
if (new_file_name[i])
{
/* No, there was not enough room in the destination buffer. */
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the invalid path error code. */
return(FX_INVALID_PATH);
}
/* Place a NULL at the end of the string. */
*work_ptr = (CHAR)FX_NULL;
/* At this point, we have successfully prepended the path in the new file name, override
the new file name so it is used from now on. */
new_file_name = (CHAR *)media_ptr -> fx_media_rename_buffer;
}
#endif
/* Search the target directory for the same file name. */
status = _fx_directory_search(media_ptr, new_file_name, &new_dir_entry, &search_directory, &new_name_ptr);
/* Determine if the name already exists. */
if (status == FX_SUCCESS)
{
/* Determine if the new name simply has an ASCII case change. If so, simply let the processing
continue. */
i = 0;
do
{
/* Pickup an old name and new name character and convert to upper case if necessary. */
alpha = old_file_name[i];
if ((alpha >= 'a') && (alpha <= 'z'))
{
/* Lower case, convert to upper case! */
alpha = (CHAR)((INT)alpha - 0x20);
}
beta = new_file_name[i];
if ((beta >= 'a') && (beta <= 'z'))
{
/* Lower case, convert to upper case! */
beta = (CHAR)((INT)beta - 0x20);
}
/* Now compare the characters. */
if ((alpha != beta) || (alpha == 0))
{
/* Get out of this loop! */
break;
}
/* Move to next character. */
i++;
} while (i < (FX_MAXIMUM_PATH-1));
/* Now determine if the names match. */
if (alpha != beta)
{
/* No, the names do not match so simply return an error
to the caller. */
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the not a file error code. */
return(FX_ALREADY_CREATED);
}
}
/* Change the file name and look for extra stuff at the end. */
if (_fx_directory_name_extract(new_name_ptr, &new_dir_entry.fx_dir_entry_name[0]))
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Invalid name, return error status. */
return(FX_INVALID_NAME);
}
/* Search for a free spot in the target directory. */
status = _fx_directory_free_search(media_ptr, &search_directory, &new_dir_entry);
/* Determine if a free spot was found. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Extract the new file name. */
_fx_directory_name_extract(new_name_ptr, &new_dir_entry.fx_dir_entry_name[0]);
/* Determine if a long name is present. */
if (new_dir_entry.fx_dir_entry_long_name_present)
{
/* Yes, clear the short file name. */
new_dir_entry.fx_dir_entry_short_name[0] = 0;
}
/* Save the updated directory parameters. */
new_dir_entry.fx_dir_entry_attributes = old_dir_entry.fx_dir_entry_attributes;
new_dir_entry.fx_dir_entry_cluster = old_dir_entry.fx_dir_entry_cluster;
new_dir_entry.fx_dir_entry_file_size = old_dir_entry.fx_dir_entry_file_size;
/* Save the reserved field. */
new_dir_entry.fx_dir_entry_reserved = old_dir_entry.fx_dir_entry_reserved;
/* Set time and date stamps. */
new_dir_entry.fx_dir_entry_created_time_ms = old_dir_entry.fx_dir_entry_created_time_ms;
new_dir_entry.fx_dir_entry_created_time = old_dir_entry.fx_dir_entry_created_time;
new_dir_entry.fx_dir_entry_created_date = old_dir_entry.fx_dir_entry_created_date;
new_dir_entry.fx_dir_entry_last_accessed_date = old_dir_entry.fx_dir_entry_last_accessed_date;
new_dir_entry.fx_dir_entry_time = old_dir_entry.fx_dir_entry_time;
new_dir_entry.fx_dir_entry_date = old_dir_entry.fx_dir_entry_date;
/* Is there a leading dot? */
if (new_dir_entry.fx_dir_entry_name[0] == '.')
{
/* Yes, toggle the hidden attribute bit. */
new_dir_entry.fx_dir_entry_attributes |= FX_HIDDEN;
}
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
/* Invalidate the directory cache. */
media_ptr -> fx_media_last_found_name[0] = FX_NULL;
#endif
/* Now write out the directory entry. */
status = _fx_directory_entry_write(media_ptr, &new_dir_entry);
/* Determine if the write was successful. */
if (status != FX_SUCCESS)
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
#ifndef FX_DONT_UPDATE_OPEN_FILES
/* Search the opened files to update any currently opened files. */
open_count = media_ptr -> fx_media_opened_file_count;
search_ptr = media_ptr -> fx_media_opened_file_list;
while (open_count)
{
/* Look at each opened file to see if it matches the file being renamed. */
if ((search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
old_dir_entry.fx_dir_entry_log_sector) &&
(search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
old_dir_entry.fx_dir_entry_byte_offset))
{
/* Yes, the file being renamed is already open. Update the file's
information so that it is kept current. */
search_ptr -> fx_file_dir_entry.fx_dir_entry_cluster = new_dir_entry.fx_dir_entry_cluster;
search_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = new_dir_entry.fx_dir_entry_file_size;
search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector = new_dir_entry.fx_dir_entry_log_sector;
search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset = new_dir_entry.fx_dir_entry_byte_offset;
/* Copy the new name into the file's name buffer. */
i = 0;
while (i < (FX_MAX_LONG_NAME_LEN - 1))
{
/* Copy byte of the new name. */
search_ptr -> fx_file_dir_entry.fx_dir_entry_name[i] = new_dir_entry.fx_dir_entry_name[i];
/* Move to the next character. */
i++;
/* Determine if we are at the end of the name. */
if (new_dir_entry.fx_dir_entry_name[i] == FX_NULL)
{
/* Determine if we are not at the maximum name size. */
if (i < (FX_MAX_LONG_NAME_LEN - 1))
{
/* Get out of the loop. */
break;
}
}
}
/* Set the NULL termination in the copy of the new name. */
search_ptr -> fx_file_dir_entry.fx_dir_entry_name[i] = FX_NULL;
}
/* Adjust the pointer and decrement the search count. */
search_ptr = search_ptr -> fx_file_opened_next;
open_count--;
}
#endif
/* Now we are ready to remove the old directory entry. */
old_dir_entry.fx_dir_entry_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
old_dir_entry.fx_dir_entry_short_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
/* Now wipe out the old directory entry. */
status = _fx_directory_entry_write(media_ptr, &old_dir_entry);
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
/* End transaction. */
status = _fx_fault_tolerant_transaction_end(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* File rename is complete, return status. */
return(status);
}
+83
View File
@@ -0,0 +1,83 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_file.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_seek PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function positions the internal file pointers to the specified */
/* byte offset such that the next read or write operation will be */
/* performed there. If the byte offset is greater than the size, the */
/* file pointers will be positioned to the end of the file. */
/* */
/* INPUT */
/* */
/* file_ptr File control block pointer */
/* byte_offset Byte offset into the file */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_file_extended_seek Seek to specified position */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), and */
/* Added conditional to */
/* disable one line function, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
#ifndef FX_DISABLE_ONE_LINE_FUNCTION
UINT _fx_file_seek(FX_FILE *file_ptr, ULONG byte_offset)
{
return(_fx_file_extended_seek(file_ptr, (ULONG64) byte_offset));
}
#endif /* FX_DISABLE_ONE_LINE_FUNCTION */
+83
View File
@@ -0,0 +1,83 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_file.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_truncate PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the file to the specified size, if smaller than */
/* the current file size. If the new file size is less than the */
/* current file read/write position, the internal file pointers will */
/* also be modified. */
/* */
/* INPUT */
/* */
/* file_ptr File control block pointer */
/* size New size of the file in bytes */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_file_extended_truncate Truncate the file size */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), and */
/* Added conditional to */
/* disable one line function, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
#ifndef FX_DISABLE_ONE_LINE_FUNCTION
UINT _fx_file_truncate(FX_FILE *file_ptr, ULONG size)
{
return(_fx_file_extended_truncate(file_ptr, (ULONG64)size));
}
#endif /* FX_DISABLE_ONE_LINE_FUNCTION */
+86
View File
@@ -0,0 +1,86 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_file.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_truncate_release PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the file to the specified size, if smaller than */
/* the current file size. If the new file size is less than the */
/* current file read/write position, the internal file pointers will */
/* also be modified. Any unused clusters are released back to the */
/* media. */
/* */
/* INPUT */
/* */
/* file_ptr File control block pointer */
/* size New size of the file in bytes */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_file_extended_truncate_release Truncate the file size and */
/* released unused clusters */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), and */
/* Added conditional to */
/* disable one line function, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
#ifndef FX_DISABLE_ONE_LINE_FUNCTION
UINT _fx_file_truncate_release(FX_FILE *file_ptr, ULONG size)
{
return(_fx_file_extended_truncate_release(file_ptr, (ULONG64)size));
}
#endif /* FX_DISABLE_ONE_LINE_FUNCTION */
File diff suppressed because it is too large Load Diff
+83
View File
@@ -0,0 +1,83 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_file.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_write_notify_set PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the notify function called whenever file is */
/* is written to. */
/* */
/* INPUT */
/* */
/* file_ptr File control block pointer */
/* file_write_notify Notify function called when */
/* file is written to */
/* */
/* OUTPUT */
/* */
/* FX_SUCCESS */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_file_write_notify_set(FX_FILE *file_ptr, VOID (*file_write_notify)(FX_FILE *file))
{
/* Set the notify function. */
file_ptr -> fx_file_write_notify = file_write_notify;
/* Return successful status. */
return(FX_SUCCESS);
}
+189
View File
@@ -0,0 +1,189 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_media.h"
#include "fx_file.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_abort PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function marks all open files for the specified media as */
/* aborted and then removes the media control block from the open */
/* media list and marks it as aborted as well. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* tx_mutex_delete Delete the mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_media_abort(FX_MEDIA *media_ptr)
{
FX_INT_SAVE_AREA
ULONG open_count;
FX_FILE *file_ptr;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_aborts++;
#endif
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_ABORT, media_ptr, 0, 0, 0, FX_TRACE_MEDIA_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Loop through the media's open files. */
open_count = media_ptr -> fx_media_opened_file_count;
file_ptr = media_ptr -> fx_media_opened_file_list;
while (open_count)
{
/* Mark the file as aborted. */
file_ptr -> fx_file_id = FX_FILE_ABORTED_ID;
/* Adjust the pointer and decrement the file opened count. */
file_ptr = file_ptr -> fx_file_opened_next;
open_count--;
}
/* Build the "abort" I/O driver request. */
media_ptr -> fx_media_driver_request = FX_DRIVER_ABORT;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_ABORT, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Call the specified I/O driver with the abort request. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Now remove this media from the open list. */
/* Lockout interrupts for media removal. */
FX_DISABLE_INTS
/* See if the media is the only one on the media opened list. */
if (_fx_system_media_opened_count == ((ULONG) 1))
{
/* Only opened media, just set the opened list to NULL. */
_fx_system_media_opened_ptr = FX_NULL;
}
else
{
/* Otherwise, not the only opened media, link-up the neighbors. */
(media_ptr -> fx_media_opened_next) -> fx_media_opened_previous =
media_ptr -> fx_media_opened_previous;
(media_ptr -> fx_media_opened_previous) -> fx_media_opened_next =
media_ptr -> fx_media_opened_next;
/* See if we have to update the opened list head pointer. */
if (_fx_system_media_opened_ptr == media_ptr)
{
/* Yes, move the head pointer to the next opened media. */
_fx_system_media_opened_ptr = media_ptr -> fx_media_opened_next;
}
}
/* Decrement the opened media counter. */
_fx_system_media_opened_count--;
/* Finally, Indicate that this media is aborted. */
media_ptr -> fx_media_id = FX_MEDIA_ABORTED_ID;
/* Restore interrupt posture. */
FX_RESTORE_INTS
/* Delete the media protection structure if FX_SINGLE_THREAD is not
defined. */
#ifndef FX_SINGLE_THREAD
#ifndef FX_DONT_CREATE_MUTEX
/* Note that the protection is never released. The mutex delete
service will handle all threads waiting access to this media
control block. */
tx_mutex_delete(& (media_ptr -> fx_media_protect));
#endif
#endif
#ifdef FX_DONT_CREATE_MUTEX
/* Release media protection. */
FX_UNPROTECT
#endif
/* Return status to the caller. */
return(FX_SUCCESS);
}
+203
View File
@@ -0,0 +1,203 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_media.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_boot_info_extract PORTABLE C */
/* 6.1.10 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function extracts and validates the information from the boot */
/* record found in the memory buffer. If the boot record is invalid, */
/* an FX_MEDIA_INVALID status is returned to the caller. */
/* */
/* The FAT boot sector (512 bytes) that is operated on by this */
/* function must look like the following: */
/* */
/* Byte Offset Meaning Size */
/* */
/* 0x000 Jump Instructions 3 */
/* 0x003 OEM Name 8 */
/* 0x00B *Bytes per Sector 2 */
/* 0x00D *Sectors per Cluster 1 */
/* 0x00E *Reserved Sectors 2 */
/* 0x010 *Number of FATs 1 */
/* 0x011 *Max Root Dir Entries 2 */
/* 0x013 *Number of Sectors 2 */
/* 0x015 Media Type 1 */
/* 0x016 *Sectors per FAT 2 */
/* 0x018 *Sectors per Track 2 */
/* 0x01A *Number of Heads 2 */
/* 0x01C *Hidden Sectors 4 */
/* 0x020 *Huge Sectors 4 */
/* 0x024 Drive Number 1 */
/* 0x025 Reserved 1 */
/* 0x026 Boot Signature 1 */
/* 0x027 Volume ID 4 */
/* 0x02B Volume Label 11 */
/* 0x036 File System Type 8 */
/* ... ... ... */
/* 0x1FE **Signature (0x55aa) 2 */
/* */
/* * Denotes which elements of the boot record */
/* FileX uses. */
/* */
/* **Denotes the element is checked by the I/O */
/* driver. This eliminates the need for a minimum */
/* 512-byte buffer for FileX. */
/* */
/* Note: All values above are in little endian format, i.e. the LSB is */
/* in the lowest address. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_16_unsigned_read Read a UINT from buffer */
/* _fx_utility_32_unsigned_read Read a ULONG from buffer */
/* _fx_utility_64_unsigned_read Read a ULONG64 from memory */
/* */
/* CALLED BY */
/* */
/* _fx_media_open Media open function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 01-31-2022 Bhupendra Naphade Modified comment(s), added */
/* check for bimap cache size, */
/* resulting in version 6.1.10 */
/* */
/**************************************************************************/
UINT _fx_media_boot_info_extract(FX_MEDIA *media_ptr)
{
UCHAR *boot_sector;
/* Move the buffer pointer into a local copy. */
boot_sector = media_ptr -> fx_media_driver_buffer;
/* Extract the number of bytes per sector. */
media_ptr -> fx_media_bytes_per_sector = _fx_utility_16_unsigned_read(&boot_sector[FX_BYTES_SECTOR]);
if (media_ptr -> fx_media_bytes_per_sector == 0)
return(FX_MEDIA_INVALID);
/* FAT12/16/32 volume. */
/* Extract the number of sectors per track. */
media_ptr -> fx_media_sectors_per_track = _fx_utility_16_unsigned_read(&boot_sector[FX_SECTORS_PER_TRK]);
/* Extract the number of heads. */
media_ptr -> fx_media_heads = _fx_utility_16_unsigned_read(&boot_sector[FX_HEADS]);
/* Extract the total number of sectors. */
media_ptr -> fx_media_total_sectors = _fx_utility_16_unsigned_read(&boot_sector[FX_SECTORS]);
if (media_ptr -> fx_media_total_sectors == 0)
{
media_ptr -> fx_media_total_sectors = _fx_utility_32_unsigned_read(&boot_sector[FX_HUGE_SECTORS]);
}
if (media_ptr -> fx_media_total_sectors == 0)
{
return(FX_MEDIA_INVALID);
}
/* Extract the number of reserved sectors before the first FAT. */
media_ptr -> fx_media_reserved_sectors = _fx_utility_16_unsigned_read(&boot_sector[FX_RESERVED_SECTORS]);
if (media_ptr -> fx_media_reserved_sectors == 0)
{
return(FX_MEDIA_INVALID);
}
/* Extract the number of sectors per cluster. */
media_ptr -> fx_media_sectors_per_cluster = ((UINT)boot_sector[FX_SECTORS_CLUSTER] & 0xFF);
/* There should always be at least one reserved sector, representing the boot record itself. */
if (media_ptr -> fx_media_sectors_per_cluster == 0)
{
return(FX_MEDIA_INVALID);
}
/* Extract the number of sectors per FAT. */
media_ptr -> fx_media_sectors_per_FAT = _fx_utility_16_unsigned_read(&boot_sector[FX_SECTORS_PER_FAT]);
if (media_ptr -> fx_media_sectors_per_FAT == 0)
{
media_ptr -> fx_media_sectors_per_FAT = _fx_utility_32_unsigned_read(&boot_sector[FX_SECTORS_PER_FAT_32]);
}
if (media_ptr -> fx_media_sectors_per_FAT == 0)
{
return(FX_MEDIA_INVALID);
}
/* Extract the number of FATs. */
media_ptr -> fx_media_number_of_FATs = ((UINT)boot_sector[FX_NUMBER_OF_FATS] & 0xFF);
if (media_ptr -> fx_media_number_of_FATs == 0)
{
return(FX_BOOT_ERROR);
}
/* Extract the number of hidden sectors. */
#ifdef FX_DRIVER_USE_64BIT_LBA
media_ptr -> fx_media_hidden_sectors = _fx_utility_64_unsigned_read(&boot_sector[FX_HIDDEN_SECTORS]);
#else
media_ptr -> fx_media_hidden_sectors = _fx_utility_32_unsigned_read(&boot_sector[FX_HIDDEN_SECTORS]);
#endif
/* Extract the number of root directory entries. */
media_ptr -> fx_media_root_directory_entries = _fx_utility_16_unsigned_read(&boot_sector[FX_ROOT_DIR_ENTRIES]);
/* Extract root directory starting cluster (32 bit only) and compute start sector */
media_ptr -> fx_media_root_cluster_32 = _fx_utility_32_unsigned_read(&boot_sector[FX_ROOT_CLUSTER_32]);
/* Return a successful status. */
return(FX_SUCCESS);
}
+134
View File
@@ -0,0 +1,134 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_media.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_cache_invalidate PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function examines the logical cache, flushing written sectors */
/* out to the media and invalidating all sectors in the logical cache. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_FAT_flush Flush cached FAT entries */
/* _fx_utility_FAT_map_flush Flush primary FAT changes to */
/* secondary FAT(s) */
/* _fx_utility_logical_sector_flush Flush logical sector cache */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_media_cache_invalidate(FX_MEDIA *media_ptr)
{
UINT status;
UINT i;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_flushes++;
#endif
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_CACHE_INVALIDATE, media_ptr, 0, 0, 0, FX_TRACE_MEDIA_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
/* Flush changed sector(s) in the primary FAT to secondary FATs. */
_fx_utility_FAT_map_flush(media_ptr);
/* Clear the FAT cache entry array. */
for (i = 0; i < FX_MAX_FAT_CACHE; i++)
{
/* Clear entry in the FAT cache. */
media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_cluster = 0;
media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_value = 0;
}
/* Clear the secondary FAT update map. */
for (i = 0; i < FX_FAT_MAP_SIZE; i++)
{
/* Clear bit map entry for secondary FAT update. */
media_ptr -> fx_media_fat_secondary_update_map[i] = 0;
}
/* Call the logical sector flush to invalidate the logical sector cache. */
status = _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64) (media_ptr -> fx_media_total_sectors), FX_TRUE);
/* Release media protection. */
FX_UNPROTECT
/* If we get here, return successful status to the caller. */
return(status);
}
+712
View File
@@ -0,0 +1,712 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_media.h"
#include "fx_utility.h"
/* Define parameters for FileX media check utility. */
#ifndef FX_MAX_DIRECTORY_NESTING
#define FX_MAX_DIRECTORY_NESTING 20
#endif
/* Define data structures local to the FileX media check utility. */
typedef struct CURRENT_DIRECTORY_ENTRY_STRUCT
{
ULONG current_directory_entry;
ULONG current_total_entries;
ULONG current_start_cluster;
} CURRENT_DIRECTORY_ENTRY;
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_check PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks the specified media for basic structural */
/* errors, including cross linking, invalid FAT chains, and lost */
/* clusters. The function also provides the capability to correct */
/* errors. */
/* */
/* The algorithm is to follow all sub-directories immediately and */
/* check their contents. The maximum depth of sub-directories is */
/* determined by the constant FX_MAX_DIRECTORY_NESTING. */
/* By default, this is set at 20. Basically, the FAT chain of every */
/* file and sub-directory is traversed. If valid, clusters are marked */
/* in a logical FAT bit map to signal they are already in-use. The */
/* algorithm should detect any broken or cross linked FAT condition. */
/* */
/* As for memory usage, the scratch memory supplied to the media check */
/* function is used to hold several directory entries, a data */
/* structure to "stack" the current directory entry position before */
/* diving into the sub-directory, and finally the logical FAT bit map. */
/* The basic data structures take from 512-1024 bytes and the logical */
/* FAT bit map requires as many bits as there are clusters in your */
/* device. For example, a device with 8000 clusters would require */
/* 1000 bytes to represent. */
/* */
/* On the performance end of things, the traversal is reasonably fast */
/* and is basically linear with the number of files and their sizes. */
/* The lost cluster checking at the end of media check is a bit more */
/* performance comprehensive. It basically checks that each unused */
/* cluster is actually marked as free. You might decide to bypass this */
/* step if no other errors are found... or there might be ways to */
/* optimize the search by reading whole FAT sectors. You probably just */
/* need to see how it behaves in your system. */
/* */
/* INPUT */
/* */
/* media_ptr Pointer to a previously */
/* opened media */
/* scratch_memory_ptr Pointer to memory area for */
/* media check to use (as */
/* mentioned above) */
/* scratch_memory_size Size of the scratch memory */
/* error_correction_option Specifies which - if any - */
/* errors are corrected by */
/* the media check function. */
/* Setting the following bit */
/* causes that error to be */
/* corrected: */
/* */
/* 0x01 -> Fix FAT Chain Errors*/
/* 0x02 -> Fix Directory Entry */
/* Errors */
/* 0x04 -> Fix Lost Clusters */
/* */
/* errors_detected Specifies the destination */
/* ULONG to place the error */
/* report from media check. */
/* This has a similar bit map */
/* as before: */
/* */
/* 0x01 -> FAT Chain Error(s) */
/* 0x02 -> Directory Entry */
/* Error(s) */
/* 0x04 -> Lost Cluster(s) */
/* */
/* OUTPUT */
/* */
/* FX_SUCCESS Media check performed its */
/* operation successfully. */
/* This does not mean that */
/* there were no errors. The */
/* errors_detected variable */
/* needs to be examined. */
/* FX_MEDIA_NOT_OPEN The media was not open. */
/* FX_NOT_ENOUGH_MEMORY The scratch memory was not */
/* large enough or the nesting */
/* depth was greater than the */
/* maximum specified. */
/* FX_IO_ERROR I/O Error reading/writing to */
/* the media. */
/* FX_ERROR_NOT_FIXED Fundamental problem with */
/* media that couldn't be fixed*/
/* */
/* CALLS */
/* */
/* _fx_media_cache_invalidate Invalidate the cache */
/* _fx_media_check_FAT_chain_check Walk the supplied FAT chain */
/* _fx_media_check_lost_cluster_check Check for lost clusters */
/* _fx_directory_entry_read Directory entry read */
/* _fx_directory_entry_write Directory entry write */
/* _fx_media_flush Flush changes to the media */
/* _fx_utility_FAT_entry_write Write value to FAT entry */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_media_check(FX_MEDIA *media_ptr, UCHAR *scratch_memory_ptr, ULONG scratch_memory_size, ULONG error_correction_option, ULONG *errors_detected)
{
CURRENT_DIRECTORY_ENTRY *current_directory;
ULONG total_entries, last_cluster, valid_clusters;
ULONG bytes_per_cluster, i, current_errors;
UINT status, long_name_size;
UINT current_directory_index;
UCHAR *logical_fat, *working_ptr;
ALIGN_TYPE address_mask;
FX_DIR_ENTRY *temp_dir_ptr, *source_dir_ptr, *dir_entry_ptr;
#ifdef TX_ENABLE_EVENT_TRACE
TX_TRACE_BUFFER_ENTRY *trace_event;
ULONG trace_timestamp;
#endif
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_CHECK, media_ptr, scratch_memory_ptr, scratch_memory_size, 0, FX_TRACE_MEDIA_EVENTS, &trace_event, &trace_timestamp)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Determine if there are any opened files. */
if (media_ptr -> fx_media_opened_file_count)
{
/* There are opened files... this is an error! */
/* Release protection. */
FX_UNPROTECT
/* Return an error. */
return(FX_ACCESS_ERROR);
}
/* Invalidate the cache. */
_fx_media_cache_invalidate(media_ptr);
/* Initialize the reported error flag. */
*errors_detected = 0;
/* Calculate the long name size, rounded up to something that is evenly divisible by 4. */
long_name_size = (((FX_MAX_LONG_NAME_LEN + 3) >> 2) << 2);
/* Calculate the number of bytes per cluster. */
bytes_per_cluster = media_ptr -> fx_media_sectors_per_cluster * media_ptr -> fx_media_bytes_per_sector;
/* Setup address mask. */
address_mask = sizeof(ULONG) - 1;
address_mask = ~address_mask;
/* Setup working pointer. */
working_ptr = scratch_memory_ptr + (sizeof(ULONG) - 1);
working_ptr = (UCHAR *)(((ALIGN_TYPE)working_ptr) & address_mask);
/* Memory is set aside for two FX_DIR_ENTRY structures */
dir_entry_ptr = (FX_DIR_ENTRY *)working_ptr;
/* Adjust the scratch memory pointer forward. */
working_ptr = &working_ptr[sizeof(FX_DIR_ENTRY)];
/* Setup the name buffer for the first directory entry. */
dir_entry_ptr -> fx_dir_entry_name = (CHAR *)working_ptr;
/* Adjust the scratch memory pointer forward. */
working_ptr = working_ptr + long_name_size + (sizeof(ULONG) - 1);
working_ptr = (UCHAR *)(((ALIGN_TYPE)working_ptr) & address_mask);
/* Setup the source directory entry. */
source_dir_ptr = (FX_DIR_ENTRY *)working_ptr;
/* Adjust the scratch memory pointer forward. */
working_ptr = &working_ptr[sizeof(FX_DIR_ENTRY)];
/* Setup the name buffer for the source directory entry. */
source_dir_ptr -> fx_dir_entry_name = (CHAR *)working_ptr;
/* Adjust the scratch memory pointer forward. */
working_ptr = working_ptr + long_name_size + (sizeof(ULONG) - 1);
working_ptr = (UCHAR *)(((ALIGN_TYPE)working_ptr) & address_mask);
/* Setup the current directory stack memory. */
current_directory = (CURRENT_DIRECTORY_ENTRY *)working_ptr;
/* Allocate space for the size of the directory entry stack. This basically
defines the maximum level of sub-directories supported. */
working_ptr = &working_ptr[(FX_MAX_DIRECTORY_NESTING * sizeof(CURRENT_DIRECTORY_ENTRY))];
/* Setup the initial current directory entry. */
current_directory_index = 0;
/* Adjust the size to account for the header information. */
if (scratch_memory_size < (ULONG)((working_ptr - scratch_memory_ptr)))
{
/* Release media protection. */
FX_UNPROTECT
/* Return the not enough memory error. */
return(FX_NOT_ENOUGH_MEMORY);
}
/* Adjust the scratch memory size. */
scratch_memory_size = scratch_memory_size - (ULONG)(working_ptr - scratch_memory_ptr);
/* Memory is set aside for logical FAT - one bit per cluster */
logical_fat = (UCHAR *)working_ptr;
/* Determine if there is enough memory. */
if (scratch_memory_size < ((media_ptr -> fx_media_total_clusters >> 3) + 1))
{
/* Release media protection. */
FX_UNPROTECT
/* Return the not enough memory error. */
return(FX_NOT_ENOUGH_MEMORY);
}
/* Initialize the logical FAT table. */
for (i = 0; i < ((media_ptr -> fx_media_total_clusters >> 3) + 1); i++)
{
/* Clear the logical FAT entry, which actually represents eight clusters. */
logical_fat[i] = 0;
}
#ifdef FX_ENABLE_FAULT_TOLERANT
if (media_ptr -> fx_media_fault_tolerant_enabled)
{
ULONG cluster, cluster_number;
/* Mark the cluster used by fault tolerant as valid. */
for (cluster = media_ptr -> fx_media_fault_tolerant_start_cluster;
cluster < media_ptr -> fx_media_fault_tolerant_start_cluster + media_ptr -> fx_media_fault_tolerant_clusters;
cluster++)
{
cluster_number = cluster;
logical_fat[cluster_number >> 3] = (UCHAR)(logical_fat[cluster_number >> 3] | (1 << (cluster_number & 7)));
}
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* If FAT32 is present, determine if the root directory is coherent. */
if (media_ptr -> fx_media_32_bit_FAT)
{
/* A 32-bit FAT is present. We need to walk the clusters of the root directory to determine if
it is intact. */
current_errors = _fx_media_check_FAT_chain_check(media_ptr, media_ptr -> fx_media_root_cluster_32,
&last_cluster, &valid_clusters, logical_fat);
/* Make them part of the errors reported to the caller. */
*errors_detected = *errors_detected | current_errors;
/* Update the trace event with the errors detected. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
/* Determine if the I/O error is set. */
if (current_errors & FX_IO_ERROR)
{
/* Release media protection. */
FX_UNPROTECT
/* File I/O Error. */
return(FX_IO_ERROR);
}
/* Check the status. */
if (*errors_detected)
{
/* Determine if we can fix the FAT32 root directory error. */
if ((valid_clusters) && (error_correction_option & FX_FAT_CHAIN_ERROR))
{
/* Make the chain end at the last cluster. */
status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, media_ptr -> fx_media_fat_last);
/* Determine if the write was successful. */
if (status)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Adjust the total entries in the root directory. */
media_ptr -> fx_media_root_directory_entries = (valid_clusters * bytes_per_cluster) / FX_DIR_ENTRY_SIZE;
}
else
{
/* Release media protection. */
FX_UNPROTECT
/* Return an error. */
return(FX_ERROR_NOT_FIXED);
}
}
}
/* Pickup total entries in the root directory. */
total_entries = media_ptr -> fx_media_root_directory_entries;
/* Set temp directory pointer to NULL. */
temp_dir_ptr = FX_NULL;
/* Put the root directory information in the entry stack */
current_directory[current_directory_index].current_total_entries = total_entries;
current_directory[current_directory_index].current_start_cluster = media_ptr -> fx_media_fat_last;
current_directory[current_directory_index].current_directory_entry = 0;
/* Now we shall do the checking in depth first manner. */
do
{
/* Pickup the directory index. */
i = current_directory[current_directory_index].current_directory_entry;
/* Loop to process remaining directory entries. */
while (i < current_directory[current_directory_index].current_total_entries)
{
/* Read a directory entry. */
status = _fx_directory_entry_read(media_ptr, temp_dir_ptr, &i, dir_entry_ptr);
/* Determine if the read was successful. */
if (status)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Check for the last entry. */
if (dir_entry_ptr -> fx_dir_entry_name[0] == (CHAR)FX_DIR_ENTRY_DONE)
{
/* Last entry in this directory - no need to check further. */
break;
}
/* Is the entry free? */
if ((dir_entry_ptr -> fx_dir_entry_name[0] == (CHAR)FX_DIR_ENTRY_FREE) && (dir_entry_ptr -> fx_dir_entry_short_name[0] == 0))
{
/* A deleted entry */
i++;
continue;
}
/* Look for any cross links or errors in the FAT chain of current directory entry. */
current_errors = _fx_media_check_FAT_chain_check(media_ptr, dir_entry_ptr -> fx_dir_entry_cluster,
&last_cluster, &valid_clusters, logical_fat);
/* Make them part of the errors reported to the caller. */
*errors_detected = *errors_detected | current_errors;
/* Update the trace event with the errors detected. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
/* Determine if the I/O error is set. */
if (current_errors & FX_IO_ERROR)
{
/* Release media protection. */
FX_UNPROTECT
/* File I/O Error. */
return(FX_IO_ERROR);
}
/* Check for errors. */
if (*errors_detected)
{
/* Determine if we can fix the FAT chain. */
if (error_correction_option & FX_FAT_CHAIN_ERROR)
{
/* Determine if there is a valid cluster to write the EOF to. */
if (valid_clusters)
{
/* Write EOF in the last FAT entry. */
status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, media_ptr -> fx_media_fat_last);
/* Determine if the write was successful. */
if (status)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
}
}
}
/* Determine if we need to update the size of the directory entry. */
if (dir_entry_ptr -> fx_dir_entry_file_size > (valid_clusters * bytes_per_cluster))
{
/* Yes, update the directory entry's size. */
dir_entry_ptr -> fx_dir_entry_file_size = valid_clusters * bytes_per_cluster;
/* Determine if the new file size is zero. */
if (dir_entry_ptr -> fx_dir_entry_file_size == 0)
{
/* Consider this a directory error. */
*errors_detected = *errors_detected | FX_DIRECTORY_ERROR;
/* Update the trace event with the errors detected. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
/* Clear the starting cluster number of this directory entry. */
dir_entry_ptr -> fx_dir_entry_cluster = 0;
/* If directory fixing is required, delete this directory entry as well. */
if (error_correction_option & FX_DIRECTORY_ERROR)
{
/* Mark the entry as deleted. */
dir_entry_ptr -> fx_dir_entry_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
dir_entry_ptr -> fx_dir_entry_short_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
}
}
/* Only update the directory if the FAT chain was actually updated. */
if (error_correction_option & FX_FAT_CHAIN_ERROR)
{
/* Update the directory entry. */
status = _fx_directory_entry_write(media_ptr, dir_entry_ptr);
/* Determine if the write was successful. */
if (status)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
}
}
/* Determine if the entry is a sub-directory. */
if ((dir_entry_ptr -> fx_dir_entry_attributes & FX_DIRECTORY)
&& (valid_clusters == 0))
{
/* Consider this a directory error. */
*errors_detected = *errors_detected | FX_DIRECTORY_ERROR;
/* Update the trace event with the errors detected. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
/* Determine if we can fix the error. */
if (error_correction_option & FX_DIRECTORY_ERROR)
{
/* Yes, make the directory entry free. */
dir_entry_ptr -> fx_dir_entry_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
dir_entry_ptr -> fx_dir_entry_short_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
/* Delete the sub-directory entry. */
status = _fx_directory_entry_write(media_ptr, dir_entry_ptr);
/* Determine if the write was successful. */
if (status)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Move to next entry. */
i++;
continue;
}
}
/* Determine if the entry is a directory. */
if (dir_entry_ptr -> fx_dir_entry_attributes & FX_DIRECTORY)
{
/* Current entry is a directory. The algorithm is designed to follow all
sub-directories immediately, i.e., a depth first search. */
/* First, save the next entry position. */
current_directory[current_directory_index].current_directory_entry = i + 1;
/* Push the current directory entry on the stack. */
current_directory_index++;
/* Check for current directory stack overflow. */
if (current_directory_index >= FX_MAX_DIRECTORY_NESTING)
{
/* Release media protection. */
FX_UNPROTECT
/* Current directory stack overflow. Return error. */
return(FX_NOT_ENOUGH_MEMORY);
}
/* Otherwise, setup the new directory entry. */
current_directory[current_directory_index].current_total_entries = (valid_clusters * bytes_per_cluster) / FX_DIR_ENTRY_SIZE;
current_directory[current_directory_index].current_start_cluster = dir_entry_ptr -> fx_dir_entry_cluster;
current_directory[current_directory_index].current_directory_entry = 2;
/* Setup new source directory. */
source_dir_ptr -> fx_dir_entry_cluster = dir_entry_ptr -> fx_dir_entry_cluster;
source_dir_ptr -> fx_dir_entry_file_size = current_directory[current_directory_index].current_total_entries;
source_dir_ptr -> fx_dir_entry_last_search_cluster = 0;
temp_dir_ptr = source_dir_ptr;
/* Skip the first two entries of sub-directories. */
i = 2;
}
else
{
/* Regular file entry. */
/* Check for an invalid file size. */
if (((valid_clusters * bytes_per_cluster) - dir_entry_ptr -> fx_dir_entry_file_size) > bytes_per_cluster)
{
/* There are more clusters allocated than needed for the file's size. Indicate that this error
is present. */
*errors_detected = *errors_detected | FX_FILE_SIZE_ERROR;
/* Update the trace event with the errors detected. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
/* For now, don't shorten the cluster chain. */
}
/* Look into the next entry in the current directory. */
i++;
}
}
/* Once we get here, we have exhausted the current directory and need to return to the previous
directory. */
/* Check for being at the root directory. */
if (current_directory_index == 0)
{
/* Yes, we have now exhausted searching the root directory so we are done! */
break;
}
/* Backup to the place we left off in the previous directory. */
current_directory_index--;
/* Determine if we are now back at the root directory. */
if (current_directory[current_directory_index].current_start_cluster == media_ptr -> fx_media_fat_last)
{
/* The search directory should be NULL since it is the root directory. */
temp_dir_ptr = FX_NULL;
}
else
{
/* Otherwise, we are returning to a sub-directory. Setup the search directory
appropriately. */
source_dir_ptr -> fx_dir_entry_cluster = current_directory[current_directory_index].current_start_cluster;
source_dir_ptr -> fx_dir_entry_file_size = current_directory[current_directory_index].current_total_entries;
source_dir_ptr -> fx_dir_entry_last_search_cluster = 0;
temp_dir_ptr = source_dir_ptr;
}
} while (1);
/* At this point, all the files and sub-directories have been examined. We now need to check for
lost clusters in the logical FAT. A lost cluster is basically anything that is not reported in
the logical FAT that has a non-zero value in the real FAT. */
current_errors = _fx_media_check_lost_cluster_check(media_ptr, logical_fat, media_ptr -> fx_media_total_clusters, error_correction_option);
/* Incorporate the error returned by the lost FAT check. */
*errors_detected = *errors_detected | current_errors;
/* Update the trace event with the errors detected. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
/* Determine if the I/O error is set. */
if (current_errors & FX_IO_ERROR)
{
/* Release media protection. */
FX_UNPROTECT
/* File I/O Error. */
return(FX_IO_ERROR);
}
/* Determine if there was any error and update was selected. */
if ((*errors_detected) && (error_correction_option))
{
/* Flush any unwritten items to the media. */
_fx_media_flush(media_ptr);
}
/* Release media protection. */
FX_UNPROTECT
/* At this point, we have completed the diagnostic of the media, return success! */
return(FX_SUCCESS);
}
+162
View File
@@ -0,0 +1,162 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_media.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_check_FAT_chain_check PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function walks the supplied FAT chain looking for cross links */
/* (FAT entries already used in another FAT chain) and abnormal FAT */
/* entries and invalid chain termination. */
/* */
/* INPUT */
/* */
/* media_ptr Pointer to a previously */
/* opened media */
/* starting_cluster Starting cluster of FAT chain */
/* last_valid_cluster Last valid cluster of chain */
/* total_valid_clusters Total number of valid clusters*/
/* logical_fat Pointer to the logical FAT */
/* bit map */
/* */
/* OUTPUT */
/* */
/* error Error code */
/* */
/* CALLS */
/* */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* */
/* CALLED BY */
/* */
/* _fx_check_media Check media function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
ULONG _fx_media_check_FAT_chain_check(FX_MEDIA *media_ptr, ULONG starting_cluster, ULONG *last_valid_cluster, ULONG *total_valid_clusters, UCHAR *logical_fat)
{
ULONG prev_cluster, cluster, next_clust = 0;
ULONG cluster_number;
ULONG count, error;
UINT status;
/* Initialize the error code. */
error = 0;
/* Setup at the first cluster. */
cluster = starting_cluster;
/* Initialize the previous cluster. */
prev_cluster = 0;
/* Initialize the count to 0. */
count = 0;
/* Loop to walk through the FAT chain. */
while ((cluster >= (ULONG)FX_FAT_ENTRY_START) &&
(cluster < (FX_FAT_ENTRY_START + media_ptr -> fx_media_total_clusters)))
{
cluster_number = cluster;
/* Determine if this cluster is already in the logical FAT bit map. */
if (logical_fat[cluster_number >> 3] & (1 << (cluster_number & 7)))
{
/* Yes, the cluster is already being used by another file or
sub-directory. */
error = FX_FAT_CHAIN_ERROR;
break;
}
/* Now read the contents of the cluster. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_clust);
/* Check the return status. */
if (status != FX_SUCCESS)
{
/* Yes, the cluster is already being used by another file or
sub-directory. */
error = FX_IO_ERROR;
break;
}
/* Determine if the link is circular or the count is greater than the
total clusters. */
if ((cluster == next_clust) ||
(next_clust < (ULONG)FX_FAT_ENTRY_START) ||
((next_clust >= (FX_FAT_ENTRY_START + media_ptr -> fx_media_total_clusters)) &&
(next_clust != media_ptr -> fx_media_fat_last)))
{
error = FX_FAT_CHAIN_ERROR;
break;
}
/* Everything is good with the chain at this point. Mark it as valid. */
logical_fat[cluster_number >> 3] = (UCHAR)(logical_fat[cluster_number >> 3] | (1 << (cluster_number & 7)));
/* Move the cluster variable forward. */
prev_cluster = cluster;
cluster = next_clust;
/* Increment the number of valid clusters. */
count++;
}
/* Return the last valid cluster and the total valid cluster count. */
*last_valid_cluster = prev_cluster;
*total_valid_clusters = count;
/* Return error code. */
return(error);
}
@@ -0,0 +1,169 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_media.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_check_lost_cluster_check PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function examines all clusters to see if there are any unused */
/* clusters that are also unavailable. If specified, this routine will */
/* also mark the cluster as available. */
/* */
/* INPUT */
/* */
/* media_ptr Pointer to a previously */
/* opened media */
/* logical_fat Pointer to the logical FAT */
/* bit map */
/* total_clusters Total number of clusters */
/* error_correction_option Option for correcting lost */
/* cluster errors */
/* */
/* OUTPUT */
/* */
/* error Error code */
/* */
/* CALLS */
/* */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* _fx_utility_FAT_entry_write Write a FAT entry */
/* */
/* CALLED BY */
/* */
/* _fx_check_media Check media function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
ULONG _fx_media_check_lost_cluster_check(FX_MEDIA *media_ptr, UCHAR *logical_fat, ULONG total_clusters, ULONG error_correction_option)
{
ULONG cluster, next_cluster = 0;
ULONG fat_last;
ULONG error;
UINT status;
/* Calculate the FAT reserved and last sector values. */
if (media_ptr -> fx_media_32_bit_FAT)
{
fat_last = FX_LAST_CLUSTER_1_32;
}
else
{
fat_last = FX_LAST_CLUSTER_1;
}
/* Initialize the error. */
error = 0;
/* Loop through all the clusters to see if any clusters NOT in the logical sector FAT have
a non zero value. */
for (cluster = FX_FAT_ENTRY_START; cluster < total_clusters; cluster++)
{
/* Determine if this cluster is in the logical FAT. */
if (logical_fat[cluster >> 3] & (1 << (cluster & 7)))
{
/* Yes, the cluster is in use by a file or sub-directory. Just continue the loop. */
continue;
}
/* Otherwise, the cluster is not in use. */
/* Read the contents of what should be a free cluster. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
/* Check for a good status. */
if (status)
{
/* Set the error code. */
error = error | FX_IO_ERROR;
/* Return error code. */
return(error);
}
/* Determine if the contents of the cluster is valid. */
if (((next_cluster > (ULONG)FX_FREE_CLUSTER) && (next_cluster < media_ptr -> fx_media_fat_reserved)) ||
(next_cluster >= fat_last))
{
/* Lost cluster is present. */
/* Set the error code status. */
error = FX_LOST_CLUSTER_ERROR;
/* Determine if the lost cluster should be recovered. */
if (error_correction_option & FX_LOST_CLUSTER_ERROR)
{
/* Make the cluster available again. */
status = _fx_utility_FAT_entry_write(media_ptr, cluster, FX_FREE_CLUSTER);
/* Check for a good status. */
if (status)
{
/* Increment the available clusters. */
media_ptr -> fx_media_available_clusters++;
/* Set the error code. */
error = error | FX_IO_ERROR;
/* Return error code. */
return(error);
}
}
}
}
/* Return error code. */
return(error);
}
+425
View File
@@ -0,0 +1,425 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_media.h"
#include "fx_file.h"
#include "fx_directory.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_close PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function examines the list of open files for this media and */
/* closes each file. If a file has been written to, the file's */
/* directory information is also written out to the media. After */
/* the files have been closed, the internal logical sector is */
/* flushed and a flush command is sent to the attached driver. */
/* Finally, this media control block is removed from the list of */
/* opened media control blocks and is marked as closed. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_write Write the directory entry */
/* _fx_media_abort Abort the media on error */
/* _fx_utility_FAT_flush Flush cached FAT entries */
/* _fx_utility_FAT_map_flush Flush primary FAT changes to */
/* secondary FAT(s) */
/* _fx_utility_logical_sector_flush Flush logical sector cache */
/* _fx_utility_16_unsigned_read Read a 16-bit value */
/* _fx_utility_32_unsigned_read Read a 32-bit value */
/* _fx_utility_32_unsigned_write Write a 32-bit value */
/* tx_mutex_delete Delete protection mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), and */
/* added conditional to */
/* disable file close */
/* and cache, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_media_close(FX_MEDIA *media_ptr)
{
FX_INT_SAVE_AREA
#ifndef FX_DISABLE_FILE_CLOSE
ULONG open_count;
FX_FILE *file_ptr;
#endif /* FX_DISABLE_FILE_CLOSE */
UINT status;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_CLOSE, media_ptr, 0, 0, 0, FX_TRACE_MEDIA_EVENTS, 0, 0)
/* If trace is enabled, unregister this object. */
FX_TRACE_OBJECT_UNREGISTER(media_ptr)
/* Protect against other threads accessing the media. */
FX_PROTECT
#ifndef FX_DISABLE_FILE_CLOSE
/* Loop through the media's open files. */
open_count = media_ptr -> fx_media_opened_file_count;
file_ptr = media_ptr -> fx_media_opened_file_list;
while (open_count)
{
/* Look at each opened file to see if the same file is opened
for writing and has been written to. */
if ((file_ptr -> fx_file_open_mode == FX_OPEN_FOR_WRITE) &&
(file_ptr -> fx_file_modified))
{
/* Lockout interrupts for time/date access. */
FX_DISABLE_INTS
/* Set the new time and date. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_time = _fx_system_time;
file_ptr -> fx_file_dir_entry.fx_dir_entry_date = _fx_system_date;
/* Restore interrupt posture. */
FX_RESTORE_INTS
/* Copy the new file size into the directory entry. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =
file_ptr -> fx_file_current_file_size;
/* Write the directory entry to the media. */
status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
/* Determine if the status was unsuccessful. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Call the media abort routine. */
_fx_media_abort(media_ptr);
/* Return the error status. */
return(FX_IO_ERROR);
}
/* Clear the file modified flag. */
file_ptr -> fx_file_modified = FX_FALSE;
}
/* Mark the file as closed. */
file_ptr -> fx_file_id = FX_FILE_CLOSED_ID;
/* Adjust the pointer and decrement the opened count. */
file_ptr = file_ptr -> fx_file_opened_next;
open_count--;
}
#endif /* FX_DISABLE_FILE_CLOSE */
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
/* Flush changed sector(s) in the primary FAT to secondary FATs. */
_fx_utility_FAT_map_flush(media_ptr);
/* Flush the internal logical sector cache. */
status = _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64) (media_ptr -> fx_media_total_sectors), FX_FALSE);
/* Determine if the flush was unsuccessful. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Call the media abort routine. */
_fx_media_abort(media_ptr);
/* Return the error status. */
return(FX_IO_ERROR);
}
/* Determine if the media needs to have the additional information sector updated. This will
only be the case for 32-bit FATs. The logic here only needs to be done if the last reported
available cluster count is different that the currently available clusters. */
if ((media_ptr -> fx_media_FAT32_additional_info_sector) &&
(media_ptr -> fx_media_FAT32_additional_info_last_available != media_ptr -> fx_media_available_clusters) &&
(media_ptr -> fx_media_driver_write_protect == FX_FALSE))
{
UCHAR *buffer_ptr;
ULONG signature;
#ifndef FX_DISABLE_CACHE
/* Setup a pointer to the first cached entry's buffer. */
buffer_ptr = (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_memory_buffer;
/* Invalidate this cache entry. */
(media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector = (~(ULONG64)0);
(media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_valid = FX_FALSE;
#else
buffer_ptr = media_ptr -> fx_media_memory_buffer;
#endif /* FX_DISABLE_CACHE */
/* Read the FAT32 additional information sector from the device. */
media_ptr -> fx_media_driver_request = FX_DRIVER_READ;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
media_ptr -> fx_media_driver_buffer = buffer_ptr;
media_ptr -> fx_media_driver_logical_sector = media_ptr -> fx_media_FAT32_additional_info_sector;
media_ptr -> fx_media_driver_sectors = 1;
media_ptr -> fx_media_driver_sector_type = FX_DIRECTORY_SECTOR;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of driver read sector(s) requests. */
media_ptr -> fx_media_driver_read_requests++;
#endif
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_READ, media_ptr, media_ptr -> fx_media_FAT32_additional_info_sector, 1, buffer_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Invoke the driver to read the FAT32 additional information sector. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Determine if the FAT32 sector was read correctly. */
if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Call the media abort routine. */
_fx_media_abort(media_ptr);
/* Return the error status. */
return(FX_IO_ERROR);
}
/* Setup a pointer into the FAT32 additional information sector. */
buffer_ptr = media_ptr -> fx_media_driver_buffer;
/* Pickup the first signature long word. */
signature = _fx_utility_32_unsigned_read(&buffer_ptr[0]);
/* Determine if the signature is correct. */
if (signature == 0x41615252)
{
/* Yes, the first signature is correct, now pickup the next signature. */
signature = _fx_utility_32_unsigned_read(&buffer_ptr[484]);
/* Determine if this signature is correct. */
if (signature == 0x61417272)
{
/* Yes, we have a good FAT32 additional information sector. */
/* Set the free cluster count to the available clusters in the media control block. */
_fx_utility_32_unsigned_write(&buffer_ptr[488], media_ptr -> fx_media_available_clusters);
/* Set the next free cluster number hint to starting search cluster in the media control block. */
_fx_utility_32_unsigned_write(&buffer_ptr[492], media_ptr -> fx_media_cluster_search_start);
/* Now write the sector back out to the media. */
media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
media_ptr -> fx_media_driver_buffer = buffer_ptr;
media_ptr -> fx_media_driver_logical_sector = media_ptr -> fx_media_FAT32_additional_info_sector;
media_ptr -> fx_media_driver_sectors = 1;
media_ptr -> fx_media_driver_sector_type = FX_DIRECTORY_SECTOR;
/* Set the system write flag since we are writing a directory sector. */
media_ptr -> fx_media_driver_system_write = FX_TRUE;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of driver write sector(s) requests. */
media_ptr -> fx_media_driver_write_requests++;
#endif
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, media_ptr -> fx_media_FAT32_additional_info_sector, 1, buffer_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Invoke the driver to write the FAT32 additional information sector. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Clear the system write flag. */
media_ptr -> fx_media_driver_system_write = FX_FALSE;
/* Determine if the FAT32 sector was written correctly. */
if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Call the media abort routine. */
_fx_media_abort(media_ptr);
/* Return the sector IO error status. */
return(FX_IO_ERROR);
}
/* Successful update of the FAT32 additional information sector. Update the
last written available cluster count. */
media_ptr -> fx_media_FAT32_additional_info_last_available = media_ptr -> fx_media_available_clusters;
}
}
}
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of driver flush requests. */
media_ptr -> fx_media_driver_flush_requests++;
#endif
/* Build the "flush" I/O driver request. */
media_ptr -> fx_media_driver_request = FX_DRIVER_FLUSH;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_FLUSH, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Call the specified I/O driver with the flush request. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Build the "uninitialize" I/O driver request. */
media_ptr -> fx_media_driver_request = FX_DRIVER_UNINIT;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_UNINIT, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Call the specified I/O driver with the uninitialize request. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Now remove this media from the open list. */
/* Lockout interrupts for media removal. */
FX_DISABLE_INTS
/* See if the media is the only one on the media opened list. */
if (_fx_system_media_opened_count == ((ULONG) 1))
{
/* Only opened media, just set the opened list to NULL. */
_fx_system_media_opened_ptr = FX_NULL;
}
else
{
/* Otherwise, not the only opened media, link-up the neighbors. */
(media_ptr -> fx_media_opened_next) -> fx_media_opened_previous =
media_ptr -> fx_media_opened_previous;
(media_ptr -> fx_media_opened_previous) -> fx_media_opened_next =
media_ptr -> fx_media_opened_next;
/* See if we have to update the opened list head pointer. */
if (_fx_system_media_opened_ptr == media_ptr)
{
/* Yes, move the head pointer to the next opened media. */
_fx_system_media_opened_ptr = media_ptr -> fx_media_opened_next;
}
}
/* Decrement the opened media counter. */
_fx_system_media_opened_count--;
/* Finally, Indicate that this media is closed. */
media_ptr -> fx_media_id = FX_MEDIA_CLOSED_ID;
/* Restore interrupt posture. */
FX_RESTORE_INTS
/* Delete the media protection structure if FX_SINGLE_THREAD is not
defined. */
#ifndef FX_SINGLE_THREAD
#ifndef FX_DONT_CREATE_MUTEX
/* Note that the protection is never released. The mutex delete
service will handle all threads waiting access to this media
control block. */
tx_mutex_delete(& (media_ptr -> fx_media_protect));
#endif
#endif
/* Invoke media close callback. */
if (media_ptr -> fx_media_close_notify)
{
media_ptr -> fx_media_close_notify(media_ptr);
}
#ifdef FX_DONT_CREATE_MUTEX
/* Release media protection. */
FX_UNPROTECT
#endif
/* Return success status to the caller. */
return(FX_SUCCESS);
}
+82
View File
@@ -0,0 +1,82 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_media.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_close_notif_set PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the notify function called when media is open. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* media_close_notify Notify function called when */
/* media is closed */
/* */
/* OUTPUT */
/* */
/* FX_SUCCESS */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_media_close_notify_set(FX_MEDIA *media_ptr, VOID (*media_close_notify)(FX_MEDIA *media))
{
/* Set the notify function. */
media_ptr -> fx_media_close_notify = media_close_notify;
/* Return successful status. */
return(FX_SUCCESS);
}
@@ -0,0 +1,115 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_media.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_extended_space_available PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function returns the number of bytes available in the */
/* specified media. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* available_bytes_ptr Pointer to available bytes */
/* destination */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_media_extended_space_available(FX_MEDIA *media_ptr, ULONG64 *available_bytes_ptr)
{
ULONG64 available_bytes;
ULONG bytes_per_cluster;
ULONG available_clusters;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_SPACE_AVAILABLE, media_ptr, available_bytes_ptr, media_ptr -> fx_media_available_clusters, 0, FX_TRACE_MEDIA_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Pickup the number of free clusters. */
available_clusters = media_ptr -> fx_media_available_clusters;
/* Derive the bytes per cluster. */
bytes_per_cluster = media_ptr -> fx_media_bytes_per_sector * media_ptr -> fx_media_sectors_per_cluster;
/* Calculate the free space. */
available_bytes = ((ULONG64)available_clusters) * ((ULONG64)bytes_per_cluster);
/* Return the value. */
*available_bytes_ptr = available_bytes;
/* Release media protection. */
FX_UNPROTECT
/* Return a successful status to the caller. */
return(FX_SUCCESS);
}
+352
View File
@@ -0,0 +1,352 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_media.h"
#include "fx_file.h"
#include "fx_directory.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_flush PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function examines the list of open files for this media and */
/* "flushes" each written open file to the underlying media. After */
/* the open files have been flushed, the internal logical sector is */
/* flushed. Finally, the attached driver is sent a flush command so */
/* that it can flush its sector cache (if any) to the media. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_write Write the directory entry */
/* _fx_utility_FAT_flush Flush cached FAT entries */
/* _fx_utility_FAT_map_flush Flush primary FAT changes to */
/* secondary FAT(s) */
/* _fx_utility_logical_sector_flush Flush logical sector cache */
/* _fx_utility_32_unsigned_read Read 32-bit unsigned */
/* _fx_utility_32_unsigned_write Write 32-bit unsigned */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), and */
/* added conditional to */
/* disable cache, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_media_flush(FX_MEDIA *media_ptr)
{
UINT status;
ULONG open_count;
FX_FILE *file_ptr;
FX_INT_SAVE_AREA
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_flushes++;
#endif
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_FLUSH, media_ptr, 0, 0, 0, FX_TRACE_MEDIA_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Check for write protect at the media level (set by driver). */
if (media_ptr -> fx_media_driver_write_protect)
{
/* Release media protection. */
FX_UNPROTECT
/* Return write protect error. */
return(FX_WRITE_PROTECT);
}
/* Loop through the media's open files. */
open_count = media_ptr -> fx_media_opened_file_count;
file_ptr = media_ptr -> fx_media_opened_file_list;
while (open_count)
{
/* Look at each opened file to see if the same file is opened
for writing and has been written to. */
if ((file_ptr -> fx_file_open_mode == FX_OPEN_FOR_WRITE) &&
(file_ptr -> fx_file_modified))
{
/* Protect against update. */
FX_DISABLE_INTS
/* Set the new time and date. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_time = _fx_system_time;
file_ptr -> fx_file_dir_entry.fx_dir_entry_date = _fx_system_date;
/* Restore interrupts. */
FX_RESTORE_INTS
/* Copy the new file size into the directory entry. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =
file_ptr -> fx_file_current_file_size;
/* Write the directory entry to the media. */
status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
/* Check for a good status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Error writing the directory. */
return(status);
}
/* Clear the file modified flag. */
file_ptr -> fx_file_modified = FX_FALSE;
}
/* Adjust the pointer and decrement the opened count. */
file_ptr = file_ptr -> fx_file_opened_next;
open_count--;
}
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
/* Flush changed sector(s) in the primary FAT to secondary FATs. */
_fx_utility_FAT_map_flush(media_ptr);
/* Flush the internal logical sector cache. */
status = _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64) (media_ptr -> fx_media_total_sectors), FX_FALSE);
/* Check for a good status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Error writing the directory. */
return(status);
}
/* Determine if the media needs to have the additional information sector updated. This will
only be the case for 32-bit FATs. The logic here only needs to be done if the last reported
available cluster count is different that the currently available clusters. */
if ((media_ptr -> fx_media_FAT32_additional_info_sector) &&
(media_ptr -> fx_media_FAT32_additional_info_last_available != media_ptr -> fx_media_available_clusters))
{
UCHAR *buffer_ptr;
ULONG signature;
#ifndef FX_DISABLE_CACHE
/* Setup a pointer to the first cached entry's buffer. */
buffer_ptr = (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_memory_buffer;
/* Invalidate this cache entry. */
(media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector = (~(ULONG64)0);
(media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_valid = FX_FALSE;
#else
buffer_ptr = media_ptr -> fx_media_memory_buffer;
#endif /* FX_DISABLE_CACHE */
/* Read the FAT32 additional information sector from the device. */
media_ptr -> fx_media_driver_request = FX_DRIVER_READ;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
media_ptr -> fx_media_driver_buffer = buffer_ptr;
media_ptr -> fx_media_driver_logical_sector = media_ptr -> fx_media_FAT32_additional_info_sector;
media_ptr -> fx_media_driver_sectors = 1;
media_ptr -> fx_media_driver_sector_type = FX_DIRECTORY_SECTOR;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of driver read sector(s) requests. */
media_ptr -> fx_media_driver_read_requests++;
#endif
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_READ, media_ptr, media_ptr -> fx_media_FAT32_additional_info_sector, 1, buffer_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Invoke the driver to read the FAT32 additional information sector. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Determine if the FAT32 sector was read correctly. */
if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(FX_IO_ERROR);
}
/* Setup a pointer into the FAT32 additional information sector. */
buffer_ptr = media_ptr -> fx_media_driver_buffer;
/* Pickup the first signature long word. */
signature = _fx_utility_32_unsigned_read(&buffer_ptr[0]);
/* Determine if the signature is correct. */
if (signature == 0x41615252)
{
/* Yes, the first signature is correct, now pickup the next signature. */
signature = _fx_utility_32_unsigned_read(&buffer_ptr[484]);
/* Determine if this signature is correct. */
if (signature == 0x61417272)
{
/* Yes, we have a good FAT32 additional information sector. */
/* Set the free cluster count to the available clusters in the media control block. */
_fx_utility_32_unsigned_write(&buffer_ptr[488], media_ptr -> fx_media_available_clusters);
/* Set the next free cluster number hint to starting search cluster in the media control block. */
_fx_utility_32_unsigned_write(&buffer_ptr[492], media_ptr -> fx_media_cluster_search_start);
/* Now write the sector back out to the media. */
media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
media_ptr -> fx_media_driver_buffer = buffer_ptr;
media_ptr -> fx_media_driver_logical_sector = media_ptr -> fx_media_FAT32_additional_info_sector;
media_ptr -> fx_media_driver_sectors = 1;
media_ptr -> fx_media_driver_sector_type = FX_DIRECTORY_SECTOR;
/* Set the system write flag since we are writing a directory sector. */
media_ptr -> fx_media_driver_system_write = FX_TRUE;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of driver write sector(s) requests. */
media_ptr -> fx_media_driver_write_requests++;
#endif
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, media_ptr -> fx_media_FAT32_additional_info_sector, 1, buffer_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Invoke the driver to write the FAT32 additional information sector. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Clear the system write flag. */
media_ptr -> fx_media_driver_system_write = FX_FALSE;
/* Determine if the FAT32 sector was written correctly. */
if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the sector IO error status. */
return(FX_IO_ERROR);
}
/* Successful update of the FAT32 additional information sector. Update the
last written available cluster count. */
media_ptr -> fx_media_FAT32_additional_info_last_available = media_ptr -> fx_media_available_clusters;
}
}
}
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of driver flush requests. */
media_ptr -> fx_media_driver_flush_requests++;
#endif
/* Build the "flush" I/O driver request. */
media_ptr -> fx_media_driver_request = FX_DRIVER_FLUSH;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_FLUSH, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Call the specified I/O driver with the flush request. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Determine if the I/O driver flushed successfully. */
if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the driver error status. */
return(FX_IO_ERROR);
}
/* Release media protection. */
FX_UNPROTECT
/* If we get here, return successful status to the caller. */
return(FX_SUCCESS);
}
+695
View File
@@ -0,0 +1,695 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_media.h"
#include "fx_utility.h"
/* Define global variables necessary for formatting. */
/* Define OEM Name. This name must be 8 characters long and be blank padded.
The default may be changed by modifying this file or calling the
fx_media_format_oem_name_set utility prior to calling fx_media_format. */
UCHAR _fx_media_format_oem_name[8] = "EL FILEX";
/* Define the default media type. This default may be changed by modifying
this file or calling the fx_media_format_type_set utility prior to calling
fx_media_format. */
UCHAR _fx_media_format_media_type = 0xF8;
/* Define the default volume ID. This default may be changed by modifying
this file or calling the fx_media_format_volume_id_set utility prior to calling
fx_media_format. */
ULONG _fx_media_format_volume_id = 1;
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_format PORTABLE C */
/* 6.1.11 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function creates a FAT12/16/32 format with raw calls to the */
/* I/O driver. It can and must be called before the fx_media_open */
/* and is designed to utilize the same underlying FileX driver. */
/* */
/* INPUT */
/* */
/* media_ptr Pointer to media control block*/
/* (does not need to be opened)*/
/* driver Pointer to FileX driver (must */
/* be able to field requests */
/* prior to opening) */
/* driver_info_ptr Optional information pointer */
/* memory_ptr Pointer to memory used by the */
/* FileX for this media. */
/* memory_size Size of media memory - must */
/* at least 512 bytes and */
/* one sector size. */
/* volume_name Name of the volume */
/* number_of_fats Number of FAT tables */
/* directory_entries Number of directory entries */
/* hidden_sectors Number of hidden sectors */
/* total_sectors Total number of sectors */
/* bytes_per_sector Number of bytes per sector */
/* sectors_per_cluster Number of sectors per cluster */
/* heads Number of heads */
/* sectors_per_track Number of sectors per track */
/* */
/* OUTPUT */
/* */
/* Completion Status */
/* */
/* CALLS */
/* */
/* Media driver */
/* _fx_utility_16_unsigned_write Write 16-bit unsigned */
/* _fx_utility_32_unsigned_write Write 32-bit unsigned */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), and */
/* added conditional to */
/* disable force memset, */
/* resulting in version 6.1 */
/* 03-02-2021 William E. Lamie Modified comment(s), */
/* resulting in version 6.1.5 */
/* 08-02-2021 Bhupendra Naphade Modified comment(s), and */
/* updated boot write logic, */
/* resulting in version 6.1.8 */
/* 04-25-2022 Bhupendra Naphade Modified comment(s), and */
/* updated reserved FAT entry */
/* value, */
/* resulting in version 6.1.11 */
/* */
/**************************************************************************/
UINT _fx_media_format(FX_MEDIA *media_ptr, VOID (*driver)(FX_MEDIA *media), VOID *driver_info_ptr, UCHAR *memory_ptr, UINT memory_size,
CHAR *volume_name, UINT number_of_fats, UINT directory_entries, UINT hidden_sectors,
ULONG total_sectors, UINT bytes_per_sector, UINT sectors_per_cluster,
UINT heads, UINT sectors_per_track)
{
UCHAR *byte_ptr;
UINT reserved_sectors, i, j, root_sectors, total_clusters, bytes_needed;
UINT sectors_per_fat, f, s;
/* Create & write bootrecord from drive geometry information. */
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_FORMAT, media_ptr, directory_entries, total_sectors, sectors_per_cluster, FX_TRACE_MEDIA_EVENTS, 0, 0)
/* Validate bytes per sector value: greater than zero and no more than 4096. */
if((bytes_per_sector == 0) || (bytes_per_sector > 4096))
return(FX_SECTOR_INVALID);
/* Validate sectors per cluster value: greater than zero and no more than 128. */
if((sectors_per_cluster == 0) || (sectors_per_cluster > 128))
return(FX_SECTOR_INVALID);
/* Setup driver pointer and memory information. */
media_ptr -> fx_media_driver_entry = driver;
media_ptr -> fx_media_memory_buffer = (UCHAR *)memory_ptr;
media_ptr -> fx_media_memory_size = memory_size;
/* Store geometry information in media record - driver needs this. */
media_ptr -> fx_media_bytes_per_sector = bytes_per_sector;
media_ptr -> fx_media_sectors_per_track = sectors_per_track;
media_ptr -> fx_media_heads = heads;
media_ptr -> fx_media_hidden_sectors = hidden_sectors;
/* Initialize the supplied media I/O driver. First, build the
initialize driver request. */
media_ptr -> fx_media_driver_request = FX_DRIVER_INIT;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
media_ptr -> fx_media_driver_info = driver_info_ptr;
media_ptr -> fx_media_driver_write_protect = FX_FALSE;
media_ptr -> fx_media_driver_free_sector_update = FX_FALSE;
media_ptr -> fx_media_driver_data_sector_read = FX_FALSE;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_INIT, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Call the specified I/O driver with the initialize request. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Determine if the I/O driver initialized successfully. */
if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
{
/* Return the driver error status. */
return(FX_IO_ERROR);
}
/* Setup driver buffer memory. */
media_ptr -> fx_media_driver_buffer = memory_ptr;
/* Move the buffer pointer into a local copy. */
byte_ptr = media_ptr -> fx_media_driver_buffer;
#ifndef FX_DISABLE_FORCE_MEMORY_OPERATION
/* Clear the buffer record out, assuming it is large enough for one sector. */
for (i = 0; i < bytes_per_sector; i++)
{
/* Clear each byte of the boot record. */
byte_ptr[i] = (UCHAR)0;
}
#else
_fx_utility_memory_set(byte_ptr, 0, bytes_per_sector);
#endif /* FX_DISABLE_FORCE_MEMORY_OPERATION */
/* Set jump instruction at the beginning of the sector. */
byte_ptr[0] = (UCHAR)0xEB;
byte_ptr[1] = (UCHAR)0x34;
byte_ptr[2] = (UCHAR)0x90;
/* Set the OEM name in the boot record. */
for (i = 0; i < 8; i++)
{
/* Copy a character from the OEM name. */
byte_ptr[i + 3] = _fx_media_format_oem_name[i];
}
/* Set the media type in the boot record. */
byte_ptr[FX_MEDIA_TYPE] = _fx_media_format_media_type;
/* Set the number of bytes per sector. */
_fx_utility_16_unsigned_write(&byte_ptr[FX_BYTES_SECTOR], bytes_per_sector);
/* Set the number of sectors per track. */
_fx_utility_16_unsigned_write(&byte_ptr[FX_SECTORS_PER_TRK], sectors_per_track);
/* Set the number of heads. */
_fx_utility_16_unsigned_write(&byte_ptr[FX_HEADS], heads);
#ifdef FX_FORCE_512_BYTE_BOOT_SECTOR
/* Calculate the number of reserved sectors. If sector size is smaller than 512 bytes, there will be
reserved sectors, otherwise assumed that only the sector containing bootrecord is reserved. */
if (bytes_per_sector < 512)
{
reserved_sectors = 512 / bytes_per_sector;
}
else
{
reserved_sectors = 1;
}
#else
/* The boot sector is the only reserved sector. */
reserved_sectors = 1;
#endif
/* Calculate the maximum clusters.... This is actually greater than the actual since the FAT
sectors have yet to be accounted for. */
total_clusters = (total_sectors - reserved_sectors - ((directory_entries * FX_DIR_ENTRY_SIZE) + (bytes_per_sector - 1)) / bytes_per_sector) / sectors_per_cluster;
/* Calculate the maximum number of FAT sectors necessary for FAT12. */
if (total_clusters % 2)
{
bytes_needed = (total_clusters + total_clusters / 2) + 1;
}
else
{
bytes_needed = (total_clusters + total_clusters / 2);
}
sectors_per_fat = bytes_needed / bytes_per_sector;
if (bytes_needed % bytes_per_sector)
{
sectors_per_fat++;
}
/* Now adjust the total clusters by the number of sectors per FAT. */
total_clusters = total_clusters - ((sectors_per_fat * number_of_fats) + (sectors_per_cluster - 1)) / sectors_per_cluster;
/* Is the total cluster count greater than the FAT12 maximum? */
if (total_clusters >= FX_12_BIT_FAT_SIZE)
{
/* Yes, too big for FAT12, we need to evaluate for FAT16. */
/* Reset the maximum clusters.... This is actually greater than the actual since the FAT
sectors have yet to be accounted for. */
total_clusters = (total_sectors - reserved_sectors - ((directory_entries * FX_DIR_ENTRY_SIZE) + (bytes_per_sector - 1)) / bytes_per_sector) / sectors_per_cluster;
/* Calculate 16-bit FAT is present. Each cluster requires a 2 byte entry in the FAT table. */
sectors_per_fat = (total_clusters * 2) / bytes_per_sector;
if ((total_clusters * 2) % bytes_per_sector)
{
sectors_per_fat++;
}
/* Now adjust the total clusters by the number of sectors per FAT. */
total_clusters = total_clusters - ((sectors_per_fat * number_of_fats) + (sectors_per_cluster - 1)) / sectors_per_cluster;
/* Is the total cluster count greater than the FAT16 maximum? */
if (total_clusters >= FX_16_BIT_FAT_SIZE)
{
/* Yes, FAT32 is present. */
/* Allocate room for the FAT32 additional information sector. This contains useful information
such as the number of available clusters between successive mounting of the media. */
if (bytes_per_sector == 512)
{
/* Write sector number 1 to the additional information sector. */
_fx_utility_16_unsigned_write(&byte_ptr[48], 1);
/* Increment the reserved sectors count, since this will count as a reserved sector. */
reserved_sectors++;
}
else
{
/* Write value to indicate there is no additional information sector. */
_fx_utility_16_unsigned_write(&byte_ptr[48], 0xFFFF);
}
/* Allocate the first cluster to the root directory. */
_fx_utility_32_unsigned_write(&byte_ptr[FX_ROOT_CLUSTER_32], FX_FAT_ENTRY_START);
/* Determine if the number of root directory entries should be modified. */
directory_entries = (sectors_per_cluster * bytes_per_sector) / FX_DIR_ENTRY_SIZE;
/* Reset the total_clusters for the FAT32 calculation. */
total_clusters = (total_sectors - reserved_sectors) / sectors_per_cluster;
/* 32-bit FAT is present. Each cluster requires a 4 byte entry in the FAT table. */
sectors_per_fat = (total_clusters * 4) / bytes_per_sector;
if ((total_clusters * 4) % bytes_per_sector)
{
sectors_per_fat++;
}
/* Now adjust the total clusters by the number of sectors per FAT. */
total_clusters = total_clusters - ((sectors_per_fat * number_of_fats) + (sectors_per_cluster - 1)) / sectors_per_cluster;
}
}
/* Set sectors per FAT type. */
if (total_clusters < FX_16_BIT_FAT_SIZE)
{
/* Set the number of sectors per FAT12/16. */
_fx_utility_16_unsigned_write(&byte_ptr[FX_SECTORS_PER_FAT], sectors_per_fat);
/* Set the signature. */
byte_ptr[FX_BOOT_SIG] = 0x29;
/* Setup the volume ID. */
_fx_utility_32_unsigned_write(&byte_ptr[FX_VOLUME_ID], _fx_media_format_volume_id);
}
else
{
/* Set the number of sectors per FAT32. */
_fx_utility_32_unsigned_write(&byte_ptr[FX_SECTORS_PER_FAT_32], sectors_per_fat);
/* Set the signature. */
byte_ptr[FX_BOOT_SIG_32] = 0x29;
/* Setup the volume ID. */
_fx_utility_32_unsigned_write(&byte_ptr[FX_VOLUME_ID_32], _fx_media_format_volume_id);
}
/* Set the total number of sectors. */
if (total_sectors < (ULONG)0xFFFF)
{
/* Write the 16-bit total sector field. */
_fx_utility_16_unsigned_write(&byte_ptr[FX_SECTORS], (UINT)(total_sectors));
/* Set the number of huge sectors. */
_fx_utility_32_unsigned_write(&byte_ptr[FX_HUGE_SECTORS], 0);
}
else
{
/* Write the 16-bit total sector field as 0. */
_fx_utility_16_unsigned_write(&byte_ptr[FX_SECTORS], (UINT)0);
/* Set the number of huge sectors. */
_fx_utility_32_unsigned_write(&byte_ptr[FX_HUGE_SECTORS], total_sectors);
}
/* Set the number of reserved sectors. */
_fx_utility_16_unsigned_write(&byte_ptr[FX_RESERVED_SECTORS], reserved_sectors);
/* Set the number of sectors per cluster */
byte_ptr[FX_SECTORS_CLUSTER] = (UCHAR)sectors_per_cluster;
/* Set the number of FATs. */
byte_ptr[FX_NUMBER_OF_FATS] = (UCHAR)number_of_fats;
/* Set the number of hidden sectors. */
_fx_utility_32_unsigned_write(&byte_ptr[FX_HIDDEN_SECTORS], hidden_sectors);
/* Determine if a FAT12 or FAT16 is present. If FAT32 is present, these fields are left alone! */
if (total_clusters < FX_16_BIT_FAT_SIZE)
{
/* Yes, set the number of root directory entries. */
_fx_utility_16_unsigned_write(&byte_ptr[FX_ROOT_DIR_ENTRIES], directory_entries);
}
/* Now setup the volume label. */
if (total_clusters < FX_16_BIT_FAT_SIZE)
{
/* FAT12/16 volume label offset. */
j = FX_VOLUME_LABEL;
}
else
{
/* FAT32 volume label offset. */
j = FX_VOLUME_LABEL_32;
}
i = 0;
while (i < 11)
{
/* Determine if it is NULL. */
if (volume_name[i] == 0)
{
/* Yes, the copying is finished. */
break;
}
/* Otherwise, copy byte of volume name into boot record. */
byte_ptr[j + i] = (UCHAR)volume_name[i];
/* Increment byte position. */
i++;
}
/* Now blank-pad the remainder of the volume name. */
#ifndef FX_DISABLE_FORCE_MEMORY_OPERATION
while (i < 11)
{
byte_ptr[j + i] = (UCHAR)' ';
i++;
}
#else
_fx_utility_memory_set(&byte_ptr[j + i], ' ', (11 - i));
#endif /* FX_DISABLE_FORCE_MEMORY_OPERATION */
#ifdef FX_FORCE_512_BYTE_BOOT_SECTOR
/* Set bootrecord signature. */
byte_ptr[510] = 0x55;
byte_ptr[511] = 0xAA;
#else
/* Set bootrecord signature. */
byte_ptr[bytes_per_sector - 2] = 0x55;
byte_ptr[bytes_per_sector - 1] = 0xAA;
#endif
/* Select the boot record write command. */
media_ptr -> fx_media_driver_request = FX_DRIVER_BOOT_WRITE;
media_ptr -> fx_media_driver_system_write = FX_TRUE;
media_ptr -> fx_media_driver_sectors = 1;
media_ptr -> fx_media_driver_sector_type = FX_BOOT_SECTOR;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_BOOT_WRITE, media_ptr, memory_ptr, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Write out the bootrecord */
(driver)(media_ptr);
/* Clear the write flag. */
media_ptr -> fx_media_driver_system_write = FX_FALSE;
/* Determine if it was successful. */
if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
{
return(FX_IO_ERROR);
}
/* Calculate the number of root sectors. */
root_sectors = ((directory_entries * FX_DIR_ENTRY_SIZE) + bytes_per_sector - 1) / bytes_per_sector;
/* Determine if FAT32 is present AND if the bytes per sector is large enough to have
a FSINFO sector. */
if ((total_clusters >= FX_16_BIT_FAT_SIZE) && (bytes_per_sector == 512))
{
#ifndef FX_DISABLE_FORCE_MEMORY_OPERATION
/* Clear sector buffer. */
for (i = 0; i < bytes_per_sector; i++)
{
byte_ptr[i] = (CHAR)0;
}
#else
_fx_utility_memory_set(byte_ptr, 0, bytes_per_sector);
#endif /* FX_DISABLE_FORCE_MEMORY_OPERATION */
/* Build the FSINFO fields. */
/* Build first signature word, used to help verify this is a FSINFO sector. */
byte_ptr[0] = 0x52;
byte_ptr[1] = 0x52;
byte_ptr[2] = 0x61;
byte_ptr[3] = 0x41;
/* Build the next signature word, this too is used to help verify that this is a FSINFO sector. */
byte_ptr[484] = 0x72;
byte_ptr[485] = 0x72;
byte_ptr[486] = 0x41;
byte_ptr[487] = 0x61;
/* Build the final signature word, this too is used to help verify that this is a FSINFO sector. */
byte_ptr[508] = 0x55;
byte_ptr[509] = 0xAA;
/* Setup the total available clusters on the media. We need to subtract 1 for the FAT32 root directory. */
_fx_utility_32_unsigned_write(&byte_ptr[488], (total_clusters - 1));
/* Setup the starting free cluster to 3, since cluster 2 is reserved for the FAT32 root directory. */
_fx_utility_32_unsigned_write(&byte_ptr[492], 3);
/* Now write the FSINFO sector to the media. */
media_ptr -> fx_media_driver_logical_sector = 1;
media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE;
media_ptr -> fx_media_driver_sectors = 1;
media_ptr -> fx_media_driver_system_write = FX_TRUE;
media_ptr -> fx_media_driver_sector_type = FX_BOOT_SECTOR;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, 1, 1, memory_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Write out the sector. */
(driver)(media_ptr);
/* Clear the system write flag. */
media_ptr -> fx_media_driver_system_write = FX_FALSE;
/* Determine if it was successful. */
if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
{
return(FX_IO_ERROR);
}
}
/* At this point we need set up first to FAT entries and clear the remaining FAT sectors area. */
/* Loop through number of FATs. The first is the only one used. */
for (f = 0; f < number_of_fats; f++)
{
/* Loop through all the sectors in this FAT. */
for (s = 0; s < sectors_per_fat; s++)
{
if (s == 0)
{
/* Reserve the first two FAT table entries. */
if (total_clusters < FX_12_BIT_FAT_SIZE)
{
/* Reserve the first two FAT-12 entries. */
byte_ptr[0] = _fx_media_format_media_type;
byte_ptr[1] = (UCHAR)0xFF;
byte_ptr[2] = (UCHAR)0xFF;
/* Start clearing at FAT entry 3. */
i = 3;
}
else if (total_clusters < FX_16_BIT_FAT_SIZE)
{
/* Reserve the first two FAT-16 entries. */
byte_ptr[0] = _fx_media_format_media_type;
byte_ptr[1] = (UCHAR)0xFF;
byte_ptr[2] = (UCHAR)0xFF;
byte_ptr[3] = (UCHAR)0xFF;
/* Start clearing at FAT entry 3. */
i = 4;
}
else
{
/* Reserve the first two FAT-32 entries. */
byte_ptr[0] = _fx_media_format_media_type;
byte_ptr[1] = (UCHAR)0xFF;
byte_ptr[2] = (UCHAR)0xFF;
byte_ptr[3] = (UCHAR)0x0F;
byte_ptr[4] = (UCHAR)0xFF;
byte_ptr[5] = (UCHAR)0xFF;
byte_ptr[6] = (UCHAR)0xFF;
byte_ptr[7] = (UCHAR)0x0F;
/* Preallocate the first cluster for the root directory. */
byte_ptr[8] = (UCHAR)0xFF;
byte_ptr[9] = (UCHAR)0xFF;
byte_ptr[10] = (UCHAR)0xFF;
byte_ptr[11] = (UCHAR)0x0F;
/* Start clearing at FAT entry 3. */
i = 12;
}
}
else
{
i = 0;
}
#ifndef FX_DISABLE_FORCE_MEMORY_OPERATION
/* Clear remainder of sector buffer. */
for (; i < bytes_per_sector; i++)
{
byte_ptr[i] = (CHAR)0;
}
#else
_fx_utility_memory_set(&byte_ptr[i], 0, (bytes_per_sector - i));
#endif /* FX_DISABLE_FORCE_MEMORY_OPERATION */
/* Build sector write command. */
media_ptr -> fx_media_driver_logical_sector = reserved_sectors + (f * sectors_per_fat) + s;
media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE;
media_ptr -> fx_media_driver_sectors = 1;
media_ptr -> fx_media_driver_system_write = FX_TRUE;
media_ptr -> fx_media_driver_sector_type = FX_FAT_SECTOR;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, media_ptr -> fx_media_driver_logical_sector, 1, memory_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Write out the sector. */
(driver)(media_ptr);
/* Clear the system write flag. */
media_ptr -> fx_media_driver_system_write = FX_FALSE;
/* Determine if it was successful. */
if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
{
return(FX_IO_ERROR);
}
}
}
#ifndef FX_DISABLE_FORCE_MEMORY_OPERATION
/* Clear sector buffer. */
for (i = 0; i < bytes_per_sector; i++)
{
byte_ptr[i] = (CHAR)0;
}
#else
_fx_utility_memory_set(byte_ptr, 0, bytes_per_sector);
#endif /* FX_DISABLE_FORCE_MEMORY_OPERATION */
/* Now clear the root directory sectors. */
for (s = 0; s < root_sectors; s++)
{
/* Build sector write command. */
media_ptr -> fx_media_driver_logical_sector = reserved_sectors + (number_of_fats * sectors_per_fat) + s;
media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE;
media_ptr -> fx_media_driver_sectors = 1;
media_ptr -> fx_media_driver_system_write = FX_TRUE;
media_ptr -> fx_media_driver_sector_type = FX_DIRECTORY_SECTOR;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, media_ptr -> fx_media_driver_logical_sector, 1, memory_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Write out the sector. */
(driver)(media_ptr);
/* Clear the write flag. */
media_ptr -> fx_media_driver_system_write = FX_FALSE;
/* Determine if it was successful. */
if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
{
return(FX_IO_ERROR);
}
}
/* Build the "uninitialize" I/O driver request. */
media_ptr -> fx_media_driver_request = FX_DRIVER_UNINIT;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_UNINIT, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Call the specified I/O driver with the uninitialize request. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Return success! */
return(media_ptr -> fx_media_driver_status);
}
+97
View File
@@ -0,0 +1,97 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_media.h"
/* Define external reference to OEM name string. */
extern UCHAR _fx_media_format_oem_name[8];
UINT fx_media_format_oem_name_set(UCHAR new_oem_name[8]);
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_format_oem_name_set PORTABLE C */
/* 6.1.5 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function modifies the default OEM name for all formatting. The */
/* new OEM name must be 8 characters long - blank padded if necessary. */
/* */
/* */
/* INPUT */
/* */
/* new_oem_name Pointer to new OEM name */
/* */
/* OUTPUT */
/* */
/* Completion Status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 03-02-2021 William E. Lamie Modified comment(s), */
/* resulting in version 6.1.5 */
/* */
/**************************************************************************/
UINT fx_media_format_oem_name_set(UCHAR new_oem_name[8])
{
UINT i;
/* Simply copy the new OEM name into the default location. */
for (i = 0; i < 8; i++)
{
/* Copy one character of the new OEM name. */
_fx_media_format_oem_name[i] = new_oem_name[i];
}
/* Return success. */
return(FX_SUCCESS);
}
+88
View File
@@ -0,0 +1,88 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_media.h"
/* Define external reference to media type. */
extern UCHAR _fx_media_format_media_type;
UINT fx_media_format_type_set(UCHAR new_media_type);
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_format_type_set PORTABLE C */
/* 6.1.5 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function modifies the default media type for all formatting. */
/* */
/* */
/* INPUT */
/* */
/* new_media_type New media type value */
/* */
/* OUTPUT */
/* */
/* Completion Status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 03-02-2021 William E. Lamie Modified comment(s), */
/* resulting in version 6.1.5 */
/* */
/**************************************************************************/
UINT fx_media_format_type_set(UCHAR new_media_type)
{
/* Simply copy the new media type into the default location. */
_fx_media_format_media_type = new_media_type;
/* Return success. */
return(FX_SUCCESS);
}
@@ -0,0 +1,88 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_media.h"
/* Define external reference to media volume ID. */
extern ULONG _fx_media_format_volume_id;
UINT fx_media_format_volume_id_set(ULONG new_volume_id);
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_format_media_volume_id_set PORTABLE C */
/* 6.1.5 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function modifies the default media volume ID for all */
/* formatting. */
/* */
/* */
/* INPUT */
/* */
/* new_volume_id New media volume Id value */
/* */
/* OUTPUT */
/* */
/* Completion Status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 03-02-2021 William E. Lamie Modified comment(s), */
/* resulting in version 6.1.5 */
/* */
/**************************************************************************/
UINT fx_media_format_volume_id_set(ULONG new_volume_id)
{
/* Simply copy the new media volume ID into the default location. */
_fx_media_format_volume_id = new_volume_id;
/* Return success. */
return(FX_SUCCESS);
}
File diff suppressed because it is too large Load Diff
+82
View File
@@ -0,0 +1,82 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_media.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_open_notify_set PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the notify function called when media is open. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* media_open_notify Notify function called when */
/* media is open */
/* */
/* OUTPUT */
/* */
/* FX_SUCCESS */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_media_open_notify_set(FX_MEDIA *media_ptr, VOID (*media_open_notify)(FX_MEDIA *media))
{
/* Set the notify function. */
media_ptr -> fx_media_open_notify = media_open_notify;
/* Return successful status. */
return(FX_SUCCESS);
}
+127
View File
@@ -0,0 +1,127 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_media.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_read PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function reads the specified raw logical sector from the */
/* specified media. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* logical_sector Logical sector to read */
/* buffer_ptr Pointer to caller's buffer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_logical_sector_read Logical sector read utility */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_media_read(FX_MEDIA *media_ptr, ULONG logical_sector, VOID *buffer_ptr)
{
UINT status;
#ifdef TX_ENABLE_EVENT_TRACE
TX_TRACE_BUFFER_ENTRY *trace_event;
ULONG trace_timestamp;
#endif
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_reads++;
#endif
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_READ, media_ptr, logical_sector, buffer_ptr, 0, FX_TRACE_MEDIA_EVENTS, &trace_event, &trace_timestamp)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Read the logical sector. */
status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector, buffer_ptr, ((ULONG) 1), FX_DATA_SECTOR);
#ifdef TX_ENABLE_EVENT_TRACE
/* Check for successful status. */
if (status == FX_SUCCESS)
{
/* Update the trace event with the bytes read. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_READ, 0, 0, 0, media_ptr -> fx_media_bytes_per_sector)
}
#endif
/* Release media protection. */
FX_UNPROTECT
/* Return status to the caller. */
return(status);
}
+107
View File
@@ -0,0 +1,107 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_media.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_space_available PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function returns the number of bytes available in the */
/* specified media. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* available_bytes_ptr Pointer to available bytes */
/* destination */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* _fx_media_extended_space_available Actual space available service*/
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_media_space_available(FX_MEDIA *media_ptr, ULONG *available_bytes_ptr)
{
UINT status;
ULONG64 available_bytes;
/* Call actual media space available service. */
status = _fx_media_extended_space_available(media_ptr, &available_bytes);
/* Check status. */
if (status == FX_SUCCESS)
{
/* Determine if more than 4GB available. */
if (available_bytes > 0x00000000FFFFFFFF)
{
/* Yes, we must have more than 4GB available... report the maximum we can fit
in 32bits, which is 4GB. */
*available_bytes_ptr = 0xFFFFFFFF;
}
else
{
*available_bytes_ptr = (ULONG)(available_bytes);
}
}
/* Return status to the caller. */
return(status);
}
+89
View File
@@ -0,0 +1,89 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_media.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_volume_get PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function reads the volume name stored in the media's boot */
/* record or root directory. */
/* */
/* Note, this API is deprecated as fx_media_volume_get_extended should */
/* be used. The maximum written size to volume_name could be 12. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* volume_name Pointer to destination for */
/* the volume name (maximum */
/* 11 characters + NULL) */
/* volume_source Source of volume */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_media_volume_get_extended Actual media volume get */
/* service */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_media_volume_get(FX_MEDIA *media_ptr, CHAR *volume_name, UINT volume_source)
{
/* Call the extended version with 12 bytes volume name length. */
return(_fx_media_volume_get_extended(media_ptr, volume_name, 12, volume_source));
}
+323
View File
@@ -0,0 +1,323 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_media.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_volume_get_extended PORTABLE C */
/* 6.1.11 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function reads the volume name stored in the media's boot */
/* record or root directory. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* volume_name Pointer to destination for */
/* the volume name (maximum */
/* 11 characters + NULL) */
/* volume_name_buffer_length Buffer length for volume_name */
/* volume_source Source of volume */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_logical_sector_read Read directory sector */
/* _fx_directory_entry_read Directory entry read */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 04-25-2022 Bhupendra Naphade Modified comment(s), and */
/* updated check for */
/* volume name, */
/* resulting in version 6.1.11 */
/* */
/**************************************************************************/
UINT _fx_media_volume_get_extended(FX_MEDIA *media_ptr, CHAR *volume_name, UINT volume_name_buffer_length, UINT volume_source)
{
UINT status, offset;
ULONG i;
INT j;
FX_DIR_ENTRY dir_entry;
/* Clear the volume name. */
volume_name[0] = FX_NULL;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_VOLUME_GET, media_ptr, volume_name, volume_source, 0, FX_TRACE_MEDIA_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Ensure the volume name is NULL initially. */
volume_name[0] = FX_NULL;
if (volume_source == FX_DIRECTORY_SECTOR)
{
/* Setup pointer to media name buffer. */
dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer;
/* Clear the short name string. */
dir_entry.fx_dir_entry_short_name[0] = 0;
/* Attempt to find the volume name in the root directory. */
i = 0;
do
{
/* Read an entry from the root directory. */
status = _fx_directory_entry_read(media_ptr, FX_NULL, &i, &dir_entry);
/* Check for error status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return to caller. */
return(status);
}
/* Check for a volume name. */
if ((dir_entry.fx_dir_entry_attributes & FX_VOLUME) && ((UCHAR)dir_entry.fx_dir_entry_name[0] != (UCHAR)FX_DIR_ENTRY_FREE))
{
/* Yes, we have found a previously set volume name. */
break;
}
/* Move to next directory entry. */
i++;
} while (i < media_ptr -> fx_media_root_directory_entries);
/* Determine if a volume entry has been found. */
if (i < media_ptr -> fx_media_root_directory_entries)
{
/* Read the logical directory sector. */
status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) dir_entry.fx_dir_entry_log_sector,
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
/* Determine if an error occurred. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return error code. */
return(status);
}
/* Offset to volume label entry. */
offset = dir_entry.fx_dir_entry_byte_offset;
/* Skip trailing space characters of volume name. */
for (j = 10; j >= 0; j--)
{
/* Check for space character. */
if (media_ptr -> fx_media_memory_buffer[offset + (UINT)j] != (UCHAR)' ')
{
/* Last character found. */
break;
}
}
/* Check if the buffer is too short for the name. */
if (j >= (INT)volume_name_buffer_length - 1)
{
/* Buffer too short, return error. */
status = FX_BUFFER_ERROR;
/* Set character count to fit for the buffer. */
j = (INT)volume_name_buffer_length - 2;
}
/* NULL terminate the volume name. */
volume_name[j + 1] = FX_NULL;
/* Pickup the remaining characters of the volume name from the boot sector. */
for (; j >= 0; j--)
{
/* Pickup byte of volume name. */
volume_name[j] = (CHAR)media_ptr -> fx_media_memory_buffer[offset + (UINT)j];
}
/* Release media protection. */
FX_UNPROTECT
/* Return the completion status. */
return(status);
}
}
/* Read volume name from boot record. */
/* Read the logical directory sector 0 - we just do this to get a memory_buffer pointer */
status = _fx_utility_logical_sector_read(media_ptr, ((ULONG64) 0),
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
/* Check the return status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of driver read boot sector requests. */
media_ptr -> fx_media_driver_boot_read_requests++;
#endif
/* Build the driver request to read the boot record. */
media_ptr -> fx_media_driver_request = FX_DRIVER_BOOT_READ;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
media_ptr -> fx_media_driver_buffer = media_ptr -> fx_media_memory_buffer;
media_ptr -> fx_media_driver_sectors = 1;
media_ptr -> fx_media_driver_sector_type = FX_BOOT_SECTOR;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_BOOT_READ, media_ptr, media_ptr -> fx_media_memory_buffer, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Invoke the driver to read the boot sector. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Determine if the request is successful. */
if (media_ptr -> fx_media_driver_status)
{
/* Release media protection. */
FX_UNPROTECT
/* An error occurred in the driver. */
return(media_ptr -> fx_media_driver_status);
}
/* Calculate the offset to the volume name based on the type of FAT. */
if (media_ptr -> fx_media_32_bit_FAT)
{
/* FAT32 offset to volume name. */
offset = FX_VOLUME_LABEL_32;
}
else
{
/* FAT12/16 offset to volume name. */
offset = FX_VOLUME_LABEL;
}
/* Skip trailing space characters of volume name. */
for (j = 10; j >= 0; j--)
{
/* Check for space character. */
if (media_ptr -> fx_media_memory_buffer[offset + (UINT)j] != (UCHAR)' ')
{
/* Last character found. */
break;
}
}
/* Check if the buffer is too short for the name. */
if (j >= (INT)volume_name_buffer_length - 1)
{
/* Buffer too short, return error. */
status = FX_BUFFER_ERROR;
/* Set character count to fit for the buffer. */
j = (INT)volume_name_buffer_length - 2;
}
/* NULL terminate the volume name. */
volume_name[j + 1] = FX_NULL;
/* Pickup the remaining characters of the volume name from the boot sector. */
for (; j >= 0; j--)
{
/* Pickup byte of volume name. */
volume_name[j] = (CHAR)media_ptr -> fx_media_memory_buffer[offset + (UINT)j];
}
/* Release media protection. */
FX_UNPROTECT
/* Return the completion status. */
return(status);
}
+411
View File
@@ -0,0 +1,411 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_directory.h"
#include "fx_media.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_volume_set PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the volume name to the name supplied by the */
/* caller. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* volume_name New volume name */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_entry_read Read a directory entry */
/* _fx_utility_logical_sector_read Read directory sector */
/* _fx_utility_logical_sector_write Write directory sector */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_media_volume_set(FX_MEDIA *media_ptr, CHAR *volume_name)
{
ULONG i, j;
FX_DIR_ENTRY dir_entry, dir_entry1;
UINT status, offset;
UCHAR *work_ptr;
CHAR alpha;
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
dir_entry.fx_dir_entry_log_sector = 0;
dir_entry.fx_dir_entry_byte_offset = 0;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_VOLUME_SET, media_ptr, volume_name, 0, 0, FX_TRACE_MEDIA_EVENTS, 0, 0)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* First, check for an invalid volume name. */
if (volume_name[0] == 0)
{
/* Yes, volume name is invalid. Return an error. */
return(FX_INVALID_NAME);
}
/* Read the logical directory sector 0 - we just do this to get a memory_buffer pointer */
status = _fx_utility_logical_sector_read(media_ptr, ((ULONG64) 0),
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
/* Check the read status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of driver read boot sector requests. */
media_ptr -> fx_media_driver_boot_read_requests++;
#endif
/* Build a driver request to read the boot record. */
media_ptr -> fx_media_driver_request = FX_DRIVER_BOOT_READ;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
media_ptr -> fx_media_driver_buffer = media_ptr -> fx_media_memory_buffer;
media_ptr -> fx_media_driver_sectors = 1;
media_ptr -> fx_media_driver_sector_type = FX_BOOT_SECTOR;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_BOOT_READ, media_ptr, media_ptr -> fx_media_memory_buffer, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Invoke the driver to read the boot sector. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Determine if the request is successful. */
if (media_ptr -> fx_media_driver_status)
{
/* Release media protection. */
FX_UNPROTECT
/* An error occurred in the driver. */
return(media_ptr -> fx_media_driver_status);
}
/* Calculate the offset based on the FAT present. */
if (media_ptr -> fx_media_32_bit_FAT)
{
/* FAT32 is present. */
offset = FX_VOLUME_LABEL_32;
}
else
{
/* FAT12/16 is present. */
offset = FX_VOLUME_LABEL;
}
/* Loop to store the volume name. */
for (i = 0; volume_name[i]; i++)
{
/* Have we reached the end? */
if (i == 11)
{
break;
}
/* Pickup volume name byte. */
alpha = volume_name[i];
/* Determine if alpha needs to be converted to upper case. */
if ((alpha >= 'a') && (alpha <= 'z'))
{
/* Convert alpha to upper case. */
alpha = (CHAR)((INT)alpha - 0x20);
}
/* Store a byte of the volume name. */
media_ptr -> fx_media_memory_buffer[offset + i] = (UCHAR)alpha;
}
/* Now pad with spaces. */
for (; i < 11; i++)
{
/* Append space character to volume name. */
media_ptr -> fx_media_memory_buffer[offset + i] = 0x20;
}
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of driver write boot sector requests. */
media_ptr -> fx_media_driver_boot_write_requests++;
#endif
/* Write the boot sector with the new volume name. */
media_ptr -> fx_media_driver_request = FX_DRIVER_BOOT_WRITE;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
media_ptr -> fx_media_driver_buffer = media_ptr -> fx_media_memory_buffer;
media_ptr -> fx_media_driver_sectors = 1;
media_ptr -> fx_media_driver_sector_type = FX_BOOT_SECTOR;
/* Set the system write flag since we are writing the boot sector. */
media_ptr -> fx_media_driver_system_write = FX_TRUE;
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_BOOT_WRITE, media_ptr, media_ptr -> fx_media_memory_buffer, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Invoke the driver to write the boot sector. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Clear the system write flag. */
media_ptr -> fx_media_driver_system_write = FX_FALSE;
/* Determine if the request is successful. */
if (media_ptr -> fx_media_driver_status)
{
/* Release media protection. */
FX_UNPROTECT
/* An error occurred in the driver. */
return(media_ptr -> fx_media_driver_status);
}
/* Setup pointer to media name buffer. */
dir_entry1.fx_dir_entry_name = media_ptr -> fx_media_name_buffer;
/* Clear the short name string. */
dir_entry1.fx_dir_entry_short_name[0] = 0;
/* Now we need to find the copy of the volume name in the root directory. */
i = 0;
j = media_ptr -> fx_media_root_directory_entries + 1;
do
{
/* Read an entry from the root directory. */
status = _fx_directory_entry_read(media_ptr, FX_NULL, &i, &dir_entry1);
/* Check for error status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return to caller. */
return(status);
}
/* Determine if this is an empty entry. */
if ((dir_entry1.fx_dir_entry_name[0] == (CHAR)FX_DIR_ENTRY_FREE) && (dir_entry1.fx_dir_entry_short_name[0] == 0))
{
/* Yes, this is free entry. Is it the first? */
if (i < j)
{
/* Yes, first free entry - remember it. */
dir_entry = dir_entry1;
j = i;
}
}
/* Determine if the directory entries are exhausted. */
else if (dir_entry1.fx_dir_entry_name[0] == FX_DIR_ENTRY_DONE)
{
/* Yes, this we are at the end of the directory. Have there
been any other free entries? */
if (i < j)
{
/* No, we need to remember this as the free entry. */
dir_entry = dir_entry1;
j = i;
}
break;
}
/* Check for a volume name. */
else if (dir_entry1.fx_dir_entry_attributes & FX_VOLUME)
{
/* Yes, we have found a previously set volume name - use this entry. */
dir_entry = dir_entry1;
j = i;
break;
}
/* Move to next directory entry. */
i++;
} while (i < media_ptr -> fx_media_root_directory_entries);
/* Determine if a volume entry was not found and there are no more empty slots. */
if (i == media_ptr -> fx_media_root_directory_entries)
{
/* Determine if there was a free or previous volume name. */
if (j == (media_ptr -> fx_media_root_directory_entries + 1))
{
/* No, nothing was available in the root directory. */
/* Release media protection. */
FX_UNPROTECT
/* No, existing volume name or space in the root directly was found, return an error. */
return(FX_MEDIA_INVALID);
}
}
/* Now set the volume name and attribute. */
/* Read the logical directory sector. */
status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) dir_entry.fx_dir_entry_log_sector,
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_BOOT_SECTOR);
/* Check the status of reading the directory entry. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error status. */
return(status);
}
/* Calculate pointer into directory buffer. */
work_ptr = media_ptr -> fx_media_memory_buffer +
(UINT)dir_entry.fx_dir_entry_byte_offset;
/* Copy the volume name into the directory entry. */
for (i = 0; volume_name[i]; i++)
{
/* Have we reached the end? */
if (i == 11)
{
break;
}
/* Pickup volume name byte. */
alpha = volume_name[i];
/* Determine if alpha needs to be converted to upper case. */
if ((alpha >= 'a') && (alpha <= 'z'))
{
/* Convert alpha to upper case. */
alpha = (CHAR)((INT)alpha - 0x20);
}
/* Store volume name. */
work_ptr[i] = (UCHAR)alpha;
}
/* Pad with space characters. */
for (; i < 11; i++)
{
work_ptr[i] = 0x20;
}
/* Set the appropriate attributes. */
work_ptr[11] = FX_VOLUME | FX_ARCHIVE;
/* Set the other parts of the volume entry. */
/* Clear the hi word of cluster. */
work_ptr[20] = 0;
work_ptr[21] = 0;
/* Clear the low word of cluster. */
work_ptr[26] = 0;
work_ptr[27] = 0;
/* Clear the file size. */
work_ptr[28] = 0;
work_ptr[29] = 0;
work_ptr[30] = 0;
work_ptr[31] = 0;
/* Write the directory sector to the media. */
status = _fx_utility_logical_sector_write(media_ptr, (ULONG64) dir_entry.fx_dir_entry_log_sector,
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
/* Release media protection. */
FX_UNPROTECT
/* Return the status. */
return(status);
}
+138
View File
@@ -0,0 +1,138 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
#include "fx_media.h"
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_write PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function writes the specified raw logical sector to the */
/* specified media. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* logical_sector Logical sector to read */
/* buffer_ptr Pointer to caller's buffer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_logical_sector_write Write logical sector utility */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_media_write(FX_MEDIA *media_ptr, ULONG logical_sector, VOID *buffer_ptr)
{
UINT status;
#ifdef TX_ENABLE_EVENT_TRACE
TX_TRACE_BUFFER_ENTRY *trace_event;
ULONG trace_timestamp;
#endif
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of times this service has been called. */
media_ptr -> fx_media_writes++;
#endif
/* Check the media to make sure it is open. */
if (media_ptr -> fx_media_id != FX_MEDIA_ID)
{
/* Return the media not opened error. */
return(FX_MEDIA_NOT_OPEN);
}
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_WRITE, media_ptr, logical_sector, buffer_ptr, 0, FX_TRACE_MEDIA_EVENTS, &trace_event, &trace_timestamp)
/* Protect against other threads accessing the media. */
FX_PROTECT
/* Check for write protect at the media level (set by driver). */
if (media_ptr -> fx_media_driver_write_protect)
{
/* Release media protection. */
FX_UNPROTECT
/* Return write protect error. */
return(FX_WRITE_PROTECT);
}
/* Write the logical sector. */
status = _fx_utility_logical_sector_write(media_ptr, (ULONG64) logical_sector, buffer_ptr, ((ULONG) 1), FX_DATA_SECTOR);
#ifdef TX_ENABLE_EVENT_TRACE
/* Check for successful status. */
if (status == FX_SUCCESS)
{
/* Update the trace event with the bytes written. */
FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_WRITE, 0, 0, 0, media_ptr -> fx_media_bytes_per_sector)
}
#endif
/* Release media protection. */
FX_UNPROTECT
/* Return status to the caller. */
return(status);
}
+605
View File
@@ -0,0 +1,605 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Application Utility */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_utility.h"
/* Define internal data structures. */
typedef struct FX_MEDIA_PARTITION_STRUCT
{
ULONG fx_media_part_start;
ULONG fx_media_part_size;
} FX_MEDIA_PARTITION;
/* Define internal partition constants. */
#ifndef FX_MAX_PARTITION_COUNT
#define FX_MAX_PARTITION_COUNT 16
#endif /* FX_MAX_PARTITION_COUNT */
#define FX_PARTITION_TABLE_OFFSET 446
#define FX_PARTITION_ENTRY_SIZE 16
#define FX_PARTITION_TYPE_OFFSET 4
#define FX_PARTITION_LBA_OFFSET 8
#define FX_PARTITION_SECTORS_OFFSET 12
#define FX_PARTITION_TYPE_FREE 0x00
#define FX_PARTITION_TYPE_EXTENDED 0x05
#define FX_PARTITION_TYPE_EXTENDED_LBA 0x0F
/* Define function prototypes for the partition table parsing application
utility. */
UINT _fx_partition_offset_calculate(void *partition_sector, UINT partition,
ULONG *partition_start, ULONG *partition_size);
UINT _fx_utility_partition_get(FX_MEDIA_PARTITION *partition_table,
UINT *count, ULONG sector, UCHAR *sector_buffer);
UINT _fx_partition_offset_calculate_extended(FX_MEDIA *media_ptr, void *partition_sector, UINT partition,
ULONG *partition_start, ULONG *partition_size);
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_partition_offset_calculate PORTABLE C */
/* 6.1.6 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calculates the sector offset to the specified */
/* partition. The buffer containing the partition table is also */
/* supplied to this function. If the buffer supplied is a boot */
/* record (which could be the case in non-partition systems), this */
/* function returns an offset of zero, the total sectors, and a */
/* successful status indicating that the buffer supplied is the boot */
/* record. Otherwise, if a partition is found, this function returns */
/* the sector offset to its boot record along with a successful */
/* status. If the specified partition is not found or the buffer is */
/* not a partition table or boot record, this function returns an */
/* error. */
/* */
/* Note: Empty partitions have a FX_SUCCESS return code, however their */
/* starting sector is FX_NULL and the size returned is 0. */
/* */
/* INPUT */
/* */
/* partition_sector Pointer to buffer containing */
/* either the partition table */
/* or the boot sector */
/* partition Desired partition */
/* partition_start Return partition start */
/* partition_size Return partition size */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_partition_get Actual partition parsing */
/* routine */
/* */
/* CALLED BY */
/* */
/* Application Driver */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 04-02-2021 William E. Lamie Modified comment(s), */
/* ignored signature check for */
/* no partition situation, */
/* resulting in version 6.1.6 */
/* */
/**************************************************************************/
UINT _fx_partition_offset_calculate(void *partition_sector, UINT partition,
ULONG *partition_start, ULONG *partition_size)
{
FX_MEDIA_PARTITION partition_table[4];
UINT count;
ULONG64 total_sectors;
UCHAR *partition_sector_ptr;
/* Setup working pointer and initialize count. */
partition_sector_ptr = partition_sector;
count = 0;
/* Check for a real boot sector instead of a partition table. */
if ((partition_sector_ptr[0] == 0xe9) || ((partition_sector_ptr[0] == 0xeb) && (partition_sector_ptr[2] == 0x90)))
{
/* Yes, a real boot sector could be present. */
/* See if there are good values for sectors per FAT. */
if (partition_sector_ptr[0x16] || partition_sector_ptr[0x17] || partition_sector_ptr[0x24] || partition_sector_ptr[0x25] || partition_sector_ptr[0x26] || partition_sector_ptr[0x27])
{
/* There are values for sectors per FAT. */
/* Determine if there is a total sector count. */
total_sectors = 0;
if (partition_sector_ptr[0x13] || partition_sector_ptr[0x14])
{
/* Calculate the total sectors, FAT12/16. */
total_sectors = (((ULONG) partition_sector_ptr[0x14]) << 8) | ((ULONG) partition_sector_ptr[0x13]);
}
else if (partition_sector_ptr[0x20] || partition_sector_ptr[0x21] || partition_sector_ptr[0x22] || partition_sector_ptr[0x23])
{
/* Calculate the total sectors, FAT32. */
total_sectors = (((ULONG) partition_sector_ptr[0x23]) << 24) |
(((ULONG) partition_sector_ptr[0x22]) << 16) |
(((ULONG) partition_sector_ptr[0x21]) << 8) |
((ULONG) partition_sector_ptr[0x20]);
}
/* Determine if there is a total sector count. */
if (total_sectors)
{
if (partition_start != FX_NULL)
{
/* Return an offset of 0, size of boot record, and a successful status. */
*partition_start = 0;
}
/* Determine if the total sectors is required. */
if (partition_size != FX_NULL)
{
/* Return the total sectors. */
*partition_size = (ULONG)(total_sectors & 0xFFFFFFFF);
}
/* Return success! */
return(FX_SUCCESS);
}
}
}
/* Check signature to make sure the buffer is valid. */
if ((partition_sector_ptr[510] != 0x55) || (partition_sector_ptr[511] != 0xAA))
{
/* Invalid, return an error. */
return(FX_NOT_FOUND);
}
/* Not bootable, look for specific partition. */
_fx_utility_partition_get(partition_table, &count, 0, partition_sector_ptr);
/* Determine if return value is valid. */
if (partition >= count)
{
/* No, return an error. */
return(FX_NOT_FOUND);
}
/* Return the partition starting sector, if non-NULL. */
if (partition_start != FX_NULL)
{
*partition_start = partition_table[partition].fx_media_part_start;
}
/* Return the partition size, if non-NULL. */
if (partition_size != FX_NULL)
{
*partition_size = partition_table[partition].fx_media_part_size;
}
/* Return successful completion. */
return(FX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_utility_partition_get PORTABLE C */
/* 6.1.6 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function parses the partition sector and completes the */
/* supplied partition entry structure. */
/* */
/* INPUT */
/* */
/* partition_table Pointer to partition table */
/* count Number of partitions found */
/* sector Base sector */
/* sector_buffer Buffer containing partition */
/* table */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _fx_partition_offset_calculate Calculate partition offset */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 04-02-2021 William E. Lamie Modified comment(s), */
/* resulting in version 6.1.6 */
/* */
/**************************************************************************/
UINT _fx_utility_partition_get(FX_MEDIA_PARTITION *partition_table,
UINT *count, ULONG sector, UCHAR *sector_buffer)
{
UINT i;
ULONG base_sector, value;
/* This parameter has not been supported yet. */
FX_PARAMETER_NOT_USED(sector);
/* Initialize base sector. */
base_sector = 0;
for(i = 446; i <= 494; i+=16)
{
if (sector_buffer[i + 4] == 0) /* no partition entry here */
{
partition_table[*count].fx_media_part_start = 0;
partition_table[*count].fx_media_part_size = 0;
}
else
{
value = (ULONG) sector_buffer[i + 8]; /* little endian start value */
value = (((ULONG) sector_buffer[i + 9]) << 8) | value;
value = (((ULONG) sector_buffer[i + 10]) << 16) | value;
value = (((ULONG) sector_buffer[i + 11]) << 24) | value;
partition_table[*count].fx_media_part_start = value + base_sector;
value = (ULONG) sector_buffer[i + 12]; /* little endian size value */
value = (((ULONG) sector_buffer[i + 13]) << 8) | value;
value = (((ULONG) sector_buffer[i + 14]) << 16) | value;
value = (((ULONG) sector_buffer[i + 15]) << 24) | value;
partition_table[*count].fx_media_part_size = value;
}
(*count)++;
}
/* Return success. */
return(FX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_partition_offset_calculate_extended PORTABLE C */
/* 6.2.0 */
/* AUTHOR */
/* */
/* Xiuwen Cai, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calculates the sector offset to the specified */
/* partition. The buffer containing the partition table is also */
/* supplied to this function. If the buffer supplied is a boot */
/* record (which could be the case in non-partition systems), this */
/* function returns an offset of zero, the total sectors, and a */
/* successful status indicating that the buffer supplied is the boot */
/* record. Otherwise, if a partition is found, this function returns */
/* the sector offset to its boot record along with a successful */
/* status. If the specified partition is not found or the buffer is */
/* not a partition table or boot record, this function returns an */
/* error. */
/* */
/* Note: Empty partitions have a FX_NOT_FOUND return code. */
/* Use partition index 0 to 3 for primary partition and index 4 to */
/* FX_MAX_PARTITION_COUNT for extended partition. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* partition_sector Pointer to buffer containing */
/* either the partition table */
/* or the boot sector */
/* partition Desired partition */
/* partition_start Return partition start */
/* partition_size Return partition size */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_16_unsigned_read Read a USHORT from memory */
/* _fx_utility_32_unsigned_read Read a ULONG from memory */
/* _fx_utility_64_unsigned_read Read a ULONG64 from memory */
/* Media driver */
/* */
/* CALLED BY */
/* */
/* Application Driver */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-31-2022 Xiuwen Cai Initial Version 6.2.0 */
/* */
/**************************************************************************/
UINT _fx_partition_offset_calculate_extended(FX_MEDIA *media_ptr, void *partition_sector, UINT partition,
ULONG *partition_start, ULONG *partition_size)
{
ULONG64 total_sectors;
UCHAR *partition_sector_ptr;
UCHAR partition_type;
UINT i;
ULONG base_sector;
ULONG base_sector_extended;
/* Setup working pointer. */
partition_sector_ptr = partition_sector;
/* Check for a real boot sector instead of a partition table. */
if ((partition_sector_ptr[0] == 0xe9) || ((partition_sector_ptr[0] == 0xeb) && (partition_sector_ptr[2] == 0x90)))
{
/* Yes, a real boot sector could be present. */
/* See if there are good values for sectors per FAT. */
if (partition_sector_ptr[0x16] || partition_sector_ptr[0x17] || partition_sector_ptr[0x24] || partition_sector_ptr[0x25] || partition_sector_ptr[0x26] || partition_sector_ptr[0x27])
{
/* There are values for sectors per FAT. */
/* Get the total sectors, FAT12/16. */
total_sectors = _fx_utility_16_unsigned_read(&partition_sector_ptr[FX_SECTORS]);
if (total_sectors == 0)
{
/* Get the total sectors, FAT32. */
total_sectors = _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_HUGE_SECTORS]);
}
/* Determine if there is a total sector count. */
if (total_sectors)
{
if (partition_start != FX_NULL)
{
/* Return an offset of 0, size of boot record, and a successful status. */
*partition_start = 0;
}
/* Determine if the total sectors is required. */
if (partition_size != FX_NULL)
{
/* Return the total sectors. */
*partition_size = (ULONG)(total_sectors & 0xFFFFFFFF);
}
/* Return success! */
return(FX_SUCCESS);
}
}
}
/* Check signature to make sure the buffer is valid. */
if ((partition_sector_ptr[510] != FX_SIG_BYTE_1) || (partition_sector_ptr[511] != FX_SIG_BYTE_2))
{
/* Invalid, return an error. */
return(FX_NOT_FOUND);
}
/* Not bootable, look for specific partition. */
/* Check if primary partitions are addressed. */
if (partition < 4)
{
/* Get partition type. */
partition_type = partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + partition * FX_PARTITION_ENTRY_SIZE + FX_PARTITION_TYPE_OFFSET];
/* Check if there is a vaild partition. */
if (partition_type != FX_PARTITION_TYPE_FREE)
{
/* Return the partition starting sector, if non-NULL. */
if (partition_start != FX_NULL)
{
*partition_start = _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + partition * FX_PARTITION_ENTRY_SIZE + FX_PARTITION_LBA_OFFSET]);
}
/* Return the partition size, if non-NULL. */
if (partition_size != FX_NULL)
{
*partition_size = _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + partition * FX_PARTITION_ENTRY_SIZE + FX_PARTITION_SECTORS_OFFSET]);
}
/* Return success! */
return(FX_SUCCESS);
}
else
{
/* Not partition here. */
return(FX_NOT_FOUND);
}
}
/* Check for invalid parameter. */
if (partition > FX_MAX_PARTITION_COUNT)
{
/* Return error. */
return(FX_NOT_FOUND);
}
base_sector = 0;
/* Loop to find the extended partition table. */
for(i = FX_PARTITION_TABLE_OFFSET; i <= FX_PARTITION_TABLE_OFFSET + 3 * FX_PARTITION_ENTRY_SIZE; i += FX_PARTITION_ENTRY_SIZE)
{
/* Get partition type. */
partition_type = partition_sector_ptr[i + FX_PARTITION_TYPE_OFFSET];
if (partition_type == FX_PARTITION_TYPE_EXTENDED || partition_type == FX_PARTITION_TYPE_EXTENDED_LBA)
{
base_sector = _fx_utility_32_unsigned_read(&partition_sector_ptr[i + FX_PARTITION_LBA_OFFSET]);
break;
}
}
if (base_sector == 0)
{
/* No extended partition. */
return(FX_NOT_FOUND);
}
base_sector_extended = base_sector;
for (i = 4; i <= partition; i++)
{
/* Read the partition sector from the device. Build the read sector
command. */
media_ptr -> fx_media_driver_request = FX_DRIVER_READ;
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
media_ptr -> fx_media_driver_buffer = partition_sector_ptr;
media_ptr -> fx_media_driver_logical_sector = base_sector;
media_ptr -> fx_media_driver_sectors = 1;
media_ptr -> fx_media_driver_sector_type = FX_UNKNOWN_SECTOR;
media_ptr -> fx_media_hidden_sectors = 0;
/* Invoke the driver to read the sector. */
(media_ptr -> fx_media_driver_entry) (media_ptr);
/* Determine if the sector was read correctly. */
if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
{
/* Return error. */
return(FX_IO_ERROR);
}
/* Check signature to make sure the sector is valid. */
if ((partition_sector_ptr[510] != FX_SIG_BYTE_1) || (partition_sector_ptr[511] != FX_SIG_BYTE_2))
{
/* Invalid, return an error. */
return(FX_NOT_FOUND);
}
/* Determine if this is the desired partition. */
if (i == partition)
{
/* Get partition type. */
partition_type = partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + FX_PARTITION_TYPE_OFFSET];
if (partition_type != FX_PARTITION_TYPE_FREE)
{
/* Return the partition starting sector, if non-NULL. */
if (partition_start != FX_NULL)
{
*partition_start = _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + FX_PARTITION_LBA_OFFSET]) + base_sector;
}
/* Return the partition size, if non-NULL. */
if (partition_size != FX_NULL)
{
*partition_size = _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + FX_PARTITION_SECTORS_OFFSET]);
}
/* Return success! */
return(FX_SUCCESS);
}
else
{
/* Not partition here. */
return(FX_NOT_FOUND);
}
}
else
{
/* Get partition type. */
partition_type = partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + FX_PARTITION_ENTRY_SIZE + FX_PARTITION_TYPE_OFFSET];
if (partition_type == FX_PARTITION_TYPE_EXTENDED || partition_type == FX_PARTITION_TYPE_EXTENDED_LBA)
{
/* Update sector number for next partition table. */
base_sector = _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + FX_PARTITION_ENTRY_SIZE + FX_PARTITION_LBA_OFFSET]) + base_sector_extended;
}
else
{
/* No valid partition, get out of the loop. */
break;
}
}
}
/* Return error. */
return(FX_NOT_FOUND);
}
+370
View File
@@ -0,0 +1,370 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** RAM Disk Driver */
/** */
/**************************************************************************/
/**************************************************************************/
/* Include necessary system files. */
#include "fx_api.h"
/* The RAM driver relies on the fx_media_format call to be made prior to
the fx_media_open call. The following call will format the default
32KB RAM drive, with a sector size of 128 bytes per sector.
fx_media_format(&ram_disk,
_fx_ram_driver, // Driver entry
ram_disk_memory, // RAM disk memory pointer
media_memory, // Media buffer pointer
sizeof(media_memory), // Media buffer size
"MY_RAM_DISK", // Volume Name
1, // Number of FATs
32, // Directory Entries
0, // Hidden sectors
256, // Total sectors
128, // Sector size
1, // Sectors per cluster
1, // Heads
1); // Sectors per track
*/
VOID _fx_ram_driver(FX_MEDIA *media_ptr);
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_ram_driver PORTABLE C */
/* 6.1.5 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is the entry point to the generic RAM disk driver */
/* that is delivered with all versions of FileX. The format of the */
/* RAM disk is easily modified by calling fx_media_format prior */
/* to opening the media. */
/* */
/* This driver also serves as a template for developing FileX drivers */
/* for actual devices. Simply replace the read/write sector logic with */
/* calls to read/write from the appropriate physical device */
/* */
/* FileX RAM/FLASH structures look like the following: */
/* */
/* Physical Sector Contents */
/* */
/* 0 Boot record */
/* 1 FAT Area Start */
/* +FAT Sectors Root Directory Start */
/* +Directory Sectors Data Sector Start */
/* */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _fx_utility_memory_copy Copy sector memory */
/* _fx_utility_16_unsigned_read Read 16-bit unsigned */
/* */
/* CALLED BY */
/* */
/* FileX System Functions */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 03-02-2021 William E. Lamie Modified comment(s), */
/* resulting in version 6.1.5 */
/* */
/**************************************************************************/
VOID _fx_ram_driver(FX_MEDIA *media_ptr)
{
UCHAR *source_buffer;
UCHAR *destination_buffer;
UINT bytes_per_sector;
/* There are several useful/important pieces of information contained in
the media structure, some of which are supplied by FileX and others
are for the driver to setup. The following is a summary of the
necessary FX_MEDIA structure members:
FX_MEDIA Member Meaning
fx_media_driver_request FileX request type. Valid requests from
FileX are as follows:
FX_DRIVER_READ
FX_DRIVER_WRITE
FX_DRIVER_FLUSH
FX_DRIVER_ABORT
FX_DRIVER_INIT
FX_DRIVER_BOOT_READ
FX_DRIVER_RELEASE_SECTORS
FX_DRIVER_BOOT_WRITE
FX_DRIVER_UNINIT
fx_media_driver_status This value is RETURNED by the driver.
If the operation is successful, this
field should be set to FX_SUCCESS for
before returning. Otherwise, if an
error occurred, this field should be
set to FX_IO_ERROR.
fx_media_driver_buffer Pointer to buffer to read or write
sector data. This is supplied by
FileX.
fx_media_driver_logical_sector Logical sector FileX is requesting.
fx_media_driver_sectors Number of sectors FileX is requesting.
The following is a summary of the optional FX_MEDIA structure members:
FX_MEDIA Member Meaning
fx_media_driver_info Pointer to any additional information
or memory. This is optional for the
driver use and is setup from the
fx_media_open call. The RAM disk uses
this pointer for the RAM disk memory
itself.
fx_media_driver_write_protect The DRIVER sets this to FX_TRUE when
media is write protected. This is
typically done in initialization,
but can be done anytime.
fx_media_driver_free_sector_update The DRIVER sets this to FX_TRUE when
it needs to know when clusters are
released. This is important for FLASH
wear-leveling drivers.
fx_media_driver_system_write FileX sets this flag to FX_TRUE if the
sector being written is a system sector,
e.g., a boot, FAT, or directory sector.
The driver may choose to use this to
initiate error recovery logic for greater
fault tolerance.
fx_media_driver_data_sector_read FileX sets this flag to FX_TRUE if the
sector(s) being read are file data sectors,
i.e., NOT system sectors.
fx_media_driver_sector_type FileX sets this variable to the specific
type of sector being read or written. The
following sector types are identified:
FX_UNKNOWN_SECTOR
FX_BOOT_SECTOR
FX_FAT_SECTOR
FX_DIRECTORY_SECTOR
FX_DATA_SECTOR
*/
/* Process the driver request specified in the media control block. */
switch (media_ptr -> fx_media_driver_request)
{
case FX_DRIVER_READ:
{
/* Calculate the RAM disk sector offset. Note the RAM disk memory is pointed to by
the fx_media_driver_info pointer, which is supplied by the application in the
call to fx_media_open. */
source_buffer = ((UCHAR *)media_ptr -> fx_media_driver_info) +
((media_ptr -> fx_media_driver_logical_sector +
media_ptr -> fx_media_hidden_sectors) *
media_ptr -> fx_media_bytes_per_sector);
/* Copy the RAM sector into the destination. */
_fx_utility_memory_copy(source_buffer, media_ptr -> fx_media_driver_buffer,
media_ptr -> fx_media_driver_sectors *
media_ptr -> fx_media_bytes_per_sector);
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_WRITE:
{
/* Calculate the RAM disk sector offset. Note the RAM disk memory is pointed to by
the fx_media_driver_info pointer, which is supplied by the application in the
call to fx_media_open. */
destination_buffer = ((UCHAR *)media_ptr -> fx_media_driver_info) +
((media_ptr -> fx_media_driver_logical_sector +
media_ptr -> fx_media_hidden_sectors) *
media_ptr -> fx_media_bytes_per_sector);
/* Copy the source to the RAM sector. */
_fx_utility_memory_copy(media_ptr -> fx_media_driver_buffer, destination_buffer,
media_ptr -> fx_media_driver_sectors *
media_ptr -> fx_media_bytes_per_sector);
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_FLUSH:
{
/* Return driver success. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_ABORT:
{
/* Return driver success. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_INIT:
{
/* FLASH drivers are responsible for setting several fields in the
media structure, as follows:
media_ptr -> fx_media_driver_free_sector_update
media_ptr -> fx_media_driver_write_protect
The fx_media_driver_free_sector_update flag is used to instruct
FileX to inform the driver whenever sectors are not being used.
This is especially useful for FLASH managers so they don't have
maintain mapping for sectors no longer in use.
The fx_media_driver_write_protect flag can be set anytime by the
driver to indicate the media is not writable. Write attempts made
when this flag is set are returned as errors. */
/* Perform basic initialization here... since the boot record is going
to be read subsequently and again for volume name requests. */
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_UNINIT:
{
/* There is nothing to do in this case for the RAM driver. For actual
devices some shutdown processing may be necessary. */
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_BOOT_READ:
{
/* Read the boot record and return to the caller. */
/* Calculate the RAM disk boot sector offset, which is at the very beginning of
the RAM disk. Note the RAM disk memory is pointed to by the
fx_media_driver_info pointer, which is supplied by the application in the
call to fx_media_open. */
source_buffer = (UCHAR *)media_ptr -> fx_media_driver_info;
/* For RAM driver, determine if the boot record is valid. */
if ((source_buffer[0] != (UCHAR)0xEB) ||
((source_buffer[1] != (UCHAR)0x34) &&
(source_buffer[1] != (UCHAR)0x76)) ||
(source_buffer[2] != (UCHAR)0x90))
{
/* Invalid boot record, return an error! */
media_ptr -> fx_media_driver_status = FX_MEDIA_INVALID;
return;
}
/* For RAM disk only, pickup the bytes per sector. */
bytes_per_sector = _fx_utility_16_unsigned_read(&source_buffer[FX_BYTES_SECTOR]);
/* Ensure this is less than the media memory size. */
if (bytes_per_sector > media_ptr -> fx_media_memory_size)
{
media_ptr -> fx_media_driver_status = FX_BUFFER_ERROR;
break;
}
/* Copy the RAM boot sector into the destination. */
_fx_utility_memory_copy(source_buffer, media_ptr -> fx_media_driver_buffer,
bytes_per_sector);
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_BOOT_WRITE:
{
/* Write the boot record and return to the caller. */
/* Calculate the RAM disk boot sector offset, which is at the very beginning of the
RAM disk. Note the RAM disk memory is pointed to by the fx_media_driver_info
pointer, which is supplied by the application in the call to fx_media_open. */
destination_buffer = (UCHAR *)media_ptr -> fx_media_driver_info;
/* Copy the RAM boot sector into the destination. */
_fx_utility_memory_copy(media_ptr -> fx_media_driver_buffer, destination_buffer,
media_ptr -> fx_media_bytes_per_sector);
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
default:
{
/* Invalid driver request. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
break;
}
}
}
+119
View File
@@ -0,0 +1,119 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** System */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_system_date_get PORTABLE C */
/* 6.1.7 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function returns the current contents of the system date in */
/* the fields specified by the caller. */
/* */
/* INPUT */
/* */
/* year Pointer to year */
/* month Pointer to month */
/* day Pointer to day */
/* */
/* OUTPUT */
/* */
/* FX_SUCCESS */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 06-02-2021 William E. Lamie Modified comment(s), */
/* checked null pointer, */
/* resulting in version 6.1.7 */
/* */
/**************************************************************************/
UINT _fx_system_date_get(UINT *year, UINT *month, UINT *day)
{
UINT date;
/* Get a copy of the current date. */
date = _fx_system_date;
/* Check to see if the year is required. */
if (year)
{
/* Pickup the year. */
*year = ((date >> FX_YEAR_SHIFT) & FX_YEAR_MASK) + FX_BASE_YEAR;
}
/* Check to see if the month is required. */
if (month)
{
/* Pickup the month. */
*month = (date >> FX_MONTH_SHIFT) & FX_MONTH_MASK;
}
/* Check to see if the day is required. */
if (day)
{
/* Pickup the day. */
*day = date & FX_DAY_MASK;
}
/* If trace is enabled, insert this event into the trace buffer. */
if (year && month && day)
{
FX_TRACE_IN_LINE_INSERT(FX_TRACE_SYSTEM_DATE_GET, *year, *month, *day, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
}
/* Return successful status. */
return(FX_SUCCESS);
}
+88
View File
@@ -0,0 +1,88 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** System */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_system_date_set PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the system date to the date specified by the */
/* caller. */
/* */
/* INPUT */
/* */
/* year Year (1980-2107) */
/* month Month (1-12) */
/* day Day (1-28/29/30/31) */
/* */
/* OUTPUT */
/* */
/* FX_SUCCESS */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_system_date_set(UINT year, UINT month, UINT day)
{
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_SYSTEM_DATE_SET, year, month, day, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Set the system date. */
_fx_system_date = ((year - FX_BASE_YEAR) << FX_YEAR_SHIFT) |
(month << FX_MONTH_SHIFT) | day;
/* Return successful status. */
return(FX_SUCCESS);
}
+207
View File
@@ -0,0 +1,207 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** System */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Locate FileX control component data in this file. */
#define FX_SYSTEM_INIT
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_system_initialize PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function initializes the various control data structures for */
/* the FileX System component. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* tx_timer_create Create system timer */
/* */
/* CALLED BY */
/* */
/* Application Initialization */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), and */
/* added conditional to */
/* disable build options, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
VOID _fx_system_initialize(VOID)
{
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_SYSTEM_INITIALIZE, 0, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Initialize the head pointer of the opened media list and the
number of opened media. */
_fx_system_media_opened_ptr = FX_NULL;
_fx_system_media_opened_count = 0;
/* Initialize the time and date fields with their default values. */
_fx_system_date = FX_INITIAL_DATE;
_fx_system_time = FX_INITIAL_TIME;
/* Initialize the sector and FAT cache sizes. */
_fx_system_media_max_sector_cache = FX_MAX_SECTOR_CACHE;
_fx_system_media_max_fat_cache = FX_MAX_FAT_CACHE;
/* Create the FileX system timer. This is responsible for updating
the specified date and time at the rate specified by
FX_UPDATE_RATE_IN_TICKS. Note that the timer is not necessary for
regular FileX operation - it is only needed for accurate system
date and time stamps on files. */
#ifndef FX_NO_TIMER
tx_timer_create(&_fx_system_timer, "FileX System Timer", _fx_system_timer_entry, FX_TIMER_ID,
FX_UPDATE_RATE_IN_TICKS, FX_UPDATE_RATE_IN_TICKS, TX_AUTO_ACTIVATE);
#endif
#ifndef FX_DISABLE_BUILD_OPTIONS
/* Setup the build options variables. */
/* Setup the first build options variable. */
if (FX_MAX_LONG_NAME_LEN > 0xFF)
{
_fx_system_build_options_1 = _fx_system_build_options_1 | (((ULONG)0xFF) << 24);
}
else
{
_fx_system_build_options_1 = _fx_system_build_options_1 | (((ULONG)(FX_MAX_LONG_NAME_LEN & 0xFF)) << 24);
}
if (FX_MAX_LAST_NAME_LEN > 0xFF)
{
_fx_system_build_options_1 = _fx_system_build_options_1 | (((ULONG)0xFF) << 16);
}
else
{
_fx_system_build_options_1 = _fx_system_build_options_1 | (((ULONG)(FX_MAX_LAST_NAME_LEN & 0xFF)) << 24);
}
#ifdef FX_NO_TIMER
_fx_system_build_options_1 = _fx_system_build_options_1 | (((ULONG)1) << 10);
#endif
#ifdef FX_SINGLE_THREAD
_fx_system_build_options_1 = _fx_system_build_options_1 | (((ULONG)1) << 9);
#endif
#ifdef FX_DONT_UPDATE_OPEN_FILES
_fx_system_build_options_1 = _fx_system_build_options_1 | (((ULONG)1) << 8);
#endif
#ifdef FX_MEDIA_DISABLE_SEARCH_CACHE
_fx_system_build_options_1 = _fx_system_build_options_1 | (((ULONG)1) << 7);
#endif
#ifdef FX_MEDIA_STATISTICS_DISABLE
_fx_system_build_options_1 = _fx_system_build_options_1 | (((ULONG)1) << 6);
#endif
#ifdef FX_SINGLE_OPEN_LEGACY
_fx_system_build_options_1 = _fx_system_build_options_1 | (((ULONG)1) << 4);
#endif
#ifdef FX_RENAME_PATH_INHERIT
_fx_system_build_options_1 = _fx_system_build_options_1 | (((ULONG)1) << 3);
#endif
#ifdef FX_NO_LOCAL_PATH
_fx_system_build_options_1 = _fx_system_build_options_1 | (((ULONG)1) << 2);
#endif
#ifdef FX_FAULT_TOLERANT_DATA
_fx_system_build_options_1 = _fx_system_build_options_1 | (((ULONG)1) << 1);
#endif
#ifdef FX_FAULT_TOLERANT
_fx_system_build_options_1 = _fx_system_build_options_1 | ((ULONG)1);
#endif
/* Setup the second build options variable. */
if (FX_MAX_SECTOR_CACHE > ((ULONG)0xFFFF))
{
_fx_system_build_options_2 = _fx_system_build_options_2 | (((ULONG)0xFFFF) << 16);
}
else
{
_fx_system_build_options_2 = _fx_system_build_options_2 | (((ULONG)FX_MAX_SECTOR_CACHE) << 16);
}
if (FX_FAT_MAP_SIZE > 0xFF)
{
_fx_system_build_options_2 = _fx_system_build_options_2 | (((ULONG)0xFF) << 8);
}
else
{
_fx_system_build_options_2 = _fx_system_build_options_2 | (((ULONG)FX_FAT_MAP_SIZE) << 8);
}
if (FX_MAX_FAT_CACHE > 0xFF)
{
_fx_system_build_options_2 = _fx_system_build_options_2 | ((ULONG)0xFF);
}
else
{
_fx_system_build_options_2 = _fx_system_build_options_2 | ((ULONG)FX_MAX_FAT_CACHE);
}
/* Setup the third build options variable. */
if (FX_UPDATE_RATE_IN_SECONDS > 0xFF)
{
_fx_system_build_options_3 = _fx_system_build_options_3 | (((ULONG)0xFF) << 16);
}
else
{
_fx_system_build_options_3 = _fx_system_build_options_3 | (((ULONG)FX_UPDATE_RATE_IN_SECONDS) << 16);
}
if (FX_UPDATE_RATE_IN_TICKS > ((ULONG)0xFFFF))
{
_fx_system_build_options_3 = _fx_system_build_options_3 | ((ULONG)0xFFFF);
}
else
{
_fx_system_build_options_3 = _fx_system_build_options_3 | ((ULONG)FX_UPDATE_RATE_IN_TICKS);
}
#endif /* FX_DISABLE_BUILD_OPTIONS */
}
+119
View File
@@ -0,0 +1,119 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** System */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_system_time_get PORTABLE C */
/* 6.1.7 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function returns the current contents of the system time in */
/* the fields specified by the caller. */
/* */
/* INPUT */
/* */
/* hour Pointer to hour */
/* minute Pointer to minute */
/* second Pointer to second */
/* */
/* OUTPUT */
/* */
/* FX_SUCCESS */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* 06-02-2021 William E. Lamie Modified comment(s), */
/* checked null pointer, */
/* resulting in version 6.1.7 */
/* */
/**************************************************************************/
UINT _fx_system_time_get(UINT *hour, UINT *minute, UINT *second)
{
UINT time;
/* Get a copy of the current system time. */
time = _fx_system_time;
/* Check to see if the hour is required. */
if (hour)
{
/* Pickup the hour. */
*hour = (time >> FX_HOUR_SHIFT) & FX_HOUR_MASK;
}
/* Check to see if the minute is required. */
if (minute)
{
/* Pickup the minute. */
*minute = (time >> FX_MINUTE_SHIFT) & FX_MINUTE_MASK;
}
/* Check to see if the second is required. */
if (second)
{
/* Pickup the second. */
*second = (time & FX_SECOND_MASK) * 2;
}
/* If trace is enabled, insert this event into the trace buffer. */
if (hour && minute && second)
{
FX_TRACE_IN_LINE_INSERT(FX_TRACE_SYSTEM_TIME_GET, *hour, *minute, *second, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
}
/* Return successful status. */
return(FX_SUCCESS);
}
+88
View File
@@ -0,0 +1,88 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** System */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_system_time_set PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function set the system time to the value specified by the */
/* caller. */
/* */
/* INPUT */
/* */
/* hour Hour (0-23) */
/* minute Minute (0-59) */
/* second Second (0-59) */
/* */
/* OUTPUT */
/* */
/* FX_SUCCESS */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _fx_system_time_set(UINT hour, UINT minute, UINT second)
{
/* If trace is enabled, insert this event into the trace buffer. */
FX_TRACE_IN_LINE_INSERT(FX_TRACE_SYSTEM_TIME_SET, hour, minute, second, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
/* Set the new system time. */
_fx_system_time = (hour << FX_HOUR_SHIFT) |
(minute << FX_MINUTE_SHIFT) | (second / 2);
/* Return successful status. */
return(FX_SUCCESS);
}
+343
View File
@@ -0,0 +1,343 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** System */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_system.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_system_timer_entry PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is FileX system timer function. It is called at the */
/* rate specified by FX_UPDATE_RATE_IN_SECONDS and is responsible for */
/* maintaining both the system date and time. */
/* */
/* INPUT */
/* */
/* id Not used */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Initialization */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
VOID _fx_system_timer_entry(ULONG id)
{
UINT second;
UINT minute;
UINT hour;
UINT day;
UINT month;
UINT year;
/* Determine if the ID is valid. */
if (id == FX_TIMER_ID)
{
/* Break the current date time into separate fields for easier work! */
second = (_fx_system_time & FX_SECOND_MASK) * 2;
minute = (_fx_system_time >> FX_MINUTE_SHIFT) & FX_MINUTE_MASK;
hour = (_fx_system_time >> FX_HOUR_SHIFT) & FX_HOUR_MASK;
day = _fx_system_date & FX_DAY_MASK;
month = (_fx_system_date >> FX_MONTH_SHIFT) & FX_MONTH_MASK;
year = ((_fx_system_date >> FX_YEAR_SHIFT) & FX_YEAR_MASK) + FX_BASE_YEAR;
/* Now apply the "second" update. */
second = second + FX_UPDATE_RATE_IN_SECONDS;
/* Determine if we need to adjust the minute field. */
if (second > FX_MAXIMUM_SECOND)
{
/* Yes, we need to adjust the minute field. */
minute = minute + second / 60;
second = second % 60;
/* Determine if we need to adjust the hour field. */
if (minute > FX_MAXIMUM_MINUTE)
{
/* Yes, we need to adjust the hour field. */
hour = hour + minute / 60;
minute = minute % 60;
/* Determine if we need to adjust the day field. */
if (hour > FX_MAXIMUM_HOUR)
{
/* Yes, we need to adjust the day field. */
hour = 0;
day++;
/* Determine if we need to adjust the month field. */
switch (month)
{
case 1: /* January */
{
/* Check for end of the month. */
if (day > 31)
{
/* Move to next month. */
day = 1;
month++;
}
break;
}
case 2: /* February */
{
/* Check for leap year. We don't need to check for leap
century her (century years divisible by 400) since 2000
is and this FAT format only supports years to 2107. */
if ((year % 4) == 0)
{
/* Leap year in February... check for 29 days
instead of 28. */
if (day > 29)
{
/* Adjust the month. */
day = 1;
month++;
}
}
else
{
if (day > 28)
{
/* Adjust the month. */
day = 1;
month++;
}
}
break;
}
case 3: /* March */
{
/* Check for end of the month. */
if (day > 31)
{
/* Move to next month. */
day = 1;
month++;
}
break;
}
case 4: /* April */
{
/* Check for end of the month. */
if (day > 30)
{
/* Move to next month. */
day = 1;
month++;
}
break;
}
case 5: /* May */
{
/* Check for end of the month. */
if (day > 31)
{
/* Move to next month. */
day = 1;
month++;
}
break;
}
case 6: /* June */
{
/* Check for end of the month. */
if (day > 30)
{
/* Move to next month. */
day = 1;
month++;
}
break;
}
case 7: /* July */
{
/* Check for end of the month. */
if (day > 31)
{
/* Move to next month. */
day = 1;
month++;
}
break;
}
case 8: /* August */
{
/* Check for end of the month. */
if (day > 31)
{
/* Move to next month. */
day = 1;
month++;
}
break;
}
case 9: /* September */
{
/* Check for end of the month. */
if (day > 30)
{
/* Move to next month. */
day = 1;
month++;
}
break;
}
case 10: /* October */
{
/* Check for end of the month. */
if (day > 31)
{
/* Move to next month. */
day = 1;
month++;
}
break;
}
case 11: /* November */
{
/* Check for end of the month. */
if (day > 30)
{
/* Move to next month. */
day = 1;
month++;
}
break;
}
case 12: /* December */
{
/* Check for end of the month. */
if (day > 31)
{
/* Move to next month. */
day = 1;
month = 1;
/* Also move to next year. */
year++;
/* Check for a year that exceeds the representation
in this format. */
if (year > FX_MAXIMUM_YEAR)
{
return;
}
}
break;
}
default: /* Invalid month! */
return; /* Skip updating date/time! */
}
}
}
}
/* Now apply the new setting to the internal representation. */
/* Set the system date. */
_fx_system_date = ((year - FX_BASE_YEAR) << FX_YEAR_SHIFT) |
(month << FX_MONTH_SHIFT) | day;
/* Set the new system time. */
_fx_system_time = (hour << FX_HOUR_SHIFT) |
(minute << FX_MINUTE_SHIFT) | (second / 2);
}
}

Some files were not shown because too many files have changed in this diff Show More