Mercurial > yaffs-ecoscentric-gpl
changeset 428:a386ed10401a ecos
Drop in eCos bridge work
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/ChangeLog @@ -0,0 +1,113 @@ +2010-05-14 Ross Younger <wry@ecoscentric.com> + + * Repository recut due to upstream version control change. + * Update upstream: pulled up to 2010-05-13. Bugfixes, efficiency + and robustness improvements. eCos bridge code reworked slightly + to suit. Requires CYGFUN_LIBC_STRING_GNU_STRNLEN. + +2009-12-01 Ross Younger <wry@ecoscentric.com> + + * ecos-yaffs.c: Interface tweaks to allow this this package + to be easily used with eCosPro. + * yaffs.cdl: Create CYGSEM_FS_YAFFS_COMPATIBILITY_ECOSPRO switch + for the above, default off (i.e. for anoncvs). + +2009-11-19 Ross Younger <wry@ecoscentric.com> + + * ecos-yaffs.c, ecos-yaffs-nand.c: Update to NAND interface v2. + * yaffs.cdl: Require CYGSEM_IO_NAND_APPINTERFACE_VERSION > 1. + Declare CYGSEM_FS_YAFFS_NAND_APPINTERFACE to satisfy the two-way check. + +2009-11-17 Ross Younger <wry@ecoscentric.com> + + * yaffs_guts.c: Tweak last upstream merge. Be noisy if + we ran out of memory during mount. + +2009-11-13 Ross Younger <wry@ecoscentric.com> + + * tests: yaffs1-6 NA unless CYGPKG_KERNEL is present. + * Update upstream: (pulled up to 2009-11-11 02:11:13 +0000) + - mostly bugfixes + +2009-11-09 Ross Younger <wry@ecoscentric.com> + + * ecos-yaffs-nand.c: Update for changes to NAND interface. + +2009-11-03 Ross Younger <wry@ecoscentric.com> + + * tests: Import from eCosPro: mounttime, yaffs1, yaffs2, + yaffs4, yaffs5, yaffs6. Patch for codebase differences. + +2009-11-02 Ross Younger <wry@ecoscentric.com> + + * Update to latest snapshot from Aleph One CVS (mostly + tidyups): last upstream change is dated "2009-10-30 02:32:32 +0000" + +2009-10-29 Ross Younger <wry@ecoscentric.com> + + * yaffs_guts.c: Fix low-memory assert bug. + +2009-10-09 Ross Younger <wry@ecoscentric.com> + + * tests/fops.c: Don't make unreasonable use of stack. + * Update for latest upstream snapshot (yaffs_FlushFile) + +2009-09-24 Ross Younger <wry@ecoscentric.com> + + * doc/yaffs.sgml: Various fixups. + * ecos-yaffs-nand.h, ecos-yaffs.c, yaffs_guts.c: Build fixes for + older gcc + +2009-09-16 Ross Younger <wry@ecoscentric.com> + + * ecos-yaffs-nand.c: Correctly use ECC on YAFFS tags in yaffs2 + filesystems when not in inbandTags mode (ref: 1000821) + * ecos-yaffs.c: Improve spare area size sanity checking on mount + * yaffs_packedtags2.c: Add framework (usually conditioned out) + to count ECC corrections within the spare area. + +2009-08-28 Ross Younger <wry@ecoscentric.com> + + * doc/yaffs.sgml: Bring explanations of CDL options up-to-date. + * yaffs.cdl: Add CYGNUM_FS_YAFFS_TEMP_BUFFERS tuning parameter. + +2009-08-26 Ross Younger <wry@ecoscentric.com> + + * Added support for small-page chips: incorporates and builds on work + by Simon Kallweit. Small page devices can operate either in YAFFS1 + mode, or YAFFS2 mode with inbandTags. + * Updated #defines to omit unneeded YAFFS code. + +2009-08-18 Ross Younger <wry@ecoscentric.com> + + * yaffs-guts.c: Update from Aleph One CVS (1.85 -> 1.88) + +2009-07-20 Ross Younger <wry@ecoscentric.com> + + * ecos-yaffs.c: Compute free-space from nErasedBlocks (recommended by + Charles Manning) - not yaffs_GetNumberOfFreeChunks. + +2009-07-03 Ross Younger <wry@eCosCentric.com> + + * Add detailed RAM use estimate and worked example. + +2009-06-18 Ross Younger <wry@eCosCentric.com> + + * General enhancements and bugfixes. + * Add mount-time mallinfo check/warning in debug builds. + * Replace unconditional diag_printfs with calls to TOUT macro. + * TOUT (trace output) macro now uses configable cdl function, + may be disabled. + * Improve our definition of YBUG. + * Upstream: Merge from cvs datestamp "2009-05-16 00:00" + * Retab eCos-specific files, for consistency. + * Pare down use of libextras. + * doc: linewrap for consistency. + * Elide unneeded YAFFS1 code. + * Use eCos qsort, not yaffs's own. + +2009-05-01 Ross Younger <wry@eCosCentric.com> + + * New package. YAFFS filesystem. Beware license terms; this + package is not covered by the standard eCos license! +
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/GPL-2 @@ -0,0 +1,339 @@ + 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.
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/cdl/yaffs.cdl @@ -0,0 +1,310 @@ +# ==================================================================== +# +# yaffs.cdl +# +# YAFFS (Yet Another Flash File System) port to eCos +# +# ==================================================================== +# ####ECOSGPLCOPYRIGHTBEGIN#### +# ------------------------------------------- +# This file is part of eCos, the Embedded Configurable Operating System. +# Copyright (C) 2009-2010 eCosCentric Limited. +# +# eCos 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 or (at your option) any later +# version. +# +# eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception, if other files instantiate templates or use +# macros or inline functions from this file, or you compile this file +# and link it with other works to produce a work based on this file, +# this file does not by itself cause the resulting work to be covered by +# the GNU General Public License. However the source code for this file +# must still be made available in accordance with section (3) of the GNU +# General Public License v2. +# +# This exception does not invalidate any other reasons why a work based +# on this file might be covered by the GNU General Public License. +# ------------------------------------------- +# ####ECOSGPLCOPYRIGHTEND#### +# ==================================================================== +######DESCRIPTIONBEGIN#### +# +# Author(s): wry +# Date: 2009-05-01 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + +cdl_package CYGPKG_FS_YAFFS { + display "YAFFS flash filesystem" + parent CYGPKG_FS + include_files + # there's nothing to include as we patch in to the fstab. + + requires CYGPKG_IO_FILEIO + requires CYGPKG_IO_NAND + requires ( CYGSEM_IO_NAND_APPINTERFACE_VERSION > 1 ) + requires CYGPKG_ISOINFRA + requires CYGINT_ISO_ERRNO + requires CYGINT_ISO_ERRNO_CODES + requires CYGINT_ISO_MALLOC + requires CYGPKG_LIBC_STDLIB + # STDLIB requires CYGINT_ISO_CTYPE, which is provided by CYGPKG_LIBC_I18N + requires CYGPKG_LIBC_STRING + requires CYGFUN_LIBC_STRING_GNU_STRNLEN + + requires { CYGPKG_REDBOOT implies (CYGMEM_REDBOOT_WORKSPACE_HEAP_SIZE >= 0x00014000) } + + requires { (CYGSEM_FS_YAFFS_SMALLPAGE_MODE=="YAFFS1" && CYGNUM_NAND_SYNTH_PAGESIZE==512) implies CYGSEM_NAND_SYNTH_ALLOW_MULTIPLE_WRITES } + + implements CYGINT_IO_FILEIO_FS + + compile -library=libextras.a ecos-yaffs.c + compile yaffs_checkptrw.c \ + yaffs_guts.c \ + yaffs_nand.c \ + yaffs_ecc.c \ + yaffs_packedtags1.c \ + yaffs_packedtags2.c \ + yaffs_tagscompat.c \ + yaffs_tagsvalidity.c \ + ecos-yaffs-nand.c \ + ecos-yaffs-diriter.c + + #doc ref/yaffs.html + description " + This package provides the YAFFS filesystem which is intended for + NAND flash devices." + + cdl_component CYGPKG_FS_YAFFS_OPTIONS { + display "YAFFS build options" + flavor none + description " + Package specific build options including control over + compiler flags used only in building the YAFFS code." + + cdl_option CYGPKG_FS_YAFFS_CFLAGS_ADD { + display "Additional compiler flags" + flavor data + no_define + default_value { "-Werror" } + description " + This option modifies the set of compiler flags for + building the YAFFS filesystem. These flags + are used in addition to the set of global flags." + } + cdl_option CYGPKG_FS_YAFFS_CFLAGS_REMOVE { + display "Suppressed compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the YAFFS filesystem. These flags + are removed from the set of global flags if present." + } + } + + cdl_option CYGSEM_FS_YAFFS_SMALLPAGE_MODE { + display "YAFFS mode for small page devices" + flavor data + default_value { "YAFFS2" } + legal_values { "YAFFS1" "YAFFS2" } + description " + Small page devices - those with 512 bytes/page - may operate + in either YAFFS1 mode, or YAFFS2 with the inband tags option. + This option selects the mode to use. Note that some chips + cannot support YAFFS1 mode, so this option may not be + relevant to you." + } + + cdl_option CYGSEM_FS_YAFFS_CACHE_SHORT_NAMES { + display "Cache short filenames in RAM" + default_value 1 + description " + If set, short names are cached in memory. + This consumes more RAM, but allows faster file look-ups." + } + + cdl_option CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE { + display "Omit YAFFS2-specific code" + default_value 1 + active_if { CYGSEM_FS_YAFFS_SMALLPAGE_MODE == "YAFFS1" } + active_if CYGNUM_NAND_PAGEBUFFER <= 512 + description " + This option causes some of the YAFFS2-specific code + to be omitted from the build, in order to reduce code + size. Obviously, this can only ever work if all your devices + are small-page, and you have configured YAFFS to run them in + YAFFS1 mode." + } + + cdl_option CYGPKG_FS_YAFFS_RET_DIRENT_DTYPE { + display "Support for fileio's struct dirent d_type field" + flavor bool + default_value 0 + active_if CYGPKG_FILEIO_DIRENT_DTYPE + description "This option controls whether the YAFFS filesystem + supports setting fileio's struct dirent d_type field. + If this option is enabled, d_type will be set." + } + + cdl_option CYGNUM_FS_YAFFS_RESERVED_BLOCKS { + display "Number of reserved blocks" + flavor data + default_value 5 + legal_values 2 to 0x7fffffff + description " + The number of eraseblocks YAFFS should keep in reserve to allow + for garbage collection and for block failures. A + minimum value of 5 is recommended if you are using real + (non-synthetic) NAND devices; wizards may wish to tune it to + improve performance. Note that this setting is a global + default and may be tuned per-device by a mount-time option." + } + + cdl_option CYGNUM_FS_YAFFS_SHORTOP_CACHES { + display "Number of cache entries" + flavor data + default_value 10 + legal_values 0 to 0x7fffffff + description " + The number of page cache entries to use. Values from 10 to 20 + are recommended; set to 0 to disable cacheing. + Wizards may wish to tune this value to improve performance. + Note that this setting is a global default and may be + configured per-device by a mount-time option. There is also + an upper limit hard-wired into the code as + YAFFS_MAX_SHORT_OP_CACHES; numbers in excess of this ceiling + will be ignored." + } + + cdl_option CYGNUM_FS_YAFFS_TEMP_BUFFERS { + display "Number of preallocated temporary page buffers" + flavor data + default_value 6 + legal_values 0 to 0x7fffffff + description " + At mount time, YAFFS preallocates a number of temporary + buffers, which are used in many places throughout the code. + This setting controls how many. + If YAFFS ever runs out of temporary buffers, it calls malloc to + dynamically allocate further buffers as needed. + Most users will not need to change this setting, but it may + prove a useful tuning parameter." + } + + cdl_option CYGNUM_FS_YAFFS_TRACEMASK { + display "Output trace mask" + flavor data + default_value 0 + legal_values 0 to 0xffffffff + description " + The YAFFS filesystem has a number of categories in which it can + emit diagnostic output. They are controlled by this setting, + which is a bitfield; set bits enable various categories. + For the definition of the bits used, see yportenv.h + (\"Tracing flags\"). They tend only to be useful for debugging. + " + } + + cdl_option CYGSEM_FS_YAFFS_TRACEFN { + display "Enable debug tracing" + flavor booldata + default_value { "diag_printf" } + description " + If enabled, diagnostic output from YAFFS will be sent to + this function." + } + + cdl_option CYGSEM_FS_YAFFS_COMPATIBILITY_ECOSPRO { + display "eCosPro compatibility mode" + flavor bool + default_value 0 + description "This package is targetted at eCos but may be + built under eCosPro by setting this switch." + } + + cdl_component CYGPKG_FS_YAFFS_TESTING { + display "Testing configuration" + default_value 1 + + define_proc { + puts $::cdl_system_header "/***** Synthdisk driver proc output start *****/" + puts $::cdl_system_header "#define CYGDAT_DEVS_DISK_CFG <pkgconf/fs_yaffs.h>" + puts $::cdl_system_header "/***** Synthdisk driver proc output end *****/" + } + + + cdl_option CYGDAT_DEVS_DISK_TEST_DEVICE { + display "Test device driver" + flavor data + default_value { CYGPKG_DEVS_NAND_SYNTH?"\"synth/0\"":"\"onboard/0\"" } + } + + cdl_option CYGDAT_DEVS_DISK_TEST_MOUNTPOINT { + display "Test filesystem mountpoint" + flavor data + default_value {"\"/nand\"" } + } + + cdl_option CYGDAT_DEVS_DISK_TEST_DIRECTORY { + display "Test directory on test device" + flavor data + default_value {"\"/test\"" } + } + + + cdl_option CYGDAT_DEVS_DISK_TEST_DEVICE2 { + display "Second Test device driver" + flavor data + default_value { CYGPKG_DEVS_NAND_SYNTH?"\"synth/1\"":"\"onboard/1\"" } + } + + cdl_option CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 { + display "Second Test filesystem mountpoint" + flavor data + default_value {"\"/nand2\"" } + } + + cdl_option CYGDAT_DEVS_DISK_TEST_DIRECTORY2 { + display "Test directory on second test device" + flavor data + default_value {"\"/test\"" } + } + + } + + cdl_option CYGPKG_FS_YAFFS_TESTS { + display "YAFFS filesystem tests" + flavor data + no_define + calculated { "tests/yaffs0_fops " + . " tests/yaffs1 tests/yaffs2 tests/yaffs4 tests/yaffs5 tests/yaffs6" + } + description " + This special option specifies the set of tests to build for YAFFS." + } + + cdl_option CYGSEM_FS_YAFFS_NAND_APPINTERFACE { + display "NAND application interface version required" + flavor data + calculated 2 + no_define + description "This is the version of the NAND application + interface which this package requires. It exists to flag + up changes at the CDL level." + } + +}
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/doc/yaffs.sgml @@ -0,0 +1,681 @@ +<!-- {{{ Banner --> + +<!-- =============================================================== --> +<!-- --> +<!-- yaffs.sgml --> +<!-- --> +<!-- Documentation for the eCos port of the YAFFS filesystem. --> +<!-- --> +<!-- =============================================================== --> +<!-- ####ECOSDOCCOPYRIGHTBEGIN#### --> +<!-- =============================================================== --> +<!-- Copyright (C) 2009 eCosCentric Ltd. --> +<!-- This material may be distributed only subject to the terms --> +<!-- and conditions set forth in the Open Publication License, v1.0 --> +<!-- or later (the latest version is presently available at --> +<!-- http://www.opencontent.org/openpub/) --> +<!-- Distribution of the work or derivative of the work in any --> +<!-- standard (paper) book form is prohibited unless prior --> +<!-- permission obtained from the copyright holder --> +<!-- =============================================================== --> +<!-- ####ECOSDOCCOPYRIGHTEND#### --> +<!-- =============================================================== --> +<!-- #####DESCRIPTIONBEGIN#### --> +<!-- --> +<!-- Author(s): wry --> +<!-- Date: 2009-05-28 --> +<!-- --> +<!-- ####DESCRIPTIONEND#### --> +<!-- =============================================================== --> + +<!-- }}} --> + +<!-- ### Uncomment to make a standalone book: +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"> +<book id="fs-yaffs-book"> + <bookinfo> + <title>The YAFFS filesystem for eCos</title> + <copyright><year>2009</year><holder>eCosCentric Limited</holder></copyright> + <legalnotice> + <title>Documentation licensing terms</title> + <para>This material may be distributed only subject to the terms + and conditions set forth in the Open Publication License, v1.0 + or later (the latest version is presently available at + <ulink url="http://www.opencontent.org/openpub/">http://www.opencontent.org/openpub/</ulink>). + </para> + <para> + Distribution of the work or derivative of the work in any + standard (paper) book form is prohibited unless prior + permission is obtained from the copyright holder. + </para> + </legalnotice> + </bookinfo> + ! /### --> + +<part id="fs-yaffs"> +<title>The YAFFS filesystem</title> + +<chapter id="yaffs-overview-c"> +<title>What is YAFFS?</title> + +<para> +YAFFS is a filesystem for NAND flash chips. +</para> + +<para> +YAFFS is accessed through the FILEIO package which presents a standard +POSIX compatible IO interface through which applications use standard +open(), read(), write() and close() calls. +</para> + +<para> +YAFFS is a <emphasis>journalling</emphasis> filesystem +with <emphasis>wear-levelling</emphasis>. It is +particularly suited to NAND flash parts, having been +designed with their unique properties in mind. +The use of traditional filesystems (FAT, ext2, etc) which do not have +these features is not recommended on such chips because their design +requires the use of fixed address on the underlying hardware. +Such behaviour causes flash sectors to wear out, the consequence of +which would typically be to cause the whole device to become unbootable. +</para> + +<para> +YAFFS also provides a high degree of robustness, which is usually +a requirement of embedded devices. +A power failure or other crash can leave a traditional filesystem +in an inconsistent state which is often difficult to repair, +especially in the field. +</para> + +<para> +YAFFS can also be built into RedBoot, which allows you to store +application images on NAND flash and boot them with +RedBoot's usual flexible scripting system. +</para> + +<para> +For more information about NAND flash chips, +how they differ from NOR flash parts +and other ways to access them, refer to the documentation for the +<xref linkend="io-nand-overview" endterm="io-nand-short">. +</para> + +<para> +For more information about YAFFS itself, refer to +<ulink url="http://www.yaffs.net/">yaffs.net</ulink>. +</para> +</chapter> + +<chapter id="yaffs-getstarted"><title>Getting started with YAFFS</title> + +<sect1 id="yaffs-licensing"><title>Licensing considerations</title> +<para> +Before you can use YAFFS, you must accept its license. +<emphasis>YAFFS is not covered by the standard eCos license.</emphasis> +You will be reminded of your license to use YAFFS when you install it. +</para> + +<para> +Most users will only have access to YAFFS under the GNU GPL. +This costs nothing to license. However this usually means that if you ever +distribute your application, +you must do so under the GPL. +This requires you to publish or otherwise make all of your application, +eCos and everything else you link with it available as source code. +For full details refer to the text of the +<ulink url="http://www.gnu.org/licenses/old-licenses/gpl-2.0.html">GPL +(v2)</ulink>. +</para> + +<para> +If you cannot accept the restrictions and obligations of the GPL, +YAFFS for eCos is available under a proprietary license, for a fee. +Details are available on request from +<ulink url="http://www.ecoscentric.com/">eCosCentric</ulink> or +<ulink url="http://www.yaffs.net/yaffs-licences">Aleph One</ulink>. +</para> +</sect1> + +<sect1 id="yaffs-install"><title>Installation</title> +<para> +YAFFS is supplied as an EPK (eCos Package) file. +</para> + +<sect2 id="yaffs-install-configtool"><title>Installation via the eCos +Configuration Tool</title> +<para> +<orderedlist> +<listitem><para>Open up the eCos Configuration Tool.</para></listitem> +<listitem><para>Open up the <emphasis>Administration</emphasis> dialog, +from the <emphasis>Tools</emphasis> menu.</para></listitem> +<listitem><para>Press the <emphasis>Add</emphasis> button.</para></listitem> +<listitem><para>A file browser windows opens. Navigate to the YAFFS EPK file.</para></listitem> +<listitem><para>The License screen shows. You must accept the license +in order to install the package. Press Yes if you do.</para></listitem> +</orderedlist> +</para> +</sect2> + +<sect2 id="yaffs-install-commandline"><title>Installing from the +command-line</title> +<para> Advanced users may alternatively use the +<filename>ecosadmin.tcl</filename> tool from the command line. You +will be prompted to accept the license at the appropriate time during +the procedure. +</para> + +<programlisting> +tclsh $ECOS_REPOSITORY/ecosadmin.tcl add yaffs-v1_2_3.epk +</programlisting> +</sect2> +</sect1> + +<sect1 id="yaffs-config-build"><title>Configuration and Building</title> +<para> +After installing the EPK, YAFFS is added to your eCos repository +and is configured and built in the normal way. +</para> + +<sect2 id="yaffs-pkg-deps"><title>Package dependencies</title> +<para> +To link YAFFS into your application, +add <filename>CYGPKG_FS_YAFFS</filename> to your eCos +configuration in the normal way, either using the eCos Configuration Tool +(<emphasis>Packages</emphasis> dialog on the <emphasis>Build</emphasis> +menu), or the <filename>ecosconfig</filename> command-line tool.</para> + +<para> +You will also need to add <filename>CYGPKG_IO_NAND</filename> and +<filename>CYGPKG_IO_FILEIO</filename> to your configuration if they +are not already present. +Your platform HAL should supply packages for all NAND device(s) present. +</para> + +<para> +If you started with a smaller template than <emphasis>default</emphasis>, +you may also need to add some of the following:</para> +<itemizedlist> +<listitem><para><filename>CYGPKG_LIBC_STDLIB</filename></para></listitem> +<listitem><para><filename>CYGPKG_LIBC_STRING</filename> </para></listitem> +<listitem><para><filename>CYGPKG_MEMALLOC</filename> or something else +which provides <filename>CYGINT_ISO_MALLOC</filename></para></listitem> +<listitem><para><filename>CYGPKG_LIBC_I18N</filename> or something else +which provides <filename>CYGINT_ISO_CTYPE</filename></para></listitem> +</itemizedlist> +</sect2> + +<sect2 id="yaffs-pkg-options"><title>Configuration options</title> +<para> +YAFFS provides a number of package options, including tuning parameters. +</para> + +<variablelist> +<varlistentry><term><constant>CYGPKG_FS_YAFFS_CFLAGS_ADD</constant></term> +<term><constant>CYGPKG_FS_YAFFS_CFLAGS_REMOVE</constant></term><listitem><para> +These settings allow specific build options to be added to or removed from the CFLAGS +list when building YAFFS.</para></listitem></varlistentry> +<varlistentry><term><constant>CYGSEM_FS_YAFFS_CACHE_SHORT_NAMES</constant></term><listitem><para>If +set, caches files' short names in RAM. This consumes more RAM but +improves performance.</para></listitem></varlistentry> +<varlistentry><term><constant>CYGPKG_FS_YAFFS_RET_DIRENT_DTYPE</constant></term><listitem><para>Controls +whether YAFFS supports setting the <structfield>d_type</structfield> +field in a <structname>struct dirent</structname>. If you don't need +this, leave it switched off to save a little code size.</para></listitem></varlistentry> +<varlistentry><term><constant>CYGNUM_FS_YAFFS_RESERVED_BLOCKS</constant></term><listitem><para> +The number of blocks to keep in reserve to allow for garbage collection +and block failures. The recommended value is 5, but you can tune it +for performance. <emphasis>This setting is a global default and may be +changed by a mount-time option.</emphasis></para></listitem></varlistentry> +<varlistentry><term><constant>CYGNUM_FS_YAFFS_SHORTOP_CACHES</constant></term><listitem><para> +The number of page cache entries to use. Values of 10 to 20 are +recommended; increasing the number consumes more RAM, and 0 disables +it altogether. <emphasis>This setting is a global default and may be +changed by a mount-time option.</emphasis></para></listitem></varlistentry> +<varlistentry><term><constant>CYGNUM_FS_YAFFS_TRACEMASK</constant></term><listitem><para>This +is a 32-bit bitfield which controls diagnostic output. The bit definitions +are found in <filename>yportenv.h</filename>; they are only useful if +you are debugging YAFFS itself.</para></listitem></varlistentry> +<varlistentry><term><constant>CYGNUM_FS_YAFFS_TEMP_BUFFERS</constant></term> +<listitem><para> +YAFFS requires temporary buffers in many places throughout the code. +To avoid the overhead of a dynamic malloc every time, a number of +buffers are preallocated at mount time. This setting controls how many; +should it not prove enough, YAFFS will call malloc on demand as required. +The default setting is 6; most users will not need to change it. +</para></listitem></varlistentry> +<varlistentry><term><constant>CYGSEM_FS_YAFFS_SMALLPAGE_MODE</constant></term> +<listitem><para>This option only affects behaviour on so-called "small page" NAND devices +(those whose pages are 512 bytes long). +Such devices do not have enough space in their Out Of Band area to +store a full set of YAFFS metadata tags. There are two ways to work +around this: <itemizedlist><listitem><para><constant>YAFFS2</constant> mode - +the default - uses regular tags, but at +a price: it steals 16 bytes from the available space per page to store +them. <emphasis>This reduces the apparent available +size of your filesystem by 1/32!</emphasis></para></listitem> +<listitem><para><constant>YAFFS1</constant> mode places a smaller tagset +in the OOB area, but with a different side-effect: whenever a page is +deleted, one byte of the tags area has to be rewritten. Some devices +forbid rewrite-without-erase in this way, so it may not be safe for you +to use this option. <emphasis>You must refer to the spec sheet for the chip on +your board before selecting this option!</emphasis></para></listitem></itemizedlist> +</para></listitem></varlistentry> +<varlistentry><term><constant>CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE</constant></term><listitem><para> +This causes all YAFFS2 code to be omitted from the build. This option only makes sense when +all the devices on which YAFFS is to be used are small-page and operating in YAFFS1 mode. +<note><para>There is no corresponding option to omit YAFFS1 code, because that code is only +compiled when <constant>CYGSEM_FS_YAFFS_SMALLPAGE_MODE</constant> is set to YAFFS1. </para></note> +</para></listitem></varlistentry> +</variablelist> +</sect2> +</sect1> + +<sect1 id="yaffs-using"><title>Using YAFFS</title> +<para> +YAFFS appears in the eCos filesystem table. +This means that you can mount a filesystem in the standard Unix-like way, +then interact with it with calls to open, read, etc. +</para> + +<sect2 id="yaffs-mounting"><title>Mounting a filesystem</title> + +<para> +Before you can use a filesystem, it must be <emphasis>mounted</emphasis>. +</para> + +<para> +A NAND device is logically organised as one or more +<emphasis>partitions</emphasis>, which are +usually set up by the relevant platform HAL. +You need to tell the mount command +which device and partition you wish to access. In the following example, +we are mounting partition 0 of the <emphasis>onboard</emphasis> NAND device. +</para> +<!-- FIXME: Update if partition naming is changed. --> + +<programlisting> +rv = mount("onboard/0", "/nand", "yaffs"); +</programlisting> + +<note><para>The <emphasis>device</emphasis> argument to the +<function>mount</function> call is a NAND-specific device name, not +an entry in /dev. +Refer to the documentation for your platform HAL for details of how +the NAND device(s) are named, and to the NAND library documentation +for details of how partitions are addressed. +</para></note> + +<para> +You can, if you wish, make the filesystem mounting automatic at +static constructor time with the MTAB_ENTRY macro. (Your platform +HAL may already do this; check it carefully.) +</para> + +<programlisting> +MTAB_ENTRY(my_nand, "/nand", "yaffs", "onboard/0", "", 0); +</programlisting> + +<note><para>This example is for eCosPro. In eCos, the MTAB_ENTRY macro +takes only four arguments.</para></note> + +<sect3 id="yaffs-mount-options"><title>Mount-time options</title> +<para> +eCosPro allows various options to be passed to a filesystem at mount time, +by combining them with the filesystem argument in a particular format. +YAFFS understands the following options: +</para> + +<itemizedlist> +<listitem><para><constant>reserved</constant>=<int> The number of +physical NAND blocks to reserve for garbage collection and block failures +(minimum 2). The default is set in CDL as +<constant>CYGNUM_FS_YAFFS_RESERVED_BLOCKS</constant>.</para></listitem> +<listitem><para><constant>caches</constant>=<int> The number of +page cache entries to use. +Values of 10 to 20 are recommended. +The default is set in CDL as +<constant>CYGNUM_FS_YAFFS_SHORTOP_CACHES</constant>.</para></listitem> +<listitem><para><constant>skip-checkpoint-read</constant> Instructs YAFFS +to not attempt to reload the filesystem from a checkpoint, if one exists. +In other words, this option forces a full filesystem scan whether or not +one is necessary.</para></listitem> +</itemizedlist> +</sect3> +</sect2> + +<sect2 id="yaffs-sync"><title>Data flushing</title> +<para> +YAFFS operates a cacheing layer in order to save undue wear on the +NAND chip if many small writes are performed. Because of this, +if you wish to ensure that any data written to a still-open file has +been fully flushed, you must make a synchronisation request. This is +done with the <function>fsync</function> function, which takes as its +argument the file descriptor of the file you wish to synchronise.</para> +</sect2> + +<sect2 id="yaffs-checkpointing"><title>Checkpointing</title> +<para> +When mounting a filesystem, YAFFS has to scan the NAND chip to recreate +its internal state. This can be a slow process, but is made much +faster if there is a valid <emphasis>checkpoint</emphasis>. +</para> + +<para> +A checkpoint is written out automatically when you unmount the filesystem. +At any other time, you can manually force a checkpoint to be written +with one of the following functions: +</para> + +<itemizedlist> +<listitem><para><function>cyg_fs_fssync(mountpoint)</function> +synchronises a filesystem (automatically called on umount)</para></listitem> +<listitem><para><function>sync</function> synchronises all mounted +filesystems.</para></listitem> +</itemizedlist> + +<note><para> +A checkpoint becomes invalid as soon as there have been any other writes +to the filesystem. Finding a good place to sync is necessarily dependent +on your application logic.</para> +</note> +</sect2> + +<sect2 id="yaffs-limitations"><title>Limitations</title> +<para> +Although YAFFS is a Unix-compatible filesystem, the eCos port does not +provide support for the full range of Unix attributes. +</para> +<itemizedlist> +<listitem><para> eCos does not check file or directory permissions; +everything it creates is given fixed user and group IDs of zero and +standard permissions (files rw-r--r--, directories rwxr-xr-x).</para></listitem> +<listitem><para> It is not currently possible to change file ownership +or permissions.</para></listitem> +<listitem><para> It is not currently possible to create symbolic links, +FIFOs (named pipes), sockets or device nodes.</para></listitem> +<listitem><para> Hard links to files work in the expected way. Hard +links to directories are forbidden.</para></listitem> +<listitem><para> It is not possible to unlink the '.', '..' or +'lost+found' special directories.</para></listitem> +</itemizedlist> + +<note><para> +If you will be sharing a YAFFS filesystem between eCos and some other +operating system, you are advised to carefully check the other system's +definitions of mode (permission) bits and whether any translation may be +required.</para> +</note> +</sect2> +</sect1> + +<sect1 id="yaffs-mem-reqs"><title>Memory requirements</title> +<para> +The amount of RAM required by YAFFS to hold its in-memory data structures +grows with the number of objects (files and directories) in your +filesystem. +You are recommended to test your application thoroughly to ensure +that sufficient memory exists for YAFFS to operate with the +most complicated filesystem it is likely to encounter.</para> + +<para> +If you wish to estimate your RAM usage, the YAFFS author provides the +following calculation:</para> + +<itemizedlist> +<listitem><para> The partition itself requires a yaffs_DeviceStruct of 3608 +bytes.</para></listitem> +<listitem><para> If CYGNUM_FS_YAFFS_SHORTOP_CACHES is enabled, each +is the size of a NAND page plus 28 bytes.</para></listitem> +<listitem><para> Every object (file, directory or hardlink) in the +filesystem takes a yaffs_Object struct, which is 124 bytes.</para></listitem> +<listitem><para> Every page of every file requires a Tnode entry, but +they are always allocated in groups of 16 at a time.</para> + <itemizedlist> + <listitem><para>The size of a single Tnode entry is the + number of <emphasis>bits</emphasis> required to number all the + pages in the NAND partition YAFFS is using, numbering from + <emphasis>one</emphasis>; this is rounded up to a multiple of 2, + and has an absolute minimum of sixteen bits.</para></listitem> + <listitem><para>For example: on a partition with 65536 pages, + seventeen bits are required for the numbering, which round up to + 18. Therefore each file takes 288 bits (36 bytes) per group of Tnodes, + and one group of Tnodes will cover up to sixteen pages of data.</para></listitem> + </itemizedlist> + </listitem> +</itemizedlist> + +<note><para><emphasis>Actual memory consumption will be slightly +higher than suggested by the above.</emphasis> This arises from the +tree structure holding the Tnodes, overheads from the heap itself, +and so on.</para></note> + +<para> +YAFFS calls the standard <function>malloc</function> function to allocate +memory and <function>free</function> to release it. Normally, the eCos +heap occupies all spare RAM not needed for the program, its static +data or the stacks. Therefore, most applications will not need to do +anything special beyond ensuring there is enough spare RAM available on +the platform.</para> + +<tip><para> +If you wish to experiment with restricted-size heaps to determine +much memory your application actually uses under YAFFS, +you may find the option +<constant>CYGSEM_MEMALLOC_INVOKE_OUT_OF_MEMORY</constant> of use. +</para></tip> + +<sect2 id="yaffs-mem-reqs-example"><title>Worked example</title> +<para> +Consider a YAFFS filesystem hosted by a NAND partition with 65536 pages, +each of size 2k, using the default setting of ten short-op caches. +On this filesystem we shall store 10000 files each of +size 10240 bytes, hence each requires a single group of Tnodes. +</para> + +<table frame=all pgwide=0><title>YAFFS RAM use worked example</title> +<tgroup cols=2> +<colspec colname=c1> +<colspec colname=c2> +<thead><row> +<entry>Consumer</entry> +<entry>RAM used (bytes)</entry> +</row></thead> +<tfoot><row> +<entry>Total</entry> +<entry align=right> 1,624,368 </entry> +</row></tfoot> +<tbody> +<row> +<entry> yaffs_DeviceStruct </entry> +<entry align=right> 3,608 </entry> +</row> +<row> +<entry> Short-op caches @ 10 x (2048+28)</entry> +<entry align=right> 20,760 </entry> +</row> +<row> +<entry> yaffs_Objects @ 10,000 x 124 </entry> +<entry align=right> 1,240,000 </entry> +</row> +<row> +<entry> Tnode groups @ 10,000 x 36 <emphasis>(see above)</emphasis></entry> +<entry align=right> 360,000 </entry> +</row> +</tbody> +</tgroup> +</table> + +<para> +This example is a close match to the actual consumption measured by +eCosCentric during testing. (The measured consumption as reported +by <function>mallinfo</function> was 1,681,112 bytes, which includes +the heap's own overheads.) +</para> +</sect2> +</sect1> + +<sect1 id="yaffs-testing"><title>Testing</title> +<para> +YAFFS is supplied with a number of test programs, some of which are have been +adapted from tests for other filesystems in eCos. +</para> + +<glosslist> +<glossentry><glossterm>fops</glossterm><glossdef><para> +This was the first basic test created for the port of the filesystem. +It is believed to exercise all of the code paths (filesystem operations, +file operations and directory operations) within the eCos-YAFFS +adaptation layer. </para> <para> +This test was originally intended to run on a synthetic NAND filesystem. +On real NAND chips, it deliberately omits the more stressful routines to +avoid undue wear on the hardware. +</para></glossdef></glossentry> +<glossentry><glossterm>yaffs1</glossterm><glossdef><para> +A number of filesystem edge-case semantic tests, including +file and directory creation and deletion, +invalid open and rename operations, and +removing nonexistent files and directories. +</para></glossdef></glossentry> +<glossentry><glossterm>yaffs2</glossterm><glossdef><para> +Concurrent multi-threaded filesystem access and consistency checks. +</para></glossdef></glossentry> +<glossentry><glossterm>yaffs4</glossterm><glossdef><para> +Semantic and edge-case testing - like yaffs1 - but with long file names. +</para></glossdef></glossentry> +<glossentry><glossterm>yaffs5</glossterm><glossdef><para> +Tests that file reading and writing works over reasonably large files +(up to 1Mbyte) with different I/O chunk sizes. Some operation timings +are collected and reported, as is the data rate on large files. +</para></glossdef></glossentry> +<glossentry><glossterm>yaffs6</glossterm><glossdef><para> +Semantic and edge-case testing - like yaffs1 - but with Cyrillic filenames +in order to test UTF-8 correctness. +</para></glossdef></glossentry> +<glossentry><glossterm>mounttime</glossterm><glossdef><para> +A simple benchmark which repeatedly mounts and unmounts the filesystem +and measures how long this takes. +You can optionally use the <filename>mkfiles</filename> routine - also +present in the tests directory - to create many short files so you can +test performance on a loaded filesystem. +</para></glossdef></glossentry> +<glossentry><glossterm>hammer</glossterm><glossdef><para> +A stress test designed to shake out corner cases. +Repeatedly creates many files of varying sizes from multiple threads +until the filesystem fills up, then verifies their contents and removes +them. From time to time, all threads pause and the filesystem is +unmounted and remounted. </para><para>This test is particularly useful when +combined with the bad block injection functionality provided by +the synthetic NAND device. It has been used in this way by eCosCentric to +thoroughly test this package's stability under error conditions. +<note><para>This test runs forever, until interrupted.</para></note> +</para></glossdef></glossentry> +</glosslist> +</sect1> +</chapter> + +<chapter id="yaffs-redboot"><title>Using YAFFS with RedBoot</title> +<para> +It is possible to link YAFFS into RedBoot and use it to boot an +executable image stored on a NAND array. +</para> + +<para> +This is done by configuring and building RedBoot largely in the normal way. +You will need to add <filename>CYGPKG_FS_YAFFS</filename> and +<filename>CYGPKG_IO_FILEIO</filename> to your configuration, plus their +attendant dependencies. +</para> + +<para> +The presence of CYGPKG_IO_FILEIO activates the <filename>fs</filename> series +of RedBoot commands. The following (edited) transcript illustrates how +they might +be used in concert with other RedBoot commands to store an ELF image on +a NAND partition, load it back and execute: +</para> + +<programlisting> +RedBoot> fs mount -d onboard/0 -t yaffs /nand +yaffs: restored from checkpoint +RedBoot> load -r -h my.tftp.ip.address -b %{freememlo} my.image +Using default protocol (TFTP) +Raw file loaded 0xa013f000-0xa01554b3, assumed entry at 0xa013f000 +RedBoot> fs write /nand/myimg.elf +RedBoot> fs list /nand + 1 drwxr-xr-x 0 size 0 . + 1 drwxr-xr-x 0 size 0 .. + 262 -rw-r--r-- 0 size 91316 myimg.elf + 2 drwxr-xr-x 0 size 0 lost+found +RedBoot> load -m file /nand/myimg.elf +RedBoot> go +Hello, NAND world! +</programlisting> + +<note><para>When you command RedBoot to execute an image, it +first synchronises all mounted filesystems. Therefore, +provided these filesystems support the synchronisation operation +(which YAFFS does), it is not always necessary to unmount them before +invoking an image. +</para> +</note> + +<sect1 id="yaffs-rb-mem"><title>Memory considerations under RedBoot</title> +<para> +RedBoot traditionally has very limited requirements for memory management; +the main need is for there to be free space in RAM at the correct +(physical) address to load an image before jumping to it. +</para> + +<para> +Introducing YAFFS brings with it not just the need to have dynamically +allocatable RAM (<filename>CYGPKG_MEMALLOC</filename>), but enough +to replay the filesystem journal. This must be balanced against the need +for RAM to load images into. +</para> + +<para> +When the <filename>CYGPKG_MEMALLOC</filename> package is present in +RedBoot, by default a small (64k) heap is set up so that the maximum RAM +possible is available for loading images. This is not enough to +support YAFFS in any circumstances, so the following definition has +been included in the <filename>yaffs.cdl</filename> file: +</para> + +<programlisting> +requires { CYGPKG_REDBOOT implies (CYGMEM_REDBOOT_WORKSPACE_HEAP_SIZE >= 0x00014000) } +</programlisting> + +<caution><para> +This declaration only provideds the bare minimum heap required to mount a +trivial YAFFS filesystem. More will be required for all but the simplest +of cases and it is recommended that you test for typical use in your +environment. Refer also to <xref linkend="yaffs-mem-reqs">. +</para></caution> + +<para> +It is recommended that, should you wish to make a filesystem usable by +RedBoot, your platform HAL should make a similar +declaration in its CDL to establish an appropriate heap size. + +For example, the platform HAL for the EA LPC2468 OEM board - which has +a 128MB NAND chip on-board - contains the following declaration: +</para> + +<programlisting> +requires { (CYGPKG_REDBOOT && CYGPKG_FS_YAFFS) implies (CYGMEM_REDBOOT_WORKSPACE_HEAP_SIZE >= 0x20000) } +</programlisting> + +<tip><para> +If you wish to experiment with restricted heaps to determine +much memory your application actually uses under YAFFS, +you may find the option +<constant>CYGSEM_MEMALLOC_INVOKE_OUT_OF_MEMORY</constant> of use. +</para></tip> +</sect1> +</chapter> +</part> + +<!-- ### Uncomment to make a standalone book: +</book> + /### -->
--- a/packages/fs/yaffs/current/src/devextras.h +++ b/packages/fs/yaffs/current/src/devextras.h @@ -20,6 +20,8 @@ * */ +#include "ecos-yaffs.h" + #ifndef __EXTRAS_H__ #define __EXTRAS_H__
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/src/ecos-yaffs-diriter.c @@ -0,0 +1,89 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2010 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +//============================================================================= +// +// ecos-yaffs-diriter.c +// +// Directory Iterator support for the eCos-YAFFS adaptation layer +// +//============================================================================= +// +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-05-07 +// Note: This file is a derivative work of direct/yaffsfs.c and so +// should be taken as inheriting its license terms - hence the +// copyright banner above. +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include "ecos-yaffs-diriter.h" +#include <cyg/infra/cyg_ass.h> + +// Directory operations -------------------------------------------------- + +struct ylist_head eyaffs_all_diriters; + +void eyaffs_diriter_advance(eyaffs_diriter *ctx) +{ + CYG_ASSERT(ctx && ctx->node && ctx->node->variantType == YAFFS_OBJECT_TYPE_DIRECTORY, "node not a directory"); + if ( !ctx->nextret ) return; // already finished, nothing to do + + struct ylist_head * top = &ctx->node->variant.directoryVariant.children; + + if (ylist_empty(top)) { + ctx->nextret = NULL; + return; + } + + struct ylist_head *next = ctx->nextret->siblings.next; + + if( next == top ) // finished + ctx->nextret = NULL; + else + ctx->nextret = ylist_entry(next,yaffs_Object,siblings); // works backwards from 'next' to its containing y_Object +} + +void eyaffs_diriter_rewind(eyaffs_diriter *ctx) +{ + CYG_ASSERT(ctx && ctx->node && ctx->node->variantType == YAFFS_OBJECT_TYPE_DIRECTORY, "node not a directory"); + + struct ylist_head * top = &ctx->node->variant.directoryVariant.children; + if (ylist_empty(top)) + ctx->nextret = NULL; + else + ctx->nextret = ylist_entry(top->next, yaffs_Object, siblings); +} + +void eyaffs_diriter_objremove_callback(yaffs_Object *obj) +{ + struct ylist_head *i; + eyaffs_diriter *cur; + + if(!eyaffs_all_diriters.next) return; // nothing to do + + ylist_for_each(i, &eyaffs_all_diriters) { // foreach ($i) @eyaffs_all_diriters + if (i) { + // 'i' points to the 'iterlist' member of an eyaffs_diriter, sort out cur to point to it + cur = ylist_entry(i, eyaffs_diriter, iterlist); + + if(cur->nextret == obj) // then fix it up + eyaffs_diriter_advance(cur); + } + } +} +
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/src/ecos-yaffs-diriter.h @@ -0,0 +1,71 @@ +#ifndef CYGONCE_ECOS_YAFFS_DIRITER_H +#define CYGONCE_ECOS_YAFFS_DIRITER_H +//============================================================================= +// +// ecos-yaffs-diriter.h +// +// Directory Iterator support for the eCos-YAFFS adaptation layer +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos 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 or (at your option) any later +// version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-05-07 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include "yaffs_guts.h" + +// Directory operations -------------------------------------------------- + +/* Directory iterator used by readdir(). + * We need to keep track of all live diriters so as to avoid jumping off + * to Fishkill in the event that our next-object-to-return is deleted. + * Thankfully, yaffs provides a callback mechanism so we can detect + * this case. */ +typedef struct eyaffs_diriter { + struct ylist_head iterlist; // doubly linked list, impl by devextras.h + yaffs_Object * node; + yaffs_Object * nextret; // next one to return +} eyaffs_diriter; + +extern struct ylist_head eyaffs_all_diriters; + +void eyaffs_diriter_advance(eyaffs_diriter *ctx); +void eyaffs_diriter_rewind(eyaffs_diriter *ctx); +void eyaffs_diriter_objremove_callback(yaffs_Object *obj); + +#endif //CYGONCE_ECOS_YAFFS_DIRITER_H
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/src/ecos-yaffs-nand.c @@ -0,0 +1,283 @@ +//============================================================================= +// +// ecos-yaffs-nand.c +// +// Glue for YAFFS to the eCos NAND library +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos 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 or (at your option) any later +// version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-05-07 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include "ecos-yaffs.h" +#include "ecos-yaffs-nand.h" +#include "yaffs_packedtags1.h" +#include "yaffs_packedtags2.h" +#include "yaffs_tagscompat.h" +#include "yaffs_trace.h" +#include <cyg/nand/util.h> // for BLOCK2PAGEADDR + +int eyaffs_initialiseNAND (struct yaffs_DeviceStruct * dev) +{ + // Nothing to do - we've already inited it in mount(). + //cyg_nand_partition *part = (cyg_nand_partition*) dev->genericDevice; + return YAFFS_OK; +} + +int eyaffs_deinitialiseNAND (struct yaffs_DeviceStruct * dev) +{ + // Nothing to do + //cyg_nand_partition *part = (cyg_nand_partition*) dev->genericDevice; + return YAFFS_OK; +} + +int eyaffs_eraseBlockInNAND (struct yaffs_DeviceStruct * dev, int blockInNAND) +{ + cyg_nand_partition *part = yaffs_DeviceToContext(dev); + int rv = cyg_nandp_erase_block(part, blockInNAND); + return rv==0 ? YAFFS_OK : YAFFS_FAIL; +} + +int eyaffs_writeChunkWithTagsToNAND (struct yaffs_DeviceStruct * dev, + int chunkInNAND, const __u8 * data, + const yaffs_ExtendedTags * tags) +{ + cyg_nand_partition *part = yaffs_DeviceToContext(dev); + int rv; + + if (!dev->param.isYaffs2) { +#ifdef CONFIG_YAFFS_NO_YAFFS1 + rv = 1; +#else + yaffs_PackedTags1 pt1; + + if (tags->chunkDeleted) { + memset(&pt1, 0xff, sizeof(pt1)); + pt1.deleted = 0; + //((CYG_BYTE*)&pt1)[8] = 0; // TODO: support 9BYTE_TAGS, if there is a demand to (requires corresponding fixup in the ECC check below) + } else { + yaffs_PackTags1(&pt1, tags); + yaffs_CalcTagsECC((yaffs_Tags *)&pt1); + } + rv = cyg_nandp_write_page(part, chunkInNAND, data, &pt1, PACKEDTAGS1_OOBSIZE); +#endif + } else { +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE + return YAFFS_FAIL; +#else + // YAFFS2 mode. + // N.B. We are not doing ECC - the NAND layer does that - so don't + // need to bother with the whole tags struct, just the bit that matters. + + if (!data || !tags) { + T(YAFFS_TRACE_ERROR, + (TSTR("**>> yaffs2: both data and tags must be present" TENDSTR))); + YBUG(); + return YAFFS_FAIL; + } + + if (dev->param.inbandTags) { + yaffs_PackedTags2TagsPart *pt2tp; + pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk); + yaffs_PackTags2TagsPart(pt2tp, tags); + rv = cyg_nandp_write_page(part, chunkInNAND, data, 0, 0); + } else { + yaffs_PackedTags2 pt; + void *packed_tags_ptr = dev->param.noTagsECC ? (void*) &pt.t : (void*) &pt; + yaffs_PackTags2(&pt, tags, !dev->param.noTagsECC); + rv = cyg_nandp_write_page(part, chunkInNAND, data, packed_tags_ptr, PACKEDTAGS2_OOBSIZE(dev)); + } +#endif + } + + // all done: + return rv==0 ? YAFFS_OK : YAFFS_FAIL; +} + +int eyaffs_readChunkWithTagsFromNAND (struct yaffs_DeviceStruct * dev, + int chunkInNAND, __u8 * data, + yaffs_ExtendedTags * tags) +{ + cyg_nand_partition *part = yaffs_DeviceToContext(dev); + int localData = 0; + int rv; + + if (!dev->param.isYaffs2) { +#ifdef CONFIG_YAFFS_NO_YAFFS1 + rv = 1; +#else + yaffs_PackedTags1 pt1; + memset(&pt1, 0xff, sizeof(yaffs_PackedTags1)); + + rv = cyg_nandp_read_page(part, chunkInNAND, data, &pt1, PACKEDTAGS1_OOBSIZE); + + if (rv == 0) { + if (yaffs_CheckFF((CYG_BYTE*)&pt1, 8)) { + // block is empty + if (tags) { + memset(tags, 0, sizeof(*tags)); + tags->eccResult = YAFFS_ECC_RESULT_NO_ERROR; + } + } else { + // must check and correct tags' mini-ecc. + int deleted = !pt1.deleted; // this would break the tags ECC. + pt1.deleted = 1; + // TODO: support 9BYTE_TAGS if there is a demand. + int rv2 = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1); + if (rv2 < 0) { + T(YAFFS_TRACE_ERROR, + (TSTR ("**>>yaffs ecc error unfixed on chunk %d:0" + TENDSTR), chunkInNAND)); + dev->eccUnfixed++; + rv = EIO; + } else { + if (tags) { + yaffs_UnpackTags1(tags, &pt1); + tags->chunkDeleted = deleted; + tags->eccResult = YAFFS_ECC_RESULT_NO_ERROR; + } + + if (rv2 > 0) { + T(YAFFS_TRACE_ERROR, + (TSTR ("**>>yaffs ecc tags error fix performed on chunk %d:0" + TENDSTR), chunkInNAND)); + dev->eccFixed++; + if (tags) + tags->eccResult = YAFFS_ECC_RESULT_FIXED; + } + } + } + } // else reading the NAND failed; drop out +#endif + + } else { // YAFFS2 mode +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE + return YAFFS_FAIL; +#else + if (dev->param.inbandTags) { + if (!data) { + localData = 1; + data = yaffs_GetTempBuffer(dev, __LINE__); + } + + rv = cyg_nandp_read_page(part, chunkInNAND, data, 0, 0); + if (tags) { + yaffs_PackedTags2TagsPart *pt2tp; + pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk]; + yaffs_UnpackTags2TagsPart(tags, pt2tp); + } + } else { + yaffs_PackedTags2 pt; + void *packed_tags_ptr = dev->param.noTagsECC ? (void*) &pt.t : (void*) &pt; + rv = cyg_nandp_read_page(part, chunkInNAND, data, packed_tags_ptr, tags ? PACKEDTAGS2_OOBSIZE(dev) : 0); + if (tags) + yaffs_UnpackTags2(tags, &pt, !dev->param.noTagsECC); + } +#endif + } + + // all done: + if (localData) + yaffs_ReleaseTempBuffer(dev, data, __LINE__); + + if (rv != 0) { + if (tags) { + // mark the tags as clearly useless + memset(tags, 0, sizeof(yaffs_ExtendedTags)); + tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; + tags->blockBad = 1; + } + return YAFFS_FAIL; + } + return YAFFS_OK; + // TODO: go through yaffs_guts and ensure that all calls to ReadChunksWithTagsFromNAND DTRT on FAIL or if the read tags aren't valid. +} + +int eyaffs_markNANDBlockBad (struct yaffs_DeviceStruct * dev, int blockNo) +{ + cyg_nand_partition *part = yaffs_DeviceToContext(dev); + int rv = cyg_nandp_bbt_markbad(part, blockNo); + return rv==0 ? YAFFS_OK : YAFFS_FAIL; +} + +int eyaffs_queryNANDBlock (struct yaffs_DeviceStruct * dev, int blockNo, + yaffs_BlockState * state, __u32 *sequenceNumber) +{ + yaffs_ExtendedTags tags; + cyg_nand_page_addr pg; + cyg_nand_partition *part = yaffs_DeviceToContext(dev); + + int rv = cyg_nandp_bbt_query(part, blockNo); + if (rv < 0) return YAFFS_FAIL; + + switch(rv) { + case CYG_NAND_BBT_OK: + // Now we need to read the tags from the OOB area of the first page + pg = CYG_NAND_BLOCK2PAGEADDR(part->dev, blockNo); + // TODO: This is quite inefficient on small page devices in + // YAFFS2 mode with inbandTags enabled, as the whole page has + // to be read. Some day, it would be nice to implement part-page + // reads in the NAND layer where this can be efficiently done. + int rv2 = eyaffs_readChunkWithTagsFromNAND(dev, pg, 0, &tags); + if (rv2 == YAFFS_FAIL) { + (void) cyg_nandp_bbt_markbad(part, blockNo); + goto deadblock; + } + if (tags.chunkUsed) { + *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; + *sequenceNumber = tags.sequenceNumber; + return YAFFS_OK; + } + *state = YAFFS_BLOCK_STATE_EMPTY; + *sequenceNumber = 0; + return YAFFS_OK; + + case CYG_NAND_BBT_WORNBAD: + case CYG_NAND_BBT_RESERVED: + case CYG_NAND_BBT_FACTORY_BAD: + deadblock: + *state = YAFFS_BLOCK_STATE_DEAD; + *sequenceNumber = 0; + return YAFFS_OK; + default: + YBUG(); // can't happen + return YAFFS_FAIL; + } +} +
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/src/ecos-yaffs-nand.h @@ -0,0 +1,84 @@ +#ifndef CYGONCE_ECOS_YAFFS_NAND_H +#define CYGONCE_ECOS_YAFFS_NAND_H +//============================================================================= +// +// ecos-yaffs-nand.h +// +// Glue for YAFFS to the eCos NAND library +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos 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 or (at your option) any later +// version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-05-07 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/nand/nand.h> +#include "yaffs_guts.h" // extendedTags +#include "devextras.h" // __u8 and __u32 + +// If writing a yaffs_PackedTags1, we store only its eight meaningful bytes +#define PACKEDTAGS1_OOBSIZE 8 +#define PACKEDTAGS2_OOBSIZE(dev) (dev->param.noTagsECC ? \ + (unsigned)sizeof(yaffs_PackedTags2TagsPart) : \ + (unsigned)sizeof(yaffs_PackedTags2)) + +int eyaffs_eraseBlockInNAND (struct yaffs_DeviceStruct * dev, int blockInNAND); +int eyaffs_initialiseNAND (struct yaffs_DeviceStruct * dev); +// not mandatory: +int eyaffs_deinitialiseNAND (struct yaffs_DeviceStruct * dev); + +#ifdef CYGSEM_FS_YAFFS_SMALLPAGE_MODE_YAFFS1 +int eyaffs_writeChunkToNAND(struct yaffs_DeviceStruct *dev, + int chunkInNAND, const __u8 *data, + const yaffs_Spare *spare); +int eyaffs_readChunkFromNAND(struct yaffs_DeviceStruct *dev, + int chunkInNAND, __u8 *data, + yaffs_Spare *spare); +#endif + +int eyaffs_writeChunkWithTagsToNAND (struct yaffs_DeviceStruct * dev, + int chunkInNAND, const __u8 * data, + const yaffs_ExtendedTags * tags); +int eyaffs_readChunkWithTagsFromNAND (struct yaffs_DeviceStruct * dev, + int chunkInNAND, __u8 * data, + yaffs_ExtendedTags * tags); +int eyaffs_markNANDBlockBad (struct yaffs_DeviceStruct * dev, int blockNo); +int eyaffs_queryNANDBlock (struct yaffs_DeviceStruct * dev, int blockNo, + yaffs_BlockState * state, __u32 *sequenceNumber); + +#endif //CYGONCE_ECOS_YAFFS_NAND_H
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/src/ecos-yaffs.c @@ -0,0 +1,1052 @@ +//============================================================================= +// +// ecos-eyaffs.c +// +// eyaffs interface to the eCos filesystem layer +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009-2010 eCosCentric Limited. +// +// eCos 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 or (at your option) any later +// version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-05-05 +// +//####DESCRIPTIONEND#### +//============================================================================= + +/* Major TODO: + * At the moment we tend to look files up by name(dirsearch), perform + * our own sanity checks, then pass on to YAFFS fns which then go and + * repeat the last step of the lookup. IWBNI we exposed corresponding + * YAFFS functions which took yaffs_Object* instead of name. */ + +#include "yportenv.h" +#include "yaffs_guts.h" +#include "yaffs_packedtags2.h" +#include "ecos-yaffs.h" +#include "ecos-yaffs-nand.h" +#include "ecos-yaffs-diriter.h" + +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <unistd.h> +#include <cyg/fileio/fileio.h> +#include <cyg/fileio/dirent.h> +#include <cyg/infra/cyg_ass.h> +#include <cyg/nand/nand.h> +#include <cyg/nand/util.h> + +// convenience error test macros. x should be an ecos error code. +#define ER(x) do { int _x = (x); if (_x != 0) return _x; } while(0) +#define EG(x) do { _err = (x); if (_err != 0) goto err_exit; } while(0) +// ... variants which take a negative ecos error code +#define ERm(x) ER(-(x)) +#define EGm(x) EG(-(x)) +// ... variants for YAFFS ops, which return YAFFS_OK or YAFFS_FAIL +#define YER(x) do { int _x = (x); if (_x == YAFFS_FAIL) return EIO; } while(0) + +// sneaky grab from fileio misc.cxx: +__externC cyg_mtab_entry cyg_mtab[]; +__externC cyg_mtab_entry cyg_mtab_end; + +// For yaffs_guts: +unsigned int yaffs_traceMask = CYGNUM_FS_YAFFS_TRACEMASK; + +// How many attempts do we make to write a page before giving up? +// This could easily be added to CDL. +unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; + +// eCos doesn't support file permissions or user IDs at all. +// We hard-code sensible values in case anybody makes decisions on +// the output from stat() et al. +// (Update: As of March 2009 there is now limited support for chmod in both +// anoncvs and eCosPro.) +#define FIXED_UID 0 +#define FIXED_GID 0 +#define DIRECTORY_FIXED_PERMS (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) +#define FILE_FIXED_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) +// TODO: We could make uid/gid/fixedperms configurable. + +// Helper functions and forward defs ------------------------------------- +static int eyaffs_count_links(yaffs_Object * node) +{ + int links = 0; + struct ylist_head *tmp; + ylist_for_each(tmp, &(node->hardLinks)) { + ++links; + } + return links; +} + +static int eyaffs_stat_object(yaffs_Object *node, struct stat *buf); + +// Directory search / traversal ------------------------------------------ +typedef struct ey_dirsearch +{ + yaffs_Object *dir; // directory to search + const char *path; // path to follow + yaffs_Object *node; // Node found + const char *name; // last name used + int namelen;// name fragment length + cyg_bool last; // last name in path? +} ey_dirsearch; + +static void init_dirsearch(ey_dirsearch *ds, yaffs_Object *dir, const char *name) +{ + ds->dir = dir; + ds->path = name; + ds->node = dir; + ds->name = name; + ds->namelen = 0; + ds->last = false; +} + +// Search a single directory for the next name in a path +static int find_entry(ey_dirsearch *ds) +{ + yaffs_Object *dir = ds->dir; + const char *name = ds->path; + const char *n = name; + char namelen = 0; + + yaffs_Object *d; + + // check that we really have a directory + switch (yaffs_GetObjectType(dir)) { + case DT_DIR: break; + + case DT_LNK: // TODO: symlink support + default: return ENOTDIR; + } + + // Isolate the next element of the path name. + while( *n != '\0' && *n != '/' ) + n++, namelen++; + + // Check if this is the last path element. + while( *n == '/') n++; + if( *n == '\0' ) + ds->last = true; + + // update name in dirsearch object + ds->name = name; + ds->namelen = namelen; + + // First, special case "." and "..": + if (name[0] == '.') { + if (namelen == 1) { // "." + ds->node = dir; + return ENOERR; + } else if (name[1] == '.' && namelen == 2) { // ".." + ds->node = dir->parent; + if (!ds->node) ds->node = dir; // ".." at the root stays in the root + return ENOERR; + } + } + + // Otherwise, search the directory for a matching entry + YCHAR namebuf[YAFFS_MAX_NAME_LENGTH+1]; + memcpy(namebuf, name, namelen); + namebuf[(int)namelen]=0; + + d = yaffs_FindObjectByName(dir, namebuf); + // TODO: Create a variant of y_FindObjectByName which takes dir, name and len. Indeed, that would be beneficial for a lot of its functions. + if( d == NULL ) return ENOENT; + d = yaffs_GetEquivalentObject(d); // traverse hardlinks + + // pass back the node we have found + ds->node = d; + + return ENOERR; +} + +/* Main directory search code. Use init_dirsearch() to init the struct. + * If we return with d->last set, d->name _might_ be null-terminated. + * (It will iff no trailing slashes were passed in.) + * Code that acts on the output name MUST use d->namelen and not assume + * null-termination without testing first. + */ +static int eyaffs_find(ey_dirsearch *d) +{ + if ( *(d->path) == 0 ) + return ENOERR; + for (;;) { + ER(find_entry(d)); + if (d->last) return ENOERR; + // Not done yet? Next one down... + d->dir = d->node; + d->path += d->namelen; + // While we could check file perms here, eCos doesn't support them. + while ( *(d->path) == '/' ) ++d->path; // skip separators + } +} + +// File operations -------------------------------------------------------- + +static int eyaffs_pathconf(yaffs_Object *node, struct cyg_pathconf_info *info) +{ + switch(info->name) { + case _PC_LINK_MAX: + info->value = LINK_MAX; + return ENOERR; + + case _PC_NAME_MAX: + info->value = YAFFS_MAX_NAME_LENGTH; + return ENOERR; + + case _PC_PATH_MAX: + info->value = PATH_MAX; + return ENOERR; + + case _PC_PRIO_IO: + case _PC_SYNC_IO: + info->value=0; + return ENOERR; + + case _PC_NO_TRUNC: + info->value=1; + return ENOERR; + + case _PC_MAX_CANON: // terminals only + case _PC_MAX_INPUT: // terminals + case _PC_PIPE_BUF: // pipes + case _PC_ASYNC_IO: // not supported + case _PC_CHOWN_RESTRICTED: // we don't track owners + case _PC_VDISABLE: // terminals + default: + info->value = -1; + return EINVAL; + } +} + +static int eyaffs_fo_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) +{ + yaffs_Object *node = (yaffs_Object*) fp->f_data; + int i; + off_t pos = fp->f_offset; + ssize_t resid = uio->uio_resid; + + for (i=0; i < uio->uio_iovcnt; i++) { + cyg_iovec *iov = &uio->uio_iov[i]; + unsigned char *buf = iov->iov_base; + off_t len = iov->iov_len; + + if (pos + len > node->variant.fileVariant.fileSize) + len = node->variant.fileVariant.fileSize - pos; + + while (len > 0 && pos < node->variant.fileVariant.fileSize) { + off_t l = yaffs_ReadDataFromFile(node, buf, pos, len); + len -= l; + pos += l; + buf += l; + resid -= l; + } + } + uio->uio_resid = resid; + fp->f_offset = pos; + return ENOERR; +} + +static int eyaffs_fo_write (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) +{ + yaffs_Object *node = (yaffs_Object*) fp->f_data; + int i; + off_t pos = fp->f_offset; + ssize_t resid = uio->uio_resid; + + if (fp->f_flag & CYG_FAPPEND) + pos = fp->f_offset = node->variant.fileVariant.fileSize; + + CYG_ASSERT(pos >= 0, "pos became negative"); + + for (i=0; i < uio->uio_iovcnt; i++) { + cyg_iovec *iov = &uio->uio_iov[i]; + unsigned char *buf = iov->iov_base; + off_t len = iov->iov_len; + + while (len > 0) { + off_t l = yaffs_WriteDataToFile(node, buf, pos, len, 0); + len -= l; + buf += l; + pos += l; + resid -= l; + + if (l==0) goto stop; // urgh, how does this cope with dire errors? + } + } + + // Timestamps are updated on yaffs_FlushFile() +stop: + uio->uio_resid = resid; + fp->f_offset = pos; + return ENOERR; +} + + +static int eyaffs_fo_lseek (struct CYG_FILE_TAG *fp, off_t *apos, int whence ) +{ + yaffs_Object *node = (yaffs_Object*) fp->f_data; + off_t pos = *apos; + + switch (whence) + { + case SEEK_SET: + // Pos is already where we want to be + break; + case SEEK_CUR: + // Add pos to current offset + pos += fp->f_offset; + break; + case SEEK_END: + // Add pos to file size + pos += node->variant.fileVariant.fileSize; + break; + default: + return EINVAL; + } + + // Check that pos is still within current file size, + // or at the very end + if (pos < 0 || pos > node->variant.fileVariant.fileSize) + return EINVAL; + + *apos = fp->f_offset = pos; + return ENOERR; +} + +static int eyaffs_fo_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, + CYG_ADDRWORD data) +{ + return EINVAL; // No ioctls defined +} + +static int eyaffs_fo_fsync (struct CYG_FILE_TAG *fp, int mode ) +{ + yaffs_Object *node = (yaffs_Object*) fp->f_data; + int ymode = (mode == CYG_FDATASYNC) ? 1 : 0; + YER(yaffs_FlushFile(node,1,ymode)); + return ENOERR; +} + +static int eyaffs_fo_close (struct CYG_FILE_TAG *fp) +{ + yaffs_Object *node = (yaffs_Object*) fp->f_data; + + YER(yaffs_FlushFile(node,1,0)); + if (node->unlinked) { + YER(yaffs_DeleteObject(node)); + } + fp->f_data = 0; + node->myInode = 0; + return ENOERR; +} + +static int eyaffs_fo_fstat (struct CYG_FILE_TAG *fp, struct stat *buf ) +{ + yaffs_Object *node = (yaffs_Object*) fp->f_data; + + return eyaffs_stat_object(node, buf); +} + +static int eyaffs_fo_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len ) +{ + yaffs_Object *node = (yaffs_Object*) fp->f_data; + + switch(key) { + case FS_INFO_CONF: + return eyaffs_pathconf(node, (struct cyg_pathconf_info *)buf ); + } + return EINVAL; +} +static int eyaffs_fo_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len ) +{ + return EINVAL; // None defined +} + +static cyg_fileops eyaffs_fileops = +{ + eyaffs_fo_read, eyaffs_fo_write, + eyaffs_fo_lseek, eyaffs_fo_ioctl, + cyg_fileio_seltrue, + eyaffs_fo_fsync, eyaffs_fo_close, + eyaffs_fo_fstat, + eyaffs_fo_getinfo, eyaffs_fo_setinfo +}; + +// Directory entrypoints -------------- + +static int eyaffs_fo_dirread (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) +{ + eyaffs_diriter *diriter = (eyaffs_diriter*) fp->f_data; + struct dirent *ent = (struct dirent *)uio->uio_iov[0].iov_base; + unsigned offset = fp->f_offset; + off_t len = uio->uio_iov[0].iov_len; + + if( len < sizeof(struct dirent) ) + return EINVAL; + + if (offset == 0) { + strcpy(ent->d_name, "."); +#ifdef CYGPKG_FS_YAFFS_RET_DIRENT_DTYPE + ent->d_type = __stat_mode_DIR; +#endif + goto done; + } + if (offset == 1) { + strcpy(ent->d_name, ".."); +#ifdef CYGPKG_FS_YAFFS_RET_DIRENT_DTYPE + ent->d_type = __stat_mode_DIR; +#endif + goto done; + } + + // else use the iter: + yaffs_Object * node = diriter->nextret; + + if (!node) goto done_eof; + + yaffs_GetObjectName(node, ent->d_name, sizeof(ent->d_name)); +#ifdef CYGPKG_FS_YAFFS_RET_DIRENT_DTYPE + ent->d_type = yaffs_GetObjectType(node); +#endif + eyaffs_diriter_advance(diriter); + +done: + uio->uio_resid -= sizeof(struct dirent); + fp->f_offset++; +done_eof: + return ENOERR; +} + +static int eyaffs_fo_dirlseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence ) +{ + // This is easy, we only allow a full rewind. + if (whence != SEEK_SET || *pos != 0) + return EINVAL; + // get and rewind the diriter + eyaffs_diriter *diriter = (eyaffs_diriter*) fp->f_data; + eyaffs_diriter_rewind(diriter); + fp->f_offset = 0; + return ENOERR; +} + +static int eyaffs_fo_dirclose (struct CYG_FILE_TAG *fp) +{ + eyaffs_diriter *diriter = (eyaffs_diriter*) fp->f_data; + + ylist_del(&diriter->iterlist); + memset(diriter, 0xbb, sizeof(eyaffs_diriter)); + fp->f_data = 0; + YFREE(diriter); + return ENOERR; +} + + +static cyg_fileops eyaffs_dirops = +{ + eyaffs_fo_dirread, + (cyg_fileop_write *)cyg_fileio_enosys, + eyaffs_fo_dirlseek, + (cyg_fileop_ioctl *)cyg_fileio_enosys, + cyg_fileio_seltrue, + (cyg_fileop_fsync *)cyg_fileio_enosys, + eyaffs_fo_dirclose, + (cyg_fileop_fstat *)cyg_fileio_enosys, + (cyg_fileop_getinfo *)cyg_fileio_enosys, + (cyg_fileop_setinfo *)cyg_fileio_enosys +}; + +// Filesystem operations ------------------------------------------------- +// N.B. Function names are prefixed with 'e' to distinguish them from +// those internal to yaffs. + + +static int eyaffs_mount ( cyg_fstab_entry *fste, cyg_mtab_entry *mte ) +{ + int _err = ENOERR; + + cyg_nand_device *nand = 0; + cyg_nand_partition *part = 0; + ERm(cyg_nand_resolve_device(mte->devname, &nand, &part)); + + if (!part || !part->dev || (part->last <= part->first) ) { + TOUT(("eyaffs_mount: Invalid partition\n")); + ER(EINVAL); + } + + // Is this partition already mounted? + cyg_mtab_entry *m = cyg_mtab; + while (m != &cyg_mtab_end) { + if (m->valid + && (0==strcmp(m->fsname,"yaffs")) + && (yaffs_DeviceToContext(m->data) == part) ) { + ER(EBUSY); + /* TODO: Set up a refcount to allow a yaffs/nand fs + * to be mounted multiple times. In that case, + * re-use the existing yaffs device struct. */ + } + m++; + } + + // Option handling. Defaults come from CDL. + int o_nReserved = CYGNUM_FS_YAFFS_RESERVED_BLOCKS; + int o_nShortOpCaches = CYGNUM_FS_YAFFS_SHORTOP_CACHES; + int o_skipCheckpointRead = 0; + +#if !defined(CYGSEM_FS_YAFFS_COMPATIBILITY_ECOSPRO) || (CYGSEM_FS_YAFFS_COMPATIBILITY_ECOSPRO == 1) + // At the time of writing, the options field is not present in eCos. +#else + if (mte->options) { + // If you get a build failure here along the lines of: + // ‘cyg_mtab_entry’ has no member named ‘options’ + // then you probably need to turn off CYGSEM_FS_YAFFS_COMPATIBILITY_ECOSPRO. + int t; + char buf[10]; + // reserved=<int>: Number of blocks to reserve (minimum 2) + if (0==cyg_fs_get_option(mte->options, "reserved", buf, sizeof buf)) { + t = atoi(buf); + if (t>=2 && t <= (part->last - part->first)) + o_nReserved = t; + else + TOUT(("eyaffs_mount: ignoring invalid value `reserved=%d'", t)); + } + // caches=<int>: Number of cache entries to use (10-20 recommended) + if (0==cyg_fs_get_option(mte->options, "caches", buf, sizeof buf)) { + t = atoi(buf); + if (t>=0) + o_nShortOpCaches = t; + else + TOUT(("eyaffs_mount: ignoring invalid value `caches=%d'", t)); + } + // skip-checkpoint-read: Ignore the checkpoint restore and instead + // do a full filesystem scan. + if (0==cyg_fs_get_option(mte->options, "skip-checkpoint-read", buf, sizeof buf)) { + o_skipCheckpointRead = 1; + } + // TODO: readonly option, runtime and/or CDL? + } +#endif // CYGSEM_FS_YAFFS_COMPATIBILITY + +#ifdef CYGPKG_INFRA_DEBUG + // Best-efforts sanity check that there's enough heap. + // The rule of thumb is 2 bytes per page. + struct mallinfo mi = mallinfo(); + unsigned want = ( 1 << (nand->block_page_bits + 1) ) * (1 + part->last - part->first); + if ( mi.fordblks < want) { + TOUT(("eyaffs_mount: warning: arena reports %u bytes free; %u recommended for this device\n", mi.fordblks, want)); + } + +#endif + + yaffs_Device *y = YMALLOC(sizeof(yaffs_Device)); // ^^^^^^^^^^^^^^^^ + if (!y) EG(ENOMEM); + memset(y, 0, sizeof(yaffs_Device)); + y->param.name = mte->devname; + y->context = (void*) part; + + y->nDataBytesPerChunk = + y->param.totalBytesPerChunk = CYG_NAND_BYTES_PER_PAGE(nand); + y->param.inbandTags = 0; + + y->param.nChunksPerBlock = CYG_NAND_PAGES_PER_BLOCK(nand); + y->param.nReservedBlocks = o_nReserved; + y->param.startBlock = 0; + y->param.endBlock = CYG_NAND_PARTITION_NBLOCKS(part)-1; + y->param.useNANDECC = 1; + y->param.nShortOpCaches = o_nShortOpCaches; + + if (CYG_NAND_BYTES_PER_PAGE(nand) == 512) { +#ifdef CYGSEM_FS_YAFFS_SMALLPAGE_MODE_YAFFS1 + y->param.isYaffs2 = 0; + if (CYG_NAND_APPSPARE_PER_PAGE(nand) < PACKEDTAGS1_OOBSIZE) { + NAND_ERROR(nand, + "Device has %d spare per page but YAFFS1 needs %d\n", + CYG_NAND_APPSPARE_PER_PAGE(nand), PACKEDTAGS1_OOBSIZE); + EG(EINVAL); + } +#else // CYGSEM_FS_YAFFS_SMALLPAGE_MODE_YAFFS2 + y->param.isYaffs2 = 1; + // 512-byte page devices normally have 8-byte spare areas. + // This isn't big enough for YAFFS2 tags, which need 25. + y->param.inbandTags = 1; +#endif + } else { + y->param.isYaffs2 = 1; + if (CYG_NAND_APPSPARE_PER_PAGE(nand) < PACKEDTAGS2_OOBSIZE(y)) { + NAND_ERROR(nand, + "Device has %d spare per page but YAFFS2 needs %u\n", + CYG_NAND_APPSPARE_PER_PAGE(nand), PACKEDTAGS2_OOBSIZE(y)); + EG(EINVAL); + } + } + +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE + if (y->param.isYaffs2) { + NAND_ERROR(nand, "Device is set to run with yaffs2 code, which is compiled out.\n"); + EG(ENODEV); + } +#endif + + y->param.eraseBlockInNAND = eyaffs_eraseBlockInNAND; + y->param.initialiseNAND = eyaffs_initialiseNAND; + y->param.deinitialiseNAND = eyaffs_deinitialiseNAND; + + y->param.writeChunkWithTagsToNAND = eyaffs_writeChunkWithTagsToNAND; + y->param.readChunkWithTagsFromNAND = eyaffs_readChunkWithTagsFromNAND; + y->param.markNANDBlockBad = eyaffs_markNANDBlockBad; + y->param.queryNANDBlock = eyaffs_queryNANDBlock; + + y->isMounted = 0; + y->param.removeObjectCallback = eyaffs_diriter_objremove_callback; + + if (o_skipCheckpointRead) { + NAND_CHATTER(1, nand, "mounting with skip-checkpoint-read\n"); + y->param.skipCheckpointRead = 1; + } + + int yerr = yaffs_GutsInitialise(y); + if (yerr == YAFFS_FAIL) { + NAND_CHATTER(1, nand, "yaffs_GutsInitialise failed!\n"); + EG(EIO); + } + + yaffs_Object * root = yaffs_Root(y); + mte->root = (cyg_dir) root; + mte->data = (CYG_ADDRWORD) y; + CYG_ASSERT(_err == ENOERR, "Unhandled error in initialisation"); + // At this point we could use the device struct's devList to link it + // into a global devList. (We don't currently need to, so won't.) + return ENOERR; +err_exit: + if (y) YFREE(y); + return _err; +} + +#if !defined(CYGSEM_FS_YAFFS_COMPATIBILITY_ECOSPRO) || (CYGSEM_FS_YAFFS_COMPATIBILITY_ECOSPRO == 0) +static int eyaffs_umount ( cyg_mtab_entry *mte ) +#else +static int eyaffs_umount ( cyg_mtab_entry *mte, cyg_bool force ) +#endif +{ + yaffs_Device *y = (yaffs_Device*) mte->data; + + yaffs_FlushEntireDeviceCache(y); + yaffs_CheckpointSave(y); + yaffs_Deinitialise(y); + + YFREE(y); + return ENOERR; +} + +static int eyaffs_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *name, + int mode, cyg_file *file ) +{ + int _err; + ey_dirsearch ds; + yaffs_Object *node = 0; + + // 'mode' is the open options (flags), not the permissions. + // (eCos doesn't support file perms.) + + // fileio gives us either the root, or the current wd, to start at + init_dirsearch(&ds, (yaffs_Object*) dir, name); + _err = eyaffs_find(&ds); + + if (_err == ENOENT) { + // It's not there. Are we creat()ing? + if (ds.last && (mode & O_CREAT) ) { + // A trailing slash implies directory, which makes no sense here + if (ds.name[ds.namelen] == '/') return EISDIR; + CYG_ASSERT(ds.name[ds.namelen]==0, "Length fencepost failed"); + node = yaffs_MknodFile(ds.dir, ds.name, FILE_FIXED_PERMS, FIXED_UID, FIXED_GID); + if (!node || (node==YAFFS_FAIL)) return ENOMEM; + _err = ENOERR; + } + // else we return ENOENT + } else if (_err == ENOERR) { + // The node exists. If the O_CREAT and O_EXCL bits are set, we + // must fail the open. + if( (mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) ) + _err = EEXIST; + else node = ds.node; + } + + if( _err != ENOERR ) return _err; + + if (yaffs_GetObjectType(node) == DT_LNK) { + // TODO: symlink support + return ENOSYS; + } + + if(yaffs_GetObjectType(node) == DT_DIR) return EISDIR; + + // Could check perms here (and on the dir tree too) + + if( mode & O_TRUNC ) + YER(yaffs_ResizeFile(node, 0)); + + file->f_flag |= mode & CYG_FILE_MODE_MASK; + file->f_type = CYG_FILE_TYPE_FILE; + file->f_ops = &eyaffs_fileops; + file->f_offset = (mode & O_APPEND) ? yaffs_GetObjectFileLength(node) : 0; + file->f_data = (CYG_ADDRWORD) node; + file->f_xops = 0; + node->myInode = file; + + return ENOERR; +} + +static int eyaffs_unlink ( cyg_mtab_entry *mte, cyg_dir dir, const char *name ) +{ + int _err; + ey_dirsearch ds; + + init_dirsearch(&ds, (yaffs_Object*) dir, name); + _err = eyaffs_find(&ds); + if (_err != ENOERR) return _err; + + if(yaffs_GetObjectType(ds.node) == DT_DIR) return EISDIR; + if (ds.name[ds.namelen] == '/') return EISDIR; // cannot unlink dirs + YER(yaffs_Unlink(ds.dir,ds.name)); // this appears to DTRT wrt 0-linked still-open files + return ENOERR; +} + +static int eyaffs_mkdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name ) +{ + ey_dirsearch ds; + + init_dirsearch(&ds, (yaffs_Object*) dir, name); + int _err = eyaffs_find(&ds); + if (_err == ENOENT) { + if (ds.last) { + char dirname[ds.namelen+1]; + memcpy(dirname, ds.name, ds.namelen); + dirname[ds.namelen] = 0; + // OK, create it! + yaffs_Object * node = yaffs_MknodDirectory(ds.dir, dirname, DIRECTORY_FIXED_PERMS, FIXED_UID, FIXED_GID); + _err = (node == NULL) ? EIO : ENOERR; + } else { + // Intermediate directory doesn't exist - ENOENT + } + } else { + // something there already + if (_err == ENOERR) _err = EEXIST; + } + return _err; +} + +static int eyaffs_rmdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name ) +{ + ey_dirsearch ds; + + init_dirsearch(&ds, (yaffs_Object*) dir, name); + int _err = eyaffs_find(&ds); + if (_err != ENOERR) return _err; + + if(yaffs_GetObjectType(ds.node) != DT_DIR) return ENOTDIR; + if (0==strcmp(ds.name,".")) return EINVAL; + if (0==ds.namelen) return EINVAL; + + char dirname[ds.namelen+1]; + memcpy(dirname, ds.name, ds.namelen); + dirname[ds.namelen] = 0; + + if (YAFFS_FAIL == yaffs_Unlink(ds.dir,dirname)) return ENOTEMPTY; + return ENOERR; +} + +static int eyaffs_rename ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1, + cyg_dir dir2, const char *name2 ) +{ + ey_dirsearch ds1, ds2; + + init_dirsearch(&ds1, (yaffs_Object*) dir1, name1); + int _err = eyaffs_find(&ds1); + if (_err != ENOERR) return _err; + + init_dirsearch(&ds2, (yaffs_Object*) dir2, name2); + _err = eyaffs_find(&ds2); + + if (ds2.last && _err == ENOENT) + ds2.node = NULL, _err = ENOERR; // through-rename + + if (_err != ENOERR) return _err; + + if (ds1.node == ds2.node) return ENOERR; // identity op + + if (ds2.node) { + int type1 = yaffs_GetObjectType(ds1.node), + type2 = yaffs_GetObjectType(ds2.node); + if ( (type1 != DT_DIR) && (type2 == DT_DIR) ) + return EISDIR; + if ( (type1 == DT_DIR) && (type2 != DT_DIR) ) + return ENOTDIR; + // YAFFS will delete the target + } + // Alas, if this is a directory rename, there may be trailing / involved, + // so we have to strip them. + char xname1[ds1.namelen+1]; + memcpy(xname1, ds1.name, ds1.namelen); + xname1[ds1.namelen] = 0; + char xname2[ds2.namelen+1]; + memcpy(xname2, ds2.name, ds2.namelen); + xname2[ds2.namelen] = 0; + + YER(yaffs_RenameObject(ds1.dir, xname1, ds2.dir, xname2)); + return ENOERR; +} + +static int eyaffs_link ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1, + cyg_dir dir2, const char *name2, int type ) +{ + ey_dirsearch ds1, ds2; + + // Only do hard links for now + if (type != CYG_FSLINK_HARD) return EINVAL; + + init_dirsearch(&ds1, (yaffs_Object*) dir1, name1); + int _err = eyaffs_find(&ds1); + if (_err != ENOERR) return _err; + + init_dirsearch(&ds2, (yaffs_Object*) dir2, name2); + _err = eyaffs_find(&ds2); + if (_err == ENOERR) return EEXIST; // Can't rename-over + + if (ds2.last && _err == ENOENT) + ds2.node = 0, _err = ENOERR; // link-through + + ER(_err); + + // Forbid hard links to directories + if (ds1.node->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) + return EPERM; + + if (ds2.name[ds2.namelen] == '/') return EISDIR; // eh? makes no sense. + yaffs_Object * newnode = yaffs_Link(ds2.dir, ds2.name, ds1.node); + if (newnode) return ENOERR; + else return EIO; +} + +static int eyaffs_opendir( cyg_mtab_entry *mte, cyg_dir dir, const char *name, + cyg_file *file ) +{ + int _err; + ey_dirsearch ds; + + init_dirsearch(&ds, (yaffs_Object*) dir, name); + _err = eyaffs_find(&ds); + if (_err != ENOERR) return _err; + + if(yaffs_GetObjectType(ds.node) != DT_DIR) return ENOTDIR; + + eyaffs_diriter *diriter = YMALLOC(sizeof(eyaffs_diriter)); + if (!diriter) return ENOMEM; + + YINIT_LIST_HEAD(&diriter->iterlist); + diriter->node = ds.node; + + if (!eyaffs_all_diriters.next) YINIT_LIST_HEAD(&eyaffs_all_diriters); + ylist_add(&diriter->iterlist, &eyaffs_all_diriters); + eyaffs_diriter_rewind(diriter); + + file->f_type = CYG_FILE_TYPE_FILE; + file->f_ops = &eyaffs_dirops; + file->f_offset = 0; + file->f_data = (CYG_ADDRWORD) diriter; + file->f_xops = 0; + return ENOERR; +} + +static int eyaffs_chdir ( cyg_mtab_entry *mte, cyg_dir xdir, const char *name, + cyg_dir *dir_out ) +{ + yaffs_Object *dir = (yaffs_Object*) xdir; + if (dir_out) { + ey_dirsearch ds; + init_dirsearch(&ds, dir, name); + int _err = eyaffs_find(&ds); + if (_err != ENOERR) return _err; + if (yaffs_GetObjectType(ds.node) != DT_DIR) + return ENOTDIR; + *dir_out = (cyg_dir)ds.node; + } else { + // the "dec-refcount" case: nothing to do + } + return ENOERR; +} + +static int eyaffs_stat ( cyg_mtab_entry *mte, cyg_dir dir, const char *name, + struct stat *buf) +{ + int _err; + ey_dirsearch ds; + + init_dirsearch(&ds, (yaffs_Object*) dir, name); + _err = eyaffs_find(&ds); + if (_err != ENOERR) return _err; + + return eyaffs_stat_object(ds.node, buf); +} + +static int eyaffs_stat_object(yaffs_Object *node, struct stat *buf) +{ + switch (yaffs_GetObjectType(node)) { + case DT_REG: + buf->st_mode = __stat_mode_REG; + buf->st_size = node->variant.fileVariant.fileSize; + break; + case DT_DIR: + buf->st_mode = __stat_mode_DIR; + buf->st_size = 0; + break; + default: + return ENOSYS; // Don't support anything else yet + } + + buf->st_mode |= node->yst_mode &~ S_IFMT; + + buf->st_ino = node->objectId; + buf->st_dev = 0; + buf->st_nlink = eyaffs_count_links(node); + buf->st_uid = node->yst_uid; + buf->st_gid = node->yst_gid; + + buf->st_atime = node->yst_atime; + buf->st_mtime = node->yst_mtime; + buf->st_ctime = node->yst_ctime; + + return ENOERR; +} + +static int eyaffs_getinfo( cyg_mtab_entry *mte, cyg_dir dir, const char *name, + int key, void *buf, int len ) +{ + int _err; + ey_dirsearch ds; + yaffs_Device *y = (yaffs_Device*) mte->data; + + switch(key) { + case FS_INFO_GETCWD: + // yaffs doesn't provide anything special, we'd only end up duplicating the fallback ".." method. + case FS_INFO_ATTRIB: // not supported +#ifdef FS_INFO_CALLBACK + case FS_INFO_CALLBACK: // not supported +#endif + return ENOSYS; +#ifdef CYGSEM_FILEIO_INFO_DISK_USAGE + case FS_INFO_DISK_USAGE: + { + struct cyg_fs_disk_usage *usage = (struct cyg_fs_disk_usage *) buf; + CYG_CHECK_DATA_PTR(buf, "getinfo buf"); + if (len < sizeof(struct cyg_fs_disk_usage)) return EINVAL; + usage->total_blocks = y->param.endBlock - y->param.startBlock + 1; + usage->free_blocks = y->nErasedBlocks; + usage->block_size = y->nDataBytesPerChunk * y->param.nChunksPerBlock; + return ENOERR; + } +#else + (void)y; +#endif + } + + init_dirsearch(&ds, (yaffs_Object*) dir, name); + _err = eyaffs_find(&ds); + if (_err != ENOERR) return _err; + + switch(key) { + case FS_INFO_CONF: + if (len < sizeof (struct cyg_pathconf_info)) return EINVAL; + return eyaffs_pathconf(ds.node, (struct cyg_pathconf_info *) buf); + +#ifdef FS_INFO_MBCS_TRANSLATE + case FS_INFO_MBCS_TRANSLATE: +#endif + default: + return ENOSYS; + } +} + +static int eyaffs_do_sync_fs(yaffs_Device * y) +{ + yaffs_FlushEntireDeviceCache(y); + // TODO: If there were a convenient way to enumerate all the open + // files in a filesystem, we could fsync them all here. + // This might involve code similar to cyg_fd_filesys_close(). + yaffs_CheckpointSave(y); + return ENOERR; +} + +static int eyaffs_setinfo( cyg_mtab_entry *mte, cyg_dir dir, const char *name, + int key, void *buf, int len ) +{ + switch (key) { + case FS_INFO_SYNC: + return eyaffs_do_sync_fs( (yaffs_Device*) mte->data ); + case FS_INFO_ATTRIB: // not supported +#ifdef FS_INFO_CALLBACK + case FS_INFO_CALLBACK: // not supported +#endif +#ifdef FS_INFO_SECURE_ERASE + case FS_INFO_SECURE_ERASE: +#endif +#ifdef FS_INFO_MBCS_TRANSLATE + case FS_INFO_MBCS_TRANSLATE: +#endif + return ENOSYS; + } + return EINVAL; +} + +FSTAB_ENTRY(eyaffs_fste, "yaffs", 0, CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM, + /* N.B. If you get a build failure here (initialization + * from incompatible pointer type), it might be because you're + * using this GPL-licensed package on eCosPro and need to set + * CYGSEM_FS_YAFFS_COMPATIBILITY_ECOSPRO. + */ + eyaffs_mount, + eyaffs_umount, + eyaffs_open, + eyaffs_unlink, + eyaffs_mkdir, + eyaffs_rmdir, + eyaffs_rename, + eyaffs_link, + eyaffs_opendir, + eyaffs_chdir, + eyaffs_stat, + eyaffs_getinfo, + eyaffs_setinfo); + +// -----------------------------------------------------------------------
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/src/ecos-yaffs.h @@ -0,0 +1,91 @@ +#ifndef CYGONCE_FS_ECOS_YAFFS_H +#define CYGONCE_FS_ECOS_YAFFS_H +//============================================================================= +// +// ecos-yaffs.h +// +// Options for the eCos interface to the YAFFS filesystem +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos 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 or (at your option) any later +// version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-05-05 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <pkgconf/system.h> +#include <pkgconf/fs_yaffs.h> + +/* Options from yaffs moduleconfig.h */ +#define CONFIG_YAFFS_FS + +#ifdef CYGSEM_FS_YAFFS_SMALLPAGE_MODE_YAFFS1 +# define CONFIG_YAFFS_YAFFS1 +# define CONFIG_YAFFS_YAFFS2 +#else // CYGSEM_FS_YAFFS_SMALLPAGE_MODE_YAFFS2 +# define CONFIG_YAFFS_NO_YAFFS1 +# define CONFIG_YAFFS_YAFFS2 +#endif + +/* eCos does not currently supply DT_REG &c. and ATTR_MODE &c., so we'll + * use YAFFS's: */ +#define CONFIG_YAFFS_PROVIDE_DEFS + +/* Our NAND layer does ECC, so we won't use YAFFS's - but we do need + * to use its internal ECC on the tags */ +//#define YAFFS_IGNORE_TAGS_ECC +//#define CONFIG_YAFFS_DOES_ECC +//#define CONFIG_YAFFS_ECC_WRONG_ORDER + +/* Do not test whether chunks are erased before writing to them */ +#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK + +/* Cache short names, taking more RAM, but faster look-ups */ +#ifdef CYGSEM_FS_YAFFS_CACHE_SHORT_NAMES +#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM +#endif + +/* The count of blocks to reserve for checkpointing */ +#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10 + +/* Use older-style on-NAND data format with pageStatus byte? + * This probably requires work in the NAND layer in order to support. */ +//#define CONFIG_YAFFS_9BYTE_TAGS + +#define yaffs_DeviceToContext(dev) ((cyg_nand_partition *)(((yaffs_Device*)(dev))->context)) + +#endif /* CYGONCE_FS_ECOS_YAFFS_H */
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/src/ecos-yport.h @@ -0,0 +1,137 @@ +#ifndef CYGONCE_FS_ECOS_YPORT_H +#define CYGONCE_FS_ECOS_YPORT_H +//============================================================================= +// +// ecos-yport.h +// +// eCos porting layer for YAFFS +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos 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 or (at your option) any later +// version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-05-05 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include "ecos-yaffs.h" + +#include "devextras.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/diag.h> +#include <cyg/infra/cyg_type.h> + +#define YCHAR char +#define YUCHAR unsigned char +#define _Y(x) x +#define yaffs_strcat(a,b) strcat(a,b) +#define yaffs_strcpy(a,b) strcpy(a,b) +#define yaffs_strncpy(a,b,c) strncpy(a,b,c) +#define yaffs_strncmp(a,b,c) strncmp(a,b,c) +#define yaffs_strlen(s) strlen(s) +#define yaffs_sprintf sprintf +#define yaffs_toupper(a) toupper(a) + +#define YAFFS_PATH_DIVIDERS "/" + +#define Y_INLINE inline + +#define YMALLOC(x) malloc(x) +#define YFREE(x) free(x) +#define YMALLOC_ALT(x) malloc(x) +#define YFREE_ALT(x) free(x) + +#define YMALLOC_DMA(x) YMALLOC(x) + +#ifdef CYGFUN_KERNEL_API_C +#include <cyg/kernel/kapi.h> +#define YYIELD() do { cyg_thread_yield(); } while(0) +#else +#define YYIELD() do {} while(0) +#endif + + +//#define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) +//#define YALERT(s) YINFO(s) +#define YBUG() do { cyg_assert_fail(__PRETTY_FUNCTION__, __FILE__, __LINE__, "==>> yaffs bug detected"); } while(0) + +#define TENDSTR "\n" +#define TSTR(x) x +#define TCONT(x) x +#ifdef CYGSEM_FS_YAFFS_TRACEFN +externC int CYGSEM_FS_YAFFS_TRACEFN (const char *fmt, ...) CYGBLD_ATTRIB_PRINTF_FORMAT(1,2); +#define TOUT(p) CYGSEM_FS_YAFFS_TRACEFN p +#else +static inline int _yaffs_trace_ignore (const char *fmt, ...) CYGBLD_ATTRIB_PRINTF_FORMAT(1,2); +static inline int _yaffs_trace_ignore (const char *fmt, ...) { return 0; } +#define TOUT(p) _yaffs_trace_ignore p +#endif + + +#define YAFFS_LOSTNFOUND_NAME "lost+found" +#define YAFFS_LOSTNFOUND_PREFIX "obj" +//#define YPRINTF(x) printf x + +#ifdef CYGPKG_LIBC_TIME +#define Y_CURRENT_TIME time(NULL) +#else +#define Y_CURRENT_TIME ((time_t)-1) +#endif +#define Y_TIME_CONVERT(x) (x) + +// eCos defines mode bits differently to POSIX. +#define YAFFS_ROOT_MODE ( S_IRUSR | S_IWUSR | S_IXUSR | \ + S_IRGRP | S_IXGRP | \ + S_IROTH | S_IXOTH ) +#define YAFFS_LOSTNFOUND_MODE YAFFS_ROOT_MODE + +#define yaffs_SumCompare(x,y) ((x) == (y)) +#define yaffs_strcmp(a,b) strcmp(a,b) + +typedef off_t loff_t; /* This will break and should probably be removed + if/when we add 64-bit file support generally. */ + +#define yaffs_qsort qsort /* provided by eCos stdlib */ + +#define yaffs_strnlen(s,l) strnlen(s,l) + +#endif /* CYGONCE_FS_ECOS_YPORT_H */
--- a/packages/fs/yaffs/current/src/yaffs_guts.c +++ b/packages/fs/yaffs/current/src/yaffs_guts.c @@ -48,6 +48,10 @@ /* Robustification (if it ever comes about...) */ +/* eCos note: I have discussed the existence of robustification hooks + * with Charles Manning. He put them in as stubs, but then concluded + * that there was no value in filling them in. + * - wry, 2009-06-19 */ static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND); static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND, int erasedOk); @@ -565,8 +569,8 @@ static void yaffs_VerifyObjectHeader(yaf if (!(tags && obj && oh)) { T(YAFFS_TRACE_VERIFY, - (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR), - tags, obj, oh)); + (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR), + (__u32)tags, (__u32)obj, (__u32)oh)); return; } @@ -4474,7 +4478,8 @@ static void yaffs_InvalidateWholeChunkCa /*--------------------- Checkpointing --------------------*/ - +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE +#else static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev, int head) { yaffs_CheckpointValidity cp; @@ -4979,6 +4984,7 @@ static int yaffs_ReadCheckpointData(yaff return ok ? 1 : 0; } +#endif // !OMIT_YAFFS2_CODE static void yaffs_InvalidateCheckpoint(yaffs_Device *dev) { @@ -5003,7 +5009,10 @@ int yaffs_CheckpointSave(yaffs_Device *d if (!dev->isCheckpointed) { yaffs_InvalidateCheckpoint(dev); +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE +#else yaffs_WriteCheckpointData(dev); +#endif } T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); @@ -5011,6 +5020,8 @@ int yaffs_CheckpointSave(yaffs_Device *d return dev->isCheckpointed; } +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE +#else int yaffs_CheckpointRestore(yaffs_Device *dev) { int retval; @@ -5028,6 +5039,7 @@ int yaffs_CheckpointRestore(yaffs_Device return retval; } +#endif /*--------------------- File read/write ------------------------ * Read and write have very similar structures. @@ -5816,6 +5828,8 @@ int yaffs_Unlink(yaffs_Object *dir, cons /*----------------------- Initialisation Scanning ---------------------- */ +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE +#else static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, int backwardScanning) { @@ -5849,6 +5863,7 @@ static void yaffs_HandleShadowedObject(y obj->valid = 1; /* So that we don't read any other info for this file */ } +#endif typedef struct { int seq; @@ -5888,6 +5903,8 @@ static void yaffs_HardlinkFixup(yaffs_De +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE +#else static int ybicmp(const void *a, const void *b) { register int aseq = ((yaffs_BlockIndex *)a)->seq; @@ -5899,7 +5916,7 @@ static int ybicmp(const void *a, const v else return aseq - bseq; } - +#endif struct yaffs_ShadowFixerStruct { int objectId; @@ -6055,8 +6072,12 @@ static void yaffs_EmptyLostAndFound(yaff yaffs_DeleteDirectoryContents(dev->lostNFoundDir); } + static int yaffs_Scan(yaffs_Device *dev) { +#ifdef CONFIG_YAFFS_NO_YAFFS1 + return YAFFS_FAIL; +#else yaffs_ExtendedTags tags; int blk; int blockIterator; @@ -6486,14 +6507,18 @@ static int yaffs_Scan(yaffs_Device *dev) yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); - if (alloc_failed) + if (alloc_failed) { + T(YAFFS_TRACE_ERROR, (TSTR("malloc failed in yaffs_ScanBackwards" TENDSTR))); return YAFFS_FAIL; + } T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR))); return YAFFS_OK; -} +#endif //CONFIG_YAFFS_NO_YAFFS1 +} + static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) { @@ -6552,6 +6577,8 @@ static void yaffs_CheckObjectDetailsLoad } } +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE +#else static int yaffs_ScanBackwards(yaffs_Device *dev) { yaffs_ExtendedTags tags; @@ -7199,6 +7226,7 @@ static int yaffs_ScanBackwards(yaffs_Dev return YAFFS_OK; } +#endif // !CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE /*------------------------------ Directory Functions ----------------------------- */ @@ -8013,6 +8041,9 @@ int yaffs_GutsInitialise(yaffs_Device *d if (!init_failed) { /* Now scan the flash. */ if (dev->param.isYaffs2) { +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE + init_failed = 1; +#else if (yaffs_CheckpointRestore(dev)) { yaffs_CheckObjectDetailsLoaded(dev->rootDir); T(YAFFS_TRACE_ALWAYS, @@ -8047,8 +8078,9 @@ int yaffs_GutsInitialise(yaffs_Device *d if (!init_failed && !yaffs_ScanBackwards(dev)) init_failed = 1; } - } else if (!yaffs_Scan(dev)) - init_failed = 1; +#endif // !CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE + } else if (!yaffs_Scan(dev)) + init_failed = 1; yaffs_StripDeletedObjects(dev); yaffs_FixHangingObjects(dev);
--- a/packages/fs/yaffs/current/src/yaffs_nand.c +++ b/packages/fs/yaffs/current/src/yaffs_nand.c @@ -17,6 +17,39 @@ #include "yaffs_getblockinfo.h" +#ifdef CONFIG_YAFFS_NO_YAFFS1 +// Trap to let us compile the source largely unmodified but to elide the +// YAFFS1 code unless we really need it +static inline int noyaffs1(void) { + T(YAFFS_TRACE_ERROR, (TSTR("YAFFS1 support compiled out" TENDSTR))); + YBUG(); + return YAFFS_FAIL; +} + +static inline +int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev, + int chunkInNAND, + const __u8 *data, + const yaffs_ExtendedTags *tags) +{ return noyaffs1(); } +static inline +int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev, + int chunkInNAND, + __u8 *data, + yaffs_ExtendedTags *tags) +{ return noyaffs1(); } +static inline +int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, + int blockNo) +{ return noyaffs1(); } +static inline +int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, + int blockNo, + yaffs_BlockState *state, + __u32 *sequenceNumber) +{ return noyaffs1(); } +#endif + int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *buffer, yaffs_ExtendedTags *tags)
--- a/packages/fs/yaffs/current/src/yaffs_packedtags2.c +++ b/packages/fs/yaffs/current/src/yaffs_packedtags2.c @@ -16,6 +16,13 @@ #include "yaffs_trace.h" #include "yaffs_tagsvalidity.h" +#if 0 +// Used in conjunction with RANDOMLY_LOSE mode on the synth nand driver to +// demonstrate that it is behaving as intended. +#define COUNT_ECC_TAG_FIXES +unsigned yaffs_tag_ecc_fixes = 0; +#endif + /* This code packs a set of extended tags into a binary structure for * NAND storage */ @@ -155,7 +162,6 @@ void yaffs_UnpackTags2TagsPart(yaffs_Ext } - void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC) { @@ -179,6 +185,9 @@ void yaffs_UnpackTags2(yaffs_ExtendedTag break; case 1: eccResult = YAFFS_ECC_RESULT_FIXED; +#ifdef COUNT_ECC_TAG_FIXES + ++yaffs_tag_ecc_fixes; +#endif break; case -1: eccResult = YAFFS_ECC_RESULT_UNFIXED;
--- a/packages/fs/yaffs/current/src/yaffs_tagscompat.c +++ b/packages/fs/yaffs/current/src/yaffs_tagscompat.c @@ -17,7 +17,9 @@ #include "yaffs_getblockinfo.h" #include "yaffs_trace.h" +#ifndef CONFIG_YAFFS_NO_YAFFS1 static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND); +#endif // ! NO_YAFFS1, i.e. only when YAFFS1 is needed #ifdef NOTYET static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND); static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND, @@ -57,11 +59,16 @@ int yaffs_CountBits(__u8 x) /********** Tags ECC calculations *********/ void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare) -{ +{ +#if 1 + YBUG(); // Should never get here if configured out.. +#else yaffs_ECCCalculate(data, spare->ecc1); yaffs_ECCCalculate(&data[256], spare->ecc2); +#endif } +#ifndef CONFIG_YAFFS_NO_YAFFS1 void yaffs_CalcTagsECC(yaffs_Tags *tags) { /* Calculate an ecc */ @@ -113,9 +120,11 @@ int yaffs_CheckECCOnTags(yaffs_Tags *tag return 0; } +#endif /********** Tags **********/ +#ifndef CONFIG_YAFFS_NO_YAFFS1 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr) { @@ -136,7 +145,10 @@ static void yaffs_LoadTagsIntoSpare(yaff static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr) { - yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr; + // slightly convoluted to work around the strict-aliasing rules + yaffs_TagsUnion tuu; + tuu.asTags = *tagsPtr; + yaffs_TagsUnion *tu = &tuu; int result; tu->asBytes[0] = sparePtr->tagByte0; @@ -191,6 +203,9 @@ static int yaffs_ReadChunkFromNAND(struc } if (!dev->param.useNANDECC) { +#if 1 + YBUG(); +#else retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data, spare); if (data && doErrorCorrection) { /* Do ECC correction */ @@ -245,6 +260,7 @@ static int yaffs_ReadChunkFromNAND(struc else *eccResult = YAFFS_ECC_RESULT_NO_ERROR; } +#endif } else { /* Must allocate enough memory for spare+2*sizeof(int) */ /* for ecc results from device. */ @@ -296,6 +312,7 @@ static int yaffs_ReadChunkFromNAND(struc } return retVal; } +#endif // ! NO_YAFFS1, i.e. only when YAFFS1 is present #ifdef NOTYET static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, @@ -329,6 +346,7 @@ static int yaffs_CheckChunkErased(struct * Functions for robustisizing */ +#ifndef CONFIG_YAFFS_NO_YAFFS1 static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND) { int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock; @@ -344,6 +362,7 @@ static void yaffs_HandleReadDataError(ya * NB recursion */ } +#endif // ! NO_YAFFS1, i.e. only when YAFFS1 is needed #ifdef NOTYET static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND) @@ -396,6 +415,7 @@ static int yaffs_VerifyCompare(const __u } #endif /* NOTYET */ +#ifndef CONFIG_YAFFS_NO_YAFFS1 int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, const __u8 *data, @@ -537,3 +557,5 @@ int yaffs_TagsCompatabilityQueryNANDBloc return YAFFS_OK; } +#endif // ! NO_YAFFS1, i.e. only when YAFFS1 is needed +
--- a/packages/fs/yaffs/current/src/yaffs_tagscompat.h +++ b/packages/fs/yaffs/current/src/yaffs_tagscompat.h @@ -17,6 +17,8 @@ #define __YAFFS_TAGSCOMPAT_H__ #include "yaffs_guts.h" + +#ifndef CONFIG_YAFFS_NO_YAFFS1 int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, const __u8 *data, @@ -34,6 +36,7 @@ int yaffs_TagsCompatabilityQueryNANDBloc void yaffs_CalcTagsECC(yaffs_Tags *tags); int yaffs_CheckECCOnTags(yaffs_Tags *tags); +#endif int yaffs_CountBits(__u8 byte); #endif
--- a/packages/fs/yaffs/current/src/yportenv.h +++ b/packages/fs/yaffs/current/src/yportenv.h @@ -17,6 +17,8 @@ #ifndef __YPORTENV_H__ #define __YPORTENV_H__ +#include "ecos-yaffs.h" + /* * Define the MTD version in terms of Linux Kernel versions * This allows yaffs to be used independantly of the kernel @@ -147,6 +149,10 @@ #define yaffs_SumCompare(x, y) ((x) == (y)) #define yaffs_strcmp(a, b) strcmp(a, b) +#elif defined CYGPKG_FS_YAFFS + +#include "ecos-yport.h" + #else /* Should have specified a configuration type */ #error Unknown configuration
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/tests/ar4prng.inl @@ -0,0 +1,98 @@ +//============================================================================= +// +// ar4prng.inl +// +// Inline providing ARC4-based PRNG +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos 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 or (at your option) any later +// version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-04-06 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#define _SWAP(_a,_b) do { int tmp = (_a); (_a) = (_b); (_b) = tmp; } while(0) + +typedef struct { + unsigned char S[256]; + int i,j; +} ar4ctx; + +void ar4prng_init(ar4ctx *c, unsigned char *seed, unsigned seedlen) +{ + int i,j=0; + for (i=0; i<256; i++) c->S[i] = i; + for (i=0; i<256; i++) { + j = (j + c->S[i] + seed[i%seedlen]) %256; + _SWAP(c->S[i], c->S[j]); + } + c->i = c->j = 0; +} + +unsigned char ar4prng_next(ar4ctx *c) +{ + c->i = (c->i + 1) %256; + c->j = (c->j + c->S[c->i]) %256; + _SWAP(c->S[c->i], c->S[c->j]); + return c->S[(c->S[c->i] + c->S[c->j])%256]; +} + +void ar4prng_many(ar4ctx *c, unsigned char *optr, unsigned len) +{ + while (len--) *(optr++) = ar4prng_next(c); +} + +#include <cyg/infra/cyg_type.h> + +/* If you care about systematic sampling bias, do not naively + * reduce a u32 mod some limit. */ +cyg_uint32 ar4prng_u32(ar4ctx *c) +{ + cyg_uint32 rv = 0; + ar4prng_many(c, (void*)&rv, sizeof(rv)); + return rv; +} + +cyg_int32 ar4prng_s32(ar4ctx *c) +{ + cyg_int32 rv = 0; + ar4prng_many(c, (void*)&rv, sizeof(rv)); + return rv; +} + +#undef _SWAP +
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/tests/yaffs0_fops.c @@ -0,0 +1,777 @@ +//============================================================================= +// +// yaffs0_fops.c +// +// Filesystem, file and directory operation tests for YAFFS on eCos +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 Free Software Foundation, Inc. +// +// eCos 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 or (at your option) any later +// version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-05-11 +// Description: A good (read/write) shakedown of the filesystem ops. +// On the SYNTH device, includes a long test which fills up +// the filesystem. +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/infra/testcase.h> +#include <pkgconf/system.h> + +#if !defined(CYGPKG_LIBC_TIME) || !defined(CYGPKG_ERROR) || !defined(CYGPKG_LIBC_STDIO) + +void cyg_user_start(void) +{ + CYG_TEST_NA("Needs CYGPKG_LIBC_TIME, CYGPKG_ERROR and CYGPKG_LIBC_STDIO"); +} + +#else + + +#include <cyg/infra/diag.h> +#include <cyg/fileio/fileio.h> +#include <dirent.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +#define MUST(what) do { CYG_TEST_CHECK((what), #what); } while(0) + +#define MUSTOS(what) do { \ + if (0 != what) { \ + perror(#what); \ + CYG_TEST_FAIL(#what); \ + cyg_test_exit(); \ + } \ +} while(0) + +#define EXPECT(what,val) do { CYG_TEST_CHECK((what) == (val), #what "==" #val); } while(0) + +#ifdef CYGPKG_DEVS_NAND_SYNTH +#define DEVICE "synth/0" +#else +#define DEVICE "onboard/0" +#endif +#define MOUNTPOINT "/nand" +#define FSTYPE "yaffs" + +MTAB_ENTRY(my_auto, MOUNTPOINT, FSTYPE, DEVICE, 0/*priv set up by mount*/); + +void list_dir_contents(const char *dir) +{ + DIR *d = opendir(dir); + if (!d) { + diag_printf("opendir %s: %s (%d)\n", dir, strerror(errno), errno); + return; + } + diag_printf("Directory %s contains:\n", dir); + + struct dirent *de; + int n = 0; + while ((de=readdir(d))) { + diag_printf("\t%s\n", de->d_name); + ++n; + } + diag_printf("(ends)\n"); + + // Rewind and try again + int m = 0; + rewinddir(d); + while ((de=readdir(d))) + ++m; + if (n != m) + CYG_TEST_FAIL_EXIT("dir reread check failed - rewinddir broken?"); + + closedir(d); +} + +#if 0 +void MKDIR(const char *dir) +{ + MUSTOS(mkdir(dir,0777)); +} +#else +#define MKDIR(d) MUSTOS(mkdir(d,0777)) +#endif + +#if 0 +void RMDIR(const char *dir) +{ + MUSTOS(rmdir(dir)); +} +#else +#define RMDIR(d) MUSTOS(rmdir(d)) +#endif + +#define RENAME(d,d2) MUSTOS(rename(d,d2)) +#define UNLINK(p) MUSTOS(unlink(p)) +#define LINK(p1,p2) MUSTOS(link(p1,p2)) + +void CHDIR(const char *dir) +{ + MUSTOS(chdir(dir)); +} + +void WANTDIR(const char *d) +{ + struct stat st; + MUSTOS(stat(d,&st)); + EXPECT(S_ISDIR(st.st_mode),1); +} + +void DONOTWANT(const char *f) +{ + struct stat st; + if (stat(f,&st) != -1) { + diag_printf("Do not want %s, but it is there\n",f); + CYG_TEST_FAIL_EXIT("Unexpected entity present"); + } + EXPECT(errno,ENOENT); +} + +void RM_RF_work(const char *f, int recurse) +{ + //diag_printf("chdir %s <r=%d>\n",f,recurse); + MUSTOS(chdir(f)); + DIR *d = opendir("."); + if (!d) { + diag_printf("opendir %s: %s\n", f, strerror(errno)); + return; + } + //diag_printf("opened dir %s\n",f); + struct dirent de_stack; + struct dirent *de_res; + while (0==readdir_r(d, &de_stack, &de_res) && de_res) { + struct stat st; + if (0==strcmp(de_res->d_name,".")) continue; + if (0==strcmp(de_res->d_name,"..")) continue; + MUSTOS(stat(de_res->d_name,&st)); + if (S_ISDIR(st.st_mode)) { + RM_RF_work(de_res->d_name, recurse+1); + //diag_printf("rmdir %s\n", de_res->d_name); + if (rmdir(de_res->d_name)) + perror("rmdir"); + } else { + // diag_printf("unlink %s\n", de_res->d_name); + MUSTOS(unlink(de_res->d_name)); + } + // N.B. We have just unlinked a file or deleted a subdir + // during a live opendir/readdir cycle. What we get from readdir + // isn't (strictly) well-defined, but we expect to not crash. + // In fact what we get from YAFFS is probably the best + // possible behaviour: there's no explosion, and when we + // next say readdir() we get the next entry! + } + //diag_printf("rm -rf closes %s\n",f); + closedir(d); + MUSTOS(chdir("..")); + //diag_printf("chdir ..\n"); +} + +void RM_RF(const char *p) +{ + //diag_printf("chdir /\n"); + //MUSTOS(chdir(MOUNTPOINT)); + diag_printf("rm -rf %s\n",p); + RM_RF_work(p,0); + //diag_printf("rmdir %s\n",p); + RMDIR(p); +} + +void checklen(const char *f, off_t size) +{ + struct stat st; + MUSTOS(stat(f, &st)); + if (st.st_size != size) { + diag_printf("!! file %s size by stat is %lu, expect %lu\n", f, st.st_size, size); + CYG_TEST_FAIL_EXIT("file size readback mismatch"); + } +} + +// -------------------------------------------------------------- + +// Function inspiration borrowed from fileio1.c and just about +// every other filesystem in eCos... Only this time, we're +// sufficiently paranoid to want to use arc4 to generate our file data. + +#define SHOW_RESULT(fn,res) do { \ + diag_printf("%s returned %d, errno %d (%s)\n", #fn, (int)res, errno, strerror(errno)); \ + CYG_TEST_FAIL("Unexpected result from "#fn); \ + cyg_test_exit(); \ +} while(0) + +#define IOSIZE 100 + +#include "ar4prng.inl" + +#define SEEDLEN (sizeof(time_t)) +unsigned char seed[SEEDLEN]; + +ar4ctx prng; + +static void reinit_prng(void) +{ + static int seed_inited = 0; + + if (!seed_inited) { + // This is a bit cruddy, but will introduce sufficient variation to make it interesting. + time((time_t*)seed); + seed_inited=1; + } + + ar4prng_init(&prng, seed, SEEDLEN); +} + +unsigned char buf[IOSIZE], testbuf[IOSIZE]; + +static void createfile( char *name, size_t size ) +{ + int fd; + ssize_t wrote; + int err; + size_t savesize = size; + + diag_printf("<INFO>: create file %s size %zd\n",name,size); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + reinit_prng(); + + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + while( size > 0 ) + { + ssize_t len = size; + if ( len > IOSIZE ) len = IOSIZE; + + ar4prng_many(&prng, buf, len); + wrote = write( fd, buf, len ); + if( wrote != len ) SHOW_RESULT( write, wrote ); + + size -= wrote; + } + + err = fsync(fd); + if (err < 0) SHOW_RESULT(fsync, err); + + struct stat st; + err = fstat(fd, &st); + if (err < 0) SHOW_RESULT(fstat, err); + if (st.st_size != savesize) + CYG_TEST_FAIL_EXIT("fstat size mismatched"); + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +static void checkfile( char *name ) +{ + int fd; + ssize_t done, pos=0, lastread=-1; + int i; + int err; + + diag_printf("<INFO>: check file %s\n",name); + + reinit_prng(); + + err = access( name, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd = open( name, O_RDONLY ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + for(;;) + { + done = read( fd, buf, IOSIZE ); + pos += done; + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + lastread = done; + + ar4prng_many(&prng, testbuf, done); + + for( i = 0; i < done; i++ ) + if( buf[i] != testbuf[i] ) + { + diag_printf("buf[%d](%02x) != %02x\n",i,buf[i],testbuf[i]); + CYG_TEST_FAIL_EXIT("Data read not equal to data written"); + } + } + + // While we're here, let's have a play with lseek. +#define LSEEK(f, o, w, expect) do { \ + err = lseek(f, o, w); \ + if (err != expect) SHOW_RESULT(fseek, err); \ +} while(0) + + LSEEK(fd, -lastread, SEEK_END, pos-lastread); + done = read(fd, buf, IOSIZE); + CYG_ASSERT(done == lastread, "reread last chunk size mismatch - lseek broken?"); + for (i=0; i<IOSIZE; i++) { + if (buf[i] != testbuf[i]) { + diag_printf("buf[%d](%02x) != %02x\n",i,buf[i],testbuf[i]); + CYG_TEST_FAIL_EXIT("Data mismatch - lseek broken?"); + } + } + + reinit_prng(); + ar4prng_many(&prng, testbuf, IOSIZE); + + LSEEK(fd, 10, SEEK_SET, 10); + done = read(fd, &buf[10], IOSIZE-10); + CYG_ASSERT(done == IOSIZE-10, "reading after fseek"); + LSEEK(fd, -IOSIZE, SEEK_CUR, 0); // i.e. to beginning of file + done = read(fd, buf, 10); + CYG_ASSERT(done == 10, "reading after 2nd fseek"); + for (i=0; i<IOSIZE; i++) { + if (buf[i] != testbuf[i]) { + diag_printf("buf[%d](%02x) != %02x\n",i,buf[i],testbuf[i]); + CYG_TEST_FAIL_EXIT("Data mismatch - lseek broken?"); + } + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +static void copyfile( char *name2, char *name1 ) +{ + int err; + int fd1, fd2; + ssize_t done, wrote; + + diag_printf("<INFO>: copy file %s -> %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + err = access( name2, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_WRONLY|O_CREAT ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done = read( fd2, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + wrote = write( fd1, buf, done ); + if( wrote != done ) SHOW_RESULT( write, wrote ); + + if( wrote != done ) break; + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +static void comparefiles( char *name2, char *name1 ) +{ + int err; + int fd1, fd2; + ssize_t done1, done2; + int i; + + diag_printf("<INFO>: compare files %s == %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_RDONLY ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done1 = read( fd1, buf, IOSIZE ); + if( done1 < 0 ) SHOW_RESULT( read, done1 ); + + done2 = read( fd2, testbuf, IOSIZE ); + if( done2 < 0 ) SHOW_RESULT( read, done2 ); + + if( done1 != done2 ) + diag_printf("Files different sizes\n"); + + if( done1 == 0 ) break; + + for( i = 0; i < done1; i++ ) + if( buf[i] != testbuf[i] ) + { + diag_printf("buf[%d](%02x) != buf[%d](%02x)\n",i,buf[i],i,testbuf[i]); + CYG_TEST_FAIL("Data in files not equal\n"); + } + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +#ifdef CYGPKG_DEVS_NAND_SYNTH + +#include <pkgconf/devs_nand_synth.h> + +static void maxfile( char *name ) +{ + int fd; + ssize_t wrote; + int err; + size_t size = 0; + + diag_printf("<INFO>: create maximal file %s\n",name); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + reinit_prng(); + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + do + { + ar4prng_many(&prng, buf, IOSIZE); + wrote = write( fd, buf, IOSIZE ); + if( wrote < 0 ) SHOW_RESULT( write, wrote ); + + CYG_ASSERT(size <= (CYGNUM_NAND_SYNTH_CHIPSIZE*1024), "filesystem overfull"); + size += wrote; + + } while( wrote == IOSIZE ); + + diag_printf("<INFO>: file size == %zd\n",size); + + err = close( fd ); + cyg_fs_setinfo(MOUNTPOINT, FS_INFO_SYNC, NULL, 0); // sync(); + if( err < 0 ) SHOW_RESULT( close, err ); +} +#endif // CYGPKG_DEVS_NAND_SYNTH + +// -------------------------------------------------------------- + +void cyg_user_start(void) +{ + CYG_TEST_INIT(); + + // 1. Mounting and unmounting. We should already be mounted + // by the time we get here (MTAB_ENTRY). + struct stat st; + MUSTOS(stat(MOUNTPOINT, &st)); + diag_printf("got mountpoint ino %08x\n",st.st_ino); + + EXPECT(mount(DEVICE, MOUNTPOINT, FSTYPE), -1); + MUSTOS(umount(MOUNTPOINT)); + EXPECT(umount(MOUNTPOINT),-1); + MUSTOS(mount(DEVICE, MOUNTPOINT, FSTYPE)); + EXPECT(mount(DEVICE, MOUNTPOINT, FSTYPE), -1); + CYG_TEST_INFO("mount, umount OK"); + + // 2. Directory creation, deletion and rename + // In fact we start by deleting if our test dir was already there... +#define DIR1 MOUNTPOINT"/testdir" +#define DIR2 MOUNTPOINT"/testdir2" + if (0==stat(DIR1, &st)) { + CYG_TEST_INFO("dir " DIR1 " already present - attempting to nuke"); + RM_RF(DIR1); + } + if (0==stat(DIR2, &st)) { + CYG_TEST_INFO("dir " DIR2 " already present - attempting to nuke"); + RM_RF(DIR2); + } + EXPECT(rmdir(DIR1),-1); + MKDIR(DIR1); + RMDIR(DIR1); + EXPECT(rmdir(DIR1),-1); + MKDIR(DIR1); + EXPECT(mkdir(DIR1,0777),-1); + + MKDIR(DIR1"/foo////"); + EXPECT(rmdir(DIR1),-1); + EXPECT(rmdir(DIR1"/."),-1); + EXPECT(rmdir(DIR1"/foo/.."),-1); + EXPECT(rmdir(DIR1"/./foo/."),-1); // Linux doesn't allow this either. + RMDIR(DIR1"/./foo/"); // Trailing slash on a dir op shouldn't catch us out + + RENAME(DIR1"/", MOUNTPOINT"/newdir/"); + WANTDIR(MOUNTPOINT"/newdir"); + WANTDIR(MOUNTPOINT"/newdir/////"); + DONOTWANT(DIR1); + RMDIR(MOUNTPOINT"/newdir"); + + EXPECT(rmdir(MOUNTPOINT"/"),-1); + EXPECT(rmdir(MOUNTPOINT),-1); + + CYG_TEST_INFO("directory creation, deletion OK"); + + // 3. chdir. We'll make a simple hierarchy: + // DIR1 + // DIR1/1 + // DIR1/1a + // DIR1/foo/1foo + // DIR2 + // DIR2/2 + // DIR2/bar/2bar + // DIR2/bar/2baz + // .. then chdir into each in turn and confirm that the contents are as expected. + MKDIR(DIR1); + MKDIR(DIR1"/1"); + MKDIR(DIR1"/1a"); + MKDIR(DIR1"/foo"); + MKDIR(DIR1"/foo/1foo"); + MKDIR(DIR2); + MKDIR(DIR2"/2"); + MKDIR(DIR2"/bar"); + MKDIR(DIR2"/bar/2bar"); + MKDIR(DIR2"/bar/2baz"); + + CHDIR(DIR1); + WANTDIR("1"); + WANTDIR("1a"); + WANTDIR("foo"); + DONOTWANT("2"); + DONOTWANT("1foo"); + DONOTWANT("bar"); + DONOTWANT("2bar"); + DONOTWANT("2baz"); + + CHDIR("foo"); + WANTDIR("1foo"); + DONOTWANT("1"); + DONOTWANT("1a"); + DONOTWANT("foo"); + + CHDIR(".."); + WANTDIR("1"); + WANTDIR("1a"); + WANTDIR("foo"); + DONOTWANT("bar"); + CHDIR("."); + WANTDIR("1"); + WANTDIR("1a"); + WANTDIR("foo"); + DONOTWANT("bar"); + WANTDIR("foo/1foo"); + RMDIR("foo/1foo"); + DONOTWANT("foo/1foo"); + + CYG_TEST_INFO("chdir, opendir, readdir OK"); + + // 4. File creation, copying, renaming, deletion - throughout dirs + + CHDIR(DIR1); + createfile("floop", 202); + checklen("floop", 202); + checkfile(DIR1"/floop"); + copyfile("floop", DIR2"/fee"); + CHDIR(DIR2); + checkfile("fee"); + checklen("fee", 202); + comparefiles("fee", DIR1"/floop"); + + copyfile("fee", DIR1"/fum"); + checkfile(DIR1"/fum"); + chdir(DIR1); + checkfile("fum"); + comparefiles("floop", "fum"); + comparefiles("fum", DIR2"/fee"); + + // Rename ... + RENAME("fum", DIR2"/fum2"); + DONOTWANT("fum"); + DONOTWANT("fum2"); + DONOTWANT(DIR1"/fum"); + checkfile(DIR2"/fum2"); + CHDIR(DIR2); + checkfile("fum2"); + CHDIR(DIR1); + RENAME(DIR2"/fum2", "fum3"); + checkfile("fum3"); + checkfile(DIR1"/fum3"); + DONOTWANT(DIR2"/fum3"); + comparefiles(DIR1"/fum3", DIR1"/floop"); + CHDIR(DIR2); + comparefiles(DIR1"/fum3", DIR1"/floop"); + + // A brief diversion to check rewinddir... + list_dir_contents(DIR1); + + // Create-over, rename-over + CHDIR(DIR1); + checklen("floop", 202); + checklen(DIR2"/fee", 202); + createfile(DIR2"/fee", 4242); + checklen(DIR2"/fee", 4242); + checklen("floop", 202); + RENAME(DIR2"/fee", "floop"); + checklen("floop", 4242); + + // Unlink + CHDIR(DIR2); + UNLINK(DIR1"/fum3"); + DONOTWANT(DIR1"/fum3"); + DONOTWANT("fum3"); + CHDIR(DIR1); + DONOTWANT("fum3"); + + CYG_TEST_INFO("file create/read/write, copy, delete OK"); + + // 5. File hard links (and directory, which aren't supported) + + LINK("floop","floop2"); + checklen("floop2", 4242); + LINK("floop",DIR2"/floop3"); + CHDIR(DIR2); + LINK(DIR1"/floop", "floop4"); + LINK(DIR1"/floop", DIR1"/floop5"); + DONOTWANT("floop2"); + checkfile("floop3"); + checkfile("floop4"); + DONOTWANT("floop5"); + CHDIR(DIR1); + checkfile("floop2"); + DONOTWANT("floop3"); + DONOTWANT("floop4"); + checkfile("floop5"); + + checkfile(DIR1"/floop2"); + checkfile(DIR2"/floop3"); + checkfile(DIR2"/floop4"); + checkfile(DIR1"/floop5"); + + UNLINK("floop2"); + UNLINK(DIR2"/floop3"); + CHDIR(DIR2); + UNLINK("floop4"); + UNLINK(DIR1"/floop5"); + + DONOTWANT(DIR1"/floop2"); + DONOTWANT(DIR2"/floop3"); + DONOTWANT(DIR2"/floop4"); + DONOTWANT(DIR1"/floop5"); + + CHDIR(DIR1); + checkfile("floop"); + // we'll leave floop lying around for fpathconf() test + + EXPECT(link(DIR1, DIR2"/dir-hardlink-should-fail"), -1); + EXPECT(errno, EPERM); + + CYG_TEST_INFO("hard links OK"); + +#ifdef CYGPKG_DEVS_NAND_SYNTH + // 6. EOF-on-write (by filling the filesystem!) + CYG_TEST_INFO("bigfile test, this might take a few seconds"); + + // To speed this test up tune your synth nand device to not be so big. + maxfile(DIR1"/bigfile"); + checkfile(DIR1"/bigfile"); + { + struct stat st; + stat(DIR1"/bigfile", &st); + } + UNLINK(DIR1"/bigfile"); + CYG_TEST_INFO("EOF on write OK"); +#else + CYG_TEST_INFO("SKIPPING EOF-on-write test (only applied to synth nand)"); +#endif + + // 7. Ancillary checks - getinfo, setinfo (no ioctls supported as yet) + +#ifdef CYGSEM_FILEIO_INFO_DISK_USAGE + struct cyg_fs_disk_usage usage; + MUSTOS(cyg_fs_getinfo(MOUNTPOINT, FS_INFO_DISK_USAGE, &usage, sizeof(usage))); + diag_printf("getinfo/disk_usage says:\n\ttotal blocks %llu\n\tfree blocks %llu\n\tblock size %u\n", usage.total_blocks, usage.free_blocks, usage.block_size); +#endif + + diag_printf("pathconf says:\n\tNAME_MAX %ld\n\tPATH_MAX %ld\n\tSYNC_IO %ld\n", + pathconf(DIR1, _PC_NAME_MAX), + pathconf(DIR1, _PC_PATH_MAX), + pathconf(DIR1, _PC_SYNC_IO)); + + MUSTOS(cyg_fs_setinfo(MOUNTPOINT, FS_INFO_SYNC, 0, 0)); + + int fd = open(DIR1"/floop", O_RDONLY); + CYG_ASSERT(fd >= 0, "open"); + CYG_ASSERT(fpathconf(fd, _PC_NAME_MAX) != -1, "fpathconf PC_NAME_MAX"); + close(fd); + + CYG_TEST_INFO("getinfo, setinfo OK"); + + // Clean up. + + CHDIR(MOUNTPOINT); + RM_RF(DIR1); + RM_RF(DIR2); + DONOTWANT(DIR1); + DONOTWANT(DIR2); + CYG_TEST_INFO("recursive deletion OK"); + + MUSTOS(umount(MOUNTPOINT)); +#ifndef CYGDBG_USE_ASSERTS + CYG_TEST_INFO("WARNING: asserts disabled, test INCOMPLETE, try switching on CYGPKG_INFRA_DEBUG"); +#else + CYG_TEST_PASS_FINISH("All OK"); +#endif +} + +#endif +
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/tests/yaffs1.c @@ -0,0 +1,974 @@ +//========================================================================== +// +// yaffs1.c +// +// Test fileio system +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2007 Free Software Foundation, Inc. +// Copyright (C) 2004, 2006, 2007 eCosCentric Limited +// +// eCos 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 or (at your option) any later +// version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): nickg +// Contributors: nickg +// Date: 2000-05-25 +// Purpose: Test fileio system +// Description: This test uses the testfs to check out the initialization +// and basic operation of the fileio system +// +// +// +// +// +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/system.h> + +#ifdef CYGPKG_KERNEL + +#include <pkgconf/hal.h> +#include <pkgconf/kernel.h> +#include <pkgconf/io_fileio.h> + +#include CYGDAT_DEVS_DISK_CFG // testing config defines + +#include <cyg/kernel/ktypes.h> // base kernel types +#include <cyg/infra/cyg_trac.h> // tracing macros +#include <cyg/infra/cyg_ass.h> // assertion macros + +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> + +#include <cyg/fileio/fileio.h> + +#include <cyg/infra/testcase.h> +#include <cyg/infra/diag.h> // HAL polled output + +//========================================================================== +// Config options + +#define TEST_DEVICE CYGDAT_DEVS_DISK_TEST_DEVICE + +#define TEST_MOUNTPOINT CYGDAT_DEVS_DISK_TEST_MOUNTPOINT + +#define TEST_DIRECTORY CYGDAT_DEVS_DISK_TEST_DIRECTORY + +#define TEST_FSTYPE "yaffs" + +#ifdef CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DEVICE2 CYGDAT_DEVS_DISK_TEST_DEVICE2 + +#define TEST_MOUNTPOINT2 CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DIRECTORY2 CYGDAT_DEVS_DISK_TEST_DIRECTORY2 + +#define TEST_FSTYPE2 "yaffs" + +#endif + +//========================================================================== + +#define SHOW_RESULT( _fn, _res ) \ +{ \ + diag_printf("<FAIL>: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):""); \ +} + +//========================================================================== + +#define IOSIZE 100 + +#define LONGNAME1 "long_file_name_that_should_take_up_more_than_one_directory_entry_1" +#define LONGNAME2 "long_file_name_that_should_take_up_more_than_one_directory_entry_2" + + +//========================================================================== + +#ifndef CYGPKG_LIBC_STRING + +char *strcat( char *s1, const char *s2 ) +{ + char *s = s1; + while( *s1 ) s1++; + while( (*s1++ = *s2++) != 0); + return s; +} + +#endif + +__externC int +rename( const char * /* oldpath */, const char * /* newpath */ ) __THROW; + +//========================================================================== + +static void listdir( char *name, int statp, int numexpected, int *numgot ) +{ + int err; + DIR *dirp; + int num=0; + + diag_printf("<INFO>: reading directory %s\n",name); + +// diag_printf("<INFO>: opendir(%s)\n",name); + dirp = opendir( name ); + if( dirp == NULL ) SHOW_RESULT( opendir, -1 ); + + for(;;) + { + struct dirent *entry = readdir( dirp ); + + if( entry == NULL ) + break; + num++; + diag_printf("<INFO>: entry %14s",entry->d_name); +#ifdef CYGPKG_FS_FAT_RET_DIRENT_DTYPE + diag_printf(" d_type %2x", entry->d_type); +#endif + if( statp ) + { + char fullname[PATH_MAX]; + struct stat sbuf; + + if( name[0] ) + { + strcpy(fullname, name ); + if( !(name[0] == '/' && name[1] == 0 ) ) + strcat(fullname, "/" ); + } + else fullname[0] = 0; + + strcat(fullname, entry->d_name ); + + err = stat( fullname, &sbuf ); + if( err < 0 ) + { + if( errno == ENOSYS ) + diag_printf(" <no status available>"); + else SHOW_RESULT( stat, err ); + } + else + { + diag_printf(" [mode %08x ino %08x nlink %d size %ld]", + sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size); + } +#ifdef CYGPKG_FS_FAT_RET_DIRENT_DTYPE + if ((entry->d_type & S_IFMT) != (sbuf.st_mode & S_IFMT)) + CYG_TEST_FAIL("File mode's don't match between dirent and stat"); +#endif + } + + diag_printf("\n"); + } + +// diag_printf("<INFO>: closedir(%s)\n",name); + err = closedir( dirp ); + if( err < 0 ) SHOW_RESULT( stat, err ); + if (numexpected >= 0 && num != numexpected) + CYG_TEST_FAIL("Wrong number of dir entries\n"); + if ( numgot != NULL ) + *numgot = num; +} + +//========================================================================== + +static void createfile( char *name, size_t size ) +{ + char buf[IOSIZE]; + int fd; + ssize_t wrote; + int i; + int err; + + diag_printf("<INFO>: create file %s size %zd\n",name,size); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + while( size > 0 ) + { + ssize_t len = size; + if ( len > IOSIZE ) len = IOSIZE; + + wrote = write( fd, buf, len ); + if( wrote != len ) SHOW_RESULT( write, wrote ); + + size -= wrote; + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +//========================================================================== + +#if 0 +static void maxfile( char *name ) +{ + char buf[IOSIZE]; + int fd; + ssize_t wrote; + int i; + int err; + size_t size = 0; + size_t prevsize = 0; + + diag_printf("<INFO>: create maximal file %s\n",name); + diag_printf("<INFO>: This may take a few minutes\n"); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + do + { + wrote = write( fd, buf, IOSIZE ); + //if( wrote < 0 ) SHOW_RESULT( write, wrote ); + + if( wrote >= 0 ) + size += wrote; + + if( (size-prevsize) > 100000 ) + { + diag_printf("<INFO>: size = %zd\n", size); + prevsize = size; + } + + } while( wrote == IOSIZE ); + + diag_printf("<INFO>: file size == %zd\n",size); + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} +#endif + +//========================================================================== + +static void checkfile( char *name ) +{ + char buf[IOSIZE]; + int fd; + ssize_t done; + int i; + int err; + off_t pos = 0; + + diag_printf("<INFO>: check file %s\n",name); + + err = access( name, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd = open( name, O_RDONLY ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + for(;;) + { + done = read( fd, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + for( i = 0; i < done; i++ ) + if( buf[i] != i%256 ) + { + diag_printf("buf[%ld+%d](%02x) != %02x\n",pos,i,buf[i],i%256); + CYG_TEST_FAIL("Data read not equal to data written\n"); + for(;;); + } + + pos += done; + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +//========================================================================== + +static void copyfile( char *name2, char *name1 ) +{ + + int err; + char buf[IOSIZE]; + int fd1, fd2; + ssize_t done, wrote; + + diag_printf("<INFO>: copy file %s -> %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + err = access( name2, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_WRONLY|O_CREAT ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done = read( fd2, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + wrote = write( fd1, buf, done ); + if( wrote != done ) SHOW_RESULT( write, wrote ); + + if( wrote != done ) break; + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +//========================================================================== + +static void comparefiles( char *name2, char *name1 ) +{ + int err; + char buf1[IOSIZE]; + char buf2[IOSIZE]; + int fd1, fd2; + ssize_t done1, done2; + int i; + + diag_printf("<INFO>: compare files %s == %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_RDONLY ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done1 = read( fd1, buf1, IOSIZE ); + if( done1 < 0 ) SHOW_RESULT( read, done1 ); + + done2 = read( fd2, buf2, IOSIZE ); + if( done2 < 0 ) SHOW_RESULT( read, done2 ); + + if( done1 != done2 ) + diag_printf("Files different sizes\n"); + + if( done1 == 0 ) break; + + for( i = 0; i < done1; i++ ) + if( buf1[i] != buf2[i] ) + { + diag_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]); + CYG_TEST_FAIL("Data in files not equal\n"); + } + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +//========================================================================== + +void checkcwd( const char *cwd ) +{ + static char cwdbuf[PATH_MAX]; + char *ret; + + ret = getcwd( cwdbuf, sizeof(cwdbuf)); + if( ret == NULL ) SHOW_RESULT( getcwd, ret ); + + if( strcmp( cwdbuf, cwd ) != 0 ) + { + diag_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd ); + CYG_TEST_FAIL( "Current directory mismatch"); + } +} + +//========================================================================== +// main + +void fileio1_main( CYG_ADDRESS id ) +{ + int err; + int existingdirents=-1; + cyg_bool mp2 = false; + int fd; +#if defined(CYGSEM_FILEIO_BLOCK_USAGE) + struct cyg_fs_block_usage usage; +#endif + + char dirname[64]; + char filename1[64]; + char filename2[64]; + +#define NEW_FILENAME( fn, f ) \ +{ \ + fn[0]=0; \ + strcat(fn, dirname); \ + strcat(fn, "/"); \ + strcat(fn,f); \ +} + +#define NEW_FILENAME1( f ) NEW_FILENAME( filename1, f ) +#define NEW_FILENAME2( f ) NEW_FILENAME( filename2, f ) + + CYG_TEST_INIT(); + + // -------------------------------------------------------------- + + err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE ); + if( err < 0 ) { + SHOW_RESULT( mount, err ); + CYG_TEST_FAIL_FINISH("yaffs1"); + } + + err = access( TEST_MOUNTPOINT TEST_DIRECTORY, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + if( err < 0 && errno == EACCES ) + { + diag_printf("<INFO>: create %s\n", + TEST_MOUNTPOINT TEST_DIRECTORY); + err = mkdir( TEST_MOUNTPOINT TEST_DIRECTORY, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + } + + err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY ); + + listdir( TEST_MOUNTPOINT TEST_DIRECTORY, true, -1, &existingdirents ); + + // -------------------------------------------------------------- +#if defined(CYGSEM_FILEIO_BLOCK_USAGE) + err = cyg_fs_getinfo(TEST_MOUNTPOINT, FS_INFO_BLOCK_USAGE, + &usage, sizeof(usage)); + if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err ); + diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n", + usage.total_blocks, usage.total_blocks * usage.block_size); + diag_printf("<INFO>: free size: %6lld blocks, %10lld bytes\n", + usage.free_blocks, usage.free_blocks * usage.block_size); + diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size); +#endif + // -------------------------------------------------------------- + + dirname[0] = 0; + strcat(dirname, TEST_MOUNTPOINT ); + strcat(dirname, TEST_DIRECTORY ); + + // -------------------------------------------------------------- + + createfile( "foo", 20257 ); + checkfile( "foo" ); + copyfile( "foo", "fee"); + checkfile( "fee" ); + comparefiles( "foo", "fee" ); + diag_printf("<INFO>: mkdir bar\n"); + err = mkdir( "bar", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + listdir( dirname , true, existingdirents+3, NULL ); + + copyfile( "fee", "bar/fum" ); + checkfile( "bar/fum" ); + comparefiles( "fee", "bar/fum" ); + diag_printf("<INFO>: cd bar\n"); + err = chdir( "bar" ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + // Create a further subdirectory and immediately remove it + // This should make no overall change, but may expose later + // node cache reference counting issues. + diag_printf("<INFO>: mkdir delme\n"); + err = mkdir( "delme", 0); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + diag_printf("<INFO>: cd delme\n"); + err = chdir( "delme"); + if( err < 0 ) SHOW_RESULT( chdir, err ); + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + diag_printf("<INFO>: rmdir delme\n"); + err = rmdir( "delme" ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + NEW_FILENAME1( "bar/delme1" ); + diag_printf("<INFO>: mkdir %s\n",filename1); + err = mkdir( filename1, 0); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + diag_printf("<INFO>: rmdir %s\n",filename1); + err = rmdir( filename1 ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + + NEW_FILENAME1( "bar" ); + checkcwd( filename1 ); + + diag_printf("<INFO>: rename ../foo bundy\n"); + err = rename( "../foo", "bundy" ); + if( err < 0 ) SHOW_RESULT( rename, err ); + + listdir( dirname, true, existingdirents+2, NULL ); + listdir( "." , true, 4, NULL ); + + checkfile( "../bar/bundy" ); + comparefiles("../fee", "bundy" ); + +#if defined(CYGSEM_FILEIO_BLOCK_USAGE) + err = cyg_fs_getinfo(TEST_MOUNTPOINT, FS_INFO_BLOCK_USAGE, + &usage, sizeof(usage)); + if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err ); + diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n", + usage.total_blocks, usage.total_blocks * usage.block_size); + diag_printf("<INFO>: free size: %6lld blocks, %10lld bytes\n", + usage.free_blocks, usage.free_blocks * usage.block_size); + diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size); +#endif + // -------------------------------------------------------------- + // Check for some common error cases + + + // First make some directories + diag_printf("<INFO>: mkdir doo\n"); + err = mkdir( "doo", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir fie\n"); + err = mkdir( "fie", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir fie/foe\n"); + err = mkdir( "fie/foe", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + + diag_printf("<INFO>: rename fum doo -- should fail\n"); + err = rename( "fum", "doo" ); + if( err < 0 && errno != EISDIR ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename doo fum -- should fail\n"); + err = rename( "doo", "fum" ); + if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename doo fie -- should fail\n"); + err = rename( "doo", "fie" ); + // FATFS returns ENOTEMPTY, since fie has foe within it + if( err < 0 && errno != EIO ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: open floop for reading -- should fail\n"); + err = open( "floop", O_RDONLY ); + if( err < 0 && errno != ENOENT ) SHOW_RESULT( open, err ); + + NEW_FILENAME1( "x/y" ) + diag_printf("<INFO>: rename fum %s -- should fail\n",filename1); + err = rename( "fum", filename1 ); + if( err < 0 && errno != ENOENT ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename fum fum -- should succeed\n"); + err = rename( "fum", "fum" ); + if( err < 0 ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: unlink fee -- should fail\n"); + err = unlink( "fee" ); + if( err < 0 && errno != ENOENT ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "bar" ); + diag_printf("<INFO>: rmdir %s -- should fail\n",filename1); + err = rmdir( filename1 ); + // FATFS gives EBUSY here, since bar is the current dir + if( err < 0 && errno != ENOTEMPTY ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: unlink %s -- should fail\n",filename1); + err = unlink( filename1 ); + // FATFS returns EBUSY here, also because bar is current dir + if( err < 0 && errno != EISDIR ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "bar/fum" ); + diag_printf("<INFO>: rmdir %s -- should fail\n",filename1); + err = rmdir( filename1 ); + if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: mkdir %s -- should fail\n",filename1); + err = mkdir( filename1, 0 ); + if( err < 0 && errno != EEXIST ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: open bundy exclusive -- should fail\n"); + fd = open( "bundy", O_WRONLY|O_CREAT|O_EXCL ); + if( fd < 0 && errno != EEXIST ) SHOW_RESULT( open, fd ); + + diag_printf("<INFO>: open %s -- should fail\n",dirname); + fd = open( dirname, O_WRONLY ); + if( fd < 0 && errno != EISDIR ) SHOW_RESULT( open, fd ); + + + listdir( dirname, true, existingdirents+2, NULL ); + listdir( "." , true, 6, NULL ); + + // -------------------------------------------------------------- + + diag_printf("<INFO>: rename fie doo\n"); + err = rename( "fie", "doo" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: rmdir doo/foe\n"); + err = rmdir("doo/foe"); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: rmdir doo\n"); + err = rmdir("doo"); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink ../fee\n"); + err = unlink( "../fee" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink fum\n"); + err = unlink( "fum" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink ../bar/bundy\n"); + err = unlink( "../bar/bundy" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( dirname ); + + diag_printf("<INFO>: rmdir bar\n"); + err = rmdir( "bar" ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + listdir( dirname, false, existingdirents, NULL ); + + // -------------------------------------------------------------- + +#ifdef TEST_MOUNTPOINT2 + diag_printf("<INFO>: mount %s\n", TEST_MOUNTPOINT2); + err = mount( TEST_DEVICE2, TEST_MOUNTPOINT2, TEST_FSTYPE2 ); + + if( err == 0 ) + { + mp2 = true; + diag_printf("<INFO>: mount %s succeeded\n", TEST_MOUNTPOINT2); + err = access( TEST_MOUNTPOINT2 TEST_DIRECTORY2, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + if( err < 0 && errno == EACCES ) + { + diag_printf("<INFO>: create %s\n", + TEST_MOUNTPOINT2 TEST_DIRECTORY2); + err = mkdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + } + + err = chdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2 ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( TEST_MOUNTPOINT2 TEST_DIRECTORY2 ); + + dirname[0] = 0; + strcat(dirname, TEST_MOUNTPOINT2 ); + strcat(dirname, TEST_DIRECTORY2 ); + + } + else + { + mp2 = false; + diag_printf("<INFO>: mount %s failed, ", TEST_MOUNTPOINT2); + diag_printf("using %s instead\n", dirname ); + } + +#endif + + listdir( dirname , true, -1, &existingdirents); + + NEW_FILENAME1( "tinky" ); + NEW_FILENAME2( "laalaa" ); + + createfile( filename1, 4567 ); + copyfile( filename1, filename2 ); + checkfile( filename1); + checkfile( filename2); + comparefiles( filename1, filename2 ); + + diag_printf("<INFO>: cd %s\n",dirname); + err = chdir( dirname ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( dirname ); + + diag_printf("<INFO>: mkdir noonoo\n"); + err = mkdir( "noonoo", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + listdir( dirname , true, existingdirents+3, NULL); + + diag_printf("<INFO>: cd noonoo\n"); + err = chdir( "noonoo" ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + NEW_FILENAME1( "noonoo" ); + checkcwd( filename1 ); + + createfile( "tinky", 6789 ); + checkfile( "tinky" ); + + createfile( "dipsy", 34567 ); + checkfile( "dipsy" ); + copyfile( "dipsy", "po" ); + checkfile( "po" ); + comparefiles( "dipsy", "po" ); + + listdir( ".", true, 5, NULL ); + listdir( "..", true, existingdirents+3, NULL ); + + // -------------------------------------------------------------- + + diag_printf("<INFO>: unlink tinky\n"); + err = unlink( "tinky" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink dipsy\n"); + err = unlink( "dipsy" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink po\n"); + err = unlink( "po" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( dirname ); + + diag_printf("<INFO>: rmdir noonoo\n"); + err = rmdir( "noonoo" ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + // -------------------------------------------------------------- + + diag_printf("<INFO>: mkdir x\n"); + err = mkdir( "x", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir x/y\n"); + err = mkdir( "x/y", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir x/y/z\n"); + err = mkdir( "x/y/z", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir x/y/z/w\n"); + err = mkdir( "x/y/z/w", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + NEW_FILENAME1( "x/y/z/w" ); + diag_printf("<INFO>: cd %s\n",filename1); + err = chdir( filename1 ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( "x/y/z" ); + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( "x/y/z" ); + diag_printf("<INFO>: cd .\n"); + err = chdir( "." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( "x/y" ); + diag_printf("<INFO>: cd ../../y\n"); + err = chdir( "../../y" ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + diag_printf("<INFO>: cd ../..\n"); + err = chdir( "../.." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( dirname ); + + diag_printf("<INFO>: rmdir x/y/z/w\n"); + err = rmdir( "x/y/z/w" ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir x/y/z\n"); + err = rmdir( "x/y/z" ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir x/y\n"); + err = rmdir( "x/y" ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir x\n"); + err = rmdir( "x" ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + // -------------------------------------------------------------- + + checkcwd( dirname ); + + diag_printf("<INFO>: unlink tinky\n"); + err = unlink( "tinky" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink laalaa\n"); + err = unlink( "laalaa" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + // -------------------------------------------------------------- + + diag_printf("<INFO>: cd %s\n", TEST_MOUNTPOINT TEST_DIRECTORY); + err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY ); + + listdir( ".", true, -1, NULL ); + +#ifdef TEST_MOUNTPOINT2 + if( mp2 ) + { + diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT2); + err = umount( TEST_MOUNTPOINT2 ); + if( err < 0 ) SHOW_RESULT( umount, err ); + } +#endif + + // -------------------------------------------------------------- + +#if 0 + maxfile("file.max"); + + listdir( "/", true, -1, NULL ); + + diag_printf("<INFO>: unlink file.max\n"); + err = unlink( "file.max" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + // -------------------------------------------------------------- + + diag_printf("<INFO>: cd /\n"); + err = chdir( "/" ); + if( err == 0 ) + { + checkcwd( "/" ); + + diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT); + err = umount( TEST_MOUNTPOINT ); + if( err < 0 ) SHOW_RESULT( umount, err ); + } + + diag_printf("<INFO>: syncing\n"); + cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_SYNC, NULL, 0); // sync(); + + CYG_TEST_PASS_FINISH("yaffs1"); +} + +// ------------------------------------------------------------------------- + +#include <cyg/kernel/kapi.h> + +static cyg_handle_t thread_handle; +static cyg_thread thread; +static char stack[CYGNUM_HAL_STACK_SIZE_TYPICAL+1024]; + +externC void +cyg_start( void ) +{ + cyg_thread_create(3, // Priority - just a number + fileio1_main, // entry + 0, // index + 0, // no name + &stack[0], // Stack + sizeof(stack), // Size + &thread_handle, // Handle + &thread // Thread data structure + ); + cyg_thread_resume(thread_handle); + + cyg_scheduler_start(); +} + +#else // CYGPKG_KERNEL + +#include <cyg/infra/testcase.h> + +externC void cyg_start(void) +{ + CYG_TEST_NA("Needs CYGPKG_KERNEL"); +} + +#endif + +// ------------------------------------------------------------------------- +// EOF yaffs1.c
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/tests/yaffs2.c @@ -0,0 +1,826 @@ +//========================================================================== +// +// yaffs2.c +// +// Test fileio system +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2007 Free Software Foundation, Inc. +// Copyright (C) 2004, 2006, 2007 eCosCentric Limited +// +// eCos 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 or (at your option) any later +// version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): nickg +// Contributors: nickg +// Date: 2000-05-25 +// Purpose: Test fileio system +// Description: This test uses the testfs to check out the initialization +// and basic operation of the fileio system +// +// +// +// +// +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/system.h> + +#ifdef CYGPKG_KERNEL + +#include <pkgconf/hal.h> +#include <pkgconf/kernel.h> +#include <pkgconf/io_fileio.h> +#include <pkgconf/io_fileio.h> + +#include CYGDAT_DEVS_DISK_CFG // testing config defines + +#include <cyg/kernel/ktypes.h> // base kernel types +#include <cyg/infra/cyg_trac.h> // tracing macros +#include <cyg/infra/cyg_ass.h> // assertion macros + +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> + +#include <cyg/fileio/fileio.h> + +#include <cyg/infra/testcase.h> +#include <cyg/infra/diag.h> // HAL polled output + +#include <cyg/kernel/instrmnt.h> + +//========================================================================== +// Config options + +#define TEST_DEVICE CYGDAT_DEVS_DISK_TEST_DEVICE + +#define TEST_MOUNTPOINT CYGDAT_DEVS_DISK_TEST_MOUNTPOINT + +#define TEST_DIRECTORY CYGDAT_DEVS_DISK_TEST_DIRECTORY + +#define TEST_FSTYPE "yaffs" + +#ifdef CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DEVICE2 CYGDAT_DEVS_DISK_TEST_DEVICE2 + +#define TEST_MOUNTPOINT2 CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DIRECTORY2 CYGDAT_DEVS_DISK_TEST_DIRECTORY2 + +#define TEST_FSTYPE2 "yaffs" + +#endif + +//========================================================================== + +#if 0 +# define X(_args_) \ +{ \ + cyg_drv_isr_lock(); \ + diag_printf("%08x: ",cyg_thread_self()); \ + diag_printf _args_; \ + cyg_drv_isr_unlock(); \ + \ +} +#else +# define X(_args_) CYG_EMPTY_STATEMENT +#endif + +#ifdef JNGPKG_USB_STACK +extern int usb_stack_init(void); +#endif + +//========================================================================== + +#define SHOW_RESULT( _fn, _res ) \ +diag_printf("<FAIL>: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):""); + +//========================================================================== + +#define IOSIZE 100 + +#define NTHREAD 6 + + +//========================================================================== + +#ifndef CYGPKG_LIBC_STRING + +char *strcat( char *s1, const char *s2 ) +{ + char *s = s1; + while( *s1 ) s1++; + while( (*s1++ = *s2++) != 0); + return s; +} + +#endif + +__externC int +rename( const char * /* oldpath */, const char * /* newpath */ ) __THROW; + +//========================================================================== + + +static cyg_mutex_t db_lock; + +#define db_printf( args... ) \ +{ \ + cyg_mutex_lock( &db_lock ); \ + diag_printf("%d: ",id); \ + diag_printf( args ); \ + cyg_mutex_unlock( &db_lock ); \ +} + +//========================================================================== + +static void listdir( char *name, int statp, int numexpected, int *numgot, int id ) +{ + int err; + DIR *dirp; + int num=0; + + db_printf("<INFO>: reading directory %s\n",name); + + dirp = opendir( name ); + if( dirp == NULL ) SHOW_RESULT( opendir, -1 ); + + for(;;) + { + struct dirent entry_data; + struct dirent *entry; + + err = readdir_r( dirp, &entry_data, &entry ); + + if( err < 0 || entry == NULL ) + break; + num++; + + cyg_mutex_lock( &db_lock ); + diag_printf("%d: <INFO>: entry %14s",id, entry->d_name); + + if( statp ) + { + char fullname[PATH_MAX]; + struct stat sbuf; + + if( name[0] ) + { + strcpy(fullname, name ); + if( !(name[0] == '/' && name[1] == 0 ) ) + strcat(fullname, "/" ); + } + else fullname[0] = 0; + + strcat(fullname, entry->d_name ); + + err = stat( fullname, &sbuf ); + if( err < 0 ) + { + if( errno == ENOSYS ) + diag_printf(" <no status available>"); + else + { + SHOW_RESULT( stat, err ); + cyg_scheduler_lock(); + CYG_INSTRUMENT_USER(0xff,err,errno); + for(;;); + } + } + else + { + diag_printf(" [mode %08x ino %08x nlink %d size %ld]", + sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size); + } + } + + diag_printf("\n"); + cyg_mutex_unlock( &db_lock ); + } + + err = closedir( dirp ); + if( err < 0 ) SHOW_RESULT( stat, err ); + if (numexpected >= 0 && num != numexpected) + CYG_TEST_FAIL("Wrong number of dir entries\n"); + if ( numgot != NULL ) + *numgot = num; +} + +//========================================================================== + +static void createfile( char *name, size_t size, int id ) +{ + char buf[IOSIZE]; + int fd; + ssize_t wrote; + int i; + int err; + + db_printf("<INFO>: create file %s size %ld\n",name, (long)size); + + err = access( name, F_OK ); + if( err < 0 && errno == EEXIST ) + { + err = unlink( name ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + } + else + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + while( size > 0 ) + { + ssize_t len = size; + if ( len > IOSIZE ) len = IOSIZE; + + wrote = write( fd, buf, len ); + if( wrote != len ) SHOW_RESULT( write, wrote ); + + size -= wrote; + + cyg_thread_yield(); + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +//========================================================================== + +#if 0 +static void maxfile( char *name, int id ) +{ + char buf[IOSIZE]; + int fd; + ssize_t wrote; + int i; + int err; + size_t size = 0; + size_t prevsize = 0; + + db_printf("<INFO>: create maximal file %s\n",name); + db_printf("<INFO>: This may take a few minutes\n"); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + do + { + wrote = write( fd, buf, IOSIZE ); + //if( wrote < 0 ) SHOW_RESULT( write, wrote ); + + if( wrote >= 0 ) + size += wrote; + + if( (size-prevsize) > 100000 ) + { + db_printf("<INFO>: size = %ld \n", size); + prevsize = size; + } + + } while( wrote == IOSIZE ); + + db_printf("<INFO>: file size == %ld\n",size); + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} +#endif + +//========================================================================== + +static void checkfile( char *name, int id ) +{ + char buf[IOSIZE]; + int fd; + ssize_t done; + int i; + int err; + off_t pos = 0; + + db_printf("<INFO>: check file %s\n",name); + + err = access( name, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd = open( name, O_RDONLY ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + for(;;) + { + done = read( fd, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + for( i = 0; i < done; i++ ) + if( buf[i] != i%256 ) + { +// db_printf("buf[%d+%d](%02x) != %02x\n",pos,i,buf[i],i%256); +// CYG_TEST_FAIL("Data read not equal to data written\n"); + X(("buf[%ld+%d](%02x) != %02x\n",pos,i,buf[i],i%256)); + cyg_scheduler_lock(); + CYG_INSTRUMENT_USER(0xf0,err,errno); + for(;;); + } + + pos += done; + + cyg_thread_yield(); + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +//========================================================================== + +static void copyfile( char *name2, char *name1, int id ) +{ + + int err; + char buf[IOSIZE]; + int fd1, fd2; + ssize_t done, wrote; + + db_printf("<INFO>: copy file %s -> %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + err = access( name2, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_WRONLY|O_CREAT ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done = read( fd2, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + wrote = write( fd1, buf, done ); + if( wrote != done ) SHOW_RESULT( write, wrote ); + + if( wrote != done ) break; + + cyg_thread_yield(); + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +//========================================================================== + +static void comparefiles( char *name2, char *name1, int id ) +{ + int err; + char buf1[IOSIZE]; + char buf2[IOSIZE]; + int fd1, fd2; + ssize_t done1, done2; + int i; + + db_printf("<INFO>: compare files %s == %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_RDONLY ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done1 = read( fd1, buf1, IOSIZE ); + if( done1 < 0 ) SHOW_RESULT( read, done1 ); + + done2 = read( fd2, buf2, IOSIZE ); + if( done2 < 0 ) SHOW_RESULT( read, done2 ); + + if( done1 != done2 ) + db_printf("Files different sizes\n"); + + if( done1 == 0 ) break; + + for( i = 0; i < done1; i++ ) + if( buf1[i] != buf2[i] ) + { +// db_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]); +// CYG_TEST_FAIL("Data in files not equal\n"); + X(("%s[%d](%02x) != %s[%d](%02x)\n",name1,i,buf1[i],name2,i,buf2[i])); + cyg_scheduler_lock(); + CYG_INSTRUMENT_USER(0xf1,err,errno); + for(;;); + } + + cyg_thread_yield(); + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +//========================================================================== + +void checkcwd( const char *cwd, int id ) +{ + static char cwdbuf[PATH_MAX]; + char *ret; + + ret = getcwd( cwdbuf, sizeof(cwdbuf)); + if( ret == NULL ) SHOW_RESULT( getcwd, ret ); + + if( strcmp( cwdbuf, cwd ) != 0 ) + { + db_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd ); + CYG_TEST_FAIL( "Current directory mismatch"); + } +} + +//========================================================================== +// main + +static cyg_sem_t sem; + +void fileio2_main( CYG_ADDRESS id ) +{ + int err; + int existingdirents=-1; + + char dirname[64]; + char filename1[64]; + char filename2[64]; + +#define NEW_FILENAME( fn, f ) \ +{ \ + fn[0]=0; \ + strcat(fn, dirname); \ + strcat(fn, "/"); \ + strcat(fn,f); \ +} + +#define NEW_FILENAME1( f ) NEW_FILENAME( filename1, f ) +#define NEW_FILENAME2( f ) NEW_FILENAME( filename2, f ) + + // -------------------------------------------------------------- + + if( id == 0 ) + { + int i; + +#ifdef JNGPKG_USB_STACK + err = usb_stack_init(); + cyg_thread_delay( 1000 ); +#endif + + CYG_TEST_INIT(); + + err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE ); + if( err < 0 ) { + SHOW_RESULT( mount, err ); + CYG_TEST_FAIL_FINISH("yaffs2"); + } + + err = access( TEST_MOUNTPOINT TEST_DIRECTORY, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + if( err < 0 && errno == EACCES ) + { + db_printf("<INFO>: create %s\n", + TEST_MOUNTPOINT TEST_DIRECTORY); + err = mkdir( TEST_MOUNTPOINT TEST_DIRECTORY, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + } + + err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY, id ); + + for( i = 0; i < NTHREAD-1; i++ ) + cyg_semaphore_post( &sem ); + } + else + { + cyg_semaphore_wait( &sem ); + } + + // -------------------------------------------------------------- + + dirname[0] = 0; + strcat(dirname, TEST_MOUNTPOINT ); + strcat(dirname, TEST_DIRECTORY ); + strcat(dirname, "/dirX"); + dirname[sizeof(TEST_MOUNTPOINT) + + sizeof(TEST_DIRECTORY) - 2 + + 4] = '0' + id; +// dirname[5] = 0; + + + db_printf("<INFO>: create %s\n",dirname); + err = mkdir( dirname, 0 ); + if( err < 0 && errno != EEXIST ) SHOW_RESULT( mkdir, err ); + + listdir( dirname, true, -1, &existingdirents, id ); + + db_printf("<INFO>: existingdirents %d\n",existingdirents); + + // -------------------------------------------------------------- + + NEW_FILENAME1( "foo" ); + createfile( filename1, 20257, id ); + checkfile( filename1, id ); + + NEW_FILENAME1( "foo" ); + NEW_FILENAME2( "fee" ); + + copyfile( filename1, filename2, id); + checkfile( filename2, id ); + comparefiles( filename1, filename2, id ); + + NEW_FILENAME1( "bar" ); + db_printf("<INFO>: mkdir bar\n"); + err = mkdir( filename1, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + listdir( dirname , true, existingdirents+3, NULL, id ); + + NEW_FILENAME1( "bar/fum" ); + copyfile( filename2, filename1, id ); + checkfile( filename1, id ); + comparefiles( filename2, filename1, id ); + + NEW_FILENAME1( "foo" ); + NEW_FILENAME2( "bar/bundy" ); + db_printf("<INFO>: rename %s -> %s\n",filename1,filename2); + err = rename( filename1, filename2 ); + if( err < 0 ) SHOW_RESULT( rename, err ); + + NEW_FILENAME1( "bar" ); + + listdir( dirname, true, existingdirents+2, NULL, id ); + listdir( filename1 , true, 4, NULL, id ); + + NEW_FILENAME1( "fee" ); + checkfile( filename2, id ); + comparefiles( filename1, filename2, id ); + +// db_printf("spinning\n"); for(;;) cyg_thread_delay(10); + + + // -------------------------------------------------------------- + + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "bar/fum" ); + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "bar/bundy" ); + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "bar" ); + db_printf("<INFO>: rmdir %s\n",filename1); + err = rmdir( filename1 ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + +// listdir( dirname, false, existingdirents, NULL, id ); + + listdir( dirname, true, existingdirents, NULL, id ); + + // -------------------------------------------------------------- + + + listdir( dirname , true, -1, &existingdirents, id); + + NEW_FILENAME1( "tinky" ); + NEW_FILENAME2( "laalaa" ); + createfile( filename1, 4567, id ); + copyfile( filename1, filename2, id ); + checkfile( filename1, id); + checkfile( filename2, id); + comparefiles( filename1, filename2, id ); + + NEW_FILENAME1( "noonoo" ); + db_printf("<INFO>: mkdir %s\n",filename1); + err = mkdir( filename1, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + listdir( dirname , true, existingdirents+3, NULL, id); + + NEW_FILENAME1( "noonoo/tinky" ); + createfile( filename1, 6789, id ); + checkfile( filename1, id ); + + NEW_FILENAME1( "noonoo/dipsy" ); + NEW_FILENAME2( "noonoo/po" ); + createfile( filename1, 34567, id ); + checkfile( filename1, id ); + copyfile( filename1, filename2, id ); + checkfile( filename2, id ); + comparefiles( filename1, filename2, id ); + + NEW_FILENAME1( "noonoo" ); + listdir( filename1, true, 5, NULL, id ); + listdir( dirname, true, existingdirents+3, NULL, id ); + + // -------------------------------------------------------------- + + NEW_FILENAME1( "noonoo/tinky" ); + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "noonoo/dipsy" ); + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "noonoo/po" ); + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "noonoo" ); + db_printf("<INFO>: rmdir %s\n",filename1); + err = rmdir( filename1 ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + listdir( dirname, true, existingdirents+2, NULL, id ); + + // -------------------------------------------------------------- + + + NEW_FILENAME1( "tinky" ); + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "laalaa" ); + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + listdir( dirname, true, -1, NULL, id ); + +#if 0 + NEW_FILENAME1( "file.max" ); + maxfile( filename1, id ); + + listdir( dirname, true, -1, NULL, id ); + + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + db_printf("<INFO>: rmdir %s\n",dirname); + err = rmdir( dirname ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + db_printf("<INFO>: syncing\n"); + cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_SYNC, NULL, 0); // sync(); + + + if( id == 0 ) + { + int i; + db_printf("<INFO>: waiting for other threads to finish\n"); + for( i = 0; i < NTHREAD-1; i++ ) + cyg_semaphore_wait( &sem ); + + CYG_TEST_PASS_FINISH("yaffs2"); + } + else + { + db_printf("<INFO>: thread finished\n"); + cyg_semaphore_post( &sem ); + } + + cyg_thread_exit(); +} + +// ------------------------------------------------------------------------- + +#include <cyg/kernel/kapi.h> + +#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL*2) + +static char stack[NTHREAD][STACK_SIZE]; +static cyg_handle_t thread_handle[NTHREAD]; +static cyg_thread thread[NTHREAD]; + +externC void +cyg_start( void ) +{ + int i; + + CYG_INSTRUMENT_USER(0x01,0,0); + + cyg_mutex_init( &db_lock ); + + cyg_semaphore_init( &sem, 0 ); + + for( i = 0; i < NTHREAD; i++ ) + { + cyg_thread_create(3, // Priority - just a number + fileio2_main, // entry + i, // index + 0, // no name + &stack[i][0], // Stack + STACK_SIZE, // Size + &thread_handle[i], // Handle + &thread[i] // Thread data structure + ); + cyg_thread_resume(thread_handle[i]); + } + + cyg_scheduler_start(); +} + +#else // CYGPKG_KERNEL + +#include <cyg/infra/testcase.h> + +externC void cyg_start(void) +{ + CYG_TEST_NA("Needs CYGPKG_KERNEL"); +} + +#endif + + +// ------------------------------------------------------------------------- +// EOF yaffs2.c
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/tests/yaffs4.c @@ -0,0 +1,949 @@ +//========================================================================== +// +// yaffs4.c +// +// Test fileio system +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. +// Copyright (C) 2004, 2005, 2006, 2007 eCosCentric Limited +// +// eCos 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 or (at your option) any later +// version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): nickg +// Contributors: nickg +// Date: 2005-07-25 +// Purpose: Test fileio system +// Description: This test uses the testfs to check out the initialization +// and basic operation of the fileio system. +// This is essentially a copy of yaffs1 but using long +// file names. +// +// +// +// +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/system.h> + +#ifdef CYGPKG_KERNEL + +#include <pkgconf/hal.h> +#include <pkgconf/kernel.h> +#include <pkgconf/io_fileio.h> + +#include CYGDAT_DEVS_DISK_CFG // testing config defines + +#include <cyg/kernel/ktypes.h> // base kernel types +#include <cyg/infra/cyg_trac.h> // tracing macros +#include <cyg/infra/cyg_ass.h> // assertion macros + +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> + +#include <cyg/fileio/fileio.h> + +#include <cyg/infra/testcase.h> +#include <cyg/infra/diag.h> // HAL polled output + +//========================================================================== +// Config options + +#define TEST_DEVICE CYGDAT_DEVS_DISK_TEST_DEVICE + +#define TEST_MOUNTPOINT CYGDAT_DEVS_DISK_TEST_MOUNTPOINT + +#define TEST_DIRECTORY CYGDAT_DEVS_DISK_TEST_DIRECTORY + +#define TEST_FSTYPE "yaffs" + +#ifdef CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DEVICE2 CYGDAT_DEVS_DISK_TEST_DEVICE2 + +#define TEST_MOUNTPOINT2 CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DIRECTORY2 CYGDAT_DEVS_DISK_TEST_DIRECTORY2 + +#define TEST_FSTYPE2 "yaffs" + +#endif + +//========================================================================== + +#define SHOW_RESULT( _fn, _res ) \ +{ \ + diag_printf("<FAIL>: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):""); \ +} + +//========================================================================== + +#define IOSIZE 100 + +#define CLEANUP + +#define LONGNAME1 "long_file_name_that_should_take_up_more_than_one_directory_entry_1" +#define LONGNAME2 "long_file_name_that_should_take_up_more_than_one_directory_entry_2" + +// 123456789012345678901234567890 +#define FOO "foo_longer_file_x.filename" +//#define FEE "fee_.filename" +//#define BAR "bar_long_directory_name.dirname" +#define FEE "a234567890123" +#define BAR "a2345678901234" +#define BUNDY "bundy_long_file_name_ccccccccccccccccccccccccccccccc.filename" +#define FUM "bundy_long_file_name_fum.filename" +#define DOO "doo_aaaaaaaaaabbbbbbbbbbbccccccccccccc" +#define FIE "fie.rrrrrrrrrrrrllllllllllllvvvvvvvvvvvvv" +#define FOE "foe_xxxxxxxxxxllllll.xxxxxxeeeeeeeeee" + +#define TINKY "tinky_long_file_name.filename" +#define LAALAA "laalaa_long_file_name.filename" +#define NOONOO "noonoo_long_directory_name.dirname" +#define DIPSY "dipsy_long_file_name.filename" +#define PO "po_long_file_name.filename" + +#define XXXX "xxxx_long_directory_name.dirname" +#define YYYY "yyyy_long_directory_name.dirname" +#define ZZZZ "zzzz_long_directory_name.dirname" +#define WWWW "wwww_long_directory_name.dirname" + + +//========================================================================== + +#ifndef CYGPKG_LIBC_STRING + +char *strcat( char *s1, const char *s2 ) +{ + char *s = s1; + while( *s1 ) s1++; + while( (*s1++ = *s2++) != 0); + return s; +} + +#endif + +__externC int +rename( const char * /* oldpath */, const char * /* newpath */ ) __THROW; + +//========================================================================== + +static void listdir( char *name, int statp, int numexpected, int *numgot ) +{ + int err; + DIR *dirp; + int num=0; + + diag_printf("<INFO>: reading directory %s\n",name); + +// diag_printf("<INFO>: opendir(%s)\n",name); + dirp = opendir( name ); + if( dirp == NULL ) SHOW_RESULT( opendir, -1 ); + + for(;;) + { + struct dirent *entry = readdir( dirp ); + + if( entry == NULL ) + break; + num++; + diag_printf("<INFO>: entry"); + if( statp ) + { + char fullname[PATH_MAX]; + struct stat sbuf; + + if( name[0] ) + { + strcpy(fullname, name ); + if( !(name[0] == '/' && name[1] == 0 ) ) + strcat(fullname, "/" ); + } + else fullname[0] = 0; + + strcat(fullname, entry->d_name ); + + err = stat( fullname, &sbuf ); + if( err < 0 ) + { + if( errno == ENOSYS ) + diag_printf(" <no status available>"); + else SHOW_RESULT( stat, err ); + } + else + { + diag_printf(" [mode %08x ino %08x nlink %d size %6ld]", + sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size); + } + } + + diag_printf(" %s\n",entry->d_name); + } + +// diag_printf("<INFO>: closedir(%s)\n",name); + err = closedir( dirp ); + if( err < 0 ) SHOW_RESULT( stat, err ); + if (numexpected >= 0 && num != numexpected) + CYG_TEST_FAIL("Wrong number of dir entries"); + if ( numgot != NULL ) + *numgot = num; +} + +//========================================================================== + +static void createfile( char *name, size_t size ) +{ + char buf[IOSIZE]; + int fd; + ssize_t wrote; + int i; + int err; + + diag_printf("<INFO>: create file %s size %ld\n",name, (long)size); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + while( size > 0 ) + { + ssize_t len = size; + if ( len > IOSIZE ) len = IOSIZE; + + wrote = write( fd, buf, len ); + if( wrote != len ) SHOW_RESULT( write, wrote ); + + size -= wrote; + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +//========================================================================== + +#if 0 +static void maxfile( char *name ) +{ + char buf[IOSIZE]; + int fd; + ssize_t wrote; + int i; + int err; + size_t size = 0; + size_t prevsize = 0; + + diag_printf("<INFO>: create maximal file %s\n",name); + diag_printf("<INFO>: This may take a few minutes\n"); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + do + { + wrote = write( fd, buf, IOSIZE ); + //if( wrote < 0 ) SHOW_RESULT( write, wrote ); + + if( wrote >= 0 ) + size += wrote; + + if( (size-prevsize) > 100000 ) + { + diag_printf("<INFO>: size = %ld \n", size); + prevsize = size; + } + + } while( wrote == IOSIZE ); + + diag_printf("<INFO>: file size == %ld\n",size); + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} +#endif + +//========================================================================== + +static void checkfile( char *name ) +{ + char buf[IOSIZE]; + int fd; + ssize_t done; + int i; + int err; + off_t pos = 0; + + diag_printf("<INFO>: check file %s\n",name); + + err = access( name, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd = open( name, O_RDONLY ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + for(;;) + { + done = read( fd, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + for( i = 0; i < done; i++ ) + if( buf[i] != i%256 ) + { + diag_printf("buf[%ld+%d](%02x) != %02x\n",pos,i,buf[i],i%256); + CYG_TEST_FAIL("Data read not equal to data written\n"); + for(;;); + } + + pos += done; + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +//========================================================================== + +static void copyfile( char *name2, char *name1 ) +{ + + int err; + char buf[IOSIZE]; + int fd1, fd2; + ssize_t done, wrote; + + diag_printf("<INFO>: copy file %s -> %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + err = access( name2, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_WRONLY|O_CREAT ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done = read( fd2, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + wrote = write( fd1, buf, done ); + if( wrote != done ) SHOW_RESULT( write, wrote ); + + if( wrote != done ) break; + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +//========================================================================== + +static void comparefiles( char *name2, char *name1 ) +{ + int err; + char buf1[IOSIZE]; + char buf2[IOSIZE]; + int fd1, fd2; + ssize_t done1, done2; + int i; + + diag_printf("<INFO>: compare files %s == %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_RDONLY ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done1 = read( fd1, buf1, IOSIZE ); + if( done1 < 0 ) SHOW_RESULT( read, done1 ); + + done2 = read( fd2, buf2, IOSIZE ); + if( done2 < 0 ) SHOW_RESULT( read, done2 ); + + if( done1 != done2 ) + diag_printf("Files different sizes\n"); + + if( done1 == 0 ) break; + + for( i = 0; i < done1; i++ ) + if( buf1[i] != buf2[i] ) + { + diag_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]); + CYG_TEST_FAIL("Data in files not equal\n"); + } + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +//========================================================================== + +void checkcwd( const char *cwd ) +{ + static char cwdbuf[PATH_MAX]; + char *ret; + + ret = getcwd( cwdbuf, sizeof(cwdbuf)); + if( ret == NULL ) SHOW_RESULT( getcwd, ret ); + + if( strcmp( cwdbuf, cwd ) != 0 ) + { + diag_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd ); + CYG_TEST_FAIL( "Current directory mismatch"); + } +} + +//========================================================================== +// main + +void fileio4_main( CYG_ADDRESS id ) +{ + int err; + int existingdirents=-1; + cyg_bool mp2 = false; + int fd; + + char dirname[256]; + char filename1[256]; + char filename2[256]; + +#define NEW_FILENAME( fn, f ) \ +{ \ + fn[0]=0; \ + strcat(fn, dirname); \ + strcat(fn, "/"); \ + strcat(fn,f); \ +} + +#define NEW_FILENAME1( f ) NEW_FILENAME( filename1, f ) +#define NEW_FILENAME2( f ) NEW_FILENAME( filename2, f ) + + CYG_TEST_INIT(); + + // -------------------------------------------------------------- + + err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE ); + if( err < 0 ) { + SHOW_RESULT( mount, err ); + CYG_TEST_FAIL_FINISH("yaffs4"); + } + + err = access( TEST_MOUNTPOINT TEST_DIRECTORY, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + if( err < 0 && errno == EACCES ) + { + diag_printf("<INFO>: create %s\n", + TEST_MOUNTPOINT TEST_DIRECTORY); + err = mkdir( TEST_MOUNTPOINT TEST_DIRECTORY, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + } + + err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY ); + + listdir( TEST_MOUNTPOINT TEST_DIRECTORY, true, -1, &existingdirents ); + + // -------------------------------------------------------------- + + dirname[0] = 0; + strcat(dirname, TEST_MOUNTPOINT ); + strcat(dirname, TEST_DIRECTORY ); + + // -------------------------------------------------------------- + + createfile( FOO, 20257 ); + checkfile( FOO ); + copyfile( FOO, FEE); + checkfile( FEE ); + comparefiles( FOO, FEE ); + diag_printf("<INFO>: mkdir " BAR "\n"); + err = mkdir( BAR, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + listdir( dirname , true, existingdirents+3, NULL ); + + copyfile( FEE, BAR "/" FUM ); + checkfile( BAR "/" FUM ); + comparefiles( FEE, BAR "/" FUM ); + + diag_printf("<INFO>: cd " BAR "\n"); + err = chdir( BAR ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + NEW_FILENAME1( BAR ); + checkcwd( filename1 ); + + diag_printf("<INFO>: rename ../" FOO " " BUNDY "\n"); + err = rename( "../" FOO, BUNDY ); + if( err < 0 ) SHOW_RESULT( rename, err ); + + listdir( dirname, true, existingdirents+2, NULL ); + listdir( "." , true, 4, NULL ); + + checkfile( "../" BAR "/" BUNDY ); + comparefiles("../" FEE, BUNDY ); + + // -------------------------------------------------------------- + // Check for some common error cases + + // First make some directories + diag_printf("<INFO>: mkdir " DOO "\n"); + err = mkdir( DOO, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir " FIE" \n"); + err = mkdir( FIE, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir " FIE "/" FOE "\n"); + err = mkdir( FIE "/" FOE, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + + diag_printf("<INFO>: rename " FUM " " DOO " -- should fail\n"); + err = rename( FUM, DOO ); + if( err < 0 && errno != EISDIR ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename " DOO " " FUM " -- should fail\n"); + err = rename( DOO, FUM ); + if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename " DOO " " FIE " -- should fail\n"); + err = rename( DOO, FIE ); + if( err < 0 && errno != EIO ) SHOW_RESULT( rename, err ); + + NEW_FILENAME1( XXXX "/" YYYY ) + diag_printf("<INFO>: rename " FUM " %s -- should fail\n",filename1); + err = rename( FUM, filename1 ); + if( err < 0 && errno != ENOENT ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename " FUM " " FUM " -- should fail\n"); + err = rename( FUM, FUM ); + if( err < 0 && errno != ENOENT ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: unlink " FEE " -- should fail\n"); + err = unlink( FEE ); + if( err < 0 && errno != ENOENT ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( BAR ); + diag_printf("<INFO>: rmdir %s -- should fail\n",filename1); + err = rmdir( filename1 ); + if( err < 0 && errno != ENOTEMPTY ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: unlink %s -- should fail\n",filename1); + err = unlink( filename1 ); + if( err < 0 && errno != EISDIR ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( BAR "/" FUM ); + diag_printf("<INFO>: rmdir %s -- should fail\n",filename1); + err = rmdir( filename1 ); + if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: mkdir %s -- should fail\n",filename1); + err = mkdir( filename1, 0 ); + if( err < 0 && errno != EEXIST ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: open " BUNDY " exclusive -- should fail\n"); + fd = open( BUNDY, O_WRONLY|O_CREAT|O_EXCL ); + if( fd < 0 && errno != EEXIST ) SHOW_RESULT( open, fd ); + + diag_printf("<INFO>: open %s -- should fail\n",dirname); + fd = open( dirname, O_WRONLY ); + if( fd < 0 && errno != EISDIR ) SHOW_RESULT( open, fd ); + + + listdir( dirname, true, existingdirents+2, NULL ); + listdir( "." , true, 6, NULL ); + + // -------------------------------------------------------------- + +#ifdef CLEANUP + + diag_printf("<INFO>: rename " FIE " " DOO "\n"); + err = rename( FIE, DOO ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: rmdir " DOO "/" FOE "\n"); + err = rmdir(DOO "/" FOE); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: rmdir " DOO "\n"); + err = rmdir(DOO); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink ../" FEE "\n"); + err = unlink( "../" FEE ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink " FUM "\n"); + err = unlink( FUM ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink ../" BAR "/" BUNDY "\n"); + err = unlink( "../" BAR "/" BUNDY ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( dirname ); + +#ifdef CLEANUP + diag_printf("<INFO>: rmdir " BAR "\n"); + err = rmdir( BAR ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + listdir( dirname, false, existingdirents, NULL ); +#endif + + // -------------------------------------------------------------- + +#ifdef TEST_MOUNTPOINT2 + diag_printf("<INFO>: mount %s\n", TEST_MOUNTPOINT2); + err = mount( TEST_DEVICE2, TEST_MOUNTPOINT2, TEST_FSTYPE2 ); + + if( err == 0 ) + { + mp2 = true; + diag_printf("<INFO>: mount %s succeeded\n", TEST_MOUNTPOINT2); + err = access( TEST_MOUNTPOINT2 TEST_DIRECTORY2, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + if( err < 0 && errno == EACCES ) + { + diag_printf("<INFO>: create %s\n", + TEST_MOUNTPOINT2 TEST_DIRECTORY2); + err = mkdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + } + + err = chdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2 ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( TEST_MOUNTPOINT2 TEST_DIRECTORY2 ); + + dirname[0] = 0; + strcat(dirname, TEST_MOUNTPOINT2 ); + strcat(dirname, TEST_DIRECTORY2 ); + + } + else + { + mp2 = false; + diag_printf("<INFO>: mount %s failed, ", TEST_MOUNTPOINT2); + diag_printf("using %s instead\n", dirname ); + } + +#endif + + listdir( dirname , true, -1, &existingdirents); + + NEW_FILENAME1( TINKY ); + NEW_FILENAME2( LAALAA ); + + createfile( filename1, 4567 ); + copyfile( filename1, filename2 ); + checkfile( filename1); + checkfile( filename2); + comparefiles( filename1, filename2 ); + + diag_printf("<INFO>: cd %s\n",dirname); + err = chdir( dirname ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( dirname ); + + diag_printf("<INFO>: mkdir " NOONOO "\n"); + err = mkdir( NOONOO, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + listdir( dirname , true, existingdirents+3, NULL); + + diag_printf("<INFO>: cd " NOONOO "\n"); + err = chdir( NOONOO ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + NEW_FILENAME1( NOONOO ); + checkcwd( filename1 ); + + createfile( TINKY, 6789 ); + checkfile( TINKY ); + + createfile( DIPSY, 34567 ); + checkfile( DIPSY ); + copyfile( DIPSY, PO ); + checkfile( PO ); + comparefiles( DIPSY, PO ); + + listdir( ".", true, 5, NULL ); + listdir( "..", true, existingdirents+3, NULL ); + + // -------------------------------------------------------------- + +#ifdef CLEANUP + diag_printf("<INFO>: unlink " TINKY "\n"); + err = unlink( TINKY ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink " DIPSY "\n"); + err = unlink( DIPSY ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink " PO "\n"); + err = unlink( PO ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( dirname ); + +#ifdef CLEANUP + diag_printf("<INFO>: rmdir " NOONOO "\n"); + err = rmdir( NOONOO ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); +#endif + + // -------------------------------------------------------------- + + diag_printf("<INFO>: mkdir " XXXX "\n"); + err = mkdir( XXXX, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir " XXXX "/" YYYY "\n"); + err = mkdir( XXXX "/" YYYY, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir " XXXX "/" YYYY "/" ZZZZ "\n"); + err = mkdir( XXXX "/" YYYY "/" ZZZZ, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir " XXXX "/" YYYY "/" ZZZZ "/" WWWW "\n"); + err = mkdir( XXXX "/" YYYY "/" ZZZZ "/" WWWW, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ "/" WWWW ); + diag_printf("<INFO>: cd %s\n",filename1); + err = chdir( filename1 ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ ); + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ ); + diag_printf("<INFO>: cd .\n"); + err = chdir( "." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( XXXX "/" YYYY ); + diag_printf("<INFO>: cd ../../" YYYY "\n"); + err = chdir( "../../" YYYY ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + diag_printf("<INFO>: cd ../..\n"); + err = chdir( "../.." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( dirname ); + + diag_printf("<INFO>: rmdir " XXXX "/" YYYY "/" ZZZZ "/" WWWW "\n"); + err = rmdir( XXXX "/" YYYY "/" ZZZZ "/" WWWW ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir "XXXX "/" YYYY "/" ZZZZ "\n"); + err = rmdir( XXXX "/" YYYY "/" ZZZZ ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir " XXXX "/" YYYY "\n"); + err = rmdir( XXXX "/" YYYY ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir "XXXX "\n"); + err = rmdir( XXXX ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + // -------------------------------------------------------------- + + checkcwd( dirname ); + +#ifdef CLEANUP + diag_printf("<INFO>: unlink "TINKY "\n"); + err = unlink( TINKY ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink " LAALAA" \n"); + err = unlink( LAALAA ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + // -------------------------------------------------------------- + + diag_printf("<INFO>: cd %s\n", TEST_MOUNTPOINT TEST_DIRECTORY); + err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY ); + + listdir( ".", true, -1, NULL ); + +#ifdef TEST_MOUNTPOINT2 + if( mp2 ) + { + diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT2); + err = umount( TEST_MOUNTPOINT2 ); + if( err < 0 ) SHOW_RESULT( umount, err ); + } +#endif + + // -------------------------------------------------------------- + +#if 0 + maxfile("file.max"); + + listdir( "/", true, -1, NULL ); + + diag_printf("<INFO>: unlink file.max\n"); + err = unlink( "file.max" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + // -------------------------------------------------------------- + + diag_printf("<INFO>: cd /\n"); + err = chdir( "/" ); + if( err == 0 ) + { + checkcwd( "/" ); + + diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT); + err = umount( TEST_MOUNTPOINT ); + if( err < 0 ) SHOW_RESULT( umount, err ); + } + + diag_printf("<INFO>: syncing\n"); + cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_SYNC, NULL, 0); // sync(); + + CYG_TEST_PASS_FINISH("yaffs4"); +} + +// ------------------------------------------------------------------------- + +#include <cyg/kernel/kapi.h> + +static cyg_handle_t thread_handle; +static cyg_thread thread; +static char stack[CYGNUM_HAL_STACK_SIZE_TYPICAL+1024*4]; + +externC void +cyg_start( void ) +{ + cyg_thread_create(3, // Priority - just a number + fileio4_main, // entry + 0, // index + 0, // no name + &stack[0], // Stack + sizeof(stack), // Size + &thread_handle, // Handle + &thread // Thread data structure + ); + cyg_thread_resume(thread_handle); + + cyg_scheduler_start(); +} + +#else // CYGPKG_KERNEL + +#include <cyg/infra/testcase.h> + +externC void cyg_start(void) +{ + CYG_TEST_NA("Needs CYGPKG_KERNEL"); +} + +#endif + +// ------------------------------------------------------------------------- +// EOF yaffs4.c
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/tests/yaffs5.c @@ -0,0 +1,830 @@ +//========================================================================== +// +// yaffs5.c +// +// Test FAT filesystem +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2007 Free Software Foundation, Inc. +// Copyright (C) 2004, 2006, 2007 eCosCentric Limited +// +// eCos 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 or (at your option) any later +// version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): nickg +// Contributors: nickg +// Date: 2007-03-28 +// Purpose: Test FAT system +// Description: This test gets some performance figures from the +// FAT filesystem. +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/system.h> + +#ifdef CYGPKG_KERNEL + +#include <pkgconf/hal.h> +#include <pkgconf/kernel.h> +#include <pkgconf/io_fileio.h> + +#include CYGDAT_DEVS_DISK_CFG // testing config defines + +#include <cyg/kernel/ktypes.h> // base kernel types +#include <cyg/infra/cyg_trac.h> // tracing macros +#include <cyg/infra/cyg_ass.h> // assertion macros + +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> +#include <stdlib.h> + +#include <cyg/fileio/fileio.h> + +#include <cyg/infra/testcase.h> +#include <cyg/infra/diag.h> // HAL polled output + +//========================================================================== +// Config options + +#define TEST_DEVICE CYGDAT_DEVS_DISK_TEST_DEVICE + +#define TEST_MOUNTPOINT CYGDAT_DEVS_DISK_TEST_MOUNTPOINT + +#define TEST_DIRECTORY CYGDAT_DEVS_DISK_TEST_DIRECTORY + +#define TEST_FSTYPE "yaffs" + +#ifdef CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DEVICE2 CYGDAT_DEVS_DISK_TEST_DEVICE2 + +#define TEST_MOUNTPOINT2 CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DIRECTORY2 CYGDAT_DEVS_DISK_TEST_DIRECTORY2 + +#define TEST_FSTYPE2 "yaffs" + +#endif + +//========================================================================== + +#define SHOW_RESULT( _fn, _res ) \ +{ \ + diag_printf("<FAIL>: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):""); \ +} + +//========================================================================== + +typedef struct +{ + cyg_int64 ticks; + cyg_int32 halticks; +} timestamp; + +typedef struct +{ + timestamp start; + timestamp end; + cyg_int64 interval; // In HAL ticks + cyg_int64 us_interval; // Interval in microseconds +} timing; + +static cyg_int64 ticks_overhead = 0; +static cyg_int32 us_per_haltick = 0; +static cyg_int32 halticks_per_us = 0; + +static cyg_int64 rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION; +static cyg_int64 rtc_period = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; +static cyg_int32 ticks_per_second; + +//========================================================================== + +static char date_string[] = __DATE__; +static char time_string[] = __TIME__; + +cyg_uint32 timehash; + +//========================================================================== + +static void wait_for_tick( void ) +{ + cyg_tick_count_t now = cyg_current_time(); + + while( cyg_current_time() == now ) + continue; +} + +static void get_timestamp( timestamp *ts ) +{ + ts->ticks = cyg_current_time(); + HAL_CLOCK_READ( (cyg_uint32 *)&ts->halticks ); +} + +static cyg_int64 ticks_to_us( cyg_int64 ticks ) +{ + cyg_int64 us; + + if( us_per_haltick != 0 ) + us = ticks * us_per_haltick; + else + us = ticks / halticks_per_us; + + return us; +} + +static void calculate_interval( timing *t ) +{ + t->interval = t->end.halticks - t->start.halticks; + + t->interval += (t->end.ticks - t->start.ticks) * rtc_period; + + t->interval -= ticks_overhead; + + t->us_interval = ticks_to_us( t->interval ); +} + +static void init_timing( void ) +{ + timing t; + + ticks_per_second = (1000000000ULL*rtc_resolution[1])/rtc_resolution[0]; + us_per_haltick = 1000000/(rtc_period * rtc_resolution[1]); + halticks_per_us = (rtc_period * rtc_resolution[1])/1000000; + + wait_for_tick(); + + get_timestamp( &t.start ); + get_timestamp( &t.end ); + + calculate_interval( &t ); + + ticks_overhead = t.interval; + + diag_printf("Timing overhead %lld ticks\n", ticks_overhead ); + +} + +//========================================================================== + +#ifndef CYGPKG_LIBC_STRING + +char *strcat( char *s1, const char *s2 ) +{ + char *s = s1; + while( *s1 ) s1++; + while( (*s1++ = *s2++) != 0); + return s; +} + +#endif + +__externC int +rename( const char * /* oldpath */, const char * /* newpath */ ) __THROW; + +//========================================================================== + +static void listdir( char *name, int statp, int numexpected, int *numgot ) +{ + int err; + DIR *dirp; + int num=0; + + diag_printf("<INFO>: reading directory %s\n",name); + +// diag_printf("<INFO>: opendir(%s)\n",name); + dirp = opendir( name ); + if( dirp == NULL ) SHOW_RESULT( opendir, -1 ); + + for(;;) + { + struct dirent *entry = readdir( dirp ); + + if( entry == NULL ) + break; + num++; + diag_printf("<INFO>: entry %14s",entry->d_name); + if( statp ) + { + char fullname[PATH_MAX]; + struct stat sbuf; + + if( name[0] ) + { + strcpy(fullname, name ); + if( !(name[0] == '/' && name[1] == 0 ) ) + strcat(fullname, "/" ); + } + else fullname[0] = 0; + + strcat(fullname, entry->d_name ); + + err = stat( fullname, &sbuf ); + if( err < 0 ) + { + if( errno == ENOSYS ) + diag_printf(" <no status available>"); + else SHOW_RESULT( stat, err ); + } + else + { + diag_printf(" [mode %08x ino %08x nlink %d size %ld]", + sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size); + } + } + + diag_printf("\n"); + } + +// diag_printf("<INFO>: closedir(%s)\n",name); + err = closedir( dirp ); + if( err < 0 ) SHOW_RESULT( stat, err ); + if (numexpected >= 0 && num != numexpected) + CYG_TEST_FAIL("Wrong number of dir entries\n"); + if ( numgot != NULL ) + *numgot = num; +} + +//========================================================================== + +static void createfile( char *name, size_t asize, size_t block_size ) +{ + size_t size = asize; + cyg_uint8 *buf; + cyg_uint32 *b; + int fd; + ssize_t wrote; + int i; + int err; + timing opent, writet; + + diag_printf("\n--------------------------------------------------------------------\n"); + diag_printf("<INFO>: create file %s size %ld block_size %ld\n",name, (long)size, (long)block_size); + + buf = malloc( block_size ); + if( buf == NULL ) + { + SHOW_RESULT( malloc, -1 ); + return; + } + b = (cyg_uint32 *)buf; + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + i = 0; + while( i < block_size/sizeof(cyg_uint32) ) + { + b[i] = i; + i++; + b[i++] = 0; + b[i++] = timehash; + b[i++] = 0x12345678; + } + + + get_timestamp( &opent.start ); + fd = open( name, O_WRONLY|O_CREAT ); + get_timestamp( &opent.end ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + get_timestamp( &writet.start ); + while( size > 0 ) + { + ssize_t len = size; + if ( len > block_size ) len = block_size; + + b[1] = asize-size; + b[block_size/sizeof(cyg_uint32)-3] = asize-size; + wrote = write( fd, buf, len ); + if( wrote != len ) SHOW_RESULT( write, wrote ); + + size -= wrote; + } + get_timestamp( &writet.end ); + + free( buf ); + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); + + calculate_interval( &opent ); + calculate_interval( &writet ); + + diag_printf("CreateFile Results: %s size %ld\n", name, (long)asize); + diag_printf(" Open %8d.%03d ms\n", (int)(opent.us_interval/1000), (int)(opent.us_interval%1000) ); + diag_printf(" Write %8d.%03d ms\n", (int)(writet.us_interval/1000), (int)(writet.us_interval%1000) ); + diag_printf(" Data Rate %10lld KiB/s\n", (1000000LL*asize)/1024/writet.us_interval); +} + +//========================================================================== + +static void checkfile( char *name, size_t block_size ) +{ + cyg_uint8 *buf; + cyg_uint32 *b; + int fd; + ssize_t done; + int err; + off_t pos = 0; + timing opent, readt; + + diag_printf("\n--------------------------------------------------------------------\n"); + diag_printf("<INFO>: check file %s\n",name); + + buf = malloc( block_size ); + if( buf == NULL ) + { + SHOW_RESULT( malloc, -1 ); + return; + } + b = (cyg_uint32 *)buf; + + err = access( name, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + get_timestamp( &opent.start ); + fd = open( name, O_RDONLY ); + get_timestamp( &opent.end ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + get_timestamp( &readt.start ); + for(;;) + { + done = read( fd, buf, block_size ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + // Check that this is the block we wrote + if( b[0] != 0 ) + diag_printf("b[%d] != %08x\n", 0, 0 ); + + if( b[1] != pos ) + diag_printf("b[%d] != %08x\n", 1, (unsigned)pos ); + + if( b[2] != timehash ) + diag_printf("b[%d] != %08x\n", 2, timehash ); + + if( b[3] != 0x12345678 ) + diag_printf("b[%d] != %08x\n", 3, 0x12345678 ); + + if( b[(block_size/sizeof(cyg_uint32))-4] != (block_size/sizeof(cyg_uint32)-4) ) + diag_printf("b[%lu](%08x) != %08x\n", (long)block_size/sizeof(cyg_uint32)-4, + b[(block_size/sizeof(cyg_uint32))-4], + (unsigned)(block_size/sizeof(cyg_uint32)-4) ); + + if( b[block_size/sizeof(cyg_uint32)-3] != pos ) + diag_printf("b[%lu] != %08x\n", (long)block_size/sizeof(cyg_uint32)-3, (unsigned)pos ); + + if( b[block_size/sizeof(cyg_uint32)-2] != timehash ) + diag_printf("b[%lu] != %08x\n", (long)block_size/sizeof(cyg_uint32)-2, timehash ); + + if( b[block_size/sizeof(cyg_uint32)-1] != 0x12345678 ) + diag_printf("b[%lu] != %08x\n", (long)block_size/sizeof(cyg_uint32)-1, 0x12345678 ); + + pos += done; + } + get_timestamp( &readt.end ); + + free( buf ); + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); + + calculate_interval( &opent ); + calculate_interval( &readt ); + + diag_printf("CheckFile Results: %s size %ld\n", name, pos); + diag_printf(" Open %8d.%03d ms\n", (int)(opent.us_interval/1000), (int)(opent.us_interval%1000) ); + diag_printf(" Read %8d.%03d ms\n", (int)(readt.us_interval/1000), (int)(readt.us_interval%1000) ); + diag_printf(" Data Rate %10lld KiB/s\n", (1000000LL*pos)/1024/readt.us_interval); +} + +//========================================================================== + +#define TIME_DATA_MAX 20 + +static void checkfile1( char *name, size_t block_size ) +{ + cyg_uint8 *buf; + cyg_uint32 *b; + int fd; + ssize_t done; + int err; + off_t pos = 0; + timing totalt; + + struct + { + int valid; + timing mountt; + timing opent; + timing seekt; + timing readt; + timing closet; + timing umountt; + } time_data[TIME_DATA_MAX]; + int td; + + for( td = 0; td < TIME_DATA_MAX; td++ ) + time_data[td].valid = 0; + td = 0; + + diag_printf("\n--------------------------------------------------------------------\n"); + diag_printf("<INFO>: check file1 %s\n",name); + + buf = malloc( block_size ); + if( buf == NULL ) + { + SHOW_RESULT( malloc, -1 ); + return; + } + b = (cyg_uint32 *)buf; + + get_timestamp( &totalt.start ); + for(;;) + { + get_timestamp( &time_data[td].mountt.start ); + err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE ); + get_timestamp( &time_data[td].mountt.end ); + if( err < 0 ) SHOW_RESULT( mount, err ); + + get_timestamp( &time_data[td].opent.start ); + fd = open( name, O_RDONLY ); + get_timestamp( &time_data[td].opent.end ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + get_timestamp( &time_data[td].seekt.start ); + err = lseek( fd, pos, SEEK_SET ); + get_timestamp( &time_data[td].seekt.end ); + if( err < 0 ) SHOW_RESULT( lseek, err ); + + get_timestamp( &time_data[td].readt.start ); + done = read( fd, buf, block_size ); + get_timestamp( &time_data[td].readt.end ); + if( done < 0 ) SHOW_RESULT( read, done ); + + get_timestamp( &time_data[td].closet.start ); + err = close( fd ); + get_timestamp( &time_data[td].closet.end ); + if( err < 0 ) SHOW_RESULT( close, err ); + + get_timestamp( &time_data[td].umountt.start ); + err = umount( TEST_MOUNTPOINT ); + get_timestamp( &time_data[td].umountt.end ); + if( err < 0 ) SHOW_RESULT( umount, err ); + + if( done == 0 ) break; + + // Check that this is the block we wrote + if( b[0] != 0 ) + diag_printf("b[%d] != %08x\n", 0, 0 ); + + if( b[1] != pos ) + diag_printf("b[%d] != %08x\n", 1, (unsigned)pos ); + +// if( b[2] != timehash ) +// diag_printf("b[%d] != %08x\n", 2, timehash ); + + if( b[3] != 0x12345678 ) + diag_printf("b[%d] != %08x\n", 3, 0x12345678 ); + + if( b[(block_size/sizeof(cyg_uint32))-4] != (block_size/sizeof(cyg_uint32)-4) ) + diag_printf("b[%lu](%08x) != %08x\n", (long)block_size/sizeof(cyg_uint32)-4, + b[(block_size/sizeof(cyg_uint32))-4], + (unsigned)(block_size/sizeof(cyg_uint32)-4) ); + + if( b[block_size/sizeof(cyg_uint32)-3] != pos ) + diag_printf("b[%lu] != %08x\n", (long)block_size/sizeof(cyg_uint32)-3, (unsigned)pos ); + +// if( b[block_size/sizeof(cyg_uint32)-2] != timehash ) +// diag_printf("b[%d] != %08x\n", block_size/sizeof(cyg_uint32)-2, timehash ); + + if( b[block_size/sizeof(cyg_uint32)-1] != 0x12345678 ) + diag_printf("b[%lu] != %08x\n", (long)block_size/sizeof(cyg_uint32)-1, 0x12345678 ); + + pos += done; + + time_data[td].valid = 1; + if( td < (TIME_DATA_MAX-1) ) + td++; + } + get_timestamp( &totalt.end ); + + free( buf ); + + diag_printf("Block Mount Open Seek Read Close Umount\n"); + + for( td = 0; td < TIME_DATA_MAX; td++ ) + { + if( !time_data[td].valid ) + continue; + + calculate_interval( &time_data[td].mountt ); + calculate_interval( &time_data[td].opent ); + calculate_interval( &time_data[td].seekt ); + calculate_interval( &time_data[td].readt ); + calculate_interval( &time_data[td].closet ); + calculate_interval( &time_data[td].umountt ); + + diag_printf("%2d:", td); + diag_printf(" %8d.%03d", (int)(time_data[td].mountt.us_interval/1000), (int)(time_data[td].mountt.us_interval%1000) ); + diag_printf(" %8d.%03d", (int)(time_data[td].opent.us_interval/1000), (int)(time_data[td].opent.us_interval%1000) ); + diag_printf(" %8d.%03d", (int)(time_data[td].seekt.us_interval/1000), (int)(time_data[td].seekt.us_interval%1000) ); + diag_printf(" %8d.%03d", (int)(time_data[td].readt.us_interval/1000), (int)(time_data[td].readt.us_interval%1000) ); + diag_printf(" %8d.%03d", (int)(time_data[td].closet.us_interval/1000), (int)(time_data[td].closet.us_interval%1000) ); + diag_printf(" %8d.%03d", (int)(time_data[td].umountt.us_interval/1000), (int)(time_data[td].umountt.us_interval%1000) ); + diag_printf("\n"); + } + + calculate_interval( &totalt ); + diag_printf("CheckFile1 Results: %s size %ld\n", name, pos); + diag_printf(" Total %8d.%03d ms\n", (int)(totalt.us_interval/1000), (int)(totalt.us_interval%1000) ); + diag_printf(" Data Rate %10lld KiB/s\n", (1000000LL*pos)/1024/totalt.us_interval); + +} + +//========================================================================== + +void checkcwd( const char *cwd ) +{ + static char cwdbuf[PATH_MAX]; + char *ret; + + ret = getcwd( cwdbuf, sizeof(cwdbuf)); + if( ret == NULL ) SHOW_RESULT( getcwd, ret ); + + if( strcmp( cwdbuf, cwd ) != 0 ) + { + diag_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd ); + CYG_TEST_FAIL( "Current directory mismatch"); + } +} + +//========================================================================== + +void fs_callback( cyg_int32 event, CYG_ADDRWORD data ) +{ +#if 0 + diag_printf("Filesystem %sSAFE\n", + event==CYG_FS_CALLBACK_UNSAFE?"UN":""); +#endif +} + + +//========================================================================== +// main + +void yaffs5_main( CYG_ADDRESS id ) +{ + int err; + int existingdirents=-1; + int i; + timing mountt, umountt; + +#if defined(CYGSEM_FILEIO_BLOCK_USAGE) + struct cyg_fs_block_usage usage; +#endif +// struct cyg_fs_callback_info callback; + + CYG_TEST_INIT(); + + init_timing(); + + for( i = 0 ; date_string[i] != 0 ; i++ ) + timehash = (timehash<<1) ^ date_string[i]; + for( i = 0 ; time_string[i] != 0 ; i++ ) + timehash = (timehash<<1) ^ time_string[i]; + + // -------------------------------------------------------------- + +#if 1 +#define DO_UMOUNT + get_timestamp( &mountt.start ); + err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE ); +// err = mount( TEST_DEVICE, TEST_MOUNTPOINT, "yaffs:sync=write" ); +// err = mount( TEST_DEVICE, TEST_MOUNTPOINT, "yaffs:sync=close" ); +// err = mount( TEST_DEVICE, TEST_MOUNTPOINT, "yaffs:sync=data" ); + get_timestamp( &mountt.end ); + if( err < 0 ) { + SHOW_RESULT( mount, err ); + CYG_TEST_FAIL_FINISH("yaffs5"); + } + +#if 0 + callback.callback = fs_callback; + callback.data = 0; + err = cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_CALLBACK, + &callback, sizeof(callback)); + if( err < 0 ) SHOW_RESULT( cyg_fs_setinfo, err ); +#endif + + calculate_interval( &mountt ); + diag_printf(" Mount %8d.%03d ms\n", (int)(mountt.us_interval/1000), (int)(mountt.us_interval%1000) ); + + err = access( TEST_MOUNTPOINT TEST_DIRECTORY, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + if( err < 0 && errno == EACCES ) + { + diag_printf("<INFO>: create %s\n", + TEST_MOUNTPOINT TEST_DIRECTORY); + err = mkdir( TEST_MOUNTPOINT TEST_DIRECTORY, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + } + + err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY ); + + listdir( TEST_MOUNTPOINT TEST_DIRECTORY, true, -1, &existingdirents ); + + // -------------------------------------------------------------- +#if defined(CYGSEM_FILEIO_BLOCK_USAGE) + err = cyg_fs_getinfo(TEST_MOUNTPOINT, FS_INFO_BLOCK_USAGE, + &usage, sizeof(usage)); + if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err ); + diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n", + usage.total_blocks, usage.total_blocks * usage.block_size); + diag_printf("<INFO>: free size: %6lld blocks, %10lld bytes\n", + usage.free_blocks, usage.free_blocks * usage.block_size); + diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size); +#endif + // -------------------------------------------------------------- + +#endif + +#if 1 + createfile( "yaffs5.0", 1024*1024, 16*1024 ); + checkfile( "yaffs5.0",16*1024 ); + err = unlink( "yaffs5.0" ); + cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_SYNC, NULL, 0); // sync(); +#endif + +#if 1 + createfile( "yaffs5.0", 200*1024, 1024 ); + checkfile( "yaffs5.0", 1024 ); + err = unlink( "yaffs5.0" ); +#endif + +#if 1 + createfile( "yaffs5.1", 1024*1024, 1024 ); + createfile( "yaffs5.2", 1024*1024, 4*1024 ); + cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_SYNC, NULL, 0); // sync(); + createfile( "yaffs5.3", 8*1024*1024, 32*1024 ); + + checkfile( "yaffs5.1", 1024 ); + checkfile( "yaffs5.2", 4*1024 ); + checkfile( "yaffs5.3", 32*1024 ); + + diag_printf("\n--------------------------------------------------------------------\n"); + + listdir( "." , true, existingdirents+3, NULL ); + + // -------------------------------------------------------------- + + diag_printf("<INFO>: unlink yaffs5.1\n"); + err = unlink( "yaffs5.1" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink yaffs5.2\n"); + err = unlink( "yaffs5.2" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink yaffs5.3\n"); + err = unlink( "yaffs5.3" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + // -------------------------------------------------------------- + +#if 1 && defined(DO_UMOUNT) + + diag_printf("<INFO>: unlink yaffs5.4\n"); + err = unlink( "yaffs5.4" ); + + createfile( "yaffs5.4", 5*1024*1024, 32*1024 ); +#endif + + // -------------------------------------------------------------- + +#ifdef DO_UMOUNT + diag_printf("<INFO>: cd /\n"); + err = chdir( "/" ); + if( err == 0 ) + { + checkcwd( "/" ); + + diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT); + get_timestamp( &umountt.start ); + err = umount( TEST_MOUNTPOINT ); + get_timestamp( &umountt.end ); + if( err < 0 ) SHOW_RESULT( umount, err ); + + calculate_interval( &umountt ); + diag_printf(" Umount %8d.%03d ms\n", (int)(umountt.us_interval/1000), (int)(umountt.us_interval%1000) ); + + } +#endif + +#if 1 + + diag_printf("<INFO>: syncing\n"); + cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_SYNC, NULL, 0); // sync(); + + checkfile1(TEST_MOUNTPOINT TEST_DIRECTORY "/yaffs5.4", 32*1024 ); + + // Remount just to remove yaffs5.4 + err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE ); + if( err < 0 ) { + SHOW_RESULT( mount, err ); + CYG_TEST_FAIL_FINISH("yaffs5"); + } + err = unlink( TEST_MOUNTPOINT TEST_DIRECTORY "/yaffs5.4" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + err = umount( TEST_MOUNTPOINT ); + if( err < 0 ) SHOW_RESULT( umount, err ); + +#endif + + diag_printf("<INFO>: syncing\n"); + cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_SYNC, NULL, 0); // sync(); + + CYG_TEST_PASS_FINISH("yaffs5"); +} + +// ------------------------------------------------------------------------- + +#include <cyg/kernel/kapi.h> + +static cyg_handle_t thread_handle; +static cyg_thread thread; +static char stack[CYGNUM_HAL_STACK_SIZE_TYPICAL+8*1024]; +//static char stack[64*1024]; + +externC void +cyg_start( void ) +{ + cyg_thread_create(3, // Priority - just a number + yaffs5_main, // entry + 0, // index + 0, // no name + &stack[0], // Stack + sizeof(stack), // Size + &thread_handle, // Handle + &thread // Thread data structure + ); + cyg_thread_resume(thread_handle); + + cyg_scheduler_start(); +} + +#else // CYGPKG_KERNEL + +#include <cyg/infra/testcase.h> + +externC void cyg_start(void) +{ + CYG_TEST_NA("Needs CYGPKG_KERNEL"); +} + +#endif + +// ------------------------------------------------------------------------- +// EOF yaffs5.c
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/tests/yaffs6.c @@ -0,0 +1,983 @@ +//========================================================================== +// +// yaffs6.c +// +// Test FAT UTF-8 support +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. +// Copyright (C) 2004, 2005, 2006, 2007 eCosCentric Limited +// +// eCos 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 or (at your option) any later +// version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): nickg +// Contributors: nickg +// Date: 2007-06-20 +// Purpose: Test fileio system +// Description: This test uses the testfs to check out the initialization +// and basic operation of the fileio system. +// This is essentially a copy of yaffs4 with UTF8 encoded +// file names. +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/system.h> + +#ifdef CYGPKG_KERNEL + +#include <pkgconf/hal.h> +#include <pkgconf/kernel.h> +#include <pkgconf/io_fileio.h> + +#include CYGDAT_DEVS_DISK_CFG // testing config defines + +#include <cyg/kernel/ktypes.h> // base kernel types +#include <cyg/infra/cyg_trac.h> // tracing macros +#include <cyg/infra/cyg_ass.h> // assertion macros + +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> + +#include <cyg/fileio/fileio.h> + +#include <cyg/infra/testcase.h> +#include <cyg/infra/diag.h> // HAL polled output + +//========================================================================== +// Config options + +#define TEST_DEVICE CYGDAT_DEVS_DISK_TEST_DEVICE + +#define TEST_MOUNTPOINT CYGDAT_DEVS_DISK_TEST_MOUNTPOINT + +#define TEST_DIRECTORY CYGDAT_DEVS_DISK_TEST_DIRECTORY + +#define TEST_FSTYPE "yaffs" + +#ifdef CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DEVICE2 CYGDAT_DEVS_DISK_TEST_DEVICE2 + +#define TEST_MOUNTPOINT2 CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DIRECTORY2 CYGDAT_DEVS_DISK_TEST_DIRECTORY2 + +#define TEST_FSTYPE2 "yaffs" + +#endif + +//========================================================================== + +#define SHOW_RESULT( _fn, _res ) \ +{ \ + diag_printf("<FAIL>: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):""); \ +} + +//========================================================================== + +#define IOSIZE 100 + +#define CLEANUP + +//========================================================================== +// The following filenames are in Cyrillic and are UTF-8 encoded. +// +// WARNING: Only edit this file with an editor that is UTF-8 aware (I +// use EMACS on Linux, but Notepad on Windows also works). Saving this +// file from an unaware editor could cause these strings to be +// corrupted and make this test fail. If the strings below do not +// appear as clean Cyrillic characters then exit now without saving +// and look for a better editor. + +#if 1 + +#define FOO "Фоо" +#define FEE "Спутник" +#define BAR "Байконур" +#define BUNDY "СергеЬй ПаЬвлович Королёв" +#define FUM "Юрий Гагаринский" +#define DOO "Константин Эдуардович Циолковский" +//#define FIE "Федеральное космическое агентство России" +#define FIE "Федеральное космическое" +#define FOE "Валентин Петрович Глушко" + +#define TINKY "Восток" +#define LAALAA "Восход" +#define NOONOO "Салют" +#define DIPSY "Космодром" +#define PO "Лайка" + +#define XXXX "Гласность" +#define YYYY "перестройка" +#define ZZZZ "Калашникова" +#define WWWW "матрёшка" + +#else + +#define FOO "foo" +#define FEE "fee" +#define BAR "bar" +#define BUNDY "bundy" +#define FUM "fum" +#define DOO "doo" +#define FIE "fie" +#define FOE "foe" + +#define TINKY "tinky" +#define LAALAA "laalaa" +#define NOONOO "noonoo" +#define DIPSY "dipsy" +#define PO "po" + +#define XXXX "xxxx" +#define YYYY "yyyy" +#define ZZZZ "zzzz" +#define WWWW "wwww" + +#endif + + +//========================================================================== + +#ifndef CYGPKG_LIBC_STRING + +char *strcat( char *s1, const char *s2 ) +{ + char *s = s1; + while( *s1 ) s1++; + while( (*s1++ = *s2++) != 0); + return s; +} + +#endif + +__externC int +rename( const char * /* oldpath */, const char * /* newpath */ ) __THROW; + +//========================================================================== + +static void listdir( char *name, int statp, int numexpected, int *numgot ) +{ + int err; + DIR *dirp; + int num=0; + + diag_printf("<INFO>: reading directory %s\n",name); + +// diag_printf("<INFO>: opendir(%s)\n",name); + dirp = opendir( name ); + if( dirp == NULL ) SHOW_RESULT( opendir, -1 ); + + for(;;) + { + struct dirent *entry = readdir( dirp ); + + if( entry == NULL ) + break; + num++; + + diag_printf("<INFO>: entry "); + + if( statp ) + { + char fullname[PATH_MAX]; + struct stat sbuf; + + if( name[0] ) + { + strcpy(fullname, name ); + if( !(name[0] == '/' && name[1] == 0 ) ) + strcat(fullname, "/" ); + } + else fullname[0] = 0; + + strcat(fullname, entry->d_name ); + + err = stat( fullname, &sbuf ); + if( err < 0 ) + { + if( errno == ENOSYS ) + diag_printf(" <no status available>"); + else SHOW_RESULT( stat, err ); + } + else + { + diag_printf(" [mode %08x ino %08x nlink %d size %6ld]", + sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size); + } + } + + diag_printf(" %s\n",entry->d_name); + } + +// diag_printf("<INFO>: closedir(%s)\n",name); + err = closedir( dirp ); + if( err < 0 ) SHOW_RESULT( stat, err ); + if (numexpected >= 0 && num != numexpected) + CYG_TEST_FAIL("Wrong number of dir entries"); + if ( numgot != NULL ) + *numgot = num; +} + +//========================================================================== + +static void createfile( char *name, size_t size ) +{ + char buf[IOSIZE]; + int fd; + ssize_t wrote; + int i; + int err; + + diag_printf("<INFO>: create file %s size %ld\n",name, (long)size); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + while( size > 0 ) + { + ssize_t len = size; + if ( len > IOSIZE ) len = IOSIZE; + + wrote = write( fd, buf, len ); + if( wrote != len ) SHOW_RESULT( write, wrote ); + + size -= wrote; + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +//========================================================================== + +#if 0 +static void maxfile( char *name ) +{ + char buf[IOSIZE]; + int fd; + ssize_t wrote; + int i; + int err; + size_t size = 0; + size_t prevsize = 0; + + diag_printf("<INFO>: create maximal file %s\n",name); + diag_printf("<INFO>: This may take a few minutes\n"); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + do + { + wrote = write( fd, buf, IOSIZE ); + //if( wrote < 0 ) SHOW_RESULT( write, wrote ); + + if( wrote >= 0 ) + size += wrote; + + if( (size-prevsize) > 100000 ) + { + diag_printf("<INFO>: size = %ld \n", size); + prevsize = size; + } + + } while( wrote == IOSIZE ); + + diag_printf("<INFO>: file size == %ld\n",size); + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} +#endif + +//========================================================================== + +static void checkfile( char *name ) +{ + char buf[IOSIZE]; + int fd; + ssize_t done; + int i; + int err; + off_t pos = 0; + + diag_printf("<INFO>: check file %s\n",name); + + err = access( name, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd = open( name, O_RDONLY ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + for(;;) + { + done = read( fd, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + for( i = 0; i < done; i++ ) + if( buf[i] != i%256 ) + { + diag_printf("buf[%ld+%d](%02x) != %02x\n",pos,i,buf[i],i%256); + CYG_TEST_FAIL("Data read not equal to data written\n"); + for(;;); + } + + pos += done; + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +//========================================================================== + +static void copyfile( char *name2, char *name1 ) +{ + + int err; + char buf[IOSIZE]; + int fd1, fd2; + ssize_t done, wrote; + + diag_printf("<INFO>: copy file %s -> %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + err = access( name2, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_WRONLY|O_CREAT ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done = read( fd2, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + wrote = write( fd1, buf, done ); + if( wrote != done ) SHOW_RESULT( write, wrote ); + + if( wrote != done ) break; + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +//========================================================================== + +static void comparefiles( char *name2, char *name1 ) +{ + int err; + char buf1[IOSIZE]; + char buf2[IOSIZE]; + int fd1, fd2; + ssize_t done1, done2; + int i; + + diag_printf("<INFO>: compare files %s == %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_RDONLY ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done1 = read( fd1, buf1, IOSIZE ); + if( done1 < 0 ) SHOW_RESULT( read, done1 ); + + done2 = read( fd2, buf2, IOSIZE ); + if( done2 < 0 ) SHOW_RESULT( read, done2 ); + + if( done1 != done2 ) + diag_printf("Files different sizes\n"); + + if( done1 == 0 ) break; + + for( i = 0; i < done1; i++ ) + if( buf1[i] != buf2[i] ) + { + diag_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]); + CYG_TEST_FAIL("Data in files not equal\n"); + } + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +//========================================================================== + +void checkcwd( const char *cwd ) +{ + static char cwdbuf[PATH_MAX]; + char *ret; + + ret = getcwd( cwdbuf, sizeof(cwdbuf)); + if( ret == NULL ) SHOW_RESULT( getcwd, ret ); + + if( strcmp( cwdbuf, cwd ) != 0 ) + { + diag_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd ); + CYG_TEST_FAIL( "Current directory mismatch"); + } +} + +//========================================================================== +// main + +void yaffs6_main( CYG_ADDRESS id ) +{ + int err; + int existingdirents=-1; + cyg_bool mp2 = false; + int fd; + + char dirname[256]; + char filename1[256]; + char filename2[256]; + +#define NEW_FILENAME( fn, f ) \ +{ \ + fn[0]=0; \ + strcat(fn, dirname); \ + strcat(fn, "/"); \ + strcat(fn,f); \ +} + +#define NEW_FILENAME1( f ) NEW_FILENAME( filename1, f ) +#define NEW_FILENAME2( f ) NEW_FILENAME( filename2, f ) + + CYG_TEST_INIT(); + +#ifdef CYGDBG_INFRA_DIAG_CHECK_STRINGS + diag_printf("WARNING: CYGDBG_INFRA_DIAG_CHECK_STRINGS is defined, Cyrillic file names will not be printed.\n"); +#else + diag_printf("WARNING: Cyrillic file names printed in UTF-8 may not be readable in some environments.\n"); +#endif + + // -------------------------------------------------------------- + + err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE ); + if( err < 0 ) { + SHOW_RESULT( mount, err ); + CYG_TEST_FAIL_FINISH("yaffs6"); + } + + err = access( TEST_MOUNTPOINT TEST_DIRECTORY, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + if( err < 0 && errno == EACCES ) + { + diag_printf("<INFO>: create %s\n", + TEST_MOUNTPOINT TEST_DIRECTORY); + err = mkdir( TEST_MOUNTPOINT TEST_DIRECTORY, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + } + + err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY ); + + listdir( TEST_MOUNTPOINT TEST_DIRECTORY, true, -1, &existingdirents ); + + // -------------------------------------------------------------- + + dirname[0] = 0; + strcat(dirname, TEST_MOUNTPOINT ); + strcat(dirname, TEST_DIRECTORY ); + + // -------------------------------------------------------------- + + createfile( FOO, 20257 ); + checkfile( FOO ); + copyfile( FOO, FEE); + checkfile( FEE ); + comparefiles( FOO, FEE ); + + diag_printf("<INFO>: mkdir " BAR "\n"); + err = mkdir( BAR, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + listdir( dirname , true, existingdirents+3, NULL ); + + copyfile( FEE, BAR "/" FUM ); + checkfile( BAR "/" FUM ); + comparefiles( FEE, BAR "/" FUM ); + + diag_printf("<INFO>: cd " BAR "\n"); + err = chdir( BAR ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + NEW_FILENAME1( BAR ); + checkcwd( filename1 ); + + diag_printf("<INFO>: rename ../" FOO " " BUNDY "\n"); + err = rename( "../" FOO, BUNDY ); + if( err < 0 ) SHOW_RESULT( rename, err ); + + listdir( dirname, true, existingdirents+2, NULL ); + listdir( "." , true, 4, NULL ); + + checkfile( "../" BAR "/" BUNDY ); + comparefiles("../" FEE, BUNDY ); + +#if 1 + + // -------------------------------------------------------------- + // Check for some common error cases + + // First make some directories + diag_printf("<INFO>: mkdir " DOO "\n"); + err = mkdir( DOO, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir " FIE" \n"); + err = mkdir( FIE, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir " FIE "/" FOE "\n"); + err = mkdir( FIE "/" FOE, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + + diag_printf("<INFO>: rename " FUM " " DOO " -- should fail\n"); + err = rename( FUM, DOO ); + if( err < 0 && errno != EISDIR ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename " DOO " " FUM " -- should fail\n"); + err = rename( DOO, FUM ); + if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename " DOO " " FIE " -- should fail\n"); + err = rename( DOO, FIE ); + if( err < 0 && errno != EIO ) SHOW_RESULT( rename, err ); + + NEW_FILENAME1( XXXX "/" YYYY ) + diag_printf("<INFO>: rename " FUM " %s -- should fail\n",filename1); + err = rename( FUM, filename1 ); + if( err < 0 && errno != ENOENT ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename " FUM " " FUM " -- should fail\n"); + err = rename( FUM, FUM ); + if( err < 0 ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: unlink " FEE " -- should fail\n"); + err = unlink( FEE ); + if( err < 0 && errno != ENOENT ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( BAR ); + diag_printf("<INFO>: rmdir %s -- should fail\n",filename1); + err = rmdir( filename1 ); + if( err < 0 && errno != ENOTEMPTY ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: unlink %s -- should fail\n",filename1); + err = unlink( filename1 ); + if( err < 0 && errno != EISDIR ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( BAR "/" FUM ); + diag_printf("<INFO>: rmdir %s -- should fail\n",filename1); + err = rmdir( filename1 ); + if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: mkdir %s -- should fail\n",filename1); + err = mkdir( filename1, 0 ); + if( err < 0 && errno != EEXIST ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: open " BUNDY " exclusive -- should fail\n"); + fd = open( BUNDY, O_WRONLY|O_CREAT|O_EXCL ); + if( fd < 0 && errno != EEXIST ) SHOW_RESULT( open, fd ); + + diag_printf("<INFO>: open %s -- should fail\n",dirname); + fd = open( dirname, O_WRONLY ); + if( fd < 0 && errno != EISDIR ) SHOW_RESULT( open, fd ); + + + listdir( dirname, true, existingdirents+2, NULL ); + listdir( "." , true, 6, NULL ); + + // -------------------------------------------------------------- + +#ifdef CLEANUP + + diag_printf("<INFO>: rename " FIE " " DOO "\n"); + err = rename( FIE, DOO ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: rmdir " DOO "/" FOE "\n"); + err = rmdir(DOO "/" FOE); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: rmdir " DOO "\n"); + err = rmdir(DOO); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink ../" FEE "\n"); + err = unlink( "../" FEE ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink " FUM "\n"); + err = unlink( FUM ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink ../" BAR "/" BUNDY "\n"); + err = unlink( "../" BAR "/" BUNDY ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( dirname ); + +#ifdef CLEANUP + diag_printf("<INFO>: rmdir " BAR "\n"); + err = rmdir( BAR ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + listdir( dirname, false, existingdirents, NULL ); +#endif + + // -------------------------------------------------------------- + +#ifdef TEST_MOUNTPOINT2 + diag_printf("<INFO>: mount %s\n", TEST_MOUNTPOINT2); + err = mount( TEST_DEVICE2, TEST_MOUNTPOINT2, TEST_FSTYPE2 ); + + if( err == 0 ) + { + mp2 = true; + diag_printf("<INFO>: mount %s succeeded\n", TEST_MOUNTPOINT2); + err = access( TEST_MOUNTPOINT2 TEST_DIRECTORY2, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + if( err < 0 && errno == EACCES ) + { + diag_printf("<INFO>: create %s\n", + TEST_MOUNTPOINT2 TEST_DIRECTORY2); + err = mkdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + } + + err = chdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2 ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( TEST_MOUNTPOINT2 TEST_DIRECTORY2 ); + + dirname[0] = 0; + strcat(dirname, TEST_MOUNTPOINT2 ); + strcat(dirname, TEST_DIRECTORY2 ); + + } + else + { + mp2 = false; + diag_printf("<INFO>: mount %s failed, ", TEST_MOUNTPOINT2); + diag_printf("using %s instead\n", dirname ); + } + +#endif + + listdir( dirname , true, -1, &existingdirents); + + NEW_FILENAME1( TINKY ); + NEW_FILENAME2( LAALAA ); + + createfile( filename1, 4567 ); + copyfile( filename1, filename2 ); + checkfile( filename1); + checkfile( filename2); + comparefiles( filename1, filename2 ); + + diag_printf("<INFO>: cd %s\n",dirname); + err = chdir( dirname ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( dirname ); + + diag_printf("<INFO>: mkdir " NOONOO "\n"); + err = mkdir( NOONOO, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + listdir( dirname , true, existingdirents+3, NULL); + + diag_printf("<INFO>: cd " NOONOO "\n"); + err = chdir( NOONOO ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + NEW_FILENAME1( NOONOO ); + checkcwd( filename1 ); + + createfile( TINKY, 6789 ); + checkfile( TINKY ); + + createfile( DIPSY, 34567 ); + checkfile( DIPSY ); + copyfile( DIPSY, PO ); + checkfile( PO ); + comparefiles( DIPSY, PO ); + + listdir( ".", true, 5, NULL ); + listdir( "..", true, existingdirents+3, NULL ); + + // -------------------------------------------------------------- + +#ifdef CLEANUP + diag_printf("<INFO>: unlink " TINKY "\n"); + err = unlink( TINKY ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink " DIPSY "\n"); + err = unlink( DIPSY ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink " PO "\n"); + err = unlink( PO ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( dirname ); + +#ifdef CLEANUP + diag_printf("<INFO>: rmdir " NOONOO "\n"); + err = rmdir( NOONOO ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); +#endif + + // -------------------------------------------------------------- + + err = mkdir( XXXX, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + err = mkdir( XXXX "/" YYYY, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + err = mkdir( XXXX "/" YYYY "/" ZZZZ, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + err = mkdir( XXXX "/" YYYY "/" ZZZZ "/" WWWW, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ "/" WWWW ); + diag_printf("<INFO>: cd %s\n",filename1); + err = chdir( filename1 ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ ); + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ ); + diag_printf("<INFO>: cd .\n"); + err = chdir( "." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( XXXX "/" YYYY ); + diag_printf("<INFO>: cd ../../" YYYY "\n"); + err = chdir( "../../" YYYY ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + diag_printf("<INFO>: cd ../..\n"); + err = chdir( "../.." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( dirname ); + + diag_printf("<INFO>: rmdir " XXXX "/" YYYY "/" ZZZZ "/" WWWW "\n"); + err = rmdir( XXXX "/" YYYY "/" ZZZZ "/" WWWW ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir "XXXX "/" YYYY "/" ZZZZ "\n"); + err = rmdir( XXXX "/" YYYY "/" ZZZZ ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir " XXXX "/" YYYY "\n"); + err = rmdir( XXXX "/" YYYY ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir "XXXX "\n"); + err = rmdir( XXXX ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + // -------------------------------------------------------------- + + checkcwd( dirname ); + +#ifdef CLEANUP + diag_printf("<INFO>: unlink "TINKY "\n"); + err = unlink( TINKY ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink " LAALAA" \n"); + err = unlink( LAALAA ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + // -------------------------------------------------------------- + + diag_printf("<INFO>: cd %s\n", TEST_MOUNTPOINT TEST_DIRECTORY); + err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY ); + + listdir( ".", true, -1, NULL ); + +#ifdef TEST_MOUNTPOINT2 + if( mp2 ) + { + diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT2); + err = umount( TEST_MOUNTPOINT2 ); + if( err < 0 ) SHOW_RESULT( umount, err ); + } +#endif + + // -------------------------------------------------------------- + +#if 0 + maxfile("file.max"); + + listdir( "/", true, -1, NULL ); + + diag_printf("<INFO>: unlink file.max\n"); + err = unlink( "file.max" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + // -------------------------------------------------------------- + +#endif + diag_printf("<INFO>: cd /\n"); + err = chdir( "/" ); + if( err == 0 ) + { + checkcwd( "/" ); + + diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT); + err = umount( TEST_MOUNTPOINT ); + if( err < 0 ) SHOW_RESULT( umount, err ); + } + + diag_printf("<INFO>: syncing\n"); + cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_SYNC, NULL, 0); // sync(); + + CYG_TEST_PASS_FINISH("yaffs6"); +} + +// ------------------------------------------------------------------------- + +#include <cyg/kernel/kapi.h> + +static cyg_handle_t thread_handle; +static cyg_thread thread; +static char stack[CYGNUM_HAL_STACK_SIZE_TYPICAL+1024*4]; + +externC void +cyg_start( void ) +{ + cyg_thread_create(3, // Priority - just a number + yaffs6_main, // entry + 0, // index + 0, // no name + &stack[0], // Stack + sizeof(stack), // Size + &thread_handle, // Handle + &thread // Thread data structure + ); + cyg_thread_resume(thread_handle); + + cyg_scheduler_start(); +} + +#else // CYGPKG_KERNEL + +#include <cyg/infra/testcase.h> + +externC void cyg_start(void) +{ + CYG_TEST_NA("Needs CYGPKG_KERNEL"); +} + +#endif + +// ------------------------------------------------------------------------- +// EOF yaffs6.c
