Initial commit

This commit is contained in:
PProvost 2020-05-11 08:47:24 -06:00
commit 2d93b0a9a0
266 changed files with 58461 additions and 0 deletions

40
.gitattributes vendored Normal file
View File

@ -0,0 +1,40 @@
.git* export-ignore
.hooks* export-ignore
# Custom attribute to mark sources as using our C code style.
[attr]our-c-style whitespace=tab-in-indent eol=lf format.clang-format-6.0
# Custom attribute to mark sources as generated.
# Do not perform whitespace checks. Do not format.
[attr]generated whitespace=-tab-in-indent,-indent-with-non-tab -format.clang-format-6.0
bootstrap eol=lf
configure eol=lf
*.[1-9] eol=lf
*.bash eol=lf
*.sh eol=lf
*.sh.in eol=lf
*.bat eol=crlf
*.bat.in eol=crlf
*.sln eol=crlf
*.vcproj eol=crlf
*.pfx -text
*.png -text
*.png.in -text
*.c our-c-style
*.cc our-c-style
*.cpp our-c-style
*.cu our-c-style
*.cxx our-c-style
*.h our-c-style
*.hh our-c-style
*.hpp our-c-style
*.hxx our-c-style
*.notcu our-c-style
*.cmake whitespace=tab-in-indent
*.rst whitespace=tab-in-indent conflict-marker-size=79
*.txt whitespace=tab-in-indent

14
.gitignore vendored Executable file
View File

@ -0,0 +1,14 @@
.vscode/
_deps/
build/
CMakeFiles/
CMakeScripts/
CMakeLists.txt.user
CMakeCache.txt
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake

49
CMakeLists.txt Executable file
View File

@ -0,0 +1,49 @@
cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
# Set up the project
project(filex
VERSION 6.0.0
LANGUAGES C ASM
)
if(NOT DEFINED THREADX_ARCH)
message(FATAL_ERROR "Error: THREADX_ARCH not defined")
endif()
if(NOT DEFINED THREADX_TOOLCHAIN)
message(FATAL_ERROR "Error: THREADX_TOOLCHAIN not defined")
endif()
# Define our target library and an alias for consumers
add_library(${PROJECT_NAME})
add_library("azrtos::${PROJECT_NAME}" ALIAS ${PROJECT_NAME})
# Define any required dependencies between this library and others
target_link_libraries(${PROJECT_NAME} PUBLIC
"azrtos::threadx"
)
# A place for generated/copied include files (no need to change)
set(CUSTOM_INC_DIR ${CMAKE_CURRENT_BINARY_DIR}/custom_inc)
# Pick up the port specific stuff first
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/ports/${THREADX_ARCH}/${THREADX_TOOLCHAIN})
# Then the common files
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/common)
# Include the user's override file if required
if (NOT FX_USER_FILE)
message(STATUS "Using default fx_user.h file")
set(FX_USER_FILE ${CMAKE_CURRENT_LIST_DIR}/common/inc/fx_user_sample.h)
else()
message(STATUS "Using custom fx_user.h file from ${FX_USER_FILE}")
endif()
configure_file(${FX_USER_FILE} ${CUSTOM_INC_DIR}/fx_user.h COPYONLY)
target_include_directories(${PROJECT_NAME}
PUBLIC
${CUSTOM_INC_DIR}
)
target_compile_definitions(${PROJECT_NAME} PUBLIC "FX_INCLUDE_USER_DEFINE_FILE" )

246
LICENSE.txt Normal file
View File

@ -0,0 +1,246 @@
MICROSOFT SOFTWARE LICENSE TERMS
MICROSOFT AZURE RTOS
Shape
These license terms are an agreement between you and Microsoft Corporation (or
one of its affiliates). They apply to the software named above and any Microsoft
services or software updates (except to the extent such services or updates are
accompanied by new or additional terms, in which case those different terms
apply prospectively and do not alter your or Microsofts rights relating to
pre-updated software or services). IF YOU COMPLY WITH THESE LICENSE TERMS, YOU
HAVE THE RIGHTS BELOW. BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS.
INSTALLATION AND USE RIGHTS.
General. You may install and use the software and the included Microsoft
applications solely for internal development, testing and evaluation purposes.
Any distribution or production use requires a separate license as set forth in
Section 2.
Contributions. Microsoft welcomes contributions to this software. In the event
that you make a contribution to this software you will be required to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and
actually do, grant Microsoft the rights to use your contribution. For details,
visit https://cla.microsoft.com.
Included Microsoft Applications. The software includes other Microsoft
applications which are governed by the licenses embedded in or made available
with those applications.
Third Party Components. The software may include third party components with
separate legal notices or governed by other agreements, as may be described
within the software or in the ThirdPartyNotices file(s) accompanying the
software.
Competitive Benchmarking. If you are a direct competitor, and you access or use
the software for purposes of competitive benchmarking, analysis, or intelligence
gathering, you waive as against Microsoft, its subsidiaries, and its affiliated
companies (including prospectively) any competitive use, access, and
benchmarking test restrictions in the terms governing your software to the
extent your terms of use are, or purport to be, more restrictive than
Microsofts terms. If you do not waive any such purported restrictions in the
terms governing your software, you are not allowed to access or use this
software, and will not do so.
DISTRIBUTION AND PRODUCTION USE. If you have obtained and/or are developing on
microprocessor(s) and/or microcontroller(s) (“hardware”) listed in the file
named “LICENSED-HARDWARE.txt” included in the repository and/or distributed with
the software you have the following rights in and to the software solely when
used in combination with the hardware. In the event hardware is not listed in
the LICENSED-HARDWARE.txt file, you do not have the rights in this Section 2.
Distribution and Production Use Rights.
You may use the software in production (e.g. program the modified or unmodified
software to devices you own or control) and distribute (i.e. make available to
third parties) the modified or unmodified binary image produced from this code.
You may permit your device distributors or developers to copy and distribute the
binary image as programmed or to be programmed to your devices.
You may redistribute the unmodified or modified source to your device
distributors or developers. Modifications must be clearly marked. Any
redistribution in source code form must contain this license and any other
licenses that accompany the software.
Requirements. For any code you distribute, you must:
when distributed in binary form, except as embedded in a device, include with
such distribution the terms of this agreement;
when distributed in source code form to distributors or developers of your
devices, include with such distribution the terms of this agreement; and
indemnify, defend and hold harmless Microsoft from any claims, including
attorneys fees, related to the distribution or use of your devices, except to
the extent that any claim is based solely on the unmodified software.
Restrictions. You may not:
use or modify the software to create a competing real time operating system
software;
remove any copyright notices or licenses contained in the software;
use Microsofts trademarks or trade dress in your application in any way that
suggests your device or application comes from or is endorsed by Microsoft;
transfer individual components, specific libraries, classes, functions or code
fragments of the software separately for purposes unrelated to the software; or
use or distribute the software in any way that would subject the software or
Microsofts intellectual property or technology to any other license terms.
SCOPE OF LICENSE. The software is licensed, not sold. Microsoft reserves all
other rights. Unless applicable law gives you more rights despite this
limitation, you will not (and have no right to):
remove, minimize, block, or modify any notices of Microsoft or its suppliers in
the software;
use the software in any way that is against the law or to create or propagate
malware; or
share, publish, distribute, or lease the software (except as permitted in
Section 2 above), or provide the software as a stand-alone offering for others
to use.
DATA. This software may interact with other Microsoft products that collect data
that is transmitted to Microsoft. To learn more about how Microsoft processes
personal data we collect, please see the Microsoft Privacy Statement at
https://go.microsoft.com/fwlink/?LinkId=248681.
EXPORT RESTRICTIONS. You must comply with all domestic and international export
laws and regulations that apply to the software, which include restrictions on
destinations, end users, and end use. For further information on export
restrictions, visit https://aka.ms/exporting.
SUPPORT SERVICES. Microsoft is not obligated under this agreement to provide any
support services for the software. Any support provided is “as is”, “with all
faults”, and without warranty of any kind.
UPDATES. Microsoft may periodically update the software. You may obtain updates
only from Microsoft or Microsoft-authorized sources. Updates may not include or
support all existing software features, services, or peripheral devices.
TERMINATION. Without prejudice to any other rights, Microsoft may terminate this
agreement if you fail to comply with any of its terms or conditions. In such
event, you must destroy all copies of the software and all of its component
parts.
ENTIRE AGREEMENT. This agreement, and any other terms Microsoft may provide for
supplements, updates, or third-party applications, is the entire agreement for
the software. To the extent you have entered into a separate agreement with
Microsoft relating specifically to the software, the terms in such agreement
shall control.
APPLICABLE LAW AND PLACE TO RESOLVE DISPUTES. If you acquired the software in
the United States or Canada, the laws of the state or province where you live
(or, if a business, where your principal place of business is located) govern
the interpretation of this agreement, claims for its breach, and all other
claims (including consumer protection, unfair competition, and tort claims),
regardless of conflict of laws principles. If you acquired the software in any
other country, its laws apply. If U.S. federal jurisdiction exists, you and
Microsoft consent to exclusive jurisdiction and venue in the federal court in
King County, Washington for all disputes heard in court. If not, you and
Microsoft consent to exclusive jurisdiction and venue in the Superior Court of
King County, Washington for all disputes heard in court.
CONSUMER RIGHTS; REGIONAL VARIATIONS. This agreement describes certain legal
rights. You may have other rights, including consumer rights, under the laws of
your state or country. Separate and apart from your relationship with Microsoft,
you may also have rights with respect to the party from which you acquired the
software. This agreement does not change those other rights if the laws of your
state or country do not permit it to do so. For example, if you acquired the
software in one of the below regions, or mandatory country law applies, then the
following provisions apply to you:
Australia. You have statutory guarantees under the Australian Consumer Law and
nothing in this agreement is intended to affect those rights.
Germany and Austria.
i.Warranty. The properly licensed software will perform substantially as
described in any Microsoft materials that accompany the software. However,
Microsoft gives no contractual guarantee in relation to the licensed software.
ii.Limitation of Liability. In case of intentional conduct, gross negligence,
claims based on the Product Liability Act, as well as, in case of death or
personal or physical injury, Microsoft is liable according to the statutory law.
Subject to the foregoing clause ii., Microsoft will only be liable for slight
negligence if Microsoft is in breach of such material contractual obligations,
the fulfillment of which facilitate the due performance of this agreement, the
breach of which would endanger the purpose of this agreement and the compliance
with which a party may constantly trust in (so-called "cardinal obligations").
In other cases of slight negligence, Microsoft will not be liable for slight
negligence.
DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS IS.” YOU BEAR THE RISK OF
USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES, OR CONDITIONS. TO
THE EXTENT PERMITTED UNDER APPLICABLE LAWS, MICROSOFT EXCLUDES ALL IMPLIED
WARRANTIES, INCLUDING MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
NON-INFRINGEMENT.
LIMITATION ON AND EXCLUSION OF DAMAGES. IF YOU HAVE ANY BASIS FOR RECOVERING
DAMAGES DESPITE THE PRECEDING DISCLAIMER OF WARRANTY, YOU CAN RECOVER FROM
MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT
RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL,
INDIRECT, OR INCIDENTAL DAMAGES.
This limitation applies to (a) anything related to the software, services,
content (including code) on third party Internet sites, or third party
applications; and (b) claims for breach of contract, warranty, guarantee, or
condition; strict liability, negligence, or other tort; or any other claim; in
each case to the extent permitted by applicable law.
It also applies even if Microsoft knew or should have known about the
possibility of the damages. The above limitation or exclusion may not apply to
you because your state, province, or country may not allow the exclusion or
limitation of incidental, consequential, or other damages.
Please note: As this software is distributed in Canada, some of the clauses in
this agreement are provided below in French.
Remarque: Ce logiciel étant distribué au Canada, certaines des clauses dans ce
contrat sont fournies ci-dessous en français.
EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel
». Toute utilisation de ce logiciel est à votre seule risque et péril. Microsoft
naccorde aucune autre garantie expresse. Vous pouvez bénéficier de droits
additionnels en vertu du droit local sur la protection des consommateurs, que ce
contrat ne peut modifier. La ou elles sont permises par le droit locale, les
garanties implicites de qualité marchande, dadéquation à un usage particulier
et dabsence de contrefaçon sont exclues.
LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES
DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une
indemnisation en cas de dommages directs uniquement à hauteur de 5,00 $ US. Vous
ne pouvez prétendre à aucune indemnisation pour les autres dommages, y compris
les dommages spéciaux, indirects ou accessoires et pertes de bénéfices.
Cette limitation concerne:
•tout ce qui est relié au logiciel, aux services ou au contenu (y compris le
code) figurant sur des sites Internet tiers ou dans des programmes tiers; et
•les réclamations au titre de violation de contrat ou de garantie, ou au titre
de responsabilité stricte, de négligence ou dune autre faute dans la limite
autorisée par la loi en vigueur.
Elle sapplique également, même si Microsoft connaissait ou devrait connaître
léventualité dun tel dommage. Si votre pays nautorise pas lexclusion ou la
limitation de responsabilité pour les dommages indirects, accessoires ou de
quelque nature que ce soit, il se peut que la limitation ou lexclusion
ci-dessus ne sappliquera pas à votre égard.
EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous
pourriez avoir dautres droits prévus par les lois de votre pays. Le présent
contrat ne modifie pas les droits que vous confèrent les lois de votre pays si
celles-ci ne le permettent pas.

16
LICENSED-HARDWARE.txt Normal file
View File

@ -0,0 +1,16 @@
LICENSED HARDWARE LIST
Last Updated: 2020-05-08
Microsoft has entered into OEM Agreements with manufacturers of the following
microprocessors and microcontrollers (the “hardware”) to enable those
manufacturers to include and distribute Azure RTOS in certain hardware. If you
have obtained and/or are developing on microprocessor(s) and/or
microcontroller(s) (“hardware”) listed below you inherit the “Distribution and
Production Use” rights in Section 2 of the Microsoft Software License Terms for
Microsoft Azure RTOS. If hardware is not listed below, you do not have those
rights.
--------------------------------------------------------------------------------
More coming soon. Please check back frequently for updates.

3
README.md Executable file
View File

@ -0,0 +1,3 @@
# FileX
TODO: Description here

1
TODO Normal file
View File

@ -0,0 +1 @@
* exFAT is still in here... do we need to remove it?

246
common/CMakeLists.txt Normal file
View File

@ -0,0 +1,246 @@
target_sources(${PROJECT_NAME} PRIVATE
# {{BEGIN_TARGET_SOURCES}}
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_attributes_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_attributes_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_create.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_default_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_default_get_copy.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_default_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_delete.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_entry_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_entry_write.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_exFAT_entry_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_exFAT_entry_write.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_exFAT_free_search.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_exFAT_unicode_entry_write.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_first_entry_find.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_first_full_entry_find.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_free_search.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_information_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_local_path_clear.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_local_path_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_local_path_get_copy.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_local_path_restore.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_local_path_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_long_name_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_long_name_get_extended.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_name_extract.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_name_test.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_next_entry_find.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_next_full_entry_find.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_rename.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_search.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_short_name_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_directory_short_name_get_extended.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_add_FAT_log.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_add_bitmap_log.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_add_checksum_log.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_add_dir_log.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_apply_logs.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_calculate_checksum.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_cleanup_FAT_chain.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_create_log_file.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_enable.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_read_FAT.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_read_directory_sector.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_read_log_file.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_recover.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_reset_log_file.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_set_FAT_chain.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_transaction_end.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_transaction_fail.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_transaction_start.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_fault_tolerant_write_log_file.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_allocate.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_attributes_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_attributes_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_best_effort_allocate.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_close.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_create.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_date_time_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_delete.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_extended_allocate.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_extended_best_effort_allocate.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_extended_relative_seek.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_extended_seek.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_extended_truncate.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_extended_truncate_release.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_open.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_relative_seek.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_rename.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_seek.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_truncate.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_truncate_release.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_write.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_file_write_notify_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_abort.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_boot_info_extract.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_cache_invalidate.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_check.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_check_FAT_chain_check.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_check_lost_cluster_check.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_close.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_close_notify_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_exFAT_format.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_extended_space_available.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_flush.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_format.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_format_oem_name_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_format_type_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_format_volume_id_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_open.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_open_notify_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_space_available.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_volume_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_volume_get_extended.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_volume_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_media_write.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_partition_offset_calculate.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_ram_driver.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_system_date_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_system_date_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_system_initialize.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_system_time_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_system_time_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_system_timer_entry.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_trace_event_insert.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_trace_event_update.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_trace_object_register.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_trace_object_unregister.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_unicode_directory_create.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_unicode_directory_entry_change.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_unicode_directory_entry_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_unicode_directory_rename.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_unicode_directory_search.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_unicode_file_create.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_unicode_file_rename.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_unicode_length_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_unicode_length_get_extended.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_unicode_name_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_unicode_name_get_extended.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_unicode_short_name_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_unicode_short_name_get_extended.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_16_unsigned_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_16_unsigned_write.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_32_unsigned_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_32_unsigned_write.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_64_unsigned_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_64_unsigned_write.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_FAT_entry_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_FAT_entry_write.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_FAT_flush.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_FAT_map_flush.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_FAT_sector_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_absolute_path_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_allocate_new_cluster.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_bitmap_cache_prepare.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_bitmap_cache_update.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_bitmap_flush.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_bitmap_free_cluster_find.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_bitmap_initialize.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_bitmap_start_sector_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_cluster_free.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_cluster_state_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_cluster_state_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_geometry_check.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_name_hash_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_size_calculate.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_system_area_checksum_verify.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_system_area_checksum_write.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_system_area_format.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_system_sector_write.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_unicode_name_hash_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_exFAT_upcase_table.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_logical_sector_cache_entry_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_logical_sector_flush.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_logical_sector_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_logical_sector_write.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_memory_copy.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_memory_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_string_length_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_utility_token_length_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_attributes_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_attributes_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_create.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_default_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_default_get_copy.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_default_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_delete.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_first_entry_find.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_first_full_entry_find.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_information_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_local_path_clear.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_local_path_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_local_path_get_copy.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_local_path_restore.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_local_path_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_long_name_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_long_name_get_extended.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_name_test.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_next_entry_find.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_next_full_entry_find.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_rename.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_short_name_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_directory_short_name_get_extended.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_fault_tolerant_enable.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_allocate.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_attributes_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_attributes_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_best_effort_allocate.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_close.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_create.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_date_time_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_delete.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_extended_allocate.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_extended_best_effort_allocate.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_extended_relative_seek.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_extended_seek.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_extended_truncate.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_extended_truncate_release.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_open.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_relative_seek.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_rename.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_seek.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_truncate.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_truncate_release.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_write.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_file_write_notify_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_abort.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_cache_invalidate.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_check.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_close.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_close_notify_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_exFAT_format.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_extended_space_available.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_flush.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_format.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_open.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_open_notify_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_read.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_space_available.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_volume_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_volume_get_extended.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_volume_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_media_write.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_system_date_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_system_date_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_system_time_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_system_time_set.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_unicode_directory_create.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_unicode_directory_rename.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_unicode_file_create.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_unicode_file_rename.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_unicode_name_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_unicode_name_get_extended.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_unicode_short_name_get.c
${CMAKE_CURRENT_LIST_DIR}/src/fxe_unicode_short_name_get_extended.c
# {{END_TARGET_SOURCES}}
)
target_include_directories(${PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_LIST_DIR}/inc
)

1566
common/inc/fx_api.h Normal file

File diff suppressed because it is too large Load Diff

135
common/inc/fx_directory.h Normal file
View File

@ -0,0 +1,135 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/* */
/* COMPONENT DEFINITION RELEASE */
/* */
/* fx_directory.h PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This file defines the FileX Directory component constants, data */
/* definitions, and external references. It is assumed that fx_api.h */
/* (and fx_port.h) have already been included. */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
#ifndef FX_DIRECTORY_H
#define FX_DIRECTORY_H
/* Define the external Directory component function prototypes. */
UINT _fx_directory_attributes_read(FX_MEDIA *media_ptr, CHAR *directory_name, UINT *attributes_ptr);
UINT _fx_directory_attributes_set(FX_MEDIA *media_ptr, CHAR *directory_name, UINT attributes);
UINT _fx_directory_create(FX_MEDIA *media_ptr, CHAR *directory_name);
UINT _fx_directory_default_get(FX_MEDIA *media_ptr, CHAR **return_path_name);
UINT _fx_directory_default_get_copy(FX_MEDIA *media_ptr, CHAR *return_path_name_buffer, UINT return_path_name_buffer_size);
UINT _fx_directory_default_set(FX_MEDIA *media_ptr, CHAR *new_path_name);
UINT _fx_directory_delete(FX_MEDIA *media_ptr, CHAR *directory_name);
UINT _fx_directory_entry_read_FAT(FX_MEDIA *media_ptr, FX_DIR_ENTRY *source_dir, ULONG *entry_ptr,
FX_DIR_ENTRY *destination_ptr);
UINT _fx_directory_first_entry_find(FX_MEDIA *media_ptr, CHAR *directory_name);
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 _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 _fx_directory_local_path_clear(FX_MEDIA *media_ptr);
UINT _fx_directory_local_path_get(FX_MEDIA *media_ptr, CHAR **return_path_name);
UINT _fx_directory_local_path_get_copy(FX_MEDIA *media_ptr, CHAR *return_path_name_buffer, UINT return_path_name_buffer_size);
UINT _fx_directory_local_path_restore(FX_MEDIA *media_ptr, FX_LOCAL_PATH *local_path_ptr);
UINT _fx_directory_local_path_set(FX_MEDIA *media_ptr, FX_LOCAL_PATH *local_path_ptr, CHAR *new_path_name);
UINT _fx_directory_long_name_get(FX_MEDIA *media_ptr, CHAR *short_file_name, CHAR *long_file_name);
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 _fx_directory_name_test(FX_MEDIA *media_ptr, CHAR *directory_name);
UINT _fx_directory_next_entry_find(FX_MEDIA *media_ptr, CHAR *directory_name);
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);
UINT _fx_directory_rename(FX_MEDIA *media_ptr, CHAR *old_directory_name, CHAR *new_directory_name);
UINT _fx_directory_short_name_get(FX_MEDIA *media_ptr, CHAR *long_file_name, CHAR *short_file_name);
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 _fxe_directory_attributes_read(FX_MEDIA *media_ptr, CHAR *directory_name, UINT *attributes_ptr);
UINT _fxe_directory_attributes_set(FX_MEDIA *media_ptr, CHAR *directory_name, UINT attributes);
UINT _fxe_directory_create(FX_MEDIA *media_ptr, CHAR *directory_name);
UINT _fxe_directory_default_get(FX_MEDIA *media_ptr, CHAR **return_path_name);
UINT _fxe_directory_default_get_copy(FX_MEDIA *media_ptr, CHAR *return_path_name_buffer, UINT return_path_name_buffer_size);
UINT _fxe_directory_default_set(FX_MEDIA *media_ptr, CHAR *new_path_name);
UINT _fxe_directory_delete(FX_MEDIA *media_ptr, CHAR *directory_name);
UINT _fxe_directory_first_entry_find(FX_MEDIA *media_ptr, CHAR *directory_name);
UINT _fxe_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 _fxe_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 _fxe_directory_local_path_clear(FX_MEDIA *media_ptr);
UINT _fxe_directory_local_path_get(FX_MEDIA *media_ptr, CHAR **return_path_name);
UINT _fxe_directory_local_path_get_copy(FX_MEDIA *media_ptr, CHAR *return_path_name_buffer, UINT return_path_name_buffer_size);
UINT _fxe_directory_local_path_restore(FX_MEDIA *media_ptr, FX_LOCAL_PATH *local_path_ptr);
UINT _fxe_directory_local_path_set(FX_MEDIA *media_ptr, FX_LOCAL_PATH *local_path_ptr, CHAR *new_path_name, UINT local_path_control_block_size);
UINT _fxe_directory_long_name_get(FX_MEDIA *media_ptr, CHAR *short_file_name, CHAR *long_file_name);
UINT _fxe_directory_long_name_get_extended(FX_MEDIA *media_ptr, CHAR *short_file_name, CHAR *long_file_name, UINT long_file_name_buffer_length);
UINT _fxe_directory_name_test(FX_MEDIA *media_ptr, CHAR *directory_name);
UINT _fxe_directory_next_entry_find(FX_MEDIA *media_ptr, CHAR *directory_name);
UINT _fxe_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);
UINT _fxe_directory_rename(FX_MEDIA *media_ptr, CHAR *old_directory_name, CHAR *new_directory_name);
UINT _fxe_directory_short_name_get(FX_MEDIA *media_ptr, CHAR *long_file_name, CHAR *short_file_name);
UINT _fxe_directory_short_name_get_extended(FX_MEDIA *media_ptr, CHAR *long_file_name, CHAR *short_file_name, UINT short_file_name_length);
/* Define the internal Directory component function prototypes. */
#ifdef FX_ENABLE_EXFAT
#define UPDATE_DELETE (0)
#define UPDATE_FILE (1)
#define UPDATE_STREAM (2)
#define UPDATE_NAME (3)
#define UPDATE_FULL (4)
UINT _fx_directory_entry_read_ex(FX_MEDIA *media_ptr, FX_DIR_ENTRY *source_dir, ULONG *entry, FX_DIR_ENTRY *destination_ptr, UINT hash);
UINT _fx_directory_exFAT_entry_read(FX_MEDIA *media_ptr, FX_DIR_ENTRY *source_dir, ULONG *entry_ptr, FX_DIR_ENTRY *destination_ptr, UINT hash, UINT skip, UCHAR *unicode_name, UINT *unicode_len);
UINT _fx_directory_exFAT_entry_write(FX_MEDIA *media_ptr, FX_DIR_ENTRY *entry_ptr, UCHAR update_level);
UINT _fx_directory_exFAT_unicode_entry_write(FX_MEDIA *media_ptr, FX_DIR_ENTRY *entry_ptr, UCHAR update_level, USHORT *unicode_name,
UINT unicode_len);
UINT _fx_directory_exFAT_free_search(FX_MEDIA *media_ptr, FX_DIR_ENTRY *directory_ptr, FX_DIR_ENTRY *entry_ptr);
#endif /* FX_ENABLE_EXFAT */
UINT _fx_directory_entry_read(FX_MEDIA *media_ptr, FX_DIR_ENTRY *source_dir, ULONG *entry, FX_DIR_ENTRY *destination_ptr);
UINT _fx_directory_entry_write(FX_MEDIA *media_ptr, FX_DIR_ENTRY *entry_ptr);
UINT _fx_directory_free_search(FX_MEDIA *media_ptr, FX_DIR_ENTRY *directory_ptr, FX_DIR_ENTRY *entry_ptr);
CHAR *_fx_directory_name_extract(CHAR *source_ptr, CHAR *dest_ptr);
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);
#endif

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 */
/** */
/** Directory */
/** */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/* */
/* COMPONENT DEFINITION RELEASE */
/* */
/* fx_directory_exFAT.h PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This file defines the exFAT Directory entry component constants, */
/* data definitions, and external references. */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
#ifndef FX_DIRECTORY_EXFAT_H
#define FX_DIRECTORY_EXFAT_H
#include "fx_api.h"
#define FX_EXFAT_DIR_ENTRY_TYPE_ALLOCATION_BITMAP 0x81
#define FX_EXFAT_DIR_ENTRY_TYPE_UP_CASE_TABLE 0x82
#define FX_EXFAT_DIR_ENTRY_TYPE_VOLUME_LABEL 0x83
#define FX_EXFAT_DIR_ENTRY_TYPE_FILE_DIRECTORY 0x85
#define FX_EXFAT_DIR_ENTRY_TYPE_VOLUME_GUID 0xA0
#define FX_EXFAT_DIR_ENTRY_TYPE_STREAM_EXTENSION 0xC0
#define FX_EXFAT_DIR_ENTRY_TYPE_FILE_NAME 0xC1
#define FX_EXFAT_DIR_ENTRY_TYPE_CONTINUOUS_INFO_MANAGE 0xE0
#define FX_EXFAT_DIR_ENTRY_TYPE_CONTINUOUS_INFO 0xE1
#define FX_EXFAT_DIR_ENTRY_TYPE_END_MARKER 0x00
#define FX_EXFAT_DIR_ENTRY_TYPE_FREE 0xFF
/* Define the directory entry size. */
#define FX_EXFAT_DIR_ENTRY_SIZE 32
/* Define bit masks. */
#define FX_EXFAT_ENTRY_TYPE_CODE_MASK 0x1F
#define FX_EXFAT_ENTRY_TYPE_IMPORTANCE_MASK 0x20
#define FX_EXFAT_ENTRY_TYPE_CATEGORY_MASK 0x40
#define FX_EXFAT_ENTRY_TYPE_IN_USE_MASK 0x80
#define FX_EXFAT_SECOND_FLAG_ALLOCATION_POSSIBLE_MASK 0x01
/* Define common primary and secondary directory entry structure. */
#define FX_EXFAT_ENTRY_TYPE 0 /* Size 1 byte */
/* Define primary-specific directory entry structure. */
#define FX_EXFAT_SECOND_COUNT 1 /* Size 1 byte */
#define FX_EXFAT_CHECK_SUM 2 /* Size 2 bytes */
#define FX_EXFAT_PRIM_FLAG 4 /* Size 2 bytes */
/* Define secondary-specific directory entry structure. */
#define FX_EXFAT_SECOND_FLAG 1 /* Size 1 byte */
/* Define common primary and secondary directory entry structure. */
#define FX_EXFAT_FIRST_CLUSTER 20 /* Size 4 bytes */
#define FX_EXFAT_DATA_LENGTH 24 /* Size 8 bytes */
/* Define Allocation Bitmap directory entry. */
#define FX_EXFAT_BIT_MAP_FLAGS 1 /* Size 1 byte */
/* Define UP-case Table Entry specific. */
#define FX_EXFAT_UP_CASE_TABLE_CHECK_SUM 4 /* Size 4 bytes */
/* Define Volume Label Entry specific. */
#define FX_EXFAT_CHAR_COUNT 1 /* Size 1 byte */
#define FX_EXFAT_VOLUME_LABEL 2 /* Size 22 bytes */
/* Define File directory entry specific. This is a primary item. */
#define FX_EXFAT_FILE_ATTR 4 /* Size 2 bytes */
#define FX_EXFAT_CREATE_TIME 8 /* Size 4 bytes */
#define FX_EXFAT_LAST_MODIFIED_TIME 12 /* Size 4 bytes */
#define FX_EXFAT_LAST_ACCESSED_TIME 16 /* Size 4 bytes */
#define FX_EXFAT_LAST_CREATE_10MS_INC 20 /* Size 1 byte */
#define FX_EXFAT_LAST_MODIFIED_10MS_INC 21 /* Size 1 byte */
#define FX_EXFAT_CREATE_UTC_OFFSET 22 /* Size 1 byte */
#define FX_EXFAT_LAST_MODIFIED_UTC_OFFSET 23 /* Size 1 byte */
#define FX_EXFAT_LAST_ACCESSED_UTC_OFFSET 24 /* Size 1 byte */
/* Define Volume GUID directory entry specific. This is a primary item. */
#define FX_EXFAT_VOLUME_GUID 6 /* Size 16 bytes */
/* Define Stream extension directory entry specific. This is a secondary item. */
#define FX_EXFAT_NAME_LENGTH 3 /* Size 1 byte */
#define FX_EXFAT_NAME_HASH 4 /* Size 2 bytes */
#define FX_EXFAT_VALID_DATA_LENGTH 8 /* Size 8 bytes */
/* Define File Name directory entry specific. This is a secondary item. */
#define FX_EXFAT_FILE_NAME 2 /* Size 30 bytes */
/* Define Continuous Information Manage directory entry specific. This is a secondary item. */
#define FX_EXFAT_VENDOR_GUID 2 /* Size 16 bytes */
#define FX_EXFAT_FAT_CHECKSUM 20 /* Size 4 bytes */
/* Define Continuous Information directory entry specific. This is a secondary item. */
#define FX_EXFAT_SET_CHECKSUM 18 /* Size 2 bytes */
#endif

