Update version numbers in preparation for new release.

This commit is contained in:
Richard Barry 2015-08-05 12:59:42 +00:00
parent b4c3d91aff
commit 99d4f2c454
1451 changed files with 31767 additions and 11220 deletions

View file

@ -53,8 +53,8 @@
/* If the application writer needs to place the buffer used by the CLI at a
fixed address then set configAPPLICATION_PROVIDES_cOutputBuffer to 1 in
FreeRTOSConfig.h, and provide then declare an array as follows with the
following name and size in one of the application files:
FreeRTOSConfig.h, then declare an array with the following name and size in
one of the application files:
char cOutputBuffer[ configCOMMAND_INT_MAX_OUTPUT_SIZE ];
*/
#ifndef configAPPLICATION_PROVIDES_cOutputBuffer

View file

@ -0,0 +1,18 @@
Reliance Edge Credits
=====================
This is a list (or partial list) of people who have made non-trivial or
noteworthy contributions to the Reliance Edge project. It is sorted by name.
Entries are formatted as below:
Real Name (githubaccount)
Short description of how Real Name contributed to Reliance Edge.
The real name may be withheld by request and the GitHub account name might be
missing if the contributor does not use GitHub.
Credits
-------
None yet! ;)

View file

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View file

@ -0,0 +1,115 @@
# Reliance Edge
Reliance Edge is a small, portable, highly reliable power-fail safe file system
for resource-constrained embedded systems like microcontrollers. It is written
in C and provides a familiar POSIX-like file system API, making it easy to use
in your application; or an alternate minimalist API if your application has
simple storage needs. Reliance Edge is highly configurable and can be tuned to
the precise needs of your application.
## Documentation
The complete documentation for Reliance Edge is distributed separately. It
includes an API reference and detailed discussions of various aspects of using
Reliance Edge, including porting, building, configuring, and testing. This
complete documentation, called the _Developer's Guide_, can be obtained for free
from here:
<http://www.datalight.com/reliance-edge>
In addition this README, see [doc/release_notes.md](doc/release_notes.md) for a
list of updates to Reliance Edge and a list of known issues. There is also a
quick-start guide in the doc/ directory that describes step-by-step how to
compile and run Reliance Edge in a simulated Windows environment.
## Why Use Reliance Edge?
Reliance Edge is ideal for small embedded systems with data storage
requirements, especially if there is a chance of sudden power loss or other
system failures. Compared to "raw" disk access, using a file system like
Reliance Edge removes the burden of tracking which sectors belong to which
objects, and allows data to be updated more reliably. Compared to the FAT file
system, using Reliance Edge eliminates the possibility that file system data
will be left in an inconsistent state, corrupting the disk; Reliance Edge does
not need a fsck/CHKDSK utility. Compared to journaling file systems, Reliance
Edge has less overhead and results in less storage media wear for longer device
lifetimes.
Reliance Edge uses a unique transactional model that not only prevents file
system corruption but also allows a set of changes to be made in an atomic "all
or nothing" fashion. This is very useful for applications that make sets of
interrelated changes. By using the features of Reliance Edge, a set of changes
can be incorporated into a single atomic transaction, which is committed in its
entirety or not at all even if interrupted by power loss; this means the
application does not need code to recover from partially-finished updates.
## Hardware
The typical hardware for Reliance Edge is a 32-bit microcontroller, but other
targets are possible. In its typical configurations, Reliance Edge needs at
least 4 KB to 5 KB of RAM, 11 to 18 KB of code space (on the ROM or NOR flash),
and 500 to 700 bytes of stack.
Reliance Edge is not designed for high-end embedded systems that run complicated
operating systems like Linux or Windows Embedded Compact. Embedded systems of
that variety are better served by other file systems, like Datalight's
[Reliance Nitro](http://www.datalight.com/products/embedded-file-systems/reliance-nitro).
## Getting Reliance Edge Working
Before you can use Reliance Edge, it must be ported and configured. At a
minimum, porting includes filling-in functions so that Reliance Edge can issue
commands to your storage medium; depending on your needs, other functions may
need to be filled in as well. These functions reside in a subdirectory in the
os/ directory; see os/stub/ for a blank set of functions. Configuring includes
creating a project directory (start by copying projects/newproj) and creating
the two configuration files (redconf.h/redconf.c) using the Reliance Edge
Configuration Utility (which can be downloaded from
<http://www.datalight.com/reliance-edge>).
These topics are covered in much greater detail in the _Developer's Guide_,
linked above.
## Using Reliance Edge
Using Reliance Edge is a simple matter of including the primary Reliance Edge
application header in your application (either include/redposix.h or
include/redfse.h) and compiling and linking against Reliance Edge binaries.
The Reliance Edge driver must be initialized before it is used (via the
red\_init() or RedFseInit() functions) and then volumes can be mounted and file
and directory functions invoked. The Reliance Edge API is documented in the
_Developer's Guide_ (linked above) and also via comments in the source code.
## Licensing
Reliance Edge is an open-source project licensed under the GNU General Public
License v2 (GPLv2). Businesses and individuals that for commercial or other
reasons cannot comply with the terms of the GPLv2 license may obtain a
commercial license before incorporating Reliance Edge into proprietary software
for distribution in any form. Visit <http://www.datalight.com/reliance-edge>
for more information. The commercial distribution also includes extra tests and
tools not distributed with the GPLv2 version.
See LICENSE.txt for the full license terms of this distribution of the product.
## Getting Help
If you need assistance using Reliance Edge, and you have already consulted the
_Developer's Guide_, contact <RelianceEdgeSupport@datalight.com>.
In the near future, a community forum or message board will be set up to
facilitate discussion of Reliance Edge and allow users to get help from
Datalight and from each other. In the meantime, please use the email address
given above.
## Contributing
Contributions to Reliance Edge are welcome. Our policy is that Datalight must
own the copyright of all code incorporated into Reliance Edge; if contributing a
significant amount of code, you will be asked to file a copyright assignment
agreement. See CONTRIBUTING.txt for further details and contribution
guidelines.
To report bugs, please create a GitHub issue or contact
<RelianceEdgeSupport@datalight.com>.

View file

@ -0,0 +1,131 @@
RELIANCE EDGE
Reliance Edge is a small, portable, highly reliable power-fail safe file
system for resource-constrained embedded systems like microcontrollers.
It is written in C and provides a familiar POSIX-like file system API,
making it easy to use in your application; or an alternate minimalist
API if your application has simple storage needs. Reliance Edge is
highly configurable and can be tuned to the precise needs of your
application.
Documentation
The complete documentation for Reliance Edge is distributed separately.
It includes an API reference and detailed discussions of various aspects
of using Reliance Edge, including porting, building, configuring, and
testing. This complete documentation, called the _Developer's Guide_,
can be obtained for free from here:
http://www.datalight.com/reliance-edge
In addition this README, see doc/release_notes.md for a list of updates
to Reliance Edge and a list of known issues. There is also a quick-start
guide in the doc/ directory that describes step-by-step how to compile
and run Reliance Edge in a simulated Windows environment.
Why Use Reliance Edge?
Reliance Edge is ideal for small embedded systems with data storage
requirements, especially if there is a chance of sudden power loss or
other system failures. Compared to "raw" disk access, using a file
system like Reliance Edge removes the burden of tracking which sectors
belong to which objects, and allows data to be updated more reliably.
Compared to the FAT file system, using Reliance Edge eliminates the
possibility that file system data will be left in an inconsistent state,
corrupting the disk; Reliance Edge does not need a fsck/CHKDSK utility.
Compared to journaling file systems, Reliance Edge has less overhead and
results in less storage media wear for longer device lifetimes.
Reliance Edge uses a unique transactional model that not only prevents
file system corruption but also allows a set of changes to be made in an
atomic "all or nothing" fashion. This is very useful for applications
that make sets of interrelated changes. By using the features of
Reliance Edge, a set of changes can be incorporated into a single atomic
transaction, which is committed in its entirety or not at all even if
interrupted by power loss; this means the application does not need code
to recover from partially-finished updates.
Hardware
The typical hardware for Reliance Edge is a 32-bit microcontroller, but
other targets are possible. In its typical configurations, Reliance Edge
needs at least 4 KB to 5 KB of RAM, 11 to 18 KB of code space (on the
ROM or NOR flash), and 500 to 700 bytes of stack.
Reliance Edge is not designed for high-end embedded systems that run
complicated operating systems like Linux or Windows Embedded Compact.
Embedded systems of that variety are better served by other file
systems, like Datalight's Reliance Nitro.
Getting Reliance Edge Working
Before you can use Reliance Edge, it must be ported and configured. At a
minimum, porting includes filling-in functions so that Reliance Edge can
issue commands to your storage medium; depending on your needs, other
functions may need to be filled in as well. These functions reside in a
subdirectory in the os/ directory; see os/stub/ for a blank set of
functions. Configuring includes creating a project directory (start by
copying projects/newproj) and creating the two configuration files
(redconf.h/redconf.c) using the Reliance Edge Configuration Utility
(which can be downloaded from http://www.datalight.com/reliance-edge).
These topics are covered in much greater detail in the _Developer's
Guide_, linked above.
Using Reliance Edge
Using Reliance Edge is a simple matter of including the primary Reliance
Edge application header in your application (either include/redposix.h
or include/redfse.h) and compiling and linking against Reliance Edge
binaries. The Reliance Edge driver must be initialized before it is used
(via the red_init() or RedFseInit() functions) and then volumes can be
mounted and file and directory functions invoked. The Reliance Edge API
is documented in the _Developer's Guide_ (linked above) and also via
comments in the source code.
Licensing
Reliance Edge is an open-source project licensed under the GNU General
Public License v2 (GPLv2). Businesses and individuals that for
commercial or other reasons cannot comply with the terms of the GPLv2
license may obtain a commercial license before incorporating Reliance
Edge into proprietary software for distribution in any form. Visit
http://www.datalight.com/reliance-edge for more information. The
commercial distribution also includes extra tests and tools not
distributed with the GPLv2 version.
See LICENSE.txt for the full license terms of this distribution of the
product.
Getting Help
If you need assistance using Reliance Edge, and you have already
consulted the _Developer's Guide_, contact
RelianceEdgeSupport@datalight.com.
In the near future, a community forum or message board will be set up to
facilitate discussion of Reliance Edge and allow users to get help from
Datalight and from each other. In the meantime, please use the email
address given above.
Contributing
Contributions to Reliance Edge are welcome. Our policy is that Datalight
must own the copyright of all code incorporated into Reliance Edge; if
contributing a significant amount of code, you will be asked to file a
copyright assignment agreement. See CONTRIBUTING.txt for further details
and contribution guidelines.
To report bugs, please create a GitHub issue or contact
RelianceEdgeSupport@datalight.com.

View file

@ -0,0 +1,164 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements block device I/O using logical blocks as the units.
The OS block device implementations operate on sectors. The core does I/O
in terms of logical blocks: this module translates from logical blocks to
sectors.
*/
#include <redfs.h>
#include <redcore.h>
/** @brief Read a range of logical blocks.
@param bVolNum The volume whose block device is being read from.
@param ulBlockStart The first block to read.
@param ulBlockCount The number of blocks to read.
@param pBuffer The buffer to populate with the data read.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EIO A disk I/O error occurred.
@retval -RED_EINVAL Invalid parameters.
*/
REDSTATUS RedIoRead(
uint8_t bVolNum,
uint32_t ulBlockStart,
uint32_t ulBlockCount,
void *pBuffer)
{
REDSTATUS ret;
if( (bVolNum >= REDCONF_VOLUME_COUNT)
|| (ulBlockStart >= gaRedVolume[bVolNum].ulBlockCount)
|| ((gaRedVolume[bVolNum].ulBlockCount - ulBlockStart) < ulBlockCount)
|| (ulBlockCount == 0U)
|| (pBuffer == NULL))
{
REDERROR();
ret = -RED_EINVAL;
}
else
{
uint8_t bSectorShift = gaRedVolume[bVolNum].bBlockSectorShift;
uint64_t ullSectorStart = (uint64_t)ulBlockStart << bSectorShift;
uint32_t ulSectorCount = ulBlockCount << bSectorShift;
REDASSERT(bSectorShift < 32U);
REDASSERT((ulSectorCount >> bSectorShift) == ulBlockCount);
ret = RedOsBDevRead(bVolNum, ullSectorStart, ulSectorCount, pBuffer);
}
CRITICAL_ASSERT(ret == 0);
return ret;
}
#if REDCONF_READ_ONLY == 0
/** @brief Write a range of logical blocks.
@param bVolNum The volume whose block device is being written to.
@param ulBlockStart The first block to write.
@param ulBlockCount The number of blocks to write.
@param pBuffer The buffer containing the data to write.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EIO A disk I/O error occurred.
@retval -RED_EINVAL Invalid parameters.
*/
REDSTATUS RedIoWrite(
uint8_t bVolNum,
uint32_t ulBlockStart,
uint32_t ulBlockCount,
const void *pBuffer)
{
REDSTATUS ret;
if( (bVolNum >= REDCONF_VOLUME_COUNT)
|| (ulBlockStart >= gaRedVolume[bVolNum].ulBlockCount)
|| ((gaRedVolume[bVolNum].ulBlockCount - ulBlockStart) < ulBlockCount)
|| (ulBlockCount == 0U)
|| (pBuffer == NULL))
{
REDERROR();
ret = -RED_EINVAL;
}
else
{
uint8_t bSectorShift = gaRedVolume[bVolNum].bBlockSectorShift;
uint64_t ullSectorStart = (uint64_t)ulBlockStart << bSectorShift;
uint32_t ulSectorCount = ulBlockCount << bSectorShift;
REDASSERT(bSectorShift < 32U);
REDASSERT((ulSectorCount >> bSectorShift) == ulBlockCount);
ret = RedOsBDevWrite(bVolNum, ullSectorStart, ulSectorCount, pBuffer);
}
CRITICAL_ASSERT(ret == 0);
return ret;
}
/** @brief Flush any caches beneath the file system.
@param bVolNum The volume number of the volume whose block device is being
flushed.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p bVolNum is an invalid volume number.
@retval -RED_EIO A disk I/O error occurred.
*/
REDSTATUS RedIoFlush(
uint8_t bVolNum)
{
REDSTATUS ret;
if(bVolNum >= REDCONF_VOLUME_COUNT)
{
REDERROR();
ret = -RED_EINVAL;
}
else
{
ret = RedOsBDevFlush(bVolNum);
}
CRITICAL_ASSERT(ret == 0);
return ret;
}
#endif /* REDCONF_READ_ONLY == 0 */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,950 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements directory operations.
*/
#include <redfs.h>
#if REDCONF_API_POSIX == 1
#include <redcore.h>
#define DIR_INDEX_INVALID UINT32_MAX
#if (REDCONF_NAME_MAX % 4U) != 0U
#define DIRENT_PADDING (4U - (REDCONF_NAME_MAX % 4U))
#else
#define DIRENT_PADDING (0U)
#endif
#define DIRENT_SIZE (4U + REDCONF_NAME_MAX + DIRENT_PADDING)
#define DIRENTS_PER_BLOCK (REDCONF_BLOCK_SIZE / DIRENT_SIZE)
#define DIRENTS_MAX (uint32_t)REDMIN(UINT32_MAX, UINT64_SUFFIX(1) * INODE_DATA_BLOCKS * DIRENTS_PER_BLOCK)
/** @brief On-disk directory entry.
*/
typedef struct
{
/** The inode number that the directory entry points at. If the directory
entry is available, this holds INODE_INVALID.
*/
uint32_t ulInode;
/** The name of the directory entry. For names shorter than
REDCONF_NAME_MAX, unused bytes in the array are zeroed. For names of
the maximum length, the string is not null terminated.
*/
char acName[REDCONF_NAME_MAX];
#if DIRENT_PADDING > 0U
/** Unused padding so that ulInode is always aligned on a four-byte
boundary.
*/
uint8_t abPadding[DIRENT_PADDING];
#endif
} DIRENT;
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX_RENAME == 1)
static REDSTATUS DirCyclicRenameCheck(uint32_t ulSrcInode, const CINODE *pDstPInode);
#endif
#if REDCONF_READ_ONLY == 0
static REDSTATUS DirEntryWrite(CINODE *pPInode, uint32_t ulIdx, uint32_t ulInode, const char *pszName, uint32_t ulNameLen);
static uint64_t DirEntryIndexToOffset(uint32_t ulIdx);
#endif
static uint32_t DirOffsetToEntryIndex(uint64_t ullOffset);
#if REDCONF_READ_ONLY == 0
/** @brief Create a new entry in a directory.
@param pPInode A pointer to the cached inode structure of the directory
to which the new entry will be added.
@param pszName The name to be given to the new entry, terminated by a
null or a path separator.
@param ulInode The inode number the new name will point at.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EIO A disk I/O error occurred.
@retval -RED_ENOSPC There is not enough space on the volume to
create the new directory entry; or the directory
is full.
@retval -RED_ENOTDIR @p pPInode is not a directory.
@retval -RED_ENAMETOOLONG @p pszName is too long.
@retval -RED_EEXIST @p pszName already exists in @p ulPInode.
@retval -RED_EINVAL @p pPInode is not a mounted dirty cached inode
structure; or @p pszName is not a valid name.
*/
REDSTATUS RedDirEntryCreate(
CINODE *pPInode,
const char *pszName,
uint32_t ulInode)
{
REDSTATUS ret;
if(!CINODE_IS_DIRTY(pPInode) || (pszName == NULL) || !INODE_IS_VALID(ulInode))
{
ret = -RED_EINVAL;
}
else if(!pPInode->fDirectory)
{
ret = -RED_ENOTDIR;
}
else
{
uint32_t ulNameLen = RedNameLen(pszName);
if(ulNameLen == 0U)
{
ret = -RED_EINVAL;
}
else if(ulNameLen > REDCONF_NAME_MAX)
{
ret = -RED_ENAMETOOLONG;
}
else
{
uint32_t ulEntryIdx;
ret = RedDirEntryLookup(pPInode, pszName, &ulEntryIdx, NULL);
if(ret == 0)
{
ret = -RED_EEXIST;
}
else if(ret == -RED_ENOENT)
{
if(ulEntryIdx == DIR_INDEX_INVALID)
{
ret = -RED_ENOSPC;
}
else
{
ret = 0;
}
}
else
{
/* Unexpected error, no action.
*/
}
if(ret == 0)
{
ret = DirEntryWrite(pPInode, ulEntryIdx, ulInode, pszName, ulNameLen);
}
}
}
return ret;
}
#endif /* REDCONF_READ_ONLY == 0 */
#if DELETE_SUPPORTED
/** @brief Delete an existing directory entry.
@param pPInode A pointer to the cached inode structure of the directory
containing the entry to be deleted.
@param ulDeleteIdx Position within the directory of the entry to be
deleted.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EIO A disk I/O error occurred.
@retval -RED_ENOSPC The file system does not have enough space to modify
the parent directory to perform the deletion.
@retval -RED_ENOTDIR @p pPInode is not a directory.
@retval -RED_EINVAL @p pPInode is not a mounted dirty cached inode
structure; or @p ulIdx is out of range.
*/
REDSTATUS RedDirEntryDelete(
CINODE *pPInode,
uint32_t ulDeleteIdx)
{
REDSTATUS ret = 0;
if(!CINODE_IS_DIRTY(pPInode) || (ulDeleteIdx >= DIRENTS_MAX))
{
ret = -RED_EINVAL;
}
else if(!pPInode->fDirectory)
{
ret = -RED_ENOTDIR;
}
else if((DirEntryIndexToOffset(ulDeleteIdx) + DIRENT_SIZE) == pPInode->pInodeBuf->ullSize)
{
uint32_t ulTruncIdx = ulDeleteIdx;
bool fDone = false;
/* We are deleting the last dirent in the directory, so search
backwards to find the last populated dirent, allowing us to truncate
the directory to that point.
*/
while((ret == 0) && (ulTruncIdx > 0U) && !fDone)
{
ret = RedInodeDataSeekAndRead(pPInode, ulTruncIdx / DIRENTS_PER_BLOCK);
if(ret == 0)
{
const DIRENT *pDirents = CAST_CONST_DIRENT_PTR(pPInode->pbData);
uint32_t ulBlockIdx = (ulTruncIdx - 1U) % DIRENTS_PER_BLOCK;
do
{
if(pDirents[ulBlockIdx].ulInode != INODE_INVALID)
{
fDone = true;
break;
}
ulTruncIdx--;
ulBlockIdx--;
} while(ulBlockIdx != UINT32_MAX);
}
else if(ret == -RED_ENODATA)
{
ret = 0;
REDASSERT((ulTruncIdx % DIRENTS_PER_BLOCK) == 0U);
ulTruncIdx -= DIRENTS_PER_BLOCK;
}
else
{
/* Unexpected error, loop will terminate; nothing else
to be done.
*/
}
}
/* Truncate the directory, deleting the requested entry and any empty
dirents at the end of the directory.
*/
if(ret == 0)
{
ret = RedInodeDataTruncate(pPInode, DirEntryIndexToOffset(ulTruncIdx));
}
}
else
{
/* The dirent to delete is not the last entry in the directory, so just
zero it.
*/
ret = DirEntryWrite(pPInode, ulDeleteIdx, INODE_INVALID, "", 0U);
}
return ret;
}
#endif /* DELETE_SUPPORTED */
/** @brief Perform a case-sensitive search of a directory for a given name.
If found, then position of the entry within the directory and the inode
number it points to are returned. As an optimization for directory entry
creation, in the case where the requested entry does not exist, the position
of the first available (unused) entry is returned.
@param pPInode A pointer to the cached inode structure of the directory
to search.
@param pszName The name of the desired entry, terminated by either a
null or a path separator.
@param pulEntryIdx On successful return, meaning that the desired entry
exists, populated with the position of the entry. If
returning an -RED_ENOENT error, populated with the
position of the first available entry, or set to
DIR_INDEX_INVALID if the directory is full. Optional.
@param pulInode On successful return, populated with the inode number
that the name points to. Optional; may be `NULL`.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EIO A disk I/O error occurred.
@retval -RED_ENOENT @p pszName does not name an existing file or
directory.
@retval -RED_ENOTDIR @p pPInode is not a directory.
@retval -RED_EINVAL @p pPInode is not a mounted cached inode
structure; or @p pszName is not a valid name; or
@p pulEntryIdx is `NULL`.
@retval -RED_ENAMETOOLONG @p pszName is too long.
*/
REDSTATUS RedDirEntryLookup(
CINODE *pPInode,
const char *pszName,
uint32_t *pulEntryIdx,
uint32_t *pulInode)
{
REDSTATUS ret = 0;
if(!CINODE_IS_MOUNTED(pPInode) || (pszName == NULL))
{
ret = -RED_EINVAL;
}
else if(!pPInode->fDirectory)
{
ret = -RED_ENOTDIR;
}
else
{
uint32_t ulNameLen = RedNameLen(pszName);
if(ulNameLen == 0U)
{
ret = -RED_EINVAL;
}
else if(ulNameLen > REDCONF_NAME_MAX)
{
ret = -RED_ENAMETOOLONG;
}
else
{
uint32_t ulIdx = 0U;
uint32_t ulDirentCount = DirOffsetToEntryIndex(pPInode->pInodeBuf->ullSize);
uint32_t ulFreeIdx = DIR_INDEX_INVALID; /* Index of first free dirent. */
/* Loop over the directory blocks, searching each block for a
dirent that matches the given name.
*/
while((ret == 0) && (ulIdx < ulDirentCount))
{
ret = RedInodeDataSeekAndRead(pPInode, ulIdx / DIRENTS_PER_BLOCK);
if(ret == 0)
{
const DIRENT *pDirents = CAST_CONST_DIRENT_PTR(pPInode->pbData);
uint32_t ulBlockLastIdx = REDMIN(DIRENTS_PER_BLOCK, ulDirentCount - ulIdx);
uint32_t ulBlockIdx;
for(ulBlockIdx = 0U; ulBlockIdx < ulBlockLastIdx; ulBlockIdx++)
{
const DIRENT *pDirent = &pDirents[ulBlockIdx];
if(pDirent->ulInode != INODE_INVALID)
{
/* The name in the dirent will not be null
terminated if it is of the maximum length, so
use a bounded string compare and then make sure
there is nothing more to the name.
*/
if( (RedStrNCmp(pDirent->acName, pszName, ulNameLen) == 0)
&& ((ulNameLen == REDCONF_NAME_MAX) || (pDirent->acName[ulNameLen] == '\0')))
{
/* Found a matching dirent, stop and return its
information.
*/
if(pulInode != NULL)
{
*pulInode = pDirent->ulInode;
#ifdef REDCONF_ENDIAN_SWAP
*pulInode = RedRev32(*pulInode);
#endif
}
ulIdx += ulBlockIdx;
break;
}
}
else if(ulFreeIdx == DIR_INDEX_INVALID)
{
ulFreeIdx = ulIdx + ulBlockIdx;
}
else
{
/* The directory entry is free, but we already found a free one, so there's
nothing to do here.
*/
}
}
if(ulBlockIdx < ulBlockLastIdx)
{
/* If we broke out of the for loop, we found a matching
dirent and can stop the search.
*/
break;
}
ulIdx += ulBlockLastIdx;
}
else if(ret == -RED_ENODATA)
{
if(ulFreeIdx == DIR_INDEX_INVALID)
{
ulFreeIdx = ulIdx;
}
ret = 0;
ulIdx += DIRENTS_PER_BLOCK;
}
else
{
/* Unexpected error, let the loop terminate, no action
here.
*/
}
}
if(ret == 0)
{
/* If we made it all the way to the end of the directory
without stopping, then the given name does not exist in the
directory.
*/
if(ulIdx == ulDirentCount)
{
/* If the directory had no sparse dirents, then the first
free dirent is beyond the end of the directory. If the
directory is already the maximum size, then there is no
free dirent.
*/
if((ulFreeIdx == DIR_INDEX_INVALID) && (ulDirentCount < DIRENTS_MAX))
{
ulFreeIdx = ulDirentCount;
}
ulIdx = ulFreeIdx;
ret = -RED_ENOENT;
}
if(pulEntryIdx != NULL)
{
*pulEntryIdx = ulIdx;
}
}
}
}
return ret;
}
#if (REDCONF_API_POSIX_READDIR == 1) || (REDCONF_CHECKER == 1)
/** @brief Read the next entry from a directory, given a starting index.
@param pInode A pointer to the cached inode structure of the directory to
read from.
@param pulIdx On entry, the directory index to start reading from. On
successful return, populated with the directory index to use
for subsequent reads. On -RED_ENOENT return, populated with
the directory index immediately following the last valid
one.
@param pszName On successful return, populated with the name of the next
directory entry. Buffer must be at least
REDCONF_NAME_MAX + 1 in size, to store the maximum name
length plus a null terminator.
@param pulInode On successful return, populated with the inode number
pointed at by the next directory entry.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EIO A disk I/O error occurred.
@retval -RED_ENOENT There are no more entries in the directory.
@retval -RED_ENOTDIR @p pPInode is not a directory.
@retval -RED_EINVAL @p pPInode is not a mounted cached inode structure;
or @p pszName is `NULL`; or @p pulIdx is `NULL`; or
@p pulInode is `NULL`.
*/
REDSTATUS RedDirEntryRead(
CINODE *pPInode,
uint32_t *pulIdx,
char *pszName,
uint32_t *pulInode)
{
REDSTATUS ret = 0;
if(!CINODE_IS_MOUNTED(pPInode) || (pulIdx == NULL) || (pszName == NULL) || (pulInode == NULL))
{
ret = -RED_EINVAL;
}
else if(!pPInode->fDirectory)
{
ret = -RED_ENOTDIR;
}
else
{
uint32_t ulIdx = *pulIdx;
uint32_t ulDirentCount = DirOffsetToEntryIndex(pPInode->pInodeBuf->ullSize);
/* Starting either at the beginning of the directory or where we left
off, loop over the directory blocks, searching each block for a
non-sparse dirent to return as the next entry in the directory.
*/
while((ret == 0) && (ulIdx < ulDirentCount))
{
uint32_t ulBlockOffset = ulIdx / DIRENTS_PER_BLOCK;
ret = RedInodeDataSeekAndRead(pPInode, ulBlockOffset);
if(ret == 0)
{
const DIRENT *pDirents = CAST_CONST_DIRENT_PTR(pPInode->pbData);
uint32_t ulBlockLastIdx = REDMIN(DIRENTS_PER_BLOCK, ulDirentCount - (ulBlockOffset * DIRENTS_PER_BLOCK));
uint32_t ulBlockIdx;
for(ulBlockIdx = ulIdx % DIRENTS_PER_BLOCK; ulBlockIdx < ulBlockLastIdx; ulBlockIdx++)
{
if(pDirents[ulBlockIdx].ulInode != INODE_INVALID)
{
*pulIdx = ulIdx + 1U;
RedStrNCpy(pszName, pDirents[ulBlockIdx].acName, REDCONF_NAME_MAX);
pszName[REDCONF_NAME_MAX] = '\0';
*pulInode = pDirents[ulBlockIdx].ulInode;
#ifdef REDCONF_ENDIAN_SWAP
*pulInode = RedRev32(*pulInode);
#endif
break;
}
ulIdx++;
}
if(ulBlockIdx < ulBlockLastIdx)
{
REDASSERT(ulIdx <= ulDirentCount);
break;
}
}
else if(ret == -RED_ENODATA)
{
ulIdx += DIRENTS_PER_BLOCK - (ulIdx % DIRENTS_PER_BLOCK);
ret = 0;
}
else
{
/* Unexpected error, loop will terminate; nothing else to do.
*/
}
REDASSERT(ulIdx <= ulDirentCount);
}
if((ret == 0) && (ulIdx >= ulDirentCount))
{
*pulIdx = ulDirentCount;
ret = -RED_ENOENT;
}
}
return ret;
}
#endif
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX_RENAME == 1)
/** Rename a directory entry.
@param pSrcPInode The inode of the directory containing @p pszSrcName.
@param pszSrcName The name of the directory entry to be renamed.
@param pSrcInode On successful return, populated with the inode of the
source entry.
@param pDstPInode The inode of the directory in which @p pszDstName will
be created or replaced.
@param pszDstName The name of the directory entry to be created or
replaced.
@param pDstInode On successful return, if the destination previously
existed, populated with the inode previously pointed to
by the destination. This may be the same as the source
inode. If the destination did not exist, populated with
INODE_INVALID.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EEXIST #REDCONF_RENAME_ATOMIC is false and the
destination name exists.
@retval -RED_EINVAL @p pSrcPInode is not a mounted dirty cached
inode structure; or @p pSrcInode is `NULL`; or
@p pszSrcName is not a valid name; or
@p pDstPInode is not a mounted dirty cached
inode structure; or @p pDstInode is `NULL`; or
@p pszDstName is not a valid name.
@retval -RED_EIO A disk I/O error occurred.
@retval -RED_EISDIR The destination name exists and is a directory,
and the source name is a non-directory.
@retval -RED_ENAMETOOLONG Either @p pszSrcName or @p pszDstName is longer
than #REDCONF_NAME_MAX.
@retval -RED_ENOENT The source name is not an existing entry; or
either @p pszSrcName or @p pszDstName point to
an empty string.
@retval -RED_ENOTDIR @p pSrcPInode is not a directory; or
@p pDstPInode is not a directory; or the source
name is a directory and the destination name is
a file.
@retval -RED_ENOTEMPTY The destination name is a directory which is not
empty.
@retval -RED_ENOSPC The file system does not have enough space to
extend the @p ulDstPInode directory.
@retval -RED_EROFS The directory to be removed resides on a
read-only file system.
*/
REDSTATUS RedDirEntryRename(
CINODE *pSrcPInode,
const char *pszSrcName,
CINODE *pSrcInode,
CINODE *pDstPInode,
const char *pszDstName,
CINODE *pDstInode)
{
REDSTATUS ret;
if( !CINODE_IS_DIRTY(pSrcPInode)
|| (pszSrcName == NULL)
|| (pSrcInode == NULL)
|| !CINODE_IS_DIRTY(pDstPInode)
|| (pszDstName == NULL)
|| (pDstInode == NULL))
{
ret = -RED_EINVAL;
}
else if(!pSrcPInode->fDirectory || !pDstPInode->fDirectory)
{
ret = -RED_ENOTDIR;
}
else
{
uint32_t ulDstIdx = 0U; /* Init'd to quiet warnings. */
uint32_t ulSrcIdx;
/* Look up the source and destination names.
*/
ret = RedDirEntryLookup(pSrcPInode, pszSrcName, &ulSrcIdx, &pSrcInode->ulInode);
if(ret == 0)
{
ret = RedDirEntryLookup(pDstPInode, pszDstName, &ulDstIdx, &pDstInode->ulInode);
if(ret == -RED_ENOENT)
{
if(ulDstIdx == DIR_INDEX_INVALID)
{
ret = -RED_ENOSPC;
}
else
{
#if REDCONF_RENAME_ATOMIC == 1
pDstInode->ulInode = INODE_INVALID;
#endif
ret = 0;
}
}
#if REDCONF_RENAME_ATOMIC == 0
else if(ret == 0)
{
ret = -RED_EEXIST;
}
else
{
/* Nothing to do here, just propagate the error.
*/
}
#endif
}
#if REDCONF_RENAME_ATOMIC == 1
/* If both names point to the same inode, POSIX says to do nothing to
either name.
*/
if((ret == 0) && (pSrcInode->ulInode != pDstInode->ulInode))
#else
if(ret == 0)
#endif
{
ret = RedInodeMount(pSrcInode, FTYPE_EITHER, true);
#if REDCONF_RENAME_ATOMIC == 1
if((ret == 0) && (pDstInode->ulInode != INODE_INVALID))
{
/* Source and destination must be the same type (file/dir).
*/
ret = RedInodeMount(pDstInode, pSrcInode->fDirectory ? FTYPE_DIR : FTYPE_FILE, true);
/* If renaming directories, the destination must be empty.
*/
if((ret == 0) && pDstInode->fDirectory && (pDstInode->pInodeBuf->ullSize > 0U))
{
ret = -RED_ENOTEMPTY;
}
}
#endif
/* If we are renaming a directory, make sure the rename isn't
cyclic (e.g., renaming "foo" into "foo/bar").
*/
if((ret == 0) && pSrcInode->fDirectory)
{
ret = DirCyclicRenameCheck(pSrcInode->ulInode, pDstPInode);
}
if(ret == 0)
{
ret = DirEntryWrite(pDstPInode, ulDstIdx, pSrcInode->ulInode, pszDstName, RedNameLen(pszDstName));
}
if(ret == 0)
{
ret = RedDirEntryDelete(pSrcPInode, ulSrcIdx);
if(ret == -RED_ENOSPC)
{
REDSTATUS ret2;
/* If there was not enough space to branch the parent
directory inode and data block containin the source
entry, revert destination directory entry to its
previous state.
*/
#if REDCONF_RENAME_ATOMIC == 1
if(pDstInode->ulInode != INODE_INVALID)
{
ret2 = DirEntryWrite(pDstPInode, ulDstIdx, pDstInode->ulInode, pszDstName, RedNameLen(pszDstName));
}
else
#endif
{
ret2 = RedDirEntryDelete(pDstPInode, ulDstIdx);
}
if(ret2 != 0)
{
ret = ret2;
CRITICAL_ERROR();
}
}
}
if(ret == 0)
{
pSrcInode->pInodeBuf->ulPInode = pDstPInode->ulInode;
}
}
}
return ret;
}
/** @brief Check for a cyclic rename.
A cyclic rename is renaming a directory into a subdirectory of itself. For
example, renaming "a" into "a/b/c/d" is cyclic. These renames must not be
allowed since they would corrupt the directory tree.
@param ulSrcInode The inode number of the directory being renamed.
@param pDstPInode A pointer to the cached inode structure of the directory
into which the source is being renamed.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EIO A disk I/O error occurred.
@retval -RED_EINVAL The rename is cyclic; or invalid parameters.
@retval -RED_ENOTDIR @p pDstPInode is not a directory.
*/
static REDSTATUS DirCyclicRenameCheck(
uint32_t ulSrcInode,
const CINODE *pDstPInode)
{
REDSTATUS ret = 0;
if(!INODE_IS_VALID(ulSrcInode) || !CINODE_IS_MOUNTED(pDstPInode))
{
REDERROR();
ret = -RED_EINVAL;
}
else if(ulSrcInode == pDstPInode->ulInode)
{
ret = -RED_EINVAL;
}
else if(!pDstPInode->fDirectory)
{
ret = -RED_ENOTDIR;
}
else
{
CINODE NextParent;
/* Used to prevent infinite loop in case of corrupted directory
structure.
*/
uint32_t ulIteration = 0U;
NextParent.ulInode = pDstPInode->pInodeBuf->ulPInode;
while( (NextParent.ulInode != ulSrcInode)
&& (NextParent.ulInode != INODE_ROOTDIR)
&& (NextParent.ulInode != INODE_INVALID)
&& (ulIteration < gpRedVolConf->ulInodeCount))
{
ret = RedInodeMount(&NextParent, FTYPE_DIR, false);
if(ret != 0)
{
break;
}
NextParent.ulInode = NextParent.pInodeBuf->ulPInode;
RedInodePut(&NextParent, 0U);
ulIteration++;
}
if((ret == 0) && (ulIteration == gpRedVolConf->ulInodeCount))
{
CRITICAL_ERROR();
ret = -RED_EFUBAR;
}
if((ret == 0) && (ulSrcInode == NextParent.ulInode))
{
ret = -RED_EINVAL;
}
}
return ret;
}
#endif /* (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX_RENAME == 1) */
#if REDCONF_READ_ONLY == 0
/** @brief Update the contents of a directory entry.
@param pPInode A pointer to the cached inode structure of the directory
whose entry is being written.
@param ulIdx The index of the directory entry to write.
@param ulInode The inode number the directory entry is to point at.
@param pszName The name of the directory entry.
@param ulNameLen The length of @p pszName.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EIO A disk I/O error occurred.
@retval -RED_ENOSPC There is not enough space on the volume to write the
directory entry.
@retval -RED_ENOTDIR @p pPInode is not a directory.
@retval -RED_EINVAL Invalid parameters.
*/
static REDSTATUS DirEntryWrite(
CINODE *pPInode,
uint32_t ulIdx,
uint32_t ulInode,
const char *pszName,
uint32_t ulNameLen)
{
REDSTATUS ret;
if( !CINODE_IS_DIRTY(pPInode)
|| (ulIdx >= DIRENTS_MAX)
|| (!INODE_IS_VALID(ulInode) && (ulInode != INODE_INVALID))
|| (pszName == NULL)
|| (ulNameLen > REDCONF_NAME_MAX)
|| ((ulNameLen == 0U) != (ulInode == INODE_INVALID)))
{
REDERROR();
ret = -RED_EINVAL;
}
else if(!pPInode->fDirectory)
{
ret = -RED_ENOTDIR;
}
else
{
uint64_t ullOffset = DirEntryIndexToOffset(ulIdx);
uint32_t ulLen = DIRENT_SIZE;
static DIRENT de;
RedMemSet(&de, 0U, sizeof(de));
de.ulInode = ulInode;
#ifdef REDCONF_ENDIAN_SWAP
de.ulInode = RedRev32(de.ulInode);
#endif
RedStrNCpy(de.acName, pszName, ulNameLen);
ret = RedInodeDataWrite(pPInode, ullOffset, &ulLen, &de);
}
return ret;
}
/** @brief Convert a directory entry index to a byte offset.
@param ulIdx Directory entry index.
@return Byte offset in the directory corresponding with ulIdx.
*/
static uint64_t DirEntryIndexToOffset(
uint32_t ulIdx)
{
uint32_t ulBlock = ulIdx / DIRENTS_PER_BLOCK;
uint32_t ulOffsetInBlock = ulIdx % DIRENTS_PER_BLOCK;
uint64_t ullOffset;
REDASSERT(ulIdx < DIRENTS_MAX);
ullOffset = (uint64_t)ulBlock << BLOCK_SIZE_P2;
ullOffset += (uint64_t)ulOffsetInBlock * DIRENT_SIZE;
return ullOffset;
}
#endif /* REDCONF_READ_ONLY == 0 */
/** @brief Convert a byte offset to a directory entry index.
@param ullOffset Byte offset in the directory.
@return Directory entry index corresponding with @p ullOffset.
*/
static uint32_t DirOffsetToEntryIndex(
uint64_t ullOffset)
{
uint32_t ulIdx;
REDASSERT(ullOffset < INODE_SIZE_MAX);
REDASSERT(((uint32_t)(ullOffset & (REDCONF_BLOCK_SIZE - 1U)) % DIRENT_SIZE) == 0U);
/* Avoid doing any 64-bit divides.
*/
ulIdx = (uint32_t)(ullOffset >> BLOCK_SIZE_P2) * DIRENTS_PER_BLOCK;
ulIdx += (uint32_t)(ullOffset & (REDCONF_BLOCK_SIZE - 1U)) / DIRENT_SIZE;
return ulIdx;
}
#endif /* REDCONF_API_POSIX == 1 */

View file

@ -0,0 +1,235 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements the Reliance Edge file system formatter.
*/
#include <redfs.h>
#include <redcoreapi.h>
#include <redcore.h>
#if FORMAT_SUPPORTED
/** @brief Format a file system volume.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EBUSY Volume is mounted.
@retval -RED_EIO A disk I/O error occurred.
*/
REDSTATUS RedVolFormat(void)
{
REDSTATUS ret;
if(gpRedVolume->fMounted)
{
ret = -RED_EBUSY;
}
else
{
ret = RedOsBDevOpen(gbRedVolNum, BDEV_O_RDWR);
}
if(ret == 0)
{
MASTERBLOCK *pMB;
REDSTATUS ret2;
/* Overwrite the master block with zeroes, so that if formatting is
interrupted, the volume will not be mountable.
*/
ret = RedBufferGet(BLOCK_NUM_MASTER, BFLAG_NEW | BFLAG_DIRTY, CAST_VOID_PTR_PTR(&pMB));
if(ret == 0)
{
ret = RedBufferFlush(BLOCK_NUM_MASTER, 1U);
RedBufferDiscard(pMB);
}
if(ret == 0)
{
ret = RedIoFlush(gbRedVolNum);
}
#if REDCONF_IMAP_EXTERNAL == 1
if((ret == 0) && !gpRedCoreVol->fImapInline)
{
uint32_t ulImapBlock;
uint32_t ulImapBlockLimit = gpRedCoreVol->ulImapStartBN + (gpRedCoreVol->ulImapNodeCount * 2U);
uint16_t uImapFlags = (uint16_t)((uint32_t)BFLAG_META_IMAP | BFLAG_NEW | BFLAG_DIRTY);
/* Technically it is only necessary to create one copy of each imap
node (the copy the metaroot points at), but creating them both
avoids headaches during disk image analysis from stale imaps
left over from previous formats.
*/
for(ulImapBlock = gpRedCoreVol->ulImapStartBN; ulImapBlock < ulImapBlockLimit; ulImapBlock++)
{
IMAPNODE *pImap;
ret = RedBufferGet(ulImapBlock, uImapFlags, CAST_VOID_PTR_PTR(&pImap));
if(ret != 0)
{
break;
}
RedBufferPut(pImap);
}
}
#endif
/* Write the first metaroot.
*/
if(ret == 0)
{
RedMemSet(gpRedMR, 0U, sizeof(*gpRedMR));
gpRedMR->ulFreeBlocks = gpRedVolume->ulBlocksAllocable;
#if REDCONF_API_POSIX == 1
gpRedMR->ulFreeInodes = gpRedVolConf->ulInodeCount;
#endif
gpRedMR->ulAllocNextBlock = gpRedCoreVol->ulFirstAllocableBN;
/* The branched flag is typically set automatically when bits in
the imap change. It is set here explicitly because the imap has
only been initialized, not changed.
*/
gpRedCoreVol->fBranched = true;
ret = RedVolTransact();
}
#if REDCONF_API_POSIX == 1
/* Create the root directory.
*/
if(ret == 0)
{
CINODE rootdir;
rootdir.ulInode = INODE_ROOTDIR;
ret = RedInodeCreate(&rootdir, INODE_INVALID, RED_S_IFDIR);
if(ret == 0)
{
RedInodePut(&rootdir, 0U);
}
}
#endif
#if REDCONF_API_FSE == 1
/* The FSE API does not support creating or deletes files, so all the
inodes are created during setup.
*/
if(ret == 0)
{
uint32_t ulInodeIdx;
for(ulInodeIdx = 0U; ulInodeIdx < gpRedVolConf->ulInodeCount; ulInodeIdx++)
{
CINODE ino;
ino.ulInode = INODE_FIRST_FREE + ulInodeIdx;
ret = RedInodeCreate(&ino, INODE_INVALID, RED_S_IFREG);
if(ret == 0)
{
RedInodePut(&ino, 0U);
}
}
}
#endif
/* Write the second metaroot.
*/
if(ret == 0)
{
ret = RedVolTransact();
}
/* Populate and write out the master block.
*/
if(ret == 0)
{
ret = RedBufferGet(BLOCK_NUM_MASTER, (uint16_t)((uint32_t)BFLAG_META_MASTER | BFLAG_NEW | BFLAG_DIRTY), CAST_VOID_PTR_PTR(&pMB));
}
if(ret == 0)
{
pMB->ulVersion = RED_DISK_LAYOUT_VERSION;
RedStrNCpy(pMB->acBuildNum, RED_BUILD_NUMBER, sizeof(pMB->acBuildNum));
pMB->ulFormatTime = RedOsClockGetTime();
pMB->ulInodeCount = gpRedVolConf->ulInodeCount;
pMB->ulBlockCount = gpRedVolume->ulBlockCount;
pMB->uMaxNameLen = REDCONF_NAME_MAX;
pMB->uDirectPointers = REDCONF_DIRECT_POINTERS;
pMB->uIndirectPointers = REDCONF_INDIRECT_POINTERS;
pMB->bBlockSizeP2 = BLOCK_SIZE_P2;
#if REDCONF_API_POSIX == 1
pMB->bFlags |= MBFLAG_API_POSIX;
#endif
#if REDCONF_INODE_TIMESTAMPS == 1
pMB->bFlags |= MBFLAG_INODE_TIMESTAMPS;
#endif
#if REDCONF_INODE_BLOCKS == 1
pMB->bFlags |= MBFLAG_INODE_BLOCKS;
#endif
#if (REDCONF_API_POSIX == 1) && (REDCONF_API_POSIX_LINK == 1)
pMB->bFlags |= MBFLAG_INODE_NLINK;
#endif
ret = RedBufferFlush(BLOCK_NUM_MASTER, 1U);
RedBufferPut(pMB);
}
if(ret == 0)
{
ret = RedIoFlush(gbRedVolNum);
}
ret2 = RedOsBDevClose(gbRedVolNum);
if(ret == 0)
{
ret = ret2;
}
}
/* Discard the buffers so a subsequent format will not run into blocks it
does not expect.
*/
if(ret == 0)
{
ret = RedBufferDiscardRange(0U, gpRedVolume->ulBlockCount);
}
return ret;
}
#endif /* FORMAT_SUPPORTED */

View file

@ -0,0 +1,348 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements allocation routines.
This module implements routines for working with the imap, a bitmap which
tracks which blocks are allocated or free. Some of the functionality is
delegated to imapinline.c and imapextern.c.
*/
#include <redfs.h>
#include <redcore.h>
/** @brief Get the allocation bit of a block from either metaroot.
Will pass the call down either to the inline imap or to the external imap
implementation, whichever is appropriate for the current volume.
@param bMR The metaroot index: either 0 or 1.
@param ulBlock The block number to query.
@param pfAllocated On successful return, populated with the allocation bit
of the block.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p bMR is out of range; or @p ulBlock is out of range;
or @p pfAllocated is `NULL`.
@retval -RED_EIO A disk I/O error occurred.
*/
REDSTATUS RedImapBlockGet(
uint8_t bMR,
uint32_t ulBlock,
bool *pfAllocated)
{
REDSTATUS ret;
if( (bMR > 1U)
|| (ulBlock < gpRedCoreVol->ulInodeTableStartBN)
|| (ulBlock >= gpRedVolume->ulBlockCount)
|| (pfAllocated == NULL))
{
REDERROR();
ret = -RED_EINVAL;
}
else
{
#if (REDCONF_IMAP_INLINE == 1) && (REDCONF_IMAP_EXTERNAL == 1)
if(gpRedCoreVol->fImapInline)
{
ret = RedImapIBlockGet(bMR, ulBlock, pfAllocated);
}
else
{
ret = RedImapEBlockGet(bMR, ulBlock, pfAllocated);
}
#elif REDCONF_IMAP_INLINE == 1
ret = RedImapIBlockGet(bMR, ulBlock, pfAllocated);
#else
ret = RedImapEBlockGet(bMR, ulBlock, pfAllocated);
#endif
}
return ret;
}
#if REDCONF_READ_ONLY == 0
/** @brief Set the allocation bit of a block in the working metaroot.
Will pass the call down either to the inline imap or to the external imap
implementation, whichever is appropriate for the current volume.
@param ulBlock The block number to allocate or free.
@param fAllocated Whether to allocate the block (true) or free it (false).
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p ulBlock is out of range; or @p ulBlock is allocable
and @p fAllocated is 1.
@retval -RED_EIO A disk I/O error occurred.
*/
REDSTATUS RedImapBlockSet(
uint32_t ulBlock,
bool fAllocated)
{
REDSTATUS ret;
if( (ulBlock < gpRedCoreVol->ulInodeTableStartBN)
|| (ulBlock >= gpRedVolume->ulBlockCount))
{
REDERROR();
ret = -RED_EINVAL;
}
else if( (ulBlock >= gpRedCoreVol->ulFirstAllocableBN)
&& ( (fAllocated && (gpRedMR->ulFreeBlocks == 0U))
|| ((!fAllocated) && (gpRedMR->ulFreeBlocks >= gpRedVolume->ulBlocksAllocable))))
{
/* Attempting either to free more blocks than are allocable, or
allocate a block when there are none available. This could indicate
metadata corruption.
*/
CRITICAL_ERROR();
ret = -RED_EFUBAR;
}
else
{
#if (REDCONF_IMAP_INLINE == 1) && (REDCONF_IMAP_EXTERNAL == 1)
if(gpRedCoreVol->fImapInline)
{
ret = RedImapIBlockSet(ulBlock, fAllocated);
}
else
{
ret = RedImapEBlockSet(ulBlock, fAllocated);
}
#elif REDCONF_IMAP_INLINE == 1
ret = RedImapIBlockSet(ulBlock, fAllocated);
#else
ret = RedImapEBlockSet(ulBlock, fAllocated);
#endif
/* Any change to the allocation state of a block indicates that the
volume is now branched.
*/
gpRedCoreVol->fBranched = true;
}
/* If a block was marked as no longer in use, discard it from the buffers.
*/
if((ret == 0) && (!fAllocated))
{
ret = RedBufferDiscardRange(ulBlock, 1U);
CRITICAL_ASSERT(ret == 0);
}
/* Adjust the free/almost free block count if the block was allocable.
*/
if((ret == 0) && (ulBlock >= gpRedCoreVol->ulFirstAllocableBN))
{
if(fAllocated)
{
gpRedMR->ulFreeBlocks--;
}
else
{
bool fWasAllocated;
/* Whether the block became free or almost free depends on its
previous allocation state. If it was used, then it is now
almost free. Otherwise, it was new and is now free.
*/
ret = RedImapBlockGet(1U - gpRedCoreVol->bCurMR, ulBlock, &fWasAllocated);
CRITICAL_ASSERT(ret == 0);
if(ret == 0)
{
if(fWasAllocated)
{
gpRedCoreVol->ulAlmostFreeBlocks++;
}
else
{
gpRedMR->ulFreeBlocks++;
}
}
}
}
return ret;
}
/** @brief Allocate one block.
@param pulBlock On successful return, populated with the allocated block
number.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p pulBlock is `NULL`.
@retval -RED_EIO A disk I/O error occurred.
@retval -RED_ENOSPC Insufficient free space to perform the allocation.
*/
REDSTATUS RedImapAllocBlock(
uint32_t *pulBlock)
{
REDSTATUS ret;
if(pulBlock == NULL)
{
REDERROR();
ret = -RED_EINVAL;
}
else if(gpRedMR->ulFreeBlocks == 0U)
{
ret = -RED_ENOSPC;
}
else
{
uint32_t ulStopBlock = gpRedMR->ulAllocNextBlock;
bool fAllocated = false;
do
{
ALLOCSTATE state;
ret = RedImapBlockState(gpRedMR->ulAllocNextBlock, &state);
CRITICAL_ASSERT(ret == 0);
if(ret == 0)
{
if(state == ALLOCSTATE_FREE)
{
ret = RedImapBlockSet(gpRedMR->ulAllocNextBlock, true);
CRITICAL_ASSERT(ret == 0);
*pulBlock = gpRedMR->ulAllocNextBlock;
fAllocated = true;
}
/* Increment the next block number, wrapping it when the end of
the volume is reached.
*/
gpRedMR->ulAllocNextBlock++;
if(gpRedMR->ulAllocNextBlock == gpRedVolume->ulBlockCount)
{
gpRedMR->ulAllocNextBlock = gpRedCoreVol->ulFirstAllocableBN;
}
}
}
while((ret == 0) && !fAllocated && (gpRedMR->ulAllocNextBlock != ulStopBlock));
if((ret == 0) && !fAllocated)
{
/* The free block count was already determined to be non-zero, no
error occurred while looking for free blocks, but no free blocks
were found. This indicates metadata corruption.
*/
CRITICAL_ERROR();
ret = -RED_EFUBAR;
}
}
return ret;
}
#endif /* REDCONF_READ_ONLY == 0 */
/** @brief Get the allocation state of a block.
Takes into account the allocation bits from both metaroots, and returns one
of four possible allocation state values:
- ::ALLOCSTATE_FREE Free and may be allocated; writeable.
- ::ALLOCSTATE_USED In-use and transacted; not writeable.
- ::ALLOCSTATE_NEW In-use but not transacted; writeable.
- ::ALLOCSTATE_AFREE Will become free after a transaction; not writeable.
@param ulBlock The block number to query.
@param pState On successful return, populated with the state of the block.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p ulBlock is out of range; or @p pState is `NULL`.
@retval -RED_EIO A disk I/O error occurred.
*/
REDSTATUS RedImapBlockState(
uint32_t ulBlock,
ALLOCSTATE *pState)
{
REDSTATUS ret;
if( (ulBlock < gpRedCoreVol->ulInodeTableStartBN)
|| (ulBlock >= gpRedVolume->ulBlockCount)
|| (pState == NULL))
{
REDERROR();
ret = -RED_EINVAL;
}
else
{
bool fBitCurrent;
ret = RedImapBlockGet(gpRedCoreVol->bCurMR, ulBlock, &fBitCurrent);
if(ret == 0)
{
bool fBitOld;
ret = RedImapBlockGet(1U - gpRedCoreVol->bCurMR, ulBlock, &fBitOld);
if(ret == 0)
{
if(fBitCurrent)
{
if(fBitOld)
{
*pState = ALLOCSTATE_USED;
}
else
{
*pState = ALLOCSTATE_NEW;
}
}
else
{
if(fBitOld)
{
*pState = ALLOCSTATE_AFREE;
}
else
{
*pState = ALLOCSTATE_FREE;
}
}
}
}
}
return ret;
}

View file

@ -0,0 +1,316 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements routines for the external imap.
The external imap is used on volumes that are too big for the imap bitmap
to be stored entirely in the metaroot, so instead the bitmap is stored in
imap nodes on disk, and the metaroot bitmap is used to toggle between imap
nodes.
*/
#include <redfs.h>
#if REDCONF_IMAP_EXTERNAL == 1
#include <redcore.h>
#if REDCONF_READ_ONLY == 0
static REDSTATUS ImapNodeBranch(uint32_t ulImapNode, IMAPNODE **ppImap);
static bool ImapNodeIsBranched(uint32_t ulImapNode);
#endif
/** @brief Get the allocation bit of a block from the imap as it exists in
either metaroot.
@param bMR The metaroot index: either 0 or 1.
@param ulBlock The block number to query.
@param pfAllocated On successful exit, populated with the allocation bit
of the block.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p bMR is out of range; or @p ulBlock is out of range;
or @p pfAllocated is `NULL`.
@retval -RED_EIO A disk I/O error occurred.
*/
REDSTATUS RedImapEBlockGet(
uint8_t bMR,
uint32_t ulBlock,
bool *pfAllocated)
{
REDSTATUS ret;
if( gpRedCoreVol->fImapInline
|| (bMR > 1U)
|| (ulBlock < gpRedCoreVol->ulInodeTableStartBN)
|| (ulBlock >= gpRedVolume->ulBlockCount)
|| (pfAllocated == NULL))
{
REDERROR();
ret = -RED_EINVAL;
}
else
{
uint32_t ulOffset = ulBlock - gpRedCoreVol->ulInodeTableStartBN;
uint32_t ulImapNode = ulOffset / IMAPNODE_ENTRIES;
uint8_t bMRToRead = bMR;
IMAPNODE *pImap;
#if REDCONF_READ_ONLY == 0
/* If the imap node is not branched, then both copies of the imap are
identical. If the old metaroot copy is requested, use the current
copy instead, since it is more likely to be buffered.
*/
if(bMR == (1U - gpRedCoreVol->bCurMR))
{
if(!ImapNodeIsBranched(ulImapNode))
{
bMRToRead = 1U - bMR;
}
}
#endif
ret = RedBufferGet(RedImapNodeBlock(bMRToRead, ulImapNode), BFLAG_META_IMAP, CAST_VOID_PTR_PTR(&pImap));
if(ret == 0)
{
*pfAllocated = RedBitGet(pImap->abEntries, ulOffset % IMAPNODE_ENTRIES);
RedBufferPut(pImap);
}
}
return ret;
}
#if REDCONF_READ_ONLY == 0
/** @brief Set the allocation bit of a block in the working-state imap.
@param ulBlock The block number to allocate or free.
@param fAllocated Whether to allocate the block (true) or free it (false).
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p ulBlock is out of range.
@retval -RED_EIO A disk I/O error occurred.
*/
REDSTATUS RedImapEBlockSet(
uint32_t ulBlock,
bool fAllocated)
{
REDSTATUS ret;
if( gpRedCoreVol->fImapInline
|| (ulBlock < gpRedCoreVol->ulInodeTableStartBN)
|| (ulBlock >= gpRedVolume->ulBlockCount))
{
REDERROR();
ret = -RED_EINVAL;
}
else
{
uint32_t ulOffset = ulBlock - gpRedCoreVol->ulInodeTableStartBN;
uint32_t ulImapNode = ulOffset / IMAPNODE_ENTRIES;
IMAPNODE *pImap;
ret = ImapNodeBranch(ulImapNode, &pImap);
if(ret == 0)
{
uint32_t ulImapEntry = ulOffset % IMAPNODE_ENTRIES;
if(RedBitGet(pImap->abEntries, ulImapEntry) == fAllocated)
{
/* The driver shouldn't ever set a bit in the imap to its
current value. That shouldn't ever be needed, and it
indicates that the driver is doing unnecessary I/O, or
that the imap is corrupt.
*/
CRITICAL_ERROR();
ret = -RED_EFUBAR;
}
else if(fAllocated)
{
RedBitSet(pImap->abEntries, ulImapEntry);
}
else
{
RedBitClear(pImap->abEntries, ulImapEntry);
}
RedBufferPut(pImap);
}
}
return ret;
}
/** @brief Branch an imap node and get a buffer for it.
If the imap node is already branched, it can be overwritten in its current
location, and this function just gets it buffered dirty. If the node is not
already branched, the metaroot must be updated to toggle the imap node to
its alternate location, thereby preserving the committed state copy of the
imap node.
@param ulImapNode The imap node to branch and buffer.
@param ppImap On successful return, populated with the imap node
buffer, which will be marked dirty.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p ulImapNode is out of range; or @p ppImap is `NULL`.
@retval -RED_EIO A disk I/O error occurred.
*/
static REDSTATUS ImapNodeBranch(
uint32_t ulImapNode,
IMAPNODE **ppImap)
{
REDSTATUS ret;
if((ulImapNode >= gpRedCoreVol->ulImapNodeCount) || (ppImap == NULL))
{
REDERROR();
ret = -RED_EINVAL;
}
else if(ImapNodeIsBranched(ulImapNode))
{
/* Imap node is already branched, so just get it buffered dirty.
*/
ret = RedBufferGet(RedImapNodeBlock(gpRedCoreVol->bCurMR, ulImapNode), BFLAG_META_IMAP | BFLAG_DIRTY, CAST_VOID_PTR_PTR(ppImap));
}
else
{
uint32_t ulBlockCurrent;
uint32_t ulBlockOld;
/* The metaroot currently points to the committed state imap node.
Toggle the metaroot to point at the alternate, writeable location.
*/
if(RedBitGet(gpRedMR->abEntries, ulImapNode))
{
RedBitClear(gpRedMR->abEntries, ulImapNode);
}
else
{
RedBitSet(gpRedMR->abEntries, ulImapNode);
}
ulBlockCurrent = RedImapNodeBlock(gpRedCoreVol->bCurMR, ulImapNode);
ulBlockOld = RedImapNodeBlock(1U - gpRedCoreVol->bCurMR, ulImapNode);
ret = RedBufferDiscardRange(ulBlockCurrent, 1U);
/* Buffer the committed copy then reassign the block number to the
writeable location. This also dirties the buffer.
*/
if(ret == 0)
{
ret = RedBufferGet(ulBlockOld, BFLAG_META_IMAP, CAST_VOID_PTR_PTR(ppImap));
if(ret == 0)
{
RedBufferBranch(*ppImap, ulBlockCurrent);
}
}
}
return ret;
}
/** @brief Determine whether an imap node is branched.
If the imap node is branched, it can be overwritten in its current location.
@param ulImapNode The imap node to examine.
@return Whether the imap node is branched.
*/
static bool ImapNodeIsBranched(
uint32_t ulImapNode)
{
bool fNodeBitSetInMetaroot0 = RedBitGet(gpRedCoreVol->aMR[0U].abEntries, ulImapNode);
bool fNodeBitSetInMetaroot1 = RedBitGet(gpRedCoreVol->aMR[1U].abEntries, ulImapNode);
/* If the imap node is not branched, both metaroots will point to the same
copy of the node.
*/
return fNodeBitSetInMetaroot0 != fNodeBitSetInMetaroot1;
}
#endif /* REDCONF_READ_ONLY == 0 */
/** @brief Calculate the block number of the imap node location indicated by the
given metaroot.
An imap node has two locations on disk. A bit in the metaroot bitmap
indicates which location is the valid one, according to that metaroot. This
function returns the block number of the imap node which is valid in the
given metaroot.
@param bMR Which metaroot to examine.
@param ulImapNode The imap node for which to calculate the block number.
@return Block number of the imap node, as indicated by the given metaroot.
*/
uint32_t RedImapNodeBlock(
uint8_t bMR,
uint32_t ulImapNode)
{
uint32_t ulBlock;
REDASSERT(ulImapNode < gpRedCoreVol->ulImapNodeCount);
ulBlock = gpRedCoreVol->ulImapStartBN + (ulImapNode * 2U);
if(bMR > 1U)
{
REDERROR();
}
else if(RedBitGet(gpRedCoreVol->aMR[bMR].abEntries, ulImapNode))
{
/* Bit is set, so point ulBlock at the second copy of the node.
*/
ulBlock++;
}
else
{
/* ulBlock already points at the first copy of the node.
*/
}
return ulBlock;
}
#endif /* REDCONF_IMAP_EXTERNAL == 1 */

View file

@ -0,0 +1,133 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements routines for the inline imap.
The inline imap is used on volumes that are small enough for the imap bitmap
to be entirely contained within the metaroot.
*/
#include <redfs.h>
#if REDCONF_IMAP_INLINE == 1
#include <redcore.h>
/** @brief Get the allocation bit of a block from either metaroot.
@param bMR The metaroot index: either 0 or 1.
@param ulBlock The block number to query.
@param pfAllocated On successful return, populated with the allocation bit
of the block.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p bMR is out of range; or @p ulBlock is out of range;
@p pfAllocated is `NULL`; or the current volume does not
use the inline imap.
*/
REDSTATUS RedImapIBlockGet(
uint8_t bMR,
uint32_t ulBlock,
bool *pfAllocated)
{
REDSTATUS ret;
if( (!gpRedCoreVol->fImapInline)
|| (bMR > 1U)
|| (ulBlock < gpRedCoreVol->ulInodeTableStartBN)
|| (ulBlock >= gpRedVolume->ulBlockCount)
|| (pfAllocated == NULL))
{
REDERROR();
ret = -RED_EINVAL;
}
else
{
*pfAllocated = RedBitGet(gpRedCoreVol->aMR[bMR].abEntries, ulBlock - gpRedCoreVol->ulInodeTableStartBN);
ret = 0;
}
return ret;
}
#if REDCONF_READ_ONLY == 0
/** @brief Set the allocation bit of a block in the working metaroot.
@param ulBlock The block number to allocate or free.
@param fAllocated Whether to allocate the block (true) or free it (false).
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p ulBlock is out of range; or the current volume does
not use the inline imap.
*/
REDSTATUS RedImapIBlockSet(
uint32_t ulBlock,
bool fAllocated)
{
REDSTATUS ret;
if( (!gpRedCoreVol->fImapInline)
|| (ulBlock < gpRedCoreVol->ulInodeTableStartBN)
|| (ulBlock >= gpRedVolume->ulBlockCount))
{
REDERROR();
ret = -RED_EINVAL;
}
else
{
uint32_t ulOffset = ulBlock - gpRedCoreVol->ulInodeTableStartBN;
if(RedBitGet(gpRedMR->abEntries, ulOffset) == fAllocated)
{
/* The driver shouldn't ever set a bit in the imap to its current
value. This is more of a problem with the external imap, but it
is checked here for consistency.
*/
CRITICAL_ERROR();
ret = -RED_EFUBAR;
}
else if(fAllocated)
{
RedBitSet(gpRedMR->abEntries, ulOffset);
ret = 0;
}
else
{
RedBitClear(gpRedMR->abEntries, ulOffset);
ret = 0;
}
}
return ret;
}
#endif
#endif /* REDCONF_IMAP_INLINE == 1 */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,536 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements core volume operations.
*/
#include <redfs.h>
#include <redcore.h>
static bool MetarootIsValid(METAROOT *pMR, bool *pfSectorCRCIsValid);
#ifdef REDCONF_ENDIAN_SWAP
static void MetaRootEndianSwap(METAROOT *pMetaRoot);
#endif
/** @brief Mount a file system volume.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EIO Volume not formatted, improperly formatted, or corrupt.
*/
REDSTATUS RedVolMount(void)
{
REDSTATUS ret;
#if REDCONF_READ_ONLY == 0
ret = RedOsBDevOpen(gbRedVolNum, BDEV_O_RDWR);
#else
ret = RedOsBDevOpen(gbRedVolNum, BDEV_O_RDONLY);
#endif
if(ret == 0)
{
ret = RedVolMountMaster();
if(ret == 0)
{
ret = RedVolMountMetaroot();
}
if(ret != 0)
{
(void)RedOsBDevClose(gbRedVolNum);
}
}
return ret;
}
/** @brief Mount the master block.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EIO Master block missing, corrupt, or inconsistent with the
compile-time driver settings.
*/
REDSTATUS RedVolMountMaster(void)
{
REDSTATUS ret;
MASTERBLOCK *pMB;
/* Read the master block, to ensure that the disk was formatted with
Reliance Edge.
*/
ret = RedBufferGet(BLOCK_NUM_MASTER, BFLAG_META_MASTER, CAST_VOID_PTR_PTR(&pMB));
if(ret == 0)
{
/* Verify that the driver was compiled with the same settings that
the disk was formatted with. If not, the user has made a
mistake: either the driver settings are wrong, or the disk needs
to be reformatted.
*/
if( (pMB->ulVersion != RED_DISK_LAYOUT_VERSION)
|| (pMB->ulInodeCount != gpRedVolConf->ulInodeCount)
|| (pMB->ulBlockCount != gpRedVolume->ulBlockCount)
|| (pMB->uMaxNameLen != REDCONF_NAME_MAX)
|| (pMB->uDirectPointers != REDCONF_DIRECT_POINTERS)
|| (pMB->uIndirectPointers != REDCONF_INDIRECT_POINTERS)
|| (pMB->bBlockSizeP2 != BLOCK_SIZE_P2)
|| (((pMB->bFlags & MBFLAG_API_POSIX) != 0U) != (REDCONF_API_POSIX == 1))
|| (((pMB->bFlags & MBFLAG_INODE_TIMESTAMPS) != 0U) != (REDCONF_INODE_TIMESTAMPS == 1))
|| (((pMB->bFlags & MBFLAG_INODE_BLOCKS) != 0U) != (REDCONF_INODE_BLOCKS == 1)))
{
ret = -RED_EIO;
}
#if REDCONF_API_POSIX == 1
else if(((pMB->bFlags & MBFLAG_INODE_NLINK) != 0U) != (REDCONF_API_POSIX_LINK == 1))
{
ret = -RED_EIO;
}
#else
else if((pMB->bFlags & MBFLAG_INODE_NLINK) != 0U)
{
ret = -RED_EIO;
}
#endif
else
{
/* Master block configuration is valid.
Save the sequence number of the master block in the volume,
since we need it later (see RedVolMountMetaroot()) and we do
not want to re-buffer the master block.
*/
gpRedVolume->ullSequence = pMB->hdr.ullSequence;
}
RedBufferPut(pMB);
}
return ret;
}
/** @brief Mount the latest metaroot.
This function also populates the volume contexts.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EIO Both metaroots are missing or corrupt.
*/
REDSTATUS RedVolMountMetaroot(void)
{
REDSTATUS ret;
ret = RedIoRead(gbRedVolNum, BLOCK_NUM_FIRST_METAROOT, 1U, &gpRedCoreVol->aMR[0U]);
if(ret == 0)
{
ret = RedIoRead(gbRedVolNum, BLOCK_NUM_FIRST_METAROOT + 1U, 1U, &gpRedCoreVol->aMR[1U]);
}
/* Determine which metaroot is the most recent copy that was written
completely.
*/
if(ret == 0)
{
uint8_t bMR = UINT8_MAX;
bool fSectorCRCIsValid;
if(MetarootIsValid(&gpRedCoreVol->aMR[0U], &fSectorCRCIsValid))
{
bMR = 0U;
#ifdef REDCONF_ENDIAN_SWAP
MetaRootEndianSwap(&gpRedCoreVol->aMR[0U]);
#endif
}
else if(gpRedVolConf->fAtomicSectorWrite && !fSectorCRCIsValid)
{
ret = -RED_EIO;
}
else
{
/* Metaroot is not valid, so it is ignored and there's nothing
to do here.
*/
}
if(ret == 0)
{
if(MetarootIsValid(&gpRedCoreVol->aMR[1U], &fSectorCRCIsValid))
{
#ifdef REDCONF_ENDIAN_SWAP
MetaRootEndianSwap(&gpRedCoreVol->aMR[1U]);
#endif
if((bMR != 0U) || (gpRedCoreVol->aMR[1U].hdr.ullSequence > gpRedCoreVol->aMR[0U].hdr.ullSequence))
{
bMR = 1U;
}
}
else if(gpRedVolConf->fAtomicSectorWrite && !fSectorCRCIsValid)
{
ret = -RED_EIO;
}
else
{
/* Metaroot is not valid, so it is ignored and there's nothing
to do here.
*/
}
}
if(ret == 0)
{
if(bMR == UINT8_MAX)
{
/* Neither metaroot was valid.
*/
ret = -RED_EIO;
}
else
{
gpRedCoreVol->bCurMR = bMR;
gpRedMR = &gpRedCoreVol->aMR[bMR];
}
}
}
if(ret == 0)
{
/* Normally the metaroot contains the highest sequence number, but the
master block is the last block written during format, so on a
freshly formatted volume the master block sequence number (stored in
gpRedVolume->ullSequence) will be higher than that in the metaroot.
*/
if(gpRedMR->hdr.ullSequence > gpRedVolume->ullSequence)
{
gpRedVolume->ullSequence = gpRedMR->hdr.ullSequence;
}
/* gpRedVolume->ullSequence stores the *next* sequence number; to avoid
giving the next node written to disk the same sequence number as the
metaroot, increment it here.
*/
ret = RedVolSeqNumIncrement();
}
if(ret == 0)
{
gpRedVolume->fMounted = true;
#if REDCONF_READ_ONLY == 0
gpRedVolume->fReadOnly = false;
#endif
#if RESERVED_BLOCKS > 0U
gpRedCoreVol->fUseReservedBlocks = false;
#endif
gpRedCoreVol->ulAlmostFreeBlocks = 0U;
gpRedCoreVol->aMR[1U - gpRedCoreVol->bCurMR] = *gpRedMR;
gpRedCoreVol->bCurMR = 1U - gpRedCoreVol->bCurMR;
gpRedMR = &gpRedCoreVol->aMR[gpRedCoreVol->bCurMR];
}
return ret;
}
/** @brief Determine whether the metaroot is valid.
@param pMR The metaroot buffer.
@param pfSectorCRCIsValid Populated with whether the first sector of the
metaroot buffer is valid.
@return Whether the metaroot is valid.
@retval true The metaroot buffer is valid.
@retval false The metaroot buffer is invalid.
*/
static bool MetarootIsValid(
METAROOT *pMR,
bool *pfSectorCRCIsValid)
{
bool fRet = false;
if(pfSectorCRCIsValid == NULL)
{
REDERROR();
}
else if(pMR == NULL)
{
REDERROR();
*pfSectorCRCIsValid = false;
}
#ifdef REDCONF_ENDIAN_SWAP
else if(RedRev32(pMR->hdr.ulSignature) != META_SIG_METAROOT)
#else
else if(pMR->hdr.ulSignature != META_SIG_METAROOT)
#endif
{
*pfSectorCRCIsValid = false;
}
else
{
const uint8_t *pbMR = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pMR);
uint32_t ulSectorCRC = pMR->ulSectorCRC;
uint32_t ulCRC;
#ifdef REDCONF_ENDIAN_SWAP
ulSectorCRC = RedRev32(ulSectorCRC);
#endif
/* The sector CRC was zero when the CRC was computed during the
transaction, so it must be zero here.
*/
pMR->ulSectorCRC = 0U;
ulCRC = RedCrc32Update(0U, &pbMR[8U], gpRedVolConf->ulSectorSize - 8U);
fRet = ulCRC == ulSectorCRC;
*pfSectorCRCIsValid = fRet;
if(fRet)
{
if(gpRedVolConf->ulSectorSize < REDCONF_BLOCK_SIZE)
{
ulCRC = RedCrc32Update(ulCRC, &pbMR[gpRedVolConf->ulSectorSize], REDCONF_BLOCK_SIZE - gpRedVolConf->ulSectorSize);
}
#ifdef REDCONF_ENDIAN_SWAP
ulCRC = RedRev32(ulCRC);
#endif
fRet = ulCRC == pMR->hdr.ulCRC;
}
}
return fRet;
}
#if REDCONF_READ_ONLY == 0
/** @brief Commit a transaction point.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EIO A disk I/O error occurred.
*/
REDSTATUS RedVolTransact(void)
{
REDSTATUS ret = 0;
REDASSERT(!gpRedVolume->fReadOnly); /* Should be checked by caller. */
if(gpRedCoreVol->fBranched)
{
gpRedMR->ulFreeBlocks += gpRedCoreVol->ulAlmostFreeBlocks;
gpRedCoreVol->ulAlmostFreeBlocks = 0U;
ret = RedBufferFlush(0U, gpRedVolume->ulBlockCount);
if(ret == 0)
{
gpRedMR->hdr.ulSignature = META_SIG_METAROOT;
gpRedMR->hdr.ullSequence = gpRedVolume->ullSequence;
ret = RedVolSeqNumIncrement();
}
if(ret == 0)
{
const uint8_t *pbMR = CAST_VOID_PTR_TO_CONST_UINT8_PTR(gpRedMR);
uint32_t ulSectorCRC;
#ifdef REDCONF_ENDIAN_SWAP
MetaRootEndianSwap(gpRedMR);
#endif
gpRedMR->ulSectorCRC = 0U;
ulSectorCRC = RedCrc32Update(0U, &pbMR[8U], gpRedVolConf->ulSectorSize - 8U);
if(gpRedVolConf->ulSectorSize < REDCONF_BLOCK_SIZE)
{
gpRedMR->hdr.ulCRC = RedCrc32Update(ulSectorCRC, &pbMR[gpRedVolConf->ulSectorSize], REDCONF_BLOCK_SIZE - gpRedVolConf->ulSectorSize);
}
else
{
gpRedMR->hdr.ulCRC = ulSectorCRC;
}
gpRedMR->ulSectorCRC = ulSectorCRC;
#ifdef REDCONF_ENDIAN_SWAP
gpRedMR->hdr.ulCRC = RedRev32(gpRedMR->hdr.ulCRC);
gpRedMR->ulSectorCRC = RedRev32(gpRedMR->ulSectorCRC);
#endif
/* Flush the block device before writing the metaroot, so that all
previously written blocks are guaranteed to be on the media before
the metaroot is written. Otherwise, if the block device reorders
the writes, the metaroot could reach the media before metadata it
points at, creating a window for disk corruption if power is lost.
*/
ret = RedIoFlush(gbRedVolNum);
}
if(ret == 0)
{
ret = RedIoWrite(gbRedVolNum, BLOCK_NUM_FIRST_METAROOT + gpRedCoreVol->bCurMR, 1U, gpRedMR);
#ifdef REDCONF_ENDIAN_SWAP
MetaRootEndianSwap(gpRedMR);
#endif
}
/* Flush the block device to force the metaroot write to the media. This
guarantees the transaction point is really complete before we return.
*/
if(ret == 0)
{
ret = RedIoFlush(gbRedVolNum);
}
/* Toggle to the other metaroot buffer. The working state and committed
state metaroot buffers exchange places.
*/
if(ret == 0)
{
uint8_t bNextMR = 1U - gpRedCoreVol->bCurMR;
gpRedCoreVol->aMR[bNextMR] = *gpRedMR;
gpRedCoreVol->bCurMR = bNextMR;
gpRedMR = &gpRedCoreVol->aMR[gpRedCoreVol->bCurMR];
gpRedCoreVol->fBranched = false;
}
CRITICAL_ASSERT(ret == 0);
}
return ret;
}
#endif
#ifdef REDCONF_ENDIAN_SWAP
static void MetaRootEndianSwap(
METAROOT *pMetaRoot)
{
if(pMetaRoot == NULL)
{
REDERROR();
}
else
{
pMetaRoot->ulSectorCRC = RedRev32(pMetaRoot->ulSectorCRC);
pMetaRoot->ulFreeBlocks = RedRev32(pMetaRoot->ulFreeBlocks);
#if REDCONF_API_POSIX == 1
pMetaRoot->ulFreeInodes = RedRev32(pMetaRoot->ulFreeInodes);
#endif
pMetaRoot->ulAllocNextBlock = RedRev32(pMetaRoot->ulAllocNextBlock);
}
}
#endif
/** @brief Process a critical file system error.
@param pszFileName The file in which the error occurred.
@param ulLineNum The line number at which the error occurred.
*/
void RedVolCriticalError(
const char *pszFileName,
uint32_t ulLineNum)
{
#if REDCONF_OUTPUT == 1
#if REDCONF_READ_ONLY == 0
if(!gpRedVolume->fReadOnly)
{
RedOsOutputString("Critical file system error in Reliance Edge, setting volume to READONLY\n");
}
else
#endif
{
RedOsOutputString("Critical file system error in Reliance Edge (volume already READONLY)\n");
}
#endif
#if REDCONF_READ_ONLY == 0
gpRedVolume->fReadOnly = true;
#endif
#if REDCONF_ASSERTS == 1
RedOsAssertFail(pszFileName, ulLineNum);
#else
(void)pszFileName;
(void)ulLineNum;
#endif
}
/** @brief Increment the sequence number.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL Cannot increment sequence number: maximum value reached.
This should not ever happen.
*/
REDSTATUS RedVolSeqNumIncrement(void)
{
REDSTATUS ret;
if(gpRedVolume->ullSequence == UINT64_MAX)
{
/* In practice this should never, ever happen; to get here, there would
need to be UINT64_MAX disk writes, which would take eons: longer
than the lifetime of any product or storage media. If this assert
fires and the current year is still written with four digits,
suspect memory corruption.
*/
CRITICAL_ERROR();
ret = -RED_EFUBAR;
}
else
{
gpRedVolume->ullSequence++;
ret = 0;
}
return ret;
}

View file

@ -0,0 +1,257 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDCORE_H
#define REDCORE_H
#include <redstat.h>
#include <redvolume.h>
#include "rednodes.h"
#include "redcoremacs.h"
#include "redcorevol.h"
#define META_SIG_MASTER (0x5453414DU) /* 'MAST' */
#define META_SIG_METAROOT (0x4154454DU) /* 'META' */
#define META_SIG_IMAP (0x50414D49U) /* 'IMAP' */
#define META_SIG_INODE (0x444F4E49U) /* 'INOD' */
#define META_SIG_DINDIR (0x494C4244U) /* 'DBLI' */
#define META_SIG_INDIR (0x49444E49U) /* 'INDI' */
REDSTATUS RedIoRead(uint8_t bVolNum, uint32_t ulBlockStart, uint32_t ulBlockCount, void *pBuffer);
#if REDCONF_READ_ONLY == 0
REDSTATUS RedIoWrite(uint8_t bVolNum, uint32_t ulBlockStart, uint32_t ulBlockCount, const void *pBuffer);
REDSTATUS RedIoFlush(uint8_t bVolNum);
#endif
/** Indicates a block buffer is dirty (its contents are different than the
contents of the corresponding block on disk); or, when passed into
RedBufferGet(), indicates that the buffer should be marked dirty.
*/
#define BFLAG_DIRTY ((uint16_t) 0x0001U)
/** Tells RedBufferGet() that the buffer is for a newly allocated block, and its
contents should be zeroed instead of being read from disk. Always used in
combination with BFLAG_DIRTY.
*/
#define BFLAG_NEW ((uint16_t) 0x0002U)
/** Indicates that a block buffer is a master block (MASTERBLOCK) metadata node.
*/
#define BFLAG_META_MASTER ((uint16_t)(0x0004U | BFLAG_META))
/** Indicates that a block buffer is an imap (IMAPNODE) metadata node.
*/
#define BFLAG_META_IMAP ((uint16_t)(0x0008U | BFLAG_META))
/** Indicates that a block buffer is an inode (INODE) metadata node.
*/
#define BFLAG_META_INODE ((uint16_t)(0x0010U | BFLAG_META))
/** Indicates that a block buffer is an indirect (INDIR) metadata node.
*/
#define BFLAG_META_INDIR ((uint16_t)(0x0020U | BFLAG_META))
/** Indicates that a block buffer is a double indirect (DINDIR) metadata node.
*/
#define BFLAG_META_DINDIR ((uint16_t)(0x0040U | BFLAG_META))
/** Indicates that a block buffer is a metadata node. Callers of RedBufferGet()
should not use this flag; instead, use one of the BFLAG_META_* flags.
*/
#define BFLAG_META ((uint16_t) 0x8000U)
void RedBufferInit(void);
REDSTATUS RedBufferGet(uint32_t ulBlock, uint16_t uFlags, void **ppBuffer);
void RedBufferPut(const void *pBuffer);
#if REDCONF_READ_ONLY == 0
REDSTATUS RedBufferFlush(uint32_t ulBlockStart, uint32_t ulBlockCount);
void RedBufferDirty(const void *pBuffer);
void RedBufferBranch(const void *pBuffer, uint32_t ulBlockNew);
#if (REDCONF_API_POSIX == 1) || FORMAT_SUPPORTED
void RedBufferDiscard(const void *pBuffer);
#endif
#endif
REDSTATUS RedBufferDiscardRange(uint32_t ulBlockStart, uint32_t ulBlockCount);
/** @brief Allocation state of a block.
*/
typedef enum
{
ALLOCSTATE_FREE, /**< Free and may be allocated; writeable. */
ALLOCSTATE_USED, /**< In-use and transacted; not writeable. */
ALLOCSTATE_NEW, /**< In-use but not transacted; writeable. */
ALLOCSTATE_AFREE /**< Will become free after a transaction; not writeable. */
} ALLOCSTATE;
REDSTATUS RedImapBlockGet(uint8_t bMR, uint32_t ulBlock, bool *pfAllocated);
#if REDCONF_READ_ONLY == 0
REDSTATUS RedImapBlockSet(uint32_t ulBlock, bool fAllocated);
REDSTATUS RedImapAllocBlock(uint32_t *pulBlock);
#endif
REDSTATUS RedImapBlockState(uint32_t ulBlock, ALLOCSTATE *pState);
#if REDCONF_IMAP_INLINE == 1
REDSTATUS RedImapIBlockGet(uint8_t bMR, uint32_t ulBlock, bool *pfAllocated);
REDSTATUS RedImapIBlockSet(uint32_t ulBlock, bool fAllocated);
#endif
#if REDCONF_IMAP_EXTERNAL == 1
REDSTATUS RedImapEBlockGet(uint8_t bMR, uint32_t ulBlock, bool *pfAllocated);
REDSTATUS RedImapEBlockSet(uint32_t ulBlock, bool fAllocated);
uint32_t RedImapNodeBlock(uint8_t bMR, uint32_t ulImapNode);
#endif
/** @brief Cached inode structure.
*/
typedef struct
{
uint32_t ulInode; /**< The inode number of the cached inode. */
#if REDCONF_API_POSIX == 1
bool fDirectory; /**< True if the inode is a directory. */
#endif
#if REDCONF_READ_ONLY == 0
bool fBranched; /**< True if the inode is branched (writeable). */
bool fDirty; /**< True if the inode buffer is dirty. */
#endif
bool fCoordInited; /**< True after the first seek. */
INODE *pInodeBuf; /**< Pointer to the inode buffer. */
#if DINDIR_POINTERS > 0U
DINDIR *pDindir; /**< Pointer to the double indirect node buffer. */
#endif
#if REDCONF_DIRECT_POINTERS < INODE_ENTRIES
INDIR *pIndir; /**< Pointer to the indirect node buffer. */
#endif
uint8_t *pbData; /**< Pointer to the data block buffer. */
/* All the members below this point are part of the seek coordinates; see
RedInodeDataSeek().
*/
uint32_t ulLogicalBlock; /**< Logical block offset into the inode. */
#if DINDIR_POINTERS > 0U
uint32_t ulDindirBlock; /**< Physical block number of the double indirect node. */
#endif
#if REDCONF_DIRECT_POINTERS < INODE_ENTRIES
uint32_t ulIndirBlock; /**< Physical block number of the indirect node. */
#endif
uint32_t ulDataBlock; /**< Physical block number of the file data block. */
uint16_t uInodeEntry; /**< Which inode entry to traverse to reach ulLogicalBlock. */
#if DINDIR_POINTERS > 0U
uint16_t uDindirEntry; /**< Which double indirect entry to traverse to reach ulLogicalBlock. */
#endif
#if REDCONF_DIRECT_POINTERS < INODE_ENTRIES
uint16_t uIndirEntry; /**< Which indirect entry to traverse to reach ulLogicalBlock. */
#endif
} CINODE;
#define CINODE_IS_MOUNTED(pInode) (((pInode) != NULL) && INODE_IS_VALID((pInode)->ulInode) && ((pInode)->pInodeBuf != NULL))
#define CINODE_IS_DIRTY(pInode) (CINODE_IS_MOUNTED(pInode) && (pInode)->fDirty)
#define IPUT_UPDATE_ATIME (0x01U)
#define IPUT_UPDATE_MTIME (0x02U)
#define IPUT_UPDATE_CTIME (0x04U)
#define IPUT_UPDATE_MASK (IPUT_UPDATE_ATIME|IPUT_UPDATE_MTIME|IPUT_UPDATE_CTIME)
REDSTATUS RedInodeMount(CINODE *pInode, FTYPE type, bool fBranch);
#if REDCONF_READ_ONLY == 0
REDSTATUS RedInodeBranch(CINODE *pInode);
#endif
#if (REDCONF_READ_ONLY == 0) && ((REDCONF_API_POSIX == 1) || FORMAT_SUPPORTED)
REDSTATUS RedInodeCreate(CINODE *pInode, uint32_t ulPInode, uint16_t uMode);
#endif
#if DELETE_SUPPORTED
REDSTATUS RedInodeDelete(CINODE *pInode);
REDSTATUS RedInodeLinkDec(CINODE *pInode);
#endif
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX == 1)
REDSTATUS RedInodeFree(CINODE *pInode);
#endif
void RedInodePut(CINODE *pInode, uint8_t bTimeFields);
void RedInodePutCoord(CINODE *pInode);
#if DINDIR_POINTERS > 0U
void RedInodePutDindir(CINODE *pInode);
#endif
#if REDCONF_DIRECT_POINTERS < INODE_ENTRIES
void RedInodePutIndir(CINODE *pInode);
#endif
void RedInodePutData(CINODE *pInode);
#if ((REDCONF_READ_ONLY == 0) && ((REDCONF_API_POSIX == 1) || FORMAT_SUPPORTED)) || (REDCONF_CHECKER == 1)
REDSTATUS RedInodeIsFree(uint32_t ulInode, bool *pfFree);
#endif
REDSTATUS RedInodeBitGet(uint8_t bMR, uint32_t ulInode, uint8_t bWhich, bool *pfAllocated);
REDSTATUS RedInodeDataRead(CINODE *pInode, uint64_t ullStart, uint32_t *pulLen, void *pBuffer);
#if REDCONF_READ_ONLY == 0
REDSTATUS RedInodeDataWrite(CINODE *pInode, uint64_t ullStart, uint32_t *pulLen, const void *pBuffer);
#if DELETE_SUPPORTED || TRUNCATE_SUPPORTED
REDSTATUS RedInodeDataTruncate(CINODE *pInode, uint64_t ullSize);
#endif
#endif
REDSTATUS RedInodeDataSeekAndRead(CINODE *pInode, uint32_t ulBlock);
REDSTATUS RedInodeDataSeek(CINODE *pInode, uint32_t ulBlock);
#if REDCONF_API_POSIX == 1
#if REDCONF_READ_ONLY == 0
REDSTATUS RedDirEntryCreate(CINODE *pPInode, const char *pszName, uint32_t ulInode);
#endif
#if DELETE_SUPPORTED
REDSTATUS RedDirEntryDelete(CINODE *pPInode, uint32_t ulDeleteIdx);
#endif
REDSTATUS RedDirEntryLookup(CINODE *pPInode, const char *pszName, uint32_t *pulEntryIdx, uint32_t *pulInode);
#if (REDCONF_API_POSIX_READDIR == 1) || (REDCONF_CHECKER == 1)
REDSTATUS RedDirEntryRead(CINODE *pPInode, uint32_t *pulIdx, char *pszName, uint32_t *pulInode);
#endif
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX_RENAME == 1)
REDSTATUS RedDirEntryRename(CINODE *pSrcPInode, const char *pszSrcName, CINODE *pSrcInode, CINODE *pDstPInode, const char *pszDstName, CINODE *pDstInode);
#endif
#endif
REDSTATUS RedVolMount(void);
REDSTATUS RedVolMountMaster(void);
REDSTATUS RedVolMountMetaroot(void);
#if REDCONF_READ_ONLY == 0
REDSTATUS RedVolTransact(void);
#endif
void RedVolCriticalError(const char *pszFileName, uint32_t ulLineNum);
REDSTATUS RedVolSeqNumIncrement(void);
#if FORMAT_SUPPORTED
REDSTATUS RedVolFormat(void);
#endif
#endif

View file

@ -0,0 +1,92 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDCOREMACS_H
#define REDCOREMACS_H
#define BLOCK_NUM_MASTER (0UL) /* Block number of the master block. */
#define BLOCK_NUM_FIRST_METAROOT (1UL) /* Block number of the first metaroot. */
#define BLOCK_SPARSE (0U)
#define DINDIR_POINTERS ((INODE_ENTRIES - REDCONF_DIRECT_POINTERS) - REDCONF_INDIRECT_POINTERS)
#define DINDIR_DATA_BLOCKS (INDIR_ENTRIES * INDIR_ENTRIES)
#define INODE_INDIR_BLOCKS (REDCONF_INDIRECT_POINTERS * INDIR_ENTRIES)
#define INODE_DINDIR_BLOCKS (DINDIR_POINTERS * DINDIR_DATA_BLOCKS)
#define INODE_DATA_BLOCKS (REDCONF_DIRECT_POINTERS + INODE_INDIR_BLOCKS + INODE_DINDIR_BLOCKS)
#define INODE_SIZE_MAX (UINT64_SUFFIX(1) * REDCONF_BLOCK_SIZE * INODE_DATA_BLOCKS)
/* First inode number that can be allocated.
*/
#if REDCONF_API_POSIX == 1
#define INODE_FIRST_FREE (INODE_FIRST_VALID + 1U)
#else
#define INODE_FIRST_FREE (INODE_FIRST_VALID)
#endif
/** @brief Determine if an inode number is valid.
*/
#define INODE_IS_VALID(INODENUM) (((INODENUM) >= INODE_FIRST_VALID) && ((INODENUM) < (INODE_FIRST_VALID + gpRedVolConf->ulInodeCount)))
/* The number of blocks reserved to allow a truncate or delete operation to
complete when the disk is otherwise full.
The more expensive of the two operations is delete, which has to actually
write to a file data block to remove the directory entry.
*/
#if REDCONF_READ_ONLY == 1
#define RESERVED_BLOCKS 0U
#elif (REDCONF_API_POSIX == 1) && ((REDCONF_API_POSIX_UNLINK == 1) || (REDCONF_API_POSIX_RMDIR == 1))
#if DINDIR_POINTERS > 0U
#define RESERVED_BLOCKS 3U
#elif REDCONF_INDIRECT_POINTERS > 0U
#define RESERVED_BLOCKS 2U
#else
#define RESERVED_BLOCKS 1U
#endif
#elif ((REDCONF_API_POSIX == 1) && (REDCONF_API_POSIX_FTRUNCATE == 1)) || ((REDCONF_API_FSE == 1) && (REDCONF_API_FSE_TRUNCATE == 1))
#if DINDIR_POINTERS > 0U
#define RESERVED_BLOCKS 2U
#elif REDCONF_INDIRECT_POINTERS > 0U
#define RESERVED_BLOCKS 1U
#else
#define RESERVED_BLOCKS 0U
#endif
#else
#define RESERVED_BLOCKS 0U
#endif
#define CRITICAL_ASSERT(EXP) ((EXP) ? (void)0 : CRITICAL_ERROR())
#define CRITICAL_ERROR() RedVolCriticalError(__FILE__, __LINE__)
#endif

View file

@ -0,0 +1,95 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDCOREVOL_H
#define REDCOREVOL_H
/** @brief Per-volume run-time data specific to the core.
*/
typedef struct
{
/** Whether this volume uses the inline imap (true) or external imap
(false). Computed at initialization time based on the block count.
*/
bool fImapInline;
#if REDCONF_IMAP_EXTERNAL == 1
/** First block number of the on-disk imap. Valid only when fImapInline
is false.
*/
uint32_t ulImapStartBN;
/** The number of double-allocated imap nodes that make up the imap.
*/
uint32_t ulImapNodeCount;
#endif
/** Block number where the inode table starts.
*/
uint32_t ulInodeTableStartBN;
/** First block number that can be allocated.
*/
uint32_t ulFirstAllocableBN;
/** The two metaroot structures, committed and working state.
*/
METAROOT aMR[2U];
/** The index of the current metaroot; must be 0 or 1.
*/
uint8_t bCurMR;
/** Whether the volume has been branched or not.
*/
bool fBranched;
/** The number of blocks which will become free after the next transaction.
*/
uint32_t ulAlmostFreeBlocks;
#if RESERVED_BLOCKS > 0U
/** Whether to use the blocks reserved for operations that create free
space.
*/
bool fUseReservedBlocks;
#endif
} COREVOLUME;
/* Pointer to the core volume currently being accessed; populated during
RedCoreVolSetCurrent().
*/
extern COREVOLUME * CONST_IF_ONE_VOLUME gpRedCoreVol;
/* Pointer to the metaroot currently being accessed; populated during
RedCoreVolSetCurrent() and RedCoreVolTransact().
*/
extern METAROOT *gpRedMR;
#endif

View file

@ -0,0 +1,195 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDNODES_H
#define REDNODES_H
#define NODEHEADER_SIZE (16U)
#define NODEHEADER_OFFSET_SIG (0U)
#define NODEHEADER_OFFSET_CRC (4U)
#define NODEHEADER_OFFSET_SEQ (8U)
/** @brief Common header for all metadata nodes.
*/
typedef struct
{
uint32_t ulSignature; /**< Value which uniquely identifies the metadata node type. */
uint32_t ulCRC; /**< CRC-32 checksum of the node contents, starting after the CRC. */
uint64_t ullSequence; /**< Current sequence number at the time the node was written to disk. */
} NODEHEADER;
/** Flag set in the master block when REDCONF_API_POSIX == 1. */
#define MBFLAG_API_POSIX (0x01U)
/** Flag set in the master block when REDCONF_INODE_TIMESTAMPS == 1. */
#define MBFLAG_INODE_TIMESTAMPS (0x02U)
/** Flag set in the master block when REDCONF_INODE_BLOCKS == 1. */
#define MBFLAG_INODE_BLOCKS (0x04U)
/** Flag set in the master block when (REDCONF_API_POSIX == 1) && (REDCONF_API_POSIX_LINK == 1). */
#define MBFLAG_INODE_NLINK (0x08U)
/** @brief Node which identifies the volume and stores static volume information.
*/
typedef struct
{
NODEHEADER hdr; /**< Common node header. */
uint32_t ulVersion; /**< On-disk layout version number. */
char acBuildNum[8U]; /**< Build number of the product (not null terminated). */
uint32_t ulFormatTime; /**< Date and time the volume was formatted. */
uint32_t ulInodeCount; /**< Compile-time configured number of inodes. */
uint32_t ulBlockCount; /**< Compile-time configured number of logical blocks. */
uint16_t uMaxNameLen; /**< Compile-time configured maximum file name length. */
uint16_t uDirectPointers; /**< Compile-time configured number of direct pointers per inode. */
uint16_t uIndirectPointers; /**< Compile-time configured number of indirect pointers per inode. */
uint8_t bBlockSizeP2; /**< Compile-time configured block size, expressed as a power of two. */
uint8_t bFlags; /**< Compile-time booleans which affect on-disk structures. */
} MASTERBLOCK;
#if REDCONF_API_POSIX == 1
#define METAROOT_HEADER_SIZE (NODEHEADER_SIZE + 16U) /* Size in bytes of the metaroot header fields. */
#else
#define METAROOT_HEADER_SIZE (NODEHEADER_SIZE + 12U) /* Size in bytes of the metaroot header fields. */
#endif
#define METAROOT_ENTRY_BYTES (REDCONF_BLOCK_SIZE - METAROOT_HEADER_SIZE) /* Number of bytes remaining in the metaroot block for entries. */
#define METAROOT_ENTRIES (METAROOT_ENTRY_BYTES * 8U)
/** @brief Metadata root node; each volume has two.
*/
typedef struct
{
NODEHEADER hdr; /**< Common node header. */
uint32_t ulSectorCRC; /**< CRC-32 checksum of the first sector. */
uint32_t ulFreeBlocks; /**< Number of allocable blocks that are free. */
#if REDCONF_API_POSIX == 1
uint32_t ulFreeInodes; /**< Number of inode slots that are free. */
#endif
uint32_t ulAllocNextBlock; /**< Forward allocation pointer. */
/** Imap bitmap. With inline imaps, this is the imap bitmap that indicates
which inode blocks are used and which allocable blocks are used.
Otherwise, this bitmap toggles nodes in the external imap between one
of two possible block locations.
*/
uint8_t abEntries[METAROOT_ENTRY_BYTES];
} METAROOT;
#if REDCONF_IMAP_EXTERNAL == 1
#define IMAPNODE_HEADER_SIZE (NODEHEADER_SIZE) /* Size in bytes of the imap node header fields. */
#define IMAPNODE_ENTRY_BYTES (REDCONF_BLOCK_SIZE - IMAPNODE_HEADER_SIZE) /* Number of bytes remaining in the imap node for entries. */
#define IMAPNODE_ENTRIES (IMAPNODE_ENTRY_BYTES * 8U)
/** @brief One node of the external imap.
*/
typedef struct
{
NODEHEADER hdr; /**< Common node header. */
/** Bitmap which indicates which inode blocks are used and which allocable
blocks are used.
*/
uint8_t abEntries[IMAPNODE_ENTRY_BYTES];
} IMAPNODE;
#endif
#define INODE_HEADER_SIZE (NODEHEADER_SIZE + 8U + ((REDCONF_INODE_BLOCKS == 1) ? 4U : 0U) + \
((REDCONF_INODE_TIMESTAMPS == 1) ? 12U : 0U) + 4U + ((REDCONF_API_POSIX == 1) ? 4U : 0U))
#define INODE_ENTRIES ((REDCONF_BLOCK_SIZE - INODE_HEADER_SIZE) / 4U)
#if (REDCONF_DIRECT_POINTERS < 0) || (REDCONF_DIRECT_POINTERS > (INODE_ENTRIES - REDCONF_INDIRECT_POINTERS))
#error "Configuration error: invalid value of REDCONF_DIRECT_POINTERS"
#endif
#if (REDCONF_INDIRECT_POINTERS < 0) || (REDCONF_INDIRECT_POINTERS > (INODE_ENTRIES - REDCONF_DIRECT_POINTERS))
#error "Configuration error: invalid value of REDCONF_INDIRECT_POINTERS"
#endif
/** @brief Stores metadata for a file or directory.
*/
typedef struct
{
NODEHEADER hdr; /**< Common node header. */
uint64_t ullSize; /**< Size of the inode, in bytes. */
#if REDCONF_INODE_BLOCKS == 1
uint32_t ulBlocks; /**< Total number file data blocks allocated to the inode. */
#endif
#if REDCONF_INODE_TIMESTAMPS == 1
uint32_t ulATime; /**< Time of last access (seconds since January 1, 1970). */
uint32_t ulMTime; /**< Time of last modification (seconds since January 1, 1970). */
uint32_t ulCTime; /**< Time of last status change (seconds since January 1, 1970). */
#endif
uint16_t uMode; /**< Inode type (file or directory) and permissions (reserved). */
#if (REDCONF_API_POSIX == 1) && (REDCONF_API_POSIX_LINK == 1)
uint16_t uNLink; /**< Link count, number of names pointing to the inode. */
#else
uint8_t abPadding[2]; /**< Padding to 32-bit align the next member. */
#endif
#if REDCONF_API_POSIX == 1
uint32_t ulPInode; /**< Parent inode number. Only guaranteed to be accurate for directories. */
#endif
/** Block numbers for lower levels of the file metadata structure. Some
fraction of these entries are for direct pointers (file data block
numbers), some for indirect pointers, some for double-indirect
pointers; the number allocated to each is static but user-configurable.
For all types, an array slot is zero if the range is sparse or beyond
the end of file.
*/
uint32_t aulEntries[INODE_ENTRIES];
} INODE;
#define INDIR_HEADER_SIZE (NODEHEADER_SIZE + 4U)
#define INDIR_ENTRIES ((REDCONF_BLOCK_SIZE - INDIR_HEADER_SIZE) / 4U)
/** @brief Node for storing block pointers.
*/
typedef struct
{
NODEHEADER hdr; /**< Common node header. */
uint32_t ulInode; /**< Inode which owns this indirect or double indirect. */
/** For indirect nodes, stores block numbers of file data. For double
indirect nodes, stores block numbers of indirect nodes. An array
slot is zero if the corresponding block or indirect range is beyond
the end of file or entirely sparse.
*/
uint32_t aulEntries[INDIR_ENTRIES];
} INDIR, DINDIR;
#endif

View file

@ -0,0 +1,389 @@
Datalight Coding Style
======================
This is a description of the Datalight Coding Style intended for third parties
who want to contribute code to Reliance Edge. This document is derived from the
DDSS Coding Guidelines, but only contains a subset of the content which is most
likely to be relevant to third party contributors.
Reliance Edge complies with the MISRA-C:2012 coding guidelines, which includes
many rules that affect coding style. Unfortunately the MISRA-C:2012 document is
not freely available, and is much too long to be effectively summarized, but if
you are familiar with the rules, adhere to them. A few important rules of
thumb: avoid the goto and continue keywords; avoid using more than one break
in a loop; and avoid having more than one return from a function (single point
of exit); default cases in every switch statement; avoid recursion; and make
generous use of parentheses. Outside of the file system driver, in tests and
host tools, the MISRA-C rules are relaxed.
Beyond MISRA-C, Datalight has a standard coding style. Most aspects of this
style are matters of preference, but when contributing code to Datalight an
effort should be made to use this style for the sake of consistency.
Below is an example function, which illustrates several key points of Datalight
Coding Style:
/** @brief One-sentence description of what this function does.
Additional description.
@param ulFirstParameter Description of the parameter.
@param pszPointer Description of the parameter.
@return Describe the return value.
@retval true Optional description of specific return value.
@retval false Optional description of specific return value.
*/
bool ExampleFunction(
uint32_t ulFirstParameter,
char *pszPointer)
{
bool fStatus = true;
/* This is a single-line comment.
*/
if(ulFirstParameter > 0U)
{
/* This is a multi-line comment. Filler text: Lorem ipsum dolor sit
amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua.
*/
FunctionCall();
while(fStatus)
{
fStatus = AnotherFunction(ulFirstParameter, pszPointer);
}
}
return fStatus;
}
Tab Stop Conventions
--------------------
In all C code (.c/.h), use a tab width of four spaces, and use soft tabs (in
other words, tabs are expanded to spaces). In Makefiles, use hard tabs and a
tab width of 8.
Naming
------
Datalight uses CamelCase for functions and variables. Type names are generally
UPPERCASE, except for standard types like uint32_t. Preprocessor macros are
UPPERCASE, with words separated by underscores (for example, INODE_INVALID).
Doxygen Documentation
---------------------
Doxygen is used to document functions (including static functions), along with
types, structures, files, etc. For Doxygen tags, use '@' instead of a backslash
(thus "@param" not "\param").
Function Declarations
---------------------
Multi-line function declarations are preferred, as they tend to be more
readable. Use the following form:
static bool ExampleFunctionDeclaration(
uint32_t ulFirstParameter,
char *pszPointer,
uint8_t **ppbBuffer)
{
uint16_t uLocalVar; /* descriptive comment */
uint8_t *pbBuffer = NULL; /* descriptive comment */
Function body...
}
The following guidelines should be used:
- Align both the data-type and the variable names, for parameters and locals, at
the same level if practical.
- For pointer types, the '*' belongs to the variable name---it's not part of the
data-type, so keep it with the variable name.
- If useful, single line comments may be used to describe local variables (not
a requirement).
- For functions with no parameters, the "void" declaration does not need to be
on a separate line.
- Generally each variable should be declared on a separate line. This promotes
readability, and facilitates having a comment for each variable.
Function declarations should be spaced apart by two blank lines between the
closing brace which ends a function and the Doxygen comment which starts the
next.
Curly Braces
------------
Datalight lines up all curly braces vertically. As per MISRA-C, curly braces
are never omitted, even if the braces contain only a single statement.
For consistency, even structure declarations and initializations should use the
same style, with the curly braces lined up vertically. One exception is for
structure initializations where both the opening and closing curly braces can
fit on the same line. If so, do it.
Code Comments
-------------
Datalight uses the standard C style /* comments */. C++ style comments (//) are
never used. The Datalight standard comment style is shown below. This style
applies to all general comments within the code.
/* This is a single-line comment.
*/
if(ulFirstParameter > 0U)
{
/* This is a multi-line comment. Filler text: Lorem ipsum dolor sit amet,
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore
et dolore magna aliqua.
*/
while(fStatus)
{
}
}
Note the characteristics:
- The /* and */ align with the natural 4 character indentation.
- The comment text is exactly indented another 4 characters.
- The comment text starts on the same line as the opening /*.
- The terminating */ is on its own line.
- There is usually a single blank line preceding the comment, however if the
preceding line is an opening curly brace, then an extra blank line is not
necessary.
- There is usually no blank line after the comment, but rather the closing */
"attaches" the comment to the code about which the comment refers.
- These comments should always fit with the standard 80 character margin.
Comments where the /* and */ are on the same line may be used in a few places:
- For variable or parameter descriptions, where the comment fits on the same
line as the declaration.
- For structure member declarations, where the comment fits on the same line as
the declaration.
- For macros or preprocessor logic, where the comment fits on the same line.
It is OK for such comments to exceed the 80 character margin by a small amount,
if necessary, as this sometimes promotes code readability.
Indentation Style
-----------------
The general paradigm used in Datalight code is that curly braces line up
vertically, and everything in between them is indented. This should include all
comments, labels, and preprocessor symbols. The only things which are aligned
at the left-most columns are:
- Symbols, variables, declarations, and preprocessor logic which are at the
module-scope (outside of a function)
- Comments which are outside of a function
- Function declarations
- Function open and closing curly braces
Typically comments are always lined up directly with the code to which they
apply.
Labels (when used; gotos are disallowed in driver code) are lined up two
characters to the left of the code they reside in, to make them stand out, while
as the same time, still remaining subservient to the level of curly braces in
which they reside. For example:
bool ExampleLabelUsage(void)
{
MutexLock();
Lots of complicated code...
Unlock:
MutexUnlock();
return fSuccess;
}
Preprocessor logic, such as controlling features which are conditionally
compiled in or out, should not disrupt the flow of the code, but rather should
be indented in similar fashion to the code it controls, but positioned two
characters to the left. For example, consider the following code snippet. The
preprocessor conditions are both indented relative to the outer curly braces,
but do not disrupt the normal code flow.
int32_t red_statvfs(
const char *pszVolume,
REDSTATFS *pStatvfs)
{
REDSTATUS ret;
ret = PosixEnter();
if(ret == 0)
{
uint8_t bVolNum;
ret = RedPathSplit(pszVolume, &bVolNum, NULL);
#if REDCONF_VOLUME_COUNT > 1U
if(ret == 0)
{
ret = RedCoreVolSetCurrent(bVolNum);
}
#endif
if(ret == 0)
{
ret = RedCoreVolStat(pStatvfs);
}
PosixLeave();
}
return PosixReturn(ret);
}
Note that, like anything else between curly brackets, the contents of a switch
statement are indented:
switch(ulSignature)
{
case META_SIG_MASTER:
fValid = (uFlags == BFLAG_META_MASTER);
break;
case META_SIG_IMAP:
fValid = (uFlags == BFLAG_META_IMAP);
break;
case META_SIG_INODE:
fValid = (uFlags == BFLAG_META_INODE);
break;
case META_SIG_DINDIR:
fValid = (uFlags == BFLAG_META_DINDIR);
break;
case META_SIG_INDIR:
fValid = (uFlags == BFLAG_META_INDIR);
break;
default:
fValid = false;
break;
}
Maximum Line Length
-------------------
The maximum line length for code need not be rigidly limited to the traditional
80 characters. Nevertheless the line lengths should be kept reasonable.
Anything longer than 100 to 120 characters should probably be broken up. The
most important consideration is readability---fitting on the screen is important
for readability, but equally important is facilitating an easy understanding of
the logical code flow.
There are a few exceptions on both sides of the issue. Generally comments
should be limited to 80 characters always. Some lines of code may exceed the
120 character length by a large margin, if it makes the code more understandable
and maintainable. This is especially true when dealing with code that generates
output which needs to be lined up.
Regardless of everything else, no lines should exceed 250 characters because
some editors cannot handle anything larger.
Maximum Display Output Line Length
----------------------------------
Any code which displays TTY style output, whether on a screen or a terminal,
should be constructed so the output is readable and wraps properly on an 80
character wide display. This primarily applies to the "standard" output from
various tests and tools as well as syntax output for those tests and tools;
debug output can violate this rule.
Preprocessor Notation
---------------------
Don't use preprocessor notation where the # is separated from the keyword by one
or more white spaces. For example, don't do:
#ifndef SYMBOL1
# define SYMBOL1
#endif
Instead, do:
#ifndef SYMBOL1
#define SYMBOL1
#endif
Hexadecimal Notation
--------------------
Use uppercase for any alphabetic hexadecimal digits, and lower case for the
notational element. For example:
#define HEXNUM 0x123abd /* Bad */
#define HEXNUM 0X123ABD /* Bad */
#define HEXNUM 0x123ABD /* Good */
Hungarian Notation
------------------
Datalight uses Hungarian notation. The following type prefixes are used:
Type Prefix | Meaning
----------- | -------
c | char
uc | unsigned char
i | int
n | unsigned int or size_t
b | uint8_t
u | uint16_t
ul | uint32_t
ull | uint64_t
sz | array of char that will be null-terminated
f | bool
h | A handle
fn | A function (always used with the "p" modifier)
There is no official Hungarian for int8_t, int16_t, int32_t, or int64_t,
although some code uses unofficial variants (like "ll" for int64_t).
The following modifiers may be used in combination with the type prefixes
defined above, or in combination with other types:
Modifier | Meaning
-------- | -------
a | An array
p | A pointer
g | A global variable
Notes:
- There is no standard Hungarian for structure declarations, however the use of
the "a" and "p" modifiers is completely appropriate (and expected).
- For those data types which do not have any standard defined Hungarian prefix,
using none is preferable to misusing another prefix which would lead to
confusion.
- The "p" pointer modifier must be used such that a variable which is a pointer
to a pointer uses multiple "p" prefixes. A general rule-of-thumb is that the
variable name should have the same number of "p" prefixes as the declaration
has asterisks. This allows pointer expressions to be easily decoded using
cancellation.
Variable Scope
--------------
Declare a variable in the narrowest scope in which it is meaningful.
Unnecessarily declaring all variables at the beginning of a function, where they
may be physically far from where they are actually used, makes the code harder
to maintain.
When multiple blocks of code share a variable, but not its value, declare the
variable separately for each code block.
For example, if two separate blocks contain loops indexed by a variable ulIndex
declare it separately in each block rather than declaring it once in a wider
scope and using it in both places.
Using distinct declarations in the two blocks allows the compiler to check for
failure to initialize the variable in the second block. If there is a single
declaration, the (now meaningless) value left over from the first block can be
used erroneously in the second block.

View file

@ -0,0 +1,61 @@
# Reliance Edge Release Notes
This file contains a list of updates made to Reliance Edge over the course of
recent releases and a list of known issues.
## Release History and Changes
### Reliance Edge v1.0, July 2015
#### Common Code Changes
- First release of commercial kit and MISRA C:2012 Design Assurance Package.
The commercial kit includes many new tools and tests which were not previously
available.
- Overhauled parsing of command-line parameters to be consistent for all tools
and tests. Command-line tools now use Unix-style short and long options (such
as `-H` and `--help`) instead of DOS-style switches (such as `/?`).
- Renamed all os/\*/include/ostypes.h headers to os/\*/include/redostypes.h, so
that all headers use the product prefix. If you created a port using v0.9,
this header needs to be renamed and its header guard (#ifndef OSTYPES_H etc.)
should also be updated.
- Add a new header for OS-specific MISRA C:2012 deviation macros, located at
os/\*/include/redosdeviations.h. If you created a port using v0.9, copy the
template from os/stub/include/redosdeviations.h into the include directory.
- Eliminated support for sector sizes less than 256. If using a smaller sector
size (say for a RAM disk), this must now be emulated in the implementation of
the block device OS service.
- Added RedFseFormat() as an optional FSE API, allowing FSE applications to
format the volume at run-time.
- This added a new macro to redconf.h: existing redconf.h files from v0.9 must
be updated to work with v1.0. Open redconf.h with the configuration tool,
ignore the warning about the missing macro, and save it.
- Internal restructuring has renamed the macros for the string and memory
functions used in redconf.h. An existing redconf.h file from v0.9 will need
to be updated; for a file containing the old names, the new config tool will
default to using the (slow) Reliance Edge string/memory functions; to use the
C library or custom versions, this will need to be selected in the
configuration utility.
- Fix a bug which would result in an error when attempting to create a name with
one or more trailing path separators (such as `red_mkdir("/foo/bar/")`).
- Fix a bug where an open handle for an inode on one volume would prevent the
same inode number from being deleted on a different volume.
#### FreeRTOS Port Changes
- The implementation of the timestamp OS service no longer requires that
`configUSE_TIMERS` be set to `1`.
### Reliance Edge v0.9 (Beta), April 2015
First public release.
## Known Issues
### Visual Studio 2005
The Reliance Edge Win32 port (used for the host tools and the Win32 test
project) cannot be compiled by Visual Studio 2005. This is not going to be
fixed since VS2005 is an old toolset. Newer versions of Visual Studio, starting
with Visual Studio 2008, work just fine.

View file

@ -0,0 +1,71 @@
RELIANCE EDGE RELEASE NOTES
This file contains a list of updates made to Reliance Edge over the
course of recent releases and a list of known issues.
Release History and Changes
Reliance Edge v1.0, July 2015
Common Code Changes
- First release of commercial kit and MISRA C:2012 Design
Assurance Package. The commercial kit includes many new tools and
tests which were not previously available.
- Overhauled parsing of command-line parameters to be consistent for
all tools and tests. Command-line tools now use Unix-style short and
long options (such as -H and --help) instead of DOS-style switches
(such as /?).
- Renamed all os/*/include/ostypes.h headers to
os/*/include/redostypes.h, so that all headers use the
product prefix. If you created a port using v0.9, this header needs
to be renamed and its header guard (#ifndef OSTYPES_H etc.) should
also be updated.
- Add a new header for OS-specific MISRA C:2012 deviation macros,
located at os/*/include/redosdeviations.h. If you created a port
using v0.9, copy the template from os/stub/include/redosdeviations.h
into the include directory.
- Eliminated support for sector sizes less than 256. If using a
smaller sector size (say for a RAM disk), this must now be emulated
in the implementation of the block device OS service.
- Added RedFseFormat() as an optional FSE API, allowing FSE
applications to format the volume at run-time.
- This added a new macro to redconf.h: existing redconf.h files from
v0.9 must be updated to work with v1.0. Open redconf.h with the
configuration tool, ignore the warning about the missing macro, and
save it.
- Internal restructuring has renamed the macros for the string and
memory functions used in redconf.h. An existing redconf.h file from
v0.9 will need to be updated; for a file containing the old names,
the new config tool will default to using the (slow) Reliance Edge
string/memory functions; to use the C library or custom versions,
this will need to be selected in the configuration utility.
- Fix a bug which would result in an error when attempting to create a
name with one or more trailing path separators (such as
red_mkdir("/foo/bar/")).
- Fix a bug where an open handle for an inode on one volume would
prevent the same inode number from being deleted on a
different volume.
FreeRTOS Port Changes
- The implementation of the timestamp OS service no longer requires
that configUSE_TIMERS be set to 1.
Reliance Edge v0.9 (Beta), April 2015
First public release.
Known Issues
Visual Studio 2005
The Reliance Edge Win32 port (used for the host tools and the Win32 test
project) cannot be compiled by Visual Studio 2005. This is not going to
be fixed since VS2005 is an old toolset. Newer versions of Visual
Studio, starting with Visual Studio 2008, work just fine.

View file

@ -0,0 +1,690 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implementation of the Reliance Edge FSE API.
*/
#include <redfs.h>
#if REDCONF_API_FSE == 1
/** @defgroup red_group_fse The File System Essentials Interface
@{
*/
#include <redvolume.h>
#include <redcoreapi.h>
#include <redfse.h>
static REDSTATUS FseEnter(uint8_t bVolNum);
static void FseLeave(void);
static bool gfFseInited; /* Whether driver is initialized. */
/** @brief Initialize the Reliance Edge file system driver.
Prepares the Reliance Edge file system driver to be used. Must be the first
Reliance Edge function to be invoked: no volumes can be mounted until the
driver has been initialized.
If this function is called when the Reliance Edge driver is already
initialized, it does nothing and returns success.
This function is not thread safe: attempting to initialize from multiple
threads could leave things in a bad state.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
*/
REDSTATUS RedFseInit(void)
{
REDSTATUS ret;
if(gfFseInited)
{
ret = 0;
}
else
{
ret = RedCoreInit();
if(ret == 0)
{
gfFseInited = true;
}
}
return ret;
}
/** @brief Uninitialize the Reliance Edge file system driver.
Tears down the Reliance Edge file system driver. Cannot be used until all
Reliance Edge volumes are unmounted. A subsequent call to RedFseInit()
will initialize the driver again.
If this function is called when the Reliance Edge driver is already
uninitialized, it does nothing and returns success.
This function is not thread safe: attempting to uninitialize from multiple
threads could leave things in a bad state.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EBUSY At least one volume is still mounted.
*/
REDSTATUS RedFseUninit(void)
{
REDSTATUS ret = 0;
if(!gfFseInited)
{
ret = 0;
}
else
{
uint8_t bVolNum;
#if REDCONF_TASK_COUNT > 1U
RedOsMutexAcquire();
#endif
for(bVolNum = 0U; bVolNum < REDCONF_VOLUME_COUNT; bVolNum++)
{
if(gaRedVolume[bVolNum].fMounted)
{
ret = -RED_EBUSY;
break;
}
}
if(ret == 0)
{
gfFseInited = false;
}
#if REDCONF_TASK_COUNT > 1U
RedOsMutexRelease();
#endif
if(ret == 0)
{
ret = RedCoreUninit();
}
}
return ret;
}
/** @brief Mount a file system volume.
Prepares the file system volume to be accessed. Mount will fail if the
volume has never been formatted, or if the on-disk format is inconsistent
with the compile-time configuration.
If the volume is already mounted, this function does nothing and returns
success.
@param bVolNum The volume number of the volume to be mounted.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p bVolNum is an invalid volume number; or the driver is
uninitialized.
@retval -RED_EIO Volume not formatted, improperly formatted, or corrupt.
*/
REDSTATUS RedFseMount(
uint8_t bVolNum)
{
REDSTATUS ret;
ret = FseEnter(bVolNum);
if(ret == 0)
{
if(!gpRedVolume->fMounted)
{
ret = RedCoreVolMount();
}
FseLeave();
}
return ret;
}
/** @brief Unmount a file system volume.
This function discards the in-memory state for the file system and marks it
as unmounted. Subsequent attempts to access the volume will fail until the
volume is mounted again.
If unmount automatic transaction points are enabled, this function will
commit a transaction point prior to unmounting. If unmount automatic
transaction points are disabled, this function will unmount without
transacting, effectively discarding the working state.
Before unmounting, this function will wait for any active file system
thread to complete by acquiring the FS mutex. The volume will be marked as
unmounted before the FS mutex is released, so subsequent FS threads will
possibly block and then see an error when attempting to access a volume
which is unmounting or unmounted.
If the volume is already unmounted, this function does nothing and returns
success.
@param bVolNum The volume number of the volume to be unmounted.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p bVolNum is an invalid volume number; or the driver is
uninitialized.
@retval -RED_EIO I/O error during unmount automatic transaction point.
*/
REDSTATUS RedFseUnmount(
uint8_t bVolNum)
{
REDSTATUS ret;
ret = FseEnter(bVolNum);
if(ret == 0)
{
if(gpRedVolume->fMounted)
{
ret = RedCoreVolUnmount();
}
FseLeave();
}
return ret;
}
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_FSE_FORMAT == 1)
/** @brief Format a file system volume.
Uses the statically defined volume configuration. After calling this
function, the volume needs to be mounted -- see RedFseMount().
An error is returned if the volume is mounted.
@param bVolNum The volume number of the volume to be formatted.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EBUSY The volume is mounted.
@retval -RED_EINVAL @p bVolNum is an invalid volume number; or the driver is
uninitialized.
@retval -RED_EIO I/O error formatting the volume.
*/
REDSTATUS RedFseFormat(
uint8_t bVolNum)
{
REDSTATUS ret;
ret = FseEnter(bVolNum);
if(ret == 0)
{
ret = RedCoreVolFormat();
FseLeave();
}
return ret;
}
#endif
/** @brief Read from a file.
Data which has not yet been written, but which is before the end-of-file
(sparse data), shall read as zeroes. A short read -- where the number of
bytes read is less than requested -- indicates that the requested read was
partially or, if zero bytes were read, entirely beyond the end-of-file.
If @p ullFileOffset is at or beyond the maximum file size, it is treated
like any other read entirely beyond the end-of-file: no data is read and
zero is returned.
@param bVolNum The volume number of the file to read.
@param ulFileNum The file number of the file to read.
@param ullFileOffset The file offset to read from.
@param ulLength The number of bytes to read.
@param pBuffer The buffer to populate with the data read. Must be
at least ulLength bytes in size.
@return The number of bytes read (nonnegative) or a negated ::REDSTATUS
code indicating the operation result (negative).
@retval >=0 The number of bytes read from the file.
@retval -RED_EBADF @p ulFileNum is not a valid file number.
@retval -RED_EINVAL @p bVolNum is an invalid volume number or not mounted;
or @p pBuffer is `NULL`; or @p ulLength exceeds
INT32_MAX and cannot be returned properly.
@retval -RED_EIO A disk I/O error occurred.
*/
int32_t RedFseRead(
uint8_t bVolNum,
uint32_t ulFileNum,
uint64_t ullFileOffset,
uint32_t ulLength,
void *pBuffer)
{
int32_t ret;
if(ulLength > (uint32_t)INT32_MAX)
{
ret = -RED_EINVAL;
}
else
{
ret = FseEnter(bVolNum);
}
if(ret == 0)
{
uint32_t ulReadLen = ulLength;
ret = RedCoreFileRead(ulFileNum, ullFileOffset, &ulReadLen, pBuffer);
FseLeave();
if(ret == 0)
{
ret = (int32_t)ulReadLen;
}
}
return ret;
}
#if REDCONF_READ_ONLY == 0
/** @brief Write to a file.
If the write extends beyond the end-of-file, the file size will be
increased.
A short write -- where the number of bytes written is less than requested
-- indicates either that the file system ran out of space but was still
able to write some of the request; or that the request would have caused
the file to exceed the maximum file size, but some of the data could be
written prior to the file size limit.
If an error is returned (negative return), either none of the data was
written or a critical error occurred (like an I/O error) and the file
system volume will be read-only.
@param bVolNum The volume number of the file to write.
@param ulFileNum The file number of the file to write.
@param ullFileOffset The file offset to write at.
@param ulLength The number of bytes to write.
@param pBuffer The buffer containing the data to be written. Must
be at least ulLength bytes in size.
@return The number of bytes written (nonnegative) or a negated ::REDSTATUS
code indicating the operation result (negative).
@retval >0 The number of bytes written to the file.
@retval -RED_EBADF @p ulFileNum is not a valid file number.
@retval -RED_EFBIG No data can be written to the given file offset since
the resulting file size would exceed the maximum file
size.
@retval -RED_EINVAL @p bVolNum is an invalid volume number or not mounted;
or @p pBuffer is `NULL`; or @p ulLength exceeds
INT32_MAX and cannot be returned properly.
@retval -RED_EIO A disk I/O error occurred.
@retval -RED_ENOSPC No data can be written because there is insufficient
free space.
@retval -RED_EROFS The file system volume is read-only.
*/
int32_t RedFseWrite(
uint8_t bVolNum,
uint32_t ulFileNum,
uint64_t ullFileOffset,
uint32_t ulLength,
const void *pBuffer)
{
int32_t ret;
if(ulLength > (uint32_t)INT32_MAX)
{
ret = -RED_EINVAL;
}
else
{
ret = FseEnter(bVolNum);
}
if(ret == 0)
{
uint32_t ulWriteLen = ulLength;
ret = RedCoreFileWrite(ulFileNum, ullFileOffset, &ulWriteLen, pBuffer);
FseLeave();
if(ret == 0)
{
ret = (int32_t)ulWriteLen;
}
}
return ret;
}
#endif
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_FSE_TRUNCATE == 1)
/** @brief Truncate a file (set the file size).
Allows the file size to be increased, decreased, or to remain the same. If
the file size is increased, the new area is sparse (will read as zeroes).
If the file size is decreased, the data beyond the new end-of-file will
return to free space once it is no longer part of the committed state
(either immediately or after the next transaction point).
This function can fail when the disk is full if @p ullNewFileSize is
non-zero. If decreasing the file size, this can be fixed by transacting and
trying again: Reliance Edge guarantees that it is possible to perform a
truncate of at least one file that decreases the file size after a
transaction point. If disk full transactions are enabled, this will happen
automatically.
@param bVolNum The volume number of the file to truncate.
@param ulFileNum The file number of the file to truncate.
@param ullNewFileSize The new file size, in bytes.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EBADF @p ulFileNum is not a valid file number.
@retval -RED_EFBIG @p ullNewFileSize exceeds the maximum file size.
@retval -RED_EINVAL @p bVolNum is an invalid volume number or not mounted.
@retval -RED_EIO A disk I/O error occurred.
@retval -RED_ENOSPC Insufficient free space to perform the truncate.
@retval -RED_EROFS The file system volume is read-only.
*/
REDSTATUS RedFseTruncate(
uint8_t bVolNum,
uint32_t ulFileNum,
uint64_t ullNewFileSize)
{
REDSTATUS ret;
ret = FseEnter(bVolNum);
if(ret == 0)
{
ret = RedCoreFileTruncate(ulFileNum, ullNewFileSize);
FseLeave();
}
return ret;
}
#endif
/** @brief Retrieve the size of a file.
@param bVolNum The volume number of the file whose size is being read.
@param ulFileNum The file number of the file whose size is being read.
@return The size of the file (nonnegative) or a negated ::REDSTATUS code
indicating the operation result (negative).
@retval >=0 The size of the file.
@retval -RED_EBADF @p ulFileNum is not a valid file number.
@retval -RED_EINVAL @p bVolNum is an invalid volume number or not mounted.
@retval -RED_EIO A disk I/O error occurred.
*/
int64_t RedFseSizeGet(
uint8_t bVolNum,
uint32_t ulFileNum)
{
int64_t ret;
ret = FseEnter(bVolNum);
if(ret == 0)
{
uint64_t ullSize;
ret = RedCoreFileSizeGet(ulFileNum, &ullSize);
FseLeave();
if(ret == 0)
{
/* Unless there is an on-disk format change, the maximum file size
is guaranteed to be less than INT64_MAX, and so it can be safely
returned in an int64_t.
*/
REDASSERT(ullSize < (uint64_t)INT64_MAX);
ret = (int64_t)ullSize;
}
}
return ret;
}
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_FSE_TRANSMASKSET == 1)
/** @brief Update the transaction mask.
The following events are available:
- #RED_TRANSACT_UMOUNT
- #RED_TRANSACT_WRITE
- #RED_TRANSACT_TRUNCATE
- #RED_TRANSACT_VOLFULL
The #RED_TRANSACT_MANUAL macro (by itself) may be used to disable all
automatic transaction events. The #RED_TRANSACT_MASK macro is a bitmask of
all transaction flags, excluding those representing excluded functionality.
Attempting to enable events for excluded functionality will result in an
error.
@param bVolNum The volume number of the volume whose transaction mask
is being changed.
@param ulEventMask A bitwise-OR'd mask of automatic transaction events to
be set as the current transaction mode.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p bVolNum is an invalid volume number or not mounted;
or @p ulEventMask contains invalid bits.
@retval -RED_EROFS The file system volume is read-only.
*/
REDSTATUS RedFseTransMaskSet(
uint8_t bVolNum,
uint32_t ulEventMask)
{
REDSTATUS ret;
ret = FseEnter(bVolNum);
if(ret == 0)
{
ret = RedCoreTransMaskSet(ulEventMask);
FseLeave();
}
return ret;
}
#endif
#if REDCONF_API_FSE_TRANSMASKGET == 1
/** @brief Read the transaction mask.
If the volume is read-only, the returned event mask is always zero.
@param bVolNum The volume number of the volume whose transaction mask
is being retrieved.
@param pulEventMask Populated with a bitwise-OR'd mask of automatic
transaction events which represent the current
transaction mode for the volume.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p bVolNum is an invalid volume number or not mounted;
or @p pulEventMask is `NULL`.
*/
REDSTATUS RedFseTransMaskGet(
uint8_t bVolNum,
uint32_t *pulEventMask)
{
REDSTATUS ret;
ret = FseEnter(bVolNum);
if(ret == 0)
{
ret = RedCoreTransMaskGet(pulEventMask);
FseLeave();
}
return ret;
}
#endif
#if REDCONF_READ_ONLY == 0
/** @brief Commit a transaction point.
Reliance Edge is a transactional file system. All modifications, of both
metadata and filedata, are initially working state. A transaction point
is a process whereby the working state atomically becomes the committed
state, replacing the previous committed state. Whenever Reliance Edge is
mounted, including after power loss, the state of the file system after
mount is the most recent committed state. Nothing from the committed
state is ever missing, and nothing from the working state is ever included.
@param bVolNum The volume number of the volume to transact.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p bVolNum is an invalid volume number or not mounted.
@retval -RED_EIO A disk I/O error occurred.
@retval -RED_EROFS The file system volume is read-only.
*/
REDSTATUS RedFseTransact(
uint8_t bVolNum)
{
REDSTATUS ret;
ret = FseEnter(bVolNum);
if(ret == 0)
{
ret = RedCoreVolTransact();
FseLeave();
}
return ret;
}
#endif
/** @} */
/** @brief Enter the file system driver.
@param bVolNum The volume to be accessed.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL The file system driver is uninitialized; or @p bVolNum
is not a valid volume number.
*/
static REDSTATUS FseEnter(
uint8_t bVolNum)
{
REDSTATUS ret;
if(gfFseInited)
{
#if REDCONF_TASK_COUNT > 1U
RedOsMutexAcquire();
#endif
/* This also serves to range-check the volume number (even in single
volume configurations).
*/
ret = RedCoreVolSetCurrent(bVolNum);
#if REDCONF_TASK_COUNT > 1U
if(ret != 0)
{
RedOsMutexRelease();
}
#endif
}
else
{
ret = -RED_EINVAL;
}
return ret;
}
/** @brief Leave the file system driver.
*/
static void FseLeave(void)
{
REDASSERT(gfFseInited);
#if REDCONF_TASK_COUNT > 1U
RedOsMutexRelease();
#endif
}
#endif /* REDCONF_API_FSE == 1 */

View file

@ -0,0 +1,112 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Defines macros used to interact with the Reliance Edge API.
*/
#ifndef REDAPIMACS_H
#define REDAPIMACS_H
/** Clear all events: manual transactions only. */
#define RED_TRANSACT_MANUAL 0x00000000U
/** Transact prior to unmounting in red_umount() or RedFseUnmount(). */
#define RED_TRANSACT_UMOUNT 0x00000001U
/** Transact after a successful red_open() which created a file. */
#define RED_TRANSACT_CREAT 0x00000002U
/** Transact after a successful red_unlink() or red_rmdir(). */
#define RED_TRANSACT_UNLINK 0x00000004U
/** Transact after a successful red_mkdir(). */
#define RED_TRANSACT_MKDIR 0x00000008U
/** Transact after a successful red_rename(). */
#define RED_TRANSACT_RENAME 0x00000010U
/** Transact after a successful red_link(). */
#define RED_TRANSACT_LINK 0x00000020U
/** Transact after a successful red_close(). */
#define RED_TRANSACT_CLOSE 0x00000040U
/** Transact after a successful red_write() or RedFseWrite(). */
#define RED_TRANSACT_WRITE 0x00000080U
/** Transact after a successful red_fsync(). */
#define RED_TRANSACT_FSYNC 0x00000100U
/** Transact after a successful red_ftruncate(), RedFseTruncate(), or red_open() with RED_O_TRUNC that actually truncates. */
#define RED_TRANSACT_TRUNCATE 0x00000200U
/** Transact to free space in disk full situations. */
#define RED_TRANSACT_VOLFULL 0x00000400U
#if REDCONF_READ_ONLY == 1
/** Mask of all supported automatic transaction events. */
#define RED_TRANSACT_MASK 0U
#elif REDCONF_API_POSIX == 1
/** @brief Mask of all supported automatic transaction events.
*/
#define RED_TRANSACT_MASK \
( \
RED_TRANSACT_UMOUNT | \
RED_TRANSACT_CREAT | \
((REDCONF_API_POSIX_UNLINK == 1) ? RED_TRANSACT_UNLINK : 0U) | \
((REDCONF_API_POSIX_MKDIR == 1) ? RED_TRANSACT_MKDIR : 0U) | \
((REDCONF_API_POSIX_RENAME == 1) ? RED_TRANSACT_RENAME : 0U) | \
((REDCONF_API_POSIX_LINK == 1) ? RED_TRANSACT_LINK : 0U) | \
RED_TRANSACT_CLOSE | \
RED_TRANSACT_WRITE | \
RED_TRANSACT_FSYNC | \
((REDCONF_API_POSIX_FTRUNCATE == 1) ? RED_TRANSACT_TRUNCATE : 0U) | \
RED_TRANSACT_VOLFULL \
)
#else /* REDCONF_API_FSE == 1 */
/** @brief Mask of all supported automatic transaction events.
*/
#define RED_TRANSACT_MASK \
( \
RED_TRANSACT_UMOUNT | \
RED_TRANSACT_WRITE | \
((REDCONF_API_FSE_TRUNCATE == 1) ? RED_TRANSACT_TRUNCATE : 0U) | \
RED_TRANSACT_VOLFULL \
)
#endif /* REDCONF_READ_ONLY */
#if (REDCONF_TRANSACT_DEFAULT & RED_TRANSACT_MASK) != REDCONF_TRANSACT_DEFAULT
#error "Configuration error: invalid value of REDCONF_TRANSACT_DEFAULT"
#endif
#endif

View file

@ -0,0 +1,317 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Compile-time validity checks for the REDCONF macros.
*/
#ifndef REDCONFIGCHK_H
#define REDCONFIGCHK_H
#ifndef REDCONF_READ_ONLY
#error "Configuration error: REDCONF_READ_ONLY must be defined."
#endif
#ifndef REDCONF_API_POSIX
#error "Configuration error: REDCONF_API_POSIX must be defined."
#endif
#ifndef REDCONF_API_FSE
#error "Configuration error: REDCONF_API_FSE must be defined."
#endif
#if REDCONF_API_POSIX == 1
#ifndef REDCONF_API_POSIX_FORMAT
#error "Configuration error: REDCONF_API_POSIX_FORMAT must be defined."
#endif
#ifndef REDCONF_API_POSIX_UNLINK
#error "Configuration error: REDCONF_API_POSIX_UNLINK must be defined."
#endif
#ifndef REDCONF_API_POSIX_MKDIR
#error "Configuration error: REDCONF_API_POSIX_MKDIR must be defined."
#endif
#ifndef REDCONF_API_POSIX_RMDIR
#error "Configuration error: REDCONF_API_POSIX_RMDIR must be defined."
#endif
#ifndef REDCONF_API_POSIX_RENAME
#error "Configuration error: REDCONF_API_POSIX_RENAME must be defined."
#endif
#ifndef REDCONF_API_POSIX_LINK
#error "Configuration error: REDCONF_API_POSIX_LINK must be defined."
#endif
#ifndef REDCONF_API_POSIX_FTRUNCATE
#error "Configuration error: REDCONF_API_POSIX_FTRUNCATE must be defined."
#endif
#ifndef REDCONF_API_POSIX_READDIR
#error "Configuration error: REDCONF_API_POSIX_READDIR must be defined."
#endif
#ifndef REDCONF_NAME_MAX
#error "Configuration error: REDCONF_NAME_MAX must be defined."
#endif
#ifndef REDCONF_PATH_SEPARATOR
#error "Configuration error: REDCONF_PATH_SEPARATOR must be defined."
#endif
#ifndef REDCONF_RENAME_ATOMIC
#error "Configuration error: REDCONF_RENAME_ATOMIC must be defined."
#endif
#ifndef REDCONF_HANDLE_COUNT
#error "Configuration error: REDCONF_HANDLE_COUNT must be defined."
#endif
#endif
#if REDCONF_API_FSE == 1
#ifndef REDCONF_API_FSE_FORMAT
#error "Configuration error: REDCONF_API_FSE_FORMAT must be defined."
#endif
#ifndef REDCONF_API_FSE_TRUNCATE
#error "Configuration error: REDCONF_API_FSE_TRUNCATE must be defined."
#endif
#ifndef REDCONF_API_FSE_TRANSMASKSET
#error "Configuration error: REDCONF_API_FSE_TRANSMASKSET must be defined."
#endif
#ifndef REDCONF_API_FSE_TRANSMASKGET
#error "Configuration error: REDCONF_API_FSE_TRANSMASKGET must be defined."
#endif
#endif
#ifndef REDCONF_TASK_COUNT
#error "Configuration error: REDCONF_TASK_COUNT must be defined."
#endif
#ifndef REDCONF_ENDIAN_BIG
#error "Configuration error: REDCONF_ENDIAN_BIG must be defined."
#endif
#ifndef REDCONF_ALIGNMENT_SIZE
#error "Configuration error: REDCONF_ALIGNMENT_SIZE must be defined."
#endif
#ifndef REDCONF_CRC_ALGORITHM
#error "Configuration error: REDCONF_CRC_ALGORITHM must be defined."
#endif
#ifndef REDCONF_INODE_TIMESTAMPS
#error "Configuration error: REDCONF_INODE_TIMESTAMPS must be defined."
#endif
#ifndef REDCONF_ATIME
#error "Configuration error: REDCONF_ATIME must be defined."
#endif
#ifndef REDCONF_DIRECT_POINTERS
#error "Configuration error: REDCONF_DIRECT_POINTERS must be defined."
#endif
#ifndef REDCONF_INDIRECT_POINTERS
#error "Configuration error: REDCONF_INDIRECT_POINTERS must be defined."
#endif
#ifndef REDCONF_INODE_BLOCKS
#error "Configuration error: REDCONF_INODE_BLOCKS must be defined."
#endif
#ifndef REDCONF_IMAP_EXTERNAL
#error "Configuration error: REDCONF_IMAP_EXTERNAL must be defined."
#endif
#ifndef REDCONF_IMAP_INLINE
#error "Configuration error: REDCONF_IMAP_INLINE must be defined."
#endif
#ifndef REDCONF_OUTPUT
#error "Configuration error: REDCONF_OUTPUT must be defined."
#endif
#ifndef REDCONF_ASSERTS
#error "Configuration error: REDCONF_ASSERTS must be defined."
#endif
#ifndef REDCONF_TRANSACT_DEFAULT
#error "Configuration error: REDCONF_TRANSACT_DEFAULT must be defined."
#endif
#ifndef REDCONF_BUFFER_COUNT
#error "Configuration error: REDCONF_BUFFER_COUNT must be defined."
#endif
#ifndef REDCONF_BLOCK_SIZE
#error "Configuration error: REDCONF_BLOCK_SIZE must be defined."
#endif
#ifndef REDCONF_VOLUME_COUNT
#error "Configuration error: REDCONF_VOLUME_COUNT must be defined."
#endif
#ifndef REDCONF_IMAGE_BUILDER
#error "Configuration error: REDCONF_IMAGE_BUILDER must be defined."
#endif
#ifndef REDCONF_CHECKER
#error "Configuration error: REDCONF_CHECKER must be defined."
#endif
#if (REDCONF_READ_ONLY != 0) && (REDCONF_READ_ONLY != 1)
#error "Configuration error: REDCONF_READ_ONLY must be either 0 or 1"
#endif
#if (REDCONF_API_POSIX != 0) && (REDCONF_API_POSIX != 1)
#error "Configuration error: REDCONF_API_POSIX must be either 0 or 1."
#endif
#if (REDCONF_API_FSE != 0) && (REDCONF_API_FSE != 1)
#error "Configuration error: REDCONF_API_FSE must be either 0 or 1."
#endif
#if (REDCONF_API_FSE == 0) && (REDCONF_API_POSIX == 0)
#error "Configuration error: either REDCONF_API_FSE or REDCONF_API_POSIX must be set to 1."
#endif
#if REDCONF_API_POSIX == 1
#if REDCONF_API_FSE != 0
#error "Configuration error: REDCONF_API_FSE must be 0 if REDCONF_API_POSIX is 1"
#endif
#if (REDCONF_API_POSIX_FORMAT != 0) && (REDCONF_API_POSIX_FORMAT != 1)
#error "Configuration error: REDCONF_API_POSIX_FORMAT must be either 0 or 1."
#endif
#if (REDCONF_API_POSIX_UNLINK != 0) && (REDCONF_API_POSIX_UNLINK != 1)
#error "Configuration error: REDCONF_API_POSIX_UNLINK must be either 0 or 1."
#endif
#if (REDCONF_API_POSIX_MKDIR != 0) && (REDCONF_API_POSIX_MKDIR != 1)
#error "Configuration error: REDCONF_API_POSIX_MKDIR must be either 0 or 1."
#endif
#if (REDCONF_API_POSIX_RMDIR != 0) && (REDCONF_API_POSIX_RMDIR != 1)
#error "Configuration error: REDCONF_API_POSIX_RMDIR must be either 0 or 1."
#endif
#if (REDCONF_API_POSIX_RENAME != 0) && (REDCONF_API_POSIX_RENAME != 1)
#error "Configuration error: REDCONF_API_POSIX_RENAME must be either 0 or 1."
#endif
#if (REDCONF_API_POSIX_LINK != 0) && (REDCONF_API_POSIX_LINK != 1)
#error "Configuration error: REDCONF_API_POSIX_LINK must be either 0 or 1."
#endif
#if (REDCONF_API_POSIX_FTRUNCATE != 0) && (REDCONF_API_POSIX_FTRUNCATE != 1)
#error "Configuration error: REDCONF_API_POSIX_FTRUNCATE must be either 0 or 1."
#endif
#if (REDCONF_API_POSIX_READDIR != 0) && (REDCONF_API_POSIX_READDIR != 1)
#error "Configuration error: REDCONF_API_POSIX_READDIR must be either 0 or 1."
#endif
#if (REDCONF_NAME_MAX < 1U) || (REDCONF_NAME_MAX > (REDCONF_BLOCK_SIZE - 4U))
#error "Configuration error: invalid value of REDCONF_NAME_MAX"
#endif
#if (REDCONF_PATH_SEPARATOR < 1) || (REDCONF_PATH_SEPARATOR > 127)
#error "Configuration error: invalid value of REDCONF_PATH_SEPARATOR"
#endif
#if (REDCONF_RENAME_ATOMIC != 0) && (REDCONF_RENAME_ATOMIC != 1)
#error "Configuration error: REDCONF_RENAME_ATOMIC must be either 0 or 1."
#endif
#if (REDCONF_HANDLE_COUNT < 1U) || (REDCONF_HANDLE_COUNT > 4096U)
#error "Configuration error: invalid value of REDCONF_HANDLE_COUNT"
#endif
#endif
#if REDCONF_API_FSE == 1
#if (REDCONF_API_FSE_FORMAT != 0) && (REDCONF_API_FSE_FORMAT != 1)
#error "Configuration error: REDCONF_API_FSE_FORMAT must be either 0 or 1."
#endif
#if (REDCONF_API_FSE_TRUNCATE != 0) && (REDCONF_API_FSE_TRUNCATE != 1)
#error "Configuration error: REDCONF_API_FSE_TRUNCATE must be either 0 or 1."
#endif
#if (REDCONF_API_FSE_TRANSMASKSET != 0) && (REDCONF_API_FSE_TRANSMASKSET != 1)
#error "Configuration error: REDCONF_API_FSE_TRANSMASKSET must be either 0 or 1."
#endif
#if (REDCONF_API_FSE_TRANSMASKGET != 0) && (REDCONF_API_FSE_TRANSMASKGET != 1)
#error "Configuration error: REDCONF_API_FSE_TRANSMASKGET must be either 0 or 1."
#endif
#endif
#if REDCONF_TASK_COUNT < 1U
#error "Configuration error: invalid value of REDCONF_TASK_COUNT"
#endif
#if (REDCONF_ENDIAN_BIG != 0) && (REDCONF_ENDIAN_BIG != 1)
#error "Configuration error: REDCONF_ENDIAN_BIG must be either 0 or 1."
#endif
#if (REDCONF_ALIGNMENT_SIZE != 1U) && (REDCONF_ALIGNMENT_SIZE != 2U) && (REDCONF_ALIGNMENT_SIZE != 4U) && (REDCONF_ALIGNMENT_SIZE != 8U)
#error "Configuration error: invalid value REDCONF_ALIGNMENT_SIZE"
#endif
/* REDCONF_CRC_ALGORITHM checked in crc.c
*/
#if (REDCONF_INODE_TIMESTAMPS != 0) && (REDCONF_INODE_TIMESTAMPS != 1)
#error "Configuration error: REDCONF_INODE_TIMESTAMPS must be either 0 or 1."
#endif
#if (REDCONF_ATIME != 0) && (REDCONF_ATIME != 1)
#error "Configuration error: REDCONF_ATIME must be either 0 or 1."
#endif
#if (REDCONF_INODE_TIMESTAMPS == 0) && (REDCONF_ATIME == 1)
#error "Configuration error: REDCONF_ATIME must be 0 when REDCONF_INODE_TIMESTAMPS is 0."
#endif
/* REDCONF_DIRECT_POINTERS and REDCONF_INDIRECT_POINTERS checked in rednodes.h
*/
#if (REDCONF_INODE_BLOCKS != 0) && (REDCONF_INODE_BLOCKS != 1)
#error "Configuration error: REDCONF_INODE_BLOCKS must be either 0 or 1."
#endif
/* Further validity checking of imap specs done in RelCoreInit()
*/
#if (REDCONF_IMAP_EXTERNAL != 0) && (REDCONF_IMAP_EXTERNAL != 1)
#error "Configuration error: REDCONF_IMAP_EXTERNAL must be either 0 or 1."
#endif
#if (REDCONF_IMAP_INLINE != 0) && (REDCONF_IMAP_INLINE != 1)
#error "Configuration error: REDCONF_IMAP_INLINE must be either 0 or 1."
#endif
#if (REDCONF_IMAP_INLINE == 0) && (REDCONF_IMAP_EXTERNAL == 0)
#error "Configuration error: At least one of REDCONF_IMAP_INLINE and REDCONF_IMAP_EXTERNAL must be set"
#endif
#if (REDCONF_OUTPUT != 0) && (REDCONF_OUTPUT != 1)
#error "Configuration error: REDCONF_OUTPUT must be either 0 or 1."
#endif
#if (REDCONF_ASSERTS != 0) && (REDCONF_ASSERTS != 1)
#error "Configuration error: REDCONF_ASSERTS must be either 0 or 1."
#endif
/* REDCONF_BLOCK_SIZE checked in redmacs.h
*/
#if (REDCONF_VOLUME_COUNT < 1U) || (REDCONF_VOLUME_COUNT > 255U)
#error "REDCONF_VOLUME_COUNT must be an integer between 1 and 255"
#endif
/* REDCONF_BUFFER_COUNT lower limit checked in buffer.c
*/
#if REDCONF_BUFFER_COUNT > 255U
#error "REDCONF_BUFFER_COUNT cannot be greater than 255"
#endif
#if (REDCONF_IMAGE_BUILDER != 0) && (REDCONF_IMAGE_BUILDER != 1)
#error "Configuration error: REDCONF_IMAGE_BUILDER must be either 0 or 1."
#endif
#if (REDCONF_CHECKER != 0) && (REDCONF_CHECKER != 1)
#error "Configuration error: REDCONF_CHECKER must be either 0 or 1."
#endif
#endif

View file

@ -0,0 +1,97 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDCOREAPI_H
#define REDCOREAPI_H
#include <redstat.h>
REDSTATUS RedCoreInit(void);
REDSTATUS RedCoreUninit(void);
REDSTATUS RedCoreVolSetCurrent(uint8_t bVolNum);
#if FORMAT_SUPPORTED
REDSTATUS RedCoreVolFormat(void);
#endif
#if REDCONF_CHECKER == 1
REDSTATUS RedCoreVolCheck(void);
#endif
REDSTATUS RedCoreVolMount(void);
REDSTATUS RedCoreVolUnmount(void);
#if REDCONF_READ_ONLY == 0
REDSTATUS RedCoreVolTransact(void);
#endif
#if REDCONF_API_POSIX == 1
REDSTATUS RedCoreVolStat(REDSTATFS *pStatFS);
#endif
#if (REDCONF_READ_ONLY == 0) && ((REDCONF_API_POSIX == 1) || (REDCONF_API_FSE_TRANSMASKSET == 1))
REDSTATUS RedCoreTransMaskSet(uint32_t ulEventMask);
#endif
#if (REDCONF_API_POSIX == 1) || (REDCONF_API_FSE_TRANSMASKGET == 1)
REDSTATUS RedCoreTransMaskGet(uint32_t *pulEventMask);
#endif
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX == 1)
REDSTATUS RedCoreCreate(uint32_t ulPInode, const char *pszName, bool fDir, uint32_t *pulInode);
#endif
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX == 1) && (REDCONF_API_POSIX_LINK == 1)
REDSTATUS RedCoreLink(uint32_t ulPInode, const char *pszName, uint32_t ulInode);
#endif
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX == 1) && ((REDCONF_API_POSIX_UNLINK == 1) || (REDCONF_API_POSIX_RMDIR == 1))
REDSTATUS RedCoreUnlink(uint32_t ulPInode, const char *pszName);
#endif
#if REDCONF_API_POSIX == 1
REDSTATUS RedCoreLookup(uint32_t ulPInode, const char *pszName, uint32_t *pulInode);
#endif
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX == 1) && (REDCONF_API_POSIX_RENAME == 1)
REDSTATUS RedCoreRename(uint32_t ulSrcPInode, const char *pszSrcName, uint32_t ulDstPInode, const char *pszDstName);
#endif
#if REDCONF_API_POSIX == 1
REDSTATUS RedCoreStat(uint32_t ulInode, REDSTAT *pStat);
#endif
#if REDCONF_API_FSE == 1
REDSTATUS RedCoreFileSizeGet(uint32_t ulInode, uint64_t *pullSize);
#endif
REDSTATUS RedCoreFileRead(uint32_t ulInode, uint64_t ullStart, uint32_t *pulLen, void *pBuffer);
#if REDCONF_READ_ONLY == 0
REDSTATUS RedCoreFileWrite(uint32_t ulInode, uint64_t ullStart, uint32_t *pulLen, const void *pBuffer);
#endif
#if TRUNCATE_SUPPORTED
REDSTATUS RedCoreFileTruncate(uint32_t ulInode, uint64_t ullSize);
#endif
#if (REDCONF_API_POSIX == 1) && (REDCONF_API_POSIX_READDIR == 1)
REDSTATUS RedCoreDirRead(uint32_t ulInode, uint32_t *pulPos, char *pszName, uint32_t *pulInode);
#endif
#endif

View file

@ -0,0 +1,224 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief This header contains macros which deviate from MISRA C:2012
*/
#ifndef REDDEVIATIONS_H
#define REDDEVIATIONS_H
/** @brief Append a suffix to a constant so that it is an unsigned 64-bit value.
Usages of this macro deviate from MISRA C:2012 Rule 1.2 (advisory). The
rule prohibits the use of language extensions. The ULL suffix became part
of the C standard with C99. Since this code base adheres to C89, use of
this suffix is a language extension. Reliance Edge needs to deal with
64-bit quantities, which by convention are explicitly suffixed. In at
least one case, with the INODE_SIZE_MAX macro, the code needs a way to force
a constant to be 64-bits even though its value is not so large that it would
be automatically promoted to 64-bits. Thus the need for this macro and the
deviation. In practice, the ULL suffix has proven to be a nearly universal
extension among C89 compilers.
As rule 19.2 is advisory, a deviation record is not required. This notice
is the only record of the deviation. PC-Lint does not issue an error for
this deviation so there is no error inhibition option.
Usages of this macro also deviate from MISRA C:2012 Rule 20.10 (advisory).
The rule prohibits use of the ## preprocessor operator. The code is not
obscure, and the operator is used only once, so this is deemed to be safe.
As rule 20.10 is advisory, a deviation record is not required. This notice
is the only record of the deviation.
Consistent use of this macro, even in non MISRA C code, is encouraged to
make it easier to search for 64-bit values.
*/
#define UINT64_SUFFIX(number) (number##ULL)
/** @brief Append a suffix to a constant so that it is a signed 64-bit value.
Usages of this macro deviate from MISRA C:2012 Rule 1.2 (advisory). See the
description of UINT64_SUFFIX() for details.
Usages of this macro deviate from MISRA C:2012 Rule 20.10 (advisory). See
the description of UINT64_SUFFIX() for details.
*/
#define INT64_SUFFIX(number) (number##LL)
/** @brief Cast a pointer to a const uint8_t pointer.
All usages of this macro deviate from MISRA C:2012 Rule 11.5 (advisory).
Because there are no alignment requirements for a uint8_t pointer, this is
safe. However, it is technically a deviation from the rule.
As Rule 11.5 is advisory, a deviation record is not required. This notice
and the PC-Lint error inhibition option are the only records of the
deviation.
*/
#define CAST_VOID_PTR_TO_CONST_UINT8_PTR(PTR) ((const uint8_t *)(PTR))
/** @brief Cast a pointer to a uint8_t pointer.
All usages of this macro deviate from MISRA C:2012 Rule 11.5 (advisory).
Because there are no alignment requirements for a uint8_t pointer, this is
safe. However, it is technically a deviation from the rule.
As Rule 11.5 is advisory, a deviation record is not required. This notice
and the PC-Lint error inhibition option are the only records of the
deviation.
*/
#define CAST_VOID_PTR_TO_UINT8_PTR(PTR) ((uint8_t *)(PTR))
/** @brief Cast a pointer to a const uint32_t pointer.
Usages of this macro may deviate from MISRA C:2012 Rule 11.5 (advisory).
It is only used in cases where the pointer is known to be aligned, and thus
it is safe to do so.
As Rule 11.5 is advisory, a deviation record is not required. This notice
and the PC-Lint error inhibition option are the only records of the
deviation.
Usages of this macro may deviate from MISRA C:2012 Rule 11.3 (required).
As Rule 11.3 is required, a separate deviation record is required.
Regarding the cast to (const void *): this is there to placate some
compilers which emit warnings when a type with lower alignment requirements
(such as const uint8_t *) is cast to a type with higher alignment
requirements. In the places where this macro is used, the pointer is
checked to be of sufficient alignment.
*/
#define CAST_CONST_UINT32_PTR(PTR) ((const uint32_t *)(const void *)(PTR))
/** @brief Cast a pointer to a pointer to (void **).
Usages of this macro deviate from MISRA C:2012 Rule 11.3 (required).
It is only used for populating a node structure pointer with a buffer
pointer. Buffer pointers are 8-byte aligned, thus it is safe to do so.
As Rule 11.3 is required, a separate deviation record is required.
*/
#define CAST_VOID_PTR_PTR(PTRPTR) ((void **)(PTRPTR))
/** @brief Create a two-dimensional byte array which is safely aligned.
Usages of this macro deviate from MISRA C:2012 Rule 19.2 (advisory).
A union is required to force alignment of the block buffers, which are used
to access metadata nodes, which must be safely aligned for 64-bit types.
As rule 19.2 is advisory, a deviation record is not required. This notice
and the PC-Lint error inhibition option are the only records of the
deviation.
*/
#define ALIGNED_2D_BYTE_ARRAY(un, nam, size1, size2) \
union \
{ \
uint8_t nam[size1][size2]; \
uint64_t DummyAlign; \
} un
/** @brief Determine whether RedMemMove() must copy memory in the forward
direction, instead of in the reverse.
In order to copy between overlapping memory regions, RedMemMove() must copy
forward if the destination memory is lower, and backward if the destination
memory is higher. Failure to do so would yield incorrect results.
The only way to make this determination without gross inefficiency is to
use pointer comparison. Pointer comparisons are undefined unless both
pointers point within the same object or array (or one element past the end
of the array); see section 6.3.8 of ANSI C89. While RedMemMove() is
normally only used when memory regions overlap, which would not result in
undefined behavior, it (like memmove()) is supposed to work even for non-
overlapping regions, which would make this function invoke undefined
behavior. Experience has shown the pointer comparisons of this sort behave
intuitively on common platforms, even though the behavior is undefined. For
those platforms where this is not the case, this implementation of memmove()
should be replaced with an alternate one.
Usages of this macro deviate from MISRA-C:2012 Rule 18.3 (required). As
Rule 18.3 is required, a separate deviation record is required.
*/
#define MEMMOVE_MUST_COPY_FORWARD(dest, src) ((dest) < (src))
/** @brief Cast a pointer to a (const DIRENT *).
Usages of this macro deviate from MISRA-C:2012 Rule 11.3 (required).
It is used for populating a directory entry structure pointer with a
buffer pointer. Buffer pointers are 8-byte aligned, and DIRENT only
requires 4-byte alignment, thus the typecast is safe.
As Rule 11.3 is required, a separate deviation record is required.
*/
#define CAST_CONST_DIRENT_PTR(PTR) ((const DIRENT *)(PTR))
/** @brief Determine whether a pointer is aligned.
A pointer is aligned if its address is an even multiple of
::REDCONF_ALIGNMENT_SIZE.
This is used in the slice-by-8 RedCrc32Update() function, which needs to
know whether a pointer is aligned, since the slice-by-8 algorithm needs to
access the memory in an aligned fashion, and if the pointer is not aligned,
this can result in faults or suboptimal performance (depending on platform).
There is no way to perform this check without deviating from MISRA C rules
against casting pointers to integer types. Usage of this macro deviates
from MISRA C:2012 Rule 11.4 (advisory). The main rationale the rule cites
against converting pointers to integers is that the chosen integer type may
not be able to represent the pointer; this is a non-issue here since we use
uintptr_t. The text says the rule still applies when using uintptr_t due to
concern about unaligned pointers, but that is not an issue here since the
integer value of the pointer is not saved and not converted back into a
pointer and dereferenced. The result of casting a pointer to a sufficiently
large integer is implementation-defined, but macros similar to this one have
been used by Datalight for a long time in a wide variety of environments and
they have always worked as expected.
As Rule 11.4 is advisory, a deviation record is not required. This notice
and the PC-Lint error inhibition option are the only records of the
deviation.
@note PC-Lint also thinks this macro as it is used below violates Rule 11.6
(required). This is a false positive, since Rule 11.6 only applies to
void pointers. Below, we use it on a pointer-to-object (uint8_t *),
which is covered by Rule 11.4.
*/
#define IS_ALIGNED_PTR(ptr) (((uintptr_t)(ptr) & (REDCONF_ALIGNMENT_SIZE - 1U)) == 0U)
#endif

View file

@ -0,0 +1,114 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Error values for Reliance Edge APIs
*/
#ifndef REDERRNO_H
#define REDERRNO_H
/** @brief Return type for Reliance Edge error values.
*/
typedef int32_t REDSTATUS;
/* The errno numbers are the same as Linux.
*/
/** Operation not permitted. */
#define RED_EPERM 1
/** No such file or directory. */
#define RED_ENOENT 2
/** I/O error. */
#define RED_EIO 5
/** Bad file number. */
#define RED_EBADF 9
/** Out of memory */
#define RED_ENOMEM 12
/** Device or resource busy. */
#define RED_EBUSY 16
/** File exists. */
#define RED_EEXIST 17
/** Cross-device link. */
#define RED_EXDEV 18
/** Not a directory. */
#define RED_ENOTDIR 20
/** Is a directory. */
#define RED_EISDIR 21
/** Invalid argument. */
#define RED_EINVAL 22
/** File table overflow. */
#define RED_ENFILE 23
/** Too many open files. */
#define RED_EMFILE 24
/** File too large. */
#define RED_EFBIG 27
/** No space left on device. */
#define RED_ENOSPC 28
/** Read-only file system. */
#define RED_EROFS 30
/** Too many links. */
#define RED_EMLINK 31
/** Math result not representable. */
#define RED_ERANGE 34
/** File name too long. */
#define RED_ENAMETOOLONG 36
/** Function not implemented. */
#define RED_ENOSYS 38
/** Directory not empty. */
#define RED_ENOTEMPTY 39
/** No data available. */
#define RED_ENODATA 61
/** Too many users. */
#define RED_EUSERS 87
/** Nothing will be okay ever again. */
#define RED_EFUBAR RED_EINVAL
#endif

View file

@ -0,0 +1,54 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDEXCLUDE_H
#define REDEXCLUDE_H
#define DELETE_SUPPORTED \
( \
(REDCONF_READ_ONLY == 0) \
&& ( (REDCONF_API_POSIX == 1) \
&& ( (REDCONF_API_POSIX_RMDIR == 1) \
|| (REDCONF_API_POSIX_UNLINK == 1) \
|| ((REDCONF_API_POSIX_RENAME == 1) && (REDCONF_RENAME_ATOMIC == 1)))))
#define TRUNCATE_SUPPORTED \
( \
(REDCONF_READ_ONLY == 0) \
&& ( ((REDCONF_API_POSIX == 1) && (REDCONF_API_POSIX_FTRUNCATE == 1)) \
|| ((REDCONF_API_FSE == 1) && (REDCONF_API_FSE_TRUNCATE == 1))))
#define FORMAT_SUPPORTED \
( \
(REDCONF_READ_ONLY == 0) \
&& ( ((REDCONF_API_POSIX == 1) && (REDCONF_API_POSIX_FORMAT == 1)) \
|| ((REDCONF_API_FSE == 1) && (REDCONF_API_FSE_FORMAT == 1)) \
|| (REDCONF_IMAGE_BUILDER == 1)))
#endif

View file

@ -0,0 +1,46 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDFS_H
#define REDFS_H
#include <redconf.h>
#include "redconfigchk.h"
#include <redtypes.h>
#include "rederrno.h"
#include "reddeviations.h"
#include "redmacs.h"
#include "redapimacs.h"
#include "redutils.h"
#include "redosserv.h"
#include "redmisc.h"
#include "redver.h"
#include "redexclude.h"
#endif

View file

@ -0,0 +1,105 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Interface for the Reliance Edge FSE API.
The FSE (File Systems Essentials) API is a minimalist file system API
intended for simple use cases with a fixed number of statically-defined
files. It does not support creating or deleting files dynamically. Files
are referenced by a fixed file number, rather than by name; there are no
file names and no directories. There are also no file handles: files are
not opened or closed, and file offsets are given explicitly.
If the FSE API is too limited to meet the needs of your application,
consider using the more feature-rich POSIX-like file system API instead.
*/
#ifndef REDFSE_H
#define REDFSE_H
/* This header is intended for application use; some applications are written
in C++.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <redconf.h>
#if REDCONF_API_FSE == 1
#include <redtypes.h>
#include "redapimacs.h"
#include "rederrno.h"
/** @brief First valid file number.
This macro can be used to statically define file numbers for given files,
as in the below example:
~~~{.c}
#define LOG_FILE (RED_FILENUM_FIRST_VALID)
#define DATABASE_FILE (RED_FILENUM_FIRST_VALID + 1U)
#define ICON1_FILE (RED_FILENUM_FIRST_VALID + 2U)
#define ICON2_FILE (RED_FILENUM_FIRST_VALID + 3U)
~~~
*/
#define RED_FILENUM_FIRST_VALID (2U)
REDSTATUS RedFseInit(void);
REDSTATUS RedFseUninit(void);
REDSTATUS RedFseMount(uint8_t bVolNum);
REDSTATUS RedFseUnmount(uint8_t bVolNum);
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_FSE_FORMAT == 1)
REDSTATUS RedFseFormat(uint8_t bVolNum);
#endif
int32_t RedFseRead(uint8_t bVolNum, uint32_t ulFileNum, uint64_t ullFileOffset, uint32_t ulLength, void *pBuffer);
#if REDCONF_READ_ONLY == 0
int32_t RedFseWrite(uint8_t bVolNum, uint32_t ulFileNum, uint64_t ullFileOffset, uint32_t ulLength, const void *pBuffer);
#endif
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_FSE_TRUNCATE == 1)
REDSTATUS RedFseTruncate(uint8_t bVolNum, uint32_t ulFileNum, uint64_t ullNewFileSize);
#endif
int64_t RedFseSizeGet(uint8_t bVolNum, uint32_t ulFileNum);
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_FSE_TRANSMASKSET == 1)
REDSTATUS RedFseTransMaskSet(uint8_t bVolNum, uint32_t ulEventMask);
#endif
#if REDCONF_API_FSE_TRANSMASKGET == 1
REDSTATUS RedFseTransMaskGet(uint8_t bVolNum, uint32_t *pulEventMask);
#endif
#if REDCONF_READ_ONLY == 0
REDSTATUS RedFseTransact(uint8_t bVolNum);
#endif
#endif /* REDCONF_API_FSE == 1 */
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,77 @@
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/** @file
@brief Interfaces for getopt() and getopt_long() work-alike functions.
This code was taken from FreeBSD and slightly modified, mostly to rename
symbols with external linkage to avoid naming conflicts in systems where
there are real getopt()/getopt_long() implementations. Changed to use
fixed-width types to allow code using these interfaces to be consistent
with the rest of the product.
*/
#ifndef REDGETOPT_H
#define REDGETOPT_H
#define red_no_argument 0
#define red_required_argument 1
#define red_optional_argument 2
/** @brief Specifies a long option.
*/
typedef struct
{
/* name of long option */
const char *name;
/*
* one of red_no_argument, red_required_argument, and red_optional_argument:
* whether option takes an argument
*/
int32_t has_arg;
/* if not NULL, set *flag to val when option found */
int32_t *flag;
/* if flag not NULL, value to set *flag to; else return value */
int32_t val;
} REDOPTION;
int32_t RedGetopt(int32_t nargc, char * const *nargv, const char *options);
int32_t RedGetoptLong(int32_t nargc, char * const *nargv, const char *options, const REDOPTION *long_options, int32_t *idx);
extern const char *red_optarg;
extern int32_t red_optind;
extern int32_t red_opterr;
extern int32_t red_optopt;
extern int32_t red_optreset;
#endif

View file

@ -0,0 +1,103 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDMACS_H
#define REDMACS_H
#ifndef NULL
#define NULL ((void *)0)
#endif
#ifndef UINT8_MAX
#define UINT8_MAX (0xFFU)
#endif
#ifndef UINT16_MAX
#define UINT16_MAX (0xFFFFU)
#endif
#ifndef UINT32_MAX
#define UINT32_MAX (0xFFFFFFFFU)
#endif
#ifndef UINT64_MAX
#define UINT64_MAX UINT64_SUFFIX(0xFFFFFFFFFFFFFFFF)
#endif
#ifndef INT32_MAX
#define INT32_MAX (0x7FFFFFFF)
#endif
#ifndef INT64_MAX
#define INT64_MAX INT64_SUFFIX(0x7FFFFFFFFFFFFFFF)
#endif
#ifndef true
#define true (1)
#endif
#ifndef false
#define false (0)
#endif
#define SECTOR_SIZE_MIN (256U)
#if REDCONF_BLOCK_SIZE == 256U
#define BLOCK_SIZE_P2 8U
#elif REDCONF_BLOCK_SIZE == 512U
#define BLOCK_SIZE_P2 9U
#elif REDCONF_BLOCK_SIZE == 1024U
#define BLOCK_SIZE_P2 10U
#elif REDCONF_BLOCK_SIZE == 2048U
#define BLOCK_SIZE_P2 11U
#elif REDCONF_BLOCK_SIZE == 4096U
#define BLOCK_SIZE_P2 12U
#elif REDCONF_BLOCK_SIZE == 8192U
#define BLOCK_SIZE_P2 13U
#elif REDCONF_BLOCK_SIZE == 16384U
#define BLOCK_SIZE_P2 14U
#elif REDCONF_BLOCK_SIZE == 32768U
#define BLOCK_SIZE_P2 15U
#elif REDCONF_BLOCK_SIZE == 65536U
#define BLOCK_SIZE_P2 16U
#else
#error "REDCONF_BLOCK_SIZE must be a power of two value between 256 and 65536"
#endif
#define REDMIN(a, b) (((a) < (b)) ? (a) : (b))
#define INODE_INVALID (0U) /* General-purpose invalid inode number (must be zero). */
#define INODE_FIRST_VALID (2U) /* First valid inode number. */
#define INODE_ROOTDIR (INODE_FIRST_VALID) /* Inode number of the root directory. */
/* Expands to a "const" qualifier when the volume count is one, otherwise
expands to nothing. This is useful for variables that never change in
single-volume configurations but do change in multi-volume configurations.
*/
#if REDCONF_VOLUME_COUNT == 1U
#define CONST_IF_ONE_VOLUME const
#else
#define CONST_IF_ONE_VOLUME
#endif
#endif

View file

@ -0,0 +1,48 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDMISC_H
#define REDMISC_H
/** @brief Type of an inode or handle.
Used to indicate the actual or expected type of an inode or handle.
*/
typedef enum
{
FTYPE_FILE, /**< Type is file. */
FTYPE_DIR, /**< Type is directory. */
/** Type is either file or directory: used only to indicate an expected
type, never as an actual type.
*/
FTYPE_EITHER
} FTYPE;
#endif

View file

@ -0,0 +1,86 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDOSSERV_H
#define REDOSSERV_H
#include <redostypes.h>
/** @brief Type of access requested when opening a block device.
*/
typedef enum
{
BDEV_O_RDONLY, /**< Open block device for read access. */
BDEV_O_WRONLY, /**< Open block device for write access. */
BDEV_O_RDWR /**< Open block device for read and write access. */
} BDEVOPENMODE;
REDSTATUS RedOsBDevOpen(uint8_t bVolNum, BDEVOPENMODE mode);
REDSTATUS RedOsBDevClose(uint8_t bVolNum);
REDSTATUS RedOsBDevRead(uint8_t bVolNum, uint64_t ullSectorStart, uint32_t ulSectorCount, void *pBuffer);
#if REDCONF_READ_ONLY == 0
REDSTATUS RedOsBDevWrite(uint8_t bVolNum, uint64_t ullSectorStart, uint32_t ulSectorCount, const void *pBuffer);
REDSTATUS RedOsBDevFlush(uint8_t bVolNum);
#endif
/* Non-standard API: for host machines only.
*/
REDSTATUS RedOsBDevConfig(uint8_t bVolNum, const char *pszBDevSpec);
#if REDCONF_TASK_COUNT > 1U
REDSTATUS RedOsMutexInit(void);
REDSTATUS RedOsMutexUninit(void);
void RedOsMutexAcquire(void);
void RedOsMutexRelease(void);
#endif
#if (REDCONF_TASK_COUNT > 1U) && (REDCONF_API_POSIX == 1)
uint32_t RedOsTaskId(void);
#endif
REDSTATUS RedOsClockInit(void);
REDSTATUS RedOsClockUninit(void);
uint32_t RedOsClockGetTime(void);
REDSTATUS RedOsTimestampInit(void);
REDSTATUS RedOsTimestampUninit(void);
REDTIMESTAMP RedOsTimestamp(void);
uint64_t RedOsTimePassed(REDTIMESTAMP tsSince);
#if REDCONF_OUTPUT == 1
void RedOsOutputString(const char *pszString);
#endif
#if REDCONF_ASSERTS == 1
void RedOsAssertFail(const char *pszFileName, uint32_t ulLineNum);
#endif
#endif

View file

@ -0,0 +1,196 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Interface for the Reliance Edge POSIX-like API.
The POSIX-like file system API is the primary file system API for
Reliance Edge, which supports the full functionality of the file system.
This API aims to be compatible with POSIX where reasonable, but it is
simplified considerably to meet the needs of resource-constrained embedded
systems. The API has also been extended to provide access to the unique
features of Reliance Edge, and to cover areas (like mountins and formatting)
which do not have APIs in the POSIX specification.
*/
#ifndef REDPOSIX_H
#define REDPOSIX_H
/* This header is intended for application use; some applications are written
in C++.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <redconf.h>
#if REDCONF_API_POSIX == 1
#include <redtypes.h>
#include "redapimacs.h"
#include "rederrno.h"
#include "redstat.h"
/** Open for reading only. */
#define RED_O_RDONLY 0x00000001U
/** Open for writing only. */
#define RED_O_WRONLY 0x00000002U
/** Open for reading and writing. */
#define RED_O_RDWR 0x00000004U
/** File offset for all writes is end-of-file. */
#define RED_O_APPEND 0x00000008U
/** Create the file. */
#define RED_O_CREAT 0x00000010U
/** Error if path already exists. */
#define RED_O_EXCL 0x00000020U
/** Truncate file to size zero. */
#define RED_O_TRUNC 0x00000040U
/** @brief Last file system error (errno).
Under normal circumstances, each task using the file system has an
independent `red_errno` value. Applications do not need to worry about
one task obliterating an error value that another task needed to read. The
value is initially zero. When one of the POSIX-like APIs return an
indication of error, `red_errno` is set to an error value.
In some circumstances, `red_errno` will be a global errno location which
is shared by multiple tasks. If the calling task is not registered as a
file system user and all of the task slots are full, there can be no
task-specific errno, so the global errno is used. Likewise, if the file
system driver is uninitialized, there are no registered file system users
and `red_errno` always refers to the global errno. Under these
circumstances, multiple tasks manipulating `red_errno` could be
problematic. When the task count is set to one, `red_errno` always refers
to the global errno.
Note that `red_errno` is usable as an lvalue; i.e., in addition to reading
the error value, the error value can be set:
~~~{.c}
red_errno = 0;
~~~
*/
#define red_errno (*red_errnoptr())
/** @brief Positions from which to seek within a file.
*/
typedef enum
{
/* 0/1/2 are the traditional values for SET/CUR/END, respectively. Prior
to the release of Unix System V in 1983, the SEEK_* symbols did not
exist and C programs hard-coded the 0/1/2 values with those meanings.
*/
RED_SEEK_SET = 0, /**< Set file offset to given offset. */
RED_SEEK_CUR = 1, /**< Set file offset to current offset plus signed offset. */
RED_SEEK_END = 2 /**< Set file offset to EOF plus signed offset. */
} REDWHENCE;
#if REDCONF_API_POSIX_READDIR == 1
/** @brief Opaque directory handle.
*/
typedef struct sREDHANDLE REDDIR;
/** @brief Directory entry information.
*/
typedef struct
{
uint32_t d_ino; /**< File serial number (inode number). */
char d_name[REDCONF_NAME_MAX+1U]; /**< Name of entry. */
REDSTAT d_stat; /**< File information (POSIX extension). */
} REDDIRENT;
#endif
int32_t red_init(void);
int32_t red_uninit(void);
int32_t red_mount(const char *pszVolume);
int32_t red_umount(const char *pszVolume);
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX_FORMAT == 1)
int32_t red_format(const char *pszVolume);
#endif
#if REDCONF_READ_ONLY == 0
int32_t red_transact(const char *pszVolume);
#endif
#if REDCONF_READ_ONLY == 0
int32_t red_settransmask(const char *pszVolume, uint32_t ulEventMask);
#endif
int32_t red_gettransmask(const char *pszVolume, uint32_t *pulEventMask);
int32_t red_statvfs(const char *pszVolume, REDSTATFS *pStatvfs);
int32_t red_open(const char *pszPath, uint32_t ulOpenMode);
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX_UNLINK == 1)
int32_t red_unlink(const char *pszPath);
#endif
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX_MKDIR == 1)
int32_t red_mkdir(const char *pszPath);
#endif
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX_RMDIR == 1)
int32_t red_rmdir(const char *pszPath);
#endif
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX_RENAME == 1)
int32_t red_rename(const char *pszOldPath, const char *pszNewPath);
#endif
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX_LINK == 1)
int32_t red_link(const char *pszPath, const char *pszHardLink);
#endif
int32_t red_close(int32_t iFildes);
int32_t red_read(int32_t iFildes, void *pBuffer, uint32_t ulLength);
#if REDCONF_READ_ONLY == 0
int32_t red_write(int32_t iFildes, const void *pBuffer, uint32_t ulLength);
#endif
#if REDCONF_READ_ONLY == 0
int32_t red_fsync(int32_t iFildes);
#endif
int64_t red_lseek(int32_t iFildes, int64_t llOffset, REDWHENCE whence);
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX_FTRUNCATE == 1)
int32_t red_ftruncate(int32_t iFildes, uint64_t ullSize);
#endif
int32_t red_fstat(int32_t iFildes, REDSTAT *pStat);
#if REDCONF_API_POSIX_READDIR == 1
REDDIR *red_opendir(const char *pszPath);
REDDIRENT *red_readdir(REDDIR *pDirStream);
void red_rewinddir(REDDIR *pDirStream);
int32_t red_closedir(REDDIR *pDirStream);
#endif
REDSTATUS *red_errnoptr(void);
#endif /* REDCONF_API_POSIX */
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,94 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDSTAT_H
#define REDSTAT_H
/** Mode bit for a directory. */
#define RED_S_IFDIR 0x4000U
/** Mode bit for a regular file. */
#define RED_S_IFREG 0x8000U
/** @brief Test for a directory.
*/
#define RED_S_ISDIR(m) (((m) & RED_S_IFDIR) != 0U)
/** @brief Test for a regular file.
*/
#define RED_S_ISREG(m) (((m) & RED_S_IFREG) != 0U)
/** File system is read-only. */
#define RED_ST_RDONLY 0x00000001U
/** File system ignores suid and sgid bits. */
#define RED_ST_NOSUID 0x00000002U
/** @brief Status information on an inode.
*/
typedef struct
{
uint8_t st_dev; /**< Volume number of volume containing file. */
uint32_t st_ino; /**< File serial number (inode number). */
uint16_t st_mode; /**< Mode of file. */
uint16_t st_nlink; /**< Number of hard links to the file. */
uint64_t st_size; /**< File size in bytes. */
#if REDCONF_INODE_TIMESTAMPS == 1
uint32_t st_atime; /**< Time of last access (seconds since 01-01-1970). */
uint32_t st_mtime; /**< Time of last data modification (seconds since 01-01-1970). */
uint32_t st_ctime; /**< Time of last status change (seconds since 01-01-1970). */
#endif
#if REDCONF_INODE_BLOCKS == 1
uint32_t st_blocks; /**< Number of blocks allocated for this object. */
#endif
} REDSTAT;
/** @brief Status information on a file system volume.
*/
typedef struct
{
uint32_t f_bsize; /**< File system block size. */
uint32_t f_frsize; /**< Fundamental file system block size. */
uint32_t f_blocks; /**< Total number of blocks on file system in units of f_frsize. */
uint32_t f_bfree; /**< Total number of free blocks. */
uint32_t f_bavail; /**< Number of free blocks available to non-privileged process. */
uint32_t f_files; /**< Total number of file serial numbers. */
uint32_t f_ffree; /**< Total number of free file serial numbers. */
uint32_t f_favail; /**< Number of file serial numbers available to non-privileged process. */
uint32_t f_fsid; /**< File system ID (useless, populated with zero). */
uint32_t f_flag; /**< Bit mask of f_flag values. Includes read-only file system flag. */
uint32_t f_namemax; /**< Maximum filename length. */
uint64_t f_maxfsize; /**< Maximum file size (POSIX extension). */
uint32_t f_dev; /**< Volume number (POSIX extension). */
} REDSTATFS;
#endif

View file

@ -0,0 +1,249 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Prototypes for Reliance Edge test entry points.
*/
#ifndef REDTESTS_H
#define REDTESTS_H
#include <redtypes.h>
#include "redtestutils.h"
#include "redver.h"
/* This macro is only defined by the error injection project.
*/
#ifdef REDCONF_ERROR_INJECTION
#include <rederrinject.h>
#endif
#define FSSTRESS_SUPPORTED \
( ((RED_KIT == RED_KIT_GPL) || (RED_KIT == RED_KIT_SANDBOX)) \
&& (REDCONF_OUTPUT == 1) && (REDCONF_READ_ONLY == 0) && (REDCONF_PATH_SEPARATOR == '/') \
&& (REDCONF_API_POSIX == 1) && (REDCONF_API_POSIX_UNLINK == 1) && (REDCONF_API_POSIX_MKDIR == 1) \
&& (REDCONF_API_POSIX_RMDIR == 1) && (REDCONF_API_POSIX_RENAME == 1) && (REDCONF_API_POSIX_LINK == 1) \
&& (REDCONF_API_POSIX_FTRUNCATE == 1) && (REDCONF_API_POSIX_READDIR == 1))
#define FSE_STRESS_TEST_SUPPORTED \
( ((RED_KIT == RED_KIT_COMMERCIAL) || (RED_KIT == RED_KIT_SANDBOX)) \
&& (REDCONF_OUTPUT == 1) && (REDCONF_READ_ONLY == 0) && (REDCONF_API_FSE == 1) \
&& (REDCONF_API_FSE_FORMAT == 1) && (REDCONF_API_FSE_TRANSMASKSET == 1) && (REDCONF_API_FSE_TRANSMASKGET == 1) \
&& (REDCONF_API_FSE_TRUNCATE == 1))
#define POSIX_API_TEST_SUPPORTED \
( ((RED_KIT == RED_KIT_COMMERCIAL) || (RED_KIT == RED_KIT_SANDBOX)) \
&& (REDCONF_OUTPUT == 1) && (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX == 1) \
&& (REDCONF_API_POSIX_FORMAT == 1) && (REDCONF_API_POSIX_UNLINK == 1))
#define FSE_API_TEST_SUPPORTED \
( ((RED_KIT == RED_KIT_COMMERCIAL) || (RED_KIT == RED_KIT_SANDBOX)) \
&& (REDCONF_OUTPUT == 1) && (REDCONF_READ_ONLY == 0) && (REDCONF_API_FSE == 1) \
&& (REDCONF_API_FSE_FORMAT == 1))
#define STOCH_POSIX_TEST_SUPPORTED \
( ((RED_KIT == RED_KIT_COMMERCIAL) || (RED_KIT == RED_KIT_SANDBOX)) \
&& (REDCONF_OUTPUT == 1) && (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX == 1) \
&& (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX_FORMAT == 1) && (REDCONF_API_POSIX_READDIR == 1) \
&& (REDCONF_API_POSIX_MKDIR == 1) && (REDCONF_API_POSIX_RMDIR == 1) && (REDCONF_API_POSIX_UNLINK == 1) \
&& (REDCONF_API_POSIX_RENAME == 1))
#define FSIOTEST_SUPPORTED \
( ((RED_KIT == RED_KIT_COMMERCIAL) || (RED_KIT == RED_KIT_SANDBOX)) \
&& (REDCONF_OUTPUT == 1) && (REDCONF_API_POSIX == 1))
#define BDEVTEST_SUPPORTED \
( ((RED_KIT == RED_KIT_COMMERCIAL) || (RED_KIT == RED_KIT_SANDBOX)) \
&& (REDCONF_OUTPUT == 1) && (REDCONF_READ_ONLY == 0))
#define DISKFULL_TEST_SUPPORTED \
( ((RED_KIT == RED_KIT_COMMERCIAL) || (RED_KIT == RED_KIT_SANDBOX)) \
&& (REDCONF_OUTPUT == 1) && (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX == 1) \
&& (REDCONF_API_POSIX_FORMAT == 1) && (REDCONF_API_POSIX_FTRUNCATE == 1))
typedef enum
{
PARAMSTATUS_OK, /* Parameters were good; continue. */
PARAMSTATUS_BAD, /* Parameters were bad; stop. */
PARAMSTATUS_HELP /* Help request; not an error, but stop. */
} PARAMSTATUS;
#if FSSTRESS_SUPPORTED
typedef struct
{
bool fNoCleanup; /**< --no-cleanup */
uint32_t ulLoops; /**< --loops */
uint32_t ulNops; /**< --nops */
bool fNamePad; /**< --namepad */
uint32_t ulSeed; /**< --seed */
bool fVerbose; /**< --verbose */
} FSSTRESSPARAM;
PARAMSTATUS FsstressParseParams(int argc, char *argv[], FSSTRESSPARAM *pParam, uint8_t *pbVolNum, const char **ppszDevice);
void FsstressDefaultParams(FSSTRESSPARAM *pParam);
int FsstressStart(const FSSTRESSPARAM *pParam);
#endif
#if STOCH_POSIX_TEST_SUPPORTED
typedef struct
{
const char *pszVolume; /**< Volume path prefix. */
uint32_t ulIterations; /**< --iterations */
uint32_t ulFileListMax; /**< --files */
uint32_t ulDirListMax; /**< --dirs */
uint32_t ulOpenFileListMax; /**< --open-files */
uint32_t ulOpenDirListMax; /**< --open-dirs */
uint32_t ulRandomSeed; /**< --seed */
} STOCHPOSIXPARAM;
PARAMSTATUS RedStochPosixParseParams(int argc, char *argv[], STOCHPOSIXPARAM *pParam, uint8_t *pbVolNum, const char **ppszDevice);
void RedStochPosixDefaultParams(STOCHPOSIXPARAM *pParam);
int RedStochPosixStart(const STOCHPOSIXPARAM *pParam);
#endif
#if FSE_STRESS_TEST_SUPPORTED
typedef struct
{
uint8_t bVolNum; /**< Volume number. */
uint32_t ulFileCount; /**< --files */
uint32_t ulMaxFileSize; /**< --max */
uint32_t ulMaxOpSize; /**< --buffer-size */
uint32_t ulNops; /**< --nops */
uint32_t ulLoops; /**< --loops */
uint32_t ulSampleRate; /**< --sample-rate */
uint64_t ullSeed; /**< --seed */
} FSESTRESSPARAM;
PARAMSTATUS FseStressParseParams(int argc, char *argv[], FSESTRESSPARAM *pParam, uint8_t *pbVolNum, const char **ppszDevice);
void FseStressDefaultParams(FSESTRESSPARAM *pParam);
int FseStressStart(const FSESTRESSPARAM *pParam);
#endif
#if POSIX_API_TEST_SUPPORTED
typedef struct
{
const char *pszVolume; /**< Volume path prefix. */
bool fQuick; /**< --quick */
bool fQuitOnFailure; /**< --quit-on-failure */
bool fDebugErrors; /**< --debug */
} POSIXTESTPARAM;
PARAMSTATUS RedPosixTestParseParams(int argc, char *argv[], POSIXTESTPARAM *pParam, uint8_t *pbVolNum, const char **ppszDevice);
void RedPosixTestDefaultParams(POSIXTESTPARAM *pParam);
int RedPosixTestStart(const POSIXTESTPARAM *pParam);
#endif
#if FSE_API_TEST_SUPPORTED
typedef struct
{
uint8_t bVolNum; /**< Volume number. */
bool fQuitOnFailure; /**< --quit-on-failure */
bool fDebugErrors; /**< --debug */
} FSETESTPARAM;
PARAMSTATUS RedFseTestParseParams(int argc, char *argv[], FSETESTPARAM *pParam, uint8_t *pbVolNum, const char **ppszDevice);
void RedFseTestDefaultParams(FSETESTPARAM *pParam);
int RedFseTestStart(const FSETESTPARAM *pParam);
#endif
#if FSIOTEST_SUPPORTED
typedef enum
{
TESTFS_RELEDGE, /* Datalight Reliance Edge */
TESTFS_FATFS, /* ChaN's FatFs */
TESTFS_FATSL /* FreeRTOS+FAT SL */
} TESTFS;
typedef struct
{
TESTFS testfs; /**< --fs */
const char *pszVolume; /**< Volume path prefix. */
bool fSeqRead; /**< --seq=r */
bool fSeqWrite; /**< --seq=w */
bool fSeqRewrite; /**< --seq=e */
bool fRandomRead; /**< --rand=r */
bool fRandomWrite; /**< --rand=w */
bool fMixedWrite; /**< --mixed */
bool fScanTest; /**< --scan */
uint32_t ulFSBlockSize; /**< --block-size */
uint32_t ulMaxFileSize; /**< --max */
uint32_t ulRandomReadPasses; /**< --rand-pass=r:w (r part) */
uint32_t ulRandomWritePasses; /**< --rand-pass=r:w (w part) */
uint32_t ulMixedWritePasses; /**< --mixed-pass */
int32_t iFlushOnWriteRatio; /**< --rand-fow */
uint32_t ulBufferMin; /**< --start */
uint32_t ulBufferSize; /**< --buffer-size */
bool fWriteVerify; /**< --verify */
uint32_t ulSampleRate; /**< --sample-rate */
uint32_t ulScanCount; /**< --scan-files */
uint64_t ullSeed; /**< --seed */
} FSIOTESTPARAM;
PARAMSTATUS FSIOTestParseParams(int argc, char *argv[], FSIOTESTPARAM *pParam, uint8_t *pbVolNum, const char **ppszDevice);
void FSIOTestDefaultParams(FSIOTESTPARAM *pParam);
int FSIOTestStart(const FSIOTESTPARAM *pParam);
#endif
#if BDEVTEST_SUPPORTED
typedef struct
{
uint8_t bDrvNum; /**< Volume number (for sector size/count). */
bool fSeqWrite; /**< --seq:w */
bool fSeqRead; /**< --seq:r */
bool fRandWrite; /**< --rand:w */
bool fRandRead; /**< --rand:r */
uint32_t ulSampleSecs; /**< --sample-rate */
uint32_t ulPasses; /**< --passes */
uint32_t ulMinIOSectors; /**< --count=min[:max] (min part) */
uint32_t ulMaxIOSectors; /**< --count=min[:max] (max part) */
uint32_t ulMaxSizeKB; /**< --max */
uint32_t ulTestSeconds; /**< --time */
bool fVerify; /**< --verify */
bool fAsyncWrites; /**< --async */
uint64_t ullSeed; /**< --seed */
} BDEVTESTPARAM;
PARAMSTATUS BDevTestParseParams(int argc, char *argv[], BDEVTESTPARAM *pParam, uint8_t *pbVolNum, const char **ppszDevice);
void BDevTestDefaultParams(BDEVTESTPARAM *pParam);
int BDevTestStart(const BDEVTESTPARAM *pParam);
#endif
#if DISKFULL_TEST_SUPPORTED
typedef struct
{
const char *pszVolume; /**< Volume path prefix. */
bool fQuitOnFailure; /**< --quit-on-failure */
bool fDebugErrors; /**< --debug */
} DISKFULLTESTPARAM;
PARAMSTATUS DiskFullTestParseParams(int argc, char *argv[], DISKFULLTESTPARAM *pParam, uint8_t *pbVolNum, const char **ppszDevice);
void DiskFullTestDefaultParams(DISKFULLTESTPARAM *pParam);
int DiskFullTestStart(const DISKFULLTESTPARAM *pParam);
#endif
#endif

View file

@ -0,0 +1,71 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Reliance Edge utilities only needed for tests.
*/
#ifndef REDTESTUTILS_H
#define REDTESTUTILS_H
#define ISDIGIT(c) (((c) >= '0') && ((c) <= '9'))
void RedRandSeed(uint64_t ullSeed);
uint64_t RedRand64(uint64_t *pullSeed);
uint32_t RedRand32(uint32_t *pulSeed);
char *RedRatio(char *pBuffer, uint32_t ulBufferLen, uint64_t ullDividend, uint64_t ullDivisor, uint32_t ulDecPlaces);
uint64_t RedMulDiv64(uint64_t ullBase, uint32_t ulMultiplier, uint64_t ullDivisor);
uint64_t RedUint64DivMod32(uint64_t ullDividend, uint32_t ulDivisor, uint32_t *pulRemainder);
uint64_t RedUint64DivMod64(uint64_t ullDividend, uint64_t ullDivisor, uint64_t *pullRemainder);
char *RedScaleBytes(uint32_t ulByteValue, char *pszBuffer, uint32_t ulBufferSize);
char *RedScaleKB(uint32_t ulKBValue, char *pszBuffer, uint32_t ulBufferSize);
uint32_t RedGetKBPerSecond(uint64_t ullKB, uint32_t ulMS);
uint32_t RedGetKBPerSecondSectors(uint32_t ulBytesPerSector, uint64_t ullSectors, uint64_t ullUS);
int32_t RedAtoI(const char *pszNum);
const char *RedHtoUL(const char *pszNum, uint32_t *pulNum);
const char *RedHtoULL(const char *pszNum, uint64_t *pullNum);
const char *RedNtoUL(const char *pszNum, uint32_t *pulNum);
const char *RedNtoULL(const char *pszNum, uint64_t *pullNum);
const char *RedSizeToUL(const char *pszNum, uint32_t *pulResult);
int32_t RedStrICmp(const char *pszStr1, const char *pszStr2);
int32_t RedStrNICmp(const char *pszStr1, const char *pszStr2, uint32_t ulLen);
char RedToLower(char c);
#include <stdarg.h>
#if REDCONF_OUTPUT == 1
void RedPrintf(const char *pszFormat, ...);
void RedVPrintf(const char *pszFormat, va_list arglist);
#endif
int32_t RedSNPrintf(char *pcBuffer, uint32_t ulBufferLen, const char *pszFormat, ...);
int32_t RedVSNPrintf(char *pcBuffer, uint32_t ulBufferLen, const char *pszFormat, va_list arglist);
#endif

View file

@ -0,0 +1,36 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Interfaces for common-code utilities for tools and tests.
*/
#ifndef REDTOOLCMN_H
#define REDTOOLCMN_H
uint8_t RedFindVolumeNumber(const char *pszVolume);
#endif

View file

@ -0,0 +1,71 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDUTILS_H
#define REDUTILS_H
#if REDCONF_ASSERTS == 1
#define REDERROR() RedOsAssertFail(__FILE__, __LINE__)
#define REDASSERT(EXP) ((EXP) ? (void)0 : REDERROR())
#else
#define REDERROR() ((void)0)
#define REDASSERT(EXP) ((void)0)
#endif
void RedMemCpy(void *pDest, const void *pSrc, uint32_t ulLen);
void RedMemMove(void *pDest, const void *pSrc, uint32_t ulLen);
void RedMemSet(void *pDest, uint8_t bVal, uint32_t ulLen);
int32_t RedMemCmp(const void *pMem1, const void *pMem2, uint32_t ulLen);
uint32_t RedStrLen(const char *pszStr);
int32_t RedStrCmp(const char *pszStr1, const char *pszStr2);
int32_t RedStrNCmp(const char *pszStr1, const char *pszStr2, uint32_t ulLen);
void RedStrNCpy(char *pszDst, const char *pszSrc, uint32_t ulLen);
uint32_t RedCrc32Update(uint32_t ulInitCrc32, const void *pBuffer, uint32_t ulLength);
uint32_t RedCrcNode(const void *pBuffer);
#if REDCONF_API_POSIX == 1
uint32_t RedNameLen(const char *pszName);
#endif
bool RedBitGet(const uint8_t *pbBitmap, uint32_t ulBit);
void RedBitSet(uint8_t *pbBitmap, uint32_t ulBit);
void RedBitClear(uint8_t *pbBitmap, uint32_t ulBit);
#ifdef REDCONF_ENDIAN_SWAP
uint64_t RedRev64(uint64_t ullToRev);
uint32_t RedRev32(uint32_t ulToRev);
uint16_t RedRev16(uint16_t uToRev);
#endif
void RedSignOn(void);
#endif

View file

@ -0,0 +1,106 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Macros for version numbers, build number, and product information.
*/
#ifndef REDVER_H
#define REDVER_H
/** @brief Consecutive number assigned to each automated build.
<!-- This macro is updated automatically: do not edit! -->
*/
#define RED_BUILD_NUMBER "664"
#define RED_KIT_GPL 0U /* Open source GPL kit. */
#define RED_KIT_COMMERCIAL 1U /* Commercially-licensed kit. */
#define RED_KIT_SANDBOX 2U /* Not a kit: developer sandbox. */
/** @brief Indicates the Reliance Edge kit.
<!-- This macro is updated automatically: do not edit! -->
*/
#define RED_KIT RED_KIT_GPL
/** @brief Version number to display in output.
*/
#define RED_VERSION "v1.0"
/** @brief On-disk version number.
This is incremented only when the on-disk layout is updated in such a way
which is incompatible with previously released versions of the file system.
*/
#define RED_DISK_LAYOUT_VERSION 1U
/** @brief Base name of the file system product.
*/
#define RED_PRODUCT_BASE_NAME "Reliance Edge"
/* Specifies whether the product is in alpha stage, beta stage, or neither.
*/
#if 0
#if 1
#define ALPHABETA " (Alpha)"
#else
#define ALPHABETA " (Beta)"
#endif
#else
#define ALPHABETA ""
#endif
/** @brief Full product name and version.
*/
#define RED_PRODUCT_NAME "Datalight "RED_PRODUCT_BASE_NAME" "RED_VERSION" Build "RED_BUILD_NUMBER ALPHABETA
/** @brief Product copyright.
*/
#define RED_PRODUCT_LEGAL "Copyright (c) 2014-2015 Datalight, Inc. All Rights Reserved Worldwide."
/** @brief Product patents.
*/
#define RED_PRODUCT_PATENT "Patents: US#7284101."
/** @brief Product edition.
*/
#if RED_KIT == RED_KIT_GPL
#define RED_PRODUCT_EDITION "Open-Source GPLv2 Edition -- Compiled "__DATE__" at "__TIME__
#elif RED_KIT == RED_KIT_COMMERCIAL
#define RED_PRODUCT_EDITION "Commercial Edition -- Compiled "__DATE__" at "__TIME__
#else
#define RED_PRODUCT_EDITION "Developer Sandbox -- Compiled "__DATE__" at "__TIME__
#endif
#endif

View file

@ -0,0 +1,134 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDVOLUME_H
#define REDVOLUME_H
/** @brief Per-volume configuration structure.
Contains the configuration values that may differ between volumes. Must be
declared in an array in redconf.c in the Reliance Edge project directory and
statically initialized with values representing the volume configuration of
the target system.
*/
typedef struct
{
/** The sector size for the block device underlying the volume: the basic
unit for reading and writing to the storage media. Commonly ranges
between 512 and 4096, but any power-of-two value not greater than the
block size will work.
*/
uint32_t ulSectorSize;
/** The number of sectors in this file system volume.
*/
uint64_t ullSectorCount;
/** Whether a sector write on the block device underlying the volume is
atomic. It is atomic if when the sector write is interrupted, the
contents of the sector are guaranteed to be either all of the new data,
or all of the old data. If unsure, leave as false.
*/
bool fAtomicSectorWrite;
/** This is the maximum number of inodes (files and directories). This
number includes the root directory inode (inode 2; created during
format), but does not include inodes 0 or 1, which do not exist on
disk. The number of inodes cannot be less than 1.
*/
uint32_t ulInodeCount;
#if REDCONF_API_POSIX == 1
/** The path prefix for the volume; for example, "VOL1:", "FlashDisk", etc.
*/
const char *pszPathPrefix;
#endif
} VOLCONF;
extern const VOLCONF gaRedVolConf[REDCONF_VOLUME_COUNT];
extern const VOLCONF * CONST_IF_ONE_VOLUME gpRedVolConf;
/** @brief Per-volume run-time data.
*/
typedef struct
{
/** Whether the volume is currently mounted.
*/
bool fMounted;
#if REDCONF_READ_ONLY == 0
/** Whether the volume is read-only.
*/
bool fReadOnly;
/** The active automatic transaction mask.
*/
uint32_t ulTransMask;
#endif
/** The power of 2 difference between sector size and block size.
*/
uint8_t bBlockSectorShift;
/** The number of logical blocks in this file system volume. The unit here
is the global block size.
*/
uint32_t ulBlockCount;
/** The total number of allocable blocks; Also the maximum count of free
blocks.
*/
uint32_t ulBlocksAllocable;
/** The maximum number of bytes that an inode is capable of addressing.
*/
uint64_t ullMaxInodeSize;
/** The current metadata sequence number. This value is included in all
metadata nodes and incremented every time a metadata node is written.
It is assumed to never wrap around.
*/
uint64_t ullSequence;
} VOLUME;
/* Array of VOLUME structures, populated at during RedCoreInit().
*/
extern VOLUME gaRedVolume[REDCONF_VOLUME_COUNT];
/* Volume number currently being accessed; populated during
RedCoreVolSetCurrent().
*/
extern CONST_IF_ONE_VOLUME uint8_t gbRedVolNum;
/* Pointer to the volume currently being accessed; populated during
RedCoreVolSetCurrent().
*/
extern VOLUME * CONST_IF_ONE_VOLUME gpRedVolume;
#endif

View file

@ -0,0 +1,165 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Macros to encapsulate MISRA C:2012 deviations in OS-specific code.
*/
#ifndef REDOSDEVIATIONS_H
#define REDOSDEVIATIONS_H
#if REDCONF_OUTPUT == 1
/* Needed for PRINT_ASSERT() and OUTPUT_CHARACTER().
*/
#include <stdio.h>
#endif
#if REDCONF_ASSERTS == 1
#if REDCONF_OUTPUT == 1
/** Print a formatted message for an assertion.
Usages of this macro deviate from MISRA C:2012 Rule 21.6 (required). Using
printf() is the most convenient way to output this information; and the risk
of "unspecified, undefined and implementation-defined" behavior causing
problems (as cited in the rationale for the rule) is small. The driver does
not depend on this string being outputted correctly. Furthermore, use of
printf() disappears when either asserts or output are disabled.
As Rule 21.6 is required, a separate deviation record is required.
*/
#define PRINT_ASSERT(file, line) \
(void)printf("Assertion failed in \"%s\" at line %u\n\r", ((file) == NULL) ? "" : (file), (unsigned)(line))
#else
#define PRINT_ASSERT(file, line) do { (void)(file); (void)(line); } while(false)
#endif /* REDCONF_OUTPUT == 1 */
#endif /* REDCONF_ASSERTS == 1 */
/** Cast a value to unsigned long.
Usages of this macro deviate from MISRA C:2012 Directive 4.6. This macro is
used in two places to cast a uint64_t value (used by the block device
abstraction for sector numbers) to unsigned long, since third-party code
which is not under the control of this project uses unsigned long for sector
numbers. The cast is guaranteed to not lose any information, since when the
disk is opened the sector count is verified to be less than or equal to an
unsigned long value. The text of the directive mentions that "it might be
desirable not to apply this guideline when interfacing with ... code outside
the project's control", which describes the situation for this deviation.
As Directive 4.6 is advisory, a deviation record is not required. This
notice is the only record of the deviation.
*/
#define CAST_ULONG(ull) ((unsigned long)(ull))
/** Cast a const-qualified pointer to a pointer which is *not* const-qualified.
Usages of this macro deviate from MISRA C:2012 Rule 11.8. This macro is
used in exactly one place in order to cope with a poorly designed
third-party interface. Reliance Edge, at every level of the stack, uses
const-qualified pointers for buffers used in write operations, since the
data is read from the buffer, and the buffer does not need to be modified
(consistent with Rule 8.13). One of the third-party block device interfaces
that Reliance Edge interfaces with does not follow this convention: it uses
an unqualified pointer for the buffer parameter of its sector write
function. This forces the need for the cast to avoid warnings. The
implementation of the sector write function is provided by the user, so it
is to be hoped that the buffer is not actually modified.
As Rule 11.8 is required, a separate deviation record is required.
*/
#define CAST_AWAY_CONST(type, ptr) ((type *)(ptr))
/** Allocate zero-initialized (cleared) memory.
All usages of this macro deviate from MISRA C:2012 Directive 4.12 (required)
and Rule 21.3 (required). In the context of the single place it is actually
used, this macro also deviates from Rule 22.1 (required).
This macro is used in the FreeRTOS block device code in order to allocate a
RAM disk, when that implementation of the block device is selected. The
primary rationale for all these deviations is that a) the RAM disk cannot be
allocated statically (since the volume information is stored in a
structure), and b) the RAM disk is primarily intended as a temporary testing
tool for users who want to try out Reliance Edge before the real storage
media is available. In most real systems, Reliance Edge is used with
non-volatile storage like SD/MMC or eMMC, not with RAM disks.
Rule 22.1 states that all resources which are allocated must also be
explicitly freed. The RAM disk is allocated and never freed, deviating from
that rule. This is done because the data in the RAM disk is emulating a
non-volatile storage medium, and thus needs to persist even after the block
device is closed, to allow the file system to be ormatted and then mounted,
or unmounted and remounted in the course of a test. Thus the memory will
remain allocated until the target device is rebooted. This is assumed to be
acceptable for the primary purpose of the RAM disk, which is preliminary
testing.
As Directive 4.12, Rule 21.3, and Rule 22.1 are all required, separate
deviation records are required.
*/
#define ALLOCATE_CLEARED_MEMORY(nelem, elsize) calloc(nelem, elsize)
#if REDCONF_OUTPUT == 1
/** Output a character to a serial port or other display device.
Usages of this macro deviate from MISRA C:2012 Rule 21.6 (required).
FreeRTOS does not include a standard method of printing characters, so
putchar() is the most convenient and portable way to accomplish the task.
The risk of "unspecified, undefined and implementation-defined" behavior
causing problems (as cited in the rationale for the rule) is small. The
driver does not depend on the character being outputted correctly.
Furthermore, use of putchar() disappears when output is disabled.
As Rule 21.6 is required, a separate deviation record is required.
*/
#define OUTPUT_CHARACTER(ch) (void)putchar(ch)
#endif
#if (REDCONF_TASK_COUNT > 1U) && (REDCONF_API_POSIX == 1)
/** Cast a TaskHandle_t (a pointer type) to uintptr_t.
Usage of this macro deivate from MISRA-C:2012 Rule 11.4 (advisory). This
macro is used for the FreeRTOS version of RedOsTaskId(). Some RTOSes
natively use an integer for task IDs; others use pointers. RedOsTaskId()
uses integers, FreeRTOS uses pointers; to reconcile this difference, the
pointer must be cast to integer. This is fairly safe, since the resulting
integer is never cast back to a pointer; and although the integer
representation of a pointer is implementation-defined, the representation is
irrelevant provided that unique pointers are converted to unique integers.
As Rule 11.4 is advisory, a deviation record is not required. This notice
is the only record of the deviation.
*/
#define CAST_TASK_PTR_TO_UINTPTR(taskptr) ((uintptr_t)(taskptr))
#endif
#endif

View file

@ -0,0 +1,42 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Defines OS-specific types for use in common code.
*/
#ifndef REDOSTYPES_H
#define REDOSTYPES_H
/** @brief Implementation-defined timestamp type.
This can be an integer, a structure, or a pointer: anything that is
convenient for the implementation. Since the underlying type is not fixed,
common code should treat this as an opaque type.
*/
typedef uint32_t REDTIMESTAMP;
#endif

View file

@ -0,0 +1,54 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements assertion handling.
*/
#include <redfs.h>
#if REDCONF_ASSERTS == 1
#include <redosdeviations.h>
/** @brief Invoke the native assertion handler.
@param pszFileName Null-terminated string containing the name of the file
where the assertion fired.
@param ulLineNum Line number in @p pszFileName where the assertion
fired.
*/
void RedOsAssertFail(
const char *pszFileName,
uint32_t ulLineNum)
{
PRINT_ASSERT(pszFileName, ulLineNum);
for( ;; )
{
}
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,79 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements real-time clock functions.
*/
#include <redfs.h>
/** @brief Initialize the real time clock.
The behavior of calling this function when the RTC is already initialized
is undefined.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
*/
REDSTATUS RedOsClockInit(void)
{
return 0;
}
/** @brief Uninitialize the real time clock.
The behavior of calling this function when the RTC is not initialized is
undefined.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
*/
REDSTATUS RedOsClockUninit(void)
{
return 0;
}
/** @brief Get the date/time.
The behavior of calling this function when the RTC is not initialized is
undefined.
@return The number of seconds since January 1, 1970 excluding leap seconds
(in other words, standard Unix time). If the resolution or epoch
of the RTC is different than this, the implementation must convert
it to the expected representation.
*/
uint32_t RedOsClockGetTime(void)
{
/* FreeRTOS does not provide an RTC abstraction since most of the systems
it targets have no RTC hardware. If your hardware includes an RTC that
you would like to use, this function must be customized.
*/
return 0;
}

View file

@ -0,0 +1,120 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements a synchronization object to provide mutual exclusion.
*/
#include <FreeRTOS.h>
#include <semphr.h>
#include <redfs.h>
#if REDCONF_TASK_COUNT > 1U
static SemaphoreHandle_t xMutex;
/** @brief Initialize the mutex.
After initialization, the mutex is in the released state.
The behavior of calling this function when the mutex is still initialized
is undefined.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
*/
REDSTATUS RedOsMutexInit(void)
{
REDSTATUS ret;
xMutex = xSemaphoreCreateMutex();
if(xMutex != NULL)
{
ret = 0;
}
else
{
ret = -RED_ENOMEM;
}
return ret;
}
/** @brief Uninitialize the mutex.
The behavior of calling this function when the mutex is not initialized is
undefined; likewise, the behavior of uninitializing the mutex when it is
in the acquired state is undefined.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
*/
REDSTATUS RedOsMutexUninit(void)
{
vSemaphoreDelete(xMutex);
xMutex = NULL;
return 0;
}
/** @brief Acquire the mutex.
The behavior of calling this function when the mutex is not initialized is
undefined; likewise, the behavior of recursively acquiring the mutex is
undefined.
*/
void RedOsMutexAcquire(void)
{
while(xSemaphoreTake(xMutex, portMAX_DELAY) != pdTRUE)
{
}
}
/** @brief Release the mutex.
The behavior is undefined in the following cases:
- Releasing the mutex when the mutex is not initialized.
- Releasing the mutex when it is not in the acquired state.
- Releasing the mutex from a task or thread other than the one which
acquired the mutex.
*/
void RedOsMutexRelease(void)
{
BaseType_t xSuccess;
xSuccess = xSemaphoreGive(xMutex);
REDASSERT(xSuccess == pdTRUE);
(void)xSuccess;
}
#endif

View file

@ -0,0 +1,70 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements outputting a character string.
*/
#include <redfs.h>
#if REDCONF_OUTPUT == 1
#include <redosdeviations.h>
/** @brief Write a string to a user-visible output location.
Write a null-terminated string to the serial port, console, terminal, or
other display device, such that the text is visible to the user.
@param pszString A null-terminated string.
*/
void RedOsOutputString(
const char *pszString)
{
if(pszString == NULL)
{
REDERROR();
}
else
{
uint32_t ulIdx = 0U;
while(pszString[ulIdx] != '\0')
{
OUTPUT_CHARACTER(pszString[ulIdx]);
/* Serial output often requires a \r to print newlines correctly.
*/
if(pszString[ulIdx] == '\n')
{
OUTPUT_CHARACTER('\r');
}
ulIdx++;
}
}
}
#endif

View file

@ -0,0 +1,68 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements task functions.
*/
#include <FreeRTOS.h>
#include <task.h>
#include <redfs.h>
#if (REDCONF_TASK_COUNT > 1U) && (REDCONF_API_POSIX == 1)
#include <redosdeviations.h>
#if INCLUDE_xTaskGetCurrentTaskHandle != 1
#error "INCLUDE_xTaskGetCurrentTaskHandle must be 1 when REDCONF_TASK_COUNT > 1 and REDCONF_API_POSIX == 1"
#endif
/** @brief Get the current task ID.
This task ID must be unique for all tasks using the file system.
@return The task ID. Must not be 0.
*/
uint32_t RedOsTaskId(void)
{
/* Simply casting the xTaskGetCurrentTaskHandle() return value results in
warnings from some compilers, so use variables.
*/
TaskHandle_t xTask = xTaskGetCurrentTaskHandle();
uintptr_t taskptr = CAST_TASK_PTR_TO_UINTPTR(xTask);
uint32_t ulTaskPtr = (uint32_t)taskptr;
/* Assert no information was lost casting from uintptr_t to uint32_t.
*/
REDASSERT(ulTaskPtr == taskptr);
/* NULL is a valid task handle in FreeRTOS, so add one to all task IDs.
*/
REDASSERT((ulTaskPtr + 1U) != 0U);
return ulTaskPtr + 1U;
}
#endif

View file

@ -0,0 +1,109 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements timestamp functions.
The functionality implemented herein is not needed for the file system
driver, only to provide accurate results with performance tests.
*/
#include <FreeRTOS.h>
#include <task.h>
#include <redfs.h>
/* configTICK_RATE_HZ is almost always 100, 250, 500, or 1000. If
1000000U % configTICK_RATE_HZ != 0, then RedOsTimePassed() will be a
little inaccurate.
*/
#define MICROSECS_PER_TICK (1000000U / configTICK_RATE_HZ)
/** @brief Initialize the timestamp service.
The behavior of invoking this function when timestamps are already
initialized is undefined.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_ENOSYS The timestamp service has not been implemented.
*/
REDSTATUS RedOsTimestampInit(void)
{
return 0;
}
/** @brief Uninitialize the timestamp service.
The behavior of invoking this function when timestamps are not initialized
is undefined.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
*/
REDSTATUS RedOsTimestampUninit(void)
{
return 0;
}
/** @brief Retrieve a timestamp.
The behavior of invoking this function when timestamps are not initialized
is undefined
@return A timestamp which can later be passed to RedOsTimePassed() to
determine the amount of time which passed between the two calls.
*/
REDTIMESTAMP RedOsTimestamp(void)
{
return xTaskGetTickCount();
}
/** @brief Determine how much time has passed since a timestamp was retrieved.
The behavior of invoking this function when timestamps are not initialized
is undefined.
@param tsSince A timestamp acquired earlier via RedOsTimestamp().
@return The number of microseconds which have passed since @p tsSince.
*/
uint64_t RedOsTimePassed(
REDTIMESTAMP tsSince)
{
/* This works even if the tick count has wrapped around, provided it has
only wrapped around once.
*/
uint32_t ulTicksPassed = (uint32_t)xTaskGetTickCount() - tsSince;
uint64_t ullMicrosecs = (uint64_t)ulTicksPassed * MICROSECS_PER_TICK;
return ullMicrosecs;
}

View file

@ -0,0 +1,448 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements path utilities for the POSIX-like API layer.
*/
#include <redfs.h>
#if REDCONF_API_POSIX == 1
#include <redcoreapi.h>
#include <redvolume.h>
#include <redposix.h>
#include "redpath.h"
static bool IsRootDir(const char *pszLocalPath);
static bool PathHasMoreNames(const char *pszPathIdx);
/** @brief Split a path into its component parts: a volume and a volume-local
path.
@param pszPath The path to split.
@param pbVolNum On successful return, if non-NULL, populated with
the volume number extracted from the path.
@param ppszLocalPath On successful return, populated with the
volume-local path: the path stripped of any volume
path prefixing. If this parameter is NULL, that
indicates there should be no local path, and any
characters beyond the prefix (other than path
separators) are treated as an error.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p pszPath is `NULL`.
@retval -RED_ENOENT @p pszPath could not be matched to any volume; or
@p ppszLocalPath is NULL but @p pszPath includes a local
path.
*/
REDSTATUS RedPathSplit(
const char *pszPath,
uint8_t *pbVolNum,
const char **ppszLocalPath)
{
REDSTATUS ret = 0;
if(pszPath == NULL)
{
ret = -RED_EINVAL;
}
else
{
const char *pszLocalPath = pszPath;
uint8_t bMatchVol = UINT8_MAX;
uint32_t ulMatchLen = 0U;
uint8_t bDefaultVolNum = UINT8_MAX;
uint8_t bVolNum;
for(bVolNum = 0U; bVolNum < REDCONF_VOLUME_COUNT; bVolNum++)
{
const char *pszPrefix = gaRedVolConf[bVolNum].pszPathPrefix;
uint32_t ulPrefixLen = RedStrLen(pszPrefix);
if(ulPrefixLen == 0U)
{
/* A volume with a path prefix of an empty string is the
default volume, used when the path does not match the
prefix of any other volume.
The default volume should only be found once. During
initialization, RedCoreInit() ensures that all volume
prefixes are unique (including empty prefixes).
*/
REDASSERT(bDefaultVolNum == UINT8_MAX);
bDefaultVolNum = bVolNum;
}
/* For a path to match, it must either be the prefix exactly, or
be followed by a path separator character. Thus, with a volume
prefix of "/foo", both "/foo" and "/foo/bar" are matches, but
"/foobar" is not.
*/
else if( (RedStrNCmp(pszPath, pszPrefix, ulPrefixLen) == 0)
&& ((pszPath[ulPrefixLen] == '\0') || (pszPath[ulPrefixLen] == REDCONF_PATH_SEPARATOR)))
{
/* The length of this match should never exactly equal the
length of a previous match: that would require a duplicate
volume name, which should have been detected during init.
*/
REDASSERT(ulPrefixLen != ulMatchLen);
/* If multiple prefixes match, the longest takes precedence.
Thus, if there are two prefixes "Flash" and "Flash/Backup",
the path "Flash/Backup/" will not be erroneously matched
with the "Flash" volume.
*/
if(ulPrefixLen > ulMatchLen)
{
bMatchVol = bVolNum;
ulMatchLen = ulPrefixLen;
}
}
else
{
/* No match, keep looking.
*/
}
}
if(bMatchVol != UINT8_MAX)
{
/* The path matched a volume path prefix.
*/
bVolNum = bMatchVol;
pszLocalPath = &pszPath[ulMatchLen];
}
else if(bDefaultVolNum != UINT8_MAX)
{
/* The path didn't match any of the prefixes, but one of the
volumes has a path prefix of "", so an unprefixed path is
assigned to that volume.
*/
bVolNum = bDefaultVolNum;
REDASSERT(pszLocalPath == pszPath);
}
else
{
/* The path cannot be assigned a volume.
*/
ret = -RED_ENOENT;
}
if(ret == 0)
{
if(pbVolNum != NULL)
{
*pbVolNum = bVolNum;
}
if(ppszLocalPath != NULL)
{
*ppszLocalPath = pszLocalPath;
}
else
{
/* If no local path is expected, then the string should either
terminate after the path prefix or the local path should name
the root directory. Allowing path separators here means that
red_mount("/data/") is OK with a path prefix of "/data".
*/
if(pszLocalPath[0U] != '\0')
{
if(!IsRootDir(pszLocalPath))
{
ret = -RED_ENOENT;
}
}
}
}
}
return ret;
}
/** @brief Lookup the inode named by the given path.
@param pszLocalPath The path to lookup; this is a local path, without any
volume prefix.
@param pulInode On successful return, populated with the number of the
inode named by @p pszLocalPath.
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p pszLocalPath is `NULL`; or @p pulInode is
`NULL`.
@retval -RED_EIO A disk I/O error occurred.
@retval -RED_ENOENT @p pszLocalPath is an empty string; or
@p pszLocalPath does not name an existing file
or directory.
@retval -RED_ENOTDIR A component of the path other than the last is
not a directory.
@retval -RED_ENAMETOOLONG The length of a component of @p pszLocalPath is
longer than #REDCONF_NAME_MAX.
*/
REDSTATUS RedPathLookup(
const char *pszLocalPath,
uint32_t *pulInode)
{
REDSTATUS ret;
if((pszLocalPath == NULL) || (pulInode == NULL))
{
REDERROR();
ret = -RED_EINVAL;
}
else if(pszLocalPath[0U] == '\0')
{
ret = -RED_ENOENT;
}
else if(IsRootDir(pszLocalPath))
{
ret = 0;
*pulInode = INODE_ROOTDIR;
}
else
{
uint32_t ulPInode;
const char *pszName;
ret = RedPathToName(pszLocalPath, &ulPInode, &pszName);
if(ret == 0)
{
ret = RedCoreLookup(ulPInode, pszName, pulInode);
}
}
return ret;
}
/** @brief Given a path, return the parent inode number and a pointer to the
last component in the path (the name).
@param pszLocalPath The path to examine; this is a local path, without any
volume prefix.
@param pulPInode On successful return, populated with the inode number of
the parent directory of the last component in the path.
For example, with the path "a/b/c", populated with the
inode number of "b".
@param ppszName On successful return, populated with a pointer to the
last component in the path. For example, with the path
"a/b/c", populated with a pointer to "c".
@return A negated ::REDSTATUS code indicating the operation result.
@retval 0 Operation was successful.
@retval -RED_EINVAL @p pszLocalPath is `NULL`; or @p pulPInode is
`NULL`; or @p ppszName is `NULL`; or the path
names the root directory.
@retval -RED_EIO A disk I/O error occurred.
@retval -RED_ENOENT @p pszLocalPath is an empty string; or a
component of the path other than the last does
not exist.
@retval -RED_ENOTDIR A component of the path other than the last is
not a directory.
@retval -RED_ENAMETOOLONG The length of a component of @p pszLocalPath is
longer than #REDCONF_NAME_MAX.
*/
REDSTATUS RedPathToName(
const char *pszLocalPath,
uint32_t *pulPInode,
const char **ppszName)
{
REDSTATUS ret;
if((pszLocalPath == NULL) || (pulPInode == NULL) || (ppszName == NULL))
{
REDERROR();
ret = -RED_EINVAL;
}
else if(IsRootDir(pszLocalPath))
{
ret = -RED_EINVAL;
}
else if(pszLocalPath[0U] == '\0')
{
ret = -RED_ENOENT;
}
else
{
uint32_t ulInode = INODE_ROOTDIR;
uint32_t ulPInode = INODE_INVALID;
uint32_t ulPathIdx = 0U;
uint32_t ulLastNameIdx = 0U;
ret = 0;
do
{
uint32_t ulNameLen;
/* Skip over path separators, to get pszLocalPath[ulPathIdx]
pointing at the next name.
*/
while(pszLocalPath[ulPathIdx] == REDCONF_PATH_SEPARATOR)
{
ulPathIdx++;
}
if(pszLocalPath[ulPathIdx] == '\0')
{
break;
}
/* Point ulLastNameIdx at the first character of the name; after
we exit the loop, it will point at the first character of the
last name in the path.
*/
ulLastNameIdx = ulPathIdx;
/* Point ulPInode at the parent inode: either the root inode
(first pass) or the inode of the previous name. After we exit
the loop, this will point at the parent inode of the last name.
*/
ulPInode = ulInode;
ulNameLen = RedNameLen(&pszLocalPath[ulPathIdx]);
/* Lookup the inode of the name, unless we are at the last name in
the path: we don't care whether the last name exists or not.
*/
if(PathHasMoreNames(&pszLocalPath[ulPathIdx + ulNameLen]))
{
ret = RedCoreLookup(ulPInode, &pszLocalPath[ulPathIdx], &ulInode);
}
/* Move on to the next path element.
*/
if(ret == 0)
{
ulPathIdx += ulNameLen;
}
}
while(ret == 0);
if(ret == 0)
{
*pulPInode = ulPInode;
*ppszName = &pszLocalPath[ulLastNameIdx];
}
}
return ret;
}
/** @brief Determine whether a path names the root directory.
@param pszLocalPath The path to examine; this is a local path, without any
volume prefix.
@return Returns whether @p pszLocalPath names the root directory.
@retval true @p pszLocalPath names the root directory.
@retval false @p pszLocalPath does not name the root directory.
*/
static bool IsRootDir(
const char *pszLocalPath)
{
bool fRet;
if(pszLocalPath == NULL)
{
REDERROR();
fRet = false;
}
else
{
uint32_t ulIdx = 0U;
/* A string containing nothing but path separators (usually only one)
names the root directory. An empty string does *not* name the root
directory, since in POSIX empty strings typically elicit -RED_ENOENT
errors.
*/
while(pszLocalPath[ulIdx] == REDCONF_PATH_SEPARATOR)
{
ulIdx++;
}
fRet = (ulIdx > 0U) && (pszLocalPath[ulIdx] == '\0');
}
return fRet;
}
/** @brief Determine whether there are more names in a path.
Example | Result
------- | ------
"" false
"\" false
"\\" false
"a" true
"\a" true
"\\a" true
@param pszPathIdx The path to examine, incremented to the point of
interest.
@return Returns whether there are more names in @p pszPathIdx.
@retval true @p pszPathIdx has more names.
@retval false @p pszPathIdx has no more names.
*/
static bool PathHasMoreNames(
const char *pszPathIdx)
{
bool fRet;
if(pszPathIdx == NULL)
{
REDERROR();
fRet = false;
}
else
{
uint32_t ulIdx = 0U;
while(pszPathIdx[ulIdx] == REDCONF_PATH_SEPARATOR)
{
ulIdx++;
}
fRet = pszPathIdx[ulIdx] != '\0';
}
return fRet;
}
#endif /* REDCONF_API_POSIX */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,38 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Interfaces of path utilities for the POSIX-like API layer.
*/
#ifndef REDPATH_H
#define REDPATH_H
REDSTATUS RedPathSplit(const char *pszPath, uint8_t *pbVolNum, const char **ppszLocalPath);
REDSTATUS RedPathLookup(const char *pszLocalPath, uint32_t *pulInode);
REDSTATUS RedPathToName(const char *pszLocalPath, uint32_t *pulPInode, const char **ppszName);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,152 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Defines macros which make the Reliance Edge POSIX-like API look more
like the actual POSIX API.
This file is intended for porting POSIX file system tests; it is not
intended for application use.
*/
#ifndef REDPOSIXCOMPAT_H
#define REDPOSIXCOMPAT_H
#ifndef assert
#define assert(x) REDASSERT(x)
#endif
#undef O_RDONLY
#undef O_WRONLY
#undef O_RDWR
#undef O_APPEND
#undef O_CREAT
#undef O_EXCL
#undef O_TRUNC
#define O_RDONLY RED_O_RDONLY
#define O_WRONLY RED_O_WRONLY
#define O_RDWR RED_O_RDWR
#define O_APPEND RED_O_APPEND
#define O_CREAT RED_O_CREAT
#define O_EXCL RED_O_EXCL
#define O_TRUNC RED_O_TRUNC
#undef SEEK_SET
#undef SEEK_CUR
#undef SEEK_END
#define SEEK_SET RED_SEEK_SET
#define SEEK_CUR RED_SEEK_CUR
#define SEEK_END RED_SEEK_END
/* Old-fashioned Linux seek names.
*/
#undef L_SET
#undef L_INCR
#undef L_XTND
#define L_SET SEEK_SET
#define L_INCR SEEK_CUR
#define L_XTND SEEK_END
#undef S_IFDIR
#undef S_IFREG
#undef S_ISDIR
#undef S_ISREG
#define S_IFDIR RED_S_IFDIR
#define S_IFREG RED_S_IFREG
#define S_ISDIR(m) RED_S_ISDIR(m)
#define S_ISREG(m) RED_S_ISREG(m)
#undef ST_RDONLY
#undef ST_NOSUID
#define ST_RDONLY RED_ST_RDONLY
#define ST_NOSUID RED_ST_NOSUID
#undef open
#undef creat
#undef unlink
#undef mkdir
#undef rmdir
#undef rename
#undef link
#undef close
#undef read
#undef write
#undef fsync
#undef fdatasync
#undef lseek
#undef ftruncate
#undef fstat
#undef opendir
#undef readdir
#undef rewinddir
#undef closedir
#define open(path, oflag) red_open(path, oflag)
#define creat(path, mode) open(path, O_WRONLY|O_CREAT|O_TRUNC)
#define unlink(path) red_unlink(path)
#define mkdir(path) red_mkdir(path)
#define rmdir(path) red_rmdir(path)
#define rename(old, new) red_rename(old, new)
#define link(path, hardlink) red_link(path, hardlink)
#define close(fd) red_close(fd)
#define read(fd, buf, len) red_read(fd, buf, len)
#define write(fd, buf, len) red_write(fd, buf, len)
#define fsync(fd) red_fsync(fd)
#define fdatasync(fd) fsync(fd)
#define lseek(fd, offset, whence) red_lseek(fd, offset, whence)
#define lseek64(fd, offset, whence) lseek(fd, offset, whence)
#define ftruncate(fd, size) red_ftruncate(fd, size)
#define fstat(fd, stat) red_fstat(fd, stat)
#define fstat64(fd, stat) fstat(fd, stat)
#define opendir(path) red_opendir(path)
#define readdir(dirp) red_readdir(dirp)
#define readdir64(dirp) readdir(dirp)
#define rewinddir(dirp) red_rewinddir(dirp)
#define closedir(dirp) red_closedir(dirp)
#undef DIR
#define DIR REDDIR
#undef errno
#define errno (*(int *)red_errnoptr())
#undef memcpy
#undef memmove
#undef memset
#undef strlen
#undef strncmp
#undef strcmp
#undef strncpy
#define memcpy(d, s, l) RedMemCpy(d, s, (uint32_t)(l))
#define memmove(d, s, l) RedMemMove(d, s, (uint32_t)(l))
#define memset(d, c, l) RedMemSet(d, (uint8_t)(c), (uint32_t)(l))
#define strlen(s) RedStrLen(s)
#define strncmp(s1, s2, l) RedStrNCmp(s1, s2, (uint32_t)(l))
#define strcmp(s1, s2) RedStrCmp(s1, s2)
#define strncpy(d, s, l) RedStrNCpy(d, s, (uint32_t)(l))
#endif

View file

@ -0,0 +1,478 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements utilities that convert strings to numbers.
*/
#include <redfs.h>
#include <redtestutils.h>
#define ISHEXDIGITU(c) (((c) >= 'A') && ((c) <= 'F'))
#define ISHEXDIGITL(c) (((c) >= 'a') && ((c) <= 'f'))
#define ISHEXDIGIT(c) (ISHEXDIGITL(c) || ISHEXDIGITU(c))
/** @brief Converts an ASCII number into an int32_t.
Converts all decimal digit numbers up to the end of the string or to the
first non-numerical character.
@note This function does *not* ignore leading white space.
@param pszNum Pointer to a constant array of characters.
@return The integer represented in the string.
*/
int32_t RedAtoI(
const char *pszNum)
{
int32_t lValue = 0;
int32_t lNegative = 1;
uint32_t ulIdx = 0U;
if(pszNum[ulIdx] == '+')
{
ulIdx++;
}
else if(pszNum[ulIdx] == '-')
{
ulIdx++;
lNegative = -1;
}
else
{
/* No sign, implicitly positive.
*/
}
while(ISDIGIT(pszNum[ulIdx]))
{
lValue *= 10;
lValue += pszNum[ulIdx] - '0';
ulIdx++;
}
lValue *= lNegative;
return lValue;
}
/** @brief Convert a hexadecimal ASCII number into a uint32_t value.
The function processes all hex digits up to a NUL-terminator, or to the
first non-hex character. Only hexadecimal digits are processed, so leading
white space, or a leading "0x" prefix are not allowed.
If pachNum points to an empty string (points to a NUL), this function will
return NULL, and the value at *pulNum will not be modified.
@note This function does not check for overflow. If there are more
significant digits than can be represented in a uint32_t variable, the
output is unspecified.
@param pachNum A pointer to a constant array of hex characters.
@param pulNum A pointer to the location in which to store the uint32_t
result. Upon return, this value will be modified ONLY if
the function succeeds and the returned pointer is valid (not
NULL).
@return A pointer to the byte following the converted number or NULL to
indicate failure.
*/
const char *RedHtoUL(
const char *pszNum,
uint32_t *pulNum)
{
uint64_t ullValue;
const char *pszReturn;
pszReturn = RedHtoULL(pszNum, &ullValue);
if(pszReturn != NULL)
{
if(ullValue < UINT32_MAX)
{
*pulNum = (uint32_t)ullValue;
}
else
{
pszReturn = NULL;
}
}
return pszReturn;
}
/** @brief Convert a hexadecimal ASCII number into a D_UINT64 value.
The function processes all hex digits up to a NUL-terminator, or to the
first non-hex character. Only hexadecimal digits are processed, so leading
white space, or a leading "0x" prefix are not allowed.
If pachNum points to an empty string (points to a NUL), this function will
return NULL, and the value at *pulNum will not be modified.
@note This function does not check for overflow. If there are more
significant digits than can be represented in a uint64_t variable, the
output is unspecified.
@param pszNum A pointer to a constant array of hex characters.
@param pullNum A pointer to the location in which to store the uint64_t
result. Upon return, this value will be modified ONLY if
the function succeeds and the returned pointer is valid (not
NULL).
@return A pointer to the byte following the converted number, or NULL to
indicate failure.
*/
const char *RedHtoULL(
const char *pszNum,
uint64_t *pullNum)
{
uint64_t ullValue = 0U;
const char *pszReturn = NULL;
uint32_t ulIdx = 0U;
REDASSERT(pszNum != NULL);
REDASSERT(pullNum != NULL);
while(pszNum[ulIdx] != '\0')
{
char cDigit = pszNum[ulIdx];
if(ISDIGIT(cDigit))
{
cDigit -= '0';
}
else if(ISHEXDIGITU(cDigit))
{
cDigit -= ('A' - 10);
}
else if(ISHEXDIGITL(cDigit))
{
cDigit -= ('a' - 10);
}
else
{
break;
}
REDASSERT((ullValue & UINT64_SUFFIX(0xF000000000000000)) == 0U);
ullValue <<= 4U;
ullValue += cDigit;
ulIdx++;
pszReturn = &pszNum[ulIdx];
}
/* Modify the number returned only if we found one or more valid hex
digits.
*/
if(pszReturn != NULL)
{
*pullNum = ullValue;
}
return pszReturn;
}
/** @brief Convert the ASCII number to a uint32_t value.
The number may be hex or decimal. Hex numbers must be prefixed by '0x', and
they may be upper or lower case. The conversion process will stop with the
first non hex or decimal digit.
If the number is negative (the first character is a '-' sign), the value
will be range checked and returned as the equivalent unsigned value.
@note This function will NOT fail for numbers which exceed the size of a
uint32_t value.
@param pszNum A pointer to the ASCII number to convert
@param pulNum A pointer to the uint32_t location to store the result.
This value will be modified on return only if the function
succeeds and the returned pointer is valid (not NULL).
@return A pointer to the byte following the converted number, or NULL to
indicate failure.
*/
const char *RedNtoUL(
const char *pszNum,
uint32_t *pulNum)
{
bool fNegative = false;
uint32_t ulIdx = 0U;
const char *pszReturn;
REDASSERT(pszNum != NULL);
REDASSERT(pulNum != NULL);
if(pszNum[ulIdx] == '-')
{
fNegative = true;
ulIdx++;
}
/* Hex numbers must be prefixed with '0x'.
*/
if((pszNum[ulIdx] == '0') && ((pszNum[ulIdx + 1U] == 'x') || (pszNum[ulIdx + 1U] == 'X')))
{
ulIdx += 2U;
if(ISDIGIT(pszNum[ulIdx]) || ISHEXDIGIT(pszNum[ulIdx]))
{
pszReturn = RedHtoUL(&pszNum[ulIdx], pulNum);
}
else
{
pszReturn = NULL;
}
}
else if(ISDIGIT(pszNum[ulIdx]))
{
uint32_t ulTemp;
ulTemp = RedAtoI(&pszNum[ulIdx]);
while(ISDIGIT(pszNum[ulIdx]))
{
ulIdx++;
}
if(fNegative)
{
/* Fail if the number is out of range.
*/
if(ulTemp > INT32_MAX)
{
pszReturn = NULL;
}
else
{
*pulNum = -((int32_t)ulTemp);
pszReturn = &pszNum[ulIdx];
}
}
else
{
*pulNum = ulTemp;
pszReturn = &pszNum[ulIdx];
}
}
else
{
/* Return an error if there is not at least one hex or decimal digit.
*/
pszReturn = NULL;
}
return pszReturn;
}
/** @brief Convert the ASCII number pointed to by pachNum to a uint64_t value.
The number may be hex or decimal. Hex numbers must be prefixed by '0x', and
they may be upper or lower case. The conversion process will stop with the
first non hex or decimal digit.
If the number is negative (the first character is a '-' sign), the value
will be range checked and returned as the equivalent unsigned value.
@param pszNum A pointer to the ASCII number to convert.
@param pullNum A pointer to the uint64_t location to store the result.
This value will be modified on return only if the function
succeeds and the returned pointer is valid (not NULL).
@return A pointer to the byte following the converted number, or NULL to
indicate failure.
*/
const char *RedNtoULL(
const char *pszNum,
uint64_t *pullNum)
{
bool fNegative = false;
uint32_t ulIdx = 0U;
const char *pszReturn;
REDASSERT(pszNum != NULL);
REDASSERT(pullNum != NULL);
if(pszNum[ulIdx] == '-')
{
fNegative = true;
ulIdx++;
}
/* Hex numbers must be prefixed with '0x'.
*/
if((pszNum[ulIdx] == '0') && ((pszNum[ulIdx + 1U] == 'x') || (pszNum[ulIdx + 1U] == 'X')))
{
ulIdx += 2U;
if(ISDIGIT(pszNum[ulIdx]) || ISHEXDIGIT(pszNum[ulIdx]))
{
pszReturn = RedHtoULL(&pszNum[ulIdx], pullNum);
}
else
{
pszReturn = NULL;
}
}
else if(ISDIGIT(pszNum[ulIdx]))
{
uint64_t ullTemp = 0U;
while(ISDIGIT(pszNum[ulIdx]))
{
ullTemp *= 10U;
ullTemp += pszNum[ulIdx] - '0';
ulIdx++;
}
if(fNegative)
{
/* Fail if the number is out of range.
*/
if(ullTemp > INT64_MAX)
{
pszReturn = NULL;
}
else
{
*pullNum = (uint64_t)(-((int64_t)ullTemp));
pszReturn = &pszNum[ulIdx];
}
}
else
{
*pullNum = ullTemp;
pszReturn = &pszNum[ulIdx];
}
}
else
{
/* Return an error if there is not at least one hex or decimal digit.
*/
pszReturn = NULL;
}
return pszReturn;
}
/** @brief Convert an ASCII hex or decimal number, which may may have a "B",
"KB", or "MB" suffix (case insensitive), to a binary value.
Hex numbers must be prefixed with "0x".
@note If there is no postfix, KB is assumed!
May fail due to bad formatting or overflow.
@param pszNum A pointer to the ASCII number to convert.
@param pulResult A pointer to a uint32_t in which to place the result.
@return A pointer to the byte following the string, or NULL to indicate an
error. In the event of an error, *pulResult will not be modified.
*/
const char *RedSizeToUL(
const char *pszNum,
uint32_t *pulResult)
{
uint32_t ulResult;
const char *pszSuffix;
const char *pszReturn;
uint32_t ulIdx = 0U;
REDASSERT(pszNum != NULL);
REDASSERT(pulResult != NULL);
/* Do the basic hex/decimal conversion
*/
pszSuffix = RedNtoUL(pszNum, &ulResult);
if(pszSuffix != NULL)
{
if((pszSuffix[ulIdx] == 'B') || (pszSuffix[ulIdx] == 'b'))
{
ulIdx++;
pszReturn = &pszSuffix[ulIdx];
}
else if( ((pszSuffix[ulIdx] == 'M') || (pszSuffix[ulIdx] == 'm'))
&& ((pszSuffix[ulIdx + 1U] == 'B') || (pszSuffix[ulIdx + 1U] == 'b')))
{
ulIdx += 2U;
if(ulResult > (UINT32_MAX / (1024U * 1024U)))
{
pszReturn = NULL;
}
else
{
ulResult *= 1024U * 1024U;
pszReturn = &pszSuffix[ulIdx];
}
}
else
{
/* The number is either postfixed with "KB" or something
else (we don't care), but we must increment the pointer
if it is something recognize.
*/
if( ((pszSuffix[ulIdx] == 'K') || (pszSuffix[ulIdx] == 'k'))
&& ((pszSuffix[ulIdx + 1U] == 'B') || (pszSuffix[ulIdx + 1U] == 'b')))
{
ulIdx += 2U;
}
/* "B" or "MB" were not specified, so it must be "KB"
*/
if(ulResult > (UINT32_MAX / 1024U))
{
pszReturn = NULL;
}
else
{
ulResult *= 1024UL;
pszReturn = &pszSuffix[ulIdx];
}
}
if(pszReturn != NULL)
{
*pulResult = ulResult;
}
}
else
{
pszReturn = NULL;
}
return pszReturn;
}

View file

@ -0,0 +1,641 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements routines for certain 64-bit math operations and simulated
floating point.
RedUint64DivMod32() and RedUint64DivMod64() are derived from code at
http://www.hackersdelight.org. This web site states explicitly that "You
are free to use, copy, and distribute any of the code on this web site,
whether modified by you or not. You need not give attribution."
*/
#include <redfs.h>
#include <redtestutils.h>
static uint32_t nlz64(uint64_t ullValue);
/** @brief Return a ratio value formatted as a floating point string accurate to
the specified number of decimal places.
The function exists to provide floating point style output without using
any actual floating point types.
This function may scale the numbers down to avoid overflow at the high end.
Likewise, potential divide-by-zero errors are internally avoided. Here are
some examples:
Dividend | Divisor | DecPlaces | Result
-------- | ------- | --------- | ------
12133 | 28545 | 2 | "0.42"
1539 | 506 | 2 | "3.04"
To get a number formatted as a percentage, take the take the portion of the
total (normally the smaller part), multiply it by 100, and pass it to this
function as the Dividend, pass the "total" value to this function as the
Divisor, and specify the desired number of decimal places.
For example, if you have a disk format overhead value of N blocks out of a
total of Y blocks on the disk, and you want to display the format overhead
as a percentage, you would use a function call
similar to:
~~~{.c}
RedRatio(szBuffer, sizeof(szBuffer), N*100U, Y, 2U);
~~~
If N=145, Y=4096, and decimal places is 2, the resulting output would be
"3.54".
The string returned will always be null-terminated, even if it means
stomping on the least significant decimal digit.
If either the dividend or divisor values are zero, the string "0.0" will be
returned, with the prescribed number of decimal places.
@note This function has "reasonable" limits which meet the needs of the
various supplemental utilities which use this function. Extremely
large ratios, or using many decimal places may not function as
desired.
Parameters:
@param pBuffer A pointer to the buffer in which to store the null
terminated results.
@param ulBufferLen The length of the output buffer.
@param ullDividend The "total" value to divide.
@param ullDivisor The portion of ullDividend for which to calculate the
ratio (may be greater than ulDividend).
@param ulDecPlaces The number of decimal places to use, from 0 to 9.
@return @p pBuffer.
*/
char *RedRatio(
char *pBuffer,
uint32_t ulBufferLen,
uint64_t ullDividend,
uint64_t ullDivisor,
uint32_t ulDecPlaces)
{
REDASSERT(pBuffer != NULL);
REDASSERT(ulBufferLen > 0U);
REDASSERT(ulDecPlaces <= 9U); /* arbitrary */
if((ullDivisor > 0U) && (ullDividend > 0U))
{
uint32_t ii;
uint32_t ulFactor = 1U;
uint64_t ullDecimal;
uint64_t ullTemp;
for(ii = 1U; ii <= ulDecPlaces; ii++)
{
ulFactor *= 10U;
}
ullDecimal = RedMulDiv64(ullDividend, ulFactor, ullDivisor);
/* Shouldn't really be calling this function in a situation where we
can overflow at this point...
*/
REDASSERT(ullDecimal != UINT64_MAX);
if(ullDivisor <= ullDividend)
{
uint32_t ulDecimal;
(void)RedUint64DivMod32(ullDecimal, ulFactor, &ulDecimal);
ullDecimal = ulDecimal;
}
ullTemp = RedUint64DivMod64(ullDividend, ullDivisor, NULL);
if(ulDecPlaces > 0U)
{
RedSNPrintf(pBuffer, ulBufferLen, "%llu.%0*llu", (unsigned long long)ullTemp,
(unsigned)ulDecPlaces, (unsigned long long)ullDecimal);
}
else
{
RedSNPrintf(pBuffer, ulBufferLen, "%llu", (unsigned long long)ullTemp);
}
}
else
{
/* If either the dividend or divisor is zero, then just output a "0.0"
string with the prescribed number of decimal places.
*/
if(ulDecPlaces > 0U)
{
RedSNPrintf(pBuffer, ulBufferLen, "0.%0*u", (unsigned)ulDecPlaces, 0U);
}
else
{
RedStrNCpy(pBuffer, "0", ulBufferLen);
}
}
/* Ensure the returned buffer is always null-terminated
*/
pBuffer[ulBufferLen - 1U] = '\0';
return pBuffer;
}
/** @brief Multiply 64-bit and 32-bit numbers, and divide by a 64-bit number,
returning a 64-bit result.
@note This function may return an approximate value if multiplying
@p ullBase and @p ulMultplier results in a number larger than 64-bits
_and_ this cannot be avoided by scaling.
@param ullBase The base 64-bit number number.
@param ulMultiplier The 32-bit number by which to multiply.
@param ullDivisor The 64-bit number by which to divide.
@return The 64-bit unsigned integer result. Always returns zero if either
@p ullBase or @p ulMultiplier are zero (regardless what
@p ullDivisor is). Returns UINT64_MAX if an overflow condition
occurred, or if @p ullDivisor is zero.
*/
uint64_t RedMulDiv64(
uint64_t ullBase,
uint32_t ulMultiplier,
uint64_t ullDivisor)
{
uint64_t ullTemp;
/* Result would always be zero if either of these are zero. Specifically
test this case before looking for a zero divisor.
*/
if((ullBase == 0U) || (ulMultiplier == 0U))
{
return 0U;
}
if(ullDivisor == 0U)
{
return UINT64_MAX;
}
/* Since we don't have the ability (yet) to use 128-bit numbers, we jump
through the following hoops (in order) to try to determine the proper
results without losing precision:
1) Shift the divisor and one of the multiplicands as many times as is
necessary to reduce the scale -- only if it can be done without
losing precision.
2) Divide one of the multiplicands by the divisor first, but only if it
divides evenly, preserving precision.
3) Same as #2, but try it for the other multiplicand.
4) Last ditch, divide the larger multiplicand by the divisor first, then
do the multiply. This <WILL> lose precision.
These solutions are identified as CODE-PATHs #1-4 which are used to
identify the matching tests in dltmain.c.
Note that execution might partially include CODE-PATH #1 up until
shifting can no longer be done without losing precision. In that case,
one of the three remaining options will be used.
*/
ullTemp = RedUint64DivMod32(UINT64_MAX, ulMultiplier, NULL);
while(ullBase > ullTemp)
{
uint64_t ullMod;
uint64_t ullBaseTemp;
uint64_t ullWideMultiplier;
/* CODE-PATH #1
*/
/* So long as ulDivisor, and at least one of the other numbers, are
evenly divisible by 2, we can scale the numbers so the result does
not overflow the intermediate 64-bit value.
*/
if((ullDivisor & 1U) == 0U)
{
if((ullBase & 1U) == 0U)
{
/* CODE-PATH #1a
*/
ullDivisor >>= 1U;
ullBase >>= 1U;
continue;
}
if(((ulMultiplier & 1U) == 0U) && ((ullTemp & UINT64_SUFFIX(0x8000000000000000)) == 0U))
{
/* CODE-PATH #1b
*/
ullDivisor >>= 1U;
ulMultiplier >>= 1U;
ullTemp <<= 1U;
continue;
}
}
/* If we get to this point, the above method (#1) cannot be used
because not enough of the numbers are even long enough to scale the
operands down. We'll see if either multiplicand is evenly divisble
by ulDivisor, and if so, do the divide first, then the multiply.
(Note that once we get to this point, we will never exercise the
while{} loop anymore.)
*/
/* CODE-PATH #2
*/
ullBaseTemp = RedUint64DivMod64(ullBase, ullDivisor, &ullMod);
if(ullMod == 0U)
{
/* Evenly divides, so check that we won't overflow, and finish up.
*/
ullBase = ullBaseTemp;
if(ullBase > ullTemp)
{
return UINT64_MAX;
}
else
{
/* We've validated that this will not overflow.
*/
ullBase *= ulMultiplier;
return ullBase;
}
}
/* CODE-PATH #3
*/
ullWideMultiplier = RedUint64DivMod64(ulMultiplier, ullDivisor, &ullMod);
if(ullMod == 0U)
{
/* Evenly divides, so check that we won't overflow, and finish up.
*/
/* Must recalculate ullTemp relative to ullBase
*/
ullTemp = RedUint64DivMod64(UINT64_MAX, ullBase, NULL);
if(ullWideMultiplier > ullTemp)
{
return UINT64_MAX;
}
else
{
uint32_t ulNarrowMultiplier = (uint32_t)ullWideMultiplier;
/* We've validated that this will not overflow.
*/
ullBase *= ulNarrowMultiplier;
return ullBase;
}
}
/* CODE-PATH #4
Neither of the multipliers is evenly divisible by the divisor, so
just punt and divide the larger number first, then do the final
multiply.
All the other attempts above would preserve precision -- this is the
only case where precision may be lost.
*/
/* If necessary reverse the ullBase and ulMultiplier operands so that
ullBase contains the larger of the two values.
*/
if(ullBase < ulMultiplier)
{
uint32_t ulTemp = ulMultiplier;
ulMultiplier = (uint32_t)ullBase;
ullBase = ulTemp;
}
ullBase = RedUint64DivMod64(ullBase, ullDivisor, NULL);
ullTemp = RedUint64DivMod32(UINT64_MAX, ulMultiplier, NULL);
if(ullBase > ullTemp)
{
return UINT64_MAX;
}
else
{
ullBase *= ulMultiplier;
return ullBase;
}
}
/* We only get to this point if either there was never any chance of
overflow, or if the pure shifting mechanism succeeded in reducing
the scale so overflow is not a problem.
*/
ullBase *= ulMultiplier;
ullBase = RedUint64DivMod64(ullBase, ullDivisor, NULL);
return ullBase;
}
/** @brief Divide a 64-bit value by a 32-bit value, returning the quotient and
the remainder.
Essentially this function does the following:
~~~{.c}
if(pulRemainder != NULL)
{
*pulRemainder = (uint32_t)(ullDividend % ulDivisor);
}
return ullDividend / ulDivisor;
~~~
However, it does so without ever actually dividing/modulating a 64-bit
value, since such operations are not allowed in all environments.
@param ullDividend The value to divide.
@param ulDivisor The value to divide by.
@param pulRemander Populated with the remainder; may be NULL.
@return The quotient (result of the division).
*/
uint64_t RedUint64DivMod32(
uint64_t ullDividend,
uint32_t ulDivisor,
uint32_t *pulRemainder)
{
uint64_t ullQuotient;
uint32_t ulResultRemainder;
/* Check for divide by zero.
*/
if(ulDivisor == 0U)
{
REDERROR();
/* Nonsense value if no asserts.
*/
ullQuotient = UINT64_SUFFIX(0xFFFFFFFFFFFFFBAD);
ulResultRemainder = 0xFFFFFBADU;
}
else if(ullDividend <= UINT32_MAX)
{
uint32_t ulDividend = (uint32_t)ullDividend;
ullQuotient = ulDividend / ulDivisor;
ulResultRemainder = ulDividend % ulDivisor;
}
else
{
uint32_t ulResultHi;
uint32_t ulResultLo;
uint32_t ulRemainder;
uint8_t bIndex;
uint32_t ulThisDivision;
uint32_t ulMask;
uint8_t ucNextValue;
uint32_t ulInterimHi, ulInterimLo;
uint32_t ulLowDword = (uint32_t)ullDividend;
uint32_t ulHighDword = (uint32_t)(ullDividend >> 32U);
/* Compute the high part and get the remainder
*/
ulResultHi = ulHighDword / ulDivisor;
ulResultLo = 0U;
ulRemainder = ulHighDword % ulDivisor;
/* Compute the low part
*/
ulMask = 0xFF000000U;
for(bIndex = 0U; bIndex < sizeof(uint32_t); bIndex++)
{
ucNextValue = (uint8_t)((ulLowDword & ulMask) >> ((sizeof(uint32_t) - 1U - bIndex) * 8U));
ulInterimHi = ulRemainder >> 24U;
ulInterimLo = (ulRemainder << 8U) | ucNextValue;
ulThisDivision = 0U;
while(ulInterimHi != 0U)
{
uint64_t ullInterim = ((uint64_t)ulInterimHi << 32U) + ulInterimLo;
ullInterim -= ulDivisor;
ulThisDivision++;
ulInterimHi = (uint32_t)(ullInterim >> 32U);
ulInterimLo = (uint32_t)ullInterim;
}
ulThisDivision += ulInterimLo / ulDivisor;
ulRemainder = ulInterimLo % ulDivisor;
ulResultLo <<= 8U;
ulResultLo += ulThisDivision;
ulMask >>= 8U;
}
ullQuotient = ((uint64_t)ulResultHi << 32U) + ulResultLo;
ulResultRemainder = (uint32_t)(ullDividend - (ullQuotient * ulDivisor));
}
if(pulRemainder != NULL)
{
*pulRemainder = ulResultRemainder;
}
return ullQuotient;
}
/** @brief Divide a 64-bit value by a 64-bit value, returning the quotient and
the remainder.
Essentially this function does the following:
~~~{.c}
if(pullRemainder != NULL)
{
*pullRemainder = ullDividend % ullDivisor;
}
return ullDividend / ullDivisor;
~~~
However, it does so without ever actually dividing/modulating a 64-bit
value, since such operations are not allowed in all environments.
@param ullDividend The value to divide.
@param ullDivisor The value to divide by.
@param pullRemander Populated with the remainder; may be NULL.
@return The quotient (result of the division).
*/
uint64_t RedUint64DivMod64(
uint64_t ullDividend,
uint64_t ullDivisor,
uint64_t *pullRemainder)
{
/* The variables u0, u1, etc. take on only 32-bit values, but they are
declared uint64_t to avoid some compiler warning messages and to avoid
some unnecessary EXTRs that the compiler would put in, to convert
uint64_ts to ints.
*/
uint64_t u0;
uint64_t u1;
uint64_t q0;
uint64_t q1;
uint64_t ullQuotient;
/* First the procedure takes care of the case in which the divisor is a
32-bit quantity. There are two subcases: (1) If the left half of the
dividend is less than the divisor, one execution of RedUint64DivMod32()
is all that is required (overflow is not possible). (2) Otherwise it
does two divisions, using the grade school method.
*/
if((ullDivisor >> 32U) == 0U)
{
if((ullDividend >> 32U) < ullDivisor)
{
/* If ullDividend/ullDivisor cannot overflow, just do one division.
*/
ullQuotient = RedUint64DivMod32(ullDividend, (uint32_t)ullDivisor, NULL);
}
else
{
uint32_t k;
/* If ullDividend/ullDivisor would overflow:
*/
/* Break ullDividend up into two halves.
*/
u1 = ullDividend >> 32U;
u0 = ullDividend & 0xFFFFFFFFU;
/* First quotient digit and first remainder.
*/
q1 = RedUint64DivMod32(u1, (uint32_t)ullDivisor, &k);
/* 2nd quot. digit.
*/
q0 = RedUint64DivMod32(((uint64_t)k << 32U) + u0, (uint32_t)ullDivisor, NULL);
ullQuotient = (q1 << 32U) + q0;
}
}
else
{
uint64_t n;
uint64_t v1;
n = nlz64(ullDivisor); /* 0 <= n <= 31. */
v1 = (ullDivisor << n) >> 32U; /* Normalize the divisor so its MSB is 1. */
u1 = ullDividend >> 1U; /* To ensure no overflow. */
/* Get quotient from divide unsigned insn.
*/
q1 = RedUint64DivMod32(u1, (uint32_t)v1, NULL);
q0 = (q1 << n) >> 31U; /* Undo normalization and division of ullDividend by 2. */
/* Make q0 correct or too small by 1.
*/
if(q0 != 0U)
{
q0--;
}
if((ullDividend - (q0 * ullDivisor)) >= ullDivisor)
{
q0++; /* Now q0 is correct. */
}
ullQuotient = q0;
}
if(pullRemainder != NULL)
{
*pullRemainder = ullDividend - (ullQuotient * ullDivisor);
}
return ullQuotient;
}
/** @brief Compute the number of leading zeroes in a 64-bit value.
@param ullValue The value for which to compute the NLZ.
@return The number of leading zeroes in @p ullValue.
*/
static uint32_t nlz64(
uint64_t ullValue)
{
uint32_t n;
if(ullValue == 0U)
{
n = 64U;
}
else
{
uint64_t x = ullValue;
n = 0U;
if(x <= UINT64_SUFFIX(0x00000000FFFFFFFF))
{
n += 32U;
x <<= 32U;
}
if(x <= UINT64_SUFFIX(0x0000FFFFFFFFFFFF))
{
n += 16U;
x <<= 16U;
}
if(x <= UINT64_SUFFIX(0x00FFFFFFFFFFFFFF))
{
n += 8U;
x <<= 8U;
}
if(x <= UINT64_SUFFIX(0x0FFFFFFFFFFFFFFF))
{
n += 4U;
x <<= 4U;
}
if(x <= UINT64_SUFFIX(0x3FFFFFFFFFFFFFFF))
{
n += 2U;
x <<= 2U;
}
if(x <= UINT64_SUFFIX(0x7FFFFFFFFFFFFFFF))
{
n += 1;
}
}
return n;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,159 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements a random number generator.
*/
#include <redfs.h>
#include <redtestutils.h>
/* This is the global seed used by the random number generator when the caller
has not provided a seed to either the RedRand32() or RedRand64() functions.
*/
static uint64_t ullGlobalRandomNumberSeed;
/* Whether the above seed has been initialized.
*/
static bool fGlobalSeedInited;
/** @brief Set the global seed used by the random number generator.
The global seed gets used when RedRand64() or RedRand32() are called with
a NULL seed argument.
@param ullSeed The value to use as the global RNG seed.
*/
void RedRandSeed(
uint64_t ullSeed)
{
ullGlobalRandomNumberSeed = ullSeed;
fGlobalSeedInited = true;
}
/** @brief Generate a 64-bit pseudo-random number.
The period of this random number generator is 2^64 (1.8 x 1019). These
parameters are the same as the default one-stream SPRNG lcg64 generator and
it satisfies the requirements for a maximal period.
The tempering value is used and an AND mask and is specifically selected to
favor the distribution of lower bits.
@param pullSeed A pointer to the seed to use. Set this value to NULL to
use the internal global seed value.
@return A pseudo-random number in the range [0, UINT64_MAX].
*/
uint64_t RedRand64(
uint64_t *pullSeed)
{
const uint64_t ullA = UINT64_SUFFIX(2862933555777941757);
const uint64_t ullC = UINT64_SUFFIX(3037000493);
const uint64_t ullT = UINT64_SUFFIX(4921441182957829599);
uint64_t ullN;
uint64_t *pullSeedPtr;
uint64_t ullLocalSeed;
if(pullSeed != NULL)
{
ullLocalSeed = *pullSeed;
pullSeedPtr = pullSeed;
}
else
{
if(!fGlobalSeedInited)
{
/* Unfortunately, the Reliance Edge OS services don't give us much
to work with to initialize the global seed. There is no entropy
abstraction, no tick count abstraction, and the timestamp
abstraction uses an opaque type which is not guaranteed to be an
integer. The best we can do is use the RTC.
Tests using the RNG should be supplying a seed anyway, for
reproducibility.
*/
RedRandSeed((uint64_t)RedOsClockGetTime());
}
ullLocalSeed = ullGlobalRandomNumberSeed;
pullSeedPtr = &ullGlobalRandomNumberSeed;
}
ullN = (ullLocalSeed * ullA) + ullC;
*pullSeedPtr = ullN;
/* The linear congruential generator used above produces good psuedo-random
64-bit number sequences, however, as with any LCG, the period of the
lower order bits is much shorter resulting in alternately odd/even pairs
in bit zero.
The result of the LGC above is tempered below with a series of XOR and
shift operations to produce a more acceptable equidistribution of bits
throughout the 64-bit range.
*/
ullN ^= (ullN >> 21U) & ullT;
ullN ^= (ullN >> 43U) & ullT;
ullN ^= (ullN << 23U) & ~ullT;
ullN ^= (ullN << 31U) & ~ullT;
return ullN;
}
/** @brief Generate a 32-bit pseudo-random number.
@note The 32-bit random number generator internally uses the 64-bit random
number generator, returning the low 32-bits of the pseudo-random
64-bit value.
@param pulSeed A pointer to the seed to use. Set this value to NULL to use
the internal global seed value.
@return A pseudo-random number in the range [0, UINT32_MAX].
*/
uint32_t RedRand32(
uint32_t *pulSeed)
{
uint64_t ullN;
if(pulSeed != NULL)
{
uint64_t ullLocalSeed;
ullLocalSeed = *pulSeed;
ullN = RedRand64(&ullLocalSeed);
*pulSeed = (uint32_t)ullLocalSeed;
}
else
{
ullN = RedRand64(NULL);
}
return (uint32_t)ullN;
}

View file

@ -0,0 +1,559 @@
/*
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/** @file
@brief Implementations of getopt() and getopt_long() work-alike functions.
This code was taken from FreeBSD and slightly modified, mostly to rename
symbols with external linkage to avoid naming conflicts in systems where
there are real getopt()/getopt_long() implementations, and for portability.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <redfs.h>
#include <redgetopt.h>
#include <redtestutils.h>
#include <rederrno.h>
int32_t red_opterr = 1; /* if error message should be printed */
int32_t red_optind = 1; /* index into parent argv vector */
int32_t red_optopt = '?'; /* character checked for validity */
int32_t red_optreset; /* reset RedGetopt */
const char *red_optarg; /* argument associated with option */
#define PRINT_ERROR ((red_opterr) && (*options != ':'))
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
#define FLAG_LONGONLY 0x04 /* operate as RedGetoptLongOnly */
/* return values */
#define BADCH (int)'?'
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
#define EMSG ""
#define NO_PREFIX (-1)
#define D_PREFIX 0
#define DD_PREFIX 1
#define W_PREFIX 2
static int gcd(int a, int b);
static void permute_args(int panonopt_start, int panonopt_end, int opt_end, char * const *nargv);
static int parse_long_options(char * const *nargv, const char *options, const REDOPTION *long_options, int32_t *idx, int short_too, int flags);
static int getopt_internal(int nargc, char * const *nargv, const char *options, const REDOPTION *long_options, int32_t *idx, int flags);
static const char *place = EMSG; /* option letter processing */
/* XXX: set red_optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/* Error messages */
static const char recargchar[] = "option requires an argument -- %c\n";
static const char illoptchar[] = "illegal option -- %c\n"; /* From P1003.2 */
static int dash_prefix = NO_PREFIX;
static const char gnuoptchar[] = "invalid option -- %c\n";
static const char recargstring[] = "option `%s%s' requires an argument\n";
static const char ambig[] = "option `%s%s' is ambiguous\n";
static const char noarg[] = "option `%s%s' doesn't allow an argument\n";
static const char illoptstring[] = "unrecognized option `%s%s'\n";
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(int a, int b)
{
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return (b);
}
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(int panonopt_start, int panonopt_end, int opt_end,
char * const *nargv)
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
((char **) nargv)[pos] = nargv[cstart];
((char **)nargv)[cstart] = swap;
}
}
}
/*
* parse_long_options --
* Parse long options in argc/argv argument vector.
* Returns -1 if short_too is set and the option does not match long_options.
*/
static int
parse_long_options(char * const *nargv, const char *options,
const REDOPTION *long_options, int32_t *idx, int short_too, int flags)
{
const char *current_argv, *has_equal, *current_dash;
size_t current_argv_len;
int i, match, exact_match, second_partial_match;
current_argv = place;
switch (dash_prefix) {
case D_PREFIX:
current_dash = "-";
break;
case DD_PREFIX:
current_dash = "--";
break;
case W_PREFIX:
current_dash = "-W ";
break;
default:
current_dash = "";
break;
}
match = -1;
exact_match = 0;
second_partial_match = 0;
red_optind++;
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) == current_argv_len) {
/* exact match */
match = i;
exact_match = 1;
break;
}
/*
* If this is a known short option, don't allow
* a partial match of a single character.
*/
if (short_too && current_argv_len == 1)
continue;
if (match == -1) /* first partial match */
match = i;
else if ((flags & FLAG_LONGONLY) ||
long_options[i].has_arg !=
long_options[match].has_arg ||
long_options[i].flag != long_options[match].flag ||
long_options[i].val != long_options[match].val)
second_partial_match = 1;
}
if (!exact_match && second_partial_match) {
/* ambiguous abbreviation */
if (PRINT_ERROR)
fprintf(stderr,
ambig,
current_dash,
current_argv);
red_optopt = 0;
return (BADCH);
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == red_no_argument
&& has_equal) {
if (PRINT_ERROR)
fprintf(stderr,
noarg,
current_dash,
current_argv);
/*
* XXX: GNU sets red_optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
red_optopt = long_options[match].val;
else
red_optopt = 0;
return (BADCH);
}
if (long_options[match].has_arg == red_required_argument ||
long_options[match].has_arg == red_optional_argument) {
if (has_equal)
red_optarg = has_equal;
else if (long_options[match].has_arg ==
red_required_argument) {
/*
* optional argument doesn't use next nargv
*/
red_optarg = nargv[red_optind++];
}
}
if ((long_options[match].has_arg == red_required_argument)
&& (red_optarg == NULL)) {
/*
* Missing argument; leading ':' indicates no error
* should be generated.
*/
if (PRINT_ERROR)
fprintf(stderr,
recargstring,
current_dash,
current_argv);
/*
* XXX: GNU sets red_optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
red_optopt = long_options[match].val;
else
red_optopt = 0;
--red_optind;
return (BADARG);
}
} else { /* unknown option */
if (short_too) {
--red_optind;
return (-1);
}
if (PRINT_ERROR)
fprintf(stderr,
illoptstring,
current_dash,
current_argv);
red_optopt = 0;
return (BADCH);
}
if (idx)
*idx = match;
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
return (0);
} else
return (long_options[match].val);
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
*/
static int
getopt_internal(int nargc, char * const *nargv, const char *options,
const REDOPTION *long_options, int32_t *idx, int flags)
{
char *oli; /* option letter list index */
int optchar, short_too;
if (options == NULL)
return (-1);
/*
* XXX Some GNU programs (like cvs) set red_optind to 0 instead of
* XXX using red_optreset. Work around this braindamage.
*/
if (red_optind == 0)
red_optind = red_optreset = 1;
/*
* Disable GNU extensions if options string begins with a '+'.
*/
if (*options == '-')
flags |= FLAG_ALLARGS;
else if (*options == '+')
flags &= ~FLAG_PERMUTE;
if (*options == '+' || *options == '-')
options++;
red_optarg = NULL;
if (red_optreset)
nonopt_start = nonopt_end = -1;
start:
if (red_optreset || !*place) { /* update scanning pointer */
red_optreset = 0;
if (red_optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
red_optind, nargv);
red_optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set red_optind
* to the first of them.
*/
red_optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
if (*(place = nargv[red_optind]) != '-' || place[1] == '\0') {
place = EMSG; /* found non-option */
if (flags & FLAG_ALLARGS) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
red_optarg = nargv[red_optind++];
return (INORDER);
}
if (!(flags & FLAG_PERMUTE)) {
/*
* If no permutation wanted, stop parsing
* at first non-option.
*/
return (-1);
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = red_optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
red_optind, nargv);
nonopt_start = red_optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
red_optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = red_optind;
/*
* If we have "-" do nothing, if "--" we are done.
*/
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
red_optind++;
place = EMSG;
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
red_optind, nargv);
red_optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
}
/*
* Check long options if:
* 1) we were passed some
* 2) the arg is not just "-"
* 3) either the arg starts with -- we are RedGetoptLongOnly()
*/
if (long_options != NULL && place != nargv[red_optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
dash_prefix = D_PREFIX;
if (*place == '-') {
place++; /* --foo long option */
dash_prefix = DD_PREFIX;
} else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1; /* could be short option too */
optchar = parse_long_options(nargv, options, long_options,
idx, short_too, flags);
if (optchar != -1) {
place = EMSG;
return (optchar);
}
}
if ((optchar = (int)*place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
(oli = strchr(options, optchar)) == NULL) {
/*
* If the user specified "-" and '-' isn't listed in
* options, return -1 (non-option) as per POSIX.
* Otherwise, it is an unknown option character (or ':').
*/
if (optchar == (int)'-' && *place == '\0')
return (-1);
if (!*place)
++red_optind;
if (PRINT_ERROR)
fprintf(stderr, gnuoptchar, optchar);
red_optopt = optchar;
return (BADCH);
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
/* -W long-option */
if (*place) /* no space */
/* NOTHING */;
else if (++red_optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
fprintf(stderr, recargchar, optchar);
red_optopt = optchar;
return (BADARG);
} else /* white space */
place = nargv[red_optind];
dash_prefix = W_PREFIX;
optchar = parse_long_options(nargv, options, long_options,
idx, 0, flags);
place = EMSG;
return (optchar);
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++red_optind;
} else { /* takes (optional) argument */
red_optarg = NULL;
if (*place) /* no white space */
red_optarg = place;
else if (oli[1] != ':') { /* arg not optional */
if (++red_optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
fprintf(stderr, recargchar, optchar);
red_optopt = optchar;
return (BADARG);
} else
red_optarg = nargv[red_optind];
}
place = EMSG;
++red_optind;
}
/* dump back option letter */
return (optchar);
}
/** @brief Get option character from command line argument list.
For more details, consult the getopt() man pages, since this function is
generally similar.
@param nargc Number of arguments (argc passed into main()).
@param nargv Argument vector (argv passed into main()).
@param options String of option characters.
@return The next known option character in @p options. If a character not
found in @p options is found or if an option is missing an argument,
it returns '?'. Returns -1 when the argument list is exhausted.
*/
int32_t RedGetopt(
int32_t nargc,
char * const *nargv,
const char *options)
{
return getopt_internal(nargc, nargv, options, NULL, NULL, FLAG_PERMUTE);
}
/** @brief Get long options from command line argument list.
For more details, consult the getopt_long() man pages, since this function
is generally similar.
@param nargc Number of arguments (argc passed into main()).
@param nargv Argument vector (argv passed into main()).
@param options String of option characters.
@param long_options The long options; the last element of this array must be
filled with zeroes.
@param idx If non-NULL, then populated with the index of the long
option relative to @p long_options.
@return If the flag field in REDOPTION is NULL, returns the value specified
in the val field, which is usually just the corresponding short
option. If flag is non-NULL, returns zero and stores val in the
location pointed to by flag. Returns ':' if an option was missing
its argument, '?' for an unknown option, and -1 when the argument
list is exhausted.
*/
int32_t RedGetoptLong(
int32_t nargc,
char * const *nargv,
const char *options,
const REDOPTION *long_options,
int32_t *idx)
{
return getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE);
}

View file

@ -0,0 +1,99 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements common-code utilities for tools and tests.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <redfs.h>
#include <redcoreapi.h>
#include <redvolume.h>
#include <redtoolcmn.h>
/** @brief Convert a string into a volume number.
In a POSIX-like configuration, @p pszVolume can either be a volume number or
a volume path prefix. In case of ambiguity, the volume number of a matching
path prefix takes precedence.
In an FSE configuration, @p pszVolume can be a volume number.
@param pszVolume The volume string.
@return On success, returns the volume number; on failure, returns
#REDCONF_VOLUME_COUNT.
*/
uint8_t RedFindVolumeNumber(
const char *pszVolume)
{
unsigned long ulNumber;
const char *pszEndPtr;
uint8_t bVolNum = REDCONF_VOLUME_COUNT;
#if REDCONF_API_POSIX == 1
uint8_t bIndex;
#endif
/* Determine if pszVolume can be interpreted as a volume number.
*/
errno = 0;
ulNumber = strtoul(pszVolume, (char **)&pszEndPtr, 10);
if((errno == 0) && (ulNumber != ULONG_MAX) && (pszEndPtr[0U] == '\0') && (ulNumber < REDCONF_VOLUME_COUNT))
{
bVolNum = (uint8_t)ulNumber;
}
#if REDCONF_API_POSIX == 1
/* Determine if pszVolume is a valid path prefix.
*/
for(bIndex = 0U; bIndex < REDCONF_VOLUME_COUNT; bIndex++)
{
if(strcmp(gaRedVolConf[bIndex].pszPathPrefix, pszVolume) == 0)
{
break;
}
}
if(bIndex < REDCONF_VOLUME_COUNT)
{
/* Edge case: It is technically possible for pszVolume to be both a
valid volume number and a valid volume prefix, for different
volumes. For example, if pszVolume is "2", that would be recognized
as volume number 2 above. But if "2" is the (poorly chosen) path
prefix for volume number 4, that would also be matched. Since the
POSIX-like API is primarily name based, and the ability to use
volume numbers with this tool is just a convenience, the volume
prefix takes precedence.
*/
bVolNum = bIndex;
}
#endif
return bVolNum;
}

View file

@ -0,0 +1,101 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements utilities for working with bitmaps.
*/
#include <redfs.h>
/** @brief Query the state of a bit in a bitmap.
Bits are counted from most significant to least significant. Thus, the mask
for bit zero is 0x80 applied to the first byte in the bitmap.
@param pbBitmap Pointer to the bitmap.
@param ulBit The bit to query.
@retval Whether the bit is set (true) or clear (false.
*/
bool RedBitGet(
const uint8_t *pbBitmap,
uint32_t ulBit)
{
bool fRet;
if(pbBitmap == NULL)
{
REDERROR();
fRet = false;
}
else
{
fRet = (pbBitmap[ulBit >> 3U] & (0x80U >> (ulBit & 7U))) != 0U;
}
return fRet;
}
/** @brief Set a bit in a bitmap to one.
Bits are counted from most significant to least significant. Thus, the mask
for bit zero is 0x80 applied to the first byte in the bitmap.
@param pbBitmap Pointer to the bitmap.
@param ulBit The bit to set.
*/
void RedBitSet(
uint8_t *pbBitmap,
uint32_t ulBit)
{
REDASSERT(pbBitmap != NULL);
if(pbBitmap != NULL)
{
pbBitmap[ulBit >> 3U] |= (0x80U >> (ulBit & 7U));
}
}
/** @brief Clear a bit in a bitmap to zero.
Bits are counted from most significant to least significant. Thus, the mask
for bit zero is 0x80 applied to the first byte in the bitmap.
@param pbBitmap Pointer to the bitmap.
@param ulBit The bit to clear.
*/
void RedBitClear(
uint8_t *pbBitmap,
uint32_t ulBit)
{
REDASSERT(pbBitmap != NULL);
if(pbBitmap != NULL)
{
pbBitmap[ulBit >> 3U] &= ~(0x80U >> (ulBit & 7U));
}
}

View file

@ -0,0 +1,598 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements utilities for calculating CRC-32 checksums.
*/
#include <redfs.h>
/* The CRC functions do not return errors since the only detectable error
condition is a NULL buffer pointer. If such a condition does arise, the
functions assert and return the below CRC, which, although a legal CRC,
is nonetheless suspicious and could provide a clue that something has
gone wrong.
*/
#define SUSPICIOUS_CRC_VALUE (0xBAADC0DEU)
#define CRC_BITWISE (0U)
#define CRC_SARWATE (1U)
#define CRC_SLICEBY8 (2U)
#if REDCONF_CRC_ALGORITHM == CRC_BITWISE
/* The following is representative of the polynomial accepted by CCITT 32-bit
and in IEEE 802.3, Ethernet 2 specification.
x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1
(reverse order)
1110 1101 1011 1000 1000 0011 0010 0000 1
(E) (D) (B) (8) (8) (3) (2) (0)
*/
#define CCITT_32_POLYNOMIAL (0xEDB88320U)
/** @brief Compute a CRC32 for the given data buffer.
For CCITT-32 compliance, the initial CRC must be set to 0. To CRC multiple
buffers, call this function with the previously returned CRC value.
@param ulInitCrc32 Starting CRC value.
@param pBuffer Data buffer to calculate the CRC from.
@param ulLength Number of bytes of data in the given buffer.
@return The updated CRC value.
*/
uint32_t RedCrc32Update(
uint32_t ulInitCrc32,
const void *pBuffer,
uint32_t ulLength)
{
uint32_t ulCrc32;
if(pBuffer == NULL)
{
REDERROR();
ulCrc32 = SUSPICIOUS_CRC_VALUE;
}
else
{
const uint8_t *pbBuffer = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pBuffer);
uint32_t ulIdx;
ulCrc32 = ~ulInitCrc32;
for(ulIdx = 0U; ulIdx < ulLength; ++ulIdx)
{
uint32_t ulBit;
ulCrc32 ^= pbBuffer[ulIdx];
/* Branchless inner loop (greatly improves performance).
*/
for(ulBit = 0U; ulBit < 8U; ulBit++)
{
ulCrc32 = ((ulCrc32 & 1U) * CCITT_32_POLYNOMIAL) ^ (ulCrc32 >> 1U);
}
}
ulCrc32 = ~ulCrc32;
}
return ulCrc32;
}
#elif REDCONF_CRC_ALGORITHM == CRC_SARWATE
/** @brief Compute a CRC32 for the given data buffer.
For CCITT-32 compliance, the initial CRC must be set to 0. To CRC multiple
buffers, call this function with the previously returned CRC value.
@param ulInitCrc32 Starting CRC value.
@param pBuffer Data buffer to calculate the CRC from.
@param ulLength Number of bytes of data in the given buffer.
@return The updated CRC value.
*/
uint32_t RedCrc32Update(
uint32_t ulInitCrc32,
const void *pBuffer,
uint32_t ulLength)
{
static const uint32_t aulCrc32Table[] =
{
0x00000000U, 0x77073096U, 0xEE0E612CU, 0x990951BAU, 0x076DC419U, 0x706AF48FU, 0xE963A535U, 0x9E6495A3U,
0x0EDB8832U, 0x79DCB8A4U, 0xE0D5E91EU, 0x97D2D988U, 0x09B64C2BU, 0x7EB17CBDU, 0xE7B82D07U, 0x90BF1D91U,
0x1DB71064U, 0x6AB020F2U, 0xF3B97148U, 0x84BE41DEU, 0x1ADAD47DU, 0x6DDDE4EBU, 0xF4D4B551U, 0x83D385C7U,
0x136C9856U, 0x646BA8C0U, 0xFD62F97AU, 0x8A65C9ECU, 0x14015C4FU, 0x63066CD9U, 0xFA0F3D63U, 0x8D080DF5U,
0x3B6E20C8U, 0x4C69105EU, 0xD56041E4U, 0xA2677172U, 0x3C03E4D1U, 0x4B04D447U, 0xD20D85FDU, 0xA50AB56BU,
0x35B5A8FAU, 0x42B2986CU, 0xDBBBC9D6U, 0xACBCF940U, 0x32D86CE3U, 0x45DF5C75U, 0xDCD60DCFU, 0xABD13D59U,
0x26D930ACU, 0x51DE003AU, 0xC8D75180U, 0xBFD06116U, 0x21B4F4B5U, 0x56B3C423U, 0xCFBA9599U, 0xB8BDA50FU,
0x2802B89EU, 0x5F058808U, 0xC60CD9B2U, 0xB10BE924U, 0x2F6F7C87U, 0x58684C11U, 0xC1611DABU, 0xB6662D3DU,
0x76DC4190U, 0x01DB7106U, 0x98D220BCU, 0xEFD5102AU, 0x71B18589U, 0x06B6B51FU, 0x9FBFE4A5U, 0xE8B8D433U,
0x7807C9A2U, 0x0F00F934U, 0x9609A88EU, 0xE10E9818U, 0x7F6A0DBBU, 0x086D3D2DU, 0x91646C97U, 0xE6635C01U,
0x6B6B51F4U, 0x1C6C6162U, 0x856530D8U, 0xF262004EU, 0x6C0695EDU, 0x1B01A57BU, 0x8208F4C1U, 0xF50FC457U,
0x65B0D9C6U, 0x12B7E950U, 0x8BBEB8EAU, 0xFCB9887CU, 0x62DD1DDFU, 0x15DA2D49U, 0x8CD37CF3U, 0xFBD44C65U,
0x4DB26158U, 0x3AB551CEU, 0xA3BC0074U, 0xD4BB30E2U, 0x4ADFA541U, 0x3DD895D7U, 0xA4D1C46DU, 0xD3D6F4FBU,
0x4369E96AU, 0x346ED9FCU, 0xAD678846U, 0xDA60B8D0U, 0x44042D73U, 0x33031DE5U, 0xAA0A4C5FU, 0xDD0D7CC9U,
0x5005713CU, 0x270241AAU, 0xBE0B1010U, 0xC90C2086U, 0x5768B525U, 0x206F85B3U, 0xB966D409U, 0xCE61E49FU,
0x5EDEF90EU, 0x29D9C998U, 0xB0D09822U, 0xC7D7A8B4U, 0x59B33D17U, 0x2EB40D81U, 0xB7BD5C3BU, 0xC0BA6CADU,
0xEDB88320U, 0x9ABFB3B6U, 0x03B6E20CU, 0x74B1D29AU, 0xEAD54739U, 0x9DD277AFU, 0x04DB2615U, 0x73DC1683U,
0xE3630B12U, 0x94643B84U, 0x0D6D6A3EU, 0x7A6A5AA8U, 0xE40ECF0BU, 0x9309FF9DU, 0x0A00AE27U, 0x7D079EB1U,
0xF00F9344U, 0x8708A3D2U, 0x1E01F268U, 0x6906C2FEU, 0xF762575DU, 0x806567CBU, 0x196C3671U, 0x6E6B06E7U,
0xFED41B76U, 0x89D32BE0U, 0x10DA7A5AU, 0x67DD4ACCU, 0xF9B9DF6FU, 0x8EBEEFF9U, 0x17B7BE43U, 0x60B08ED5U,
0xD6D6A3E8U, 0xA1D1937EU, 0x38D8C2C4U, 0x4FDFF252U, 0xD1BB67F1U, 0xA6BC5767U, 0x3FB506DDU, 0x48B2364BU,
0xD80D2BDAU, 0xAF0A1B4CU, 0x36034AF6U, 0x41047A60U, 0xDF60EFC3U, 0xA867DF55U, 0x316E8EEFU, 0x4669BE79U,
0xCB61B38CU, 0xBC66831AU, 0x256FD2A0U, 0x5268E236U, 0xCC0C7795U, 0xBB0B4703U, 0x220216B9U, 0x5505262FU,
0xC5BA3BBEU, 0xB2BD0B28U, 0x2BB45A92U, 0x5CB36A04U, 0xC2D7FFA7U, 0xB5D0CF31U, 0x2CD99E8BU, 0x5BDEAE1DU,
0x9B64C2B0U, 0xEC63F226U, 0x756AA39CU, 0x026D930AU, 0x9C0906A9U, 0xEB0E363FU, 0x72076785U, 0x05005713U,
0x95BF4A82U, 0xE2B87A14U, 0x7BB12BAEU, 0x0CB61B38U, 0x92D28E9BU, 0xE5D5BE0DU, 0x7CDCEFB7U, 0x0BDBDF21U,
0x86D3D2D4U, 0xF1D4E242U, 0x68DDB3F8U, 0x1FDA836EU, 0x81BE16CDU, 0xF6B9265BU, 0x6FB077E1U, 0x18B74777U,
0x88085AE6U, 0xFF0F6A70U, 0x66063BCAU, 0x11010B5CU, 0x8F659EFFU, 0xF862AE69U, 0x616BFFD3U, 0x166CCF45U,
0xA00AE278U, 0xD70DD2EEU, 0x4E048354U, 0x3903B3C2U, 0xA7672661U, 0xD06016F7U, 0x4969474DU, 0x3E6E77DBU,
0xAED16A4AU, 0xD9D65ADCU, 0x40DF0B66U, 0x37D83BF0U, 0xA9BCAE53U, 0xDEBB9EC5U, 0x47B2CF7FU, 0x30B5FFE9U,
0xBDBDF21CU, 0xCABAC28AU, 0x53B39330U, 0x24B4A3A6U, 0xBAD03605U, 0xCDD70693U, 0x54DE5729U, 0x23D967BFU,
0xB3667A2EU, 0xC4614AB8U, 0x5D681B02U, 0x2A6F2B94U, 0xB40BBE37U, 0xC30C8EA1U, 0x5A05DF1BU, 0x2D02EF8DU,
};
uint32_t ulCrc32;
if(pBuffer == NULL)
{
REDERROR();
ulCrc32 = SUSPICIOUS_CRC_VALUE;
}
else
{
const uint8_t *pbBuffer = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pBuffer);
uint32_t ulIdx;
ulCrc32 = ~ulInitCrc32;
for(ulIdx = 0U; ulIdx < ulLength; ++ulIdx)
{
ulCrc32 = (ulCrc32 >> 8U) ^ aulCrc32Table[(ulCrc32 ^ pbBuffer[ulIdx]) & 0xFFU];
}
ulCrc32 = ~ulCrc32;
}
return ulCrc32;
}
#elif REDCONF_CRC_ALGORITHM == CRC_SLICEBY8
/** @brief Compute a CRC32 for the given data buffer.
For CCITT-32 compliance, the initial CRC must be set to 0. To CRC multiple
buffers, call this function with the previously returned CRC value.
@param ulInitCrc32 Starting CRC value.
@param pBuffer Data buffer to calculate the CRC from.
@param ulLength Number of bytes of data in the given buffer.
@return The updated CRC value.
*/
uint32_t RedCrc32Update(
uint32_t ulInitCrc32,
const void *pBuffer,
uint32_t ulLength)
{
/* CRC32 XOR table, with slicing-by-8 extensions.
This first column of the table contains the same XOR values as used in
the classic byte-at-a-time Sarwate algorithm. The other seven columns
are derived from the first, and are used in Intel's slicing-by-eight CRC
algorithm.
The layout of this array in memory is novel and deserves explanation.
In other implementations, including Intel's example, each of the below
columns is an array. The first column is a 256-entry array, followed by
another 256-entry array for the second column, etc. Testing on both ARM
and x86 has shown the below mixed arrangement to be about 5-9% faster.
One possible explanation: With the array-per-table approach, each of the
eight table lookups is guaranteed to be in a separate 1 KB chunk of
memory. With the below array, sometimes multiple table lookups will, by
coincidence, be close together, making better use of the cache.
*/
static const uint32_t aulCrc32Table[] =
{
0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
0x77073096U, 0x191B3141U, 0x01C26A37U, 0xB8BC6765U, 0x3D6029B0U, 0xCB5CD3A5U, 0xA6770BB4U, 0xCCAA009EU,
0xEE0E612CU, 0x32366282U, 0x0384D46EU, 0xAA09C88BU, 0x7AC05360U, 0x4DC8A10BU, 0x979F1129U, 0x4225077DU,
0x990951BAU, 0x2B2D53C3U, 0x0246BE59U, 0x12B5AFEEU, 0x47A07AD0U, 0x869472AEU, 0x31E81A9DU, 0x8E8F07E3U,
0x076DC419U, 0x646CC504U, 0x0709A8DCU, 0x8F629757U, 0xF580A6C0U, 0x9B914216U, 0xF44F2413U, 0x844A0EFAU,
0x706AF48FU, 0x7D77F445U, 0x06CBC2EBU, 0x37DEF032U, 0xC8E08F70U, 0x50CD91B3U, 0x52382FA7U, 0x48E00E64U,
0xE963A535U, 0x565AA786U, 0x048D7CB2U, 0x256B5FDCU, 0x8F40F5A0U, 0xD659E31DU, 0x63D0353AU, 0xC66F0987U,
0x9E6495A3U, 0x4F4196C7U, 0x054F1685U, 0x9DD738B9U, 0xB220DC10U, 0x1D0530B8U, 0xC5A73E8EU, 0x0AC50919U,
0x0EDB8832U, 0xC8D98A08U, 0x0E1351B8U, 0xC5B428EFU, 0x30704BC1U, 0xEC53826DU, 0x33EF4E67U, 0xD3E51BB5U,
0x79DCB8A4U, 0xD1C2BB49U, 0x0FD13B8FU, 0x7D084F8AU, 0x0D106271U, 0x270F51C8U, 0x959845D3U, 0x1F4F1B2BU,
0xE0D5E91EU, 0xFAEFE88AU, 0x0D9785D6U, 0x6FBDE064U, 0x4AB018A1U, 0xA19B2366U, 0xA4705F4EU, 0x91C01CC8U,
0x97D2D988U, 0xE3F4D9CBU, 0x0C55EFE1U, 0xD7018701U, 0x77D03111U, 0x6AC7F0C3U, 0x020754FAU, 0x5D6A1C56U,
0x09B64C2BU, 0xACB54F0CU, 0x091AF964U, 0x4AD6BFB8U, 0xC5F0ED01U, 0x77C2C07BU, 0xC7A06A74U, 0x57AF154FU,
0x7EB17CBDU, 0xB5AE7E4DU, 0x08D89353U, 0xF26AD8DDU, 0xF890C4B1U, 0xBC9E13DEU, 0x61D761C0U, 0x9B0515D1U,
0xE7B82D07U, 0x9E832D8EU, 0x0A9E2D0AU, 0xE0DF7733U, 0xBF30BE61U, 0x3A0A6170U, 0x503F7B5DU, 0x158A1232U,
0x90BF1D91U, 0x87981CCFU, 0x0B5C473DU, 0x58631056U, 0x825097D1U, 0xF156B2D5U, 0xF64870E9U, 0xD92012ACU,
0x1DB71064U, 0x4AC21251U, 0x1C26A370U, 0x5019579FU, 0x60E09782U, 0x03D6029BU, 0x67DE9CCEU, 0x7CBB312BU,
0x6AB020F2U, 0x53D92310U, 0x1DE4C947U, 0xE8A530FAU, 0x5D80BE32U, 0xC88AD13EU, 0xC1A9977AU, 0xB01131B5U,
0xF3B97148U, 0x78F470D3U, 0x1FA2771EU, 0xFA109F14U, 0x1A20C4E2U, 0x4E1EA390U, 0xF0418DE7U, 0x3E9E3656U,
0x84BE41DEU, 0x61EF4192U, 0x1E601D29U, 0x42ACF871U, 0x2740ED52U, 0x85427035U, 0x56368653U, 0xF23436C8U,
0x1ADAD47DU, 0x2EAED755U, 0x1B2F0BACU, 0xDF7BC0C8U, 0x95603142U, 0x9847408DU, 0x9391B8DDU, 0xF8F13FD1U,
0x6DDDE4EBU, 0x37B5E614U, 0x1AED619BU, 0x67C7A7ADU, 0xA80018F2U, 0x531B9328U, 0x35E6B369U, 0x345B3F4FU,
0xF4D4B551U, 0x1C98B5D7U, 0x18ABDFC2U, 0x75720843U, 0xEFA06222U, 0xD58FE186U, 0x040EA9F4U, 0xBAD438ACU,
0x83D385C7U, 0x05838496U, 0x1969B5F5U, 0xCDCE6F26U, 0xD2C04B92U, 0x1ED33223U, 0xA279A240U, 0x767E3832U,
0x136C9856U, 0x821B9859U, 0x1235F2C8U, 0x95AD7F70U, 0x5090DC43U, 0xEF8580F6U, 0x5431D2A9U, 0xAF5E2A9EU,
0x646BA8C0U, 0x9B00A918U, 0x13F798FFU, 0x2D111815U, 0x6DF0F5F3U, 0x24D95353U, 0xF246D91DU, 0x63F42A00U,
0xFD62F97AU, 0xB02DFADBU, 0x11B126A6U, 0x3FA4B7FBU, 0x2A508F23U, 0xA24D21FDU, 0xC3AEC380U, 0xED7B2DE3U,
0x8A65C9ECU, 0xA936CB9AU, 0x10734C91U, 0x8718D09EU, 0x1730A693U, 0x6911F258U, 0x65D9C834U, 0x21D12D7DU,
0x14015C4FU, 0xE6775D5DU, 0x153C5A14U, 0x1ACFE827U, 0xA5107A83U, 0x7414C2E0U, 0xA07EF6BAU, 0x2B142464U,
0x63066CD9U, 0xFF6C6C1CU, 0x14FE3023U, 0xA2738F42U, 0x98705333U, 0xBF481145U, 0x0609FD0EU, 0xE7BE24FAU,
0xFA0F3D63U, 0xD4413FDFU, 0x16B88E7AU, 0xB0C620ACU, 0xDFD029E3U, 0x39DC63EBU, 0x37E1E793U, 0x69312319U,
0x8D080DF5U, 0xCD5A0E9EU, 0x177AE44DU, 0x087A47C9U, 0xE2B00053U, 0xF280B04EU, 0x9196EC27U, 0xA59B2387U,
0x3B6E20C8U, 0x958424A2U, 0x384D46E0U, 0xA032AF3EU, 0xC1C12F04U, 0x07AC0536U, 0xCFBD399CU, 0xF9766256U,
0x4C69105EU, 0x8C9F15E3U, 0x398F2CD7U, 0x188EC85BU, 0xFCA106B4U, 0xCCF0D693U, 0x69CA3228U, 0x35DC62C8U,
0xD56041E4U, 0xA7B24620U, 0x3BC9928EU, 0x0A3B67B5U, 0xBB017C64U, 0x4A64A43DU, 0x582228B5U, 0xBB53652BU,
0xA2677172U, 0xBEA97761U, 0x3A0BF8B9U, 0xB28700D0U, 0x866155D4U, 0x81387798U, 0xFE552301U, 0x77F965B5U,
0x3C03E4D1U, 0xF1E8E1A6U, 0x3F44EE3CU, 0x2F503869U, 0x344189C4U, 0x9C3D4720U, 0x3BF21D8FU, 0x7D3C6CACU,
0x4B04D447U, 0xE8F3D0E7U, 0x3E86840BU, 0x97EC5F0CU, 0x0921A074U, 0x57619485U, 0x9D85163BU, 0xB1966C32U,
0xD20D85FDU, 0xC3DE8324U, 0x3CC03A52U, 0x8559F0E2U, 0x4E81DAA4U, 0xD1F5E62BU, 0xAC6D0CA6U, 0x3F196BD1U,
0xA50AB56BU, 0xDAC5B265U, 0x3D025065U, 0x3DE59787U, 0x73E1F314U, 0x1AA9358EU, 0x0A1A0712U, 0xF3B36B4FU,
0x35B5A8FAU, 0x5D5DAEAAU, 0x365E1758U, 0x658687D1U, 0xF1B164C5U, 0xEBFF875BU, 0xFC5277FBU, 0x2A9379E3U,
0x42B2986CU, 0x44469FEBU, 0x379C7D6FU, 0xDD3AE0B4U, 0xCCD14D75U, 0x20A354FEU, 0x5A257C4FU, 0xE639797DU,
0xDBBBC9D6U, 0x6F6BCC28U, 0x35DAC336U, 0xCF8F4F5AU, 0x8B7137A5U, 0xA6372650U, 0x6BCD66D2U, 0x68B67E9EU,
0xACBCF940U, 0x7670FD69U, 0x3418A901U, 0x7733283FU, 0xB6111E15U, 0x6D6BF5F5U, 0xCDBA6D66U, 0xA41C7E00U,
0x32D86CE3U, 0x39316BAEU, 0x3157BF84U, 0xEAE41086U, 0x0431C205U, 0x706EC54DU, 0x081D53E8U, 0xAED97719U,
0x45DF5C75U, 0x202A5AEFU, 0x3095D5B3U, 0x525877E3U, 0x3951EBB5U, 0xBB3216E8U, 0xAE6A585CU, 0x62737787U,
0xDCD60DCFU, 0x0B07092CU, 0x32D36BEAU, 0x40EDD80DU, 0x7EF19165U, 0x3DA66446U, 0x9F8242C1U, 0xECFC7064U,
0xABD13D59U, 0x121C386DU, 0x331101DDU, 0xF851BF68U, 0x4391B8D5U, 0xF6FAB7E3U, 0x39F54975U, 0x205670FAU,
0x26D930ACU, 0xDF4636F3U, 0x246BE590U, 0xF02BF8A1U, 0xA121B886U, 0x047A07ADU, 0xA863A552U, 0x85CD537DU,
0x51DE003AU, 0xC65D07B2U, 0x25A98FA7U, 0x48979FC4U, 0x9C419136U, 0xCF26D408U, 0x0E14AEE6U, 0x496753E3U,
0xC8D75180U, 0xED705471U, 0x27EF31FEU, 0x5A22302AU, 0xDBE1EBE6U, 0x49B2A6A6U, 0x3FFCB47BU, 0xC7E85400U,
0xBFD06116U, 0xF46B6530U, 0x262D5BC9U, 0xE29E574FU, 0xE681C256U, 0x82EE7503U, 0x998BBFCFU, 0x0B42549EU,
0x21B4F4B5U, 0xBB2AF3F7U, 0x23624D4CU, 0x7F496FF6U, 0x54A11E46U, 0x9FEB45BBU, 0x5C2C8141U, 0x01875D87U,
0x56B3C423U, 0xA231C2B6U, 0x22A0277BU, 0xC7F50893U, 0x69C137F6U, 0x54B7961EU, 0xFA5B8AF5U, 0xCD2D5D19U,
0xCFBA9599U, 0x891C9175U, 0x20E69922U, 0xD540A77DU, 0x2E614D26U, 0xD223E4B0U, 0xCBB39068U, 0x43A25AFAU,
0xB8BDA50FU, 0x9007A034U, 0x2124F315U, 0x6DFCC018U, 0x13016496U, 0x197F3715U, 0x6DC49BDCU, 0x8F085A64U,
0x2802B89EU, 0x179FBCFBU, 0x2A78B428U, 0x359FD04EU, 0x9151F347U, 0xE82985C0U, 0x9B8CEB35U, 0x562848C8U,
0x5F058808U, 0x0E848DBAU, 0x2BBADE1FU, 0x8D23B72BU, 0xAC31DAF7U, 0x23755665U, 0x3DFBE081U, 0x9A824856U,
0xC60CD9B2U, 0x25A9DE79U, 0x29FC6046U, 0x9F9618C5U, 0xEB91A027U, 0xA5E124CBU, 0x0C13FA1CU, 0x140D4FB5U,
0xB10BE924U, 0x3CB2EF38U, 0x283E0A71U, 0x272A7FA0U, 0xD6F18997U, 0x6EBDF76EU, 0xAA64F1A8U, 0xD8A74F2BU,
0x2F6F7C87U, 0x73F379FFU, 0x2D711CF4U, 0xBAFD4719U, 0x64D15587U, 0x73B8C7D6U, 0x6FC3CF26U, 0xD2624632U,
0x58684C11U, 0x6AE848BEU, 0x2CB376C3U, 0x0241207CU, 0x59B17C37U, 0xB8E41473U, 0xC9B4C492U, 0x1EC846ACU,
0xC1611DABU, 0x41C51B7DU, 0x2EF5C89AU, 0x10F48F92U, 0x1E1106E7U, 0x3E7066DDU, 0xF85CDE0FU, 0x9047414FU,
0xB6662D3DU, 0x58DE2A3CU, 0x2F37A2ADU, 0xA848E8F7U, 0x23712F57U, 0xF52CB578U, 0x5E2BD5BBU, 0x5CED41D1U,
0x76DC4190U, 0xF0794F05U, 0x709A8DC0U, 0x9B14583DU, 0x58F35849U, 0x0F580A6CU, 0x440B7579U, 0x299DC2EDU,
0x01DB7106U, 0xE9627E44U, 0x7158E7F7U, 0x23A83F58U, 0x659371F9U, 0xC404D9C9U, 0xE27C7ECDU, 0xE537C273U,
0x98D220BCU, 0xC24F2D87U, 0x731E59AEU, 0x311D90B6U, 0x22330B29U, 0x4290AB67U, 0xD3946450U, 0x6BB8C590U,
0xEFD5102AU, 0xDB541CC6U, 0x72DC3399U, 0x89A1F7D3U, 0x1F532299U, 0x89CC78C2U, 0x75E36FE4U, 0xA712C50EU,
0x71B18589U, 0x94158A01U, 0x7793251CU, 0x1476CF6AU, 0xAD73FE89U, 0x94C9487AU, 0xB044516AU, 0xADD7CC17U,
0x06B6B51FU, 0x8D0EBB40U, 0x76514F2BU, 0xACCAA80FU, 0x9013D739U, 0x5F959BDFU, 0x16335ADEU, 0x617DCC89U,
0x9FBFE4A5U, 0xA623E883U, 0x7417F172U, 0xBE7F07E1U, 0xD7B3ADE9U, 0xD901E971U, 0x27DB4043U, 0xEFF2CB6AU,
0xE8B8D433U, 0xBF38D9C2U, 0x75D59B45U, 0x06C36084U, 0xEAD38459U, 0x125D3AD4U, 0x81AC4BF7U, 0x2358CBF4U,
0x7807C9A2U, 0x38A0C50DU, 0x7E89DC78U, 0x5EA070D2U, 0x68831388U, 0xE30B8801U, 0x77E43B1EU, 0xFA78D958U,
0x0F00F934U, 0x21BBF44CU, 0x7F4BB64FU, 0xE61C17B7U, 0x55E33A38U, 0x28575BA4U, 0xD19330AAU, 0x36D2D9C6U,
0x9609A88EU, 0x0A96A78FU, 0x7D0D0816U, 0xF4A9B859U, 0x124340E8U, 0xAEC3290AU, 0xE07B2A37U, 0xB85DDE25U,
0xE10E9818U, 0x138D96CEU, 0x7CCF6221U, 0x4C15DF3CU, 0x2F236958U, 0x659FFAAFU, 0x460C2183U, 0x74F7DEBBU,
0x7F6A0DBBU, 0x5CCC0009U, 0x798074A4U, 0xD1C2E785U, 0x9D03B548U, 0x789ACA17U, 0x83AB1F0DU, 0x7E32D7A2U,
0x086D3D2DU, 0x45D73148U, 0x78421E93U, 0x697E80E0U, 0xA0639CF8U, 0xB3C619B2U, 0x25DC14B9U, 0xB298D73CU,
0x91646C97U, 0x6EFA628BU, 0x7A04A0CAU, 0x7BCB2F0EU, 0xE7C3E628U, 0x35526B1CU, 0x14340E24U, 0x3C17D0DFU,
0xE6635C01U, 0x77E153CAU, 0x7BC6CAFDU, 0xC377486BU, 0xDAA3CF98U, 0xFE0EB8B9U, 0xB2430590U, 0xF0BDD041U,
0x6B6B51F4U, 0xBABB5D54U, 0x6CBC2EB0U, 0xCB0D0FA2U, 0x3813CFCBU, 0x0C8E08F7U, 0x23D5E9B7U, 0x5526F3C6U,
0x1C6C6162U, 0xA3A06C15U, 0x6D7E4487U, 0x73B168C7U, 0x0573E67BU, 0xC7D2DB52U, 0x85A2E203U, 0x998CF358U,
0x856530D8U, 0x888D3FD6U, 0x6F38FADEU, 0x6104C729U, 0x42D39CABU, 0x4146A9FCU, 0xB44AF89EU, 0x1703F4BBU,
0xF262004EU, 0x91960E97U, 0x6EFA90E9U, 0xD9B8A04CU, 0x7FB3B51BU, 0x8A1A7A59U, 0x123DF32AU, 0xDBA9F425U,
0x6C0695EDU, 0xDED79850U, 0x6BB5866CU, 0x446F98F5U, 0xCD93690BU, 0x971F4AE1U, 0xD79ACDA4U, 0xD16CFD3CU,
0x1B01A57BU, 0xC7CCA911U, 0x6A77EC5BU, 0xFCD3FF90U, 0xF0F340BBU, 0x5C439944U, 0x71EDC610U, 0x1DC6FDA2U,
0x8208F4C1U, 0xECE1FAD2U, 0x68315202U, 0xEE66507EU, 0xB7533A6BU, 0xDAD7EBEAU, 0x4005DC8DU, 0x9349FA41U,
0xF50FC457U, 0xF5FACB93U, 0x69F33835U, 0x56DA371BU, 0x8A3313DBU, 0x118B384FU, 0xE672D739U, 0x5FE3FADFU,
0x65B0D9C6U, 0x7262D75CU, 0x62AF7F08U, 0x0EB9274DU, 0x0863840AU, 0xE0DD8A9AU, 0x103AA7D0U, 0x86C3E873U,
0x12B7E950U, 0x6B79E61DU, 0x636D153FU, 0xB6054028U, 0x3503ADBAU, 0x2B81593FU, 0xB64DAC64U, 0x4A69E8EDU,
0x8BBEB8EAU, 0x4054B5DEU, 0x612BAB66U, 0xA4B0EFC6U, 0x72A3D76AU, 0xAD152B91U, 0x87A5B6F9U, 0xC4E6EF0EU,
0xFCB9887CU, 0x594F849FU, 0x60E9C151U, 0x1C0C88A3U, 0x4FC3FEDAU, 0x6649F834U, 0x21D2BD4DU, 0x084CEF90U,
0x62DD1DDFU, 0x160E1258U, 0x65A6D7D4U, 0x81DBB01AU, 0xFDE322CAU, 0x7B4CC88CU, 0xE47583C3U, 0x0289E689U,
0x15DA2D49U, 0x0F152319U, 0x6464BDE3U, 0x3967D77FU, 0xC0830B7AU, 0xB0101B29U, 0x42028877U, 0xCE23E617U,
0x8CD37CF3U, 0x243870DAU, 0x662203BAU, 0x2BD27891U, 0x872371AAU, 0x36846987U, 0x73EA92EAU, 0x40ACE1F4U,
0xFBD44C65U, 0x3D23419BU, 0x67E0698DU, 0x936E1FF4U, 0xBA43581AU, 0xFDD8BA22U, 0xD59D995EU, 0x8C06E16AU,
0x4DB26158U, 0x65FD6BA7U, 0x48D7CB20U, 0x3B26F703U, 0x9932774DU, 0x08F40F5AU, 0x8BB64CE5U, 0xD0EBA0BBU,
0x3AB551CEU, 0x7CE65AE6U, 0x4915A117U, 0x839A9066U, 0xA4525EFDU, 0xC3A8DCFFU, 0x2DC14751U, 0x1C41A025U,
0xA3BC0074U, 0x57CB0925U, 0x4B531F4EU, 0x912F3F88U, 0xE3F2242DU, 0x453CAE51U, 0x1C295DCCU, 0x92CEA7C6U,
0xD4BB30E2U, 0x4ED03864U, 0x4A917579U, 0x299358EDU, 0xDE920D9DU, 0x8E607DF4U, 0xBA5E5678U, 0x5E64A758U,
0x4ADFA541U, 0x0191AEA3U, 0x4FDE63FCU, 0xB4446054U, 0x6CB2D18DU, 0x93654D4CU, 0x7FF968F6U, 0x54A1AE41U,
0x3DD895D7U, 0x188A9FE2U, 0x4E1C09CBU, 0x0CF80731U, 0x51D2F83DU, 0x58399EE9U, 0xD98E6342U, 0x980BAEDFU,
0xA4D1C46DU, 0x33A7CC21U, 0x4C5AB792U, 0x1E4DA8DFU, 0x167282EDU, 0xDEADEC47U, 0xE86679DFU, 0x1684A93CU,
0xD3D6F4FBU, 0x2ABCFD60U, 0x4D98DDA5U, 0xA6F1CFBAU, 0x2B12AB5DU, 0x15F13FE2U, 0x4E11726BU, 0xDA2EA9A2U,
0x4369E96AU, 0xAD24E1AFU, 0x46C49A98U, 0xFE92DFECU, 0xA9423C8CU, 0xE4A78D37U, 0xB8590282U, 0x030EBB0EU,
0x346ED9FCU, 0xB43FD0EEU, 0x4706F0AFU, 0x462EB889U, 0x9422153CU, 0x2FFB5E92U, 0x1E2E0936U, 0xCFA4BB90U,
0xAD678846U, 0x9F12832DU, 0x45404EF6U, 0x549B1767U, 0xD3826FECU, 0xA96F2C3CU, 0x2FC613ABU, 0x412BBC73U,
0xDA60B8D0U, 0x8609B26CU, 0x448224C1U, 0xEC277002U, 0xEEE2465CU, 0x6233FF99U, 0x89B1181FU, 0x8D81BCEDU,
0x44042D73U, 0xC94824ABU, 0x41CD3244U, 0x71F048BBU, 0x5CC29A4CU, 0x7F36CF21U, 0x4C162691U, 0x8744B5F4U,
0x33031DE5U, 0xD05315EAU, 0x400F5873U, 0xC94C2FDEU, 0x61A2B3FCU, 0xB46A1C84U, 0xEA612D25U, 0x4BEEB56AU,
0xAA0A4C5FU, 0xFB7E4629U, 0x4249E62AU, 0xDBF98030U, 0x2602C92CU, 0x32FE6E2AU, 0xDB8937B8U, 0xC561B289U,
0xDD0D7CC9U, 0xE2657768U, 0x438B8C1DU, 0x6345E755U, 0x1B62E09CU, 0xF9A2BD8FU, 0x7DFE3C0CU, 0x09CBB217U,
0x5005713CU, 0x2F3F79F6U, 0x54F16850U, 0x6B3FA09CU, 0xF9D2E0CFU, 0x0B220DC1U, 0xEC68D02BU, 0xAC509190U,
0x270241AAU, 0x362448B7U, 0x55330267U, 0xD383C7F9U, 0xC4B2C97FU, 0xC07EDE64U, 0x4A1FDB9FU, 0x60FA910EU,
0xBE0B1010U, 0x1D091B74U, 0x5775BC3EU, 0xC1366817U, 0x8312B3AFU, 0x46EAACCAU, 0x7BF7C102U, 0xEE7596EDU,
0xC90C2086U, 0x04122A35U, 0x56B7D609U, 0x798A0F72U, 0xBE729A1FU, 0x8DB67F6FU, 0xDD80CAB6U, 0x22DF9673U,
0x5768B525U, 0x4B53BCF2U, 0x53F8C08CU, 0xE45D37CBU, 0x0C52460FU, 0x90B34FD7U, 0x1827F438U, 0x281A9F6AU,
0x206F85B3U, 0x52488DB3U, 0x523AAABBU, 0x5CE150AEU, 0x31326FBFU, 0x5BEF9C72U, 0xBE50FF8CU, 0xE4B09FF4U,
0xB966D409U, 0x7965DE70U, 0x507C14E2U, 0x4E54FF40U, 0x7692156FU, 0xDD7BEEDCU, 0x8FB8E511U, 0x6A3F9817U,
0xCE61E49FU, 0x607EEF31U, 0x51BE7ED5U, 0xF6E89825U, 0x4BF23CDFU, 0x16273D79U, 0x29CFEEA5U, 0xA6959889U,
0x5EDEF90EU, 0xE7E6F3FEU, 0x5AE239E8U, 0xAE8B8873U, 0xC9A2AB0EU, 0xE7718FACU, 0xDF879E4CU, 0x7FB58A25U,
0x29D9C998U, 0xFEFDC2BFU, 0x5B2053DFU, 0x1637EF16U, 0xF4C282BEU, 0x2C2D5C09U, 0x79F095F8U, 0xB31F8ABBU,
0xB0D09822U, 0xD5D0917CU, 0x5966ED86U, 0x048240F8U, 0xB362F86EU, 0xAAB92EA7U, 0x48188F65U, 0x3D908D58U,
0xC7D7A8B4U, 0xCCCBA03DU, 0x58A487B1U, 0xBC3E279DU, 0x8E02D1DEU, 0x61E5FD02U, 0xEE6F84D1U, 0xF13A8DC6U,
0x59B33D17U, 0x838A36FAU, 0x5DEB9134U, 0x21E91F24U, 0x3C220DCEU, 0x7CE0CDBAU, 0x2BC8BA5FU, 0xFBFF84DFU,
0x2EB40D81U, 0x9A9107BBU, 0x5C29FB03U, 0x99557841U, 0x0142247EU, 0xB7BC1E1FU, 0x8DBFB1EBU, 0x37558441U,
0xB7BD5C3BU, 0xB1BC5478U, 0x5E6F455AU, 0x8BE0D7AFU, 0x46E25EAEU, 0x31286CB1U, 0xBC57AB76U, 0xB9DA83A2U,
0xC0BA6CADU, 0xA8A76539U, 0x5FAD2F6DU, 0x335CB0CAU, 0x7B82771EU, 0xFA74BF14U, 0x1A20A0C2U, 0x7570833CU,
0xEDB88320U, 0x3B83984BU, 0xE1351B80U, 0xED59B63BU, 0xB1E6B092U, 0x1EB014D8U, 0x8816EAF2U, 0x533B85DAU,
0x9ABFB3B6U, 0x2298A90AU, 0xE0F771B7U, 0x55E5D15EU, 0x8C869922U, 0xD5ECC77DU, 0x2E61E146U, 0x9F918544U,
0x03B6E20CU, 0x09B5FAC9U, 0xE2B1CFEEU, 0x47507EB0U, 0xCB26E3F2U, 0x5378B5D3U, 0x1F89FBDBU, 0x111E82A7U,
0x74B1D29AU, 0x10AECB88U, 0xE373A5D9U, 0xFFEC19D5U, 0xF646CA42U, 0x98246676U, 0xB9FEF06FU, 0xDDB48239U,
0xEAD54739U, 0x5FEF5D4FU, 0xE63CB35CU, 0x623B216CU, 0x44661652U, 0x852156CEU, 0x7C59CEE1U, 0xD7718B20U,
0x9DD277AFU, 0x46F46C0EU, 0xE7FED96BU, 0xDA874609U, 0x79063FE2U, 0x4E7D856BU, 0xDA2EC555U, 0x1BDB8BBEU,
0x04DB2615U, 0x6DD93FCDU, 0xE5B86732U, 0xC832E9E7U, 0x3EA64532U, 0xC8E9F7C5U, 0xEBC6DFC8U, 0x95548C5DU,
0x73DC1683U, 0x74C20E8CU, 0xE47A0D05U, 0x708E8E82U, 0x03C66C82U, 0x03B52460U, 0x4DB1D47CU, 0x59FE8CC3U,
0xE3630B12U, 0xF35A1243U, 0xEF264A38U, 0x28ED9ED4U, 0x8196FB53U, 0xF2E396B5U, 0xBBF9A495U, 0x80DE9E6FU,
0x94643B84U, 0xEA412302U, 0xEEE4200FU, 0x9051F9B1U, 0xBCF6D2E3U, 0x39BF4510U, 0x1D8EAF21U, 0x4C749EF1U,
0x0D6D6A3EU, 0xC16C70C1U, 0xECA29E56U, 0x82E4565FU, 0xFB56A833U, 0xBF2B37BEU, 0x2C66B5BCU, 0xC2FB9912U,
0x7A6A5AA8U, 0xD8774180U, 0xED60F461U, 0x3A58313AU, 0xC6368183U, 0x7477E41BU, 0x8A11BE08U, 0x0E51998CU,
0xE40ECF0BU, 0x9736D747U, 0xE82FE2E4U, 0xA78F0983U, 0x74165D93U, 0x6972D4A3U, 0x4FB68086U, 0x04949095U,
0x9309FF9DU, 0x8E2DE606U, 0xE9ED88D3U, 0x1F336EE6U, 0x49767423U, 0xA22E0706U, 0xE9C18B32U, 0xC83E900BU,
0x0A00AE27U, 0xA500B5C5U, 0xEBAB368AU, 0x0D86C108U, 0x0ED60EF3U, 0x24BA75A8U, 0xD82991AFU, 0x46B197E8U,
0x7D079EB1U, 0xBC1B8484U, 0xEA695CBDU, 0xB53AA66DU, 0x33B62743U, 0xEFE6A60DU, 0x7E5E9A1BU, 0x8A1B9776U,
0xF00F9344U, 0x71418A1AU, 0xFD13B8F0U, 0xBD40E1A4U, 0xD1062710U, 0x1D661643U, 0xEFC8763CU, 0x2F80B4F1U,
0x8708A3D2U, 0x685ABB5BU, 0xFCD1D2C7U, 0x05FC86C1U, 0xEC660EA0U, 0xD63AC5E6U, 0x49BF7D88U, 0xE32AB46FU,
0x1E01F268U, 0x4377E898U, 0xFE976C9EU, 0x1749292FU, 0xABC67470U, 0x50AEB748U, 0x78576715U, 0x6DA5B38CU,
0x6906C2FEU, 0x5A6CD9D9U, 0xFF5506A9U, 0xAFF54E4AU, 0x96A65DC0U, 0x9BF264EDU, 0xDE206CA1U, 0xA10FB312U,
0xF762575DU, 0x152D4F1EU, 0xFA1A102CU, 0x322276F3U, 0x248681D0U, 0x86F75455U, 0x1B87522FU, 0xABCABA0BU,
0x806567CBU, 0x0C367E5FU, 0xFBD87A1BU, 0x8A9E1196U, 0x19E6A860U, 0x4DAB87F0U, 0xBDF0599BU, 0x6760BA95U,
0x196C3671U, 0x271B2D9CU, 0xF99EC442U, 0x982BBE78U, 0x5E46D2B0U, 0xCB3FF55EU, 0x8C184306U, 0xE9EFBD76U,
0x6E6B06E7U, 0x3E001CDDU, 0xF85CAE75U, 0x2097D91DU, 0x6326FB00U, 0x006326FBU, 0x2A6F48B2U, 0x2545BDE8U,
0xFED41B76U, 0xB9980012U, 0xF300E948U, 0x78F4C94BU, 0xE1766CD1U, 0xF135942EU, 0xDC27385BU, 0xFC65AF44U,
0x89D32BE0U, 0xA0833153U, 0xF2C2837FU, 0xC048AE2EU, 0xDC164561U, 0x3A69478BU, 0x7A5033EFU, 0x30CFAFDAU,
0x10DA7A5AU, 0x8BAE6290U, 0xF0843D26U, 0xD2FD01C0U, 0x9BB63FB1U, 0xBCFD3525U, 0x4BB82972U, 0xBE40A839U,
0x67DD4ACCU, 0x92B553D1U, 0xF1465711U, 0x6A4166A5U, 0xA6D61601U, 0x77A1E680U, 0xEDCF22C6U, 0x72EAA8A7U,
0xF9B9DF6FU, 0xDDF4C516U, 0xF4094194U, 0xF7965E1CU, 0x14F6CA11U, 0x6AA4D638U, 0x28681C48U, 0x782FA1BEU,
0x8EBEEFF9U, 0xC4EFF457U, 0xF5CB2BA3U, 0x4F2A3979U, 0x2996E3A1U, 0xA1F8059DU, 0x8E1F17FCU, 0xB485A120U,
0x17B7BE43U, 0xEFC2A794U, 0xF78D95FAU, 0x5D9F9697U, 0x6E369971U, 0x276C7733U, 0xBFF70D61U, 0x3A0AA6C3U,
0x60B08ED5U, 0xF6D996D5U, 0xF64FFFCDU, 0xE523F1F2U, 0x5356B0C1U, 0xEC30A496U, 0x198006D5U, 0xF6A0A65DU,
0xD6D6A3E8U, 0xAE07BCE9U, 0xD9785D60U, 0x4D6B1905U, 0x70279F96U, 0x191C11EEU, 0x47ABD36EU, 0xAA4DE78CU,
0xA1D1937EU, 0xB71C8DA8U, 0xD8BA3757U, 0xF5D77E60U, 0x4D47B626U, 0xD240C24BU, 0xE1DCD8DAU, 0x66E7E712U,
0x38D8C2C4U, 0x9C31DE6BU, 0xDAFC890EU, 0xE762D18EU, 0x0AE7CCF6U, 0x54D4B0E5U, 0xD034C247U, 0xE868E0F1U,
0x4FDFF252U, 0x852AEF2AU, 0xDB3EE339U, 0x5FDEB6EBU, 0x3787E546U, 0x9F886340U, 0x7643C9F3U, 0x24C2E06FU,
0xD1BB67F1U, 0xCA6B79EDU, 0xDE71F5BCU, 0xC2098E52U, 0x85A73956U, 0x828D53F8U, 0xB3E4F77DU, 0x2E07E976U,
0xA6BC5767U, 0xD37048ACU, 0xDFB39F8BU, 0x7AB5E937U, 0xB8C710E6U, 0x49D1805DU, 0x1593FCC9U, 0xE2ADE9E8U,
0x3FB506DDU, 0xF85D1B6FU, 0xDDF521D2U, 0x680046D9U, 0xFF676A36U, 0xCF45F2F3U, 0x247BE654U, 0x6C22EE0BU,
0x48B2364BU, 0xE1462A2EU, 0xDC374BE5U, 0xD0BC21BCU, 0xC2074386U, 0x04192156U, 0x820CEDE0U, 0xA088EE95U,
0xD80D2BDAU, 0x66DE36E1U, 0xD76B0CD8U, 0x88DF31EAU, 0x4057D457U, 0xF54F9383U, 0x74449D09U, 0x79A8FC39U,
0xAF0A1B4CU, 0x7FC507A0U, 0xD6A966EFU, 0x3063568FU, 0x7D37FDE7U, 0x3E134026U, 0xD23396BDU, 0xB502FCA7U,
0x36034AF6U, 0x54E85463U, 0xD4EFD8B6U, 0x22D6F961U, 0x3A978737U, 0xB8873288U, 0xE3DB8C20U, 0x3B8DFB44U,
0x41047A60U, 0x4DF36522U, 0xD52DB281U, 0x9A6A9E04U, 0x07F7AE87U, 0x73DBE12DU, 0x45AC8794U, 0xF727FBDAU,
0xDF60EFC3U, 0x02B2F3E5U, 0xD062A404U, 0x07BDA6BDU, 0xB5D77297U, 0x6EDED195U, 0x800BB91AU, 0xFDE2F2C3U,
0xA867DF55U, 0x1BA9C2A4U, 0xD1A0CE33U, 0xBF01C1D8U, 0x88B75B27U, 0xA5820230U, 0x267CB2AEU, 0x3148F25DU,
0x316E8EEFU, 0x30849167U, 0xD3E6706AU, 0xADB46E36U, 0xCF1721F7U, 0x2316709EU, 0x1794A833U, 0xBFC7F5BEU,
0x4669BE79U, 0x299FA026U, 0xD2241A5DU, 0x15080953U, 0xF2770847U, 0xE84AA33BU, 0xB1E3A387U, 0x736DF520U,
0xCB61B38CU, 0xE4C5AEB8U, 0xC55EFE10U, 0x1D724E9AU, 0x10C70814U, 0x1ACA1375U, 0x20754FA0U, 0xD6F6D6A7U,
0xBC66831AU, 0xFDDE9FF9U, 0xC49C9427U, 0xA5CE29FFU, 0x2DA721A4U, 0xD196C0D0U, 0x86024414U, 0x1A5CD639U,
0x256FD2A0U, 0xD6F3CC3AU, 0xC6DA2A7EU, 0xB77B8611U, 0x6A075B74U, 0x5702B27EU, 0xB7EA5E89U, 0x94D3D1DAU,
0x5268E236U, 0xCFE8FD7BU, 0xC7184049U, 0x0FC7E174U, 0x576772C4U, 0x9C5E61DBU, 0x119D553DU, 0x5879D144U,
0xCC0C7795U, 0x80A96BBCU, 0xC25756CCU, 0x9210D9CDU, 0xE547AED4U, 0x815B5163U, 0xD43A6BB3U, 0x52BCD85DU,
0xBB0B4703U, 0x99B25AFDU, 0xC3953CFBU, 0x2AACBEA8U, 0xD8278764U, 0x4A0782C6U, 0x724D6007U, 0x9E16D8C3U,
0x220216B9U, 0xB29F093EU, 0xC1D382A2U, 0x38191146U, 0x9F87FDB4U, 0xCC93F068U, 0x43A57A9AU, 0x1099DF20U,
0x5505262FU, 0xAB84387FU, 0xC011E895U, 0x80A57623U, 0xA2E7D404U, 0x07CF23CDU, 0xE5D2712EU, 0xDC33DFBEU,
0xC5BA3BBEU, 0x2C1C24B0U, 0xCB4DAFA8U, 0xD8C66675U, 0x20B743D5U, 0xF6999118U, 0x139A01C7U, 0x0513CD12U,
0xB2BD0B28U, 0x350715F1U, 0xCA8FC59FU, 0x607A0110U, 0x1DD76A65U, 0x3DC542BDU, 0xB5ED0A73U, 0xC9B9CD8CU,
0x2BB45A92U, 0x1E2A4632U, 0xC8C97BC6U, 0x72CFAEFEU, 0x5A7710B5U, 0xBB513013U, 0x840510EEU, 0x4736CA6FU,
0x5CB36A04U, 0x07317773U, 0xC90B11F1U, 0xCA73C99BU, 0x67173905U, 0x700DE3B6U, 0x22721B5AU, 0x8B9CCAF1U,
0xC2D7FFA7U, 0x4870E1B4U, 0xCC440774U, 0x57A4F122U, 0xD537E515U, 0x6D08D30EU, 0xE7D525D4U, 0x8159C3E8U,
0xB5D0CF31U, 0x516BD0F5U, 0xCD866D43U, 0xEF189647U, 0xE857CCA5U, 0xA65400ABU, 0x41A22E60U, 0x4DF3C376U,
0x2CD99E8BU, 0x7A468336U, 0xCFC0D31AU, 0xFDAD39A9U, 0xAFF7B675U, 0x20C07205U, 0x704A34FDU, 0xC37CC495U,
0x5BDEAE1DU, 0x635DB277U, 0xCE02B92DU, 0x45115ECCU, 0x92979FC5U, 0xEB9CA1A0U, 0xD63D3F49U, 0x0FD6C40BU,
0x9B64C2B0U, 0xCBFAD74EU, 0x91AF9640U, 0x764DEE06U, 0xE915E8DBU, 0x11E81EB4U, 0xCC1D9F8BU, 0x7AA64737U,
0xEC63F226U, 0xD2E1E60FU, 0x906DFC77U, 0xCEF18963U, 0xD475C16BU, 0xDAB4CD11U, 0x6A6A943FU, 0xB60C47A9U,
0x756AA39CU, 0xF9CCB5CCU, 0x922B422EU, 0xDC44268DU, 0x93D5BBBBU, 0x5C20BFBFU, 0x5B828EA2U, 0x3883404AU,
0x026D930AU, 0xE0D7848DU, 0x93E92819U, 0x64F841E8U, 0xAEB5920BU, 0x977C6C1AU, 0xFDF58516U, 0xF42940D4U,
0x9C0906A9U, 0xAF96124AU, 0x96A63E9CU, 0xF92F7951U, 0x1C954E1BU, 0x8A795CA2U, 0x3852BB98U, 0xFEEC49CDU,
0xEB0E363FU, 0xB68D230BU, 0x976454ABU, 0x41931E34U, 0x21F567ABU, 0x41258F07U, 0x9E25B02CU, 0x32464953U,
0x72076785U, 0x9DA070C8U, 0x9522EAF2U, 0x5326B1DAU, 0x66551D7BU, 0xC7B1FDA9U, 0xAFCDAAB1U, 0xBCC94EB0U,
0x05005713U, 0x84BB4189U, 0x94E080C5U, 0xEB9AD6BFU, 0x5B3534CBU, 0x0CED2E0CU, 0x09BAA105U, 0x70634E2EU,
0x95BF4A82U, 0x03235D46U, 0x9FBCC7F8U, 0xB3F9C6E9U, 0xD965A31AU, 0xFDBB9CD9U, 0xFFF2D1ECU, 0xA9435C82U,
0xE2B87A14U, 0x1A386C07U, 0x9E7EADCFU, 0x0B45A18CU, 0xE4058AAAU, 0x36E74F7CU, 0x5985DA58U, 0x65E95C1CU,
0x7BB12BAEU, 0x31153FC4U, 0x9C381396U, 0x19F00E62U, 0xA3A5F07AU, 0xB0733DD2U, 0x686DC0C5U, 0xEB665BFFU,
0x0CB61B38U, 0x280E0E85U, 0x9DFA79A1U, 0xA14C6907U, 0x9EC5D9CAU, 0x7B2FEE77U, 0xCE1ACB71U, 0x27CC5B61U,
0x92D28E9BU, 0x674F9842U, 0x98B56F24U, 0x3C9B51BEU, 0x2CE505DAU, 0x662ADECFU, 0x0BBDF5FFU, 0x2D095278U,
0xE5D5BE0DU, 0x7E54A903U, 0x99770513U, 0x842736DBU, 0x11852C6AU, 0xAD760D6AU, 0xADCAFE4BU, 0xE1A352E6U,
0x7CDCEFB7U, 0x5579FAC0U, 0x9B31BB4AU, 0x96929935U, 0x562556BAU, 0x2BE27FC4U, 0x9C22E4D6U, 0x6F2C5505U,
0x0BDBDF21U, 0x4C62CB81U, 0x9AF3D17DU, 0x2E2EFE50U, 0x6B457F0AU, 0xE0BEAC61U, 0x3A55EF62U, 0xA386559BU,
0x86D3D2D4U, 0x8138C51FU, 0x8D893530U, 0x2654B999U, 0x89F57F59U, 0x123E1C2FU, 0xABC30345U, 0x061D761CU,
0xF1D4E242U, 0x9823F45EU, 0x8C4B5F07U, 0x9EE8DEFCU, 0xB49556E9U, 0xD962CF8AU, 0x0DB408F1U, 0xCAB77682U,
0x68DDB3F8U, 0xB30EA79DU, 0x8E0DE15EU, 0x8C5D7112U, 0xF3352C39U, 0x5FF6BD24U, 0x3C5C126CU, 0x44387161U,
0x1FDA836EU, 0xAA1596DCU, 0x8FCF8B69U, 0x34E11677U, 0xCE550589U, 0x94AA6E81U, 0x9A2B19D8U, 0x889271FFU,
0x81BE16CDU, 0xE554001BU, 0x8A809DECU, 0xA9362ECEU, 0x7C75D999U, 0x89AF5E39U, 0x5F8C2756U, 0x825778E6U,
0xF6B9265BU, 0xFC4F315AU, 0x8B42F7DBU, 0x118A49ABU, 0x4115F029U, 0x42F38D9CU, 0xF9FB2CE2U, 0x4EFD7878U,
0x6FB077E1U, 0xD7626299U, 0x89044982U, 0x033FE645U, 0x06B58AF9U, 0xC467FF32U, 0xC813367FU, 0xC0727F9BU,
0x18B74777U, 0xCE7953D8U, 0x88C623B5U, 0xBB838120U, 0x3BD5A349U, 0x0F3B2C97U, 0x6E643DCBU, 0x0CD87F05U,
0x88085AE6U, 0x49E14F17U, 0x839A6488U, 0xE3E09176U, 0xB9853498U, 0xFE6D9E42U, 0x982C4D22U, 0xD5F86DA9U,
0xFF0F6A70U, 0x50FA7E56U, 0x82580EBFU, 0x5B5CF613U, 0x84E51D28U, 0x35314DE7U, 0x3E5B4696U, 0x19526D37U,
0x66063BCAU, 0x7BD72D95U, 0x801EB0E6U, 0x49E959FDU, 0xC34567F8U, 0xB3A53F49U, 0x0FB35C0BU, 0x97DD6AD4U,
0x11010B5CU, 0x62CC1CD4U, 0x81DCDAD1U, 0xF1553E98U, 0xFE254E48U, 0x78F9ECECU, 0xA9C457BFU, 0x5B776A4AU,
0x8F659EFFU, 0x2D8D8A13U, 0x8493CC54U, 0x6C820621U, 0x4C059258U, 0x65FCDC54U, 0x6C636931U, 0x51B26353U,
0xF862AE69U, 0x3496BB52U, 0x8551A663U, 0xD43E6144U, 0x7165BBE8U, 0xAEA00FF1U, 0xCA146285U, 0x9D1863CDU,
0x616BFFD3U, 0x1FBBE891U, 0x8717183AU, 0xC68BCEAAU, 0x36C5C138U, 0x28347D5FU, 0xFBFC7818U, 0x1397642EU,
0x166CCF45U, 0x06A0D9D0U, 0x86D5720DU, 0x7E37A9CFU, 0x0BA5E888U, 0xE368AEFAU, 0x5D8B73ACU, 0xDF3D64B0U,
0xA00AE278U, 0x5E7EF3ECU, 0xA9E2D0A0U, 0xD67F4138U, 0x28D4C7DFU, 0x16441B82U, 0x03A0A617U, 0x83D02561U,
0xD70DD2EEU, 0x4765C2ADU, 0xA820BA97U, 0x6EC3265DU, 0x15B4EE6FU, 0xDD18C827U, 0xA5D7ADA3U, 0x4F7A25FFU,
0x4E048354U, 0x6C48916EU, 0xAA6604CEU, 0x7C7689B3U, 0x521494BFU, 0x5B8CBA89U, 0x943FB73EU, 0xC1F5221CU,
0x3903B3C2U, 0x7553A02FU, 0xABA46EF9U, 0xC4CAEED6U, 0x6F74BD0FU, 0x90D0692CU, 0x3248BC8AU, 0x0D5F2282U,
0xA7672661U, 0x3A1236E8U, 0xAEEB787CU, 0x591DD66FU, 0xDD54611FU, 0x8DD55994U, 0xF7EF8204U, 0x079A2B9BU,
0xD06016F7U, 0x230907A9U, 0xAF29124BU, 0xE1A1B10AU, 0xE03448AFU, 0x46898A31U, 0x519889B0U, 0xCB302B05U,
0x4969474DU, 0x0824546AU, 0xAD6FAC12U, 0xF3141EE4U, 0xA794327FU, 0xC01DF89FU, 0x6070932DU, 0x45BF2CE6U,
0x3E6E77DBU, 0x113F652BU, 0xACADC625U, 0x4BA87981U, 0x9AF41BCFU, 0x0B412B3AU, 0xC6079899U, 0x89152C78U,
0xAED16A4AU, 0x96A779E4U, 0xA7F18118U, 0x13CB69D7U, 0x18A48C1EU, 0xFA1799EFU, 0x304FE870U, 0x50353ED4U,
0xD9D65ADCU, 0x8FBC48A5U, 0xA633EB2FU, 0xAB770EB2U, 0x25C4A5AEU, 0x314B4A4AU, 0x9638E3C4U, 0x9C9F3E4AU,
0x40DF0B66U, 0xA4911B66U, 0xA4755576U, 0xB9C2A15CU, 0x6264DF7EU, 0xB7DF38E4U, 0xA7D0F959U, 0x121039A9U,
0x37D83BF0U, 0xBD8A2A27U, 0xA5B73F41U, 0x017EC639U, 0x5F04F6CEU, 0x7C83EB41U, 0x01A7F2EDU, 0xDEBA3937U,
0xA9BCAE53U, 0xF2CBBCE0U, 0xA0F829C4U, 0x9CA9FE80U, 0xED242ADEU, 0x6186DBF9U, 0xC400CC63U, 0xD47F302EU,
0xDEBB9EC5U, 0xEBD08DA1U, 0xA13A43F3U, 0x241599E5U, 0xD044036EU, 0xAADA085CU, 0x6277C7D7U, 0x18D530B0U,
0x47B2CF7FU, 0xC0FDDE62U, 0xA37CFDAAU, 0x36A0360BU, 0x97E479BEU, 0x2C4E7AF2U, 0x539FDD4AU, 0x965A3753U,
0x30B5FFE9U, 0xD9E6EF23U, 0xA2BE979DU, 0x8E1C516EU, 0xAA84500EU, 0xE712A957U, 0xF5E8D6FEU, 0x5AF037CDU,
0xBDBDF21CU, 0x14BCE1BDU, 0xB5C473D0U, 0x866616A7U, 0x4834505DU, 0x15921919U, 0x647E3AD9U, 0xFF6B144AU,
0xCABAC28AU, 0x0DA7D0FCU, 0xB40619E7U, 0x3EDA71C2U, 0x755479EDU, 0xDECECABCU, 0xC209316DU, 0x33C114D4U,
0x53B39330U, 0x268A833FU, 0xB640A7BEU, 0x2C6FDE2CU, 0x32F4033DU, 0x585AB812U, 0xF3E12BF0U, 0xBD4E1337U,
0x24B4A3A6U, 0x3F91B27EU, 0xB782CD89U, 0x94D3B949U, 0x0F942A8DU, 0x93066BB7U, 0x55962044U, 0x71E413A9U,
0xBAD03605U, 0x70D024B9U, 0xB2CDDB0CU, 0x090481F0U, 0xBDB4F69DU, 0x8E035B0FU, 0x90311ECAU, 0x7B211AB0U,
0xCDD70693U, 0x69CB15F8U, 0xB30FB13BU, 0xB1B8E695U, 0x80D4DF2DU, 0x455F88AAU, 0x3646157EU, 0xB78B1A2EU,
0x54DE5729U, 0x42E6463BU, 0xB1490F62U, 0xA30D497BU, 0xC774A5FDU, 0xC3CBFA04U, 0x07AE0FE3U, 0x39041DCDU,
0x23D967BFU, 0x5BFD777AU, 0xB08B6555U, 0x1BB12E1EU, 0xFA148C4DU, 0x089729A1U, 0xA1D90457U, 0xF5AE1D53U,
0xB3667A2EU, 0xDC656BB5U, 0xBBD72268U, 0x43D23E48U, 0x78441B9CU, 0xF9C19B74U, 0x579174BEU, 0x2C8E0FFFU,
0xC4614AB8U, 0xC57E5AF4U, 0xBA15485FU, 0xFB6E592DU, 0x4524322CU, 0x329D48D1U, 0xF1E67F0AU, 0xE0240F61U,
0x5D681B02U, 0xEE530937U, 0xB853F606U, 0xE9DBF6C3U, 0x028448FCU, 0xB4093A7FU, 0xC00E6597U, 0x6EAB0882U,
0x2A6F2B94U, 0xF7483876U, 0xB9919C31U, 0x516791A6U, 0x3FE4614CU, 0x7F55E9DAU, 0x66796E23U, 0xA201081CU,
0xB40BBE37U, 0xB809AEB1U, 0xBCDE8AB4U, 0xCCB0A91FU, 0x8DC4BD5CU, 0x6250D962U, 0xA3DE50ADU, 0xA8C40105U,
0xC30C8EA1U, 0xA1129FF0U, 0xBD1CE083U, 0x740CCE7AU, 0xB0A494ECU, 0xA90C0AC7U, 0x05A95B19U, 0x646E019BU,
0x5A05DF1BU, 0x8A3FCC33U, 0xBF5A5EDAU, 0x66B96194U, 0xF704EE3CU, 0x2F987869U, 0x34414184U, 0xEAE10678U,
0x2D02EF8DU, 0x9324FD72U, 0xBE9834EDU, 0xDE0506F1U, 0xCA64C78CU, 0xE4C4ABCCU, 0x92364A30U, 0x264B06E6U,
};
uint32_t ulCrc32;
if(pBuffer == NULL)
{
REDERROR();
ulCrc32 = SUSPICIOUS_CRC_VALUE;
}
else
{
const uint8_t *pbBuffer = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pBuffer);
uint32_t ulIdx = 0U;
const uint32_t *pulXorCrc0 = &aulCrc32Table[7U];
const uint32_t *pulXorCrc1 = &aulCrc32Table[6U];
const uint32_t *pulXorCrc2 = &aulCrc32Table[5U];
const uint32_t *pulXorCrc3 = &aulCrc32Table[4U];
const uint32_t *pulXorData4 = &aulCrc32Table[3U];
const uint32_t *pulXorData5 = &aulCrc32Table[2U];
const uint32_t *pulXorData6 = &aulCrc32Table[1U];
const uint32_t *pulXorData7 = &aulCrc32Table[0U];
uint32_t ulSliceLen;
ulCrc32 = ~ulInitCrc32;
/* Aligned memory access is used below. To avoid suboptimal
performance and faults (depending on platform), handle the
unaligned initial bytes (if any) using the Sarwate algorithm.
*/
while((ulIdx < ulLength) && !IS_ALIGNED_PTR(&pbBuffer[ulIdx]))
{
ulCrc32 = (ulCrc32 >> 8U) ^ aulCrc32Table[((ulCrc32 ^ pbBuffer[ulIdx]) & 0xFFU) << 3U];
ulIdx++;
}
/* Round down the length to the nearest multiple of eight.
*/
ulSliceLen = (((ulLength - ulIdx) >> 3U) << 3U) + ulIdx;
/* Compute the CRC in eight byte "slices". Takes advantage of
modern processors which can load in parallel from multiple
memory locations.
*/
while(ulIdx < ulSliceLen)
{
#if REDCONF_ENDIAN_BIG == 1
ulCrc32 ^= pbBuffer[ulIdx] | ((uint32_t)pbBuffer[ulIdx+1U] << 8U) |
((uint32_t)pbBuffer[ulIdx+2U] << 16U) | ((uint32_t)pbBuffer[ulIdx+3U] << 24U);
#else
ulCrc32 ^= *CAST_CONST_UINT32_PTR(&pbBuffer[ulIdx]);
#endif
ulCrc32 =
pulXorCrc3[((ulCrc32 >> 24U) & 0xFFU) << 3U] ^
pulXorCrc2[((ulCrc32 >> 16U) & 0xFFU) << 3U] ^
pulXorCrc1[((ulCrc32 >> 8U) & 0xFFU) << 3U] ^
pulXorCrc0[ (ulCrc32 & 0xFFU) << 3U] ^
pulXorData7[pbBuffer[ulIdx+7U] << 3U] ^
pulXorData6[pbBuffer[ulIdx+6U] << 3U] ^
pulXorData5[pbBuffer[ulIdx+5U] << 3U] ^
pulXorData4[pbBuffer[ulIdx+4U] << 3U];
ulIdx += 8U;
}
/* Compute the remaining bytes with the Sarwate algorithm.
*/
while(ulIdx < ulLength)
{
ulCrc32 = (ulCrc32 >> 8U) ^ aulCrc32Table[((ulCrc32 ^ pbBuffer[ulIdx]) & 0xFFU) << 3U];
ulIdx++;
}
ulCrc32 = ~ulCrc32;
}
return ulCrc32;
}
#else
#error "REDCONF_CRC_ALGORITHM must be set to CRC_BITWISE, CRC_SARWATE, or CRC_SLICEBY8"
#endif
/** @brief Compute a CRC32 for a metadata node buffer.
@param pBuffer The metadata node buffer for which to compute a CRC. Must
be a block sized buffer.
@return The CRC of the buffer.
*/
uint32_t RedCrcNode(
const void *pBuffer)
{
uint32_t ulCrc;
if(pBuffer == NULL)
{
REDERROR();
ulCrc = SUSPICIOUS_CRC_VALUE;
}
else
{
const uint8_t *pbBuffer = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pBuffer);
/* The first eight bytes of a metadata node contain the signature and
the CRC. There is little value in CRCing the signature, and the
CRC cannot be CRC'd, so skip over that part of the buffer.
*/
ulCrc = RedCrc32Update(0U, &pbBuffer[8U], REDCONF_BLOCK_SIZE - 8U);
}
return ulCrc;
}

View file

@ -0,0 +1,82 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements utilities for performing endian swaps.
*/
#include <redfs.h>
#ifdef REDCONF_ENDIAN_SWAP
/** @brief Reverse the byte order of a 64-bit number.
@param ullToRev Number whose bytes will be reversed
@retval @p ullToRev with its bytes reversed.
*/
uint64_t RedRev64(
uint64_t ullToRev)
{
uint64_t ullRet = ullToRev;
ullRet = ((ullRet & UINT64_SUFFIX(0x00000000FFFFFFFF)) << 32U) | ((ullRet & UINT64_SUFFIX(0xFFFFFFFF00000000)) >> 32U);
ullRet = ((ullRet & UINT64_SUFFIX(0x0000FFFF0000FFFF)) << 16U) | ((ullRet & UINT64_SUFFIX(0xFFFF0000FFFF0000)) >> 16U);
ullRet = ((ullRet & UINT64_SUFFIX(0x00FF00FF00FF00FF)) << 8U) | ((ullRet & UINT64_SUFFIX(0xFF00FF00FF00FF00)) >> 8U);
return ullRet;
}
/** @brief Reverse the byte order of a 32-bit number.
@param ulToRev Number whose bytes will be reversed
@retval @p ulToRev with its bytes reversed.
*/
uint32_t RedRev32(
uint32_t ulToRev)
{
return ((ulToRev & 0x000000FFU) << 24U)
| ((ulToRev & 0x0000FF00U) << 8U)
| ((ulToRev & 0x00FF0000U) >> 8U)
| ((ulToRev & 0xFF000000U) >> 24U);
}
/** @brief Reverse the byte order of a 16-bit number.
@param uToRev Number whose bytes will be reversed
@retval @p uToRev with its bytes reversed.
*/
uint16_t RedRev16(
uint16_t uToRev)
{
return ((uToRev & 0xFF00U) >> 8U)
| ((uToRev & 0x00FFU) << 8U);
}
#endif

View file

@ -0,0 +1,301 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Default implementations of memory manipulation functions.
These implementations are intended to be small and simple, and thus forego
all optimizations. If the C library is available, or if there are better
third-party implementations available in the system, those can be used
instead by defining the appropriate macros in redconf.h.
These functions are not intended to be completely 100% ANSI C compatible
implementations, but rather are designed to meet the needs of Reliance Edge.
The compatibility is close enough that ANSI C compatible implementations
can be "dropped in" as replacements without difficulty.
*/
#include <redfs.h>
#ifndef RedMemCpyUnchecked
static void RedMemCpyUnchecked(void *pDest, const void *pSrc, uint32_t ulLen);
#endif
#ifndef RedMemMoveUnchecked
static void RedMemMoveUnchecked(void *pDest, const void *pSrc, uint32_t ulLen);
#endif
#ifndef RedMemSetUnchecked
static void RedMemSetUnchecked(void *pDest, uint8_t bVal, uint32_t ulLen);
#endif
#ifndef RedMemCmpUnchecked
static int32_t RedMemCmpUnchecked(const void *pMem1, const void *pMem2, uint32_t ulLen);
#endif
/** @brief Copy memory from one address to another.
The source and destination memory buffers should not overlap. If the
buffers overlap, use RedMemMove() instead.
@param pDest The destination buffer.
@param pSrc The source buffer.
@param ulLen The number of bytes to copy.
*/
void RedMemCpy(
void *pDest,
const void *pSrc,
uint32_t ulLen)
{
if((pDest == NULL) || (pSrc == NULL))
{
REDERROR();
}
else
{
RedMemCpyUnchecked(pDest, pSrc, ulLen);
}
}
#ifndef RedMemCpyUnchecked
/** @brief Copy memory from one address to another.
This function should only be called from RedMemCpy().
@param pDest The destination buffer.
@param pSrc The source buffer.
@param ulLen The number of bytes to copy.
*/
static void RedMemCpyUnchecked(
void *pDest,
const void *pSrc,
uint32_t ulLen)
{
uint8_t *pbDest = CAST_VOID_PTR_TO_UINT8_PTR(pDest);
const uint8_t *pbSrc = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pSrc);
uint32_t ulIdx;
for(ulIdx = 0U; ulIdx < ulLen; ulIdx++)
{
pbDest[ulIdx] = pbSrc[ulIdx];
}
}
#endif
/** @brief Move memory from one address to another.
Supports overlapping memory regions. If memory regions do not overlap, it
is generally better to use RedMemCpy() instead.
@param pDest The destination buffer.
@param pSrc The source buffer.
@param ulLen The number of bytes to copy.
*/
void RedMemMove(
void *pDest,
const void *pSrc,
uint32_t ulLen)
{
if((pDest == NULL) || (pSrc == NULL))
{
REDERROR();
}
else
{
RedMemMoveUnchecked(pDest, pSrc, ulLen);
}
}
#ifndef RedMemMoveUnchecked
/** @brief Move memory from one address to another.
This function should only be called from RedMemMove().
@param pDest The destination buffer.
@param pSrc The source buffer.
@param ulLen The number of bytes to copy.
*/
static void RedMemMoveUnchecked(
void *pDest,
const void *pSrc,
uint32_t ulLen)
{
uint8_t *pbDest = CAST_VOID_PTR_TO_UINT8_PTR(pDest);
const uint8_t *pbSrc = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pSrc);
uint32_t ulIdx;
if(MEMMOVE_MUST_COPY_FORWARD(pbDest, pbSrc))
{
/* If the destination is lower than the source with overlapping memory
regions, we must copy from start to end in order to copy the memory
correctly.
Don't use RedMemCpy() to do this. It is possible that RedMemCpy()
has been replaced (even though this function has not been replaced)
with an implementation that cannot handle any kind of buffer
overlap.
*/
for(ulIdx = 0U; ulIdx < ulLen; ulIdx++)
{
pbDest[ulIdx] = pbSrc[ulIdx];
}
}
else
{
ulIdx = ulLen;
while(ulIdx > 0U)
{
ulIdx--;
pbDest[ulIdx] = pbSrc[ulIdx];
}
}
}
#endif /* RedMemMoveUnchecked */
/** @brief Initialize a buffer with the specified byte value.
@param pDest The buffer to initialize.
@param bVal The byte value with which to initialize @p pDest.
@param ulLen The number of bytes to initialize.
*/
void RedMemSet(
void *pDest,
uint8_t bVal,
uint32_t ulLen)
{
if(pDest == NULL)
{
REDERROR();
}
else
{
RedMemSetUnchecked(pDest, bVal, ulLen);
}
}
#ifndef RedMemSetUnchecked
/** @brief Initialize a buffer with the specified byte value.
This function should only be called from RedMemSet().
@param pDest The buffer to initialize.
@param bVal The byte value with which to initialize @p pDest.
@param ulLen The number of bytes to initialize.
*/
static void RedMemSetUnchecked(
void *pDest,
uint8_t bVal,
uint32_t ulLen)
{
uint8_t *pbDest = CAST_VOID_PTR_TO_UINT8_PTR(pDest);
uint32_t ulIdx;
for(ulIdx = 0U; ulIdx < ulLen; ulIdx++)
{
pbDest[ulIdx] = bVal;
}
}
#endif
/** @brief Compare the contents of two buffers.
@param pMem1 The first buffer to compare.
@param pMem2 The second buffer to compare.
@param ulLen The length to compare.
@return Zero if the two buffers are the same, otherwise nonzero.
@retval 0 @p pMem1 and @p pMem2 are the same.
@retval 1 @p pMem1 is greater than @p pMem2, as determined by the
values of the first differing bytes.
@retval -1 @p pMem2 is greater than @p pMem1, as determined by the
values of the first differing bytes.
*/
int32_t RedMemCmp(
const void *pMem1,
const void *pMem2,
uint32_t ulLen)
{
int32_t lResult;
if((pMem1 == NULL) || (pMem2 == NULL))
{
REDERROR();
lResult = 0;
}
else
{
lResult = RedMemCmpUnchecked(pMem1, pMem2, ulLen);
}
return lResult;
}
#ifndef RedMemCmpUnchecked
/** @brief Compare the contents of two buffers.
@param pMem1 The first buffer to compare.
@param pMem2 The second buffer to compare.
@param ulLen The length to compare.
@return Zero if the two buffers are the same, otherwise nonzero.
*/
static int32_t RedMemCmpUnchecked(
const void *pMem1,
const void *pMem2,
uint32_t ulLen)
{
const uint8_t *pbMem1 = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pMem1);
const uint8_t *pbMem2 = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pMem2);
uint32_t ulIdx = 0U;
int32_t lResult;
while((ulIdx < ulLen) && (pbMem1[ulIdx] == pbMem2[ulIdx]))
{
ulIdx++;
}
if(ulIdx == ulLen)
{
lResult = 0;
}
else if(pbMem1[ulIdx] > pbMem2[ulIdx])
{
lResult = 1;
}
else
{
lResult = -1;
}
return lResult;
}
#endif

View file

@ -0,0 +1,61 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements a utility to find the length of a name.
*/
#include <redfs.h>
#if REDCONF_API_POSIX == 1
/** @brief Determine the length of a name, terminated either by a null or a path
separator character.
@param pszName The name whose length is to be determined.
@return The length of the name.
*/
uint32_t RedNameLen(
const char *pszName)
{
uint32_t ulIdx = 0U;
if(pszName == NULL)
{
REDERROR();
}
else
{
while((pszName[ulIdx] != '\0') && (pszName[ulIdx] != REDCONF_PATH_SEPARATOR))
{
ulIdx++;
}
}
return ulIdx;
}
#endif

View file

@ -0,0 +1,63 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Implements a sign on message.
*/
#include <redfs.h>
/** @brief Display the Reliance Edge signon message.
*/
void RedSignOn(void)
{
#if REDCONF_OUTPUT == 1
/* Use RedOsOutputString() instead of RedPrintf() to avoid using variadic
arguments, since this function is called from the driver and cannot use
functions that violate MISRA-C:2012.
*/
RedOsOutputString(RED_PRODUCT_NAME "\n");
RedOsOutputString(RED_PRODUCT_EDITION "\n");
RedOsOutputString(RED_PRODUCT_LEGAL "\n");
RedOsOutputString(RED_PRODUCT_PATENT "\n");
#else
/* Always embed the copyright into the program data. Use "volatile" to try
to avoid the compiler removing the variables.
*/
static volatile const char szVersion[] = RED_PRODUCT_NAME;
static volatile const char szEdition[] = RED_PRODUCT_EDITION;
static volatile const char szCopyright[] = RED_PRODUCT_LEGAL;
static volatile const char szPatent[] = RED_PRODUCT_PATENT;
(void)szVersion;
(void)szEdition;
(void)szCopyright;
(void)szPatent;
#endif
}

View file

@ -0,0 +1,329 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
@brief Default implementations of string manipulation functions.
These implementations are intended to be small and simple, and thus forego
all optimizations. If the C library is available, or if there are better
third-party implementations available in the system, those can be used
instead by defining the appropriate macros in redconf.h.
These functions are not intended to be completely 100% ANSI C compatible
implementations, but rather are designed to meet the needs of Reliance Edge.
The compatibility is close enough that ANSI C compatible implementations
can be "dropped in" as replacements without difficulty.
*/
#include <redfs.h>
#ifndef RedStrLenUnchecked
static uint32_t RedStrLenUnchecked(const char *pszStr);
#endif
#ifndef RedStrCmpUnchecked
static int32_t RedStrCmpUnchecked(const char *pszStr1, const char *pszStr2);
#endif
#ifndef RedStrNCmpUnchecked
static int32_t RedStrNCmpUnchecked(const char *pszStr1, const char *pszStr2, uint32_t ulLen);
#endif
#ifndef RedStrNCpyUnchecked
static void RedStrNCpyUnchecked(char *pszDst, const char *pszSrc, uint32_t ulLen);
#endif
/** @brief Determine the length (in bytes) of a null terminated string.
The length does not include the null terminator byte.
@param pszStr The null terminated string whose length is to be determined.
@return The length of the @p pszStr string.
*/
uint32_t RedStrLen(
const char *pszStr)
{
uint32_t ulLen;
if(pszStr == NULL)
{
REDERROR();
ulLen = 0U;
}
else
{
/* Cast the result to uint32_t, since RedStrLenUnchecked() might be
strlen(), which returns size_t, which is possibly a 64-bit value.
*/
ulLen = (uint32_t)RedStrLenUnchecked(pszStr);
}
return ulLen;
}
#ifndef RedStrLenUnchecked
/** @brief Determine the length (in bytes) of a null terminated string.
@param pszStr The null terminated string whose length is to be determined.
@return The length of the @p pszStr string.
*/
static uint32_t RedStrLenUnchecked(
const char *pszStr)
{
uint32_t ulLen = 0U;
while(pszStr[ulLen] != '\0')
{
ulLen++;
}
return ulLen;
}
#endif
/** @brief Compare two null terminated strings.
@param pszStr1 The first string to compare.
@param pszStr2 The second string to compare.
@return Zero if the two strings are the same, otherwise nonzero.
@retval 0 @p pszStr1 and @p pszStr2 are the same.
@retval 1 @p pszStr1 is greater than @p pszStr2, as determined by the
values of the first differing bytes.
@retval -1 @p pszStr2 is greater than @p pszStr1, as determined by the
values of the first differing bytes.
*/
int32_t RedStrCmp(
const char *pszStr1,
const char *pszStr2)
{
int32_t lResult;
if((pszStr1 == NULL) || (pszStr2 == NULL))
{
REDERROR();
lResult = 0;
}
else
{
lResult = RedStrCmpUnchecked(pszStr1, pszStr2);
}
return lResult;
}
#ifndef RedStrCmpUnchecked
/** @brief Compare two null terminated strings.
@param pszStr1 The first string to compare.
@param pszStr2 The second string to compare.
@return Zero if the two strings are the same, otherwise nonzero.
*/
static int32_t RedStrCmpUnchecked(
const char *pszStr1,
const char *pszStr2)
{
int32_t lResult;
uint32_t ulIdx = 0U;
while((pszStr1[ulIdx] == pszStr2[ulIdx]) && (pszStr1[ulIdx] != '\0'))
{
ulIdx++;
}
/* "The sign of a non-zero return value is determined by the sign of the
difference between the values of the first pair of bytes (both
interpreted as type unsigned char) that differ in the strings being
compared." Use uint8_t instead of unsigned char to avoid MISRA C
deviations.
*/
if((uint8_t)pszStr1[ulIdx] > (uint8_t)pszStr2[ulIdx])
{
lResult = 1;
}
else if((uint8_t)pszStr1[ulIdx] < (uint8_t)pszStr2[ulIdx])
{
lResult = -1;
}
else
{
lResult = 0;
}
return lResult;
}
#endif
/** @brief Compare the first @p ulLen characters of two null terminated strings.
@param pszStr1 The first string to compare.
@param pszStr2 The second string to compare.
@param ulLen The maximum length to compare. The comparison stops when
either of the strings end or when @p ulLen bytes have been
compared.
@return Zero if the two strings are the same, otherwise nonzero.
@retval 0 @p pszStr1 and @p pszStr2 are the same.
@retval 1 @p pszStr1 is greater than @p pszStr2, as determined by the
values of the first differing bytes.
@retval -1 @p pszStr2 is greater than @p pszStr1, as determined by the
values of the first differing bytes.
*/
int32_t RedStrNCmp(
const char *pszStr1,
const char *pszStr2,
uint32_t ulLen)
{
int32_t lResult;
if((pszStr1 == NULL) || (pszStr2 == NULL))
{
REDERROR();
lResult = 0;
}
else
{
lResult = RedStrNCmpUnchecked(pszStr1, pszStr2, ulLen);
}
return lResult;
}
#ifndef RedStrNCmpUnchecked
/** @brief Compare the first @p ulLen characters of two null terminated strings.
@param pszStr1 The first string to compare.
@param pszStr2 The second string to compare.
@param ulLen The maximum length to compare. The comparison stops when
either of the strings end or when @p ulLen bytes have been
compared.
@return Zero if the two strings are the same, otherwise nonzero.
*/
static int32_t RedStrNCmpUnchecked(
const char *pszStr1,
const char *pszStr2,
uint32_t ulLen)
{
int32_t lResult = 0;
uint32_t ulIdx;
for(ulIdx = 0U; ulIdx < ulLen; ulIdx++)
{
if(pszStr1[ulIdx] != pszStr2[ulIdx])
{
/* "The sign of a non-zero return value is determined by the sign
of the difference between the values of the first pair of bytes
(both interpreted as type unsigned char) that differ in the
strings being compared." Use uint8_t instead of unsigned char
to avoid MISRA C deviations.
*/
if((uint8_t)pszStr1[ulIdx] > (uint8_t)pszStr2[ulIdx])
{
lResult = 1;
}
else
{
lResult = -1;
}
}
if((lResult != 0) || (pszStr1[ulIdx] == '\0'))
{
break;
}
}
return lResult;
}
#endif
/** @brief Copy a string.
Copy up to @p ulLen bytes of a null-terminated string (@p pszSrc) to a
destination buffer (@p pszDst). The result will not be null-terminated if
@p pszSrc is longer than @p ulLen - 1 bytes.
If @p pszSrc is shorter than @p ulLen - 1 bytes, the remainder of @p pszDst
will be filled with null bytes.
@param pszDst The destination buffer, which is at least @p ulLen bytes
in size.
@param pszSrc The null-terminated string to copy.
@param ulLen The maximum number of characters to copy.
*/
void RedStrNCpy(
char *pszDst,
const char *pszSrc,
uint32_t ulLen)
{
if((pszDst == NULL) || (pszSrc == NULL))
{
REDERROR();
}
else
{
RedStrNCpyUnchecked(pszDst, pszSrc, ulLen);
}
}
#ifndef RedStrNCpyUnchecked
/** @brief Copy a string.
@param pszDst The destination buffer, which is at least @p ulLen bytes
in size.
@param pszSrc The null-terminated string to copy.
@param ulLen The maximum number of characters to copy.
*/
static void RedStrNCpyUnchecked(
char *pszDst,
const char *pszSrc,
uint32_t ulLen)
{
uint32_t ulIdx = 0U;
while((ulIdx < ulLen) && (pszSrc[ulIdx] != '\0'))
{
pszDst[ulIdx] = pszSrc[ulIdx];
ulIdx++;
}
while(ulIdx < ulLen)
{
pszDst[ulIdx] = '\0';
ulIdx++;
}
}
#endif