From 45e1b1f8ba61e252ae03dac101feeb24a8dc8760 Mon Sep 17 00:00:00 2001 From: peteratebs Date: Sun, 11 Oct 2015 13:58:55 -0400 Subject: [PATCH] first commit --- Makefile | 6 + README.MD | 104 +++++ codesizes.txt | 308 ++++++++++++++ main | Bin 0 -> 99784 bytes main.c | 30 ++ manual.txt | 75 ++++ rtfslconst.c | 14 + rtfsldata.c | 16 + rtfsldelete.c | 51 +++ rtfslfailsafe.c | 695 +++++++++++++++++++++++++++++++ rtfslfileseek.c | 48 +++ rtfslfilestat.c | 24 ++ rtfslfiliocore.c | 202 +++++++++ rtfslfiliord.c | 82 ++++ rtfslfiliowr.c | 308 ++++++++++++++ rtfslfssystem.c | 42 ++ rtfslgfirst.c | 72 ++++ rtfslite.h | 314 ++++++++++++++ rtfslitecore.c | 929 ++++++++++++++++++++++++++++++++++++++++++ rtfsliteshell.c | 563 +++++++++++++++++++++++++ rtfslitetests.h | 24 ++ rtfslmkdir.c | 65 +++ rtfslopenpath.c | 85 ++++ rtfslrename.c | 38 ++ rtfslrmdir.c | 51 +++ rtfslsystem.c | 200 +++++++++ rtfstlitefileload.c | 96 +++++ rtfstlitetestfileio.c | 322 +++++++++++++++ rtfstlitetests.c | 460 +++++++++++++++++++++ rtfstlitetestutils.c | 183 +++++++++ 30 files changed, 5407 insertions(+) create mode 100644 Makefile create mode 100644 README.MD create mode 100644 codesizes.txt create mode 100644 main create mode 100644 main.c create mode 100644 manual.txt create mode 100644 rtfslconst.c create mode 100644 rtfsldata.c create mode 100644 rtfsldelete.c create mode 100644 rtfslfailsafe.c create mode 100644 rtfslfileseek.c create mode 100644 rtfslfilestat.c create mode 100644 rtfslfiliocore.c create mode 100644 rtfslfiliord.c create mode 100644 rtfslfiliowr.c create mode 100644 rtfslfssystem.c create mode 100644 rtfslgfirst.c create mode 100644 rtfslite.h create mode 100644 rtfslitecore.c create mode 100644 rtfsliteshell.c create mode 100644 rtfslitetests.h create mode 100644 rtfslmkdir.c create mode 100644 rtfslopenpath.c create mode 100644 rtfslrename.c create mode 100644 rtfslrmdir.c create mode 100644 rtfslsystem.c create mode 100644 rtfstlitefileload.c create mode 100644 rtfstlitetestfileio.c create mode 100644 rtfstlitetests.c create mode 100644 rtfstlitetestutils.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5bfaa9b --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ + + +all: main + +main: main.c rtfslconst.c rtfsldata.c rtfsldelete.c rtfslfailsafe.c rtfslfileseek.c rtfslfilestat.c rtfslfiliocore.c rtfslfiliord.c rtfslfiliowr.c rtfslfssystem.c rtfslgfirst.c rtfslitecore.c rtfsliteshell.c rtfslmkdir.c rtfslopenpath.c rtfslrename.c rtfslrmdir.c rtfslsystem.c rtfstlitefileload.c rtfstlitetestfileio.c rtfstlitetests.c rtfstlitetestutils.c + gcc -g -o main main.c rtfslconst.c rtfsldata.c rtfsldelete.c rtfslfailsafe.c rtfslfileseek.c rtfslfilestat.c rtfslfiliocore.c rtfslfiliord.c rtfslfiliowr.c rtfslfssystem.c rtfslgfirst.c rtfslitecore.c rtfsliteshell.c rtfslmkdir.c rtfslopenpath.c rtfslrename.c rtfslrmdir.c rtfslsystem.c rtfstlitefileload.c rtfstlitetestfileio.c rtfstlitetests.c rtfstlitetestutils.c diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..947a0b4 --- /dev/null +++ b/README.MD @@ -0,0 +1,104 @@ +Tinyfatfs Low footprint Embedded FAT file system + + EBS - RTFS (Real Time File Manager) + +* Copyright, Peter Van Oudenaren +* EBS Inc. 1987-2015 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. + +* contact sales@ebsembeddedsoftware.com + +Rtfs tiny is a very low footprint implementation of the FAT file system. + +This software was written as an experiment to create the smallest footprint FAT file system with the most attainable functionality. + +The code achieves small code size by relying on experience providing commercial FAT file system products over many years. + +The current code does not support vfat but that can be added pretty easilly in we estimate 1 to 2 K of code space. + + +The code is still not totally refined so beware, send us an email if you'd find a bug or you would like to conrtibute a patch. + +. The ram and rom requirements for rtfsl built under various configurations is provided below. +. These are for the ARM processor using the IAR compiler, similar builds need to be made for AVR +============================================================================================= +read read read +only only write Build +code data data description. +bytes bytes bytes +------- ------- ------- ---------------------- + 7422 52 1340 Full build with journaling optimized for size + 7098 86 792 Full build minus journaling un-optimized + 5480 52 792 Full build minus journaling optimized + 5192 20 780 Full build minus journaling, minus subdirectory support optimized for size + 3588 20 780 Read only file io, directory traversal and file stat functions. + 2896 12 532 Functionality to load a file from the root directory into memory, optimized for size. + +Full build includes the follow functionality for fat12, fat16 and fat32.: + . create a sub-directory in the root or in a subdirectory. + . delete a sub-directory + . create a file in the root or in a subdirectory. + . write to a file. + . read from a file. + . seek within a file. + . close a file. + . delete a file +When Failsafe support is enabled, the follow functionality is included. + . journaling flush. + . journaling journal of FAT table changes and directory entry changes. + . journaling restore. + + + + +To build the test applcation for a Linux target: +type:. + make + +To run the symple command shell based example: + +type: + sudo ./main devicename + +for example, to access a USB stick at /dev/sdb1: + sudo ./main /dev/sdb1 + +If that is succesfulyou should see the following help screen: + +LOAD FILENAME +LMOUNT - re-mount rtfs lite drive +LEXIT - Exit Lite mode refreshes device mount for rtfs +LFLUSH - Flush rtfs lite buffers +DIR +RENAME oldname newname +DELETE filename +CHDIR path +MKDIR dirname 0|1 (1 = fragment) +RMDIR dirname +FILLPAT filename nlongs 0|1 (1=fragment) +APPENDPAT filename nlongs 0|1 (1=fragment) +READPAT filename +RANDREAD filename +RANDWRITE filename +FILLDISK filenamebase +FSSTART Start Journaling +FSSTOP Stop Journaling +FSSYNC Sync volume, keep journaling +FSFLUSH Flush journal keep journaling +FSRESTORE Retore the volume from the journal + + +The currently supported features include: +. File io (create,reopen, read,write,seek,delete). +. Subdirectory support (mkdir, rmdir and set working directory). +. Failsafe journaling and restore support. +. All features have been tested both with using Failsafe and not using Failsafe. +. All tests have been performed with FAT12 so far, typically the most difficult case. + +Ongoing development efforts include the following: +. Tests still need to be performed on FAT16 and FAT32. +. Testing is on-going with development of more rigorous tests planned for tomorrow. + + diff --git a/codesizes.txt b/codesizes.txt new file mode 100644 index 0000000..d830cf2 --- /dev/null +++ b/codesizes.txt @@ -0,0 +1,308 @@ +Just file load root file system only, write support disabled in core. + main.o 56 + rtfslfiliord.o 16 4 + rtfslitecore.o 3 948 40 512 + rtfstlitefileload.o 420 + rtfstlitetests.o 152 12 4 + sys.o 64 4 + ------------------------------------------------------- + Total: 4 656 52 520 4 +Just file load root file system only, write support enabled in core. + main.o 64 + rtfslfiliord.o 16 4 + rtfslitecore.o 4 388 40 512 + rtfstlitefileload.o 420 + rtfstlitetests.o 152 12 4 + sys.o 64 4 + ------------------------------------------------------- + Total: 5 104 52 520 4 +Everything on include write in filiocore and litecore + main.o 64 + rtfslfileseek.o 276 + rtfslfilestat.o 164 + rtfslfiliocore.o 1 164 + rtfslfiliord.o 312 4 132 + rtfslgfirst.o 392 + rtfslitecore.o 4 388 40 512 + rtfslopenpath.o 500 + rtfstlitefileload.o 420 + rtfstlitetests.o 1 060 296 4 + sys.o 64 4 + ------------------------------------------------------- + Total: 8 804 340 648 4 +Everything on exclude write in filiocore and litecore + main.o 56 + rtfslfileseek.o 276 + rtfslfilestat.o 164 + rtfslfiliocore.o 992 + rtfslfiliord.o 312 4 132 + rtfslgfirst.o 392 + rtfslitecore.o 3 948 40 512 + rtfslopenpath.o 500 + rtfstlitefileload.o 420 + rtfstlitetests.o 1 060 296 4 + sys.o 64 4 + ------------------------------------------------------- + Total: 8 184 340 648 4 + Everything on include write in filiocore and litecore thumb mode + main.o 34 + rtfslfileseek.o 172 + rtfslfilestat.o 100 + rtfslfiliocore.o 732 + rtfslfiliord.o 192 4 132 + rtfslfiliowr.o 872 + rtfslgfirst.o 268 + rtfslitecore.o 2 852 40 512 + rtfslopenpath.o 306 + rtfstlitefileload.o 264 + rtfstlitetests.o 722 308 4 + sys.o 64 4 + ------------------------------------------------------- + Total: 6 578 352 648 4 + + Everything on exclude write in filiocore and litecore thumb mode + main.o 34 + rtfslfileseek.o 172 + rtfslfilestat.o 100 + rtfslfiliocore.o 624 + rtfslfiliord.o 192 4 132 + rtfslfiliowr.o 872 + rtfslgfirst.o 268 + rtfslitecore.o 2 554 40 512 + rtfslopenpath.o 306 + rtfstlitefileload.o 264 + rtfstlitetests.o 722 308 4 + sys.o 64 4 + ------------------------------------------------------- + Total: 6 172 352 648 4 + D:\dev\Projects\IAR\arm\examples\NXP\LPC24xx\IAR-LPC-2478\RtfsLite\Flash Debug\Obj: [1] + main.o 30 + rtfslfiliord.o 12 4 + rtfslitecore.o 2 554 40 512 + rtfstlitefileload.o 264 + rtfstlitetests.o 106 12 4 + sys.o 64 4 + ------------------------------------------------------- + Total: 3 030 52 520 4 + +============ +July 2 ..... + +Full build unoptimized + ------ ------- ------- ------- ------- +D:\dev\Projects\IAR\arm\examples\NXP\LPC24xx\IAR-LPC-2478\RtfsLite\Flash Debug\Obj: [1] + main.o 34 + rtfslconst.o 44 8 + rtfsldata.o 8 1 328 + rtfsldelete.o 200 + rtfslfailsafe.o 2 212 24 + rtfslfileseek.o 172 + rtfslfilestat.o 112 + rtfslfiliocore.o 1 080 + rtfslfiliord.o 308 + rtfslfiliowr.o 1 180 + rtfslgfirst.o 268 + rtfslitecore.o 3 480 32 + rtfslmkdir.o 292 + rtfslopenpath.o 306 + rtfslrmdir.o 144 + rtfsltime.o 20 + rtfstlitefileload.o 292 + rtfstlitetests.o 954 568 4 + sys.o 64 4 + ------------------------------------------------------- + Total: 11 118 676 1 340 4 + 1 394 568 + Adjusted: 9 724 612 1 340 4 + +// =================== +Full build optimized +D:\dev\Projects\IAR\arm\examples\NXP\LPC24xx\IAR-LPC-2478\RtfsLite\Flash Debug\Obj: [1] + main.o 30 + rtfslconst.o 44 8 + rtfsldata.o 8 1 328 + rtfsldelete.o 140 + rtfslfailsafe.o 1 584 + rtfslfileseek.o 100 + rtfslfilestat.o 96 + rtfslfiliocore.o 772 + rtfslfiliord.o 220 + rtfslfiliowr.o 928 + rtfslgfirst.o 236 + rtfslitecore.o 2 736 + rtfslmkdir.o 240 + rtfslopenpath.o 240 + rtfslrmdir.o 108 + rtfsltime.o 20 + rtfstlitefileload.o 220 + rtfstlitetests.o 1 324 4 + sys.o 48 4 + ------------------------------------------------------- + Total: 9 042 52 1 340 4 + 1 620 + Adjusted: 7 422 52 1 340 0 + +// =================== +Full build minus failsafe un-optimized +D:\dev\Projects\IAR\arm\examples\NXP\LPC24xx\IAR-LPC-2478\RtfsLite\Flash Debug\Obj: [1] + main.o 34 + rtfslconst.o 44 8 + rtfsldata.o 8 780 + rtfsldelete.o 200 + rtfslfileseek.o 172 + rtfslfilestat.o 112 + rtfslfiliocore.o 964 + rtfslfiliord.o 308 + rtfslfiliowr.o 1 032 + rtfslgfirst.o 268 + rtfslitecore.o 3 332 32 + rtfslmkdir.o 240 + rtfslopenpath.o 306 + rtfslrmdir.o 144 + rtfsltime.o 20 + rtfstlitefileload.o 292 + rtfstlitetests.o 942 568 4 + sys.o 64 4 + ------------------------------------------------------- + Total: 8 430 652 792 4 + 1 332 568 + Adjusted: 7 098 86 792 0 +Full build minus failsafe optimized +D:\dev\Projects\IAR\arm\examples\NXP\LPC24xx\IAR-LPC-2478\RtfsLite\Flash Debug\Obj: [1] + main.o 30 + rtfslconst.o 44 8 + rtfsldata.o 8 780 + rtfsldelete.o 140 + rtfslfileseek.o 100 + rtfslfilestat.o 96 + rtfslfiliocore.o 688 + rtfslfiliord.o 220 + rtfslfiliowr.o 824 + rtfslgfirst.o 236 + rtfslitecore.o 2 600 + rtfslmkdir.o 208 + rtfslopenpath.o 240 + rtfslrmdir.o 108 + rtfsltime.o 20 + rtfstlitefileload.o 220 + rtfstlitetests.o 1 312 4 + sys.o 48 4 + ------------------------------------------------------- + Total: 7 090 52 792 4 + 1 610 + Adjusted: 5 480 52 792 0 + +Full build minus failsafe, minus subdirectory support optimized + main.o 30 + rtfslconst.o 12 + rtfsldata.o 8 780 + rtfsldelete.o 140 + rtfslfileseek.o 100 + rtfslfilestat.o 96 + rtfslfiliocore.o 688 + rtfslfiliord.o 220 + rtfslfiliowr.o 824 + rtfslgfirst.o 236 + rtfslitecore.o 2 600 + rtfslopenpath.o 160 + rtfslrmdir.o 108 + rtfsltime.o 20 + rtfstlitefileload.o 220 + rtfstlitetests.o 1 296 4 + sys.o 48 0 + ------------------------------------------------------- + Total: 6 786 20 784 4 + 1 594 4 + Adjusted: 5 192 20 780 4 + +Full build minus failsafe, minus subdirectory support, minus write support +D:\dev\Projects\IAR\arm\examples\NXP\LPC24xx\IAR-LPC-2478\RtfsLite\Flash Debug\Obj: [1] + main.o 26 + rtfslconst.o 12 + rtfsldata.o 8 780 + rtfslfileseek.o 100 + rtfslfilestat.o 96 + rtfslfiliocore.o 532 + rtfslfiliord.o 196 + rtfslgfirst.o 236 + rtfslitecore.o 2 268 + rtfslopenpath.o 160 + rtfstlitefileload.o 220 + rtfstlitetests.o 916 4 + sys.o 48 4 + ------------------------------------------------------- + Total: 4 798 20 784 4 + 1 210 4 + Adjusted: 3 588 20 780 0 + +Full build minus failsafe, minus subdirectory support, minus write support inus read api, enough to load a file from the root directory into memory +D:\dev\Projects\IAR\arm\examples\NXP\LPC24xx\IAR-LPC-2478\RtfsLite\Flash Debug\Obj: [1] + main.o 26 + rtfslconst.o 12 + rtfsldata.o 532 + rtfslfiliord.o 12 + rtfslgfirst.o 236 + rtfslitecore.o 2 268 + rtfslopenpath.o 160 + rtfstlitefileload.o 220 + rtfstlitetests.o 532 4 + sys.o 48 4 + ------------------------------------------------------- + Total: 3 502 12 536 4 + 606 4 + Adjusted: 2 896 12 532 0 + +The small file system development is going well. + +The currently supported features include: +. File io (create,reopen, read,write,seek,delete). +. Subdirectory support (mkdir, rmdir and set working directory). +. Failsafe journaling and restore support. +. All features have been tested both with using Failsafe and not using Failsafe. +. All tests have been performed with FAT12 so far, typically the most difficult case. + +Ongoing development efforts include the following: +. Tests still need to be performed on FAT16 and FAT32. +. Testing is on-going with development of more rigorous tests planned for tomorrow. + + +. The ram and rom requirements for rtfsl built under various configurations is provided below. +============================================================================================= +read read read +only only write Build +code data data description. +bytes bytes bytes +------- ------- ------- ---------------------- + 9724 52 1340 Full build with failsafe unoptimized +10210 52 1340 Full build with failsafe unoptimized after eliminating passing drive structure. (removal of const * optimization to blame, need to re-insert const where possible) + 7422 52 1340 Full build with failsafe optimized for size + 7098 86 792 Full build minus failsafe un-optimized + 5480 52 792 Full build minus failsafe optimized + 5192 20 780 Full build minus failsafe, minus subdirectory support optimized for size + 3588 20 780 Read only file io, directory traverasal and file stat functions. + 2896 12 532 Functionality to load a file from the root directory into memory, optimized for size. + +Full build includes the follow functionality for fat12, fat16 and fat32.: + . create a sub-directory in the root or in a subdirectory. + . delete a sub-directory + . create a file in the root or in a subdirectory. + . write to a file. + . read from a file. + . seek within a file. + . close a file. + . delete a file +When Failsafe support is enabled, the follow functionality is included. + . failsafe flush. + . failsafe journal of FAT table changes and directory entry changes. + . failsafe restore. + + main.o 34 + rtfstlitefileload.o 216 + rtfstlitetestfileio.o 744 260 + rtfstlitetests.o 726 548 532 + rtfstlitetestutils.o 774 12 + sys.o 64 4 + --------------------------------------------------------- + Total: 12 710 960 1 864 4 + 2 500 + 10 210 diff --git a/main b/main new file mode 100644 index 0000000000000000000000000000000000000000..3e4deff22b46bb2894b974879f749b4fbe68a5ec GIT binary patch literal 99784 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 vvU8C2Tq6c-l*KlsQ`lJn(=~DJj= 0) + { + fd=rval; + rval=rtfsl_read(fd, 0, rtfsl.rtfsl_files[fd].segment_size_bytes); + while (rval>0) + { + unsigned long cluster,value; + value=0; + for (offset=0;rtfsl.rtfsl_files[fd].cluster_segment_array[offset][0]&&offset=0) + rval=rtfsl_read(fd, 0, rtfsl.rtfsl_files[fd].segment_size_bytes); + } + if (rval==0) + { + rtfsl.rtfsl_files[fd].dos_inode.fname[0]=PCDELETE; + rval=rtfsl_flush(fd); + } + rtfsl.rtfsl_files[fd].rtfsl_file_flags=0; /* Deallocates the file */ + } + return rval; +} diff --git a/rtfslfailsafe.c b/rtfslfailsafe.c new file mode 100644 index 0000000..d3fab23 --- /dev/null +++ b/rtfslfailsafe.c @@ -0,0 +1,695 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + +#include "rtfslite.h" +#include +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) + +/* Frame structure +1xxx :28:32 = 64 CLUSTER - OPCODE START LENGTH +031 :32 = 64 DOSINODE - OPCODE SECTOR INDEX|TABLEINDEX|DELETED +*/ + +#define DIRENT_RECORD 0x80000000 +#define DIRENT_SECTOR_MASK 0x7fffffff +#define CLUSTER_DELETE_RECORD 0x30000000 +#define CLUSTER_CHAIN_RECORD 0x20000000 +#define CLUSTER_TCHAIN_RECORD 0x10000000 +#define CLUSTER_INSTANCE_RECORD 0x00000000 +#define CLUSTER_RECORD_MASK 0x30000000 +#define CLUSTER_VALUE_MASK 0x0fffffff + +#define REPLACEMENTRECORDSTART 1 + +#define DELETEEDINODEMARKER 0xfffe + +#define RELATIONSHIP_NONE 0 +#define RELATIONSHIP_OVERLAP 1 +#define RELATIONSHIP_ADJACENT_LEFT 2 +#define RELATIONSHIP_ADJACENT_RIGHT 3 +int rtfslfs_cluster_map(unsigned long cluster_number,unsigned long value) +{ +int i; +int get_next_record; +unsigned long cluster_type; +char emit_new_record; + + struct rtfsl_failsafe_context *pfs=rtfsl.rtfsl_current_failsafe_context; + if (!pfs) + return 1; + /* We may need up to 3 replacement records, fail if we don't have them */ + if (pfs->journal_buffer_free < (3*REPLACEMENT_RECORD_SIZE_BYTES)) + return RTFSL_JOURNALFULL_CLUSTER; + + /* set up default instructions in case we don't overlap a region */ + emit_new_record=1; + if (value==0) + { + cluster_type = CLUSTER_DELETE_RECORD; + value = cluster_number; + } + else if (value == (rtfsl.current_dr.end_cluster_marker|0xf)) + { + cluster_type = CLUSTER_TCHAIN_RECORD; + value = cluster_number; + } + else if (cluster_number+1 == value) + { + cluster_type = CLUSTER_CHAIN_RECORD; + value = cluster_number; + } + else + { + cluster_type = CLUSTER_INSTANCE_RECORD; + } + // + // + //REHERE - Add a new state to discard a cluster from all records if it is used. + get_next_record=1; + for (i = 0; get_next_record && i < (int)*pfs->preplacement_record_count;i++) + { + unsigned long end_record_cluster,start_record_cluster,record_type; + int relationship; + char overwrite_current_record,split_current_record,change_start_value,change_end_value,change_record_type; + if ((pfs->preplacement_records[i][0]&DIRENT_RECORD)!=0) /* Skip non cluster remap records */ + continue; + + start_record_cluster=pfs->preplacement_records[i][0]&CLUSTER_VALUE_MASK; + record_type=pfs->preplacement_records[i][0]&CLUSTER_RECORD_MASK; + if (record_type==CLUSTER_INSTANCE_RECORD) + end_record_cluster=start_record_cluster; + else + end_record_cluster=pfs->preplacement_records[i][1]; + + overwrite_current_record=split_current_record=change_start_value=change_end_value=change_record_type=0; + if (cluster_number+1 == start_record_cluster) + relationship=RELATIONSHIP_ADJACENT_LEFT; + else if (cluster_number-1 == end_record_cluster) + relationship=RELATIONSHIP_ADJACENT_RIGHT; + else if (start_record_cluster<=cluster_number&&end_record_cluster>=cluster_number) + relationship=RELATIONSHIP_OVERLAP; + else + relationship=RELATIONSHIP_NONE; + switch (relationship) + { + case RELATIONSHIP_NONE: + default: + break; + case RELATIONSHIP_ADJACENT_LEFT: /* Cluster is 1 to the left of the region */ + switch (record_type) + { + case CLUSTER_TCHAIN_RECORD: /* Cluster is 1 to the left of a terminated chain record */ + switch (cluster_type) + { + case CLUSTER_TCHAIN_RECORD: + case CLUSTER_INSTANCE_RECORD: + case CLUSTER_DELETE_RECORD: + default: + break; + case CLUSTER_CHAIN_RECORD: + change_start_value=1; /* Chain cluster immed to left of a terminated chain, set new start of terminated chain to cluster number. */; + break; + } + break; + case CLUSTER_INSTANCE_RECORD: /* Instance record is 1 to the left of a link record, no connection */ + break; + case CLUSTER_DELETE_RECORD: /* Cluster is 1 to the left of an erase record */ + { + switch (cluster_type) + { + case CLUSTER_TCHAIN_RECORD: + case CLUSTER_INSTANCE_RECORD: + case CLUSTER_CHAIN_RECORD: + default: + break; + case CLUSTER_DELETE_RECORD: + change_start_value=1; /* delete cluster immed to left of a deleted chain, set new start of deleted chain to cluster number. */; + break; + } + } + break; + case CLUSTER_CHAIN_RECORD: /* Cluster is 1 to the left of a chain record */ + { + switch (cluster_type) + { + case CLUSTER_TCHAIN_RECORD: + case CLUSTER_INSTANCE_RECORD: + case CLUSTER_DELETE_RECORD: + default: + break; + case CLUSTER_CHAIN_RECORD: + change_start_value=1; /* Chain cluster immed to left of a chain, set new start of chain to cluster number. */; + break; + } + } + break; + default: + break; + } + break; + case RELATIONSHIP_ADJACENT_RIGHT: /* Cluster is 1 to the right of the region */ + switch (record_type) + { + case CLUSTER_TCHAIN_RECORD: /* Cluster is 1 to the right of a terminator record, no connection */ + case CLUSTER_INSTANCE_RECORD: /* Cluster is 1 to the right of a link record, no connection */ + default: + break; + case CLUSTER_DELETE_RECORD: /* Cluster is 1 to the right of an erase record */ + { + switch (cluster_type) + { + case CLUSTER_TCHAIN_RECORD: + case CLUSTER_INSTANCE_RECORD: + case CLUSTER_CHAIN_RECORD: + break; + case CLUSTER_DELETE_RECORD: + change_end_value=1; /* delete cluster immed to right of a deleted region, set new end of deleted chain to cluster number. */; + break; + } + } + break; + case CLUSTER_CHAIN_RECORD: /* Cluster is 1 to the right of the chain region */ + { + switch (cluster_type) + { + case CLUSTER_INSTANCE_RECORD: + case CLUSTER_DELETE_RECORD: + default: + break; + case CLUSTER_TCHAIN_RECORD: + change_record_type=1; /* Append a tchain to a chain so change type, fall through to change end */ + case CLUSTER_CHAIN_RECORD: + change_end_value=1; /* Chain cluster immed to right of a chain, set new end of chain to cluster number. */; + break; + } + } + break; + } + break; + case RELATIONSHIP_OVERLAP: /* Cluster overlaps the region */ + switch (record_type) + { + case CLUSTER_TCHAIN_RECORD: + { + switch (cluster_type) + { + case CLUSTER_TCHAIN_RECORD: /* terminate cluster overlaps a terminated chain, split the record into 2 terminated chains and don't emit a new record */ + { + if (cluster_number==end_record_cluster) + { + /* Writing a terminator at the current end of a terminated chain is a no-op */ + get_next_record=0; + emit_new_record=0; + } + else + { + split_current_record=1; /* terminate cluster overlaps a terminated chain, split into two terminated chains no need to emit a new record */ + emit_new_record=0; + } + } + break; + case CLUSTER_INSTANCE_RECORD: /* link cluster overlaps a terminated chain */ + case CLUSTER_DELETE_RECORD: /* erase cluster overlaps a terminated chain */ + { + split_current_record=1; /* Split current record in two and emit a new record where the hole is */ + } + break; + case CLUSTER_CHAIN_RECORD: /* chain cluster overlaps a terminated chain */ + { + if (cluster_number==end_record_cluster) + { + change_record_type=1; /* End of a terminated chain record is now a chain, change to a chain record and return */; + } + else + { + /* A chain cluster overlapping a tchain in the middle is a no-op */ + get_next_record=0; + emit_new_record=0; + } + break; + default: + break; + } + break; + } + case CLUSTER_INSTANCE_RECORD: /* The record is a one cluster instance record and they overlap, force an overwrite of the record with the current cluster */ + { + overwrite_current_record=1; + break; + } + case CLUSTER_DELETE_RECORD: /* The record is an erase and they overlap */ + { + switch (cluster_type) + { + case CLUSTER_TCHAIN_RECORD: + case CLUSTER_CHAIN_RECORD: + case CLUSTER_INSTANCE_RECORD: + { + split_current_record=1; + } + break; + case CLUSTER_DELETE_RECORD: + get_next_record=0; + emit_new_record=0; + get_next_record=0; + /* Already erased.. is a no-op */ + break; + default: + break; + } + } + break; + case CLUSTER_CHAIN_RECORD: /* The record i a chain and they overlap */ + { + switch (cluster_type) + { + case CLUSTER_TCHAIN_RECORD: + { + if (cluster_number==end_record_cluster) + { + change_record_type=1; + } + else + { + split_current_record=1; + } + } + break; + case CLUSTER_DELETE_RECORD: + case CLUSTER_INSTANCE_RECORD: + { + split_current_record=1; + } + break; + case CLUSTER_CHAIN_RECORD: + emit_new_record=0; + /* A chain overlapping a chain is a no-op */ + get_next_record=0; + break; + default: + break; + } + break; + } + default: + break; + } + break; + } + } + if (change_record_type) + { + pfs->preplacement_records[i][0]=cluster_type|(pfs->preplacement_records[i][0]&CLUSTER_VALUE_MASK); + emit_new_record=0; + get_next_record=0; + } + if (change_start_value) + { + pfs->preplacement_records[i][0]=cluster_number|(pfs->preplacement_records[i][0]&CLUSTER_RECORD_MASK); + emit_new_record=0; + get_next_record=0; + } + if (change_end_value) + { + pfs->preplacement_records[i][1]=cluster_number; + emit_new_record=0; + get_next_record=0; + } + /* Overwrite the current record if instructed or if we are inserting a new record between + the start and end of a record that is only one cluster long */ + if (overwrite_current_record||(split_current_record&&(end_record_cluster==start_record_cluster))) + { + pfs->preplacement_records[i][0]=start_record_cluster|cluster_type; + pfs->preplacement_records[i][1]=value; + split_current_record=0; + emit_new_record=0; + get_next_record=0; + } + /* We are splitting a record in two. If emit_new_record is non zero we need to remove one cluster from the range that + we are splitting. If emit_new_record is non zero we know that the start and end are not the same. */ + if (split_current_record) + { + get_next_record=0; + /* Copy the record we are going to split into the next free record slot, don't reserve it yet */ + *pfs->preplacement_records[*pfs->preplacement_record_count]=*pfs->preplacement_records[i]; + + if (emit_new_record) + { + if (cluster_number==start_record_cluster) + { /* We're overwriting the first cluster in a range, don't split it just move the start, let emit create a new record */ + pfs->preplacement_records[i][0]=(start_record_cluster+1)|(pfs->preplacement_records[i][0]&CLUSTER_RECORD_MASK); + } + else + { /* We're overwriting a cluster in the range, it isn't the first cluster and the range is > 1, split the range */ + /* Change the end of the original record */ + pfs->preplacement_records[i][1]=cluster_number-1; + /* If the original record was a tchain make it a chain */ + if (record_type==CLUSTER_TCHAIN_RECORD) + { + pfs->preplacement_records[i][0]=CLUSTER_CHAIN_RECORD|(pfs->preplacement_records[i][0]&CLUSTER_VALUE_MASK); + } + /* If we are at the end, don't split, the emit further down will creat the new record */ + if (cluster_number==end_record_cluster) + { + ; + } + else + { /* Consume the cloned record, for the fragment of the region after the cluster we carved out. Just change the start point */ + pfs->preplacement_records[*pfs->preplacement_record_count][0]=(start_record_cluster+1)|(pfs->preplacement_records[*pfs->preplacement_record_count][0]&CLUSTER_RECORD_MASK); + *pfs->preplacement_record_count= *pfs->preplacement_record_count + 1; + pfs->journal_buffer_free -= REPLACEMENT_RECORD_SIZE_BYTES; + } + } + } + else /* We splitting a record but not taking a cluster away */ + { + if (cluster_number==start_record_cluster) + { /* We're splitting at the start of a range, terminate the old record at the start */ + pfs->preplacement_records[i][1]=cluster_number; + /* Consume the cloned record, for the fragment of the region after the cluster we carved out. Just change the start point */ + pfs->preplacement_records[*pfs->preplacement_record_count][0]=(cluster_number+1)|(pfs->preplacement_records[*pfs->preplacement_record_count][0]&CLUSTER_RECORD_MASK); + } + else + { /* We're splitting but not at the start of a range, terminate the old record at the cluster - 1 */ + pfs->preplacement_records[i][1]=cluster_number-1; + pfs->preplacement_records[*pfs->preplacement_record_count][0]=(cluster_number)|(pfs->preplacement_records[*pfs->preplacement_record_count][0]&CLUSTER_RECORD_MASK); + } + /* If the original record was a tchain make it a chain */ + if (record_type==CLUSTER_TCHAIN_RECORD) + { + pfs->preplacement_records[i][0]=CLUSTER_CHAIN_RECORD|(pfs->preplacement_records[i][0]&CLUSTER_VALUE_MASK); + } + *pfs->preplacement_record_count= *pfs->preplacement_record_count + 1; + pfs->journal_buffer_free -= REPLACEMENT_RECORD_SIZE_BYTES; + } + } + } /* End for loop */ + if (emit_new_record) + { /* or one past if we are making a hole */ + pfs->preplacement_records[*pfs->preplacement_record_count][0]= cluster_number|cluster_type; + pfs->preplacement_records[*pfs->preplacement_record_count][1]= value; + *pfs->preplacement_record_count= *pfs->preplacement_record_count + 1; + pfs->journal_buffer_free -= REPLACEMENT_RECORD_SIZE_BYTES; + } + return 0; +} + +unsigned long rtfslfs_cluster_remap(unsigned long cluster,unsigned long value) +{ + int i; + unsigned long new_instance_cluster,new_delete_start,new_chain_start,new_instance_value,new_chain_end,new_delete_end; + struct rtfsl_failsafe_context *pfs=rtfsl.rtfsl_current_failsafe_context; + if (!pfs) + return value; + new_delete_start=new_chain_start=new_instance_cluster=new_delete_end=new_chain_end=new_instance_value=0; + + + for (i = 0; i < (int)*pfs->preplacement_record_count;i++) + { + unsigned long cluster_record_type; + unsigned long end_record_cluster,start_record_cluster; + + if ((pfs->preplacement_records[i][0]&DIRENT_RECORD)!=0) /* Skip non cluster remap records */ + continue; + start_record_cluster=pfs->preplacement_records[i][0]&CLUSTER_VALUE_MASK; + cluster_record_type=pfs->preplacement_records[i][0]&CLUSTER_RECORD_MASK; + if (cluster_record_type==CLUSTER_INSTANCE_RECORD) + end_record_cluster=start_record_cluster; + else + end_record_cluster=pfs->preplacement_records[i][1]; + if (clusterpreplacement_records[i][1]; + } + else + { /* It a delete, chain or tchain */ + if (start_record_cluster<=cluster&&end_record_cluster>=cluster) + { + if (cluster_record_type==CLUSTER_DELETE_RECORD) + return RTFSL_JOURNALDELETED_CLUSTER; + /* It's either a tchain or a chain */ + /* last cluster of a tchain is chain terminator */ + if (cluster_record_type==CLUSTER_TCHAIN_RECORD && end_record_cluster==cluster) + return rtfsl.current_dr.end_cluster_marker|0xf; + else + return cluster+1; + } + } + } + /* Fall through and return the unmapped value */ + return value; +} + + +int rtfslfs_dirent_remap(unsigned long sector,unsigned long index, struct rtfsl_dosinode *p_dos_inode,int reading) +{ + struct rtfsl_failsafe_context *pfs=rtfsl.rtfsl_current_failsafe_context; + int replacement_record_index=-1; + int remap_index=0; + if (pfs) + { + int i; + for (i=0; i < (int)*pfs->preplacement_record_count;i++) + { + if ((pfs->preplacement_records[i][0]&DIRENT_RECORD)==0) /* Skip non dirent remap records */ + continue; + if ((pfs->preplacement_records[i][0]&DIRENT_SECTOR_MASK)==sector) + { + if ((pfs->preplacement_records[i][1]&0x0000ffff)==index) + { + unsigned long remap_index = pfs->preplacement_records[i][1]>>16; + if (reading) + { + if (remap_index == DELETEEDINODEMARKER) + p_dos_inode->fname[0]=PCDELETE; + else + ANSImemcpy(p_dos_inode, pfs->journal_buffer+remap_index,REPLACEMENT_DOSINODESIZE_SIZE_BYTES); + return 1; + } + else + { + if (p_dos_inode->fname[0]==PCDELETE) + { /* Mark the dosinode deleted. we can't reclaim the dossinode space in the buffer but it will be ignored */ + pfs->preplacement_records[i][1]= (unsigned long)(DELETEEDINODEMARKER)<<16|(unsigned long)index; + return 1; + } + else + { + if (remap_index != DELETEEDINODEMARKER) + { + ANSImemcpy(pfs->journal_buffer+remap_index, p_dos_inode,REPLACEMENT_DOSINODESIZE_SIZE_BYTES); + return 1; + } + /* We found a record for the dossinode but its flagged deleted and we need to copy record in place */ + replacement_record_index=i; + break; + } + } + } + } + } + if (reading) + return 0; + /* If we get here we have to allocate a records */ + { + int bytes_needed=0; + if (p_dos_inode->fname[0]!=PCDELETE) + bytes_needed+=REPLACEMENT_DOSINODESIZE_SIZE_BYTES; + if (replacement_record_index<0) + bytes_needed+=REPLACEMENT_RECORD_SIZE_BYTES; + if (pfs->journal_buffer_free < bytes_needed) + return RTFSL_ERROR_JOURNAL_FULL; + } + if (p_dos_inode->fname[0]==PCDELETE) + remap_index=DELETEEDINODEMARKER; + else + { + *pfs->pcurrent_dosinode_offset-=REPLACEMENT_DOSINODESIZE_SIZE_BYTES; + pfs->journal_buffer_free-=REPLACEMENT_DOSINODESIZE_SIZE_BYTES; + remap_index=(int)*pfs->pcurrent_dosinode_offset; + ANSImemcpy(pfs->journal_buffer+remap_index,p_dos_inode,REPLACEMENT_DOSINODESIZE_SIZE_BYTES); + } + if (replacement_record_index<0) + { + replacement_record_index=*pfs->preplacement_record_count; + *pfs->preplacement_record_count= *pfs->preplacement_record_count + 1; + } + pfs->preplacement_records[replacement_record_index][0]=sector|DIRENT_RECORD; + pfs->preplacement_records[replacement_record_index][1]=remap_index<<16|index; + return 1; + } + return 0; +} +/* Format of the buffer: replacement_record_count|replacement_records|->growsup Grows down<-dosinode1|dosinode0|]*/ +int rtfslfs_start(void) /*__apifn__*/ +{ +int rval; +struct rtfsl_failsafe_context *pfs; + + pfs=rtfsl.rtfsl_current_failsafe_context=&rtfsl.rtfsl_failsafe_context; + ANSImemset(rtfsl.rtfsl_current_failsafe_context,0,sizeof(*rtfsl.rtfsl_current_failsafe_context)); + rtfsl.rtfsl_current_failsafe_context->journal_buffer=rtfsl.rtfslfs_sector_buffer; + rtfsl.rtfsl_current_failsafe_context->journal_buffer_size=RTFSL_CFG_FSBUFFERSIZEBYTES; + rval=rtfslfs_access_journal(RTFSLFS_JTEST); + if (rval==0) + { + pfs->preplacement_record_count=(unsigned long *) pfs->journal_buffer; + pfs->pcurrent_dosinode_offset=(unsigned long *) (pfs->journal_buffer+4); + pfs->preplacement_records = (treplacement_record *) (pfs->journal_buffer+8); + *pfs->pcurrent_dosinode_offset=pfs->journal_buffer_size; + *pfs->preplacement_record_count=0; + pfs->journal_buffer_free = pfs->journal_buffer_size-8; +/* + For reload.. + pfs->journal_buffer_free = (pfs->journal_buffer_size-8-( (*pfs->preplacement_record_count*8)+ pfs->journal_buffer_size-*pfs->pcurrent_dosinode_offset) ); +*/ + } + return rval; +} + +int rtfslfs_flush(void) /*__apifn__*/ +{ +int rval; + rval=rtfsl_flush_info_sec(); + if (rval==0) + rval=rtfslfs_access_journal(RTFSLFS_JWRITE); + return rval; +} + +static int _rtfslfs_sync(void); +int rtfslfs_sync(void) /*__apifn__*/ +{ +int rval; + rval=_rtfslfs_sync(); + if (rval==0) + rval=rtfslfs_start(); + return rval; +} + +int rtfslfs_restore(void) /*__apifn__*/ +{ +int rval=0; + rval=rtfslfs_start(); /* Initialize offset, pointers etc. */ + if (rval==0) + { + rval=rtfslfs_access_journal(RTFSLFS_JREAD); /* read the journal */ + if (rval==0) + rval=_rtfslfs_sync(); + } + if (rval==0) + rval=rtfsl_diskopen(); + return rval; +} + +static int _rtfslfs_sync(void) +{ +int rval=0; +struct rtfsl_failsafe_context *pfs=rtfsl.rtfsl_current_failsafe_context; + if (pfs) + { + unsigned char *b=0; + struct rtfsl_dosinode *p_dos_inode; + unsigned long sector,offset,index; + int replacement_record_index; + int buffernumber; + /* null out the failsafe context pointer so the cluster routines go to the volume, not the journal */ + rtfsl.rtfsl_current_failsafe_context=0; + + for (replacement_record_index=0;replacement_record_index<(int)*pfs->preplacement_record_count;replacement_record_index++) + { + if (pfs->preplacement_records[replacement_record_index][0]&DIRENT_RECORD) + sector=pfs->preplacement_records[replacement_record_index][0]&DIRENT_SECTOR_MASK; + else + sector=0; + if (pfs->preplacement_records[replacement_record_index][0]&DIRENT_RECORD) + { + index = pfs->preplacement_records[replacement_record_index][1]&0x0000ffff; + offset = pfs->preplacement_records[replacement_record_index][1]>>16; + buffernumber=rtfsl_read_sector_buffer(sector); + if (buffernumber<0) + return buffernumber; + b = rtfsl_buffer_address(buffernumber); + p_dos_inode = (struct rtfsl_dosinode *) b; + p_dos_inode += index; + if (offset == DELETEEDINODEMARKER && p_dos_inode->fname[0]!=PCDELETE) + { + p_dos_inode->fname[0]=PCDELETE; + rtfsl_mark_sector_buffer(buffernumber); /* Mark the buffer dirty */ + } +#if (RTFSL_INCLUDE_FAT32) + else if (sector==rtfsl.current_dr.infosec) + { + unsigned long *pl= (unsigned long *)p_dos_inode; + pl++; + rtfsl.current_dr.free_alloc=*pl++; + rtfsl.current_dr.next_alloc=*pl; + rtfsl.current_dr.flags|=RTFSL_FAT_CHANGED_FLAG; + rval=rtfsl_flush_info_sec(); + if (rval<0) + return rval; + } +#endif + else + { + if (ANSImemcmp(p_dos_inode,pfs->journal_buffer+offset,REPLACEMENT_DOSINODESIZE_SIZE_BYTES)!=0) + { + ANSImemcpy(p_dos_inode,pfs->journal_buffer+offset,REPLACEMENT_DOSINODESIZE_SIZE_BYTES); + rtfsl_mark_sector_buffer(buffernumber); /* Mark the buffer dirty */ + } + } + } + else + { + unsigned long cluster_record_type,end_record_cluster,current_cluster,value; + current_cluster=pfs->preplacement_records[replacement_record_index][0]&CLUSTER_VALUE_MASK; + cluster_record_type=pfs->preplacement_records[replacement_record_index][0]&CLUSTER_RECORD_MASK; + end_record_cluster=pfs->preplacement_records[replacement_record_index][1]; + if (cluster_record_type==CLUSTER_DELETE_RECORD) + { + value=0; + do { + rval=fatop_buff_get_frag(current_cluster|RTFSL_WRITE_CLUSTER, &value, 1); + } while(rval==0 && current_cluster++preplacement_record_count) + { + rtfsl.rtfsl_current_failsafe_context=pfs; + rtfslfs_access_journal(RTFSLFS_JCLEAR); + rtfsl.rtfsl_current_failsafe_context=0; + } + } + return rval; +} +#endif diff --git a/rtfslfileseek.c b/rtfslfileseek.c new file mode 100644 index 0000000..8488e2c --- /dev/null +++ b/rtfslfileseek.c @@ -0,0 +1,48 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + +#include "rtfslite.h" + +static unsigned long file_seek_callback (struct rtfsl_file const *pfile, unsigned long start_sector, unsigned long nbytes, void *puser_data) +{ + unsigned long target = (unsigned long) puser_data; + if (pfile->file_pointer+nbytes > target) + return target-pfile->file_pointer; + else + return nbytes; +} + +long rtfsl_lseek(int fd, long offset, int origin) /*__apifn__*/ +{ +unsigned long target_fp; +int rval; + if (origin == PSEEK_SET) /* offset from beginning of file */ + { + target_fp = (unsigned long)offset; + } + else if (origin == PSEEK_CUR) /* offset from current file pointer */ + { + target_fp=rtfsl.rtfsl_files[fd].file_pointer+offset; + } + else if (origin == PSEEK_END) /* offset from end of file */ + { + if (offset>0) + return RTFSL_ERROR_ARGS; + target_fp=rtfsl.rtfsl_files[fd].dos_inode.fsize+offset; + } + else + return RTFSL_ERROR_ARGS; + rval=rtfsl_enumerate_file(&rtfsl.rtfsl_files[fd],file_seek_callback, (void *) target_fp); + if (rval<0) + return (long)rval; + if (rtfsl.rtfsl_files[fd].file_pointer!=target_fp) + return RTFSL_ERROR_CONSISTENCY; + else + return (long) rtfsl.rtfsl_files[fd].file_pointer; +} diff --git a/rtfslfilestat.c b/rtfslfilestat.c new file mode 100644 index 0000000..fb61a19 --- /dev/null +++ b/rtfslfilestat.c @@ -0,0 +1,24 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + +#include "rtfslite.h" + +int rtfsl_fstat(int fd, struct rtfsl_statstructure *pstat) /*__apifn__*/ +{ + ANSImemset(pstat,0,sizeof(*pstat)); + pstat->st_size = rtfsl.rtfsl_files[fd].dos_inode.fsize; + pstat->fattribute= rtfsl.rtfsl_files[fd].dos_inode.fattribute; + pstat->st_atime = rtfsl.rtfsl_files[fd].dos_inode.adate<<16; + pstat->st_mtime = rtfsl.rtfsl_files[fd].dos_inode.fdate<<16|rtfsl.rtfsl_files[fd].dos_inode.ftime; + pstat->st_ctime = rtfsl.rtfsl_files[fd].dos_inode.cdate<<16|rtfsl.rtfsl_files[fd].dos_inode.ctime; + pstat->st_blocks = (pstat->st_size+rtfsl.current_dr.bytespsector-1)/rtfsl.current_dr.bytespsector; + pstat->st_blocks = rtfsl.current_dr.bytespcluster; + return(0); + +} diff --git a/rtfslfiliocore.c b/rtfslfiliocore.c new file mode 100644 index 0000000..d17019a --- /dev/null +++ b/rtfslfiliocore.c @@ -0,0 +1,202 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + +#include "rtfslite.h" + +static long rtfsl_map_region_clusterwindow(int fd,unsigned long file_pointer, unsigned long *sector, unsigned long *offset) +{ + int region; + unsigned long startcluster,file_pointer_past_segment_end,file_pointer_at_region_base,file_pointer_past_region_end; + /* */ + *offset = file_pointer%rtfsl.current_dr.bytespsector; + if (rtfsl.rtfsl_files[fd].rtfsl_file_flags & TRTFSFILE_SECTOR_REGION ) + { + *sector = rtfsl.rtfsl_files[fd].cluster_segment_array[0][0]+file_pointer/rtfsl.current_dr.bytespsector; + return (rtfsl.rtfsl_files[fd].cluster_segment_array[0][1]-rtfsl.rtfsl_files[fd].cluster_segment_array[0][0])*rtfsl.current_dr.bytespsector-file_pointer; + } + startcluster=0; + file_pointer_past_segment_end=rtfsl.rtfsl_files[fd].file_pointer_at_segment_base+rtfsl.rtfsl_files[fd].segment_size_bytes; + if (file_pointer >= file_pointer_past_segment_end) + { + startcluster = rtfsl.rtfsl_files[fd].next_segment_base; + } + else if (file_pointer >= rtfsl.rtfsl_files[fd].file_pointer_at_segment_base) /* Scan up from current */ + startcluster = rtfsl.rtfsl_files[fd].cluster_segment_array[0][0]; + + if (!startcluster) + { + startcluster = to_USHORT((unsigned char *)& rtfsl.rtfsl_files[fd].dos_inode.fclusterhi); + startcluster <<= 16; + startcluster |= to_USHORT((unsigned char *)& rtfsl.rtfsl_files[fd].dos_inode.fcluster); + rtfsl.rtfsl_files[fd].segment_size_bytes=0; + rtfsl.rtfsl_files[fd].file_pointer_at_segment_base=0; + } + while (file_pointer >= file_pointer_past_segment_end) + { + long rval; + rval=rtfsl_load_next_segment(&rtfsl.rtfsl_files[fd],startcluster); + if (rval<=0) + return rval; + file_pointer_past_segment_end=rtfsl.rtfsl_files[fd].file_pointer_at_segment_base+rtfsl.rtfsl_files[fd].segment_size_bytes; + startcluster=0; + } + file_pointer_at_region_base=file_pointer_past_region_end=rtfsl.rtfsl_files[fd].file_pointer_at_segment_base; + for(region=0; region < RTFSL_CFG_FILE_FRAG_BUFFER_SIZE && rtfsl.rtfsl_files[fd].cluster_segment_array[region][0];region++) + { + unsigned long region_length; + region_length = (rtfsl.rtfsl_files[fd].cluster_segment_array[region][1]-rtfsl.rtfsl_files[fd].cluster_segment_array[region][0]+1)*rtfsl.current_dr.bytespcluster; + + file_pointer_past_region_end += region_length; + if (file_pointer_past_region_end>file_pointer) + { + *sector = rtfsl_cl2sector(rtfsl.rtfsl_files[fd].cluster_segment_array[region][0])+(file_pointer-file_pointer_at_region_base)/rtfsl.current_dr.bytespsector; + return file_pointer_past_region_end-file_pointer; + } + file_pointer_at_region_base += region_length; + + } + return RTFSL_ERROR_CONSISTENCY; + } + +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) +static int _rtfsl_journal_io(unsigned long sector, int index, unsigned char *pdata, long n_bytes) +{ + int rval; + long copied; + for (copied=0; copied n_left) + count_inregion = n_left; + } + if (residual||offset) + { + unsigned char *p; + int startcopyfr; + if (offset) + { + /* If reading and writing are enabled use opflags to ccheck for write */ + copied=rtfsl.current_dr.bytespsector-offset; + startcopyfr=(int)offset; + offset=0; + } + else + { + copied=residual; + startcopyfr=0; + } + if (copied > n_left) + copied = n_left; + if (pdata) + { + int buffernumber=rtfsl_read_sector_buffer(rtfsl.current_dr.partition_base+sector); + if (buffernumber<0) + return buffernumber; + p = rtfsl_buffer_address(buffernumber); +#if (RTFSL_INCLUDE_WRITE_SUPPORT) + if (opflags & RTFSL_FIO_OP_WRITE) + { + if (rtfsl.rtfsl_files[fd].rtfsl_file_flags&TRTFSFILE_ISMKDIR) + { + struct rtfsl_dosinode *pdos_inode=(struct rtfsl_dosinode *)pdata; + unsigned short w; + unsigned long cl=rtfsl_sec2cluster(rtfsl.rtfsl_files[fd].sector); + /* "." points to self */ + pdos_inode->fclusterhi=rtfsl.rtfsl_files[fd].dos_inode.fclusterhi; + pdos_inode->fcluster=rtfsl.rtfsl_files[fd].dos_inode.fcluster; + pdos_inode++; + /* ".." points to parent */ + w=(unsigned short) (cl>>16); + fr_USHORT((unsigned char *)&pdos_inode->fclusterhi, w); + w=(unsigned short) cl&0xffff; + fr_USHORT((unsigned char*)&pdos_inode->fcluster, w); + } +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) + /* A small write (32 or 64 bytes) needs to be journaled will always be offset or residual so all cases are covered */ + if (rtfsl.rtfsl_current_failsafe_context && (rtfsl.rtfsl_current_failsafe_context->flags&RTFSLFS_WRITE_DIRENTRY)) + rval=_rtfsl_journal_io(rtfsl.current_dr.partition_base+sector, startcopyfr/32, pdata, copied); + else +#endif + { + ANSImemcpy(p+startcopyfr, pdata,copied); + rval=rtfsl_flush_sector_buffer(buffernumber,1); + } + if (rval<0) + return rval; + } + else +#endif + { + ANSImemcpy(pdata,p+startcopyfr,copied); + } + pdata+=copied; + } + n_left-=copied; + + file_pointer+=copied; + count_inregion-=copied; + sector+=1; + } + while (count_inregion >= rtfsl.current_dr.bytespsector) + { + copied=rtfsl.current_dr.bytespsector; + if(pdata) + { +#if (RTFSL_INCLUDE_WRITE_SUPPORT) + if (opflags & RTFSL_FIO_OP_WRITE) + { + rval = rtfsl_write_sectors(rtfsl.current_dr.partition_base+sector,1, pdata); + } + else +#endif + { + rval=rtfsl_read_sectors(rtfsl.current_dr.partition_base+sector,1, pdata); + } + if (rval < 0) + return rval; + pdata+=copied; + } + n_left-=copied; + file_pointer+=copied; + sector+=1; + count_inregion-=copied; + } + residual=(long)count_inregion; + } + rtfsl.rtfsl_files[fd].file_pointer=file_pointer; + return(n_bytes-n_left); +} diff --git a/rtfslfiliord.c b/rtfslfiliord.c new file mode 100644 index 0000000..2c97a7d --- /dev/null +++ b/rtfslfiliord.c @@ -0,0 +1,82 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + +#include "rtfslite.h" + + +extern long _rtfsl_bfilio_io(int fd, unsigned char *pdata, long n_bytes, unsigned char opflags); + +void rtfsl_setpath(unsigned char **pathnamearray) /*__apifn__*/ +{ + rtfsl.current_dr.pathnamearray=pathnamearray; +} + +int rtfsl_alloc_fd(void) +{ +int fd; + for (fd=1;fd=0) + { + unsigned char want_type=RTFSL_ENTRY_TYPE_FILE; + if (attributes&ADIRENT) + want_type=RTFSL_ENTRY_TYPE_DIRECTORY; + rval=rtfsl_open_path(rtfsl.current_dr.pathnamearray,name,&scratch_dir_file, &rtfsl.rtfsl_files[fd]); + if (rval==0 && rtfsl.rtfsl_files[fd].rtfsl_direntry_type!=want_type) + rval=RTFSL_ERROR_PATH; + if (rval <0) + { + rtfsl.rtfsl_files[fd].rtfsl_file_flags=0; /* Deallocates the file */ + fd=rval; + } + } + return fd; +} + +int rtfsl_read(int fd, unsigned char *in_buff, int count) /*__apifn__*/ +{ +long n_bytes; + if (rtfsl.rtfsl_files[fd].file_pointer+count > rtfsl.rtfsl_files[fd].dos_inode.fsize) /* fsize is stores in native byte order */ + n_bytes=rtfsl.rtfsl_files[fd].dos_inode.fsize-rtfsl.rtfsl_files[fd].file_pointer; + else + n_bytes=(long)count; + return _rtfsl_bfilio_io(fd, in_buff, n_bytes, 0); +} + + +int rtfsl_close(int fd) /*__apifn__*/ +{ +#if (RTFSL_INCLUDE_WRITE_SUPPORT) +int rval=0; + if (rtfsl.rtfsl_files[fd].rtfsl_file_flags&TRTFSFILE_DIRTY) + rval=rtfsl_flush(fd); + rtfsl.rtfsl_files[fd].rtfsl_file_flags=0; /* Deallocates the file */ + return(rval); +#else + rtfsl.rtfsl_files[fd].rtfsl_file_flags=0; /* Deallocates the file */ + return(0); +#endif +} diff --git a/rtfslfiliowr.c b/rtfslfiliowr.c new file mode 100644 index 0000000..46c1465 --- /dev/null +++ b/rtfslfiliowr.c @@ -0,0 +1,308 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + +#include "rtfslite.h" +extern long _rtfsl_bfilio_io(int fd, unsigned char *pdata, long n_bytes, unsigned char opflags); + +struct rtfsl_create_structure +{ + unsigned char *name; + int eof; + unsigned long free_file_pointer; + unsigned long file_pointer; + unsigned char attribute; +}; + +int rtfsl_clzero(unsigned long cluster) +{ +int i, rval; +unsigned long sector; + sector=rtfsl_cl2sector(cluster); + rval=0; + for (i =0; rval==0 && i < rtfsl.current_dr.secpalloc; i++,sector++) + { + unsigned char *b; + rval=rtfsl_read_sector_buffer(sector); + if (rval<0) + return rval; + b = rtfsl_buffer_address(rval); + ANSImemset(b,0,rtfsl.current_dr.bytespsector); + rval = rtfsl_write_sectors(rtfsl.current_dr.partition_base+sector,1, b); + } + return rval; +} +#define NOFREEFILESFOUND 0xffffffff + +static int create_callback(struct rtfsl_file const *pcurrent_entry_file, void *puser_data) +{ +struct rtfsl_create_structure *pcreate_structure=(struct rtfsl_create_structure *) puser_data; + + { + if ((pcurrent_entry_file->rtfsl_direntry_type&RTFSL_ENTRY_AVAILABLE)!=0) + { + if (pcreate_structure->free_file_pointer==NOFREEFILESFOUND) + pcreate_structure->free_file_pointer=pcreate_structure->file_pointer; + if ((pcurrent_entry_file->rtfsl_direntry_type&RTFSL_ENTRY_TYPE_EOF)==0) + pcreate_structure->eof=1; + } + else if (!pcreate_structure->eof && ANSImemcmp(pcreate_structure->name,pcurrent_entry_file->dos_inode.fname,11)==0) + { /* Don't allow any duplicate names even if different attributes */ + return RTFSL_ERROR_EXIST; + } + } + pcreate_structure->file_pointer+=32; + return 0; /* Continue */ +} + +int rtfsl_create(unsigned char *name,unsigned char attribute) /*__apifn__*/ +{ +int rval; +struct rtfsl_create_structure create_structure; +struct rtfsl_file new_directory_file; +unsigned short date, time; +int fd; + + fd = rtfsl_alloc_fd(); + if (fd<0) + return fd; + rtfsl_get_system_date(&time, &date); + rval = rtfsl_open_path(rtfsl.current_dr.pathnamearray,0, &new_directory_file, &rtfsl.rtfsl_files[fd]); + if (rval==0) + { + create_structure.free_file_pointer=NOFREEFILESFOUND; + create_structure.file_pointer=0; + create_structure.name = name; + create_structure.attribute=attribute; + create_structure.eof=0; + /* Find a slot */ + rval = rtfsl_enumerate_directory(&rtfsl.rtfsl_files[fd],&new_directory_file, create_callback,(void *) &create_structure); + if(rval==0) + { + unsigned long seek_to; + rval = rtfsl_finode_open(&rtfsl.rtfsl_files[fd]); + + if (create_structure.free_file_pointer==NOFREEFILESFOUND) + seek_to=create_structure.file_pointer; + else + seek_to=create_structure.free_file_pointer; + /* Will fail on 16 bit systems if the direcory extents > 32 K*/ + if ((unsigned long)rtfsl_write(fd,0,seek_to)!=seek_to) + { + rval=RTFSL_ERROR_CONSISTENCY; + } + else + { + if (create_structure.free_file_pointer==NOFREEFILESFOUND && rtfsl.current_dr.fasize<8 && (rtfsl.rtfsl_files[fd].rtfsl_direntry_type&TRTFSFILE_ISROOT_DIR)) + rval=RTFSL_ERROR_DIR_FULL; + } + if (rval==0) + { +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) + if (rtfsl.rtfsl_current_failsafe_context) + rtfsl.rtfsl_current_failsafe_context->flags |= RTFSLFS_WRITE_DIRENTRY; +#endif + // Format the dos inode and write it + ANSImemcpy(&new_directory_file.dos_inode.fname,name,11); + new_directory_file.dos_inode.fattribute=attribute; /* File attributes */ + new_directory_file.dos_inode.reservednt=0; + new_directory_file.dos_inode.create10msincrement=0; + new_directory_file.dos_inode.ctime=time; /* time & date create */ + new_directory_file.dos_inode.cdate=date; + new_directory_file.dos_inode.adate=date; /* Date last accessed */ + new_directory_file.dos_inode.ftime=time; /* time & date lastmodified */ + new_directory_file.dos_inode.fdate=date; + new_directory_file.dos_inode.fsize =0; + new_directory_file.dos_inode.fcluster=0; + new_directory_file.dos_inode.fclusterhi=0; + // call rtfsl_write on new_directory_file to extend it + rval=rtfsl_write(fd,(unsigned char *)&new_directory_file.dos_inode,32); + if (rval>=0) + rval=rtfsl_flush(fd); +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) + if (rtfsl.rtfsl_current_failsafe_context) + rtfsl.rtfsl_current_failsafe_context->flags &= ~RTFSLFS_WRITE_DIRENTRY; +#endif + } + } + } + rtfsl.rtfsl_files[fd].rtfsl_file_flags=0; + return rval; +} +#include +int rtfsl_write(int fd, unsigned char *in_buff, int count) /*__apifn__*/ +{ +unsigned long needed,bytespcluster,prev_cluster; +int rval,i,updatesize=0; + + bytespcluster=rtfsl.current_dr.bytespcluster; + needed = rtfsl.rtfsl_files[fd].file_pointer+count; + if (needed > rtfsl.rtfsl_files[fd].dos_inode.fsize) + { + unsigned long allocated = + ((rtfsl.rtfsl_files[fd].dos_inode.fsize+rtfsl.current_dr.bytespcluster-1)/rtfsl.current_dr.bytespcluster) + *bytespcluster; + unsigned long next_segment_base=0; + prev_cluster=0; + for (i =0;i < RTFSL_CFG_FILE_FRAG_BUFFER_SIZE;i++) + { + if(rtfsl.rtfsl_files[fd].cluster_segment_array[i][0]) + prev_cluster=rtfsl.rtfsl_files[fd].cluster_segment_array[i][1]; + else + break; + } + updatesize=1; + while (allocated < needed) + { + int n; + unsigned long new_cluster,value; + n=fatop_buff_get_frag(rtfsl.current_dr.next_alloc|RTFSL_ALLOC_CLUSTER, &new_cluster, 1); + if (n==0) + { + rtfsl.current_dr.next_alloc=2; + n=fatop_buff_get_frag(rtfsl.current_dr.next_alloc|RTFSL_ALLOC_CLUSTER, &new_cluster, 1); + + } + if (n==1) + { + rtfsl.current_dr.next_alloc=new_cluster; + if (rtfsl.current_dr.free_alloc>=1) + rtfsl.current_dr.free_alloc-=1; + } + else if (n<1) + { + if (n==0) + return RTFSL_ERROR_DISK_FULL; + else + return n; + } +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) + if (!rtfsl.rtfsl_current_failsafe_context) +#endif + { + /* Write a terminate chain value before linking to it. + This is safer if not using Failsafe, but it reduces the journal file efficiency when using it */ + value=rtfsl.current_dr.end_cluster_marker|0xf; + rval=fatop_buff_get_frag(new_cluster|RTFSL_WRITE_CLUSTER, &value, 1); + if (rval<0) + return rval; + } + + if (prev_cluster) + { /* Link the previous cluster to the new one */ + value=new_cluster; + rval=fatop_buff_get_frag(prev_cluster|RTFSL_WRITE_CLUSTER, &value, 1); + if (rval<0) + return rval; + } + else + { + fr_USHORT((unsigned char *) &rtfsl.rtfsl_files[fd].dos_inode.fcluster,(unsigned short)(new_cluster&0xffff)); + fr_USHORT((unsigned char *) &rtfsl.rtfsl_files[fd].dos_inode.fclusterhi,(unsigned short)((new_cluster>>16)&0xffff)); + } +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) + if (rtfsl.rtfsl_current_failsafe_context) + { + /* Write failsafe terminating the chain after extending it makes it easier to coalesce chains in the journal */ + value=rtfsl.current_dr.end_cluster_marker|0xf; + rval=fatop_buff_get_frag(new_cluster|RTFSL_WRITE_CLUSTER, &value, 1); + if (rval<0) + return rval; + } +#endif + if (!next_segment_base) /* We are allocating, but not loading the chain, this allows load next segment to follw the chain */ + rtfsl.rtfsl_files[fd].next_segment_base=next_segment_base=new_cluster; + prev_cluster=new_cluster; + allocated+=bytespcluster; + } + + } + + rval=_rtfsl_bfilio_io(fd, in_buff, (long)count, RTFSL_FIO_OP_WRITE); + if (rval<0) + return rval; + if (updatesize) + { + rtfsl.rtfsl_files[fd].rtfsl_file_flags|=TRTFSFILE_DIRTY; + rtfsl.rtfsl_files[fd].dos_inode.fsize=rtfsl.rtfsl_files[fd].file_pointer; + } + return count; +} + +int rtfsl_flush(int fd) /*__apifn__*/ +{ + unsigned long l; + unsigned char *p; + int rval; + + if (rtfsl.rtfsl_files[fd].rtfsl_file_flags&(TRTFSFILE_ISROOT_DIR|TRTFSFILE_SECTOR_REGION)) + return 0; + l=rtfsl.rtfsl_files[fd].dos_inode.fsize; + if (rtfsl.rtfsl_files[fd].dos_inode.fattribute&(ADIRENT|AVOLUME)) + fr_ULONG((unsigned char *) &rtfsl.rtfsl_files[fd].dos_inode.fsize,0); + else + fr_ULONG((unsigned char *) &rtfsl.rtfsl_files[fd].dos_inode.fsize,l); +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) + /* Submit the entry to the journal failsafe is on */ + if (rtfsl.rtfsl_current_failsafe_context) + { + rval=rtfslfs_dirent_remap(rtfsl.current_dr.partition_base+rtfsl.rtfsl_files[fd].sector,rtfsl.rtfsl_files[fd].index, &rtfsl.rtfsl_files[fd].dos_inode,0); + rtfsl.rtfsl_files[fd].dos_inode.fsize=l; + if (rval<0) + return rval; + else if (rval !=1) + return RTFSL_ERROR_CONSISTENCY; + else + return 0; + } +#endif + rval=rtfsl_read_sector_buffer(rtfsl.current_dr.partition_base+rtfsl.rtfsl_files[fd].sector); + if (rval<0) + return (int) rval; + p = rtfsl_buffer_address(rval)+rtfsl.rtfsl_files[fd].index*32; + ANSImemcpy(p,&rtfsl.rtfsl_files[fd].dos_inode,32); + rtfsl.rtfsl_files[fd].dos_inode.fsize=l; + rval=rtfsl_flush_sector_buffer(rval,1); + return rval; +} +int rtfsl_flush_info_sec(void) /*__apifn__*/ +{ +#if (RTFSL_INCLUDE_FAT32) + int rval=0; + if ((rtfsl.current_dr.flags&RTFSL_FAT_CHANGED_FLAG) && rtfsl.current_dr.infosec) + { + rtfsl.current_dr.flags&=~RTFSL_FAT_CHANGED_FLAG; +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) + if (rtfsl.rtfsl_current_failsafe_context) + { + struct rtfsl_dosinode info_inode; + unsigned long *pl; + info_inode.fname[0]='A'; /* As long as it is not the delete character */ + pl=(unsigned long *)&info_inode; + pl++; + *pl++=rtfsl.current_dr.free_alloc; + *pl=rtfsl.current_dr.next_alloc; + /* Put the information in a fake dos_inode record in the journal. restore will recognize the sector as the info sector and call rtfsl_flush_info_sec() to update */ + if (rtfsl.rtfsl_current_failsafe_context) + return rtfslfs_dirent_remap(rtfsl.current_dr.partition_base+rtfsl.current_dr.infosec,0, &info_inode,0); + } +#endif + rval=rtfsl_read_sector_buffer(rtfsl.current_dr.partition_base+rtfsl.current_dr.infosec); + if (rval>=0) + { + unsigned char *p = rtfsl_buffer_address(rval); + fr_ULONG((p+488),rtfsl.current_dr.free_alloc); + fr_ULONG((p+492),rtfsl.current_dr.next_alloc); + rval=rtfsl_flush_sector_buffer(rval,1); + } + } + return rval; +#else + return 0; +#endif +} diff --git a/rtfslfssystem.c b/rtfslfssystem.c new file mode 100644 index 0000000..76f70f0 --- /dev/null +++ b/rtfslfssystem.c @@ -0,0 +1,42 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + +//HEREHERE +//#define RTFSLFS_JTEST 1 +//#define RTFSLFS_JCLEAR 2 +//#define RTFSLFS_JREAD 3 +//#define RTFSLFS_JWRITE 4 + +#include "rtfslite.h" +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) +int rtfslfs_access_journal(int command) +{ + struct rtfsl_failsafe_context *pfs=rtfsl.rtfsl_current_failsafe_context; + int i,rval; + unsigned char *b=pfs->journal_buffer; + unsigned long journal_file_start_sector; + rval=0; + /* Clear zeor fills the buffer and writes it */ + if (command==RTFSLFS_JCLEAR) + ANSImemset(b,0,pfs->journal_buffer_size); + if (RTFSL_CFG_FSBUFFERSIZESECTORS+1 > rtfsl.current_dr.partition_base) + return RTFSL_ERROR_JOURNAL_NONE; + /* JTEST Will fall through without doing any I/O */ + journal_file_start_sector=rtfsl.current_dr.partition_base-RTFSL_CFG_FSBUFFERSIZESECTORS; + for (i=0;rval==0&&ijournal_buffer_size/rtfsl.current_dr.bytespsector; i++) + { + if (command==RTFSLFS_JREAD) + rval=rtfsl_read_sectors(journal_file_start_sector+i,1,b); + else if (command==RTFSLFS_JWRITE||command==RTFSLFS_JCLEAR) + rval=rtfsl_write_sectors(journal_file_start_sector+i,1,b); + b+=rtfsl.current_dr.bytespsector; + } + return rval; +} +#endif \ No newline at end of file diff --git a/rtfslgfirst.c b/rtfslgfirst.c new file mode 100644 index 0000000..86e2bc7 --- /dev/null +++ b/rtfslgfirst.c @@ -0,0 +1,72 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + +#include "rtfslite.h" + +/* Structure for use by rtfsl_gfirst, rtfsl_gnext */ + +#define GFIRST_EOF 2 +static int rtfsl_gfirst_callback(struct rtfsl_file const *pcurrent_entry_file, void *puser_data) +{ + struct rtfsl_dstat *pdstat = (struct rtfsl_dstat *) puser_data; + + if (pcurrent_entry_file->rtfsl_direntry_type==RTFSL_ENTRY_TYPE_EOF) + return GFIRST_EOF; + if ((pcurrent_entry_file->rtfsl_direntry_type&(RTFSL_ENTRY_TYPE_DIRECTORY|RTFSL_ENTRY_TYPE_VOLUME|RTFSL_ENTRY_TYPE_FILE))!=0) + { + if (!pdstat->nametomatch||ANSImemcmp(pcurrent_entry_file->dos_inode.fname,pdstat->nametomatch,11)==0) + { + ANSImemcpy(&pdstat->fnameandext,pcurrent_entry_file->dos_inode.fname,11); + pdstat->fnameandext[11]=0; /* Null terminate file and extension */ + pdstat->fattribute=pcurrent_entry_file->dos_inode.fattribute;; + pdstat->ftime=pcurrent_entry_file->dos_inode.ftime; + pdstat->fdate=pcurrent_entry_file->dos_inode.fdate; + pdstat->ctime=pcurrent_entry_file->dos_inode.ctime; + pdstat->cdate=pcurrent_entry_file->dos_inode.cdate; + pdstat->atime=0; + pdstat->adate=pcurrent_entry_file->dos_inode.adate; + pdstat->fsize=pcurrent_entry_file->dos_inode.fsize; + return 1; + } + } + return 0; /* Continue */ +} + +/* Return <0 on error, 1 if contents are valid and scan may continue, 0, if end of directory was reached. */ +int rtfsl_gfirst(struct rtfsl_dstat *statobj, unsigned char *name) /*__apifn__*/ +{ +int rval; + ANSImemset(statobj,0,sizeof(*statobj)); + statobj->nametomatch=name; + /* Open the current directory or root use current_matched_file as a scratch directory entry*/ + rval=rtfsl_open_path(rtfsl.current_dr.pathnamearray,0, &statobj->current_matched_file, &statobj->directory_file); + if (rval >= 0) + { + /* Enumerate statobj->directory_file in search of name */ + rval = rtfsl_finode_open(&statobj->directory_file); + if (rval==0) + { + rval=rtfsl_enumerate_directory(&statobj->directory_file,&statobj->current_matched_file,rtfsl_gfirst_callback,(void *) statobj); + if (rval==GFIRST_EOF) + rval=0; + } + } + return rval; +} + +/* Return <0 on error, 1 if contents are valid and scan may continue, 0, if end of directory was reached. */ +int rtfsl_gnext(struct rtfsl_dstat *statobj) /*__apifn__*/ +{ + statobj->nametomatch=0; + return rtfsl_enumerate_directory(&statobj->directory_file,&statobj->current_matched_file,rtfsl_gfirst_callback,(void *) statobj); +} + +void rtfsl_done(struct rtfsl_dstat *statobj) /*__apifn__*/ +{ +} diff --git a/rtfslite.h b/rtfslite.h new file mode 100644 index 0000000..42a5322 --- /dev/null +++ b/rtfslite.h @@ -0,0 +1,314 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + +#ifndef __RTFSLITE__ +#include + +#define ANSImemset memset +#define ANSImemcmp memcmp +#define ANSImemcpy memcpy + + +#define RTFSL_INCLUDE_SUBDIRECTORIES 1 +#define RTFSL_INCLUDE_FAT32 1 +#define RTFSL_INCLUDE_FAT12 1 +#define RTFSL_INCLUDE_MBR_SUPPORT 1 /* 180 bytes, need 3rd option as well */ +#define RTFSL_INCLUDE_WRITE_SUPPORT 1 /* XXX bytes */ +#define RTFSL_INCLUDE_FAILSAFE_SUPPORT 1 /* XXX bytes */ +#define RTFSL_INCLUDE_SECURE_DIGITAL 1 +#define RTFSL_CFG_FILE_FRAG_BUFFER_SIZE 4 +#define RTFSL_CFG_FSBUFFERSIZESECTORS 1 +#define RTFSL_CFG_FSBUFFERSIZEBYTES (RTFSL_CFG_FSBUFFERSIZESECTORS*512) +#define RTFSL_CFG_NFILES 2 +#define RTFSL_CFG_MAXBLOCKSIZE 512 +#define RTFSL_CFG_NUMBUFFERS 2 + +/* Set this to 1 build a minimum system supporting only the API functions +rtfsl_load_file and rtfsl_setpath. If being able to load only from the root is +acceptable you can reduce footprint further by setting RTFSL_INCLUDE_SUBDIRECTORIES to 0 */ + +#define RTFSL_INCLUDE_LOAD_ONLY 0 +#if (RTFSL_INCLUDE_LOAD_ONLY) +#undef RTFSL_INCLUDE_WRITE_SUPPORT +#undef RTFSL_INCLUDE_FAILSAFE_SUPPORT +#undef RTFSL_INCLUDE_SECURE_DIGITAL +#undef RTFSL_CFG_NFILES +#undef RTFSL_CFG_NUMBUFFERS +#define RTFSL_INCLUDE_WRITE_SUPPORT 0 +#define RTFSL_INCLUDE_FAILSAFE_SUPPORT 0 +#define RTFSL_INCLUDE_SECURE_DIGITAL 0 +#define RTFSL_CFG_NFILES 1 +#define RTFSL_CFG_NUMBUFFERS 1 +#endif + +#define RTFSL_ERROR_NONE 0 +#define RTFSL_ERROR_ARGS -1 +#define RTFSL_ERROR_CONSISTENCY -2 +#define RTFSL_ERROR_DIR_FULL -3 +#define RTFSL_ERROR_DISK_FULL -4 +#define RTFSL_ERROR_FDALLOC -5 +#define RTFSL_ERROR_FORMAT -6 +#define RTFSL_ERROR_JOURNAL_FULL -7 +#define RTFSL_ERROR_JOURNAL_NONE -8 +#define RTFSL_ERROR_NOTFOUND -9 +#define RTFSL_ERROR_PATH -10 +#define RTFSL_ERROR_EXIST -11 +#define RTFSL_ERROR_ENOTEMPTY -12 +#define RTFSL_ERROR_TEST -13 + +#define RTFSL_ERROR_IO_WRITE_PROTECT -14 +#define RTFSL_ERROR_IO_NO_MEDIA -15 +#define RTFSL_ERROR_IO_ERROR -16 + +#define RTFSL_WRITE_CLUSTER 0x8000000 +#define RTFSL_ALLOC_CLUSTER 0x4000000 +#define RTFSL_MASK_COMMAND 0xC000000 +#define RTFSL_JOURNALFULL_CLUSTER 0xffffffff +#define RTFSL_JOURNALDELETED_CLUSTER 0xfffffffe + +#define RTFSL_FIO_OP_WRITE 0x01 +#define RTFSL_FIO_OP_APPEND 0x02 + +void rtfsl_get_system_date(unsigned short *time, unsigned short *date); +int rtfsl_read_sectors(unsigned long sector,int count, unsigned char *buffer); +int rtfsl_write_sectors(unsigned long sector, int count, unsigned char *buffer); + +struct rtfsl_dosinode { + unsigned char fname[8]; + unsigned char fext[3]; + unsigned char fattribute; /* File attributes */ + unsigned char reservednt; + unsigned char create10msincrement; + unsigned short ctime; /* time & date create */ + unsigned short cdate; + unsigned short adate; /* Date last accessed */ + unsigned short fclusterhi; /* This is where fat32 stores file location */ + unsigned short ftime; /* time & date lastmodified */ + unsigned short fdate; + unsigned short fcluster; /* Cluster for data file */ + unsigned long fsize; /* File size */ + }; + +struct rtfsl_drive +{ + unsigned long partition_base; + unsigned long partition_size; + unsigned long maxfindex; + unsigned long numsecs; + unsigned long secpfat; + unsigned long rootbegin; + unsigned long firstclblock; + unsigned long free_alloc; + unsigned long next_alloc; + unsigned long end_cluster_marker; + unsigned short bytespsector; + unsigned long bytespcluster; + unsigned short secreserved; + unsigned short numroot; +#define RTFSL_IOTYPE_FILE_FLAG 0x01 +#define RTFSL_FAT_CHANGED_FLAG 0x02 /* For FAT32 systems this is set when freespece has changed and the infosec needs a flush */ + unsigned short flags; + unsigned short infosec; + unsigned short backup; + unsigned char secpalloc; + unsigned char numfats; + unsigned char fasize; + unsigned char **pathnamearray; +}; +struct rtfsl_file { + unsigned long sector; + struct rtfsl_dosinode dos_inode; + unsigned long file_pointer; + unsigned long file_pointer_at_segment_base; + unsigned long segment_size_bytes; + unsigned long next_segment_base; + unsigned long cluster_segment_array[RTFSL_CFG_FILE_FRAG_BUFFER_SIZE][2]; + unsigned short index; +#define TRTFSFILE_ISROOT_DIR 0x01 +#define TRTFSFILE_DIRTY 0x02 +#define TRTFSFILE_SECTOR_REGION 0x04 +#define TRTFSFILE_ALLOCATED 0x08 +#define TRTFSFILE_ISMKDIR 0x10 + unsigned char rtfsl_file_flags; +#define RTFSL_ENTRY_TYPE_ERASED 1 /* Must be power of 2. */ +#define RTFSL_ENTRY_TYPE_DIRECTORY 2 +#define RTFSL_ENTRY_TYPE_VOLUME 4 +#define RTFSL_ENTRY_TYPE_LFN 8 +#define RTFSL_ENTRY_TYPE_FILE 16 +#define RTFSL_ENTRY_TYPE_EOF 32 +#define RTFSL_ENTRY_AVAILABLE (RTFSL_ENTRY_TYPE_ERASED|RTFSL_ENTRY_TYPE_EOF) + unsigned char rtfsl_direntry_type; +}; + +/* Structure for use by rtfsl_gfirst, rtfsl_gnext */ +struct rtfsl_dstat { + unsigned char fnameandext[12]; /* Null terminated file and extension */ + unsigned char fattribute; /* File attributes */ + unsigned short ftime; /* time & date lastmodified. See date */ + unsigned short fdate; /* and time handlers for getting info */ + unsigned short ctime; /* time & date created */ + unsigned short cdate; + unsigned short atime; /* time & date accessed */ + unsigned short adate; /* Date last accessed */ + unsigned long fsize; /* File size */ + /* INTERNAL */ + struct rtfsl_file directory_file; + struct rtfsl_file current_matched_file; + unsigned char *nametomatch; + }; +/* Structure for use by rtfsl_stat and rtfsl_fstat */ +struct rtfsl_statstructure +{ + int st_dev; /* (0) */ + int st_ino; /* (0) */ + unsigned long st_mode; /* (0) */ + int st_nlink; /* (0) */ + int st_rdev; /* (0) */ + unsigned long st_size; /* file size, in bytes */ + unsigned long st_atime; /* last access date in high 16 bits */ + unsigned long st_mtime; /* last modification date|time */ + unsigned long st_ctime; /* file create date|time */ + unsigned long st_blksize; /* optimal blocksize for I/O (cluster size) */ + unsigned long st_blocks; /* blocks allocated for file */ + unsigned char fattribute; /* File attributes - DOS attributes + (non standard but useful) */ +}; + +#define PCDELETE (unsigned char) 0xE5 +#define ARDONLY 0x1 /* MS-DOS File attributes */ +#define AHIDDEN 0x2 +#define ASYSTEM 0x4 +#define AVOLUME 0x8 +#define ADIRENT 0x10 +#define ARCHIVE 0x20 +#define ANORMAL 0x00 +#define CHICAGO_EXT 0x0f /* Chicago extended filename attribute */ + + +#define PSEEK_SET 0 /* offset from begining of file*/ +#define PSEEK_CUR 1 /* offset from current file pointer*/ +#define PSEEK_END 2 /* offset from end of file*/ + +unsigned long to_ULONG( unsigned char *from); +unsigned short to_USHORT( unsigned char *from); +void fr_USHORT(unsigned char *to, unsigned short from); +void fr_ULONG(unsigned char *to, unsigned long from); + + + +int rtfsl_diskopen(void); +unsigned long rtfsl_cl2sector(unsigned long cluster); +int rtfsl_finode_get( struct rtfsl_file *pfile, unsigned long sector, unsigned short index); +unsigned long rtfsl_sec2cluster( unsigned long sector); +int rtfsl_finode_open(struct rtfsl_file *pfile); +int rtfsl_root_finode_open(struct rtfsl_file *pfile); +long rtfsl_load_next_segment(struct rtfsl_file *pfile,unsigned long current_cluster); + +typedef int (*DirScanCallback) (struct rtfsl_file const *pcurrent_entry_file, void *puser_data); +typedef unsigned long (*FileScanCallback) (struct rtfsl_file const *pfile, unsigned long start_sector, unsigned long nbytes, void *puser_data); + +int rtfsl_enumerate_file(struct rtfsl_file *pfile,FileScanCallback pCallback, void *puser_data); +int rtfsl_enumerate_directory(struct rtfsl_file *pdirectory_file,struct rtfsl_file *pcurrent_entry_file,DirScanCallback pCallback, void *puser_data); + +int rtfsl_read_sector_buffer(unsigned long sector); +int rtfsl_flush_sector_buffer(int bufferhandle,int force); +void rtfsl_mark_sector_buffer(int bufferhandle); +int rtfsl_flush_all_buffers(void); +int fatop_buff_get_frag(unsigned long current_cluster, unsigned long *pnext_cluster, unsigned long max_length); +int rtfsl_open_path(unsigned char **pathlist,unsigned char *pentryname, struct rtfsl_file *directory_file, struct rtfsl_file *ptarget_file); +int rtfsl_clzero(unsigned long cluster); + +int rtfsl_load_file(unsigned char *filename, unsigned long load_address); +void rtfsl_setpath(unsigned char **pathnamearray); +int rtfsl_gfirst(struct rtfsl_dstat *statobj, unsigned char *name); +int rtfsl_gnext(struct rtfsl_dstat *statobj); +void rtfsl_done(struct rtfsl_dstat *statobj); + +int rtfsl_alloc_fd(void); +int _rtfsl_open(unsigned char *name,unsigned char attributes); +int rtfsl_open(unsigned char *name); +#define rtfsl_dir_open(N) _rtfsl_open(N,ADIRENT) +int rtfsl_read(int fd, unsigned char *in_buff, int count); +int rtfsl_close(int fd); +long rtfsl_lseek(int fd, long offset, int origin); +int rtfsl_fstat(int fd, struct rtfsl_statstructure *pstat); +int rtfsl_write(int fd, unsigned char *in_buff, int count); +int rtfsl_flush(int fd); +int rtfsl_flush_info_sec(void); +int rtfsl_create(unsigned char *name, unsigned char attribute); +int rtfsl_mkdir (unsigned char *name); +int rtfsl_rmdir(unsigned char *name); +int _rtfsl_delete(unsigned char *name, unsigned char attribute); +int rtfsl_delete(unsigned char *name); +int rtfsl_rename(unsigned char *name, unsigned char *newname); + + +unsigned long rtfslfs_cluster_remap(unsigned long cluster,unsigned long value); +int rtfslfs_cluster_map(unsigned long cluster,unsigned long value); +int rtfslfs_dirent_remap(unsigned long sector,unsigned long index, struct rtfsl_dosinode *p_dos_inode,int reading); + +#define RTFSLFS_JTEST 1 +#define RTFSLFS_JCLEAR 2 +#define RTFSLFS_JREAD 3 +#define RTFSLFS_JWRITE 4 + +int rtfslfs_start(void); +int rtfslfs_flush(void); +int rtfslfs_restore(void); +int rtfslfs_sync(void); +int rtfslfs_access_journal(int command); + + + +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) +typedef unsigned long treplacement_record[2]; +struct rtfsl_failsafe_context { + /* Current cache */ + int journal_buffer_size; + int journal_buffer_free; + unsigned char *journal_buffer; +#define REPLACEMENT_RECORD_SIZE_BYTES 8 +#define REPLACEMENT_DOSINODESIZE_SIZE_BYTES 32 + unsigned long *preplacement_record_count; /* The first entry in the journal is reserved for replacement_record_count:replacement_dosinode_count */ + unsigned long *pcurrent_dosinode_offset; /* The second entry in the journal is reserved for replacement_record_count:replacement_dosinode_count */ + treplacement_record *preplacement_records; +#define RTFSLFS_WRITE_DIRENTRY 0x1 +#define RTFSLFS_MAPPED_CL_FOUND 0x2 + unsigned char flags; +}; +#endif + +extern const char *dotname; +extern const char *dotdotname; +extern const unsigned char end_name[11]; + +struct rtfsl_context { + struct rtfsl_drive current_dr; + struct rtfsl_file rtfsl_files[RTFSL_CFG_NFILES]; + unsigned long current_buffered_sectors[RTFSL_CFG_NUMBUFFERS]; + unsigned char buffer_pool_agingstack[RTFSL_CFG_NUMBUFFERS]; + unsigned char *pcurrent_buffer_pool; + unsigned long buffer_pool_dirty; +#if (RTFSL_INCLUDE_SECURE_DIGITAL) + unsigned long buffer_isfiledata; +#endif +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) + struct rtfsl_failsafe_context rtfsl_failsafe_context; + unsigned char rtfslfs_sector_buffer[RTFSL_CFG_FSBUFFERSIZEBYTES]; + struct rtfsl_failsafe_context *rtfsl_current_failsafe_context; +#endif +}; +extern struct rtfsl_context rtfsl; + +extern unsigned char rtfsl_sector_buffer[]; + +#define rtfsl_buffer_address(H) rtfsl.pcurrent_buffer_pool+((H)*rtfsl.current_dr.bytespsector) + + +#endif /* __RTFSLITE__ */ diff --git a/rtfslitecore.c b/rtfslitecore.c new file mode 100644 index 0000000..a2b4e8d --- /dev/null +++ b/rtfslitecore.c @@ -0,0 +1,929 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + + +#include "rtfslite.h" + +#define BUFHMASK(H) (1<1) +int rtfsl_load_cluster_chain(unsigned long start_cluster, unsigned long *segment_length_clusters, unsigned long *start_next_segment, unsigned long cluster_segment_array[][2], int cluster_segment_array_size); +#endif +#if (RTFSL_INCLUDE_WRITE_SUPPORT) + + +void rtfsl_mark_sector_buffer(int bufferhandle) +{ + rtfsl.buffer_pool_dirty|=BUFHMASK(bufferhandle); +} + +int rtfsl_flush_sector_buffer(int bufferhandle,int force) +{ + int rval=0; + if (force||(rtfsl.buffer_pool_dirty&BUFHMASK(bufferhandle))) + { + unsigned char *b = rtfsl.pcurrent_buffer_pool+(bufferhandle*rtfsl.current_dr.bytespsector); + rval = rtfsl_write_sectors(rtfsl.current_buffered_sectors[bufferhandle],1,b); + if (rval==0&&rtfsl.current_dr.numfats==2) + { + unsigned long l; + l=rtfsl.current_buffered_sectors[bufferhandle]-rtfsl.current_dr.partition_base; + if (l>=rtfsl.current_dr.secreserved && l1) + b=rtfsl.buffer_pool_agingstack; + for(i=0;i=0) + { + if (!found) + rval=rtfsl_read_sectors(sector,1, rtfsl.pcurrent_buffer_pool+(bufferhandle*rtfsl.current_dr.bytespsector)); + if (rval>=0) + { + int ntocopy=0; + rtfsl.current_buffered_sectors[bufferhandle]=sector; + rval=(int)bufferhandle; +#if (RTFSL_CFG_NUMBUFFERS>1) + if (b[0]!=bufferhandle) + { /* Move the buffer to the top of the aging stack if it isn;t already there */ + for (i=1;i 1) + cl = rtfsl.current_dr.firstclblock + (cluster - 2)*rtfsl.current_dr.secpalloc; + else + cl=0; + return cl; +} + + + +int rtfsl_diskopen(void) /*__apifn__*/ +{ +unsigned char *sector_buffer; +unsigned char i,*b; +int rval; + + + ANSImemset(&rtfsl, 0, sizeof(rtfsl)); + rtfsl.pcurrent_buffer_pool=rtfsl_sector_buffer; +// ANSImemset(&rtfsl.current_dr, 0, sizeof(rtfsl.current_dr)); + /* Initialize a stack we use to age buffer usage. The bottom of the stack is the least recently used handle */ + for(i=0;i 32M (4.0) */ + if (rtfsl.current_dr.numroot == 0) + rtfsl.current_dr.fasize = 8; + else + { /* Check the bpb file sys type field. If it was initialized by format use that to determine FAT type */ + if (ANSImemcmp(b+0x36, (void *)"FAT1",4)==0) + { + if (*(b + 0x3A) == (unsigned char)'2') +#if (RTFSL_INCLUDE_FAT12) + rtfsl.current_dr.fasize = 3; +#else + return RTFSL_ERROR_FORMAT; +#endif + else + if (*(b + 0x3A) == (unsigned char)'6') + rtfsl.current_dr.fasize = 4; + } + else + return RTFSL_ERROR_FORMAT; + } + if (rtfsl.current_dr.fasize == 8) + { +#if (RTFSL_INCLUDE_FAT32) + rtfsl.current_dr.secpfat = to_ULONG(b+0x24); + rtfsl.current_dr.flags = to_USHORT(b+0x28); + rtfsl.current_dr.rootbegin = to_ULONG(b+0x2c); + rtfsl.current_dr.infosec = to_USHORT(b+0x30); + rtfsl.current_dr.backup = to_USHORT(b+0x32); + /* Read one block */ + rval=rtfsl_read_sectors(rtfsl.current_dr.partition_base+rtfsl.current_dr.infosec,1,sector_buffer); + if (rval<0) + return rval; + b=sector_buffer; + b += 484; +#define FSINFOSIG 0x61417272ul + if (FSINFOSIG == to_ULONG(b)) + { + rtfsl.current_dr.free_alloc = to_ULONG(b+4); + rtfsl.current_dr.next_alloc = to_ULONG(b+8); + } + else + { /* If the signature is not found default to the beginning of the FAT */ + rtfsl.current_dr.infosec = 0; + rtfsl.current_dr.free_alloc = 0xffffffff; + rtfsl.current_dr.next_alloc = 2; + + } +#else + return RTFSL_ERROR_FORMAT; +#endif + } + else + { /* If the signature is not found default to the beginning of the FAT */ + rtfsl.current_dr.free_alloc = 0xffffffff; + rtfsl.current_dr.next_alloc = 2; + } + + rtfsl.current_dr.firstclblock = rtfsl.current_dr.secreserved + (unsigned long)rtfsl.current_dr.secpfat*rtfsl.current_dr.numfats; + if (rtfsl.current_dr.fasize != 8) + rtfsl.current_dr.firstclblock += ((unsigned long)rtfsl.current_dr.numroot*32+rtfsl.current_dr.bytespsector-1)/rtfsl.current_dr.bytespsector; +#if (RTFSL_INCLUDE_FAT12) + if (rtfsl.current_dr.fasize == 3) + { + rtfsl.current_dr.end_cluster_marker = 0xff7; + } + else +#endif + if (rtfsl.current_dr.fasize == 4) + { + rtfsl.current_dr.end_cluster_marker = 0xfff7; + } +#if (RTFSL_INCLUDE_FAT32) + else /* if (rtfsl.current_dr.fasize == 8) */ + { + rtfsl.current_dr.end_cluster_marker = 0x0ffffff7; + } +#endif + rtfsl.current_dr.maxfindex = (unsigned long)(1 + ((rtfsl.current_dr.numsecs-rtfsl.current_dr.firstclblock)/rtfsl.current_dr.secpalloc)); + { + /* Make sure the calculated index doesn't overflow the fat sectors */ + unsigned long max_index; + /* For FAT32 Each block of the fat holds 128 entries so the maximum index is + (pdr->secpfat * pdr->drive_info.clpfblock32 (128 for block size 512) )-1; */ + max_index = (unsigned long) rtfsl.current_dr.secpfat; + max_index *= (rtfsl.current_dr.bytespsector*2)/rtfsl.current_dr.fasize; + max_index -= 1; + if (rtfsl.current_dr.maxfindex > max_index) + rtfsl.current_dr.maxfindex = max_index; + } + return(0); +} + +int rtfsl_finode_get(struct rtfsl_file *pfile, unsigned long sector, unsigned short index) +{ +unsigned char *sector_buffer; +struct rtfsl_dosinode *pdos_inode; +int rval; + ANSImemset(pfile, 0, sizeof(*pfile)); + rval=rtfsl_read_sector_buffer(rtfsl.current_dr.partition_base+sector); + if (rval<0) + return rval; + sector_buffer = rtfsl_buffer_address(rval); + pfile->sector=sector; + pfile->index=index; + pdos_inode = (struct rtfsl_dosinode *) sector_buffer; + pdos_inode += index; +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) + if (rtfsl.rtfsl_current_failsafe_context) + { + /* Check the journal file for an override directory entry and copy it into the buffer if one is found. */ + rval=rtfslfs_dirent_remap(rtfsl.current_dr.partition_base+sector,index, pdos_inode,1); + if (rval<0) + return rval; + } +#endif + pfile->dos_inode = *pdos_inode; + if (pfile->dos_inode.fname[0]==0 || (ANSImemcmp(pfile->dos_inode.fname,end_name,8)==0) ) + pfile->rtfsl_direntry_type =RTFSL_ENTRY_TYPE_EOF; + else if (pfile->dos_inode.fname[0]==PCDELETE) + pfile->rtfsl_direntry_type =RTFSL_ENTRY_TYPE_ERASED; + else + { + /* Convert Kanji esc character 0x05 to 0xE5 */ + if (pfile->dos_inode.fname[0]==0x05) + pfile->dos_inode.fname[0]=PCDELETE; + if (pfile->dos_inode.fattribute== CHICAGO_EXT) + pfile->rtfsl_direntry_type =RTFSL_ENTRY_TYPE_LFN; + else if (pfile->dos_inode.fattribute&AVOLUME) + pfile->rtfsl_direntry_type =RTFSL_ENTRY_TYPE_VOLUME; + else if (pfile->dos_inode.fattribute&ADIRENT) + pfile->rtfsl_direntry_type =RTFSL_ENTRY_TYPE_DIRECTORY; + else + { + /* Dos file size is set during get, direectory size during open */ + /* Swap pfile->dos_inode.fsize since we use it a lot */ + unsigned long l = to_ULONG((unsigned char *)&pfile->dos_inode.fsize); + pfile->rtfsl_direntry_type =RTFSL_ENTRY_TYPE_FILE; + pfile->dos_inode.fsize=l; + } + } + return 0; +} +/* Load cluster chains set file size if it's a directory */ +int rtfsl_finode_open(struct rtfsl_file *pfile) +{ +unsigned long current_cluster,chain_length_bytes; +long segments; + pfile->file_pointer=0; + pfile->file_pointer_at_segment_base=0; + pfile->segment_size_bytes=0; + if (pfile->rtfsl_file_flags & TRTFSFILE_SECTOR_REGION) + return 0; + else if (pfile->rtfsl_file_flags & TRTFSFILE_ISROOT_DIR) + { +#if (RTFSL_INCLUDE_FAT32) + if (rtfsl.current_dr.fasize==8) + current_cluster = rtfsl.current_dr.rootbegin; + else +#endif + { + pfile->dos_inode.fsize = rtfsl.current_dr.numroot*32; + pfile->cluster_segment_array[0][0]=rtfsl.current_dr.rootbegin; + pfile->cluster_segment_array[0][1]=rtfsl.current_dr.rootbegin+pfile->dos_inode.fsize/rtfsl.current_dr.bytespsector; + pfile->segment_size_bytes=pfile->dos_inode.fsize; + pfile->next_segment_base=0; + pfile->rtfsl_file_flags|=TRTFSFILE_SECTOR_REGION; + return 0; + } + } + else + { + current_cluster = to_USHORT((unsigned char *)&pfile->dos_inode.fclusterhi); + current_cluster <<= 16; + current_cluster |= to_USHORT((unsigned char *)&pfile->dos_inode.fcluster); + } + if (!current_cluster) + return 0; + /* Get the first segment */ + segments = rtfsl_load_next_segment(pfile,current_cluster); + if (segments < 0) + return (int)segments; + /* Traverse the cluster chain, return the total number of segments, &chain_length_clusters and populate pfile->cluster_segment_array with up to RTFSL_CFG_FILE_FRAG_BUFFER_SIZE segments */ + chain_length_bytes=pfile->segment_size_bytes; + if (pfile->cluster_segment_array[RTFSL_CFG_FILE_FRAG_BUFFER_SIZE-1][0]) + { + while (pfile->cluster_segment_array[RTFSL_CFG_FILE_FRAG_BUFFER_SIZE-1][0]) + { + segments = rtfsl_load_next_segment(pfile,0); + if (segments < 0) + return (int)segments; + chain_length_bytes+=pfile->segment_size_bytes; + } + /* Get the first segment again */ + pfile->segment_size_bytes=0; + pfile->file_pointer_at_segment_base=0; + segments=rtfsl_load_next_segment(pfile,current_cluster); + if (segments < 0) + return (int)segments; + } + /* Dos file size is set during get, direectory size during open */ + if (pfile->dos_inode.fattribute & ADIRENT) + { + pfile->dos_inode.fsize = chain_length_bytes; + } + return 0; +} + +int rtfsl_root_finode_open(struct rtfsl_file *pfile) +{ + ANSImemset(pfile, 0, sizeof(*pfile)); + pfile->rtfsl_file_flags = TRTFSFILE_ISROOT_DIR|TRTFSFILE_ALLOCATED; + pfile->rtfsl_direntry_type=RTFSL_ENTRY_TYPE_DIRECTORY; + pfile->dos_inode.fattribute = ADIRENT|TRTFSFILE_ISROOT_DIR; + return rtfsl_finode_open(pfile); +} +/* Returns bytes */ +long rtfsl_load_next_segment(struct rtfsl_file *pfile,unsigned long current_cluster) +{ +#if (RTFSL_CFG_FILE_FRAG_BUFFER_SIZE>1) +long cluster_segments; +unsigned long cluster_segment_length; +#endif + ANSImemset(pfile->cluster_segment_array,0,sizeof(pfile->cluster_segment_array)); + if (!current_cluster) + current_cluster=pfile->next_segment_base; + if (!current_cluster) + { + return 0; + } +#if (RTFSL_CFG_FILE_FRAG_BUFFER_SIZE==1) + { + int length; + length = fatop_buff_get_frag(current_cluster, &pfile->next_segment_base,pfile->rtfsl.current_dr.end_cluster_marker); + if (length > 0) + { + pfile->segment_size_bytes = (unsigned long) length*pfile->rtfsl.current_dr.bytespcluster; + return 1; + } + else + return length; + } +#else + /* Traverse the cluster chain, return the total number of segments, &chain_length_clusters and populate pfile->cluster_segment_array with up to RTFSL_CFG_FILE_FRAG_BUFFER_SIZE segments */ + cluster_segments = (long)rtfsl_load_cluster_chain(current_cluster, &cluster_segment_length, &pfile->next_segment_base, pfile->cluster_segment_array, RTFSL_CFG_FILE_FRAG_BUFFER_SIZE); + if (cluster_segments>=0) + { + pfile->file_pointer_at_segment_base += pfile->segment_size_bytes; + cluster_segment_length = cluster_segment_length*rtfsl.current_dr.bytespcluster; + pfile->segment_size_bytes=cluster_segment_length; + } + return cluster_segments; +#endif +} + + +#if (RTFSL_CFG_FILE_FRAG_BUFFER_SIZE>1) +/* + + Scan from start_cluster, if chain_length_clusters is zero break out when is hit +*/ +int rtfsl_load_cluster_chain(unsigned long start_cluster, unsigned long *segment_length_clusters, unsigned long *start_next_segment, unsigned long cluster_segment_array[][2], int cluster_segment_array_size) +{ +unsigned long next_cluster; +int segment_count; + segment_count=0; + *segment_length_clusters=0; + *start_next_segment=0; + ANSImemset(cluster_segment_array,0,sizeof(cluster_segment_array[0])*cluster_segment_array_size); + while (start_cluster != 0) + { + int length; + length = fatop_buff_get_frag(start_cluster, &next_cluster,rtfsl.current_dr.end_cluster_marker); + if (length < 0) + return length; + + if (segment_countfile_pointer=0; + pfile->file_pointer_at_segment_base=0; + pfile->segment_size_bytes=0; + pfile->next_segment_base=0; + pfile->cluster_segment_array[0][0]=0; + pfile->next_segment_base = to_USHORT((unsigned char *)&pfile->dos_inode.fclusterhi); + pfile->next_segment_base <<= 16; + pfile->next_segment_base |= to_USHORT((unsigned char *)&pfile->dos_inode.fcluster); + for(;;) + { + if (current_cluster_segment >= RTFSL_CFG_FILE_FRAG_BUFFER_SIZE) + { + int rval; + rval = rtfsl_load_next_segment(pfile,0); + if (rval<= 0) + return rval; + current_cluster_segment = 0; + } + if (!pfile->cluster_segment_array[current_cluster_segment][0]) + break; + start_sector=rtfsl_cl2sector(pfile->cluster_segment_array[current_cluster_segment][0]); + end_sector=rtfsl_cl2sector(pfile->cluster_segment_array[current_cluster_segment][1])+rtfsl.current_dr.secpalloc-1; + nbytes = (end_sector-start_sector+1)*rtfsl.current_dr.bytespsector; + if (pfile->file_pointer+nbytes > pfile->dos_inode.fsize) + nbytes = pfile->dos_inode.fsize-pfile->file_pointer; + if (nbytes==0) + return 0; + callback_value=pCallback(pfile,start_sector, nbytes, puser_data); + if (callback_value==0) + return 0; + pfile->file_pointer += callback_value; + if (pfile->file_pointer >= pfile->dos_inode.fsize) + pfile->file_pointer=pfile->dos_inode.fsize; + if (callback_value != nbytes ||pfile->file_pointer >= pfile->dos_inode.fsize) + { + return 0; + } + current_cluster_segment += 1; + + } + return 0; +} + + +int rtfsl_enumerate_directory(struct rtfsl_file *pdirectory_file,struct rtfsl_file *pcurrent_entry_file,DirScanCallback pCallback, void *puser_data) /*__apifn__*/ +{ +unsigned long sector,start_sector,end_sector,sector_offset; +int current_cluster_segment = 0; +unsigned short start_index; + sector_offset = pdirectory_file->file_pointer/rtfsl.current_dr.bytespsector; + start_index = (unsigned short) (pdirectory_file->file_pointer%rtfsl.current_dr.bytespsector)/32; + pcurrent_entry_file->rtfsl_direntry_type =RTFSL_ENTRY_TYPE_EOF; + for(;;) + { + if (pdirectory_file->rtfsl_file_flags & TRTFSFILE_SECTOR_REGION) + { + start_sector=pdirectory_file->cluster_segment_array[current_cluster_segment][0]; + end_sector = pdirectory_file->cluster_segment_array[current_cluster_segment][1]; + } +#if (RTFSL_INCLUDE_SUBDIRECTORIES) + else + { + start_sector=rtfsl_cl2sector(pdirectory_file->cluster_segment_array[current_cluster_segment][0]); + end_sector=rtfsl_cl2sector(pdirectory_file->cluster_segment_array[current_cluster_segment][1])+rtfsl.current_dr.secpalloc-1; + + } +#endif + if (sector_offset) + { + unsigned long l = end_sector-start_sector+1; + if (sector_offset>l) + { + sector_offset-=l; + end_sector=start_sector-1; /* Dont scan any sectors just advance */ + + } + else + { + start_sector+=sector_offset; + } + } + for (sector=start_sector;sector<=end_sector;sector++) + { + unsigned short index; + for (index=start_index; index < rtfsl.current_dr.bytespsector/32; index++) + { + int callback_value; + rtfsl_finode_get(pcurrent_entry_file, sector, index); + pdirectory_file->file_pointer += 32; + callback_value=pCallback(pcurrent_entry_file, puser_data); + if (callback_value != 0) + return callback_value; + } + start_index=0; + } +#if (!RTFSL_INCLUDE_SUBDIRECTORIES) + break; +#else + if (pdirectory_file->rtfsl_file_flags & TRTFSFILE_SECTOR_REGION) + break; + + else + { + if (pcurrent_entry_file->rtfsl_direntry_type==RTFSL_ENTRY_TYPE_EOF) + break; + current_cluster_segment += 1; + if (current_cluster_segment >= RTFSL_CFG_FILE_FRAG_BUFFER_SIZE) + { + int rval; + rval = rtfsl_load_next_segment(pdirectory_file,0); + if (rval<= 0) + break; + current_cluster_segment = 0; + } + if (!pdirectory_file->cluster_segment_array[current_cluster_segment][0]) + break; + } +#endif + } + return 0; +} + +int fatop_buff_get_frag(unsigned long current_cluster, unsigned long *pnext_cluster, unsigned long max_length) +{ + unsigned long next_cluster,sector,fat12accumulator,last_sector; + unsigned long n_contig; + unsigned char *sector_buffer; + int Fat12ReadState,buffernumber; + int byte_offset_in_buffer,bytes_remaining,bytes_per; +#if (RTFSL_INCLUDE_WRITE_SUPPORT) + int towrite=3; + unsigned long writing; + unsigned long value; +#endif + + n_contig = 1; +#if (RTFSL_INCLUDE_WRITE_SUPPORT) + writing=current_cluster&RTFSL_MASK_COMMAND; + current_cluster=current_cluster&~RTFSL_MASK_COMMAND; + value = *pnext_cluster; + if (writing==RTFSL_ALLOC_CLUSTER) + n_contig=0; +#if (RTFSL_INCLUDE_FAT32) + rtfsl.current_dr.flags|=RTFSL_FAT_CHANGED_FLAG; /* We have to flush the infosec */ +#endif +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) + if (writing==RTFSL_WRITE_CLUSTER && rtfsl.rtfsl_current_failsafe_context) + { + return rtfslfs_cluster_map(current_cluster, value); + } +#endif + if (writing!=RTFSL_WRITE_CLUSTER) +#endif + *pnext_cluster = 0x0; + + Fat12ReadState = 0; + fat12accumulator=0; + bytes_per=rtfsl.current_dr.fasize/2; +#if (RTFSL_INCLUDE_FAT12) + if (rtfsl.current_dr.fasize == 3) + { + unsigned long bytenumber; + bytenumber = (current_cluster * 3)/2; + sector = bytenumber/rtfsl.current_dr.bytespsector; + byte_offset_in_buffer = bytenumber & (rtfsl.current_dr.bytespsector-1); + Fat12ReadState=(current_cluster % 2); + /* + Fat12ReadState==0 - Good to go + FatReadstate==1 - Goto FatReadstate3 + FatReadstate==3 - Start first pass ignoring accumulator and goto state 2 + FatReadstate==2 - Decrement byte offset and go to state 3 on read state 2 on write + */ + if (Fat12ReadState==2) + { + if (bytenumber) + bytenumber-=1; + else + { + sector-=1; + bytenumber=rtfsl.current_dr.bytespsector-1; + } +#if (RTFSL_INCLUDE_WRITE_SUPPORT) + if (writing==RTFSL_WRITE_CLUSTER) + Fat12ReadState=2; + else +#endif + Fat12ReadState=3; + } + else if (Fat12ReadState==1) +#if (0 && RTFSL_INCLUDE_WRITE_SUPPORT) + if (writing==RTFSL_WRITE_CLUSTER) + ; // Fat12ReadState=1; + else +#endif + Fat12ReadState=3; + } + else +#endif + { + sector = current_cluster / (rtfsl.current_dr.bytespsector/bytes_per); + byte_offset_in_buffer = (current_cluster & ((rtfsl.current_dr.bytespsector/bytes_per)-1)) * bytes_per; + } + sector = sector + rtfsl.current_dr.secreserved; + last_sector = sector+rtfsl.current_dr.secpfat-1; + bytes_remaining = rtfsl.current_dr.bytespsector-byte_offset_in_buffer; + buffernumber=rtfsl_read_sector_buffer(rtfsl.current_dr.partition_base+sector); + if (buffernumber<0) + return buffernumber; + sector_buffer = rtfsl_buffer_address(buffernumber); + while(n_contig <= max_length) + { + while (bytes_remaining) + { + next_cluster=0; + if (rtfsl.current_dr.fasize>3) + { + if (bytes_per==2) + { +#if (RTFSL_INCLUDE_WRITE_SUPPORT) + if (writing==RTFSL_WRITE_CLUSTER) + { + fr_USHORT(sector_buffer+byte_offset_in_buffer,(unsigned short)value); + break; + } + else +#endif + next_cluster = (unsigned long)to_USHORT(sector_buffer+byte_offset_in_buffer); + } + else + { +#if (RTFSL_INCLUDE_WRITE_SUPPORT) + if (writing==RTFSL_WRITE_CLUSTER) + { + fr_ULONG(sector_buffer+byte_offset_in_buffer,value); + rtfsl_mark_sector_buffer(buffernumber); + break; + } + else +#endif + next_cluster = (unsigned long)to_ULONG(sector_buffer+byte_offset_in_buffer); + } + bytes_remaining-=bytes_per; + byte_offset_in_buffer+=bytes_per; + } +#if (RTFSL_INCLUDE_FAT12) + else // if (rtfsl.current_dr.fasize == 3) + { + unsigned char *p,b; + bytes_remaining-=1; + p=(sector_buffer+byte_offset_in_buffer); + b = *p; + byte_offset_in_buffer+=1; + + if (Fat12ReadState==0) + { + Fat12ReadState=1; +#if (RTFSL_INCLUDE_WRITE_SUPPORT) + if (writing==RTFSL_WRITE_CLUSTER) + { + *p = (unsigned char )value&0xff; + towrite-=2; + if (!towrite) + break; + } + else +#endif + fat12accumulator = b; + continue; + } + else if (Fat12ReadState==1) + { + Fat12ReadState=2; +#if (RTFSL_INCLUDE_WRITE_SUPPORT) + if (writing==RTFSL_WRITE_CLUSTER) + { + *p &= 0xf0; + *p |= (unsigned char)(value>>8)&0xf; // next_clusterv[hinibble]; + if (!--towrite) + break; + continue; + } +#endif + next_cluster = b&0x0f; + next_cluster <<= 8; + next_cluster |= fat12accumulator; + fat12accumulator = (b&0xf0)>>4; + } + else if (Fat12ReadState==2) + { + Fat12ReadState=0; +#if (RTFSL_INCLUDE_WRITE_SUPPORT) + if (writing==RTFSL_WRITE_CLUSTER) + { + *p = (unsigned char)(value>>4)&0xff; // b = v>>4; next_clusterv[hinibble]; + towrite-=2; + if (!towrite) + break; + continue; + } +#endif + next_cluster = b<<4; + next_cluster |= fat12accumulator; + } + else if (Fat12ReadState==3) + { + Fat12ReadState=2; +#if (RTFSL_INCLUDE_WRITE_SUPPORT) + if (writing==RTFSL_WRITE_CLUSTER) + { + *p &= 0x0f; + *p |= (unsigned char)(value&0x0f)<<4; + if (!--towrite) + break; + continue; + } +#endif + fat12accumulator = (b&0xf0)>>4; /* hi byte of b to accumulator lo byte of value*/ + + continue; + } + } +#endif +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) + /* If failsafe is enabled give it a chance to override the cluster number or return the same value, there is no failure condition */ + if (rtfsl.rtfsl_current_failsafe_context) + { + unsigned long mapped_cluster; + mapped_cluster = rtfslfs_cluster_remap(current_cluster, next_cluster); + /* If we are allocating do not report zero valued clusters in the journal file as free or we could overwrite blocks in an uncommitted delete */ + if (mapped_cluster != next_cluster) + { + if (mapped_cluster==RTFSL_JOURNALDELETED_CLUSTER) + { + if (writing==RTFSL_ALLOC_CLUSTER) /* If we are allocating force a nonmatch on next_cluster so we skip the cluster */ + next_cluster=rtfsl.current_dr.end_cluster_marker; + else + next_cluster=0; + } + else + next_cluster=mapped_cluster; + } + } +#endif +#if (RTFSL_INCLUDE_WRITE_SUPPORT) + if (writing==RTFSL_ALLOC_CLUSTER) + { + if (next_cluster==0) + { + *pnext_cluster = current_cluster; + return 1; + } + else + { + if (current_cluster==rtfsl.current_dr.maxfindex) + { + *pnext_cluster = 0; + return 0; + } + current_cluster += 1; + } + } + else +#endif + if (n_contig < max_length && next_cluster==(current_cluster+1)) + { + n_contig += 1; + current_cluster=next_cluster; + } + else + { + if (next_cluster < 2 || next_cluster >= rtfsl.current_dr.end_cluster_marker) + { + *pnext_cluster = 0; + + } + else + *pnext_cluster = next_cluster; + return (n_contig); + } + } +#if (RTFSL_INCLUDE_WRITE_SUPPORT) + if (writing==RTFSL_WRITE_CLUSTER) + { + int rval; + rval=rtfsl_flush_sector_buffer(buffernumber,1); + if (rval<0) + return rval; + if (rtfsl.current_dr.fasize !=3||towrite==0) + return 0; + } +#endif + if (sector >= last_sector) + { + *pnext_cluster = 0; + break; + } + else + { + sector += 1; + { + int rval=rtfsl_read_sector_buffer(rtfsl.current_dr.partition_base+sector); + if (rval<0) + return rval; + sector_buffer = rtfsl_buffer_address(rval); + } + byte_offset_in_buffer = 0; + bytes_remaining = rtfsl.current_dr.bytespsector; + } + } + return n_contig; +} diff --git a/rtfsliteshell.c b/rtfsliteshell.c new file mode 100644 index 0000000..b65c3a2 --- /dev/null +++ b/rtfsliteshell.c @@ -0,0 +1,563 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + +#include "rtfslite.h" +#include "rtfslitetests.h" +#include "stdlib.h" +#include "stdio.h" +#include + +#define rtp_term_gets gets + +// File load +void BootProgressReport(int percent) +{ + +} + +char lite_term_buffer[40]; +int lite_shell_running=0; +int lite_shell_help=0; +struct _command_list { + char *cmd; + int (*proc)( int argc, char **argv); + char *helpstr; +}; +static int dortfslite_help(int argc,char **argv); +static int dortfslite_exit(int argc,char **argv); +static int dortfslite_mount(int argc,char **argv); +static int dortfslite_lflush(int argc,char **argv); +static int dortfslite_dir(int argc,char **argv); +static int dortfslite_delete(int argc,char **argv); +static int dortfslite_rename(int argc,char **argv); +static int dortfslite_chdir(int argc,char **argv); +static int dortfslite_mkdir(int argc,char **argv); +static int dortfslite_rmdir(int argc,char **argv); +static int dortfslite_fill(int argc,char **argv); +static int dortfslite_append(int argc,char **argv); +static int dortfslite_check(int argc,char **argv); +static int dortfslite_randread(int argc,char **argv); +static int dortfslite_randwrite(int argc,char **argv); +static int dortfslite_filldisk(int argc,char **argv); +static int dortfslite_fsstart(int argc,char **argv); +static int dortfslite_fsstop(int argc,char **argv); +static int dortfslite_fssync(int argc,char **argv); +static int dortfslite_fsflush(int argc,char **argv); +static int dortfslite_fsrestore(int argc,char **argv); +static int dortfslite_load(int argc,char **argv); + +static const struct _command_list command_list[] = { + { "HELP", dortfslite_help, "HELP"}, + { "LOAD", dortfslite_load, "LOAD FILENAME"}, + { "LMOUNT", dortfslite_mount, "LMOUNT - re-mount rtfs lite drive"}, + { "LEXIT", dortfslite_exit, "LEXIT - Exit Lite mode refreshes device mount for rtfs"}, + { "LFLUSH", dortfslite_lflush, "LFLUSH - Flush rtfs lite buffers"}, + { "DIR", dortfslite_dir, "DIR"}, + { "RENAME", dortfslite_rename, "RENAME oldname newname"}, + { "DELETE", dortfslite_delete, "DELETE filename"}, + { "CHDIR", dortfslite_chdir, "CHDIR path"}, + { "MKDIR", dortfslite_mkdir, "MKDIR dirname 0|1 (1 = fragment)"}, + { "RMDIR", dortfslite_rmdir, "RMDIR dirname"}, + { "FILLPAT", dortfslite_fill, "FILLPAT filename nlongs 0|1 (1=fragment)"}, + { "APPENDPAT", dortfslite_append, "APPENDPAT filename nlongs 0|1 (1=fragment)"}, + { "READPAT", dortfslite_check, "READPAT filename"}, + { "RANDREAD", dortfslite_randread, "RANDREAD filename"}, + { "RANDWRITE", dortfslite_randwrite,"RANDWRITE filename"}, + { "FILLDISK", dortfslite_filldisk,"FILLDISK filenamebase"}, + + { "FSSTART", dortfslite_fsstart, "FSSTART Start Journaling"}, + { "FSSTOP", dortfslite_fsstop, "FSSTOP Stop Journaling"}, + { "FSSYNC", dortfslite_fssync, "FSSYNC Sync volume, keep journaling"}, + { "FSFLUSH", dortfslite_fsflush, "FSFLUSH Flush journal keep journaling"}, + { "FSRESTORE", dortfslite_fsrestore,"FSRESTORE Retore the volume from the journal"}, + {0,0,0} +}; + +static void GetUserInput(void); +static char *gnext(char *p); +static void prompt(void); +static void prompt(void); +static unsigned char * Convert83tortfslite83(char *to, char *from); + +void rtfslite_shell(void) +{ + lite_shell_running=1; + lite_shell_help = 1; + if (rtfsl_diskopen()!=0) + { + PRINTF("Lite disk mount failed can not continue\n"); + return; + } + while (lite_shell_running) + prompt(); +} + + +static int check_args(int argc,int shouldbe); +static void check_return(int rval,int shouldbe); + +static int dortfslite_help(int argc,char **argv) +{ + lite_shell_help=1; + return 0; +} + +#define LOAD_ADDRESS 0xa0100000 +#define START_ADDRESS 0xa014d8bc /* iar_start_address */ +#define STACK_ADDRESS 0xa01937d0 /* cstack limit */ +typedef void (* JUMPTO)(void); +unsigned long rtp_strtoul ( + const char * str, /** String to be converted. */ + char ** delimiter, /** Character that stops the convertion. */ + int base /** Base of return value. */ +); + +static int get_load_address(unsigned char *filename, unsigned long *loadaddr, unsigned long *stackaddr, unsigned long *startaddr) +{ +int fd,rval; +struct rtfsl_statstructure statstruct; +char readbuffer [36]; + *loadaddr= 0xa0100000; + *stackaddr=0xa01937d0; + *startaddr=0xa014d8bc; + fd = rtfsl_open((unsigned char*)filename); + if (fd>=0) + { + rval=rtfsl_read(fd, readbuffer, 36); + if (rval < 36) + { + PRINTF("Read Metadata failed\n"); + return -1; + } + /* [0123456789AB][0123456789AB][0123456789AB] 10 digits plus CR LF */ + readbuffer[10]=0; + readbuffer[22]=0; + readbuffer[34]=0; + +// *loadaddr=rtp_strtoul(&readbuffer[0], 0, 16); +// *stackaddr=rtp_strtoul(&readbuffer[12], 0, 16); +// *startaddr=rtp_strtoul(&readbuffer[24], 0, 16); + rtfsl_close(fd); + return 0; + } + else + { + PRINTF("Meta Data Open failed\n"); + } + + + return -1; +} + +static JUMPTO go_main; +static unsigned long loadaddr, stackaddr, startaddr; +int rtfslite_loadfilefromdisk(char *filenambase); +static int dortfslite_load(int argc,char **argv) +{ + return rtfslite_loadfilefromdisk(*argv); +} +extern void TouchScrClose(void); +int rtfslite_loadfilefromdisk(char *filenambase) +{ +int rval; +char buffer[32]; +char filename[32]; +char binfilename[32]; +char addrfilename[32]; +loadaddr = LOAD_ADDRESS; + + strcpy(binfilename,filenambase); + strcat(binfilename,".BIN"); + strcpy(addrfilename,filenambase); + strcat(addrfilename,".TXT"); + + if (get_load_address(Convert83tortfslite83(filename, addrfilename), &loadaddr, &stackaddr, &startaddr)==0) + { + // PRINTF("Got load addr %s\n", rtp_ultoa (loadaddr, buffer,16)); + // PRINTF("Got stack addr %s\n", rtp_ultoa (stackaddr, buffer,16)); + // PRINTF("Got run addr %s\n", rtp_ultoa (startaddr, buffer,16)); + + go_main = (JUMPTO) startaddr; + Convert83tortfslite83(filename,binfilename); + PRINTF("loading file: :%s: \n", filename); + rval = rtfsl_load_file(filename, (unsigned long) loadaddr); + if (rval==0) + { +// PRINTF("load file returned %d \n", rval); +// TouchScrClose(); /* Disable interrupts before jumping off */ +// __set_SP(stackaddr); + go_main(); + } + return 0; + } +} + +static int dortfslite_mount(int argc,char **argv) +{ +int rval; + rval=rtfsl_diskopen(); + check_return(rval,0); + return 0; +} + + +static int dortfslite_exit(int argc,char **argv) +{ + lite_shell_running=0; + return 0; +} +static int dortfslite_lflush(int argc,char **argv) +{ + rtfsl_flush_all_buffers(); + return 0; +} +static int dortfslite_dir(int argc,char **argv) +{ + struct rtfsl_dstat dstat; + if (rtfsl_gfirst(&dstat, 0)==1) + { + do { + if ((dstat.fattribute&(AVOLUME|ADIRENT))==0) + { + PRINTF("Got file : %s size: %ld \n",dstat.fnameandext,dstat.fsize); + } + else + { + PRINTF("Got entry: %s \n",dstat.fnameandext); + } + } while (rtfsl_gnext(&dstat)==1); + } + return 0; +} +static int dortfslite_delete(int argc,char **argv) +{ +char filename[12]; +int rval; + if (check_args(argc,1)==0) + { + rval=rtfsl_delete(Convert83tortfslite83(filename, *argv)); + check_return(rval,0); + } + return 0; +} +static int dortfslite_rename(int argc,char **argv) +{ +unsigned char filename[12],tofilename[12]; +int rval; + if (check_args(argc,2)==0) + { + Convert83tortfslite83((char *)filename, *argv++); + Convert83tortfslite83((char *)tofilename, *argv); + rval=rtfsl_rename(filename,tofilename); + check_return(rval,0); + } + return 0; +} + +unsigned char *shellpathnamearray[8]; +char shellpathnamestore[8][12]; + +static int dortfslite_chdir(int argc,char **argv) +{ +char *p,*pnext; +int depth = 0; + if (argc==0) + { + rtfsl_setpath(0); + return 0; + } + p= *argv; + while (p) + { + pnext = strstr(p, "\\"); + if (pnext) + *pnext =0; + Convert83tortfslite83(shellpathnamestore[depth],p); + shellpathnamearray[depth]=(unsigned char *)shellpathnamestore[depth]; + shellpathnamearray[depth+1]=0; + depth+=1; + if (pnext) + p=pnext+1; + else + p=0; + } + rtfsl_setpath(shellpathnamearray); + return 0; +} +static int dortfslite_mkdir(int argc,char **argv) +{ +char filename[12]; +int rval; + rval=rtfsl_mkdir(Convert83tortfslite83(filename, *argv)); + check_return(rval,0); + return 0; +} +static int dortfslite_rmdir(int argc,char **argv) +{ +char filename[12]; +int rval; + rval=rtfsl_rmdir(Convert83tortfslite83(filename, *argv)); + check_return(rval,0); + return 0; +} +static int dortfslite_fill(int argc,char **argv) +{ +char filename[12]; +int nlongs; +int gap; +int rval; + + if (check_args(argc,3)==0) + { + Convert83tortfslite83(filename, *argv++); + nlongs = atol(*argv++); + gap = atol(*argv++); + rval=rtfsltest_file_sequential_write((unsigned char *)filename, 1, gap, nlongs, 0); + check_return(rval,0); + } + return 0; +} + +static int dortfslite_filldisk(int argc,char **argv) +{ +char filename[12]; +int rval; + + if (check_args(argc,1)==0) + { + Convert83tortfslite83(filename, *argv++); + rval=rtfsltest_file_fill_drive((unsigned char *)filename); + check_return(rval,RTFSL_ERROR_DISK_FULL); + } + return 0; +} + +static int dortfslite_append(int argc,char **argv) +{ +char filename[12]; +int nlongs; +int gap; +int rval; + + if (check_args(argc,3)==0) + { + Convert83tortfslite83(filename, *argv++); + nlongs = atol(*argv++); + gap = atol(*argv++); + rval=rtfsltest_file_sequential_write((unsigned char *)filename, 1, gap, nlongs, 1); + check_return(rval,0); + } + return 0; +} + + +static int dortfslite_check(int argc,char **argv) +{ +char filename[12]; +int rval; + if (check_args(argc,1)==0) + { + Convert83tortfslite83(filename, *argv++); + rval=rtfsltest_file_sequential_read((unsigned char *)filename); + check_return(rval,0); + } + return 0; +} +static int dortfslite_randread(int argc,char **argv) +{ +char filename[12]; +int rval; + if (check_args(argc,1)==0) + { + Convert83tortfslite83(filename, *argv++); + rval=rtfsltest_file_random_read((unsigned char *)filename); + check_return(rval,0); + } + return 0; +} +static int dortfslite_randwrite(int argc,char **argv) +{ +char filename[12]; +int rval; + if (check_args(argc,1)==0) + { + Convert83tortfslite83(filename, *argv++); + rval=rtfsltest_file_random_write((unsigned char *)filename); + check_return(rval,0); + } + return 0; +} + +static int dortfslite_fsstart(int argc,char **argv) +{ +int rval; + rval=rtfslfs_start(); + check_return(rval,0); + return 0; +} +static int dortfslite_fsstop(int argc,char **argv) +{ +int rval; + rval=rtfsl_diskopen(); + check_return(rval,0); + return 0; +} +static int dortfslite_fssync(int argc,char **argv) +{ +int rval; + rval=rtfslfs_sync(); + check_return(rval,0); + return 0; +} +static int dortfslite_fsflush(int argc,char **argv) +{ +int rval; + rval=rtfslfs_flush(); + check_return(rval,0); + return 0; +} +static int dortfslite_fsrestore(int argc,char **argv) +{ +int rval; + rval=rtfslfs_restore(); + check_return(rval,0); + return 0; +} + +const char *err_strings[] = { +"RTFSL_ERROR_NONE", +"RTFSL_ERROR_ARGS", +"RTFSL_ERROR_CONSISTENCY", +"RTFSL_ERROR_DIR_FULL", +"RTFSL_ERROR_DISK_FULL", +"RTFSL_ERROR_FDALLOC", +"RTFSL_ERROR_FORMAT", +"RTFSL_ERROR_JOURNAL_FULL", +"RTFSL_ERROR_JOURNAL_NONE", +"RTFSL_ERROR_NOTFOUND", +"RTFSL_ERROR_PATH", +"RTFSL_ERROR_EXIST", +"RTFSL_ERROR_ENOTEMPTY", +"RTFSL_ERROR_TEST"}; +static void check_return(int rval,int shouldbe) +{ + if (rval!=shouldbe) + { + if (rval < 0) + { + PRINTF("Returned: %s ", err_strings[-rval]); + } + else + { + PRINTF("Returned: %d ", rval); + } + PRINTF(", should be %d\n", shouldbe); + } +} + +static int check_args(int argc,int shouldbe) +{ + if (argc!=shouldbe) + { + PRINTF("Please pass %d arguments\n", shouldbe); + return -1; + } + return 0; +} + +/* ================================ */ +static void GetUserInput() +{ + rtp_term_gets(lite_term_buffer); +} + +static char *gnext(char *p) /*__fn__*/ +{ + while (*p==' ') p++; /* GET RID OF LEADING SPACES */ + while (*p) + { + if (*p==' ') + { + *p=0; + p++; + break; + } + p++; + } + while (*p==' ') p++; /* GET RID OF Trailing SPACES */ + if (*p==0) + return(0); + return (p); +} +/* ******************************************************************** */ +/* get next command; process history log */ +static void prompt(void) +{ + int i; + char *cmd,*p; + char *args[4]; + int argc=0; + + if (lite_shell_help) + { + for (i=0; command_list[i].cmd;i++) + { + PRINTF("%s\n",command_list[i].helpstr); + } + lite_shell_help=0; + } + argc = 0; + /* "CMD>" */ + PRINTF("CMD>"); + GetUserInput(); + + p = cmd = &lite_term_buffer[0]; + p = gnext(p); + /* Keep grabbing tokens until there are none left */ + while (p) + { + args[argc++] = p; + p = gnext(p); + } + + for (i=0; command_list[i].cmd;i++) + { + if (strcmp(command_list[i].cmd, cmd)==0) + { + if (command_list[i].proc) + command_list[i].proc(argc,args); + break; + } + } + } + + +static unsigned char * Convert83tortfslite83(char *to, char *from) +{ +int i; +char *r=to; + for (i =0; i < 8; i++) + { + if (*from==0||*from=='.') + *to++=' '; + else + *to++=(char)toupper(*from++); + } + if (*from=='.') + from++; + for (i =0; i < 3; i++) + { + if (*from==0) + *to++=' '; + else + *to++=(char)toupper(*from++); + } + *to=0; + return (unsigned char *)r; +} diff --git a/rtfslitetests.h b/rtfslitetests.h new file mode 100644 index 0000000..7fa8f3d --- /dev/null +++ b/rtfslitetests.h @@ -0,0 +1,24 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + + +extern unsigned char test_buffer[RTFSL_CFG_MAXBLOCKSIZE]; +int ut_fill_directory(int leave_n_free); +void ut_unfill_directory(unsigned char *name); +int ut_release_fragments(int file_fraglen, int gap_fraglen, int numfrags, unsigned long *fragrecord/*[numfrags]*/); +int ut_create_fragments(int file_fraglen, int gap_fraglen, int numfrags, unsigned long *fragrecord/*[numfrags]*/); + +int rtfsltest_file_sequential_write(unsigned char*filename, int file_fraglen, int gap_fraglen, int numlongs, int test_append); +int rtfsltest_file_fill_drive(unsigned char*filename); +int rtfsltest_file_sequential_read(unsigned char*filename); +int rtfsltest_file_random_read(unsigned char*filename); +int rtfsltest_file_random_write(unsigned char*filename); + +#include +#define PRINTF printf diff --git a/rtfslmkdir.c b/rtfslmkdir.c new file mode 100644 index 0000000..d06ed4f --- /dev/null +++ b/rtfslmkdir.c @@ -0,0 +1,65 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + +#include "rtfslite.h" + + +int rtfsl_mkdir(unsigned char *name) /*__apifn__*/ +{ +struct rtfsl_dosinode dotentries[3]; +int fd,rval; + + rval=rtfsl_create(name,0); + if (rval==0) + { + rval= rtfsl_open(name); + if (rval >= 0) + { + fd=rval; + rval = rtfsl_write(fd,0,rtfsl.current_dr.bytespcluster); + if (rval<0) + return rval; + rtfsl_lseek(fd, 0, PSEEK_SET); + rval=rtfsl_clzero(rtfsl.rtfsl_files[fd].cluster_segment_array[0][0]); + if (rval<0) + return rval; + ANSImemcpy(&dotentries[0],&rtfsl.rtfsl_files[fd].dos_inode,sizeof(rtfsl.rtfsl_files[fd].dos_inode)); + ANSImemcpy(&dotentries[1],&rtfsl.rtfsl_files[fd].dos_inode,sizeof(rtfsl.rtfsl_files[fd].dos_inode)); + dotentries[0].fattribute=ADIRENT; + dotentries[1].fattribute=ADIRENT; + ANSImemcpy(&dotentries[0].fname,dotname,11); + ANSImemcpy(&dotentries[1].fname,dotdotname,11); + memset(&dotentries[2].fname,0,11); + dotentries[1].fsize = 0; + dotentries[0].fsize = 0; +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) + if (rtfsl.rtfsl_current_failsafe_context) + rtfsl.rtfsl_current_failsafe_context->flags |= RTFSLFS_WRITE_DIRENTRY; +#endif + + + /* Instructs the write operation to poulate "." with "self" and ".." with parent */ + rtfsl.rtfsl_files[fd].rtfsl_file_flags|=TRTFSFILE_ISMKDIR; + rval = rtfsl_write(fd, (unsigned char*)dotentries,96); + rtfsl.rtfsl_files[fd].rtfsl_file_flags&=~TRTFSFILE_ISMKDIR; +#if (RTFSL_INCLUDE_FAILSAFE_SUPPORT) + if (rtfsl.rtfsl_current_failsafe_context) + rtfsl.rtfsl_current_failsafe_context->flags &= ~RTFSLFS_WRITE_DIRENTRY; +#endif + if (rval > 0) + { + rtfsl.rtfsl_files[fd].dos_inode.fattribute=ADIRENT; + rtfsl.rtfsl_files[fd].dos_inode.fsize=0; + rval=rtfsl_flush(fd); + } + rtfsl.rtfsl_files[fd].rtfsl_file_flags=0; /* Deallocates the file */ + } + } + return rval; +} diff --git a/rtfslopenpath.c b/rtfslopenpath.c new file mode 100644 index 0000000..ed4a27b --- /dev/null +++ b/rtfslopenpath.c @@ -0,0 +1,85 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + +#include "rtfslite.h" +struct rtfsl_open_path_structure +{ + int current_index; + unsigned char **pathlist; + unsigned char *pathentry; +}; + +static int open_path_callback(struct rtfsl_file const *pcurrent_entry_file, void *puser_data) +{ + if (pcurrent_entry_file->rtfsl_direntry_type==RTFSL_ENTRY_TYPE_DIRECTORY || pcurrent_entry_file->rtfsl_direntry_type==RTFSL_ENTRY_TYPE_FILE) + { + struct rtfsl_open_path_structure *open_path_structure = (struct rtfsl_open_path_structure *) puser_data; + unsigned char *p=open_path_structure->pathentry; + if (!p) + p=open_path_structure->pathlist[open_path_structure->current_index]; + if (p&&ANSImemcmp(pcurrent_entry_file->dos_inode.fname,p,11)==0) + { + open_path_structure->current_index+=1; + return 1; + } + } + return 0; /* Continue */ +} + +int rtfsl_open_path(unsigned char **pathlist,unsigned char *pentryname, struct rtfsl_file *directory_file, struct rtfsl_file *ptarget_file) +{ +struct rtfsl_open_path_structure open_path_structure; +int rval; + open_path_structure.current_index=0; + open_path_structure.pathlist=pathlist; + open_path_structure.pathentry=0; + ANSImemset(directory_file,0,sizeof(*directory_file)); + rval=rtfsl_root_finode_open(directory_file); + if (rval<0) + return rval; +#if(RTFSL_INCLUDE_SUBDIRECTORIES) + while (pathlist && pathlist[open_path_structure.current_index]) + { + ANSImemset(ptarget_file,0,sizeof(*ptarget_file)); + if (directory_file->rtfsl_direntry_type!=RTFSL_ENTRY_TYPE_DIRECTORY) + return RTFSL_ERROR_PATH; + rval = rtfsl_enumerate_directory(directory_file,ptarget_file, open_path_callback,(void *) &open_path_structure); + if (rval < 0) + return rval; + if (rval==1) + { + ANSImemcpy(directory_file,ptarget_file,sizeof(*ptarget_file)); + rval=rtfsl_finode_open(directory_file); + if (rval<0) + return rval; + if (!pathlist[open_path_structure.current_index]) + break; + } + else + return RTFSL_ERROR_PATH; + } +#endif + if (!pentryname) + { + ANSImemcpy(ptarget_file,directory_file,sizeof(*ptarget_file)); + rval=0; + } + else if (directory_file->rtfsl_direntry_type==RTFSL_ENTRY_TYPE_DIRECTORY) + { + open_path_structure.pathentry=pentryname; + rval=RTFSL_ERROR_NOTFOUND; + if (rtfsl_enumerate_directory(directory_file,ptarget_file, open_path_callback,(void *) &open_path_structure)==1) + { + rval=rtfsl_finode_open(ptarget_file); + } + } + else + rval=RTFSL_ERROR_PATH; + return rval; +} diff --git a/rtfslrename.c b/rtfslrename.c new file mode 100644 index 0000000..7e7dd80 --- /dev/null +++ b/rtfslrename.c @@ -0,0 +1,38 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + +#include "rtfslite.h" + + + +int rtfsl_rename(unsigned char *name, unsigned char *newname) +{ +struct rtfsl_file scratch_dir_file; +int fd,rval; + fd = rtfsl_alloc_fd(); + if (fd>=0) + { + rval=rtfsl_open_path(rtfsl.current_dr.pathnamearray,newname,&scratch_dir_file, &rtfsl.rtfsl_files[fd]); + if (rval==0) + rval=RTFSL_ERROR_EXIST; + else + { + rval=rtfsl_open_path(rtfsl.current_dr.pathnamearray,name,&scratch_dir_file, &rtfsl.rtfsl_files[fd]); + if (rval==0) + { + ANSImemcpy(rtfsl.rtfsl_files[fd].dos_inode.fname,newname,11); + rval=rtfsl_flush(fd); + } + } + rtfsl.rtfsl_files[fd].rtfsl_file_flags=0; /* Deallocates the file */ + } + else + rval=fd; + return rval; +} diff --git a/rtfslrmdir.c b/rtfslrmdir.c new file mode 100644 index 0000000..707179b --- /dev/null +++ b/rtfslrmdir.c @@ -0,0 +1,51 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + +#include "rtfslite.h" + + + +struct rtfsl_rmdir_structure +{ + unsigned long file_pointer; +}; +static int rmdir_callback(struct rtfsl_file const *pcurrent_entry_file, void *puser_data) +{ +struct rtfsl_rmdir_structure *prmdir_structure=(struct rtfsl_rmdir_structure *) puser_data; + + if (prmdir_structure->file_pointer>=64 && (pcurrent_entry_file->rtfsl_direntry_type&RTFSL_ENTRY_AVAILABLE)==0) + { + return RTFSL_ERROR_ENOTEMPTY; + } + prmdir_structure->file_pointer+=32; + return 0; /* Continue */ +} + +int rtfsl_rmdir(unsigned char *name) /*__apifn__*/ +{ +int fd,rval; +struct rtfsl_rmdir_structure rmdir_structure; +struct rtfsl_file new_directory_file; + + fd= rtfsl_dir_open(name); + if (fd>=0) + { + rmdir_structure.file_pointer=0; + /* returns RTFSL_ERROR_ENOTEMPTY if the directory contains any files or subdirectories */ + rval = rtfsl_enumerate_directory(&rtfsl.rtfsl_files[fd],&new_directory_file, rmdir_callback,(void *) &rmdir_structure); + if(rval>=0) + { + rtfsl.rtfsl_files[fd].rtfsl_file_flags=0; /* Deallocates the file */ + rval=_rtfsl_delete(name,ADIRENT); + } + } + else + rval=fd; + return rval; +} diff --git a/rtfslsystem.c b/rtfslsystem.c new file mode 100644 index 0000000..5f43e66 --- /dev/null +++ b/rtfslsystem.c @@ -0,0 +1,200 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ +#ifdef _MSC_VER +#include +#endif +#ifdef __linux__ +#include +#include +#include +int raw_dev_fd; + +int rtfsl_open_disk(char *raw_dev_name) +{ + raw_dev_fd = open(raw_dev_name,O_RDWR); + return raw_dev_fd; +} +static int rtfsl_dev_seek(unsigned long sector) +{ +unsigned long hi, lo; +unsigned long long lhi, llo, result,llbytes; + + llbytes = (unsigned long long) sector; + llbytes *= 512; + + lhi = llbytes >> 32; + llo = llbytes & 0xffffffff; + lo = (unsigned long) llo; + hi = (unsigned long) lhi; + + if (lseek64(raw_dev_fd, llbytes, SEEK_SET)!= llbytes) + return(-1); + + return(0); +} + +#endif +//#include "rtfs.h" +#ifdef RTFS_MAJOR_VERSION +DDRIVE *rtfsl_p_drive; +#endif + +#if (INCLUDE_SDCARD) +int SDCARD_blkmedia_io(void *devhandle, void *pdrive, unsigned long sector, void *buffer, unsigned long count, int reading); +#endif + +int rtfsl_read_sectors(unsigned long sector, int count, unsigned char *buffer) /*__apifn__*/ +{ +#ifdef __linux__ +unsigned long nbytes, nread; + if (rtfsl_dev_seek(sector)==0) + { + nbytes = (unsigned long)count; + nbytes *= 512; + + if ((nread = read(raw_dev_fd,buffer,nbytes)) == nbytes) + return 0; + } + return -1; +#endif +#ifdef RTFS_MAJOR_VERSION + return raw_devio_xfer(rtfsl_p_drive, (sector), buffer,1, TRUE, TRUE)?0:-1000; +#endif +#if (INCLUDE_SDCARD) + return SDCARD_blkmedia_io( (void *) 0, (void *) 0, sector, buffer, count, 1); +#endif + return -1; // RTFSL_ERROR_IO_ERROR; +} +int rtfsl_write_sectors(unsigned long sector, int count, unsigned char *buffer) /*__apifn__*/ +{ +#ifdef __linux__ +unsigned long nbytes, nwr; + if (rtfsl_dev_seek(sector)==0) + { + nbytes = (unsigned long)count; + nbytes *= 512; + + if ((nwr = write(raw_dev_fd,buffer,nbytes)) == nbytes) + return 0; + } + return -1; +#endif +#ifdef RTFS_MAJOR_VERSION + return raw_devio_xfer(rtfsl_p_drive, (sector), buffer,1, TRUE, FALSE)?0:-1000; +#endif +#if (INCLUDE_SDCARD) + return SDCARD_blkmedia_io( (void *) 0, (void *) 0, sector, buffer, count, 0); +#endif + return -1; // RTFSL_ERROR_IO_ERROR; +} + +/* + When the system needs to date stamp a file it will call this routine + to get the current time and date. YOU must modify the shipped routine + to support your hardware's time and date routines. +*/ + +void rtfsl_get_system_date(unsigned short *time, unsigned short *date) /*__apifn__*/ +{ +#ifdef _MSC_VER + /* Windows runtime provides rotuines specifically for this purpose */ + SYSTEMTIME systemtime; + FILETIME filetime; + + GetLocalTime(&systemtime); + SystemTimeToFileTime(&systemtime, &filetime); + FileTimeToDosDateTime(&filetime, date, time); +#else + +#define USE_ANSI_TIME 0 /* Enable if your runtime environment supports ansi time functions */ +#if (USE_ANSI_TIME) + { /* Use ansi time functions. */ + struct tm *timeptr; + time_t timer; + unsigned short year; /* relative to 1980 */ + unsigned short month; /* 1 - 12 */ + unsigned short day; /* 1 - 31 */ + unsigned short hour; + unsigned short minute; + unsigned short sec; /* Note: seconds are 2 second/per. ie 3 == 6 seconds */ + + time(&timer); + timeptr = localtime(&timer); + + hour = (unsigned short) timeptr->tm_hour; + minute = (unsigned short) timeptr->tm_min; + sec = (unsigned short) (timeptr->tm_sec/2); + /* Date comes back relative to 1900 (eg 93). The pc wants it relative to + 1980. so subtract 80 */ + year = (unsigned short) (timeptr->tm_year-80); + month = (unsigned short) (timeptr->tm_mon+1); + day = (unsigned short) timeptr->tm_mday; + *time = (unsigned short) ( (hour << 11) | (minute << 5) | sec); + *date = (unsigned short) ( (year << 9) | (month << 5) | day); + } +#else /* In not windows and not using ansi time functions use hardwired values. */ + /* Modify this code if you have a clock calendar chip and can retrieve the values from that device instead */ +#define hour 19 /* 7:37:28 PM */ +#define minute 37 +#define sec 14 + /* 3-28-2008 */ +#define year 18 /* relative to 1980 */ +#define month 3 /* 1 - 12 */ +#define day 28 /* 1 - 31 */ + *time = (unsigned short) ( (hour << 11) | (minute << 5) | sec); + *date = (unsigned short) ( (year << 9) | (month << 5) | day); +#endif + +#endif /* #ifdef WINDOWS #else */ +} + + +/* Convert a 32 bit intel item to a portable 32 bit */ +unsigned long to_ULONG (unsigned char *from) /*__fn__*/ +{ + unsigned long res; + unsigned long t; + t = ((unsigned long) *(from + 3)) & 0xff; + res = (t << 24); + t = ((unsigned long) *(from + 2)) & 0xff; + res |= (t << 16); + t = ((unsigned long) *(from + 1)) & 0xff; + res |= (t << 8); + t = ((unsigned long) *from) & 0xff; + res |= t; + return(res); +} + +/* Convert a 16 bit intel item to a portable 16 bit */ +unsigned short to_USHORT (unsigned char *from) /*__fn__*/ +{ + unsigned short nres; + unsigned short t; + t = (unsigned short) (((unsigned short) *(from + 1)) & 0xff); + nres = (unsigned short) (t << 8); + t = (unsigned short) (((unsigned short) *from) & 0xff); + nres |= t; + return(nres); +} + +/* Convert a portable 16 bit to a 16 bit intel item */ +void fr_USHORT (unsigned char *to, unsigned short from) /*__fn__*/ +{ + *to = (unsigned char) (from & 0x00ff); + *(to + 1) = (unsigned char) ((from >> 8) & 0x00ff); +} + +/* Convert a portable 32 bit to a 32 bit intel item */ +void fr_ULONG (unsigned char *to, unsigned long from) /*__fn__*/ +{ + *to = (unsigned char) (from & 0xff); + *(to + 1) = (unsigned char) ((from >> 8) & 0xff); + *(to + 2) = (unsigned char) ((from >> 16) & 0xff); + *(to + 3) = (unsigned char) ((from >> 24) & 0xff); +} diff --git a/rtfstlitefileload.c b/rtfstlitefileload.c new file mode 100644 index 0000000..9438744 --- /dev/null +++ b/rtfstlitefileload.c @@ -0,0 +1,96 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + +#include "rtfslite.h" + + +struct rtfst_load_structure { + unsigned char *bootfile_name; + unsigned long load_count; + unsigned char *load_address; +}; + +void BootProgressReport(int percent); +static unsigned long file_load_callback (struct rtfsl_file const *pfile, unsigned long start_sector, unsigned long nbytes, void *puser_data) +{ + struct rtfst_load_structure *pload_structure = (struct rtfst_load_structure *) puser_data; + unsigned long sector,nbytes_left,bytes_read; + unsigned char *load_address; + int rval,bytes_to_skip,percent_reported; + int n_sectors; + int n_bytes; + static int done_so_far=0;; + + load_address = pload_structure->load_address + pfile->file_pointer; + pload_structure->load_count += nbytes; + bytes_read=0; + percent_reported = 0; +#define BYTES_TO_SKIP (320*240*8) /* 2 frame buffers worth */ +//#define BYTES_TO_SKIP 0 + if (done_so_far==0) + bytes_to_skip=BYTES_TO_SKIP; + else + bytes_to_skip=0; + n_sectors=1; + n_bytes = rtfsl.current_dr.bytespsector; + for(sector=start_sector,nbytes_left=nbytes;nbytes_left;sector+=n_sectors,load_address+=n_bytes) + { + int per_cent = ((nbytes-nbytes_left)*100)/nbytes; + done_so_far += bytes_read; + if (per_cent >= (percent_reported+10)) + { + BootProgressReport(per_cent); + percent_reported = per_cent; + } + if (bytes_read <= bytes_to_skip) + { + n_sectors=1; + n_bytes = rtfsl.current_dr.bytespsector; + rval=0; + } + else + { +#define DEFAULT_SIZE_SECTORS 32 + n_sectors = DEFAULT_SIZE_SECTORS; + n_bytes = n_sectors*rtfsl.current_dr.bytespsector; + if (n_bytes > nbytes_left) + { + n_bytes=nbytes_left; + n_sectors=(n_bytes+rtfsl.current_dr.bytespsector-1)/rtfsl.current_dr.bytespsector; + if (!n_sectors) + break; + } + rval=rtfsl_read_sectors(rtfsl.current_dr.partition_base+sector, n_sectors, load_address); + } + bytes_read += n_bytes; + + if (rval<0) + return rval; + if (nbytes_left < rtfsl.current_dr.bytespsector) + nbytes_left = 0; + else + nbytes_left-=n_bytes; + } + return nbytes; +} + +int rtfsl_load_file(unsigned char *filename, unsigned long load_address) /*__apifn__*/ +{ +struct rtfsl_file root_file,current_entry_file; +struct rtfst_load_structure loadstruct; +int rval; + ANSImemset(&loadstruct,0,sizeof(loadstruct)); + loadstruct.bootfile_name = filename; + loadstruct.load_address=(unsigned char *)load_address; + + rval=rtfsl_open_path(rtfsl.current_dr.pathnamearray,filename,&root_file, ¤t_entry_file); + if (rval== 0) + rval=rtfsl_enumerate_file(¤t_entry_file,file_load_callback, (void *) &loadstruct); + return rval; +} diff --git a/rtfstlitetestfileio.c b/rtfstlitetestfileio.c new file mode 100644 index 0000000..3180019 --- /dev/null +++ b/rtfstlitetestfileio.c @@ -0,0 +1,322 @@ +/* +* EBS - RTFS (Real Time File Manager) +* +* Copyright EBS Inc. 1987-2012 +* All rights reserved. +* This code may not be redistributed in source or linkable object form +* without the consent of its author. +*/ + +#include "rtfslite.h" +#include "rtfslitetests.h" +#include "stdlib.h" + +#define MAXTESTFRAGS 128 +#if (RTFSL_INCLUDE_WRITE_SUPPORT) +int rtfsltest_file_fill_drive(unsigned char*filename) +{ +int rval; +unsigned char filename_indexed[12]; +char index = 'A'; +int pos=8; + strcpy((char*)filename_indexed,(char*)filename); + for(;;) + { + filename_indexed[pos] = index; + if (index == 'Z') + { + pos += 1; + index = 'A'; + } + index++; + + rval=rtfsl_create(filename_indexed,0); + if (rval==0) + { + int fd; + unsigned long i; + fd = rtfsl_open(filename_indexed); + if(fd<0) + { + rval=fd; + break; + } + else + { + for(i=0;i<1024*1024*1024;i+=1024*1024) + { + if ((i % 1024*1024*4)==0) + { + PRINTF("Fill : %8.8ld\r", i); + } + rval=rtfsl_write(fd,0,1024*1024); + if (rval!=1024*1024) + { + for(;i<1024*1024*1024;i+=512) + { + PRINTF("Fill : %8.8ld\r", i); + rval=rtfsl_write(fd,0,512); + if (rval!=512) + { + break; + } + } + break; + } + } + rtfsl_flush(fd); + rtfsl_close(fd); + } + } + if (rval!=512) + break; + } + rtfsl_flush_all_buffers(); + + return rval; +} +int rtfsltest_file_sequential_write(unsigned char*filename, int file_fraglen, int gap_fraglen, int numlongs, int test_append) +{ +int rval,numfrags; +struct rtfsl_statstructure statstruct; +unsigned long fragrecord[MAXTESTFRAGS]; + + numfrags=((numlongs*4)+rtfsl.current_dr.bytespcluster-1)/rtfsl.current_dr.bytespcluster; + rval=rtfsl_create(filename,0); + if (rval==0) + { + int fd; + unsigned long i; + if (gap_fraglen) + { + rval=ut_create_fragments(file_fraglen, gap_fraglen, numfrags, fragrecord); + if (rval<0) + return rval; + } + fd = rtfsl_open(filename); + if(fd<0) + rval=fd; + else + for(i=0;i<(unsigned long)numlongs;i++) + { + rval=rtfsl_write(fd, (unsigned char*)&i,4); + if (rval!= 4) + { + break; + } + if (test_append && (i&0x3ff)==0) + { + rtfsl_flush(fd); + rtfsl_close(fd); + fd = rtfsl_open(filename); + if (fd<0) + rval=fd; + else + rval=(int)rtfsl_lseek(fd,0,PSEEK_END); + if (rval< 0) + { + break; + } + } + } + if(rval>=0) + { + rtfsl_fstat(fd,&statstruct); + if (statstruct.st_size!=(unsigned long)numlongs*4) + rval=RTFSL_ERROR_TEST; + else + rval=0; + } + if(rval>=0) + rval=rtfsl_flush(fd); + rtfsl_close(fd); + if (gap_fraglen) + { + rval=ut_release_fragments(file_fraglen, gap_fraglen, numfrags, fragrecord); + if (rval<0) + return rval; + } + } + return rval; +} +#endif +int rtfsltest_file_sequential_read(unsigned char*filename) +{ +int fd,rval; +struct rtfsl_statstructure statstruct; + + + fd = rtfsl_open((unsigned char*)filename); + if (fd>=0) + { + unsigned long i,j; + rtfsl_fstat(fd,&statstruct); + for(i=0;i<(unsigned long)statstruct.st_size/4;i++) + { + rval=rtfsl_read(fd, (unsigned char*)&j,4); + if (rval!= 4) + { + PRINTF("Seq: Read Failed at offset == %lu \n",i*4);\ + return rval; + } + if (j != i) + { + PRINTF("Seq: Compare falied at offset == %lu \n",i); + return RTFSL_ERROR_TEST; + } + } + } + return 0; +} +int rtfsltest_file_random_read(unsigned char*filename) +{ +struct rtfsl_statstructure statstruct; +int fd; +unsigned long seekoffset; +unsigned long r; + + fd = rtfsl_open(filename); + if(fd<0) + return fd; + rtfsl_fstat(fd,&statstruct); + PRINTF("Seek read test. Takes a long time to complete \n"); + for (seekoffset=statstruct.st_size-1;seekoffset>0;seekoffset--) + { + rtfsl_lseek(fd,0,PSEEK_SET); + rtfsl_read(fd,test_buffer,4); + rtfsl_lseek(fd,(seekoffset/4)*4,PSEEK_SET); + rtfsl_read(fd,(unsigned char *)&r,4); + if (r!= seekoffset/4) + { + PRINTF("\nreade seek test compare error at unsigned long offset %lu\n",seekoffset/4); + return RTFSL_ERROR_TEST; + } + } + rtfsl_close(fd); + return 0; +} +#if (RTFSL_INCLUDE_WRITE_SUPPORT) +int rtfsltest_file_random_write(unsigned char*filename) +{ +struct rtfsl_statstructure statstruct; +int fd; +unsigned long seekoffset; +unsigned long l,r; +unsigned char *pl = (unsigned char *)&l; + + fd = rtfsl_open(filename); + if(fd<0) + return fd; + rtfsl_fstat(fd,&statstruct); + PRINTF("Seek write test. Takes a long time to complete \n"); + for (seekoffset=statstruct.st_size-1;seekoffset>0;seekoffset--) + { + if ((seekoffset & 0xf) == 0) + { + PRINTF("seek write test pass %8.8lu\r", seekoffset); + } + /* Read from the beginning of file to be sure we are seeking */ + rtfsl_lseek(fd,0,PSEEK_SET); + rtfsl_read(fd,test_buffer,4); + /* Write one byte of the current unsigned long flipped */ + rtfsl_lseek(fd,seekoffset,PSEEK_SET); + l=(seekoffset/4); + pl = (unsigned char *)&l; + { + *(pl+(seekoffset&0x3)) = ~*(pl+(seekoffset&0x3)); + rtfsl_write(fd,pl+(seekoffset&0x3),1); + } + /* Read from the beginning of file to be sure we are seeking */ + rtfsl_lseek(fd,0,PSEEK_SET); + rtfsl_read(fd,test_buffer,4); + /* Read the byte and make sure it's what we wrote */ + rtfsl_lseek(fd,seekoffset,PSEEK_SET); + rtfsl_read(fd,test_buffer,1); + if (test_buffer[0]!=*(pl+(seekoffset&0x3))) + { + PRINTF("\nWrite seek test compare error at byte offset %lu\n",seekoffset); + return RTFSL_ERROR_TEST; + } + /* toggle it again and write it back */ + rtfsl_lseek(fd,seekoffset,PSEEK_SET); + *(pl+(seekoffset&0x3)) = ~*(pl+(seekoffset&0x3)); + rtfsl_write(fd,pl+(seekoffset&0x3),1); + + /* Read from the beginning of file to be sure we are seeking */ + rtfsl_lseek(fd,0,PSEEK_SET); + rtfsl_read(fd,test_buffer,4); + rtfsl_lseek(fd,(seekoffset/4)*4,PSEEK_SET); + rtfsl_read(fd,(unsigned char *)&r,4); + if (r!= seekoffset/4) + { + PRINTF("\nWrite seek test compare error at unsigned long offset %lu\n",seekoffset/4); + return RTFSL_ERROR_TEST; + } + } + rtfsl_flush(fd); + rtfsl_close(fd); + return 0; +} +#endif + +#if (0) + +#if (DOBOOTFILEEST) + { + int fd; + void * load_address = malloc(1000000); + rtfsl_load_file(&tdrive,(unsigned char *)BOOTFILENAME, (unsigned long) load_address); + #if (DOFILIOREADAPITEST) + fd=rtfsl_open((byte*)BOOTFILENAME); + if (fd>=0) + { + int nread; + unsigned long total=0; + unsigned char *loadimage=(unsigned char *)load_address; + rtfsl_fstat(fd,&statstruct); + do + { + nread=rtfsl_read(fd,test_buffer,tdrive.bytespsector); + if (nread>0) + { + total+=nread; + if (ANSImemcmp(test_buffer, loadimage, nread)!=0) + { + PRINTF("Compare failed\n"); + } + loadimage += nread; + } + } while (nread > 0); + if (statstruct.st_size!=total) + { + PRINTF("filesize == %lu total read == %lu\n",statstruct.st_size,total); + } + for (seekoffset=1;seekoffset<7;seekoffset++) + { + for (seekpointer=0; seekpointerrtfsl_direntry_type==RTFSL_ENTRY_TYPE_FILE) + { + PRINTF("Found file %8.8s.%3.3s\n",pcurrent_entry_file->dos_inode.fname,pcurrent_entry_file->dos_inode.fext); + return 2; + } + else if (pcurrent_entry_file->rtfsl_direntry_type==RTFSL_ENTRY_TYPE_EOF) + return 1; + else if (pcurrent_entry_file->rtfsl_direntry_type==RTFSL_ENTRY_TYPE_LFN) + ; + else if (pcurrent_entry_file->rtfsl_direntry_type==RTFSL_ENTRY_TYPE_VOLUME) + ; + else if (pcurrent_entry_file->rtfsl_direntry_type==RTFSL_ENTRY_TYPE_DIRECTORY) + { + PRINTF("Found dir %8.8s.%3.3s\n",pcurrent_entry_file->dos_inode.fname,pcurrent_entry_file->dos_inode.fext); + return 2; + } + } + return 0; /* Continue */ +} +void test_rtfsl_lite(void) +{ + unsigned long fragrecord[32]; + struct rtfsl_statstructure statstruct; + int rval; + struct rtfsl_file root_file; + rtfsl_diskopen(); + +#if (DOFAILSAFEOPENTEST&&RTFSL_INCLUDE_FAILSAFE_SUPPORT) + rtfsl.rtfsl_current_failsafe_context=&rtfsl.rtfsl_failsafe_context; + ANSImemset(rtfsl.rtfsl_current_failsafe_context,0,sizeof(*rtfsl.rtfsl_current_failsafe_context)); + rtfsl.rtfsl_current_failsafe_context->journal_buffer=rtfsl.rtfslfs_sector_buffer; + rtfsl.rtfsl_current_failsafe_context->journal_buffer_size=RTFSL_CFG_FSBUFFERSIZEBYTES; + rtfslfs_start(); +#endif + +#if (DOFAILSAFERESTORETEST&&RTFSL_INCLUDE_FAILSAFE_SUPPORT) + rtfslfs_restore(); + rtfsl_setpath(0); + rtfsl_mkdir((unsigned char*)"AFTERRESTORE"); + return; +#endif +#if (DOFATSCANTEST) + { + unsigned long maxfindex; + unsigned long cluster, next_cluster; + long rval; +#ifdef RTFSL_MAJOR_VERSION + maxfindex=pdr->drive_info.maxfindex; +#else + maxfindex=pdr->maxfindex; +#endif + + for (cluster=2;cluster< maxfindex;cluster++) + { + next_cluster=cluster+1; + rval=fatop_buff_get_frag(&tdrive, cluster|RTFSL_WRITE_CLUSTER, &next_cluster, 1); + next_cluster=0; + rval=fatop_buff_get_frag(&tdrive, cluster, &next_cluster, 1); + if (next_cluster != cluster+1) + { + PRINTF("error: Cluster %ld: should be %X but returned %X\n", cluster, cluster+1,next_cluster); + } + } + { + unsigned long cluster_segment_array[32][2]; + unsigned long chain_length_clusters,start_next_segment; + int i,num_segments; + + num_segments = rtfsl_load_cluster_chain(&tdrive, 2, &chain_length_clusters, &start_next_segment, cluster_segment_array, 32); + + PRINTF(" = %d\n", num_segments); + for (i = 0; i < num_segments; i++) + { + PRINTF("%d: (%ld) - (%ld) \n", i, cluster_segment_array[i][0],cluster_segment_array[i][1]); + } + + } + } +#endif +#if (RTFSL_INCLUDE_WRITE_SUPPORT&&RTFSL_INCLUDE_SUBDIRECTORIES&&DOSETPATHTEST) + { + if (rtfsl_mkdir(path[0])<0) + { + PRINTF("First mkdir failed-assuming path exists\n"); + } + path[1]=0; /* Set default path one layer deep */ + rtfsl_setpath(path); + /* Set up a scenario so the directory entries we create are fragmented - make 4 fragments but test only uses 2 */ +#if (DIRECTORY_GAP_FRAGMENT_LENGTH&&DOMKDIRTEST) + ut_create_fragments(DIRECTORY_FRAGMENT_LENGTH, DIRECTORY_GAP_FRAGMENT_LENGTH, 4, fragrecord/*[numfrags]*/); +#endif + if (rtfsl_mkdir(path[0])<0) + { + PRINTF("Second mkdir failed-assuming path exists\n"); + } + path[1]=path[0]; /* Path should be two deep now */ + } +#endif + +#if (RTFSL_INCLUDE_WRITE_SUPPORT&&DOMKDIRTEST&&RTFSL_INCLUDE_SUBDIRECTORIES&&DOSETPATHTEST&&DOMULTICHAINSUBDIRECTORYTEST) + ut_fill_directory(0); +#endif + +#if (RTFSL_INCLUDE_WRITE_SUPPORT&&RTFSL_INCLUDE_SUBDIRECTORIES&&DOMKDIRTEST) + if (rtfsl_mkdir((unsigned char*)"MKDIR MDX")<0) + { + PRINTF("mkdir test failed\n"); + return; + } + +#endif +#if (RTFSL_INCLUDE_WRITE_SUPPORT&&DOMKDIRTEST&&DIRECTORY_GAP_FRAGMENT_LENGTH&&RTFSL_INCLUDE_SUBDIRECTORIES&&DOSETPATHTEST&&DOMULTICHAINSUBDIRECTORYTEST) + /* Release the clusters we allocate so the directory entries we create were fragmented */ + ut_release_fragments(DIRECTORY_FRAGMENT_LENGTH, DIRECTORY_GAP_FRAGMENT_LENGTH, 4, fragrecord/*[numfrags]*/); +#endif + +#if (DOROOTSCANTEST) + { + struct rtfsl_file current_entry_file; + if (rtfsl_root_finode_open(&root_file) == 0) + { + int r; + do { + PRINTF("Calling enum dir \n"); + r=rtfsl_enumerate_directory(&root_file,¤t_entry_file,rootscan_test_callback,(void *) ROOT_SCAN_TEST_PRINT_FILE_NAMES); + } while (r==2); + } + } +#endif +#if (DOROOTGFIRSTSCANTEST) + if (rtfsl_root_finode_open(&root_file) == 0) + { + struct rtfsl_dstat dstat; + if (rtfsl_gfirst(&dstat, 0)==1) + { + do { + if ((dstat.fattribute&(AVOLUME|ADIRENT))==0) + { + PRINTF("Got file : %s size: %ld \n",dstat.fnameandext,dstat.fsize); + } + else + { + PRINTF("Got entry: %s \n",dstat.fnameandext); + } + } while (rtfsl_gnext(&dstat)==1); + } + } +#endif + +#if (RTFSL_INCLUDE_WRITE_SUPPORT&&DOFILEWRITETEST) + rval=rtfsltest_file_sequential_write((unsigned char *)BOOTFILENAME, FILE_FRAGMENT_LENGTH, FILE_GAP_FRAGMENT_LENGTH, WRITETESTNLONGS, DOAPPENDTEST); + if (rval<0) + return; +#endif +#if (DOSEQUENTIALREADTEST) + rval=rtfsltest_file_sequential_read((unsigned char *)BOOTFILENAME); + if (rval<0) + return; +#endif +#if (RTFSL_INCLUDE_WRITE_SUPPORT&&DOFILEWRITETEST&&DOFILERANDOMWRITETEST) + rval=rtfsltest_file_random_write((unsigned char *)BOOTFILENAME); + if (rval<0) + return; +#endif + PRINTF("File sequential write-seek-write-seek-read test completed\n"); +#if (RTFSL_INCLUDE_WRITE_SUPPORT&&DOFILEWRITETEST&&DORENAMETEST) + if (rtfsl_rename((unsigned char *)BOOTFILENAME, (unsigned char *)BOOTFILENAME)!=RTFSL_ERROR_EXIST) + { + PRINTF("Rename should have failed but did not\n"); + } + rtfsl_rename((unsigned char *)BOOTFILENAME, (unsigned char *)RENAMEDFILENAME); +#endif +#if (DOBOOTFILEEST) + { + int fd; + void * load_address = malloc(1000000); + rtfsl_load_file((unsigned char *)BOOTFILENAME, (unsigned long) load_address); + #if (DOFILIOREADAPITEST) + fd=rtfsl_open((unsigned char*)BOOTFILENAME); + if (fd>=0) + { + int nread; + unsigned long total=0; + unsigned char *loadimage=(unsigned char *)load_address; + rtfsl_fstat(fd,&statstruct); + do + { + nread=rtfsl_read(fd,test_buffer,rtfsl.current_dr.bytespsector); + if (nread>0) + { + total+=nread; + if (ANSImemcmp(test_buffer, loadimage, nread)!=0) + { + PRINTF("Compare failed\n"); + } + loadimage += nread; + } + } while (nread > 0); + if (statstruct.st_size!=total) + { + PRINTF("filesize == %d total read == %ld\n",statstruct.st_size,total); + } +#if (DOFILERANDOMREADTEST) + { + unsigned long seekoffset,seekpointer; + for (seekoffset=1;seekoffset<7;seekoffset++) + { + for (seekpointer=0; seekpointerrtfsl_direntry_type&RTFSL_ENTRY_AVAILABLE)!=0) + { + if (fill_structure->first_free_pointer==-1) + fill_structure->first_free_pointer=fill_structure->last_index_pointer; + if (fill_structure->eof_pointer==-1&&(pcurrent_entry_file->rtfsl_direntry_type&RTFSL_ENTRY_TYPE_EOF)) + fill_structure->eof_pointer=fill_structure->last_index_pointer; + } + } + fill_structure->last_index_pointer++; + return 0; /* Continue */ +} + +int ut_fill_directory(int leave_n_free) +{ + char name[12]; + int n_left; + ANSImemcpy(name,"TESTNAMEEXT",11); + char c='A'; + int index = 0; + int fcount; + + + fcount = (rtfsl.current_dr.bytespcluster/32); + { + int fd; + int rval; + struct ut_fill_structure fill_structure; + struct rtfsl_file new_directory_file; + + fill_structure.first_free_pointer =-1; + fill_structure.eof_pointer=-1; + fill_structure.last_index_pointer=0; + fd = rtfsl_alloc_fd(); + if (fd<0) + return fd; + rval = rtfsl_open_path(rtfsl.current_dr.pathnamearray,0, &new_directory_file, &rtfsl.rtfsl_files[fd]); + if (rval==0) + { + rval = rtfsl_enumerate_directory(&rtfsl.rtfsl_files[fd],&new_directory_file, ut_fill_callback,(void *) &fill_structure); + if(rval<0) + return rval; + fcount = fill_structure.eof_pointer; + if (fill_structure.eof_pointer!=fill_structure.first_free_pointer) + return RTFSL_ERROR_TEST; // Warning fill directory will be inaccurate + } + rtfsl.rtfsl_files[fd].rtfsl_file_flags=0; + } + n_left = (rtfsl.current_dr.bytespcluster/32)-fcount; + while (n_left > leave_n_free) + { + int rval; + name[index]=c; + c+=1; + if (c >'Z') + { + c='A'; + index+=1; + } + rval=rtfsl_create((unsigned char*)name,0); + if (rval<0) + return rval; + n_left--; + } + return 0; +} + +/* Unconditional delete all files and subdirectories in the folder. + Does not descend. If subdirectories contain information lost clusters will result */ +void ut_unfill_directory(unsigned char *name) +{ + struct rtfsl_dstat dstat; + while (rtfsl_gfirst(&dstat, name)==1) + { + if ( (rtfsl_gnext(&dstat)==1) && /* ".." */ + (rtfsl_gnext(&dstat)==1) + ) + _rtfsl_delete(dstat.fnameandext, dstat.fattribute&ADIRENT); + else + break; + } +} + +int ut_release_fragments(int file_fraglen, int gap_fraglen, int numfrags, unsigned long *fragrecord/*[numfrags]*/) +{ +int fragnum,rval; +unsigned long cluster,value; + value=0; + for(fragnum=0; fragnum < numfrags; fragnum++) + { + for (cluster=*(fragrecord+fragnum); cluster < *(fragrecord+fragnum)+gap_fraglen;cluster++) + { + /* Use write call to free up gap_fraglen clusters */ + rval=fatop_buff_get_frag(cluster|RTFSL_WRITE_CLUSTER, &value, 1); + if (rval < 0) + return rval; + } + } + return 0; +} + +int ut_create_fragments(int file_fraglen, int gap_fraglen, int numfrags, unsigned long *fragrecord/*[numfrags]*/) +{ +unsigned long new_start_hint,start_hint,next_cluster,current_cluster,cluster,value; +int rval,fragnum,len; + if (gap_fraglen==0) + return 0; + /* */ + start_hint=2; + new_start_hint=0; + for(fragnum=0; fragnum < numfrags; fragnum++) + { + /* Use allocate call to get file_fraglen contiguous clusters, but do not write to the clusters */ + len=0; + current_cluster=0; + while (len