View File

@ -0,0 +1,412 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/* */
/* COMPONENT DEFINITION RELEASE */
/* */
/* fx_fault_tolerant.h PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This file defines the FileX Fault Tolerant component constants, */
/* data definitions, and external references. It is assumed that */
/* fx_api.h (and fx_port.h) have already been included. */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
#ifndef _FX_FAULT_TOLERANT_H_
#define _FX_FAULT_TOLERANT_H_
#ifdef FX_ENABLE_FAULT_TOLERANT
#ifndef FX_FAULT_TOLERANT
#error "FX_FAULT_TOLERANT must be defined with FX_ENABLE_FAULT_TOLERANT"
#endif /* FX_FAULT_TOLERANT */
/* Define ID of fault tolerant. */
#define FX_FAULT_TOLERANT_ID 0x46544C52
/* Define fault tolerant version. */
#define FX_FAULT_TOLERANT_VERSION_MAJOR 0x01
#define FX_FAULT_TOLERANT_VERSION_MINOR 0x00
/* Define byte offset in boot sector where the cluster number of the Fault Tolerant Log file is.
Note that this field (byte 116 to 119) is marked as reserved by FAT 12/16/32/exFAT specification. */
#ifndef FX_FAULT_TOLERANT_BOOT_INDEX
#define FX_FAULT_TOLERANT_BOOT_INDEX 116
#endif /* FX_FAULT_TOLERANT_BOOT_INDEX */
/* Define the extension invoked when fault tolerant log is recovered or applied during enable API. */
#ifndef FX_FAULT_TOLERANT_ENABLE_EXTENSION
#define FX_FAULT_TOLERANT_ENABLE_EXTENSION
#endif /* FX_FAULT_TOLERANT_ENABLE_EXTENSION */
/* Define the extension invoked when fault tolerant log is applied. */
#ifndef FX_FAULT_TOLERANT_APPLY_LOGS_EXTENSION
#define FX_FAULT_TOLERANT_APPLY_LOGS_EXTENSION
#endif /* FX_FAULT_TOLERANT_APPLY_LOGS_EXTENSION */
/* If not-defined, default port-specific processing extensions to white space. */
#ifndef FX_FAULT_TOLERANT_WRITE_LOG_FILE_EXTENSION
#define FX_FAULT_TOLERANT_WRITE_LOG_FILE_EXTENSION
#endif /* FX_FAULT_TOLERANT_WRITE_LOG_FILE_EXTENSION */
/* Define the maximum size of log file. */
#define FX_FAULT_TOLERANT_MAXIMUM_LOG_FILE_SIZE 3072
/* For backward compatibility, map the symbols deprecated to FX_FAULT_TOLERANT_MINIMAL_BUFFER_SIZE. */
#ifndef FX_FAULT_TOLERANT_MINIMAL_CLUSTER
#define FX_FAULT_TOLERANT_MINIMAL_CLUSTER FX_FAULT_TOLERANT_MAXIMUM_LOG_FILE_SIZE
#endif /* FX_FAULT_TOLERANT_MINIMAL_CLUSTER */
#ifndef FX_FAULT_TOLERANT_MINIMAL_BUFFER_SIZE
#define FX_FAULT_TOLERANT_MINIMAL_BUFFER_SIZE FX_FAULT_TOLERANT_MAXIMUM_LOG_FILE_SIZE
#endif /* FX_FAULT_TOLERANT_MINIMAL_BUFFER_SIZE */
/* Define the states of the fault tolerant module. */
#define FX_FAULT_TOLERANT_STATE_IDLE 0x00u
#define FX_FAULT_TOLERANT_STATE_STARTED 0x01u
#define FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN 0x02u
/* Define types of logs. */
#define FX_FAULT_TOLERANT_FAT_LOG_TYPE 1
#define FX_FAULT_TOLERANT_DIR_LOG_TYPE 2
#define FX_FAULT_TOLERANT_BITMAP_LOG_TYPE 3
/* Define operations of FAT chain. */
#define FX_FAULT_TOLERANT_FAT_CHAIN_RECOVER 0 /* Recover new FAT chain. */
#define FX_FAULT_TOLERANT_FAT_CHAIN_CLEANUP 1 /* Cleanup old FAT chain. */
/* Define flags for FAT chain log. */
#define FX_FAULT_TOLERANT_FLAG_FAT_CHAIN_VALID 0x01
#define FX_FAULT_TOLERANT_FLAG_BITMAP_USED 0x02
/* Define size of each section in log file. */
#define FX_FAULT_TOLERANT_LOG_HEADER_SIZE sizeof(FX_FAULT_TOLERANT_LOG_HEADER)
#define FX_FAULT_TOLERANT_FAT_CHAIN_SIZE sizeof(FX_FAULT_TOLERANT_FAT_CHAIN)
#define FX_FAULT_TOLERANT_LOG_CONTENT_HEADER_SIZE sizeof(FX_FAULT_TOLERANT_LOG_CONTENT)
/* Define offset of each section in log file. */
#define FX_FAULT_TOLERANT_FAT_CHAIN_OFFSET (FX_FAULT_TOLERANT_LOG_HEADER_SIZE)
#define FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET (FX_FAULT_TOLERANT_LOG_HEADER_SIZE + FX_FAULT_TOLERANT_FAT_CHAIN_SIZE)
/* Define size of log entries. */
/* The total size of DIR log entry is variable. 16 is the fixed size of DIR log entry. */
#define FX_FAULT_TOLERANT_FAT_LOG_ENTRY_SIZE sizeof(FX_FAULT_TOLERANT_FAT_LOG)
#define FX_FAULT_TOLERANT_BITMAP_LOG_ENTRY_SIZE sizeof(FX_FAULT_TOLERANT_BITMAP_LOG)
#define FX_FAULT_TOLERANT_DIR_LOG_ENTRY_SIZE sizeof(FX_FAULT_TOLERANT_DIR_LOG)
#ifdef FX_FAULT_TOLERANT_TRANSACTION_FAIL_FUNCTION
#define FX_FAULT_TOLERANT_TRANSACTION_FAIL _fx_fault_tolerant_transaction_fail
#else
/* Define transaction fail for fault tolerant. */
#define FX_FAULT_TOLERANT_TRANSACTION_FAIL(m) \
if ((m) -> fx_media_fault_tolerant_enabled == FX_TRUE) \
{ \
(m) -> fx_media_fault_tolerant_transaction_count--; \
if ((m) -> fx_media_fault_tolerant_transaction_count == 0) \
{ \
_fx_fault_tolerant_recover(m); \
_fx_fault_tolerant_reset_log_file(m); \
} \
}
#endif /* FX_FAULT_TOLERANT_TRANSACTION_FAIL_FUNCTION */
/* Log file format
* The entire log file fits into one cluster.
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + ID +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + Total Log Size (in Bytes) + Header Checksum + Log Header
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + version major + version minor + reserved +
* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + Checksum of FAT chain + Flag | Reserved +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + Insertion Point - Front +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + Head cluster of newly created FAT chain +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ FAT Chain
* + Head cluster of original FAT chain +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + Insertion Point - Back +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + Next Deletion Point +
* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + checksum of log content + count of log entries +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + (log 0) . +
* + . +
* + . +
* + . +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + (log 1) . +
* + . + Log Entries
* + . +
* + . +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + ... +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + (log N) . +
* + . +
* + . +
* + . +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*
*
* Log Header
*
* * ID: It is fixed value FX_FAULT_TOLERANT_ID.
* * Total Size: Total size (in bytes) of the log file, including Log Header, FAT Chain and Log Entries
* * Header Checksum: It is the checksum of all data in log header.
* * Version Major: The major version number.
* * Version Minor: The minor version number.
* * Reserved: Reserved for future use.
*
* FAT Chain
*
* * Checksum of FAT chain: It is the checksum of all data in the FAT Chain section.
* * Flag: 8 bits. The 1-6 bits are not used (from left to right).
* bit 7: When set, bitmap is used in old FAT chain.
* bit 8: When set, FAT chain is valid.
* * Reserved: Reserved for future use.
* * Insertion Point - Front: The cluster where the newly created chain is attached to
* * Head cluster of new FAT chain. It is the head cluster of new FAT chain.
* * Head cluster of oritinal FAT chain. It is the head cluster of the original FAT chain,
* which will be removed.
* * Inswertion Point - Back: The original cluster right after the newly created chain is inserted.
* * Next Deletion Point: next session of cluster to delete. It is used during deleting FAT chain.
* The deltion is carried out in stages for perofmrance reasons. When delting a FAT chain, the
* Next Deletion Point is chosen, and the chain between head and the Next Deletion Point is deleted.
*
* Log Entries:
*
* * Checksum of log entries: It is the checksum of all data in Log Entries
* * Counter of log entries: It is the counter of all log entries in Log content.
* * log 0 ... log N: Log entries. The formats are described below.
*/
/* Defined structure of log header.
*/
typedef struct FX_FAULT_TOLERANT_LOG_HEADER_STRUCT
{
ULONG fx_fault_tolerant_log_header_id;
USHORT fx_fault_tolerant_log_header_total_size;
USHORT fx_fault_tolerant_log_header_checksum;
UCHAR fx_fault_tolerant_log_header_version_major;
UCHAR fx_fault_tolerant_log_header_version_minor;
USHORT fx_fault_tolerant_log_header_reserved;
} FX_FAULT_TOLERANT_LOG_HEADER;
/* Define structure of FAT chain. */
typedef struct FX_FAULT_TOLERANT_FAT_CHAIN_STRUCT
{
USHORT fx_fault_tolerant_FAT_chain_checksumm;
UCHAR fx_fault_tolerant_FAT_chain_flag;
UCHAR fx_fault_tolerant_FAT_chain_reserved;
ULONG fx_fault_tolerant_FAT_chain_insertion_front;
ULONG fx_fault_tolerant_FAT_chain_head_new;
ULONG fx_fault_tolerant_FAT_chain_head_original;
ULONG fx_fault_tolerant_FAT_chain_insertion_back;
ULONG fx_fault_tolerant_FAT_chain_next_deletion;
} FX_FAULT_TOLERANT_FAT_CHAIN;
/* Define structure of Log content. */
typedef struct FX_FAULT_TOLERANT_LOG_CONTENT_STRUCT
{
USHORT fx_fault_tolerant_log_content_checksum;
USHORT fx_fault_tolerant_log_content_count;
} FX_FAULT_TOLERANT_LOG_CONTENT;
/* 3 types of log entries are defined. */
/* FAT log format
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + type + size +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + cluster +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + value +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*
* Description:
*
* Type: FX_FAULT_TOLERANT_FAT_LOG.
* Size: The size of this log entry.
* Cluster: The cluster number in FAT.
* Value: The value of cluster in FAT.
*
*/
typedef struct FX_FAULT_TOLERANT_FAT_LOG_STRUCT
{
USHORT fx_fault_tolerant_FAT_log_type;
USHORT fx_fault_tolerant_FAT_log_size;
ULONG fx_fault_tolerant_FAT_log_cluster;
ULONG fx_fault_tolerant_FAT_log_value;
} FX_FAULT_TOLERANT_FAT_LOG;
/* DIR log format
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + type + size +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + sector offset +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + log sector +
* + +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + log data +
* + . +
* + . +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*
* Fields description,
*
* Type: FX_FAULT_TOLERANT_DIRECTORY_LOG
* Size: The size of this log entry.
* Sector Offset: The offset in original sector this DIR is trying to write to.
* Log Sector: The original sector this DIR is trying to write to.
* Log Data: Content of DIR entries.
*
*/
typedef struct FX_FAULT_TOLERANT_DIR_LOG_STRUCT
{
USHORT fx_fault_tolerant_dir_log_type;
USHORT fx_fault_tolerant_dir_log_size;
ULONG fx_fault_tolerant_dir_log_offset;
ULONG64 fx_fault_tolerant_dir_log_sector;
} FX_FAULT_TOLERANT_DIR_LOG;
/* Bitmap log format
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + type + size +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + cluster +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* + value +
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*
* Description,
*
* Type: FX_FAULT_TOLERANT_BITMAP_LOG.
* Size: The size of this log entry.
* Cluster: The cluster number in FAT.
* Value: The value of cluster in FAT.
*/
typedef struct FX_FAULT_TOLERANT_BITMAP_LOG_STRUCT
{
USHORT fx_fault_tolerant_bitmap_log_type;
USHORT fx_fault_tolerant_bitmap_log_size;
ULONG fx_fault_tolerant_bitmap_log_cluster;
ULONG fx_fault_tolerant_bitmap_log_value;
} FX_FAULT_TOLERANT_BITMAP_LOG;
/* This function checks whether or not the log file exists, and creates the log file if it does not exist. */
UINT _fx_fault_tolerant_enable(FX_MEDIA *media_ptr, VOID *memory_buffer, UINT memory_size);
UINT _fxe_fault_tolerant_enable(FX_MEDIA *media_ptr, VOID *memory_buffer, UINT memory_size);
/* This function resets statistics and marks the start of a transaction. */
UINT _fx_fault_tolerant_transaction_start(FX_MEDIA *media_ptr);
/* This function marks the end of a transaction and completes the log file.
* Then it applies all data in the log file to the file system.
* Finally it resets the log header section. */
UINT _fx_fault_tolerant_transaction_end(FX_MEDIA *media_ptr);
/* This function resets the log file. */
UINT _fx_fault_tolerant_reset_log_file(FX_MEDIA *media_ptr);
/* This function applies the log file to the file system. */
UINT _fx_fault_tolerant_apply_logs(FX_MEDIA *media_ptr);
/* This function recovers FAT chain. */
UINT _fx_fault_tolerant_recover(FX_MEDIA *media_ptr);
/* This function adds a FAT log entry. */
UINT _fx_fault_tolerant_add_FAT_log(FX_MEDIA *media_ptr, ULONG cluster, ULONG value);
/* This function adds a directory log entry. */
UINT _fx_fault_tolerant_add_dir_log(FX_MEDIA *media_ptr, ULONG64 logical_sector, ULONG offset,
UCHAR *data, ULONG data_size);
#ifdef FX_ENABLE_EXFAT
/* This function adds a bitmap log entry. */
UINT _fx_fault_tolerant_add_bitmap_log(FX_MEDIA *media_ptr, ULONG cluster, ULONG value);
/* This function adds a checksum log entry. */
UINT _fx_fault_tolerant_add_checksum_log(FX_MEDIA *media_ptr, ULONG64 logical_sector, ULONG offset, USHORT checksum);
#endif /* FX_ENABLE_EXFAT */
/* This function sets the FAT chain. */
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);
/* This function reads a FAT entry from log file. If it doesn't exist in log file, return and read from FAT entry directly. */
UINT _fx_fault_tolerant_read_FAT(FX_MEDIA *media_ptr, ULONG cluster, ULONG *value, ULONG log_type);
/* This function reads directory sector from log file. */
UINT _fx_fault_tolerant_read_directory_sector(FX_MEDIA *media_ptr, ULONG64 logical_sector,
VOID *buffer_ptr, ULONG64 sectors);
/* This function calculates the checksum of the log header. */
USHORT _fx_fault_tolerant_calculate_checksum(UCHAR *data, UINT len);
/* This function cleans up FAT chain. */
UINT _fx_fault_tolerant_cleanup_FAT_chain(FX_MEDIA *media_ptr, UINT operation);
/* This function reads log file from file system to memory buffer. */
UINT _fx_fault_tolerant_read_log_file(FX_MEDIA *media_ptr);
/* This function writes data of one sector from memory to log file in file system. */
UINT _fx_fault_tolerant_write_log_file(FX_MEDIA *media_ptr, ULONG relative_sector);
/* This function creates log file. */
UINT _fx_fault_tolerant_create_log_file(FX_MEDIA *media_ptr);
#ifdef FX_FAULT_TOLERANT_TRANSACTION_FAIL_FUNCTION
/* This function cleans up resources created by fault tolerant when transaction fails. */
UINT _fx_fault_tolerant_transaction_fail(FX_MEDIA *media_ptr);
#endif /* FX_FAULT_TOLERANT_TRANSACTION_FAIL_FUNCTION */
#endif /* FX_ENABLE_FAULT_TOLERANT */
#endif /* _FX_FAULT_TOLERANT_H_ */

107
common/inc/fx_file.h Normal file
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 */
/** */
/** File */
/** */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/* */
/* COMPONENT DEFINITION RELEASE */
/* */
/* fx_file.h PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This file defines the FileX File component constants, data */
/* definitions, and external references. It is assumed that fx_api.h */
/* (and fx_port.h) have already been included. */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
#ifndef FX_FILE_H
#define FX_FILE_H
/* Define the external File component function prototypes. */
UINT _fx_file_allocate(FX_FILE *file_ptr, ULONG size);
UINT _fx_file_attributes_read(FX_MEDIA *media_ptr, CHAR *file_name, UINT *attributes_ptr);
UINT _fx_file_attributes_set(FX_MEDIA *media_ptr, CHAR *file_name, UINT attributes);
UINT _fx_file_best_effort_allocate(FX_FILE *file_ptr, ULONG size, ULONG *actual_size_allocated);
UINT _fx_file_close(FX_FILE *file_ptr);
UINT _fx_file_create(FX_MEDIA *media_ptr, CHAR *file_name);
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 _fx_file_delete(FX_MEDIA *media_ptr, CHAR *file_name);
UINT _fx_file_open(FX_MEDIA *media_ptr, FX_FILE *file_ptr, CHAR *file_name,
UINT open_type);
UINT _fx_file_read(FX_FILE *file_ptr, VOID *buffer_ptr, ULONG request_size, ULONG *actual_size);
UINT _fx_file_relative_seek(FX_FILE *file_ptr, ULONG byte_offset, UINT seek_from);
UINT _fx_file_rename(FX_MEDIA *media_ptr, CHAR *old_file_name, CHAR *new_file_name);
UINT _fx_file_seek(FX_FILE *file_ptr, ULONG byte_offset);
UINT _fx_file_truncate(FX_FILE *file_ptr, ULONG size);
UINT _fx_file_truncate_release(FX_FILE *file_ptr, ULONG size);
UINT _fx_file_write(FX_FILE *file_ptr, VOID *buffer_ptr, ULONG size);
UINT _fx_file_write_notify_set(FX_FILE *file_ptr, VOID (*file_write_notify)(FX_FILE *));
UINT _fx_file_extended_allocate(FX_FILE *file_ptr, ULONG64 size);
UINT _fx_file_extended_best_effort_allocate(FX_FILE *file_ptr, ULONG64 size, ULONG64 *actual_size_allocated);
UINT _fx_file_extended_relative_seek(FX_FILE *file_ptr, ULONG64 byte_offset, UINT seek_from);
UINT _fx_file_extended_seek(FX_FILE *file_ptr, ULONG64 byte_offset);
UINT _fx_file_extended_truncate(FX_FILE *file_ptr, ULONG64 size);
UINT _fx_file_extended_truncate_release(FX_FILE *file_ptr, ULONG64 size);
UINT _fxe_file_allocate(FX_FILE *file_ptr, ULONG size);
UINT _fxe_file_attributes_read(FX_MEDIA *media_ptr, CHAR *file_name, UINT *attributes_ptr);
UINT _fxe_file_attributes_set(FX_MEDIA *media_ptr, CHAR *file_name, UINT attributes);
UINT _fxe_file_best_effort_allocate(FX_FILE *file_ptr, ULONG size, ULONG *actual_size_allocated);
UINT _fxe_file_close(FX_FILE *file_ptr);
UINT _fxe_file_create(FX_MEDIA *media_ptr, CHAR *file_name);
UINT _fxe_file_date_time_set(FX_MEDIA *media_ptr, CHAR *file_name,
UINT year, UINT month, UINT day, UINT hour, UINT minute, UINT second);
UINT _fxe_file_delete(FX_MEDIA *media_ptr, CHAR *file_name);
UINT _fxe_file_open(FX_MEDIA *media_ptr, FX_FILE *file_ptr, CHAR *file_name,
UINT open_type, UINT file_control_block_size);
UINT _fxe_file_read(FX_FILE *file_ptr, VOID *buffer_ptr, ULONG request_size, ULONG *actual_size);
UINT _fxe_file_relative_seek(FX_FILE *file_ptr, ULONG byte_offset, UINT seek_from);
UINT _fxe_file_rename(FX_MEDIA *media_ptr, CHAR *old_file_name, CHAR *new_file_name);
UINT _fxe_file_seek(FX_FILE *file_ptr, ULONG byte_offset);
UINT _fxe_file_truncate(FX_FILE *file_ptr, ULONG size);
UINT _fxe_file_truncate_release(FX_FILE *file_ptr, ULONG size);
UINT _fxe_file_write(FX_FILE *file_ptr, VOID *buffer_ptr, ULONG size);
UINT _fxe_file_write_notify_set(FX_FILE *file_ptr, VOID (*file_write_notify)(FX_FILE *));
UINT _fxe_file_extended_allocate(FX_FILE *file_ptr, ULONG64 size);
UINT _fxe_file_extended_best_effort_allocate(FX_FILE *file_ptr, ULONG64 size, ULONG64 *actual_size_allocated);
UINT _fxe_file_extended_relative_seek(FX_FILE *file_ptr, ULONG64 byte_offset, UINT seek_from);
UINT _fxe_file_extended_seek(FX_FILE *file_ptr, ULONG64 byte_offset);
UINT _fxe_file_extended_truncate(FX_FILE *file_ptr, ULONG64 size);
UINT _fxe_file_extended_truncate_release(FX_FILE *file_ptr, ULONG64 size);
#endif

