mirror of
https://github.com/azure-rtos/filex.git
synced 2025-01-25 01:32:54 +08:00
Initial commit
This commit is contained in:
commit
2d93b0a9a0
40
.gitattributes
vendored
Normal file
40
.gitattributes
vendored
Normal 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
14
.gitignore
vendored
Executable 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
49
CMakeLists.txt
Executable 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
246
LICENSE.txt
Normal 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 Microsoft’s 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
|
||||
Microsoft’s 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 Microsoft’s 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
|
||||
Microsoft’s 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
|
||||
n’accorde 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, d’adéquation à un usage particulier
|
||||
et d’absence 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 d’une autre faute dans la limite
|
||||
autorisée par la loi en vigueur.
|
||||
|
||||
Elle s’applique également, même si Microsoft connaissait ou devrait connaître
|
||||
l’éventualité d’un tel dommage. Si votre pays n’autorise pas l’exclusion ou la
|
||||
limitation de responsabilité pour les dommages indirects, accessoires ou de
|
||||
quelque nature que ce soit, il se peut que la limitation ou l’exclusion
|
||||
ci-dessus ne s’appliquera pas à votre égard.
|
||||
|
||||
EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous
|
||||
pourriez avoir d’autres 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
16
LICENSED-HARDWARE.txt
Normal 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.
|
246
common/CMakeLists.txt
Normal file
246
common/CMakeLists.txt
Normal 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
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
135
common/inc/fx_directory.h
Normal 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
|
||||
|
159
common/inc/fx_directory_exFAT.h
Normal file
159
common/inc/fx_directory_exFAT.h
Normal 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
|
||||
|
412
common/inc/fx_fault_tolerant.h
Normal file
412
common/inc/fx_fault_tolerant.h
Normal 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
107
common/inc/fx_file.h
Normal 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
112
common/inc/fx_media.h
Normal 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
173
common/inc/fx_system.h
Normal 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
108
common/inc/fx_unicode.h
Normal 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
179
common/inc/fx_user_sample.h
Normal 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
119
common/inc/fx_utility.h
Normal 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
|
||||
|
154
common/src/fx_directory_attributes_read.c
Normal file
154
common/src/fx_directory_attributes_read.c
Normal 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);
|
||||
}
|
||||
|
203
common/src/fx_directory_attributes_set.c
Normal file
203
common/src/fx_directory_attributes_set.c
Normal 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);
|
||||
}
|
||||
|
902
common/src/fx_directory_create.c
Normal file
902
common/src/fx_directory_create.c
Normal 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);
|
||||
}
|
||||
|
104
common/src/fx_directory_default_get.c
Normal file
104
common/src/fx_directory_default_get.c
Normal 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);
|
||||
}
|
||||
|
118
common/src/fx_directory_default_get_copy.c
Normal file
118
common/src/fx_directory_default_get_copy.c
Normal 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);
|
||||
}
|
||||
|
451
common/src/fx_directory_default_set.c
Normal file
451
common/src/fx_directory_default_set.c
Normal 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);
|
||||
}
|
||||
|
587
common/src/fx_directory_delete.c
Normal file
587
common/src/fx_directory_delete.c
Normal 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);
|
||||
}
|
||||
|
784
common/src/fx_directory_entry_read.c
Normal file
784
common/src/fx_directory_entry_read.c
Normal 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 */
|
||||
|
1148
common/src/fx_directory_entry_write.c
Normal file
1148
common/src/fx_directory_entry_write.c
Normal file
File diff suppressed because it is too large
Load Diff
716
common/src/fx_directory_exFAT_entry_read.c
Normal file
716
common/src/fx_directory_exFAT_entry_read.c
Normal 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
|
||||
|
100
common/src/fx_directory_exFAT_entry_write.c
Normal file
100
common/src/fx_directory_exFAT_entry_write.c
Normal 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
|
||||
|
507
common/src/fx_directory_exFAT_free_search.c
Normal file
507
common/src/fx_directory_exFAT_free_search.c
Normal 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 */
|
||||
|
944
common/src/fx_directory_exFAT_unicode_entry_write.c
Normal file
944
common/src/fx_directory_exFAT_unicode_entry_write.c
Normal 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
|
||||
|
134
common/src/fx_directory_first_entry_find.c
Normal file
134
common/src/fx_directory_first_entry_find.c
Normal 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);
|
||||
}
|
||||
|
144
common/src/fx_directory_first_full_entry_find.c
Normal file
144
common/src/fx_directory_first_full_entry_find.c
Normal 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);
|
||||
}
|
||||
|
776
common/src/fx_directory_free_search.c
Normal file
776
common/src/fx_directory_free_search.c
Normal 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);
|
||||
}
|
||||
|
232
common/src/fx_directory_information_get.c
Normal file
232
common/src/fx_directory_information_get.c
Normal 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);
|
||||
}
|
||||
|
112
common/src/fx_directory_local_path_clear.c
Normal file
112
common/src/fx_directory_local_path_clear.c
Normal 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
|
||||
}
|
||||
|
123
common/src/fx_directory_local_path_get.c
Normal file
123
common/src/fx_directory_local_path_get.c
Normal 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
|
||||
}
|
||||
|
120
common/src/fx_directory_local_path_get_copy.c
Normal file
120
common/src/fx_directory_local_path_get_copy.c
Normal 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);
|
||||
}
|
||||
|
111
common/src/fx_directory_local_path_restore.c
Normal file
111
common/src/fx_directory_local_path_restore.c
Normal 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
|
||||
}
|
||||
|
445
common/src/fx_directory_local_path_set.c
Normal file
445
common/src/fx_directory_local_path_set.c
Normal 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
|
||||
}
|
||||
|
83
common/src/fx_directory_long_name_get.c
Normal file
83
common/src/fx_directory_long_name_get.c
Normal 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));
|
||||
}
|
||||
|
137
common/src/fx_directory_long_name_get_extended.c
Normal file
137
common/src/fx_directory_long_name_get_extended.c
Normal 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);
|
||||
}
|
||||
|
159
common/src/fx_directory_name_extract.c
Normal file
159
common/src/fx_directory_name_extract.c
Normal 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);
|
||||
}
|
||||
|
141
common/src/fx_directory_name_test.c
Normal file
141
common/src/fx_directory_name_test.c
Normal 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);
|
||||
}
|
||||
|
469
common/src/fx_directory_next_entry_find.c
Normal file
469
common/src/fx_directory_next_entry_find.c
Normal 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);
|
||||
}
|
||||
|
571
common/src/fx_directory_next_full_entry_find.c
Normal file
571
common/src/fx_directory_next_full_entry_find.c
Normal 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);
|
||||
}
|
||||
|
521
common/src/fx_directory_rename.c
Normal file
521
common/src/fx_directory_rename.c
Normal 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);
|
||||
}
|
||||
|
965
common/src/fx_directory_search.c
Normal file
965
common/src/fx_directory_search.c
Normal 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);
|
||||
}
|
||||
|
83
common/src/fx_directory_short_name_get.c
Normal file
83
common/src/fx_directory_short_name_get.c
Normal 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));
|
||||
}
|
||||
|
168
common/src/fx_directory_short_name_get_extended.c
Normal file
168
common/src/fx_directory_short_name_get_extended.c
Normal 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);
|
||||
}
|
||||
|
111
common/src/fx_fault_tolerant_add_FAT_log.c
Normal file
111
common/src/fx_fault_tolerant_add_FAT_log.c
Normal 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 */
|
||||
|
112
common/src/fx_fault_tolerant_add_bitmap_log.c
Normal file
112
common/src/fx_fault_tolerant_add_bitmap_log.c
Normal 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 */
|
||||
|
153
common/src/fx_fault_tolerant_add_checksum_log.c
Normal file
153
common/src/fx_fault_tolerant_add_checksum_log.c
Normal 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 */
|
||||
|
130
common/src/fx_fault_tolerant_add_dir_log.c
Normal file
130
common/src/fx_fault_tolerant_add_dir_log.c
Normal 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 */
|
||||
|
327
common/src/fx_fault_tolerant_apply_logs.c
Normal file
327
common/src/fx_fault_tolerant_apply_logs.c
Normal 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 */
|
||||
|
101
common/src/fx_fault_tolerant_calculate_checksum.c
Normal file
101
common/src/fx_fault_tolerant_calculate_checksum.c
Normal 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 */
|
||||
|
290
common/src/fx_fault_tolerant_cleanup_FAT_chain.c
Normal file
290
common/src/fx_fault_tolerant_cleanup_FAT_chain.c
Normal 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 */
|
||||
|
410
common/src/fx_fault_tolerant_create_log_file.c
Normal file
410
common/src/fx_fault_tolerant_create_log_file.c
Normal 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 */
|
||||
|
517
common/src/fx_fault_tolerant_enable.c
Normal file
517
common/src/fx_fault_tolerant_enable.c
Normal 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 */
|
||||
|
191
common/src/fx_fault_tolerant_read_FAT.c
Normal file
191
common/src/fx_fault_tolerant_read_FAT.c
Normal 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 */
|
||||
|
170
common/src/fx_fault_tolerant_read_directory_sector.c
Normal file
170
common/src/fx_fault_tolerant_read_directory_sector.c
Normal 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 */
|
||||
|
91
common/src/fx_fault_tolerant_read_log_file.c
Normal file
91
common/src/fx_fault_tolerant_read_log_file.c
Normal 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 */
|
||||
|
166
common/src/fx_fault_tolerant_recover.c
Normal file
166
common/src/fx_fault_tolerant_recover.c
Normal 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 */
|
||||
|
140
common/src/fx_fault_tolerant_reset_log_file.c
Normal file
140
common/src/fx_fault_tolerant_reset_log_file.c
Normal 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 */
|
||||
|
131
common/src/fx_fault_tolerant_set_FAT_chain.c
Normal file
131
common/src/fx_fault_tolerant_set_FAT_chain.c
Normal 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 */
|
||||
|
205
common/src/fx_fault_tolerant_transaction_end.c
Normal file
205
common/src/fx_fault_tolerant_transaction_end.c
Normal 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 */
|
||||
|
103
common/src/fx_fault_tolerant_transaction_fail.c
Normal file
103
common/src/fx_fault_tolerant_transaction_fail.c
Normal 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
|
113
common/src/fx_fault_tolerant_transaction_start.c
Normal file
113
common/src/fx_fault_tolerant_transaction_start.c
Normal 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 */
|
||||
|
110
common/src/fx_fault_tolerant_write_log_file.c
Normal file
110
common/src/fx_fault_tolerant_write_log_file.c
Normal 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 */
|
||||
|
79
common/src/fx_file_allocate.c
Normal file
79
common/src/fx_file_allocate.c
Normal 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));
|
||||
}
|
||||
|
167
common/src/fx_file_attributes_read.c
Normal file
167
common/src/fx_file_attributes_read.c
Normal 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);
|
||||
}
|
||||
|
241
common/src/fx_file_attributes_set.c
Normal file
241
common/src/fx_file_attributes_set.c
Normal 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);
|
||||
}
|
||||
|
95
common/src/fx_file_best_effort_allocate.c
Normal file
95
common/src/fx_file_best_effort_allocate.c
Normal 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
196
common/src/fx_file_close.c
Normal 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
390
common/src/fx_file_create.c
Normal 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);
|
||||
}
|
||||
|
146
common/src/fx_file_date_time_set.c
Normal file
146
common/src/fx_file_date_time_set.c
Normal 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
475
common/src/fx_file_delete.c
Normal 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);
|
||||
}
|
||||
|
869
common/src/fx_file_extended_allocate.c
Normal file
869
common/src/fx_file_extended_allocate.c
Normal 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);
|
||||
}
|
||||
|
916
common/src/fx_file_extended_best_effort_allocate.c
Normal file
916
common/src/fx_file_extended_best_effort_allocate.c
Normal 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);
|
||||
}
|
||||
|
161
common/src/fx_file_extended_relative_seek.c
Normal file
161
common/src/fx_file_extended_relative_seek.c
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
323
common/src/fx_file_extended_seek.c
Normal file
323
common/src/fx_file_extended_seek.c
Normal 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);
|
||||
}
|
||||
|
375
common/src/fx_file_extended_truncate.c
Normal file
375
common/src/fx_file_extended_truncate.c
Normal 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);
|
||||
}
|
||||
|
968
common/src/fx_file_extended_truncate_release.c
Normal file
968
common/src/fx_file_extended_truncate_release.c
Normal 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
586
common/src/fx_file_open.c
Normal 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
460
common/src/fx_file_read.c
Normal 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);
|
||||
}
|
||||
|
84
common/src/fx_file_relative_seek.c
Normal file
84
common/src/fx_file_relative_seek.c
Normal 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
596
common/src/fx_file_rename.c
Normal 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
78
common/src/fx_file_seek.c
Normal 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));
|
||||
}
|
||||
|
78
common/src/fx_file_truncate.c
Normal file
78
common/src/fx_file_truncate.c
Normal 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));
|
||||
}
|
||||
|
80
common/src/fx_file_truncate_release.c
Normal file
80
common/src/fx_file_truncate_release.c
Normal 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
1767
common/src/fx_file_write.c
Normal file
File diff suppressed because it is too large
Load Diff
81
common/src/fx_file_write_notify_set.c
Normal file
81
common/src/fx_file_write_notify_set.c
Normal 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
187
common/src/fx_media_abort.c
Normal 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);
|
||||
}
|
||||
|
320
common/src/fx_media_boot_info_extract.c
Normal file
320
common/src/fx_media_boot_info_extract.c
Normal 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);
|
||||
}
|
||||
|
132
common/src/fx_media_cache_invalidate.c
Normal file
132
common/src/fx_media_cache_invalidate.c
Normal 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
828
common/src/fx_media_check.c
Normal 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);
|
||||
}
|
||||
|
169
common/src/fx_media_check_FAT_chain_check.c
Normal file
169
common/src/fx_media_check_FAT_chain_check.c
Normal 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);
|
||||
}
|
||||
|
278
common/src/fx_media_check_lost_cluster_check.c
Normal file
278
common/src/fx_media_check_lost_cluster_check.c
Normal 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
433
common/src/fx_media_close.c
Normal 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);
|
||||
}
|
||||
|
80
common/src/fx_media_close_notify_set.c
Normal file
80
common/src/fx_media_close_notify_set.c
Normal 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
Loading…
x
Reference in New Issue
Block a user