commit 45e1b1f8ba61e252ae03dac101feeb24a8dc8760 Author: peteratebs Date: Sun Oct 11 13:58:55 2015 -0400 first commit 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 0000000..3e4deff Binary files /dev/null and b/main differ diff --git a/main.c b/main.c new file mode 100644 index 0000000..11c5e1b --- /dev/null +++ b/main.c @@ -0,0 +1,30 @@ +/* +* 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" +#ifdef __linux__ +int rtfsl_open_disk(char *raw_dev_name); +#endif + +void main(int argc, char **argv) +{ + if (argc != 2) + { + printf("Usage: %s block_dev_name\n", argv[0]); + printf("Usage: You must provide the device name of fat formatted device\n"); + return; + } + if (rtfsl_open_disk(argv[1]) < 0) + { + printf("Could not open device: %s\n", argv[1]); + return; + } + rtfslite_shell(); +} diff --git a/manual.txt b/manual.txt new file mode 100644 index 0000000..b372a96 --- /dev/null +++ b/manual.txt @@ -0,0 +1,75 @@ + +Table of contents.. + + +Introduction. + + +Configuration and porting + + +API + +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_NOTFOUND +RTFSL_ERROR_PATH +RTFSL_ERROR_EXIST +RTFSL_ERROR_TEST +/* Recommended device driver error return values, RTFSL does not generate these */ +RTFSL_ERROR_IO_WRITE_PROTECT +RTFSL_ERROR_IO_NO_MEDIA +RTFSL_ERROR_IO_ERROR + + +int rtfslfs_start(void) +int rtfslfs_flush(void) +int rtfslfs_sync(void) +int rtfslfs_restore(void) +int rtfsl_delete(unsigned char *name) + +int rtfsl_create(unsigned char *name,unsigned char attribute) +int rtfsl_open(unsigned char *name) +int rtfsl_close(int fd) +int rtfsl_read(int fd, unsigned char *in_buff, int count) +long rtfsl_lseek(int fd, long offset, int origin) +int rtfsl_write(int fd, unsigned char *in_buff, int count) +int rtfsl_fstat(int fd, struct rtfsl_statstructure *pstat) +int rtfsl_flush(int fd) + +int rtfsl_diskopen(void) +void rtfsl_setpath(unsigned char **pathnamearray) +int rtfsl_flush_info_sec(void) +int rtfsl_flush_all_buffers(void) + +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_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_mkdir(unsigned char *name) +int rtfsl_rmdir(unsigned char *name) + +int rtfsl_load_file(unsigned char *filename, unsigned long load_address) + +int rtfsl_read_sector(unsigned long sector, unsigned char *buffer) +int rtfsl_write_sector(unsigned long sector, unsigned char *buffer) +void rtfsl_get_system_date(unsigned short *time, unsigned short *date) + + + + + + +Application notes + + + diff --git a/rtfslconst.c b/rtfslconst.c new file mode 100644 index 0000000..dcf9155 --- /dev/null +++ b/rtfslconst.c @@ -0,0 +1,14 @@ +/* +* 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" + +const char *dotname = ". "; +const char *dotdotname = ".. "; +const unsigned char end_name[11] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; diff --git a/rtfsldata.c b/rtfsldata.c new file mode 100644 index 0000000..f9061a8 --- /dev/null +++ b/rtfsldata.c @@ -0,0 +1,16 @@ +/* +* 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_context rtfsl; +unsigned char rtfsl_sector_buffer[RTFSL_CFG_MAXBLOCKSIZE*RTFSL_CFG_NUMBUFFERS]; + + diff --git a/rtfsldelete.c b/rtfsldelete.c new file mode 100644 index 0000000..54d558a --- /dev/null +++ b/rtfsldelete.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" + +int rtfsl_delete(unsigned char *name) /*__apifn__*/ +{ + return _rtfsl_delete(name,0); +} + +int _rtfsl_delete(unsigned char *name,unsigned char attribute) +{ +int fd,rval,offset; + rval= _rtfsl_open(name,attribute); + if (rval >= 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