112
common/inc/fx_media.h Normal file
View File

@ -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 */
/** */
/** Media */
/** */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/* */
/* COMPONENT DEFINITION RELEASE */
/* */
/* fx_media.h PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This file defines the FileX Media component constants, data */
/* definitions, and external references. It is assumed that fx_api.h */
/* (and fx_port.h) have already been included. */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
#ifndef FX_MEDIA_H
#define FX_MEDIA_H
/* Define the external Media component function prototypes. */
UINT _fx_media_abort(FX_MEDIA *media_ptr);
UINT _fx_media_cache_invalidate(FX_MEDIA *media_ptr);
UINT _fx_media_check(FX_MEDIA *media_ptr, UCHAR *scratch_memory_ptr, ULONG scratch_memory_size, ULONG error_correction_option, ULONG *errors_detected);
UINT _fx_media_close(FX_MEDIA *media_ptr);
UINT _fx_media_flush(FX_MEDIA *media_ptr);
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);
UINT _fx_media_exFAT_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, ULONG64 hidden_sectors, ULONG64 total_sectors, UINT bytes_per_sector, UINT sectors_per_cluster, UINT volume_serial_number, UINT boundary_unit);
UINT _fx_media_open(FX_MEDIA *media_ptr, CHAR *media_name,
VOID (*media_driver)(FX_MEDIA *), VOID *driver_info_ptr,
VOID *memory_ptr, ULONG memory_size);
UINT _fx_media_read(FX_MEDIA *media_ptr, ULONG logical_sector, VOID *buffer_ptr);
UINT _fx_media_space_available(FX_MEDIA *media_ptr, ULONG *available_bytes_ptr);
UINT _fx_media_volume_get(FX_MEDIA *media_ptr, CHAR *volume_name, UINT volume_source);
UINT _fx_media_volume_get_extended(FX_MEDIA *media_ptr, CHAR *volume_name, UINT volume_name_buffer_length, UINT volume_source);
UINT _fx_media_volume_set(FX_MEDIA *media_ptr, CHAR *volume_name);
UINT _fx_media_write(FX_MEDIA *media_ptr, ULONG logical_sector, VOID *buffer_ptr);
UINT _fx_media_open_notify_set(FX_MEDIA *media_ptr, VOID (*media_open_notify)(FX_MEDIA *));
UINT _fx_media_close_notify_set(FX_MEDIA *media_ptr, VOID (*media_close_notify)(FX_MEDIA *));
UINT _fx_media_extended_space_available(FX_MEDIA *media_ptr, ULONG64 *available_bytes_ptr);
UINT _fxe_media_abort(FX_MEDIA *media_ptr);
UINT _fxe_media_cache_invalidate(FX_MEDIA *media_ptr);
UINT _fxe_media_check(FX_MEDIA *media_ptr, UCHAR *scratch_memory_ptr, ULONG scratch_memory_size, ULONG error_correction_option, ULONG *errors_detected);
UINT _fxe_media_close(FX_MEDIA *media_ptr);
UINT _fxe_media_flush(FX_MEDIA *media_ptr);
UINT _fxe_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);
UINT _fxe_media_exFAT_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, ULONG64 hidden_sectors, ULONG64 total_sectors, UINT bytes_per_sector, UINT sectors_per_cluster, UINT volume_serial_number, UINT boundary_unit);
UINT _fxe_media_open(FX_MEDIA *media_ptr, CHAR *media_name,
VOID (*media_driver)(FX_MEDIA *), VOID *driver_info_ptr,
VOID *memory_ptr, ULONG memory_size, UINT media_control_block_size);
UINT _fxe_media_read(FX_MEDIA *media_ptr, ULONG logical_sector, VOID *buffer_ptr);
UINT _fxe_media_space_available(FX_MEDIA *media_ptr, ULONG *available_bytes_ptr);
UINT _fxe_media_volume_get(FX_MEDIA *media_ptr, CHAR *volume_name, UINT volume_source);
UINT _fxe_media_volume_get_extended(FX_MEDIA *media_ptr, CHAR *volume_name, UINT volume_name_buffer_length, UINT volume_source);
UINT _fxe_media_volume_set(FX_MEDIA *media_ptr, CHAR *volume_name);
UINT _fxe_media_write(FX_MEDIA *media_ptr, ULONG logical_sector, VOID *buffer_ptr);
UINT _fxe_media_open_notify_set(FX_MEDIA *media_ptr, VOID (*media_open_notify)(FX_MEDIA *));
UINT _fxe_media_close_notify_set(FX_MEDIA *media_ptr, VOID (*media_close_notify)(FX_MEDIA *));
UINT _fxe_media_extended_space_available(FX_MEDIA *media_ptr, ULONG64 *available_bytes_ptr);
/* Define the internal Media component function prototypes. */
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 _fx_media_check_lost_cluster_check(FX_MEDIA *media_ptr, UCHAR *logical_fat, ULONG total_clusters, ULONG error_correction_option);
ULONG _fx_media_check_exFAT_lost_cluster_check(FX_MEDIA *media_ptr, UCHAR *logical_fat, ULONG total_clusters, ULONG error_correction_option);
UINT _fx_media_boot_info_extract(FX_MEDIA *media_ptr);
#endif

173
common/inc/fx_system.h Normal file
View File

@ -0,0 +1,173 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/* */
/* COMPONENT DEFINITION RELEASE */
/* */
/* fx_system.h PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This file defines the FileX system constants and global data */
/* definitions, including external references. It is assumed that */
/* fx_api.h (and fx_port.h) have already been included. */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
#ifndef FX_SYSTEM_H
#define FX_SYSTEM_H
/* Define System component constants. */
#define FX_TIMER_ID ((ULONG) 0x46585359)
/* Define the external System component function prototypes. */
VOID _fx_system_initialize(VOID);
UINT _fx_system_date_set(UINT year, UINT month, UINT day);
UINT _fx_system_time_set(UINT hour, UINT minute, UINT second);
UINT _fx_system_date_get(UINT *year, UINT *month, UINT *day);
UINT _fx_system_time_get(UINT *hour, UINT *minute, UINT *second);
VOID _fx_system_timer_entry(ULONG id);
UINT _fxe_system_date_set(UINT year, UINT month, UINT day);
UINT _fxe_system_time_set(UINT hour, UINT minute, UINT second);
UINT _fxe_system_date_get(UINT *year, UINT *month, UINT *day);
UINT _fxe_system_time_get(UINT *hour, UINT *minute, UINT *second);
/* System Component data declarations follow. */
/* Determine if the initialization function of this component is including
this file. If so, make the data definitions really happen. Otherwise,
make them extern so other functions in the component can access them. */
#ifdef FX_SYSTEM_INIT
#define SYSTEM_DECLARE
#else
#define SYSTEM_DECLARE extern
#endif
/* Define the head pointer of the opened media list. */
SYSTEM_DECLARE FX_MEDIA *_fx_system_media_opened_ptr;
/* Define the variable that holds the number of open media. */
SYSTEM_DECLARE ULONG _fx_system_media_opened_count;
/* Define the system date variable. */
SYSTEM_DECLARE UINT _fx_system_date;
/* Define the system time variable. */
SYSTEM_DECLARE UINT _fx_system_time;
/* Define the variable that holds the maximum size of the sector cache. */
SYSTEM_DECLARE ULONG _fx_system_media_max_sector_cache;
/* Define the variable that holds the maximum size of the FAT cache. */
SYSTEM_DECLARE ULONG _fx_system_media_max_fat_cache;
/* Define the global FileX build options variables. These variables contain a bit
map representing how the FileX library was built. The following are the bit
field definitions:
_fx_system_build_options_1:
Bit(s) Meaning
31-24 FX_MAX_LONG_NAME_LEN
23-16 FX_MAX_LAST_NAME_LEN
15-11 Reserved
10 FX_NO_TIMER defined
9 FX_SINGLE_THREAD defined
8 FX_DONT_UPDATE_OPEN_FILES defined
7 FX_MEDIA_DISABLE_SEARCH_CACHE defined
6 FX_MEDIA_STATISTICS_DISABLE defined
5 Reserved
4 FX_SINGLE_OPEN_LEGACY defined
3 FX_RENAME_PATH_INHERIT defined
2 FX_NO_LOCAL_PATH defined
1 FX_FAULT_TOLERANT_DATA defined
0 FX_FAULT_TOLERANT defined
_fx_system_build_options_2:
Bit(s) Meaning
31-16 FX_MAX_SECTOR_CACHE
15-8 FX_FAT_MAP_SIZE
7-0 FX_MAX_FAT_CACHE
_fx_system_build_options_3:
Bit(s) Meaning
31-24 Reserved
23-16 FX_UPDATE_RATE_IN_SECONDS
15-0 FX_UPDATE_RATE_IN_TICKS
Note that values greater than the value that can be represented in the build options
bit field are represented as all ones in the bit field. For example, if FX_MAX_LONG_NAME_LEN
is 256, the value in the bits 31-24 of _fx_system_build_options_1 is 0xFF, which is 255
decimal. */
SYSTEM_DECLARE ULONG _fx_system_build_options_1;
SYSTEM_DECLARE ULONG _fx_system_build_options_2;
SYSTEM_DECLARE ULONG _fx_system_build_options_3;
/* Define system timer control block. If accurate date/time stamps on
files is not needed, the define FX_NO_TIMER should be used when
compiling fx_system_initialize.c to eliminate the FileX timer. */
#ifndef FX_NO_TIMER
SYSTEM_DECLARE TX_TIMER _fx_system_timer;
#endif
#endif

108
common/inc/fx_unicode.h Normal file
View File

@ -0,0 +1,108 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/** Unicode */
/** */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/* */
/* COMPONENT DEFINITION RELEASE */
/* */
/* fx_unicode.h PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This file defines the FileX Unicode component constants, data */
/* definitions, and external references. It is assumed that fx_api.h */
/* (and fx_port.h) have already been included. */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
#ifndef FX_UNICODE_H
#define FX_UNICODE_H
/* Define external data for the Unicode component. */
extern UCHAR _fx_unicode_temp_long_file_name[FX_MAX_LONG_NAME_LEN];
extern UCHAR _fx_unicode_search_name[FX_MAX_LONG_NAME_LEN * 2];
/* Define the external Unicode component function prototypes. */
UINT _fx_unicode_directory_create(FX_MEDIA *media_ptr, UCHAR *source_unicode_name, ULONG source_unicode_length,
CHAR *short_name);
UINT _fx_unicode_directory_rename(FX_MEDIA *media_ptr, UCHAR *old_unicode_name, ULONG old_unicode_length,
UCHAR *new_unicode_name, ULONG new_unicode_length, CHAR *new_short_name);
UINT _fx_unicode_file_create(FX_MEDIA *media_ptr, UCHAR *source_unicode_name, ULONG source_unicode_length,
CHAR *short_name);
ULONG _fx_unicode_length_get(UCHAR *unicode_name);
ULONG _fx_unicode_length_get_extended(UCHAR *unicode_name, UINT buffer_length);
UINT _fx_unicode_name_get(FX_MEDIA *media_ptr, CHAR *source_short_name,
UCHAR *destination_unicode_name, ULONG *destination_unicode_length);
UINT _fx_unicode_name_get_extended(FX_MEDIA *media_ptr, CHAR *source_short_name,
UCHAR *destination_unicode_name, ULONG *destination_unicode_length, ULONG unicode_name_buffer_length);
UINT _fx_unicode_file_rename(FX_MEDIA *media_ptr, UCHAR *old_unicode_name, ULONG old_unicode_length,
UCHAR *new_unicode_name, ULONG new_unicode_length, CHAR *new_short_name);
UINT _fx_unicode_short_name_get(FX_MEDIA *media_ptr, UCHAR *source_unicode_name, ULONG source_unicode_length,
CHAR *destination_short_name);
UINT _fx_unicode_short_name_get_extended(FX_MEDIA *media_ptr, UCHAR *source_unicode_name, ULONG source_unicode_length,
CHAR *destination_short_name, ULONG short_name_buffer_length);
UINT _fxe_unicode_directory_create(FX_MEDIA *media_ptr, UCHAR *source_unicode_name, ULONG source_unicode_length,
CHAR *short_name);
UINT _fxe_unicode_directory_rename(FX_MEDIA *media_ptr, UCHAR *old_unicode_name, ULONG old_unicode_length,
UCHAR *new_unicode_name, ULONG new_unicode_length, CHAR *new_short_name);
UINT _fxe_unicode_file_create(FX_MEDIA *media_ptr, UCHAR *source_unicode_name, ULONG source_unicode_length,
CHAR *short_name);
UINT _fxe_unicode_file_rename(FX_MEDIA *media_ptr, UCHAR *old_unicode_name, ULONG old_unicode_length,
UCHAR *new_unicode_name, ULONG new_unicode_length, CHAR *new_short_name);
UINT _fxe_unicode_name_get(FX_MEDIA *media_ptr, CHAR *source_short_name,
UCHAR *destination_unicode_name, ULONG *destination_unicode_length);
UINT _fxe_unicode_name_get_extended(FX_MEDIA *media_ptr, CHAR *source_short_name,
UCHAR *destination_unicode_name, ULONG *destination_unicode_length, ULONG unicode_name_buffer_length);
UINT _fxe_unicode_short_name_get(FX_MEDIA *media_ptr, UCHAR *source_unicode_name, ULONG source_unicode_length,
CHAR *destination_short_name);
UINT _fxe_unicode_short_name_get_extended(FX_MEDIA *media_ptr, UCHAR *source_unicode_name, ULONG source_unicode_length,
CHAR *destination_short_name, ULONG short_name_buffer_length);
/* Define the internal Unicode component function prototypes. */
UINT _fx_unicode_directory_search(FX_MEDIA *media_ptr, FX_DIR_ENTRY *entry_ptr,
UCHAR *short_name, ULONG short_name_buffer_length,
UCHAR *unicode_name, ULONG *unicode_name_length, ULONG unicode_name_buffer_length);
UINT _fx_unicode_directory_entry_read(FX_MEDIA *media_ptr, FX_DIR_ENTRY *source_dir,
ULONG *entry_ptr, FX_DIR_ENTRY *destination_ptr,
UCHAR *unicode_name, ULONG *unicode_size);
UINT _fx_unicode_directory_entry_change(FX_MEDIA *media_ptr, FX_DIR_ENTRY *entry_ptr, UCHAR *unicode_name, ULONG unicode_name_length);
#endif

179
common/inc/fx_user_sample.h Normal file
View File

@ -0,0 +1,179 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/** User Specific */
/** */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/* */
/* PORT SPECIFIC C INFORMATION RELEASE */
/* */
/* fx_user.h PORTABLE C */
/* 6.0 */
/* */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This file contains user defines for configuring FileX in specific */
/* ways. This file will have an effect only if the application and */
/* FileX library are built with FX_INCLUDE_USER_DEFINE_FILE defined. */
/* Note that all the defines in this file may also be made on the */
/* command line when building FileX library and application objects. */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
#ifndef FX_USER_H
#define FX_USER_H
/* Define various build options for the FileX port. The application should either make changes
here by commenting or un-commenting the conditional compilation defined OR supply the defines
though the compiler's equivalent of the -D option. */
/* Override various options with default values already assigned in fx_api.h or fx_port.h. Please
also refer to fx_port.h for descriptions on each of these options. */
/* Defines the maximum size of long file names supported by FileX. The default value is 33. The
minimum value is 13 and the maximum value is 256. */
/*#define FX_MAX_LONG_NAME_LEN 256 */
/*#define FX_MAX_LAST_NAME_LEN 256 */ /* Must be as large or larger than FX_MAX_LONG_NAME_LEN */
/* Defines the maximum number of logical sectors that can be cached by FileX. The cache memory
supplied to FileX at fx_media_open determines how many sectors can actually be cached. */
/*#define FX_MAX_SECTOR_CACHE 256 */ /* Minimum value is 2, all other values must be power of 2. */
/* Defines the size in bytes of the bit map used to update the secondary FAT sectors. The larger the value the
less unnecessary secondary FAT sector writes. */
/*#define FX_FAT_MAP_SIZE 128 */ /* Minimum value is 1, no maximum value. */
/* Defines the number of entries in the FAT cache. */
/*#define FX_MAX_FAT_CACHE 16 */ /* Minimum value is 8, all values must be a power of 2. */
/* Defines the number of seconds the time parameters are updated in FileX. */
/*#define FX_UPDATE_RATE_IN_SECONDS 10 */
/* Defines the number of ThreadX timer ticks required to achieve the update rate specified by
FX_UPDATE_RATE_IN_SECONDS defined previously. By default, the ThreadX timer tick is 10ms,
so the default value for this constant is 1000. */
/*#define FX_UPDATE_RATE_IN_TICKS 1000 */
/* Defined, FileX is built without update to the time parameters. */
/*#define FX_NO_TIMER */
/* Defined, FileX is running in a single-threaded environment and does not need thread
protection. */
/*#define FX_SINGLE_THREAD */
/* Defined, FileX does not update already opened files. */
/*#define FX_DONT_UPDATE_OPEN_FILES */
/* Defined, the file search cache optimization is disabled. */
/*#define FX_MEDIA_DISABLE_SEARCH_CACHE */
/* Defined, the direct read sector update of cache is disabled. */
/*#define FX_DISABLE_DIRECT_DATA_READ_CACHE_FILL */
/* Defined, gathering of media statistics is disabled. */
/*#define FX_MEDIA_STATISTICS_DISABLE */
/* Defined, legacy single open logic for the same file is enabled. */
/*#define FX_SINGLE_OPEN_LEGACY */
/* Defined, renaming inherits path information. */
/*#define FX_RENAME_PATH_INHERIT */
/* Defined, local path logic is disabled. */
/*#define FX_NO_LOCAL_PATH */
/* Defined, FileX is able to access exFAT file system. */
/* #define FX_ENABLE_EXFAT */
/* Defined, data sector write requests are flushed immediately to the driver. */
/*#define FX_FAULT_TOLERANT_DATA */
/* Defined, system sector write requests (including FAT and directory entry requests)
are flushed immediately to the driver. */
/*#define FX_FAULT_TOLERANT */
/* Defined, enables 64-bits sector addresses used in I/O driver. */
/*#define FX_DRIVER_USE_64BIT_LBA */
/* Defined, enables FileX fault tolerant service. */
/*#define FX_ENABLE_FAULT_TOLERANT */
/* Define byte offset in boot sector where the cluster number of the Fault Tolerant Log file is.
Note that this field (byte 116 to 119) is marked as reserved by FAT 12/16/32/exFAT specification. */
/*#define FX_FAULT_TOLERANT_BOOT_INDEX 116 */
#endif

119
common/inc/fx_utility.h Normal file
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 */
/** */
/** Utility */
/** */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/* */
/* COMPONENT DEFINITION RELEASE */
/* */
/* fx_utility.h PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This file defines the FileX Utility component constants, data */
/* definitions, and external references. It is assumed that fx_api.h */
/* (and fx_port.h) have already been included. */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
#ifndef FX_UTILITY_H
#define FX_UTILITY_H
/* Define the internal Utility component function prototypes. */
UINT _fx_utility_16_unsigned_read(UCHAR *source_ptr);
VOID _fx_utility_16_unsigned_write(UCHAR *dest_ptr, UINT value);
ULONG _fx_utility_32_unsigned_read(UCHAR *source_ptr);
VOID _fx_utility_32_unsigned_write(UCHAR *dest_ptr, ULONG value);
ULONG64 _fx_utility_64_unsigned_read(UCHAR *source_ptr);
VOID _fx_utility_64_unsigned_write(UCHAR *dest_ptr, ULONG64 value);
VOID _fx_utility_memory_copy(UCHAR *source_ptr, UCHAR *dest_ptr, ULONG size);
VOID _fx_utility_memory_set(UCHAR *dest_ptr, UCHAR value, ULONG size);
FX_CACHED_SECTOR
*_fx_utility_logical_sector_cache_entry_read(FX_MEDIA *media_ptr, ULONG64 logical_sector, FX_CACHED_SECTOR **previous_cache_entry);
UINT _fx_utility_logical_sector_read(FX_MEDIA *media_ptr, ULONG64 logical_sector,
VOID *buffer_ptr, ULONG sectors, UCHAR sector_type);
UINT _fx_utility_logical_sector_write(FX_MEDIA *media_ptr, ULONG64 logical_sector,
VOID *buffer_ptr, ULONG sectors, UCHAR sector_type);
UINT _fx_utility_logical_sector_flush(FX_MEDIA *media_ptr, ULONG64 starting_sector, ULONG64 sectors, UINT invalidate);
UINT _fx_utility_FAT_entry_read(FX_MEDIA *media_ptr, ULONG cluster, ULONG *entry_ptr);
UINT _fx_utility_FAT_entry_write(FX_MEDIA *media_ptr, ULONG cluster, ULONG next_cluster);
UINT _fx_utility_FAT_flush(FX_MEDIA *media_ptr);
UINT _fx_utility_FAT_map_flush(FX_MEDIA *media_ptr);
ULONG _fx_utility_FAT_sector_get(FX_MEDIA *media_ptr, ULONG cluster);
UINT _fx_utility_string_length_get(CHAR *string, UINT max_length);
#ifdef FX_ENABLE_EXFAT
/* Define the exFAT Utility function prototypes. */
UINT _fx_utility_exFAT_cluster_free(FX_MEDIA *media_ptr, UCHAR *work_ptr);
UINT _fx_utility_exFAT_geometry_check(FX_MEDIA *media_ptr, UCHAR *sector_buffer);
UINT _fx_utility_exFAT_system_area_checksum_verify(FX_MEDIA_PTR media_ptr,
UCHAR *sector_buffer, ULONG boot_sector_offset,
ULONG *calculated_checksum);
VOID _fx_utility_exFAT_size_calculate(ULONG boundary_unit, ULONG64 size_in_sectors, ULONG sectors_per_cluster,
ULONG *sectors_per_fat_ptr, ULONG *fat_offset_ptr, ULONG *cluster_heap_offset_ptr);
UINT _fx_utility_exFAT_system_area_format(FX_MEDIA *media_ptr, ULONG boundary_unit,
ULONG *system_area_checksum_ptr, UCHAR *memory_ptr, UINT memory_size);
UINT _fx_utility_exFAT_system_sector_write(FX_MEDIA *media_ptr, UCHAR *data_buffer, ULONG64 logical_sector,
ULONG sector_count, ULONG sector_type);
UINT _fx_utility_exFAT_system_area_checksum_write(FX_MEDIA *media_ptr, UCHAR *sector_buffer,
ULONG *system_area_checksum_ptr);
/* Define the exFAT utility function prototypes. */
UINT _fx_utility_exFAT_bitmap_start_sector_get(FX_MEDIA *media_ptr, ULONG *start_sector);
UINT _fx_utility_exFAT_bitmap_cache_update(FX_MEDIA *media_ptr, ULONG cluster);
UINT _fx_utility_exFAT_bitmap_flush(FX_MEDIA *media_ptr);
UINT _fx_utility_exFAT_bitmap_initialize(FX_MEDIA *media_ptr);
UINT _fx_utility_exFAT_bitmap_cache_prepare(FX_MEDIA *media_ptr, ULONG cluster);
UINT _fx_utility_exFAT_cluster_state_get(FX_MEDIA *media_ptr, ULONG cluster, UCHAR *cluster_state);
UINT _fx_utility_exFAT_cluster_state_set(FX_MEDIA *media_ptr, ULONG cluster, UCHAR new_cluster_state);
UINT _fx_utility_exFAT_bitmap_free_cluster_find(FX_MEDIA *media_ptr, ULONG start, ULONG *free_cluster);
USHORT _fx_utility_exFAT_upcase_get(USHORT character);
USHORT _fx_utility_exFAT_name_hash_get(CHAR *name);
USHORT _fx_utility_exFAT_unicode_name_hash_get(CHAR *unicode_name, ULONG unicode_length);
USHORT _fx_utility_exFAT_upcase_get(USHORT character);
UINT _fx_utility_absolute_path_get(CHAR *base_path, CHAR *new_path, CHAR *absolute_path);
UINT _fx_utility_token_length_get(CHAR *path);
UINT _fx_utility_exFAT_allocate_new_cluster(FX_MEDIA *media_ptr, FX_DIR_ENTRY *directory_ptr, ULONG *last_cluster, ULONG *cluster);
#endif /* FX_ENABLE_EXFAT */
#endif

View File

@ -0,0 +1,154 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}

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 */
/** */
/** 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.0 */
/* 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 */
/* */
/**************************************************************************/
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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(media_ptr, &dir_entry, UPDATE_FILE);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &dir_entry);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
#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);
}

View File

@ -0,0 +1,902 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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_exFAT_bitmap_free_cluster_find */
/* Find exFAT free cluster */
/* _fx_utility_exFAT_cluster_state_set Set cluster state */
/* _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 */
/* */
/**************************************************************************/
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;
#ifdef FX_ENABLE_EXFAT
ULONG64 dir_size;
#endif /* FX_ENABLE_EXFAT */
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_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
if (((dir_entry.fx_dir_entry_name[0] == '.') && (dir_entry.fx_dir_entry_name[1] == 0)) ||
((dir_entry.fx_dir_entry_name[0] == '.') && (dir_entry.fx_dir_entry_name[1] == '.') && (dir_entry.fx_dir_entry_name[2] == 0)))
{
/* Release media protection. */
FX_UNPROTECT
/* We don't need '.' or '..' dirs for exFAT. */
return(FX_ALREADY_CREATED);
}
}
/* Save the directory entry size. */
dir_size = search_directory.fx_dir_entry_file_size;
#endif /* FX_ENABLE_EXFAT */
#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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Find free cluster from exFAT media. */
status = _fx_utility_exFAT_bitmap_free_cluster_find(media_ptr,
media_ptr -> fx_media_cluster_search_start,
&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 bad status. */
return(status);
}
}
else
{
#endif /* FX_ENABLE_EXFAT */
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);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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;
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
dir_entry.fx_dir_entry_file_size =
media_ptr -> fx_media_sectors_per_cluster * media_ptr -> fx_media_bytes_per_sector;
dir_entry.fx_dir_entry_available_file_size = dir_entry.fx_dir_entry_file_size;
/* Don't use FAT by default. */
dir_entry.fx_dir_entry_dont_use_fat = (CHAR)((INT)((search_directory.fx_dir_entry_dont_use_fat & 1) << 1) | 1);
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* Set file size to 0. */
dir_entry.fx_dir_entry_file_size = 0;
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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--;
}
}
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* 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;
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);
}
/* Mark the cluster as used. */
status = _fx_utility_exFAT_cluster_state_set(media_ptr, FAT_index, FX_EXFAT_BITMAP_CLUSTER_OCCUPIED);
/* 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);
}
/* 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;
}
if (search_directory.fx_dir_entry_name[0])
{
/* Not root directory. */
/* Copy the date and time from the actual sub-directory. */
search_directory.fx_dir_entry_time = dir_entry.fx_dir_entry_time;
search_directory.fx_dir_entry_date = dir_entry.fx_dir_entry_date;
/* Check if the directory size has changed. */
if (search_directory.fx_dir_entry_file_size == dir_size)
{
/* Not changed, we need only update time stamps. */
status = _fx_directory_exFAT_entry_write(media_ptr, &search_directory, UPDATE_FILE);
}
else
{
/* Directory size changed, update time stamps and the stream size. */
status = _fx_directory_exFAT_entry_write(media_ptr, &search_directory, UPDATE_STREAM);
}
/* 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);
}
}
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* 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_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
#ifdef FX_FAULT_TOLERANT
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
#endif
/* Now write out the new directory entry. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(media_ptr, &dir_entry, UPDATE_FULL);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &dir_entry);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
#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);
}

View File

@ -0,0 +1,104 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}

View File

@ -0,0 +1,118 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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)
{
/* 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);
}
else
{
/* Buffer is too small. Return error. */
return(FX_BUFFER_ERROR);
}
}
else
{
/* Set zero-length string. */
return_path_name_buffer[0] = '\0';
}
}
/* Return successful status. */
return(status);
}

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"
#ifdef FX_ENABLE_EXFAT
#include "fx_directory_exFAT.h"
#endif /* FX_ENABLE_EXFAT */
#ifndef FX_NO_LOCAL_PATH
FX_LOCAL_PATH_SETUP
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_default_set PORTABLE C */
/* 6.0 */
/* 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 */
/* */
/**************************************************************************/
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;
#ifdef FX_ENABLE_EXFAT
CHAR abs_str[FX_MAXIMUM_PATH]; /* TODO: possible will be better to use dynamic memory for exFAT only. */
#endif /* FX_ENABLE_EXFAT */
#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]);
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Get the absolute path. */
if (_fx_utility_absolute_path_get(path_string_ptr, new_path_name, abs_str) == FX_SUCCESS)
{
new_path_name = &(abs_str[0]);
}
else
{
/* Release media protection. */
FX_UNPROTECT
/* Invalid Path - Return the error code. */
return(FX_INVALID_PATH);
}
}
#endif /* FX_ENABLE_EXFAT */
/* 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. */
#ifdef FX_ENABLE_EXFAT
if ((!dir_entry.fx_dir_entry_cluster) && (media_ptr -> fx_media_FAT_type != FX_exFAT))
#else
if (!dir_entry.fx_dir_entry_cluster)
#endif
{
/* 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);
}

View File

@ -0,0 +1,587 @@
/**************************************************************************/
/* */
/* 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_EXFAT
#include "fx_directory_exFAT.h"
#endif /* FX_ENABLE_EXFAT */
#ifdef FX_ENABLE_FAULT_TOLERANT
#include "fx_fault_tolerant.h"
#endif /* FX_ENABLE_FAULT_TOLERANT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_delete PORTABLE C */
/* 6.0 */
/* 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_exFAT_cluster_state_set Set cluster state */
/* _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 */
/* */
/**************************************************************************/
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;
#ifdef FX_ENABLE_EXFAT
ULONG clusters_count;
ULONG bytes_per_cluster;
#endif /* FX_ENABLE_EXFAT */
#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;
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
directory_size = (ULONG)search_directory.fx_dir_entry_file_size / FX_DIR_ENTRY_SIZE;
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* 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;
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* Make sure the new name is not in the current directory. */
#ifdef FX_ENABLE_EXFAT
if (directory_size > 0)
{
/* exFAT directories do not record '.' and '..' directories. */
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
i = 0;
}
else
{
i = 2;
}
#else
/* The first two entries are skipped because they are just part of the sub-directory. */
i = 2;
#endif /* FX_ENABLE_EXFAT */
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. */
#ifdef FX_ENABLE_EXFAT
if (search_entry.fx_dir_entry_type == FX_EXFAT_DIR_ENTRY_TYPE_END_MARKER)
#else
if (search_entry.fx_dir_entry_name[0] == FX_DIR_ENTRY_DONE)
#endif /* FX_ENABLE_EXFAT */
{
break;
}
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Skip '.' and '..' folders if exists. */
if ((i == 1) && (search_entry.fx_dir_entry_type == FX_EXFAT_DIR_ENTRY_TYPE_FILE_DIRECTORY) &&
(search_entry.fx_dir_entry_name[0] == '.') &&
(search_entry.fx_dir_entry_name[1] == 0))
{
continue;
}
if ((i == 2) && (search_entry.fx_dir_entry_type == FX_EXFAT_DIR_ENTRY_TYPE_FILE_DIRECTORY) &&
(search_entry.fx_dir_entry_name[0] == '.') && (search_entry.fx_dir_entry_name[1] == '.') &&
(search_entry.fx_dir_entry_name[2] == 0))
{
continue;
}
}
#endif /* FX_ENABLE_EXFAT */
/* Determine if this is an empty entry. */
#ifdef FX_ENABLE_EXFAT
if (search_entry.fx_dir_entry_type != FX_EXFAT_DIR_ENTRY_TYPE_FREE)
#else
if ((UCHAR)search_entry.fx_dir_entry_name[0] != (UCHAR)FX_DIR_ENTRY_FREE)
#endif /* FX_ENABLE_EXFAT */
{
#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);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(media_ptr, &dir_entry, UPDATE_DELETE);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &dir_entry);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
#ifdef FX_ENABLE_EXFAT
bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster);
i = 0;
clusters_count = (ULONG)((search_directory.fx_dir_entry_file_size + bytes_per_cluster - 1) / bytes_per_cluster - 1);
#endif /* FX_ENABLE_EXFAT */
/* 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++;
#ifdef FX_ENABLE_EXFAT
/* Read the next FAT entry. */
if (search_directory.fx_dir_entry_dont_use_fat & 1)
{
/* Check for file size range */
if (i - 1 >= clusters_count)
{
next_cluster = FX_LAST_CLUSTER_exFAT;
}
else
{
next_cluster = cluster + 1;
}
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
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. */
#ifdef FX_ENABLE_EXFAT
if (!(search_directory.fx_dir_entry_dont_use_fat & 1))
{
#endif /* FX_ENABLE_EXFAT */
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);
}
#ifdef FX_ENABLE_EXFAT
}
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Mark the cluster as free. */
status = _fx_utility_exFAT_cluster_state_set(media_ptr, cluster, FX_EXFAT_BITMAP_CLUSTER_FREE);
/* 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);
}
}
#endif /* FX_ENABLE_EXFAT */
/* 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);
}

View File

@ -0,0 +1,784 @@
/**************************************************************************/
/* */
/* 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"
#ifdef FX_ENABLE_EXFAT
#include "fx_directory_exFAT.h"
#endif /* FX_ENABLE_EXFAT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_entry_read PORTABLE C */
/* 6.0 */
/* 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_directory_exFAT_entry_read Read exFAT entries */
/* _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 */
/* */
/**************************************************************************/
#ifdef FX_ENABLE_EXFAT
UINT _fx_directory_entry_read_FAT(FX_MEDIA *media_ptr, FX_DIR_ENTRY *source_dir,
ULONG *entry_ptr, FX_DIR_ENTRY *destination_ptr)
#else
UINT _fx_directory_entry_read(FX_MEDIA *media_ptr, FX_DIR_ENTRY *source_dir,
ULONG *entry_ptr, FX_DIR_ENTRY *destination_ptr)
#endif /* FX_ENABLE_EXFAT */
{
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. */
#ifdef FX_ENABLE_EXFAT
if ((source_dir) || (media_ptr -> fx_media_FAT_type == FX_FAT32))
#else
if ((source_dir) || (media_ptr -> fx_media_32_bit_FAT))
#endif
{
/* 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;
}
#ifdef FX_ENABLE_EXFAT
destination_ptr -> fx_dir_entry_dont_use_fat = 0;
/* If a file whose first byte of long name is read, fx_dir_entry_short_name will not be empty. */
/* If a free dir_entry is obtained, fx_dir_entry_short_name[0] will not be assigned as 0 around Line 623 in this file. */
/* If there is only a free dir_entry without front long name dir_entries, fx_dir_entry_name[0] will be assigned by the loop around Line 568. */
if (((UCHAR)destination_ptr -> fx_dir_entry_name[0] == FX_DIR_ENTRY_FREE) && ((UCHAR)destination_ptr -> fx_dir_entry_short_name[0] == 0))
{
destination_ptr -> fx_dir_entry_type = FX_EXFAT_DIR_ENTRY_TYPE_FREE;
}
else if ((UCHAR)destination_ptr -> fx_dir_entry_name[0] == FX_DIR_ENTRY_DONE)
{
destination_ptr -> fx_dir_entry_type = FX_EXFAT_DIR_ENTRY_TYPE_END_MARKER;
}
else
{
destination_ptr -> fx_dir_entry_type = FX_EXFAT_DIR_ENTRY_TYPE_FILE_DIRECTORY;
}
#endif /* FX_ENABLE_EXFAT */
/* Return success to the caller. */
return(FX_SUCCESS);
}
#ifdef FX_ENABLE_EXFAT
UINT _fx_directory_entry_read_ex(FX_MEDIA *media_ptr, FX_DIR_ENTRY *source_dir,
ULONG *entry_ptr, FX_DIR_ENTRY *destination_ptr, UINT hash)
{
UINT status = FX_SUCCESS;
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status =
_fx_directory_exFAT_entry_read(
media_ptr, source_dir, entry_ptr, destination_ptr, hash, FX_FALSE, NULL, NULL);
}
else
{
status =
_fx_directory_entry_read_FAT(media_ptr, source_dir, entry_ptr, destination_ptr);
}
return(status);
}
UINT _fx_directory_entry_read(FX_MEDIA *media_ptr, FX_DIR_ENTRY *source_dir,
ULONG *entry_ptr, FX_DIR_ENTRY *destination_ptr)
{
return(_fx_directory_entry_read_ex(media_ptr, source_dir, entry_ptr, destination_ptr, 0));
}
#endif /* FX_ENABLE_EXFAT */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,716 @@
/**************************************************************************/
/* */
/* 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"
#ifdef FX_ENABLE_EXFAT
#include "fx_utility.h"
#include "fx_directory_exFAT.h"
#include "fx_directory.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_exFAT_entry_read PORTABLE C */
/* 6.0 */
/* 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 */
/* hash Hash value of the file name */
/* skip Skip reading file name */
/* unicode_name Destination for unicode name */
/* unicode_length Destination for unicode name */
/* length */
/* */
/* 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 USHORT from memory */
/* _fx_utility_32_unsigned_read Read a ULONG from memory */
/* _fx_utility_64_unsigned_read Read a ULONG64 from memory */
/* */
/* CALLED BY */
/* */
/* _fx_directory_entry_read */
/* _fx_directory_free_search */
/* _fx_directory_next_full_entry_find */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _fx_directory_exFAT_entry_read(FX_MEDIA *media_ptr, FX_DIR_ENTRY *source_dir,
ULONG *entry_ptr, FX_DIR_ENTRY *destination_ptr,
UINT hash, UINT skip, UCHAR *unicode_name, UINT *unicode_length)
{
UINT status = FX_SUCCESS;
UCHAR i;
UCHAR j;
ULONG cluster = 0, next_cluster = 0;
ULONG64 next_logical_sector;
UINT relative_cluster;
UINT relative_sector = 0;
ULONG64 logical_sector;
ULONG byte_offset;
ULONG bytes_per_cluster;
UCHAR *read_ptr;
UCHAR secondary_count;
UCHAR name_length = 0;
UCHAR name_pos = 0;
UCHAR copy_size = 0;
USHORT checksum = 0;
USHORT file_checksum;
ULONG date_time;
UCHAR dont_use_fat;
ULONG clusters_count = 0;
/* Calculate the byte offset of this directory entry. */
byte_offset = (*entry_ptr) * FX_DIR_ENTRY_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);
/* 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)
{
/* Yes, setup the starting cluster to that of the sub-directory. */
cluster = source_dir -> fx_dir_entry_cluster;
/* Save the cluster count for the directory entry. */
clusters_count = (ULONG)((source_dir -> fx_dir_entry_file_size + bytes_per_cluster - 1) / bytes_per_cluster - 1);
}
else
{
/* No, setup the starting cluster to the exFAT root directory cluster. */
cluster = media_ptr -> fx_media_root_cluster_32;
}
/* Loop to position to the appropriate cluster. */
for (i = 0;; i++)
{
/* 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 > FX_RESERVED_1_exFAT))
{
/* Send error message back to caller. */
return(FX_FILE_CORRUPT);
}
/* Read the next cluster. First check if FAT is used. */
if ((source_dir) && (source_dir -> fx_dir_entry_dont_use_fat & 1))
{
/* FAT is not used. Check for file size range. */
if (i >= clusters_count)
{
/* We are at the last cluster, set next cluster to LAST CLUSTER. */
next_cluster = FX_LAST_CLUSTER_exFAT;
}
else
{
/* The next cluster is just after the current cluster. */
next_cluster = cluster + 1;
}
}
else
{
/* FAT is used, call FAT read function to get 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);
}
}
/* Are we positioned to the appropriate cluster? */
if (i < relative_cluster)
{
cluster = next_cluster;
}
else
{
break;
}
}
/* At this point, the directory data sector needs to be read. */
logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG64)cluster - FX_FAT_ENTRY_START) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
relative_sector;
/* Determine if next sector is in next cluster or in next sector. */
if ((bytes_per_cluster - byte_offset) >= (ULONG)media_ptr -> fx_media_bytes_per_sector)
{
/* Move to the next logical sector. */
next_logical_sector = logical_sector + 1;
}
else
{
/* No, calculate the next logical sector. */
if ((next_cluster >= FX_FAT_ENTRY_START) && (next_cluster <= FX_RESERVED_1_exFAT))
{
next_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));
}
else
{
next_logical_sector = 0; /* No such sector possible. */
}
}
/* 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;
/* 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_next_log_sector = next_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;
/* Check if the directory entry type has InUse bit set, or if it is an end marker. */
if ((*read_ptr & FX_EXFAT_ENTRY_TYPE_IN_USE_MASK) || (*read_ptr == FX_EXFAT_DIR_ENTRY_TYPE_END_MARKER))
{
/* Set the directory entry type. */
destination_ptr -> fx_dir_entry_type = *read_ptr;
}
else
{
/* This is a free entry. */
destination_ptr -> fx_dir_entry_type = FX_EXFAT_DIR_ENTRY_TYPE_FREE;
}
/* Check if the entry is a file directory entry. */
if (destination_ptr -> fx_dir_entry_type != FX_EXFAT_DIR_ENTRY_TYPE_FILE_DIRECTORY)
{
/* The entry is not directory entry, check if we know the type. */
if ((destination_ptr -> fx_dir_entry_type == FX_EXFAT_DIR_ENTRY_TYPE_ALLOCATION_BITMAP) ||
(destination_ptr -> fx_dir_entry_type == FX_EXFAT_DIR_ENTRY_TYPE_UP_CASE_TABLE) ||
(destination_ptr -> fx_dir_entry_type == FX_EXFAT_DIR_ENTRY_TYPE_VOLUME_LABEL) ||
(destination_ptr -> fx_dir_entry_type == FX_EXFAT_DIR_ENTRY_TYPE_FREE) ||
(destination_ptr -> fx_dir_entry_type == FX_EXFAT_DIR_ENTRY_TYPE_END_MARKER))
{
/* Known critical primary or free, just skip it. */
return(FX_SUCCESS);
}
/* Check if the entry is unknown critical primary directory entry. */
if ((destination_ptr -> fx_dir_entry_type & (FX_EXFAT_ENTRY_TYPE_IMPORTANCE_MASK | FX_EXFAT_ENTRY_TYPE_CATEGORY_MASK)) == 0)
{
/* Yes, it is an unknown critical primary entry. Return error. */
return(FX_MEDIA_INVALID);
}
/* Just ignore. */
return(FX_SUCCESS);
}
/* Calculate checksum for file entry. */
for (j = 0; j < FX_DIR_ENTRY_SIZE; ++j)
{
/* Skip the checksum field. */
if ((j == 2) || (j == 3))
{
continue;
}
/* Calculate the checksum using the algorithm described in the specification. */
/* Right rotate the checksum by one bit position and add the data. */
checksum = (USHORT)(((checksum >> 1) | (checksum << 15)) + read_ptr[j]);
}
/* Read secondary count field. */
read_ptr++;
secondary_count = *read_ptr;
/* Validate the secondary count field. */
if (secondary_count < 2)
{
/* Something wrong, file entry should have at least 2 entries: stream and filename. */
return(FX_FILE_CORRUPT);
}
/* Save secondary count. */
destination_ptr -> fx_dir_entry_secondary_count = secondary_count;
/* exFAT has no short/long name concept, set long name present for compatibility. */
destination_ptr -> fx_dir_entry_long_name_present = 1;
/* Advance the pointer to the checksum field. */
read_ptr++;
/* Read checksum field. */
file_checksum = (USHORT)_fx_utility_16_unsigned_read(read_ptr);
read_ptr += 2;
/* Read FileAttributes field. */
destination_ptr -> fx_dir_entry_attributes = (UCHAR)_fx_utility_16_unsigned_read(read_ptr); /* The same order as FAT32 but more unused bits. */
/* Skip Reserved1. */
read_ptr += 4;
/* Read CreatedTimestamp field. */
date_time = _fx_utility_32_unsigned_read(read_ptr);
destination_ptr -> fx_dir_entry_created_time = date_time & 0xffff;
destination_ptr -> fx_dir_entry_created_date = date_time >> 16;
read_ptr += 4;
/* Read LastModifiedTimestamp. */
date_time = _fx_utility_32_unsigned_read(read_ptr);
destination_ptr -> fx_dir_entry_time = date_time & 0xffff;
destination_ptr -> fx_dir_entry_date = date_time >> 16;
read_ptr += 4;
/* Read LastAccessedTimestamp. */
date_time = _fx_utility_32_unsigned_read(read_ptr);
destination_ptr -> fx_dir_entry_last_accessed_date = date_time >> 16;
read_ptr += 4;
/* Read Create10msIncrement. */
destination_ptr -> fx_dir_entry_created_time_ms = *read_ptr;
read_ptr++;
/* LastModified10msIncrement field is currently ignored. */
read_ptr++;
/* CreateUtcOffset field is currently ignored. */
read_ptr++;
/* LastModifiedUtcOffset field is currently ignored. */
read_ptr++;
/* LastAccessedUtcOffset field is currently ignored. */
/* Process all the secondary directory entries. */
for (i = 0; i < secondary_count; ++i)
{
/* Determine if a new sector needs to be read. */
if (byte_offset + FX_DIR_ENTRY_SIZE >= media_ptr -> fx_media_bytes_per_sector)
{
/* 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. */
/* Read the next cluster. First check if FAT is used. */
if ((source_dir) && (source_dir -> fx_dir_entry_dont_use_fat & 1))
{
/* FAT is not used. Check for file size range. */
if (relative_cluster >= clusters_count)
{
/* We are at the last cluster, set next cluster to LAST CLUSTER. */
next_cluster = FX_LAST_CLUSTER_exFAT;
}
else
{
/* The next cluster is just after the current cluster. */
next_cluster = cluster + 1;
}
}
else
{
/* FAT is used, call FAT read function to get 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 > FX_RESERVED_1_exFAT))
{
/* 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) +
(((ULONG64)cluster - FX_FAT_ENTRY_START) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster));
}
/* 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;
}
/* Read sub entry. */
read_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
/* Calculate checksum for sub entry. */
for (j = 0; j < FX_DIR_ENTRY_SIZE; ++j)
{
/* Right rotate the checksum by one bit position and add the data. */
checksum = (USHORT)(((checksum >> 1) | (checksum << 15)) + read_ptr[j]);
}
/* Add the entry number to the next entry. */
(*entry_ptr)++;
/* Check if we are processing the first secondary directory entry. */
if (i == 0)
{
/* Make sure the directory entry type is stream extension. */
if (*read_ptr != FX_EXFAT_DIR_ENTRY_TYPE_STREAM_EXTENSION)
{
/* Something wrong, stream entry should be next to file entry. */
return(FX_FILE_CORRUPT);
}
/* Read stream entry. */
/* Advance the pointer to general secondary flags field. */
read_ptr++;
/* Read NoFatChain field. */
dont_use_fat = ((*read_ptr) >> 1) & 1; /* 0 bit - current */
/* Check if we have a parent directory. */
if (source_dir)
{
/* Save the dont_use_fat flag for parent directory. */
dont_use_fat = (UCHAR)(dont_use_fat | ((source_dir -> fx_dir_entry_dont_use_fat & 1) << 1)); /* 1st bit parent */
}
/* Put the dont_use_fat flag to the destination. */
destination_ptr -> fx_dir_entry_dont_use_fat = (CHAR)dont_use_fat;
/* Skip the reserved1 field. */
read_ptr += 2;
/* Read the name length field. */
name_length = *read_ptr;
/* Check if name_length is invalid. */
if (name_length == 0)
{
/* Name length should be at least 1. Return error. */
return(FX_FILE_CORRUPT);
}
/* Advance the pointer to the name hash field. */
read_ptr++;
/* Hash search */
if (skip || (hash && (hash != _fx_utility_16_unsigned_read(read_ptr))))
{
/* Wrong hash, skip filename. */
destination_ptr -> fx_dir_entry_type = FX_EXFAT_DIR_ENTRY_TYPE_STREAM_EXTENSION;
name_length = 0;
(*entry_ptr) += (ULONG)(secondary_count - 1);
/* Return success. */
return(FX_SUCCESS);
}
/* Skip name hash and reserved2. */
read_ptr += 4;
/* Read Valid Data Len. */
destination_ptr -> fx_dir_entry_file_size = _fx_utility_64_unsigned_read(read_ptr);
/* Skip ValidDataLen and reserved3. */
read_ptr += 12;
destination_ptr -> fx_dir_entry_cluster = _fx_utility_32_unsigned_read(read_ptr);
read_ptr += 4;
/* Read Data Len. */
destination_ptr -> fx_dir_entry_available_file_size = _fx_utility_64_unsigned_read(read_ptr);
/* Checks for corruption */
if (((destination_ptr -> fx_dir_entry_available_file_size == 0) &&
(destination_ptr -> fx_dir_entry_cluster != 0)) ||
((destination_ptr -> fx_dir_entry_available_file_size != 0) &&
(destination_ptr -> fx_dir_entry_cluster == 0)))
{
/* Return file corrupt error. */
return(FX_FILE_CORRUPT);
}
/* File System Specification Ver 3.00 */
if (destination_ptr -> fx_dir_entry_cluster == 0)
{
/* Don't use FAT by default. */
destination_ptr -> fx_dir_entry_dont_use_fat |= 1;
}
/* Check for directory restrictions. */
if ((destination_ptr -> fx_dir_entry_attributes & FX_DIRECTORY) &&
(destination_ptr -> fx_dir_entry_available_file_size != destination_ptr -> fx_dir_entry_file_size))
{
/* Return file corrupt error. */
return(FX_FILE_CORRUPT);
}
/* Check if the directory size exceed file system limits. */
if ((destination_ptr -> fx_dir_entry_attributes & FX_DIRECTORY) &&
(destination_ptr -> fx_dir_entry_available_file_size > FX_EXFAT_MAX_DIRECTORY_SIZE))
{
/* Return the no more space error. */
return(FX_NO_MORE_SPACE);
}
}
else
{
/* Check if the entry type is file name directory entry. */
if (*read_ptr == FX_EXFAT_DIR_ENTRY_TYPE_FILE_NAME)
{
/* Skip the entry type and flags field. */
read_ptr += 2;
/* There are 15 characters in one file name directory entry. */
if (name_length > 15)
{
/* Set copy size to the max size of one entry. */
copy_size = 15;
}
else
{
/* Set copy size to the acutal remaining length. */
copy_size = name_length;
}
/* Check if we are requested to return the unicode name. */
if (unicode_name)
{
/* Loop to copy the unicode file name. from the file name directory entry. */
for (j = 0; j < copy_size * 2; ++j)
{
/* Copy the unicode file name from the file name directory entry. */
unicode_name[name_pos * 2 + j] = *read_ptr++;
}
/* Revert the read pointer for later use. */
read_ptr -= copy_size * 2;
}
/* Loop to copy the non-unicode file name. */
for (j = 0; j < copy_size; ++j)
{
/* Copy and convert the file name from the file name directory entry. */
destination_ptr -> fx_dir_entry_name[name_pos++] = (CHAR)_fx_utility_16_unsigned_read(read_ptr);
read_ptr += 2;
}
/* Modify the name_length to indicate the remaining length. */
name_length = (UCHAR)(name_length - copy_size);
}
else if (((*read_ptr & (FX_EXFAT_ENTRY_TYPE_IN_USE_MASK | FX_EXFAT_ENTRY_TYPE_IMPORTANCE_MASK | FX_EXFAT_ENTRY_TYPE_CATEGORY_MASK)) ==
(FX_EXFAT_ENTRY_TYPE_IN_USE_MASK | FX_EXFAT_ENTRY_TYPE_CATEGORY_MASK)))
{
/* Unknown critical secondary, we can't work with this directory. */
return(FX_FILE_CORRUPT);
}
}
}
/* Terminate the entry name string. */
destination_ptr -> fx_dir_entry_name[name_pos] = 0;
/* Check if we are requested to return the unicode name. */
if (unicode_name)
{
/* Terminate the unicode name string. */
unicode_name[name_pos * 2] = 0;
unicode_name[name_pos * 2 + 1] = 0;
/* Check if we are requested to return the unicode name length. */
if (unicode_length)
{
/* Return the unicode name length. */
*unicode_length = name_pos;
}
}
/* Verify checksum. */
if (checksum != file_checksum)
{
/* Return corrupted file error. */
return(FX_FILE_CORRUPT);
}
/* Check if we have found all the file name directory entries. */
if (name_length != 0)
{
/* Return file corrupted error. */
return(FX_FILE_CORRUPT);
}
/* Return success. */
return(FX_SUCCESS);
}
#endif

View File

@ -0,0 +1,100 @@
/**************************************************************************/
/* */
/* 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"
#ifdef FX_ENABLE_EXFAT
#include "fx_directory.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_exFAT_entry_write PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function writes the supplied directory entry to the specified */
/* logical sector and offset. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* entry_ptr Pointer to directory entry */
/* update_level Update level for entry write */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_directory_exFAT_unicode_entry_write */
/* */
/* CALLED BY */
/* */
/* fx_directory_attributes_set */
/* fx_directory_create */
/* fx_directory_delete */
/* fx_directory_exFAT_unicode_entry_write */
/* fx_directory_rename */
/* fx_file_allocate */
/* fx_file_attributes_set */
/* fx_file_best_effort_allocate */
/* fx_file_close */
/* fx_file_create */
/* fx_file_date_time_set */
/* fx_file_delete */
/* fx_file_rename */
/* fx_file_truncate_release */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _fx_directory_exFAT_entry_write(FX_MEDIA *media_ptr, FX_DIR_ENTRY *entry_ptr, UCHAR update_level)
{
UINT status;
/* Call the unicode director entry write function. */
status = _fx_directory_exFAT_unicode_entry_write(media_ptr, entry_ptr, update_level, NULL, 0);
/* Return completion status. */
return(status);
}
#endif

View File

@ -0,0 +1,507 @@
/**************************************************************************/
/* */
/* 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"
#ifdef FX_ENABLE_EXFAT
#include "fx_directory_exFAT.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_free_search PORTABLE C */
/* 6.0 */
/* 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_exFAT_entry_read Read entries from directory */
/* _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_exFAT_cluster_state_set Set cluster state in bitmap */
/* _fx_utility_exFAT_bitmap_flush Flush written exFAT bitmap */
/* _fx_utility_exFAT_allocate_new_cluster */
/* Allocate new cluster */
/* */
/* CALLED BY */
/* */
/* FileX System Functions */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _fx_directory_exFAT_free_search(FX_MEDIA *media_ptr, FX_DIR_ENTRY *directory_ptr, FX_DIR_ENTRY *entry_ptr)
{
ULONG i;
UCHAR *work_ptr;
UINT status, total_entries;
ULONG64 entry_sector = 0;
ULONG64 entry_next_sector = 0;
ULONG entry_offset = 0;
ULONG cluster;
ULONG last_cluster;
ULONG directory_entries;
ULONG64 logical_sector;
FX_DIR_ENTRY *search_dir_ptr;
ULONG free_entry_start;
UINT sectors;
FX_CACHED_SECTOR *cache_entry_ptr;
ULONG bytes_per_cluster;
/* Get name length. */
i = _fx_utility_string_length_get(entry_ptr -> fx_dir_entry_name, FX_MAX_EX_FAT_NAME_LEN);
/* Check if name is valid. */
if (entry_ptr -> fx_dir_entry_name[i] != 0)
{
/* Invalid name, return error. */
return(FX_INVALID_NAME);
}
/* Determine the total entries. */
total_entries = 2 + (i + 14) / 15;
/* 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. */
directory_entries = (ULONG)directory_ptr -> fx_dir_entry_file_size / FX_DIR_ENTRY_SIZE;
/* Point the search directory pointer to this entry. */
search_dir_ptr = directory_ptr;
}
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;
/* Clear dont_use_fat for root directory. */
directory_ptr -> fx_dir_entry_dont_use_fat = 0;
}
/* Loop through entries in the search directory. Yes, this is a
linear search! */
i = 0;
free_entry_start = directory_entries;
if (directory_entries > 0)
{
do
{
/* Read an entry from the directory. */
status =
_fx_directory_exFAT_entry_read(media_ptr,
search_dir_ptr, &i, entry_ptr, 0, FX_TRUE, NULL, NULL);
/* Check for error status. */
if (status != FX_SUCCESS)
{
return(status);
}
/* Determine if this is an empty entry. */
if ((entry_ptr -> fx_dir_entry_type == FX_EXFAT_DIR_ENTRY_TYPE_FREE) ||
(entry_ptr -> fx_dir_entry_type == FX_EXFAT_DIR_ENTRY_TYPE_END_MARKER))
{
/* 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 = i;
entry_sector = entry_ptr -> fx_dir_entry_log_sector;
entry_next_sector = entry_ptr -> fx_dir_entry_next_log_sector;
entry_offset = entry_ptr -> fx_dir_entry_byte_offset;
}
/* Determine if there are enough free entries to satisfy the request. */
if ((i - free_entry_start + 1) >= total_entries)
{
FX_INT_SAVE_AREA
/* Found an empty slot. All the pertinent information is already
in the entry structure. */
entry_ptr -> fx_dir_entry_log_sector = entry_sector;
entry_ptr -> fx_dir_entry_next_log_sector = entry_next_sector;
entry_ptr -> fx_dir_entry_byte_offset = entry_offset;
/* Initialize the additional directory entries. */
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
/* Return a successful completion. */
return(FX_SUCCESS);
}
}
else
{
/* Reset the free entry start. */
free_entry_start = directory_entries;
}
/* Move to the next entry. */
i++;
} while (i < directory_entries);
}
/* No empty entries were found. If the specified directory is a sub-directory,
attempt to allocate another cluster to it. */
if (media_ptr -> fx_media_available_clusters)
{
ULONG64 size;
bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster);
/* Check if it is a sub directory. */
if (search_dir_ptr)
{
/* Set size to the available file size. */
size = search_dir_ptr -> fx_dir_entry_available_file_size;
}
else
{
/* Root directory, set size to root directory size. */
size = media_ptr -> fx_media_root_directory_entries * FX_DIR_ENTRY_SIZE;
}
/* Check for directory restriction */
if (size + bytes_per_cluster > FX_EXFAT_MAX_DIRECTORY_SIZE)
{
return(FX_NO_MORE_SPACE);
}
/* Search the FAT for the next available cluster. */
status = _fx_utility_exFAT_allocate_new_cluster(media_ptr, search_dir_ptr, &last_cluster, &cluster);
if (status != FX_SUCCESS)
{
return(status);
}
/* Decrease the available clusters in the media. */
media_ptr -> fx_media_available_clusters--;
/* 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. */
/* Update entry size. */
if (search_dir_ptr)
{
search_dir_ptr -> fx_dir_entry_file_size += bytes_per_cluster;
search_dir_ptr -> fx_dir_entry_available_file_size = search_dir_ptr -> fx_dir_entry_file_size;
}
else
{
/* Change root directory entry count - FAT32 has a variable sized root directory. */
media_ptr -> fx_media_root_directory_entries += bytes_per_cluster / FX_DIR_ENTRY_SIZE;
}
/* Calculate the logical sector of this cluster. */
logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
((((ULONG64)cluster) - 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, 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 + sizeof(ULONG);
}
/* Invalidate all cached sectors that are contained in the newly allocated first
cluster of the directory. */
/* Pickup the total number of cache entries. */
i = (UINT)media_ptr -> fx_media_sector_cache_size;
/* Setup pointer to first cache entry (not in list order). */
cache_entry_ptr = media_ptr -> fx_media_sector_cache;
/* Examine all the logical sector cache entries. */
while (i--)
{
/* Determine if the cached entry is a sector in the first cluster of the
new directory. We don't need to worry about the first sector since it
was read using the logical sector read utility earlier. */
if ((cache_entry_ptr -> fx_cached_sector >= (logical_sector + 1)) &&
(cache_entry_ptr -> fx_cached_sector < (logical_sector + sectors)))
{
/* Yes, we have found a logical sector in the cache that is one of the directory
sectors that will be written with zeros. Because of this, simply make this
cache entry invalid. */
cache_entry_ptr -> fx_cached_sector = 0;
cache_entry_ptr -> fx_cached_sector_buffer_dirty = FX_FALSE;
}
/* Move to next entry in the cached sector list. */
if (cache_entry_ptr -> fx_cached_sector_next_used)
{
cache_entry_ptr = cache_entry_ptr -> fx_cached_sector_next_used;
}
}
/* Clear all sectors of new sub-directory cluster. */
do
{
/* Decrease the number of sectors to clear. */
sectors--;
/* 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;
/* Set the system write flag since we are writing a directory sector. */
media_ptr -> fx_media_driver_system_write = FX_TRUE;
/* 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(status);
}
} while (sectors);
#ifdef FX_FAULT_TOLERANT
/* Flush the internal logical sector. */
_fx_utility_logical_sector_flush(media_ptr, logical_sector, media_ptr -> fx_media_sectors_per_cluster, FX_FALSE);
#endif
if ((!search_dir_ptr) || (!(search_dir_ptr -> fx_dir_entry_dont_use_fat & 1)))
{
/* At this point, link up the last cluster with the new cluster. */
/* Setup the last cluster to indicate the end of the chain. */
status = _fx_utility_FAT_entry_write(media_ptr, cluster, FX_LAST_CLUSTER_exFAT);
/* Check the return value. */
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
/* Link the last cluster of the directory to the new cluster. */
if (last_cluster)
{
status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, cluster);
/* Check the return value. */
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
}
}
if (!last_cluster && search_dir_ptr)
{
search_dir_ptr -> fx_dir_entry_cluster = cluster;
}
/* Mark the cluster as used. */
status = _fx_utility_exFAT_cluster_state_set(media_ptr, cluster, FX_EXFAT_BITMAP_CLUSTER_OCCUPIED);
/* Check the return value. */
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
/* Move cluster search pointer forward. */
media_ptr -> fx_media_cluster_search_start = cluster + 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;
}
#ifdef FX_FAULT_TOLERANT
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
/* Flush the bitmap and its logical sector. */
_fx_utility_exFAT_bitmap_flush(media_ptr);
_fx_utility_logical_sector_flush(media_ptr, media_ptr -> fx_media_exfat_bitmap_start_sector +
(cluster >> media_ptr -> fx_media_exfat_bitmap_clusters_per_sector_shift), ((ULONG64) 1), FX_FALSE);
#endif
/* Finally load up the directory entry with information for the
beginning of the new cluster. */
{
FX_INT_SAVE_AREA
entry_ptr -> fx_dir_entry_name[0] = 0;
if (free_entry_start == directory_entries)
{
/* start from begining of new cluster */
entry_ptr -> fx_dir_entry_log_sector = logical_sector;
/* There are more sectors in this cluster. */
entry_ptr -> fx_dir_entry_next_log_sector = logical_sector + 1;
/* Clear the byte offset since this is a new entry. */
entry_ptr -> fx_dir_entry_byte_offset = 0;
}
else
{
/* start from end of last cluster */
entry_ptr -> fx_dir_entry_log_sector = entry_sector;
/* Next sector in new cluster */
entry_ptr -> fx_dir_entry_next_log_sector = logical_sector;
/* Set byte offset */
entry_ptr -> fx_dir_entry_byte_offset = entry_offset;
}
/* 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
}
entry_ptr -> fx_dir_entry_type = FX_EXFAT_DIR_ENTRY_TYPE_END_MARKER;
/* Return a successful status. */
return(FX_SUCCESS);
}
/* Return "not found" status to the caller. */
return(FX_NOT_FOUND);
}
#endif /* FX_ENABLE_EXFAT */

View File

@ -0,0 +1,944 @@
/**************************************************************************/
/* */
/* 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"
#ifdef FX_ENABLE_EXFAT
#include "fx_utility.h"
#include "fx_directory_exFAT.h"
#include "fx_directory.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
#include "fx_fault_tolerant.h"
#endif /* FX_ENABLE_FAULT_TOLERANT */
#include "fx_utility.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_exFAT_unicode_entry_write PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function writes the supplied directory entry to the specified */
/* logical sector and offset. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* entry_ptr Pointer to directory entry */
/* update_level Update level for entry write */
/* unicode_name Unicode file name */
/* unicode_length Length of unicode file name */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_exFAT_cluster_free Release unused clusters */
/* _fx_utility_exFAT_name_hash_get Get name hash */
/* _fx_utility_FAT_entry_read Read a new FAT entry */
/* _fx_utility_logical_sector_flush Flush the written log sector */
/* _fx_utility_logical_sector_read Read directory sector */
/* _fx_utility_logical_sector_write Write directory sector */
/* _fx_utility_string_length_get Get string's length */
/* _fx_utility_16_unsigned_write Write a USHORT from memory */
/* _fx_utility_32_unsigned_write Write a ULONG from memory */
/* _fx_utility_64_unsigned_read Read a ULONG64 from memory */
/* _fx_fault_tolerant_add_dir_log Add directory redo log */
/* _fx_fault_tolerant_add_checksum_log Add checksum redo log */
/* */
/* CALLED BY */
/* */
/* FileX System Functions */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _fx_directory_exFAT_unicode_entry_write(FX_MEDIA *media_ptr, FX_DIR_ENTRY *entry_ptr,
UCHAR update_level, USHORT *unicode_name, UINT unicode_length)
{
UCHAR *work_ptr;
UCHAR *sector_base_ptr;
UINT status;
UINT i, j;
ULONG64 logical_sector;
ULONG relative_sector;
ULONG byte_offset;
ULONG cluster, next_cluster;
UINT total_entries;
UINT name_length;
UINT name_pos = 0;
UINT copy_size;
USHORT checksum = 0;
ULONG date_time;
UINT use_unicode = FX_FALSE;
#ifdef FX_ENABLE_FAULT_TOLERANT
UCHAR *changed_ptr; /* Points to the directory entry that needs to be updated. */
UINT changed_size; /* The amount of bytes changed */
ULONG changed_offset; /* Offset from the beginning of the sector. */
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Check if we have unicode file name available. */
if (unicode_name && unicode_length)
{
/* Set use unicode flag. */
use_unicode = FX_TRUE;
/* Save the length of the name. */
name_length = unicode_length;
}
else
{
/* Calculate the length of the name from the name string. */
name_length = _fx_utility_string_length_get(entry_ptr -> fx_dir_entry_name, FX_MAX_EX_FAT_NAME_LEN);
/* Check if name is valid. */
if (entry_ptr -> fx_dir_entry_name[name_length] != 0)
{
/* Invalid name, return error. */
return(FX_INVALID_NAME);
}
}
/* Pickup the byte offset of the entry. */
byte_offset = entry_ptr -> fx_dir_entry_byte_offset;
/* Pickup the logical sector of the entry. */
logical_sector = entry_ptr -> fx_dir_entry_log_sector;
/* Calculate the cluster that this logical sector is in. */
cluster = (ULONG)((logical_sector - media_ptr -> fx_media_data_sector_start) / (media_ptr -> fx_media_sectors_per_cluster)) + FX_FAT_ENTRY_START;
/* Calculate the relative cluster. */
relative_sector = (ULONG)(logical_sector - (((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG64)cluster - FX_FAT_ENTRY_START) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster))));
/* Read the 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 the error status. */
return(status);
}
/* Setup a pointer into the buffer. */
sector_base_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer;
work_ptr = sector_base_ptr + (UINT)entry_ptr -> fx_dir_entry_byte_offset;
/* Build file entry fields. */
/* Check if we need to update EntryType field. */
if (update_level == UPDATE_FULL)
{
/* Set EntryType field to file directory. */
*work_ptr = FX_EXFAT_DIR_ENTRY_TYPE_FILE_DIRECTORY;
}
/* Check if we are request to delete the file. */
else if (update_level == UPDATE_DELETE)
{
/* Clear InUse bit. */
*work_ptr &= 0x7f;
}
/* Advance the pointer to the next field: SecondaryCount. */
work_ptr++;
/* Update SecondaryCount field. */
if (update_level == UPDATE_FULL)
{
/* Calculate the secondary entry count from file name length. */
total_entries = 1 + (name_length + 14) / 15;
/* Save SecondaryCount field. */
*work_ptr = (UCHAR)total_entries;
}
else
{
/* We are not performing a full update, read back the secondary entry count. */
total_entries = *work_ptr;
}
/* Advance the pointer to the next field. */
work_ptr++;
/* Skip SetChecksum field. */
work_ptr += 2;
/* Check if we need to update FileAttributes field. */
if (update_level >= UPDATE_FILE)
{
/* Write the file attributes field. */
_fx_utility_16_unsigned_write(work_ptr, entry_ptr -> fx_dir_entry_attributes);
}
/* Advance the pointer to the next field. */
work_ptr += 2;
/* Check if we need to perform full entry update. */
if (update_level == UPDATE_FULL)
{
/* Clear Reserved1 field. */
_fx_utility_16_unsigned_write(work_ptr, 0);
}
/* Advance the pointer to the next field. */
work_ptr += 2;
/* Check if we need to update the CreateTimestamp field. */
if (update_level >= UPDATE_FILE)
{
/* Calculate and update CreateTimestamp field. */
date_time = ((ULONG)entry_ptr -> fx_dir_entry_created_date << 16) |
(ULONG)entry_ptr -> fx_dir_entry_created_time;
_fx_utility_32_unsigned_write(work_ptr, date_time);
}
/* Advance the pointer to the next field. */
work_ptr += 4;
/* Check if we need to update LastModifiedTimestamp field. */
if (update_level >= UPDATE_FILE)
{
/* Calculate and update LastModifiedTimestamp field. */
date_time = ((ULONG)entry_ptr -> fx_dir_entry_date << 16) |
(ULONG)entry_ptr -> fx_dir_entry_time;
_fx_utility_32_unsigned_write(work_ptr, date_time);
}
/* Advance the pointer to the next field. */
work_ptr += 4;
/* Check if we need to update LastAccessedTimestamp field. */
if (update_level >= UPDATE_FILE)
{
/* Calculate and update LastAccessedTimestamp field. */
date_time = ((ULONG)entry_ptr -> fx_dir_entry_date << 16) |
(ULONG)entry_ptr -> fx_dir_entry_time; /* use modified as accessed */
_fx_utility_32_unsigned_write(work_ptr, date_time);
}
/* Advance the pointer to the next field. */
work_ptr += 4;
/* Check if we need to update Create10msIncrement field. */
if (update_level >= UPDATE_FILE)
{
/* Update Create10msIncrement field. */
*work_ptr = entry_ptr -> fx_dir_entry_created_time_ms;
}
/* Advance the pointer to the next field. */
work_ptr++;
/* Check if we need to perform full entry update. */
if (update_level >= UPDATE_FILE)
{
/* 10ms increment field is not supported, clear this field. */
*work_ptr = 0;
}
/* Advance the pointer to the next field. */
work_ptr++;
/* Check if we need to perform full entry update. */
if (update_level == UPDATE_FULL)
{
/*CreateUtcOffset field is not supported, clear this field. */
*work_ptr = 0;
}
/* Advance the pointer to the next field. */
work_ptr++;
/* Check if we need to perform full entry update. */
if (update_level >= UPDATE_FILE)
{
/* LastModifiedUtcOffset field is not supported, clear this field. */
*work_ptr = 0;
}
/* Advance the pointer to the next field. */
work_ptr++;
/* Check if we need to perform full entry update. */
if (update_level == UPDATE_FULL)
{
/* LastModifiedUtcOffset field is not supported, clear this field. */
*work_ptr = 0; /* Not supported. */
}
/* Advance the pointer to the next field. */
work_ptr++;
/* Clear Reserved2 field. */
if (update_level == UPDATE_FULL)
{
/* Loop to clear the reserved field. */
for (i = 0; i < 7; ++i)
{
/* Clear the reserved field. */
*work_ptr = 0;
work_ptr++;
}
}
else
{
/* Skip the reserved field. */
work_ptr += 7;
}
/* Calculate checksum. */
work_ptr -= FX_DIR_ENTRY_SIZE;
/* Loop to calculate the entry checksum. */
for (j = 0; j < FX_DIR_ENTRY_SIZE; ++j)
{
/* Skip the checksum field. */
if ((j == 2) || (j == 3))
{
continue;
}
/* Calculate the checksum using the algorithm described in the specification. */
/* Right rotate the checksum by one bit position and add the data. */
checksum = (USHORT)(((checksum >> 1) | (checksum << 15)) + work_ptr[j]);
}
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Initialize variables for fault tolerant. */
changed_ptr = work_ptr;
changed_offset = entry_ptr -> fx_dir_entry_byte_offset;
changed_size = 0;
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Update second entries. */
for (i = 0; i < total_entries; ++i)
{
/* Advance the pointer and offset to next directory entry. */
work_ptr += FX_DIR_ENTRY_SIZE;
byte_offset += FX_DIR_ENTRY_SIZE;
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Update changed_size. */
changed_size += FX_DIR_ENTRY_SIZE;
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Determine if the entry overlaps into the next sector. */
if (byte_offset >= media_ptr -> fx_media_bytes_per_sector)
{
#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))
{
/* Redirect this request to log file. */
status = _fx_fault_tolerant_add_dir_log(media_ptr, logical_sector, changed_offset, changed_ptr, changed_size);
}
else
#endif /* FX_ENABLE_FAULT_TOLERANT */
{
/* Write current logical sector out. */
status = _fx_utility_logical_sector_write(media_ptr, logical_sector,
sector_base_ptr, ((ULONG) 1), FX_DIRECTORY_SECTOR);
}
/* Determine if an error occurred. */
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
/* 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. */
if ((entry_ptr -> fx_dir_entry_dont_use_fat >> 1) & 1) /* Check parent dont_use_fat flag. */
{
/* FAT is not used, next cluster is after the current cluster. */
next_cluster = cluster + 1;
}
else
{
/* FAT is used, read FAT to get 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 > FX_RESERVED_1_exFAT))
{
/* Send error message back to caller. */
return(FX_FILE_CORRUPT);
}
/* 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) +
(((ULONG64)cluster - FX_FAT_ENTRY_START) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster));
}
/* Read the 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 the error status. */
return(status);
}
/* Setup logical sector. */
sector_base_ptr = media_ptr -> fx_media_memory_buffer;
/* Setup a fresh byte offset. */
byte_offset = 0;
/* Setup a new pointer into the buffer. */
work_ptr = sector_base_ptr;
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Initialize data for fault tolerant. */
changed_ptr = work_ptr;
changed_size = 0;
changed_offset = 0;
#endif /* FX_ENABLE_FAULT_TOLERANT */
}
/* Check if we are processing the first secondary entry. */
if (i == 0)
{
/* First sub entry is stream entry. */
/* Check if we need to perform full entry update. */
if (update_level == UPDATE_FULL)
{
/* Set the EntryType field to stream extension type. */
*work_ptr = FX_EXFAT_DIR_ENTRY_TYPE_STREAM_EXTENSION;
}
else if (update_level == UPDATE_DELETE)
{
/* Clear InUse bit. */
*work_ptr &= 0x7f;
}
/* Advance the pointer to the next field. */
work_ptr++;
/* Update GeneralSecondaryFlags field. */
if (update_level >= UPDATE_STREAM)
{
/* Check if FAT is used and the entry has associated cluster. */
if ((entry_ptr -> fx_dir_entry_dont_use_fat & 1) && (entry_ptr -> fx_dir_entry_cluster != 0))
{
/* Set the flags to don't use FAT. */
*work_ptr = 3;
}
else
{
/* FAT is used. */
*work_ptr = 1;
}
}
/* Advance the pointer to the next field. */
work_ptr++;
/* Check if we need to perform full entry update. */
if (update_level == UPDATE_FULL)
{
/* Clear Reserved1 field. */
*work_ptr = 0;
}
/* Advance the pointer to the next field. */
work_ptr++;
/* Check if we need to update NameLength field. */
if (update_level >= UPDATE_NAME)
{
/* Update NameLength field. */
*work_ptr = (UCHAR)name_length;
}
/* Advance the pointer to the next field. */
work_ptr++;
/* Check if we need to update NameHash field. */
if (update_level >= UPDATE_NAME)
{
/* Check if the supplied file name is in unicode format. */
if (use_unicode)
{
/* Update NameHash field. */
_fx_utility_16_unsigned_write(work_ptr, _fx_utility_exFAT_unicode_name_hash_get((CHAR *)unicode_name, name_length));
}
else
{
/* Update NameHash field. */
_fx_utility_16_unsigned_write(work_ptr, _fx_utility_exFAT_name_hash_get(entry_ptr -> fx_dir_entry_name));
}
}
/* Advance the pointer to the next field. */
work_ptr += 2;
/* Check if we need to perform full entry update. */
if (update_level == UPDATE_FULL)
{
/* Clear Reserved2 field. */
_fx_utility_16_unsigned_write(work_ptr, 0);
}
/* Advance the pointer to the next field. */
work_ptr += 2;
/* Check if we need to update ValidDataLength field. */
if (update_level >= UPDATE_STREAM)
{
/* Update ValidDataLength field. */
_fx_utility_64_unsigned_write(work_ptr, entry_ptr -> fx_dir_entry_file_size);
}
/* Advance the pointer to the next field. */
work_ptr += 8;
/* Check if we need to perform full entry update. */
if (update_level == UPDATE_FULL)
{
/* Clear Reserved3 field. */
_fx_utility_32_unsigned_write(work_ptr, 0);
}
/* Advance the pointer to the next field. */
work_ptr += 4;
/* Check if we need to update FirstCluster field. */
if (update_level >= UPDATE_STREAM)
{
/* Update FirstCluster field. */
_fx_utility_32_unsigned_write(work_ptr, entry_ptr -> fx_dir_entry_cluster);
}
/* Advance the pointer to the next field. */
work_ptr += 4;
/* Update DataLength fields. */
if (update_level >= UPDATE_STREAM)
{
/* Update DataLength fields. */
_fx_utility_64_unsigned_write(work_ptr, entry_ptr -> fx_dir_entry_available_file_size);
_fx_utility_64_unsigned_write(work_ptr, entry_ptr -> fx_dir_entry_file_size);
}
/* Advance the pointer to the next field. */
work_ptr += 8;
}
else
{
/* Check if we are requested to delete the entries. */
if (update_level == UPDATE_DELETE)
{
/* Check the directory entry type. */
if ((*work_ptr != FX_EXFAT_DIR_ENTRY_TYPE_FILE_NAME) && (*work_ptr != FX_EXFAT_DIR_ENTRY_TYPE_STREAM_EXTENSION))
{
/* Unknown secondary, we should free used clusters if any. */
status = _fx_utility_exFAT_cluster_free(media_ptr, work_ptr);
if (status != FX_SUCCESS)
{
/* Return completion status. */
return(status);
}
}
/* Clear InUse bit. */
*work_ptr &= 0x7f;
work_ptr += FX_DIR_ENTRY_SIZE;
}
/* Check if we need to update the file name. */
else if ((update_level == UPDATE_FULL) ||
((update_level == UPDATE_NAME) && (*work_ptr == FX_EXFAT_DIR_ENTRY_TYPE_FILE_NAME)))
{
/* Build Name entry. */
/* Update EntryType field. */
*work_ptr = FX_EXFAT_DIR_ENTRY_TYPE_FILE_NAME;
work_ptr++;
/* Update GeneralSecondaryFlags field. */
*work_ptr = 0;
work_ptr++;
/* Update FileName field. */
/* One name entry can hold up to 15 characters. Set how many characters to copy. */
if (name_length > 15)
{
copy_size = 15;
}
else
{
copy_size = name_length;
}
/* Check if the supplied file name is in unicode format. */
if (use_unicode)
{
/* Loop to copy the unicode file name. */
for (j = 0; j < copy_size; ++j)
{
/* Copy unicode file name to the file name entry. */
_fx_utility_16_unsigned_write(work_ptr, (UINT)unicode_name[name_pos++]);
work_ptr += 2;
}
}
else
{
/* Loop to copy non-unicode file name. */
for (j = 0; j < copy_size; ++j)
{
/* Copy and convert non-unicode file name. */
_fx_utility_16_unsigned_write(work_ptr, (UINT)entry_ptr -> fx_dir_entry_name[name_pos++]);
work_ptr += 2;
}
}
/* Loop to clear remaining bytes. */
for (j = copy_size; j < 15; ++j)
{
/* Clear the remaining bytes. */
_fx_utility_16_unsigned_write(work_ptr, 0);
work_ptr += 2;
}
/* Modify the name_length to indicate the remaining length. */
name_length -= copy_size;
}
else
{
/* The entry does need to be updated, move to next entry. */
work_ptr += FX_DIR_ENTRY_SIZE;
}
}
/* Set pointer back for checksum calculation. */
work_ptr -= FX_DIR_ENTRY_SIZE;
/* Loop to calculate the checksum. */
for (j = 0; j < FX_DIR_ENTRY_SIZE; ++j)
{
/* Calculate the checksum. */
/* Right rotate the checksum by one bit position and add the data. */
checksum = (USHORT)(((checksum >> 1) | (checksum << 15)) + work_ptr[j]);
}
}
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Update changed_size. */
changed_size += FX_DIR_ENTRY_SIZE;
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Go back to file entry. */
if (byte_offset < total_entries * FX_DIR_ENTRY_SIZE)
{
#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))
{
/* Redirect this request to log file. */
status = _fx_fault_tolerant_add_dir_log(media_ptr, logical_sector, changed_offset, changed_ptr, changed_size);
}
else
#endif /* FX_ENABLE_FAULT_TOLERANT */
{
/* Write current logical sector out. */
status = _fx_utility_logical_sector_write(media_ptr, logical_sector,
sector_base_ptr, ((ULONG) 1), FX_DIRECTORY_SECTOR);
}
/* Determine if an error occurred. */
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
/* Pickup the byte offset of the entry. */
byte_offset = entry_ptr -> fx_dir_entry_byte_offset;
/* Pickup the logical sector of the entry. */
logical_sector = entry_ptr -> fx_dir_entry_log_sector;
/* Calculate the cluster that this logical sector is in. */
cluster = (ULONG)((logical_sector - media_ptr -> fx_media_data_sector_start) / (media_ptr -> fx_media_sectors_per_cluster)) + FX_FAT_ENTRY_START;
/* Calculate the relative cluster. */
relative_sector = (ULONG)(logical_sector - (((ULONG)media_ptr -> fx_media_data_sector_start) +
(((ULONG64)cluster - FX_FAT_ENTRY_START) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster))));
/* Read the 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 the error status. */
return(status);
}
/* Setup logical sector. */
sector_base_ptr = media_ptr -> fx_media_memory_buffer;
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Initialize data for fault tolerant. */
/* A log for checksum. */
changed_ptr = sector_base_ptr + byte_offset + 2;
changed_size = 2;
changed_offset = byte_offset + 2;
#endif /* FX_ENABLE_FAULT_TOLERANT */
}
else
{
/* The directory entries are not crossing sector boundary, just adjust the pointer to go back to the first entry. */
byte_offset -= total_entries * FX_DIR_ENTRY_SIZE;
}
/* Setup work pointer to the directory entry. */
work_ptr = sector_base_ptr + byte_offset;
/* Store SetChecksum field. */
work_ptr += 2;
_fx_utility_16_unsigned_write(work_ptr, checksum);
#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))
{
if (changed_size == 2)
{
/* Only checksum. */
/* Redirect this request to log file. */
status = _fx_fault_tolerant_add_checksum_log(media_ptr, logical_sector, changed_offset, checksum);
}
else
{
/* Redirect this request to log file. */
status = _fx_fault_tolerant_add_dir_log(media_ptr, logical_sector, changed_offset, changed_ptr, changed_size);
}
}
else
#endif /* FX_ENABLE_FAULT_TOLERANT */
{
/* Write current logical sector out. */
status = _fx_utility_logical_sector_write(media_ptr, logical_sector,
sector_base_ptr, ((ULONG) 1), FX_DIRECTORY_SECTOR);
}
/* Determine if an error occurred. */
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
/* Check if there is a default path. */
if (media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name[0])
{
/* Check default path directory was updated. */
if ((media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_log_sector ==
entry_ptr -> fx_dir_entry_log_sector) &&
(media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_byte_offset ==
entry_ptr -> fx_dir_entry_byte_offset))
{
/* Update default path. */
media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_file_size =
entry_ptr -> fx_dir_entry_file_size;
media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_available_file_size =
entry_ptr -> fx_dir_entry_available_file_size;
media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_dont_use_fat =
entry_ptr -> fx_dir_entry_dont_use_fat;
media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_cluster =
entry_ptr -> fx_dir_entry_cluster;
}
}
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
/* Determine if there is a previously found directory entry in the directory
search cache. */
if (media_ptr -> fx_media_last_found_name[0])
{
/* Determine if the cached search directory entry matches the directory entry being
written. */
if ((entry_ptr -> fx_dir_entry_log_sector == media_ptr -> fx_media_last_found_entry.fx_dir_entry_log_sector) &&
(entry_ptr -> fx_dir_entry_byte_offset == media_ptr -> fx_media_last_found_entry.fx_dir_entry_byte_offset))
{
/* Yes, this entry is the same as the one currently in the directory search cache.
Update various fields in the directory search cache with the information being
written now. */
media_ptr -> fx_media_last_found_entry.fx_dir_entry_cluster = entry_ptr -> fx_dir_entry_cluster;
media_ptr -> fx_media_last_found_entry.fx_dir_entry_file_size = entry_ptr -> fx_dir_entry_file_size;
media_ptr -> fx_media_last_found_entry.fx_dir_entry_attributes = entry_ptr -> fx_dir_entry_attributes;
media_ptr -> fx_media_last_found_entry.fx_dir_entry_time = entry_ptr -> fx_dir_entry_time;
media_ptr -> fx_media_last_found_entry.fx_dir_entry_date = entry_ptr -> fx_dir_entry_date;
media_ptr -> fx_media_last_found_entry.fx_dir_entry_reserved = entry_ptr -> fx_dir_entry_reserved;
media_ptr -> fx_media_last_found_entry.fx_dir_entry_created_time_ms = entry_ptr -> fx_dir_entry_created_time_ms;
media_ptr -> fx_media_last_found_entry.fx_dir_entry_created_time = entry_ptr -> fx_dir_entry_created_time;
media_ptr -> fx_media_last_found_entry.fx_dir_entry_created_date = entry_ptr -> fx_dir_entry_created_date;
media_ptr -> fx_media_last_found_entry.fx_dir_entry_dont_use_fat = entry_ptr -> fx_dir_entry_dont_use_fat;
media_ptr -> fx_media_last_found_entry.fx_dir_entry_type = entry_ptr -> fx_dir_entry_type;
media_ptr -> fx_media_last_found_entry.fx_dir_entry_available_file_size = entry_ptr -> fx_dir_entry_available_file_size;
}
}
#endif
/* Return success to the caller. */
return(status);
}
#endif

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 */
/** */
/** 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}

View File

@ -0,0 +1,144 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}

View File

@ -0,0 +1,776 @@
/**************************************************************************/
/* */
/* 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"
#ifdef FX_ENABLE_EXFAT
#include "fx_directory_exFAT.h"
#endif /* FX_ENABLE_EXFAT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_free_search PORTABLE C */
/* 6.0 */
/* 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 */
/* */
/**************************************************************************/
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
#ifdef FX_ENABLE_EXFAT
/* Check if media format is exFAT. */
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Call exFAT specific function. */
return(_fx_directory_exFAT_free_search(media_ptr, directory_ptr, entry_ptr));
}
#endif /* FX_ENABLE_EXFAT */
#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);
}

View File

@ -0,0 +1,232 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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));
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);
}

View File

@ -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 */
/** */
/** 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.0 */
/* 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 */
/* */
/**************************************************************************/
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
}

View File

@ -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"
#ifndef FX_NO_LOCAL_PATH
FX_LOCAL_PATH_SETUP
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_local_path_get PORTABLE C */
/* 6.0 */
/* 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 */
/* */
/**************************************************************************/
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
/* 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
}

View File

@ -0,0 +1,120 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}
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);
}

View File

@ -0,0 +1,111 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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
/* 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
}

View File

@ -0,0 +1,445 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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
/* 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
}

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 */
/** */
/** 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.0 */
/* 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 */
/* */
/**************************************************************************/
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));
}

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 */
/** */
/** 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}

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 */
/** */
/** 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}

View File

@ -0,0 +1,141 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}

View File

@ -0,0 +1,469 @@
/**************************************************************************/
/* */
/* 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"
#ifdef FX_ENABLE_EXFAT
#include "fx_directory_exFAT.h"
#endif /* FX_ENABLE_EXFAT */
#ifndef FX_NO_LOCAL_PATH
FX_LOCAL_PATH_SETUP
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_next_entry_find PORTABLE C */
/* 6.0 */
/* 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 */
/* */
/**************************************************************************/
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)
{
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
directory_size = search_dir_ptr -> fx_dir_entry_file_size / FX_DIR_ENTRY_SIZE;
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* 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;
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
}
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);
}
#ifdef FX_ENABLE_EXFAT
if (entry.fx_dir_entry_type == FX_EXFAT_DIR_ENTRY_TYPE_END_MARKER)
{
/* Set the error code. */
status = FX_NO_MORE_ENTRIES;
/* Get out of the loop. */
break;
}
#endif /* FX_ENABLE_EXFAT */
/* Check to see if the entry has something in it. */
#ifdef FX_ENABLE_EXFAT
else if (entry.fx_dir_entry_type != FX_EXFAT_DIR_ENTRY_TYPE_FILE_DIRECTORY)
#else
if (((UCHAR)entry.fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry.fx_dir_entry_short_name[0] == 0))
#endif /* FX_ENABLE_EXFAT */
{
/* Current entry is free, skip to next entry and continue the loop. */
path_ptr -> fx_path_current_entry++;
continue;
}
#ifdef FX_ENABLE_EXFAT
else /* FX_EXFAT_DIR_ENTRY_TYPE_FILE_DIRECTORY */
#else
else if ((UCHAR)entry.fx_dir_entry_name[0] != (UCHAR)FX_DIR_ENTRY_DONE)
#endif /* FX_ENABLE_EXFAT */
{
/* 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;
}
#ifndef FX_ENABLE_EXFAT
else
{
/* Set the error code. */
status = FX_NO_MORE_ENTRIES;
/* Get out of the loop. */
break;
}
#endif /* FX_ENABLE_EXFAT */
}
/* Release media protection. */
FX_UNPROTECT
/* Return status to the caller. */
return(status);
}

View File

@ -0,0 +1,571 @@
/**************************************************************************/
/* */
/* 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"
#ifdef FX_ENABLE_EXFAT
#include "fx_directory_exFAT.h"
#endif /* FX_ENABLE_EXFAT */
#ifndef FX_NO_LOCAL_PATH
FX_LOCAL_PATH_SETUP
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_next_full_entry_find PORTABLE C */
/* 6.0 */
/* 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 */
/* _fx_directory_exFAT_entry_read Read exFAT entries */
/* */
/* CALLED BY */
/* */
/* Application Code and */
/* FileX System Functions */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
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
#ifdef FX_ENABLE_EXFAT
/* TODO: maybe will be better to use dynamic memory, just because unicode_name is not needed in case of not exFAT. */
UCHAR unicode_name[FX_MAX_LONG_NAME_LEN * 2];
UINT unicode_len = 0;
#endif /* FX_ENABLE_EXFAT */
#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;
#ifdef FX_ENABLE_EXFAT
/* Will be set by exFAT. */
entry.fx_dir_entry_secondary_count = 0;
#endif /* FX_ENABLE_EXFAT */
/* 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)
{
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
directory_size = search_dir_ptr -> fx_dir_entry_file_size / FX_DIR_ENTRY_SIZE;
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* 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;
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
}
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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
temp_status = _fx_directory_exFAT_entry_read(media_ptr, search_dir_ptr,
&(path_ptr -> fx_path_current_entry), &entry,
0, FX_FALSE, unicode_name, &unicode_len);
}
else
{
#endif /* FX_ENABLE_EXFAT */
temp_status = _fx_directory_entry_read(media_ptr, search_dir_ptr,
&(path_ptr -> fx_path_current_entry), &entry);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* Check for error status. */
if (temp_status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return error status. */
return(temp_status);
}
#ifdef FX_ENABLE_EXFAT
if (entry.fx_dir_entry_type == FX_EXFAT_DIR_ENTRY_TYPE_END_MARKER)
{
/* Set the error code. */
status = FX_NO_MORE_ENTRIES;
/* Get out of the loop. */
break;
}
#endif /* FX_ENABLE_EXFAT */
/* Check to see if the entry has something in it. */
#ifdef FX_ENABLE_EXFAT
else if (entry.fx_dir_entry_type != FX_EXFAT_DIR_ENTRY_TYPE_FILE_DIRECTORY)
#else
if (((UCHAR)entry.fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry.fx_dir_entry_short_name[0] == 0))
#endif /* FX_ENABLE_EXFAT */
{
/* 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. */
#ifdef FX_ENABLE_EXFAT
else /* FX_EXFAT_DIR_ENTRY_TYPE_FILE_DIRECTORY */
#else
else if ((UCHAR)entry.fx_dir_entry_name[0] != (UCHAR)FX_DIR_ENTRY_DONE)
#endif /* FX_ENABLE_EXFAT */
{
/* 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;
}
#ifndef FX_ENABLE_EXFAT
else
{
/* Set the error code. */
status = FX_NO_MORE_ENTRIES;
/* Get out of the loop. */
break;
}
#endif /* FX_ENABLE_EXFAT */
}
/* Release media protection. */
FX_UNPROTECT
/* Return status to the caller. */
return(status);
}

View File

@ -0,0 +1,521 @@
/**************************************************************************/
/* */
/* 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_EXFAT
#include "fx_directory_exFAT.h"
#endif /* FX_ENABLE_EXFAT */
#ifdef FX_ENABLE_FAULT_TOLERANT
#include "fx_fault_tolerant.h"
#endif /* FX_ENABLE_FAULT_TOLERANT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_rename PORTABLE C */
/* 6.0 */
/* 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 */
/* */
/**************************************************************************/
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;
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
new_dir_entry.fx_dir_entry_dont_use_fat = old_dir_entry.fx_dir_entry_dont_use_fat;
new_dir_entry.fx_dir_entry_type = old_dir_entry.fx_dir_entry_type;
new_dir_entry.fx_dir_entry_available_file_size = old_dir_entry.fx_dir_entry_available_file_size;
new_dir_entry.fx_dir_entry_secondary_count = old_dir_entry.fx_dir_entry_secondary_count;
}
#endif /* FX_ENABLE_EXFAT */
/* 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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(media_ptr, &new_dir_entry, UPDATE_FULL);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &new_dir_entry);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(media_ptr, &old_dir_entry, UPDATE_DELETE);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &old_dir_entry);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
#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);
}

View File

@ -0,0 +1,965 @@
/**************************************************************************/
/* */
/* 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"
#ifdef FX_ENABLE_EXFAT
#include "fx_directory_exFAT.h"
#endif /* FX_ENABLE_EXFAT */
#ifndef FX_NO_LOCAL_PATH
FX_LOCAL_PATH_SETUP
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_directory_search PORTABLE C */
/* 6.0 */
/* 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_exFAT_name_hash_get Get name hash */
/* _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 */
/* */
/**************************************************************************/
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;
UINT v, j;
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
#ifdef FX_ENABLE_EXFAT
USHORT hash = 0;
#endif /* FX_ENABLE_EXFAT */
#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 = '/';
}
/* Move to next character. */
v++;
/* Is the name the same? */
if (alpha != beta)
{
/* Break out of loop! */
break;
}
}
/* 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)
{
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
directory_size = search_dir_ptr -> fx_dir_entry_file_size / FX_DIR_ENTRY_SIZE;
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* 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;
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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;
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Get name hash. */
hash = _fx_utility_exFAT_name_hash_get(name);
}
#endif /* FX_ENABLE_EXFAT */
do
{
/* Read an entry from the directory. */
#ifdef FX_ENABLE_EXFAT
status = _fx_directory_entry_read_ex(media_ptr, search_dir_ptr, &i, entry_ptr, hash);
#else
status = _fx_directory_entry_read(media_ptr, search_dir_ptr, &i, entry_ptr);
#endif /* FX_ENABLE_EXFAT */
i++;
/* Check for error status. */
if (status != FX_SUCCESS)
{
return(status);
}
/* Determine if this is the last directory entry. */
#ifdef FX_ENABLE_EXFAT
if (entry_ptr -> fx_dir_entry_type == FX_EXFAT_DIR_ENTRY_TYPE_END_MARKER)
#else
if ((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_DONE)
#endif /* FX_ENABLE_EXFAT */
{
break;
}
/* Determine if this is an empty entry. */
#ifdef FX_ENABLE_EXFAT
if (entry_ptr -> fx_dir_entry_type != FX_EXFAT_DIR_ENTRY_TYPE_FILE_DIRECTORY)
#else
if (((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry_ptr -> fx_dir_entry_short_name[0] == 0))
#endif /* FX_ENABLE_EXFAT */
{
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. */
#ifdef FX_ENABLE_EXFAT
else if ((media_ptr -> fx_media_FAT_type != FX_exFAT) &&
(entry_ptr -> fx_dir_entry_short_name[0] != 0))
#else
else if (entry_ptr -> fx_dir_entry_short_name[0] != 0)
#endif /* FX_ENABLE_EXFAT */
{
/* 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. */
#ifdef FX_ENABLE_EXFAT
if ((!search_dir_ptr -> fx_dir_entry_cluster)
&& (media_ptr -> fx_media_FAT_type != FX_exFAT))
#else
if (!search_dir_ptr -> fx_dir_entry_cluster)
#endif /* FX_ENABLE_EXFAT */
{
/* 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);
}

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 */
/** */
/** 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.0 */
/* 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 */
/* */
/**************************************************************************/
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));
}

View File

@ -0,0 +1,168 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}

View File

@ -0,0 +1,111 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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 */

View File

@ -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_fault_tolerant.h"
#if defined(FX_ENABLE_FAULT_TOLERANT) && defined(FX_ENABLE_EXFAT)
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_add_bitmap_log PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function converts bitmap write into log entries and add them */
/* into log file. */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* cluster Cluster entry number */
/* value Valud of cluster state */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _fx_utility_16_unsigned_write Write a USHORT from memory */
/* _fx_utility_32_unsigned_write Write a UINT from memory */
/* memcpy Memory Copy */
/* */
/* CALLED BY */
/* */
/* _fx_directory_exFAT_unicode_entry_write */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_add_bitmap_log(FX_MEDIA *media_ptr, ULONG cluster, ULONG value)
{
ULONG file_size;
FX_FAULT_TOLERANT_BITMAP_LOG *bitmap_log;
/* Increment the size of the log file. */
file_size = media_ptr -> fx_media_fault_tolerant_file_size + FX_FAULT_TOLERANT_BITMAP_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. */
bitmap_log = (FX_FAULT_TOLERANT_BITMAP_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 *)&bitmap_log -> fx_fault_tolerant_bitmap_log_type,
FX_FAULT_TOLERANT_BITMAP_LOG_TYPE);
/* Size of log. */
_fx_utility_16_unsigned_write((UCHAR *)&bitmap_log -> fx_fault_tolerant_bitmap_log_size,
FX_FAULT_TOLERANT_BITMAP_LOG_ENTRY_SIZE);
/* Set cluster and value. */
_fx_utility_32_unsigned_write((UCHAR *)&bitmap_log -> fx_fault_tolerant_bitmap_log_cluster, cluster);
_fx_utility_32_unsigned_write((UCHAR *)&bitmap_log -> fx_fault_tolerant_bitmap_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 && FX_ENABLE_EXFAT */

View File

@ -0,0 +1,153 @@
/**************************************************************************/
/* */
/* 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"
#if defined(FX_ENABLE_FAULT_TOLERANT) && defined(FX_ENABLE_EXFAT)
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_add_checksum_log PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function converts checksum of exFAT directory entry write into */
/* log entries 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 */
/* checksum Value of checksum */
/* */
/* 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 */
/* _fx_utility_16_unsigned_write Write a USHORT from memory */
/* memcpy Memory Copy */
/* */
/* CALLED BY */
/* */
/* _fx_directory_exFAT_unicode_entry_write */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _fx_fault_tolerant_add_checksum_log(FX_MEDIA *media_ptr, ULONG64 logical_sector, ULONG offset, USHORT checksum)
{
ULONG logs_remaining;
UCHAR *current_ptr;
ULONG size;
USHORT type;
ULONG log_len;
ULONG64 log_sector;
ULONG log_offset;
FX_FAULT_TOLERANT_DIR_LOG *dir_log;
/* Get fault tolerant data. */
logs_remaining = media_ptr -> fx_media_fault_tolerant_total_logs;
/* 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 DIR 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)
{
/* Set 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);
/* Get the offset of log. */
log_offset = _fx_utility_32_unsigned_read((UCHAR *)&dir_log -> fx_fault_tolerant_dir_log_offset);
/* Is the checksum for this directory log? */
if ((log_sector == logical_sector) && (offset == log_offset + 2))
{
/* Yes. Update the checksum field. */
_fx_utility_16_unsigned_write(current_ptr + FX_FAULT_TOLERANT_DIR_LOG_ENTRY_SIZE + 2, checksum);
/* Return success. */
return(FX_SUCCESS);
}
}
/* Decrease the logs_remaining counter. */
logs_remaining--;
/* Move to start position of next log entry. */
current_ptr += log_len;
}
/* The directory is not found. Log file is corrupted. */
return(FX_FILE_CORRUPT);
}
#endif /* FX_ENABLE_FAULT_TOLERANT && FX_ENABLE_EXFAT */

View File

@ -0,0 +1,130 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* _fx_directory_exFAT_unicode_entry_write */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
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 +
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 */

View File

@ -0,0 +1,327 @@
/**************************************************************************/
/* */
/* 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.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_utility_exFAT_cluster_state_set Set state of exFAT cluster */
/* _fx_fault_tolerant_cleanup_FAT_chain Cleanup FAT chain */
/* memcpy Memory Copy */
/* _fx_utility_exFAT_bitmap_flush Flush exFAT allocation bitmap */
/* _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 */
/* */
/**************************************************************************/
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;
#ifdef FX_ENABLE_EXFAT
FX_FAULT_TOLERANT_BITMAP_LOG *bitmap_log;
ULONG current_cluster;
ULONG head_cluster;
ULONG tail_cluster;
#endif /* FX_ENABLE_EXFAT */
/* 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;
#ifdef FX_ENABLE_EXFAT
case FX_FAULT_TOLERANT_BITMAP_LOG_TYPE:
/* This is a bitmap log. */
bitmap_log = (FX_FAULT_TOLERANT_BITMAP_LOG *)current_ptr;
/* Set bitmap entry. */
status = _fx_utility_exFAT_cluster_state_set(media_ptr,
_fx_utility_32_unsigned_read((UCHAR *)&bitmap_log -> fx_fault_tolerant_bitmap_log_cluster),
(UCHAR)_fx_utility_32_unsigned_read((UCHAR *)&bitmap_log -> fx_fault_tolerant_bitmap_log_value));
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
break;
#endif /* FX_ENABLE_EXFAT */
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;
/* Copy data into destination sector. */
memcpy(media_ptr -> fx_media_memory_buffer + copy_offset,
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. */
#ifdef FX_ENABLE_EXFAT
if (FAT_chain -> fx_fault_tolerant_FAT_chain_flag & FX_FAULT_TOLERANT_FLAG_BITMAP_USED)
{
/* Process FAT chain. */
/* Get head and tail cluster from FAT chain. */
head_cluster = _fx_utility_32_unsigned_read((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_head_original);
tail_cluster = _fx_utility_32_unsigned_read((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_insertion_back);
if ((head_cluster >= FX_FAT_ENTRY_START) && (head_cluster < media_ptr -> fx_media_fat_reserved))
{
for (current_cluster = head_cluster; current_cluster < tail_cluster; current_cluster++)
{
/* Free bitmap. */
status = _fx_utility_exFAT_cluster_state_set(media_ptr, current_cluster, FX_EXFAT_BITMAP_CLUSTER_FREE);
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++;
}
}
}
else
{
#endif /* FX_ENABLE_EXFAT */
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);
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
}
/* 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
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Flush exFAT bitmap. */
_fx_utility_exFAT_bitmap_flush(media_ptr);
}
#endif /* FX_ENABLE_EXFAT */
/* 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 */

View File

@ -0,0 +1,101 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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 */

View File

@ -0,0 +1,290 @@
/**************************************************************************/
/* */
/* 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_cleanup_FAT_chain PORTABLE C */
/* 6.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_exFAT_cluster_state_get Get state of exFAT cluster */
/* _fx_utility_exFAT_cluster_state_set Set state of exFAT cluster */
/* _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_exFAT_bitmap_flush Flush exFAT allocation bitmap */
/* _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 */
/* */
/* 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 */
/* */
/**************************************************************************/
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 origianl 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 opimize 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;
/* 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);
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Flush exFAT bitmap. */
_fx_utility_exFAT_bitmap_flush(media_ptr);
}
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Free bitmap. */
status = _fx_utility_exFAT_cluster_state_set(media_ptr, cache_ptr[i], FX_EXFAT_BITMAP_CLUSTER_FREE);
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
}
#endif /* FX_ENABLE_EXFAT */
}
/* 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);
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Flush exFAT bitmap. */
_fx_utility_exFAT_bitmap_flush(media_ptr);
}
#endif /* FX_ENABLE_EXFAT */
/* Get head cluster. */
if (head_cluster == next_session)
{
break;
}
head_cluster = next_session;
}
return(FX_SUCCESS);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */

View File

@ -0,0 +1,410 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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_exFAT_cluster_state_set Set state of exFAT cluster */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* _fx_utility_FAT_entry_write Write a FAT entry */
/* _fx_utility_exFAT_bitmap_flush Flush exFAT allocation bitmap */
/* _fx_utility_FAT_flush Flush written FAT entries */
/* _fx_utility_32_unsigned_write Write a ULONG from memory */
/* _fx_utility_exFAT_system_sector_write Write data into boot sector */
/* _fx_utility_exFAT_system_area_checksum_write */
/* Write checksum of boot sector */
/* _fx_utility_exFAT_bitmap_free_cluster_find */
/* Find a free cluster */
/* _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 */
/* */
/**************************************************************************/
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;
#ifdef FX_ENABLE_EXFAT
ULONG checksum;
UINT count;
UCHAR *byte_ptr;
UCHAR cluster_state;
#endif /* FX_ENABLE_EXFAT */
/* 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;
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
do
{
/* Get cluster state. */
status = _fx_utility_exFAT_cluster_state_get(media_ptr, (FAT_index + i), &cluster_state);
/* Check for a successful status. */
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
/* Determine if the entry is free. */
if (cluster_state == FX_EXFAT_BITMAP_CLUSTER_OCCUPIED)
{
break;
}
/* Otherwise, increment the consecutive FAT indices. */
i++;
} while (i < clusters);
}
else
{
#endif /* FX_ENABLE_EXFAT */
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);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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
{
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Find free cluster from exFAT media. */
status = _fx_utility_exFAT_bitmap_free_cluster_find(media_ptr,
FAT_index + i + 1,
&FAT_value);
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
if (FAT_value < FAT_index + i + 1)
{
/* If we wrapped. */
FAT_index = media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START;
}
else
{
FAT_index = FAT_value;
}
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* Position to the next possibly free FAT entry. */
FAT_index = FAT_index + i + 1;
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
}
}
/* 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);
}
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Mark the cluster as used. */
status = _fx_utility_exFAT_cluster_state_set(media_ptr, FAT_index + i, FX_EXFAT_BITMAP_CLUSTER_OCCUPIED);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
}
#endif /* FX_ENABLE_EXFAT */
}
/* 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_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Mark the cluster as used. */
status = _fx_utility_exFAT_cluster_state_set(media_ptr, FAT_index + clusters - 1, FX_EXFAT_BITMAP_CLUSTER_OCCUPIED);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
}
#endif /* FX_ENABLE_EXFAT */
#ifdef FX_FAULT_TOLERANT
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
_fx_utility_exFAT_bitmap_flush(media_ptr);
}
#endif /* FX_ENABLE_EXFAT */
#endif
/* 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);
}
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Write backup. */
status = _fx_utility_exFAT_system_sector_write(media_ptr, media_ptr -> fx_media_fault_tolerant_memory_buffer,
FX_EXFAT_FAT_MAIN_SYSTEM_AREA_SIZE,
1, FX_BOOT_SECTOR);
/* Determine if the boot sector was read correctly. */
if (status != FX_SUCCESS)
{
/* Return the boot sector error status. */
return(FX_BOOT_ERROR);
}
/* Calculate checksum. */
checksum = 0;
byte_ptr = media_ptr -> fx_media_fault_tolerant_memory_buffer;
/* Calculate Boot Sector Check Sum. */
for (i = 0; i < FX_BOOT_SECTOR_SIZE; i++)
{
if ((FX_EF_VOLUME_FLAGS == i) ||
(FX_EF_VOLUME_FLAGS + 1 == i) ||
(FX_EF_PERCENT_IN_USE == i))
{
continue;
}
checksum = ((checksum >> 1) | (checksum << 31)) + (ULONG)byte_ptr[i];
}
for (count = 1; count < FX_EXFAT_FAT_CHECK_SUM_OFFSET; count++)
{
/* Read sector. */
status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) count,
media_ptr -> fx_media_fault_tolerant_memory_buffer, ((ULONG) 1), FX_BOOT_SECTOR);
/* Check for good completion status. */
if (status != FX_SUCCESS)
{
/* Return the error status. */
return(status);
}
/* Calculate Check Sum for System Area */
for (i = 0; i < FX_BOOT_SECTOR_SIZE; i++)
{
checksum = ((checksum >> 1) | (checksum << 31)) + (ULONG)byte_ptr[i];
}
}
/* Write System Area CheckSum. */
status = _fx_utility_exFAT_system_area_checksum_write(media_ptr, media_ptr -> fx_media_fault_tolerant_memory_buffer,
&checksum);
if (status != FX_SUCCESS)
{
return(status);
}
}
#endif /* FX_ENABLE_EXFAT */
/* 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 */

View File

@ -0,0 +1,517 @@
/**************************************************************************/
/* */
/* 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.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 operaiton 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_exFAT_cluster_state_get Get state of exFAT cluster */
/* _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 */
/* */
/**************************************************************************/
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. */
/* 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;
/* 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;
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;
}
/* 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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
UCHAR cluste_state;
for (i = 0; i < clusters; i++)
{
/* Update Bitmap */
status = _fx_utility_exFAT_cluster_state_get(media_ptr, start_cluster + i, &cluste_state);
/* Check for a bad status. */
if (status != FX_SUCCESS)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the bad status. */
return(status);
}
if (cluste_state != FX_EXFAT_BITMAP_CLUSTER_OCCUPIED)
{
/* Mark invalid. */
start_cluster = 0;
break;
}
}
}
else
{
#endif /* FX_ENABLE_EXFAT */
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;
}
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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 */

View File

@ -0,0 +1,191 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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_exFAT_cluster_state_get */
/* _fx_utility_FAT_entry_read */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
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;
#ifdef FX_ENABLE_EXFAT
FX_FAULT_TOLERANT_BITMAP_LOG *bitmap_log;
#endif
/* 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. */
#ifdef FX_ENABLE_EXFAT
if (type == FX_FAULT_TOLERANT_BITMAP_LOG_TYPE)
{
bitmap_log = (FX_FAULT_TOLERANT_BITMAP_LOG *)current_ptr;
/* Is this bitmap log entry the one looking for? */
if (_fx_utility_32_unsigned_read((UCHAR *)&bitmap_log -> fx_fault_tolerant_bitmap_log_cluster) == cluster)
{
/* Yes, it is. */
*value = _fx_utility_32_unsigned_read((UCHAR *)&bitmap_log -> fx_fault_tolerant_bitmap_log_value);
/* Do not return since there may be more than one log for this cluster. */
found = FX_TRUE;
}
}
else
{
#endif /* FX_ENABLE_EXFAT */
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;
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
}
/* 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 */

View File

@ -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 */
/** */
/** 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.0 */
/* 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 */
/* */
/**************************************************************************/
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;
/* Copy data into destination sector. */
memcpy(current_buffer_ptr + copy_offset,
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 */

View File

@ -0,0 +1,91 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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 */

View File

@ -0,0 +1,166 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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_exFAT_bitmap_flush Flush exFAT allocation bitmap */
/* _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 */
/* */
/**************************************************************************/
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
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Flush exFAT bitmap. */
_fx_utility_exFAT_bitmap_flush(media_ptr);
}
#endif /* FX_ENABLE_EXFAT */
/* 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 */

View File

@ -0,0 +1,140 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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 */

View File

@ -0,0 +1,131 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
#ifdef FX_ENABLE_EXFAT
/* Check flag for bitmap. */
if (use_bitmap == FX_TRUE)
{
flag |= FX_FAULT_TOLERANT_FLAG_BITMAP_USED;
}
#else
/* Parameters not used. Avoid compiler warnings. */
FX_PARAMETER_NOT_USED(use_bitmap);
#endif /* FX_ENABLE_EXFAT */
/* 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 */

View File

@ -0,0 +1,205 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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 */

View File

@ -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_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.0 */
/* 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 */
/* */
/**************************************************************************/
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

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_fault_tolerant.h"
#ifdef FX_ENABLE_FAULT_TOLERANT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_fault_tolerant_transaction_start PORTABLE C */
/* 6.0 */
/* 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 */
/* */
/**************************************************************************/
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 */

View File

@ -0,0 +1,110 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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 */

View File

@ -0,0 +1,79 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
UINT _fx_file_allocate(FX_FILE *file_ptr, ULONG size)
{
return(_fx_file_extended_allocate(file_ptr, (ULONG64)size));
}

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 */
/** */
/** 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
not_a_file_attr = FX_DIRECTORY;
}
else
{
#endif /* FX_ENABLE_EXFAT */
not_a_file_attr = FX_DIRECTORY | FX_VOLUME;
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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);
}

View File

@ -0,0 +1,241 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
not_a_file_attr = FX_DIRECTORY;
}
else
{
#endif /* FX_ENABLE_EXFAT */
not_a_file_attr = FX_DIRECTORY | FX_VOLUME;
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(media_ptr, &dir_entry, UPDATE_FILE);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &dir_entry);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
#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);
}

View File

@ -0,0 +1,95 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}

196
common/src/fx_file_close.c Normal file
View File

@ -0,0 +1,196 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(
media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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);
}

390
common/src/fx_file_create.c Normal file
View File

@ -0,0 +1,390 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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;
#ifdef FX_ENABLE_EXFAT
ULONG64 dir_size;
#endif /* FX_ENABLE_EXFAT */
#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);
}
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
if (((dir_entry.fx_dir_entry_name[0] == '.') && (dir_entry.fx_dir_entry_name[1] == 0)) ||
((dir_entry.fx_dir_entry_name[0] == '.') && (dir_entry.fx_dir_entry_name[1] == '.') && (dir_entry.fx_dir_entry_name[2] == 0)))
{
#ifdef FX_ENABLE_FAULT_TOLERANT
FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Release media protection. */
FX_UNPROTECT
/* We don't need '.' or '..' for exFAT */
return(FX_ALREADY_CREATED);
}
}
/* Save the directory entry size. */
dir_size = search_directory.fx_dir_entry_file_size;
#endif /* FX_ENABLE_EXFAT */
/* 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;
#ifdef FX_ENABLE_EXFAT
/* Set available file size to 0. */
dir_entry.fx_dir_entry_available_file_size = 0;
#endif /* FX_ENABLE_EXFAT */
/* 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;
}
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Don't use FAT by default. */
dir_entry.fx_dir_entry_dont_use_fat = (CHAR)(((search_directory.fx_dir_entry_dont_use_fat & 1) << 1) | 1);
if (search_directory.fx_dir_entry_name[0])
{
/* Not root directory. */
/* Copy the date and time from the actual sub-directory. */
search_directory.fx_dir_entry_time = dir_entry.fx_dir_entry_time;
search_directory.fx_dir_entry_date = dir_entry.fx_dir_entry_date;
/* Check if the directory size has changed. */
if (search_directory.fx_dir_entry_file_size == dir_size)
{
/* Not changed, we need only update time stamps. */
status = _fx_directory_exFAT_entry_write(media_ptr, &search_directory, UPDATE_FILE);
}
else
{
/* Directory size changed, update time stamps and the stream size. */
status = _fx_directory_exFAT_entry_write(media_ptr, &search_directory, UPDATE_STREAM);
}
/* 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);
}
}
}
else
{
dir_entry.fx_dir_entry_dont_use_fat = 0;
}
#endif /* FX_ENABLE_EXFAT */
/* Now write out the directory entry. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(media_ptr, &dir_entry, UPDATE_FULL);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &dir_entry);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
#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);
}

View File

@ -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 */
/** */
/** 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.0 */
/* 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 */
/* */
/**************************************************************************/
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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(media_ptr, &dir_entry, UPDATE_FILE);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &dir_entry);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* Release media protection. */
FX_UNPROTECT
/* Directory information write is complete, return status. */
return(status);
}

475
common/src/fx_file_delete.c Normal file
View File

@ -0,0 +1,475 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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_exFAT_cluster_state_set Set cluster state */
/* _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 */
/* */
/**************************************************************************/
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;
#ifdef FX_ENABLE_EXFAT
ULONG bytes_per_cluster;
ULONG clusters_count;
#endif /* FX_ENABLE_EXFAT */
#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);
}
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
not_a_file_attr = FX_DIRECTORY;
}
else
{
#endif /* FX_ENABLE_EXFAT */
not_a_file_attr = FX_DIRECTORY | FX_VOLUME;
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(media_ptr, &dir_entry, UPDATE_DELETE);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &dir_entry);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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_EXFAT
bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster);
clusters_count =
(ULONG)((dir_entry.fx_dir_entry_file_size + bytes_per_cluster - 1) / bytes_per_cluster - 1);
#endif /* FX_ENABLE_EXFAT */
#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. */
#ifdef FX_ENABLE_EXFAT
if (dir_entry.fx_dir_entry_dont_use_fat & 1)
{
status = _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_TRUE, 0,
media_ptr -> fx_media_fat_last, cluster, cluster + clusters_count);
}
else
{
#endif /* FX_ENABLE_EXFAT */
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);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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++;
#ifdef FX_ENABLE_EXFAT
if (dir_entry.fx_dir_entry_dont_use_fat & 1)
{
/* Check for file size range. */
if (cluster_count - 1 >= clusters_count)
{
contents = FX_LAST_CLUSTER_exFAT;
}
else
{
contents = cluster + 1;
}
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
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);
}
#ifdef FX_ENABLE_EXFAT
if (!(dir_entry.fx_dir_entry_dont_use_fat & 1))
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
#ifdef FX_ENABLE_EXFAT
}
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Mark the cluster as free. */
status = _fx_utility_exFAT_cluster_state_set(media_ptr, cluster, FX_EXFAT_BITMAP_CLUSTER_FREE);
/* 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);
}
}
#endif /* FX_ENABLE_EXFAT */
/* 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);
}

View File

@ -0,0 +1,869 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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_exFAT_bitmap_flush Flush exFAT allocation bitmap */
/* _fx_utility_exFAT_bitmap_free_cluster_find */
/* Find exFAT free cluster */
/* _fx_utility_exFAT_cluster_state_get Get cluster state */
/* _fx_utility_exFAT_cluster_state_set Set cluster state */
/* _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 */
/* */
/**************************************************************************/
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 FX_ENABLE_EXFAT
UCHAR cluster_state;
#endif /* FX_ENABLE_EXFAT */
#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;
#ifdef FX_ENABLE_EXFAT
if ((file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1) &&
(file_ptr -> fx_file_last_physical_cluster > FX_FAT_ENTRY_START) &&
(file_ptr -> fx_file_last_physical_cluster < media_ptr -> fx_media_total_clusters - clusters + FX_FAT_ENTRY_START))
{
found = FX_TRUE;
/* Try to keep clusters consecutive. */
for (FAT_index = file_ptr -> fx_file_last_physical_cluster + 1;
FAT_index < clusters + file_ptr -> fx_file_last_physical_cluster + 1;
FAT_index++)
{
/* Get cluster state. */
status = _fx_utility_exFAT_cluster_state_get(media_ptr, FAT_index, &cluster_state);
/* 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 (cluster_state == FX_EXFAT_BITMAP_CLUSTER_OCCUPIED)
{
found = FX_FALSE;
break;
}
}
FAT_index = file_ptr -> fx_file_last_physical_cluster + 1;
}
if (!found)
{
#endif /* FX_ENABLE_EXFAT */
while (FAT_index <= (media_ptr -> fx_media_total_clusters - clusters + FX_FAT_ENTRY_START))
{
/* Determine if enough consecutive FAT entries are available. */
i = 0;
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
do
{
/* Get cluster state. */
status = _fx_utility_exFAT_cluster_state_get(media_ptr, (FAT_index + i), &cluster_state);
/* 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 (cluster_state == FX_EXFAT_BITMAP_CLUSTER_OCCUPIED)
{
break;
}
/* Otherwise, increment the consecutive FAT indices. */
i++;
} while (i < clusters);
}
else
{
#endif /* FX_ENABLE_EXFAT */
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);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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
{
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Find free cluster from exFAT media. */
status = _fx_utility_exFAT_bitmap_free_cluster_find(media_ptr,
FAT_index + i + 1,
&FAT_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 (FAT_value < FAT_index + i + 1)
{
/* If we wrapped. */
FAT_index = media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START;
}
else
{
FAT_index = FAT_value;
}
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* Position to the next possibly free FAT entry. */
FAT_index = FAT_index + i + 1;
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
}
}
#ifdef FX_ENABLE_EXFAT
}
#endif
/* 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 */
#ifdef FX_ENABLE_EXFAT
if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
{
if ((file_ptr -> fx_file_total_clusters) &&
(FAT_index != file_ptr -> fx_file_last_physical_cluster + 1))
{
/* Clusters are not consecutive. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat &= (CHAR)0xfe; /* Set 0bit to 0 */
/* Rebuild FAT. */
FAT_value = file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster +
file_ptr -> fx_file_total_clusters - 1; /* Last cluster */
for (i = file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster; i < FAT_value; ++i)
{
status = _fx_utility_FAT_entry_write(media_ptr, i, i + 1);
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);
}
}
/* Close chain. */
status = _fx_utility_FAT_entry_write(media_ptr, FAT_value, media_ptr -> fx_media_fat_last);
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_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 stream. */
status = _fx_directory_exFAT_entry_write(
media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
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_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;
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
}
}
#endif /* FX_ENABLE_EXFAT */
/* Update the link pointers in the new clusters. */
for (i = 0; i < (clusters - 1); i++)
{
#ifdef FX_ENABLE_EXFAT
if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
#ifdef FX_ENABLE_FAULT_TOLERANT
|| (media_ptr -> fx_media_fault_tolerant_enabled == FX_TRUE)
#endif /* FX_ENABLE_FAULT_TOLERANT */
)
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
#ifdef FX_ENABLE_EXFAT
}
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Mark the cluster as used. */
status = _fx_utility_exFAT_cluster_state_set(media_ptr, FAT_index + i, FX_EXFAT_BITMAP_CLUSTER_OCCUPIED);
/* 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);
}
}
#endif /* FX_ENABLE_EXFAT */
}
#ifdef FX_ENABLE_EXFAT
if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
{
#endif /* FX_ENABLE_EXFAT */
/* 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_ENABLE_EXFAT
}
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Mark the cluster as used. */
status = _fx_utility_exFAT_cluster_state_set(media_ptr, FAT_index + clusters - 1, FX_EXFAT_BITMAP_CLUSTER_OCCUPIED);
/* 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);
}
}
#endif /* FX_ENABLE_EXFAT */
#ifdef FX_FAULT_TOLERANT
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
_fx_utility_exFAT_bitmap_flush(media_ptr);
}
#endif /* FX_ENABLE_EXFAT */
#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)
{
#ifdef FX_ENABLE_EXFAT
if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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;
#ifdef FX_ENABLE_EXFAT
if (file_ptr -> fx_file_current_available_size > (file_ptr -> fx_file_current_available_size + (bytes_per_cluster * clusters)))
{
/* 64-bit wrap around condition is present. Just set the available file size to all ones, which is
the maximum file size. */
file_ptr -> fx_file_current_available_size = 0xFFFFFFFFFFFFFFFFULL;
}
#endif /* FX_ENABLE_EXFAT */
/* Check for wrap-around when updating the available size. */
#ifdef FX_ENABLE_EXFAT
if ((media_ptr -> fx_media_FAT_type != FX_exFAT) &&
(file_ptr -> fx_file_current_available_size + (bytes_per_cluster * clusters) > 0xFFFFFFFFUL))
{
/* 32-bit wrap around condition is present. Just set the available file size to all ones, which is
the maximum file size. */
file_ptr -> fx_file_current_available_size = ((ULONG)0xFFFFFFFF);
}
else
{
/* Normal condition, update the available size. */
file_ptr -> fx_file_current_available_size =
file_ptr -> fx_file_current_available_size + (bytes_per_cluster * clusters);
}
#else
/* Update the available size. */
file_ptr -> fx_file_current_available_size =
file_ptr -> fx_file_current_available_size + (bytes_per_cluster * clusters);
#endif /* FX_ENABLE_EXFAT */
/* 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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(
media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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);
}

View File

@ -0,0 +1,916 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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_exFAT_bitmap_flush Flush exFAT allocation bitmap */
/* _fx_utility_exFAT_bitmap_free_cluster_find */
/* Find exFAT free cluster */
/* _fx_utility_exFAT_cluster_state_get Get cluster state */
/* _fx_utility_exFAT_cluster_state_set Set cluster state */
/* _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 */
/* */
/**************************************************************************/
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 FX_ENABLE_EXFAT
UCHAR cluster_state;
#endif /* FX_ENABLE_EXFAT */
#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;
#ifdef FX_ENABLE_EXFAT
if ((file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1) &&
(file_ptr -> fx_file_last_physical_cluster > FX_FAT_ENTRY_START) &&
(file_ptr -> fx_file_last_physical_cluster < media_ptr -> fx_media_total_clusters - clusters + FX_FAT_ENTRY_START))
{
found = FX_TRUE;
/* Try to keep clusters consecutive. */
for (FAT_index = file_ptr -> fx_file_last_physical_cluster + 1;
FAT_index < clusters + file_ptr -> fx_file_last_physical_cluster + 1;
FAT_index++)
{
/* Get cluster state. */
status = _fx_utility_exFAT_cluster_state_get(media_ptr, FAT_index, &cluster_state);
/* 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 (cluster_state == FX_EXFAT_BITMAP_CLUSTER_OCCUPIED)
{
found = FX_FALSE;
break;
}
}
FAT_index = file_ptr -> fx_file_last_physical_cluster + 1;
}
if (!found)
{
#endif /* FX_ENABLE_EXFAT */
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;
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
do
{
/* Get cluster state. */
status = _fx_utility_exFAT_cluster_state_get(media_ptr, (FAT_index + i), &cluster_state);
/* 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 (cluster_state == FX_EXFAT_BITMAP_CLUSTER_OCCUPIED)
{
break;
}
/* Otherwise, increment the consecutive FAT indices. */
i++;
} while ((i < clusters) && ((FAT_index + i) < media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START));
}
else
{
#endif /* FX_ENABLE_EXFAT */
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));
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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
{
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Find free cluster from exFAT media. */
status = _fx_utility_exFAT_bitmap_free_cluster_find(media_ptr,
FAT_index + i + 1,
&FAT_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 (FAT_value < FAT_index + i + 1)
{
/* If we wrapped. */
FAT_index = media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START;
}
else
{
FAT_index = FAT_value;
}
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* Position to the next possibly free FAT entry. */
FAT_index = FAT_index + i + 1;
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
}
}
/* 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;
}
#ifdef FX_ENABLE_EXFAT
}
#endif
/* 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 */
#ifdef FX_ENABLE_EXFAT
if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
{
if ((file_ptr -> fx_file_total_clusters) &&
(FAT_index != file_ptr -> fx_file_last_physical_cluster + 1))
{
/* Clusters are not consecutive. */
file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat &= (CHAR)0xfe; /* Set 0bit to 0. */
/* Rebuild FAT. */
FAT_value = file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster +
file_ptr -> fx_file_total_clusters - 1; /* Last cluster */
for (i = file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster; i < FAT_value; ++i)
{
status = _fx_utility_FAT_entry_write(media_ptr, i, i + 1);
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);
}
}
/* Close chain. */
status = _fx_utility_FAT_entry_write(media_ptr, FAT_value, media_ptr -> fx_media_fat_last);
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_ENABLE_FAULT_TOLERANT
if (media_ptr -> fx_media_fault_tolerant_enabled)
{
/* Clear the Fault Tolerant Set FAT Chain flag. */
media_ptr -> fx_media_fault_tolerant_state &= (UCHAR)(~FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN & 0xff);
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Update stream. */
status = _fx_directory_exFAT_entry_write(
media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
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_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;
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
}
}
#endif /* FX_ENABLE_EXFAT */
/* Update the link pointers in the new clusters. */
for (i = 0; i < (clusters - 1); i++)
{
#ifdef FX_ENABLE_EXFAT
if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
#ifdef FX_ENABLE_FAULT_TOLERANT
|| (media_ptr -> fx_media_fault_tolerant_enabled == FX_TRUE)
#endif /* FX_ENABLE_FAULT_TOLERANT */
)
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
#ifdef FX_ENABLE_EXFAT
}
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Mark the cluster as used. */
status = _fx_utility_exFAT_cluster_state_set(media_ptr, FAT_index + i, FX_EXFAT_BITMAP_CLUSTER_OCCUPIED);
/* 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);
}
}
#endif /* FX_ENABLE_EXFAT */
}
#ifdef FX_ENABLE_EXFAT
if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
{
#endif /* FX_ENABLE_EXFAT */
/* 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_ENABLE_EXFAT
}
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Mark the cluster as used. */
status = _fx_utility_exFAT_cluster_state_set(media_ptr, FAT_index + clusters - 1, FX_EXFAT_BITMAP_CLUSTER_OCCUPIED);
/* 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);
}
}
#endif /* FX_ENABLE_EXFAT */
#ifdef FX_FAULT_TOLERANT
/* Flush the cached individual FAT entries */
_fx_utility_FAT_flush(media_ptr);
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
_fx_utility_exFAT_bitmap_flush(media_ptr);
}
#endif /* FX_ENABLE_EXFAT */
#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)
{
#ifdef FX_ENABLE_EXFAT
if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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. */
#ifdef FX_ENABLE_EXFAT
if (file_ptr -> fx_file_current_available_size > (file_ptr -> fx_file_current_available_size + (bytes_per_cluster * clusters)))
{
/* 64-bit wrap around condition is present. Just set the available file size to all ones, which is
the maximum file size. */
file_ptr -> fx_file_current_available_size = 0xFFFFFFFFFFFFFFFFULL;
}
/* Check for wrap-around when updating the available size. */
if ((media_ptr -> fx_media_FAT_type != FX_exFAT) &&
(file_ptr -> fx_file_current_available_size + (bytes_per_cluster * clusters) > 0xFFFFFFFFUL))
{
/* 32-bit wrap around condition is present. Just set the available file size to all ones, which is
the maximum file size. */
file_ptr -> fx_file_current_available_size = 0xFFFFFFFFUL;
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* Normal condition, update the available size. */
file_ptr -> fx_file_current_available_size =
file_ptr -> fx_file_current_available_size + bytes_per_cluster * clusters;
#ifdef FX_ENABLE_EXFAT
}
if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
{
file_ptr -> fx_file_consecutive_cluster += clusters;
}
#endif /* FX_ENABLE_EXFAT */
/* 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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(
media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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);
}

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 */
/** */
/** 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.0 */
/* 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 */
/* */
/**************************************************************************/
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));
}
}
}

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 */
/** */
/** 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.0 */
/* 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 */
/* */
/**************************************************************************/
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)
{
#ifdef FX_ENABLE_EXFAT
if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
{
if (byte_offset == (ULONG64)file_ptr -> fx_file_consecutive_cluster * (ULONG64)bytes_per_cluster)
{
/* If the file bytes exactly fits the cluster size */
bytes_remaining = bytes_per_cluster;
file_ptr -> fx_file_current_relative_cluster = (ULONG)(byte_offset / bytes_per_cluster - 1);
file_ptr -> fx_file_current_physical_cluster =
file_ptr -> fx_file_first_physical_cluster + file_ptr -> fx_file_current_relative_cluster;
}
else
{
/* We shouldn't be here if don't using FAT! */
FX_UNPROTECT
return(FX_FILE_CORRUPT);
}
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
}
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);
}

View File

@ -0,0 +1,375 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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++;
#ifdef FX_ENABLE_EXFAT
if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
{
if (cluster >= file_ptr -> fx_file_last_physical_cluster)
{
contents = FX_LAST_CLUSTER_exFAT;
}
else
{
contents = cluster + 1;
}
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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);
}

View File

@ -0,0 +1,968 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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_exFAT_bitmap_flush Flush exFAT allocation bitmap */
/* _fx_utility_exFAT_cluster_state_set Set cluster state */
/* _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 */
/* */
/**************************************************************************/
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;
#ifdef FX_ENABLE_EXFAT
ULONG original_last_physical_cluster;
#endif /* FX_ENABLE_EXFAT */
#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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(
media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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++;
#ifdef FX_ENABLE_EXFAT
if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
{
if (cluster >= file_ptr -> fx_file_last_physical_cluster)
{
contents = FX_LAST_CLUSTER_exFAT;
}
else
{
contents = cluster + 1;
}
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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_EXFAT
original_last_physical_cluster = file_ptr -> fx_file_last_physical_cluster;
#endif /* FX_ENABLE_EXFAT */
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Is this the last used cluster? */
if ((cluster_count == 0) && (media_ptr -> fx_media_fault_tolerant_enabled))
{
#ifdef FX_ENABLE_EXFAT
if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
#ifdef FX_ENABLE_EXFAT
}
else
{
/* Set undo log. */
status = _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_TRUE, FX_FREE_CLUSTER,
media_ptr -> fx_media_fat_last, cluster, file_ptr -> fx_file_last_physical_cluster + 1);
/* 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_EXFAT && FX_ENABLE_FAULT_TOLERANT */
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))
{
#ifdef FX_ENABLE_EXFAT
if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
{
if (cluster >= original_last_physical_cluster)
{
contents = FX_LAST_CLUSTER_exFAT;
}
else
{
contents = cluster + 1;
}
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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_EXFAT
if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
#endif /* FX_ENABLE_EXFAT */
{
#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 */
}
#if defined(FX_ENABLE_EXFAT) && defined(FX_ENABLE_FAULT_TOLERANT)
else if (media_ptr -> fx_media_fault_tolerant_enabled)
{
/* Set undo log. */
status = _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_TRUE, cluster,
media_ptr -> fx_media_fat_last, contents, file_ptr -> fx_file_last_physical_cluster + 1);
/* 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_EXFAT && 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 */
#ifdef FX_ENABLE_EXFAT
if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
{
#endif /* FX_ENABLE_EXFAT */
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);
}
#ifdef FX_ENABLE_EXFAT
}
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* Mark the cluster as free. */
_fx_utility_exFAT_cluster_state_set(media_ptr, cluster, FX_EXFAT_BITMAP_CLUSTER_FREE);
}
#endif /* FX_ENABLE_EXFAT */
#ifdef FX_ENABLE_FAULT_TOLERANT
}
#endif /* FX_ENABLE_FAULT_TOLERANT */
/* Increment the number of available clusters. */
media_ptr -> fx_media_available_clusters++;
}
/* 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++;
#ifdef FX_ENABLE_EXFAT
if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
{
if (cluster >= file_ptr -> fx_file_last_physical_cluster)
{
contents = FX_LAST_CLUSTER_exFAT;
}
else
{
contents = cluster + 1;
}
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
#ifdef FX_ENABLE_EXFAT
/* Flush Bit Map. */
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
_fx_utility_exFAT_bitmap_flush(media_ptr);
}
#endif /* FX_ENABLE_EXFAT */
#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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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);
}

586
common/src/fx_file_open.c Normal file
View File

@ -0,0 +1,586 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
UINT _fx_file_open(FX_MEDIA *media_ptr, FX_FILE *file_ptr, CHAR *file_name, UINT open_type)
{
UINT status, leading_consecutive;
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;
UINT 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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
fat_last = FX_LAST_CLUSTER_exFAT;
not_a_file_attr = FX_DIRECTORY;
}
else if (media_ptr -> fx_media_FAT_type == FX_FAT32)
#else
if (media_ptr -> fx_media_32_bit_FAT)
#endif /* FX_ENABLE_EXFAT */
{
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;
}
/* 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;
}
/* 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;
leading_consecutive = 1;
file_ptr -> fx_file_consecutive_cluster = 1;
/* 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;
#ifdef FX_ENABLE_EXFAT
if (bytes_remaining && (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
{
cluster_count =
(ULONG)((file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size + bytes_per_cluster - 1) /
bytes_per_cluster);
file_ptr -> fx_file_consecutive_cluster = cluster_count;
}
#endif /* FX_ENABLE_EXFAT */
}
else
{
#ifdef FX_ENABLE_EXFAT
/* File is open for writing... walk the FAT chain to position to the end. */
if (bytes_remaining && (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
{
cluster_count =
(ULONG)((file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size + bytes_per_cluster - 1) /
bytes_per_cluster);
last_cluster = cluster + cluster_count - 1;
file_ptr -> fx_file_consecutive_cluster = cluster_count;
file_ptr -> fx_file_current_physical_cluster = last_cluster;
file_ptr -> fx_file_current_relative_cluster = cluster_count - 1;
bytes_remaining %= bytes_per_cluster;
if (!bytes_remaining)
{
if (file_ptr -> fx_file_dir_entry.fx_dir_entry_available_file_size >
file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size)
{
file_ptr -> fx_file_current_physical_cluster = last_cluster + 1;
file_ptr -> fx_file_current_relative_cluster++;
}
else
{
bytes_remaining = bytes_per_cluster;
}
}
bytes_available =
(ULONG)((file_ptr -> fx_file_dir_entry.fx_dir_entry_available_file_size + bytes_per_cluster - 1) /
bytes_per_cluster);
bytes_available *= bytes_per_cluster;
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
/* 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;
}
/* 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);
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
}
/* 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);
}

460
common/src/fx_file_read.c Normal file
View File

@ -0,0 +1,460 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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) +
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)
{
#ifdef FX_ENABLE_EXFAT
if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
{
cluster++;
}
else
{
#endif /* FX_ENABLE_EXFAT */
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;
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
}
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);
}
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)
{
#ifdef FX_ENABLE_EXFAT
if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
{
next_cluster = file_ptr -> fx_file_current_physical_cluster + 1;
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
}
}
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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);
}

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_relative_seek PORTABLE C */
/* 6.0 */
/* 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 */
/* */
/**************************************************************************/
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));
}

596
common/src/fx_file_rename.c Normal file
View File

@ -0,0 +1,596 @@
/**************************************************************************/
/* */
/* 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_EXFAT
#include "fx_directory_exFAT.h"
#endif /* FX_ENABLE_EXFAT */
#ifdef FX_ENABLE_FAULT_TOLERANT
#include "fx_fault_tolerant.h"
#endif /* FX_ENABLE_FAULT_TOLERANT */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_file_rename PORTABLE C */
/* 6.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
not_a_file_attr = FX_DIRECTORY;
}
else
{
#endif /* FX_ENABLE_EXFAT */
not_a_file_attr = FX_DIRECTORY | FX_VOLUME;
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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;
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
new_dir_entry.fx_dir_entry_dont_use_fat = old_dir_entry.fx_dir_entry_dont_use_fat;
new_dir_entry.fx_dir_entry_type = old_dir_entry.fx_dir_entry_type;
new_dir_entry.fx_dir_entry_available_file_size = old_dir_entry.fx_dir_entry_available_file_size;
new_dir_entry.fx_dir_entry_secondary_count = old_dir_entry.fx_dir_entry_secondary_count;
}
#endif /* FX_ENABLE_EXFAT */
/* 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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(media_ptr, &new_dir_entry, UPDATE_FULL);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &new_dir_entry);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(media_ptr, &old_dir_entry, UPDATE_DELETE);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &old_dir_entry);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
#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);
}

78
common/src/fx_file_seek.c Normal file
View File

@ -0,0 +1,78 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
UINT _fx_file_seek(FX_FILE *file_ptr, ULONG byte_offset)
{
return(_fx_file_extended_seek(file_ptr, (ULONG64) byte_offset));
}

View File

@ -0,0 +1,78 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
UINT _fx_file_truncate(FX_FILE *file_ptr, ULONG size)
{
return(_fx_file_extended_truncate(file_ptr, (ULONG64)size));
}

View File

@ -0,0 +1,80 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
UINT _fx_file_truncate_release(FX_FILE *file_ptr, ULONG size)
{
return(_fx_file_extended_truncate_release(file_ptr, (ULONG64)size));
}

1767
common/src/fx_file_write.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,81 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}

187
common/src/fx_media_abort.c Normal file
View File

@ -0,0 +1,187 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}

View File

@ -0,0 +1,320 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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)
#ifdef FX_ENABLE_EXFAT
{
/* Treat as exFAT volume. */
/* Extract the number of bytes per sector. */
media_ptr -> fx_media_exfat_bytes_per_sector_shift = boot_sector[FX_EF_BYTE_PER_SECTOR_SHIFT];
/* exFAT requires minimal value 9 (512 bytes) and maximum value 12(4096 bytes) for bytes_per_sector_shift */
if((media_ptr -> fx_media_exfat_bytes_per_sector_shift < 9) || (media_ptr -> fx_media_exfat_bytes_per_sector_shift > 12))
{
return(FX_MEDIA_INVALID);
}
media_ptr -> fx_media_bytes_per_sector = (UINT)(1 << media_ptr -> fx_media_exfat_bytes_per_sector_shift);
media_ptr -> fx_media_total_sectors = _fx_utility_64_unsigned_read(&boot_sector[FX_EF_VOLUME_LENGTH]);
if (media_ptr -> fx_media_total_sectors == 0)
{
return(FX_MEDIA_INVALID);
}
media_ptr -> fx_media_reserved_sectors = _fx_utility_32_unsigned_read(&boot_sector[FX_EF_FAT_OFFSET]);
if (media_ptr -> fx_media_reserved_sectors == 0)
{
return(FX_MEDIA_INVALID);
}
media_ptr -> fx_media_sectors_per_FAT = _fx_utility_32_unsigned_read(&boot_sector[FX_EF_FAT_LENGTH]);
if (media_ptr -> fx_media_sectors_per_FAT == 0)
{
return(FX_MEDIA_INVALID);
}
media_ptr -> fx_media_data_sector_start = _fx_utility_32_unsigned_read(&boot_sector[FX_EF_CLUSTER_HEAP_OFFSET]);
if (media_ptr -> fx_media_data_sector_start == 0)
{
return(FX_MEDIA_INVALID);
}
media_ptr -> fx_media_total_clusters = _fx_utility_32_unsigned_read(&boot_sector[FX_EF_CLUSTER_COUNT]);
if (media_ptr -> fx_media_total_clusters == 0)
{
return(FX_MEDIA_INVALID);
}
media_ptr -> fx_media_exfat_sector_per_clusters_shift = boot_sector[FX_EF_SECTOR_PER_CLUSTER_SHIFT];
if (media_ptr -> fx_media_exfat_sector_per_clusters_shift > 25 - media_ptr -> fx_media_exfat_bytes_per_sector_shift)
{
return(FX_MEDIA_INVALID);
}
media_ptr -> fx_media_sectors_per_cluster = (UINT)(1 << media_ptr -> fx_media_exfat_sector_per_clusters_shift);
media_ptr -> fx_media_number_of_FATs = boot_sector[FX_EF_NUMBER_OF_FATS];
if (media_ptr -> fx_media_number_of_FATs == 0)
{
return(FX_MEDIA_INVALID);
}
media_ptr -> fx_media_root_cluster_32 = _fx_utility_32_unsigned_read(&boot_sector[FX_EF_FIRST_CLUSTER_OF_ROOT_DIR]);
/* Root cluster starts from at least FX_FAT_ENTRY_START (2), or higher. */
if (media_ptr -> fx_media_root_cluster_32 < FX_FAT_ENTRY_START)
{
return(FX_MEDIA_INVALID);
}
/* Overflow check. */
if (((ULONG64)media_ptr -> fx_media_data_sector_start +
(ULONG64)(media_ptr -> fx_media_root_cluster_32 - FX_FAT_ENTRY_START) *
media_ptr -> fx_media_sectors_per_cluster) > 0xFFFFFFFF)
{
/* Return the invalid media error status. */
return(FX_MEDIA_INVALID);
}
/* Calculate logical number of root dir sector. */
media_ptr -> fx_media_root_sector_start = media_ptr -> fx_media_data_sector_start +
(media_ptr -> fx_media_root_cluster_32 - FX_FAT_ENTRY_START) *
media_ptr -> fx_media_sectors_per_cluster;
media_ptr -> fx_media_exfat_volume_serial_number = _fx_utility_32_unsigned_read(&boot_sector[FX_EF_VOLUME_SERIAL_NUMBER]);
media_ptr -> fx_media_exfat_file_system_revision = _fx_utility_16_unsigned_read(&boot_sector[FX_EF_FILE_SYSTEM_REVISION]);
media_ptr -> fx_media_exfat_volume_flag = _fx_utility_16_unsigned_read(&boot_sector[FX_EF_VOLUME_FLAGS]);
media_ptr -> fx_media_number_of_FATs = boot_sector[FX_EF_NUMBER_OF_FATS];
if (0 == media_ptr -> fx_media_number_of_FATs)
{
return(FX_MEDIA_INVALID);
}
/* 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_EF_PARTITION_OFFSET]);
#else
media_ptr -> fx_media_hidden_sectors = _fx_utility_32_unsigned_read(&boot_sector[FX_EF_PARTITION_OFFSET]);
#endif
media_ptr -> fx_media_exfat_drive_select = boot_sector[FX_EF_DRIVE_SELECT];
media_ptr -> fx_media_exfat_percent_in_use = boot_sector[FX_EF_PERCENT_IN_USE];
media_ptr -> fx_media_12_bit_FAT = FX_FALSE;
media_ptr -> fx_media_32_bit_FAT = FX_FALSE;
/* Legacy code support:
We will use fx_media_FAT_type for determine FAT type instead of
fx_media_12_bit_FAT and fx_media_32_bit_FAT. */
media_ptr -> fx_media_12_bit_FAT = FX_FALSE;
media_ptr -> fx_media_32_bit_FAT = FX_FALSE;
media_ptr -> fx_media_FAT_type = FX_exFAT;
return(_fx_utility_exFAT_geometry_check(media_ptr, boot_sector));
}
else
{
#else
return(FX_MEDIA_INVALID);
#endif /* FX_ENABLE_EXFAT */
/* 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]);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* Return a successful status. */
return(FX_SUCCESS);
}

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 */
/** */
/** 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}

828
common/src/fx_media_check.c Normal file
View File

@ -0,0 +1,828 @@
/**************************************************************************/
/* */
/* 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"
#ifdef FX_ENABLE_EXFAT
#include "fx_directory_exFAT.h"
#endif /* FX_ENABLE_EXFAT */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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
#ifdef FX_ENABLE_EXFAT
current_errors = 0;
#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_EXFAT
/* Mark the clusters occupied by Allocation Bitmap table, Up-cast table and the first cluster of root directory. */
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
ULONG offset = 0;
for (i = ((media_ptr -> fx_media_root_cluster_32 - FX_FAT_ENTRY_START) >> 3); i; i--)
{
logical_fat[offset++] = 0xff;
}
for (i = ((media_ptr -> fx_media_root_cluster_32 - FX_FAT_ENTRY_START) & 7); i; i--)
{
logical_fat[offset] = (UCHAR)((logical_fat[offset] << 1) | 0x1);
}
}
#endif /* FX_ENABLE_EXFAT */
#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;
#ifdef FX_ENABLE_EXFAT
/* For the index of the first cluster in exFAT is 2, adjust the number of clusters to fit Allocation Bitmap Table. */
/* We will compare logical_fat with Aollcation Bitmap table later to find out lost clusters. */
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
cluster_number = cluster - FX_FAT_ENTRY_START;
}
#endif /* FX_ENABLE_EXFAT */
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. */
#ifdef FX_ENABLE_EXFAT
if ((media_ptr -> fx_media_FAT_type == FX_FAT32) ||
(media_ptr -> fx_media_FAT_type == FX_exFAT))
#else
if (media_ptr -> fx_media_32_bit_FAT)
#endif /* FX_ENABLE_EXFAT */
{
/* 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. */
#ifdef FX_ENABLE_EXFAT
/* Hash value of the file name is not cared. */
status = _fx_directory_entry_read_ex(media_ptr, temp_dir_ptr, &i, dir_entry_ptr, 0);
#else
status = _fx_directory_entry_read(media_ptr, temp_dir_ptr, &i, dir_entry_ptr);
#endif /* FX_ENABLE_EXFAT */
/* Determine if the read was successful. */
if (status)
{
/* Release media protection. */
FX_UNPROTECT
/* Return the error code. */
return(status);
}
/* Check for the last entry. */
#ifdef FX_ENABLE_EXFAT
if (dir_entry_ptr -> fx_dir_entry_type == FX_EXFAT_DIR_ENTRY_TYPE_END_MARKER)
#else
if (dir_entry_ptr -> fx_dir_entry_name[0] == (CHAR)FX_DIR_ENTRY_DONE)
#endif /* FX_ENABLE_EXFAT */
{
/* Last entry in this directory - no need to check further. */
break;
}
/* Is the entry free? */
#ifdef FX_ENABLE_EXFAT
if (dir_entry_ptr -> fx_dir_entry_type != FX_EXFAT_DIR_ENTRY_TYPE_FILE_DIRECTORY)
#else
if ((dir_entry_ptr -> fx_dir_entry_name[0] == (CHAR)FX_DIR_ENTRY_FREE) && (dir_entry_ptr -> fx_dir_entry_short_name[0] == 0))
#endif /* FX_ENABLE_EXFAT */
{
/* A deleted entry */
i++;
continue;
}
#ifdef FX_ENABLE_EXFAT
/* Determine whether FAT chain is used. */
if (dir_entry_ptr -> fx_dir_entry_dont_use_fat & 1)
{
ULONG64 remaining_size = dir_entry_ptr -> fx_dir_entry_file_size;
ULONG cluster = dir_entry_ptr -> fx_dir_entry_cluster, cluster_number;
valid_clusters = 0;
while (remaining_size)
{
if (remaining_size >= bytes_per_cluster)
{
remaining_size -= bytes_per_cluster;
}
else
{
remaining_size = 0;
last_cluster = cluster;
}
cluster_number = cluster - FX_FAT_ENTRY_START;
/* Is the current cluster already marked? */
if ((logical_fat[cluster_number / 8] >> (cluster_number % 8)) & 0x01)
{
current_errors = FX_FILE_SIZE_ERROR;
last_cluster = dir_entry_ptr -> fx_dir_entry_cluster + valid_clusters;
break;
}
/* Mark the current cluster. */
logical_fat[cluster_number >> 3] = (UCHAR)(logical_fat[cluster_number >> 3] | (1 << (cluster_number & 7)));
valid_clusters++;
cluster++;
}
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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;
#ifdef FX_ENABLE_EXFAT
/* For exFAT, there is no dir-entries for ".." and ".". */
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
current_directory[current_directory_index].current_directory_entry = 0;
i = 0;
}
#endif /* FX_ENABLE_EXFAT */
}
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);
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
/* If exFAT is in use, compare the logical_fat with Allocation Bitmap Table directly. */
current_errors = _fx_media_check_exFAT_lost_cluster_check(media_ptr, logical_fat, media_ptr -> fx_media_total_clusters, error_correction_option);
}
else
{
#endif /* FX_ENABLE_EXFAT */
/* 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);
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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);
}

View File

@ -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_FAT_chain_check PORTABLE C */
/* 6.0 */
/* 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 */
/* */
/**************************************************************************/
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;
#ifdef FX_ENABLE_EXFAT
/* For the index of the first cluster in exFAT is 2, adjust the number of clusters to fit Allocation Bitmap Table. */
/* We will compare logical_fat with Aollcation Bitmap table later to find out lost clusters. */
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
cluster_number = cluster - FX_FAT_ENTRY_START;
}
#endif /* FX_ENABLE_EXFAT */
/* 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);
}

View File

@ -0,0 +1,278 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}
#ifdef FX_ENABLE_EXFAT
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_media_check_exFAT_lost_cluster_check PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function examines all clusters in exFAT to see if there are */
/* any unused clusters that are also unavailable. */
/* */
/* 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_exFAT_bitmap_flush Flush dirty bitmap clusters */
/* _fx_utility_exFAT_bitmap_cache_update Cache bitmap clusters */
/* */
/* CALLED BY */
/* */
/* _fx_check_media Check media function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
ULONG _fx_media_check_exFAT_lost_cluster_check(FX_MEDIA *media_ptr, UCHAR *logical_fat, ULONG total_clusters, ULONG error_correction_option)
{
ULONG cluster = FX_FAT_ENTRY_START;
ULONG cached_bitmap_bytes = media_ptr -> fx_media_exfat_bitmap_cache_size_in_sectors * media_ptr -> fx_media_bytes_per_sector;
ULONG cached_bitmap_bits = cached_bitmap_bytes << 3;
ULONG offset = 0;
UINT status, i;
/* This parameter has not been supported yet. */
FX_PARAMETER_NOT_USED(error_correction_option);
/* Flush Allocation Bitmap Table first. */
status = _fx_utility_exFAT_bitmap_flush(media_ptr);
if (FX_SUCCESS != status)
{
return(status);
}
while (total_clusters)
{
/* Read Allocation Bitmap Table from disk. */
status = _fx_utility_exFAT_bitmap_cache_update(media_ptr, cluster);
if (FX_SUCCESS != status)
{
return(status);
}
if (total_clusters >= cached_bitmap_bits)
{
total_clusters -= cached_bitmap_bits;
/* Compare cached bitmap with logical_fat. */
for (i = 0; i < media_ptr -> fx_media_bytes_per_sector; i++)
{
if (logical_fat[offset + i] != ((UCHAR *)(media_ptr -> fx_media_exfat_bitmap_cache))[i])
{
return(FX_LOST_CLUSTER_ERROR);
}
offset += cached_bitmap_bytes;
cluster += cached_bitmap_bits;
}
}
else
{
/* Compare cached bitmap with logical_fat. */
for (i = 0; i < ((total_clusters + 7) >> 3); i++)
{
if (logical_fat[offset + i] != ((UCHAR *)(media_ptr -> fx_media_exfat_bitmap_cache))[i])
{
return(FX_LOST_CLUSTER_ERROR);
}
}
total_clusters = 0;
}
}
return(FX_SUCCESS);
}
#endif /* FX_ENABLE_EXFAT */

433
common/src/fx_media_close.c Normal file
View File

@ -0,0 +1,433 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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_exFAT_bitmap_flush Flush exFAT allocation bitmap */
/* _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 */
/* */
/**************************************************************************/
UINT _fx_media_close(FX_MEDIA *media_ptr)
{
FX_INT_SAVE_AREA
ULONG open_count;
FX_FILE *file_ptr;
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
/* 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. */
#ifdef FX_ENABLE_EXFAT
if (media_ptr -> fx_media_FAT_type == FX_exFAT)
{
status = _fx_directory_exFAT_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
}
else
{
#endif /* FX_ENABLE_EXFAT */
status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
#ifdef FX_ENABLE_EXFAT
}
#endif /* FX_ENABLE_EXFAT */
/* 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--;
}
/* 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);
#ifdef FX_ENABLE_EXFAT
if ((media_ptr -> fx_media_FAT_type == FX_exFAT) &&
(FX_TRUE == media_ptr -> fx_media_exfat_bitmap_cache_dirty))
{
/* Flush bitmap. */
_fx_utility_exFAT_bitmap_flush(media_ptr);
}
#endif /* FX_ENABLE_EXFAT */
/* 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;
/* 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;
/* 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);
}

View File

@ -0,0 +1,80 @@
/**************************************************************************/
/* */
/* 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.0 */
/* 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 */
/* */
/**************************************************************************/
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);
}

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