first commit

This commit is contained in:
peteratebs 2015-10-11 13:58:55 -04:00
commit 45e1b1f8ba
30 changed files with 5407 additions and 0 deletions

6
Makefile Normal file
View File

@ -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

104
README.MD Normal file
View File

@ -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.

308
codesizes.txt Normal file
View File

@ -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

BIN
main Normal file

Binary file not shown.

30
main.c Normal file
View File

@ -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();
}

75
manual.txt Normal file
View File

@ -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

14
rtfslconst.c Normal file
View File

@ -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};

16
rtfsldata.c Normal file
View File

@ -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];

51
rtfsldelete.c Normal file
View File

@ -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<RTFSL_CFG_FILE_FRAG_BUFFER_SIZE;offset++)
{
for (cluster = rtfsl.rtfsl_files[fd].cluster_segment_array[offset][0]; cluster <= rtfsl.rtfsl_files[fd].cluster_segment_array[offset][1];cluster++)
{
rval= fatop_buff_get_frag(cluster|RTFSL_WRITE_CLUSTER, &value, 1);
if (rval<0)
{
break;
}
}
}
if (rval>=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;
}

695
rtfslfailsafe.c Normal file
View File

@ -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 <stdio.h>
#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 (cluster<start_record_cluster) /* No relationship */
continue;
if (cluster_record_type==CLUSTER_INSTANCE_RECORD)
{
if (start_record_cluster==cluster)
return pfs->preplacement_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++<end_record_cluster);
}
else if (cluster_record_type==CLUSTER_INSTANCE_RECORD)
{
value=end_record_cluster;
rval=fatop_buff_get_frag(current_cluster|RTFSL_WRITE_CLUSTER, &value, 1);
}
else /* if (cluster_record_type==CLUSTER_CHAIN_RECORD)||cluster_record_type==CLUSTER_TCHAIN_RECORD */
{
value=current_cluster+1;
while (rval==0 && current_cluster!=end_record_cluster)
{
rval=fatop_buff_get_frag(current_cluster|RTFSL_WRITE_CLUSTER, &value, 1);
value+=1;
current_cluster+=1;
};
if (cluster_record_type==CLUSTER_TCHAIN_RECORD)
value = rtfsl.current_dr.end_cluster_marker|0xf;
if (rval==0)
rval=fatop_buff_get_frag(current_cluster|RTFSL_WRITE_CLUSTER, &value, 1);
}
}
}
if (rval==0)
rval=rtfsl_flush_all_buffers();
if (rval==0 && *pfs->preplacement_record_count)
{
rtfsl.rtfsl_current_failsafe_context=pfs;
rtfslfs_access_journal(RTFSLFS_JCLEAR);
rtfsl.rtfsl_current_failsafe_context=0;
}
}
return rval;
}
#endif

48
rtfslfileseek.c Normal file
View File

@ -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;
}

24
rtfslfilestat.c Normal file
View File

@ -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);
}

202
rtfslfiliocore.c Normal file
View File

@ -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_bytes;copied+=32,index++,pdata+=32)
{
rval=rtfslfs_dirent_remap(sector,index, (struct rtfsl_dosinode *) pdata,0);
if (rval<0)
return rval;
}
return 0;
}
#endif
long _rtfsl_bfilio_io(int fd, unsigned char *pdata, long n_bytes, unsigned char opflags)
{
long n_left,copied,count_inregion;
unsigned long file_pointer; // ,region_byte_next,file_region_byte_base, file_region_block_base;
unsigned long sector,residual,offset;
int rval=0;
/* use local copies of file info so if we fail the pointers will not advance */
file_pointer = rtfsl.rtfsl_files[fd].file_pointer;
n_left = n_bytes;
sector=count_inregion=residual=offset=0;
while (n_left)
{
if (!residual)
{
count_inregion = rtfsl_map_region_clusterwindow(fd, file_pointer, &sector, &offset);
if (count_inregion<0)
return count_inregion;
if (count_inregion==0)
break;
if (count_inregion > 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);
}

82
rtfslfiliord.c Normal file
View File

@ -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<RTFSL_CFG_NFILES;fd++)
{
if (rtfsl.rtfsl_files[fd].rtfsl_file_flags==0)
{
rtfsl.rtfsl_files[fd].rtfsl_file_flags=TRTFSFILE_ALLOCATED;
return fd;
}
}
return RTFSL_ERROR_FDALLOC;
}
int rtfsl_open(unsigned char *name) /*__apifn__*/
{
return _rtfsl_open(name, 0);
}
int _rtfsl_open(unsigned char *name, unsigned char attributes)
{
struct rtfsl_file scratch_dir_file;
int fd,rval;
fd = rtfsl_alloc_fd();
if (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
}

308
rtfslfiliowr.c Normal file
View File

@ -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 <stdio.h>
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
}

42
rtfslfssystem.c Normal file
View File

@ -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&&i<pfs->journal_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

72
rtfslgfirst.c Normal file
View File

@ -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__*/
{
}

314
rtfslite.h Normal file
View File

@ -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 <string.h>
#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__ */

929
rtfslitecore.c Normal file
View File

@ -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<<H)
#define BUFHMASKNOT(H) (~(1<<H))
static const unsigned char dos_partition_types[]= {
0x01,0x04,0x06,
0x0E, /* Windows FAT16 Partition */
0x0B, /* FAT32 Partition */
0x0C, /* FAT32 Partition */
0x55, /* FAT32 Partition */
0x07 /* exFat Partition */
};
#if (RTFSL_CFG_FILE_FRAG_BUFFER_SIZE>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 && l<rtfsl.current_dr.secreserved+(unsigned long)rtfsl.current_dr.secpfat)
rval = rtfsl_write_sectors(rtfsl.current_buffered_sectors[bufferhandle]+(unsigned long)rtfsl.current_dr.secpfat,1,b);
}
rtfsl.buffer_pool_dirty&=BUFHMASKNOT(bufferhandle);
}
return rval;
}
int rtfsl_flush_all_buffers(void) /*__apifn__*/
{
int bufferhandle,rval;
rval=0;
for(bufferhandle=0;rval==0&&bufferhandle<RTFSL_CFG_NUMBUFFERS;bufferhandle++)
rval=rtfsl_flush_sector_buffer(bufferhandle,0);
#if (RTFSL_INCLUDE_FAT32)
rval=rtfsl_flush_info_sec();
#endif
return rval;
}
#endif
int rtfsl_read_sector_buffer(unsigned long sector)
{
int found,rval;
unsigned char *b,i,bufferhandle;
found=0;
bufferhandle=rtfsl.buffer_pool_agingstack[RTFSL_CFG_NUMBUFFERS-1];
rval=0;
#if(RTFSL_CFG_NUMBUFFERS>1)
b=rtfsl.buffer_pool_agingstack;
for(i=0;i<RTFSL_CFG_NUMBUFFERS;i++)
{
if (sector==rtfsl.current_buffered_sectors[i])
{
bufferhandle=i;
found=1;
break;
}
}
#endif
#if (RTFSL_INCLUDE_WRITE_SUPPORT)
if (!found)
rval = rtfsl_flush_sector_buffer(bufferhandle,0);
#endif
if (rval>=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<RTFSL_CFG_NUMBUFFERS-1;i++)
{
if(b[i]==bufferhandle)
{
ntocopy=i;
break;
}
}
if (!ntocopy)
ntocopy=RTFSL_CFG_NUMBUFFERS-1;
ANSImemcpy(b+1,b,ntocopy);
}
#endif
b[0]=bufferhandle;
}
}
return rval;
}
unsigned long rtfsl_sec2cluster(unsigned long sector)
{
if (sector < rtfsl.current_dr.firstclblock)
return 0;
return 2+(sector-rtfsl.current_dr.firstclblock)/rtfsl.current_dr.secpalloc;
}
unsigned long rtfsl_cl2sector(unsigned long cluster)
{
unsigned long cl;
if (cluster > 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<RTFSL_CFG_NUMBUFFERS;i++)
rtfsl.buffer_pool_agingstack[i]=i;
/* Check for MBR */
rval=rtfsl_read_sectors(0,1,rtfsl.pcurrent_buffer_pool);
if (rval<0)
return rval;
sector_buffer=rtfsl.pcurrent_buffer_pool;
#if (RTFSL_INCLUDE_MBR_SUPPORT)
if (sector_buffer[511]==0xaa)
{
if (sector_buffer[510]==0x55
#if (INCLUDE_WINDEV)
|| sector_buffer[510]==0x66
#endif
)
{
int i;
unsigned char *p=&sector_buffer[446];
for(i=0; rtfsl.current_dr.partition_base==0 && i < 4; i++,p+=16)
{
int j;
unsigned char p_type = *(p+4);
for (j = 0; j < sizeof(dos_partition_types);j++)
{
if(p_type==dos_partition_types[j])
{
rtfsl.current_dr.partition_base = to_ULONG (p+8);
rtfsl.current_dr.partition_size = to_ULONG (p+12);
rval=rtfsl_read_sectors(rtfsl.current_dr.partition_base,1,sector_buffer);
if (rval<0)
return rval;
break;
}
}
}
}
}
#endif
/* Check for BPB signature */
b=&sector_buffer[0];
/* The valid bpb test passes for NTFS. So identify NTFS and force jump to zero so the bpb test fails. */
/* Check for EXFAT and NTFS */
if (ANSImemcmp(b+3, (void *)"EXFAT",4)==0||ANSImemcmp(b+3, (void *)"NTFS",4)==0)
{
#if (INCLUDE_EXFAT)
!!!!!!;
#else
return RTFSL_ERROR_FORMAT;
#endif
}
if ( (*b!=0xE9) && (*b!=0xEB)
#if (INCLUDE_WINDEV)
&& (*b!=0xE9) /* E8 BPB signature so volume it is writeable*/
#endif
)
{
return RTFSL_ERROR_FORMAT;
}
rtfsl.current_dr.secpalloc = b[0xd];
rtfsl.current_dr.numfats = b[0x10];
rtfsl.current_dr.bytespsector = to_USHORT(b+0xb) ;
rtfsl.current_dr.secreserved = to_USHORT(b+0xe) ;
rtfsl.current_dr.numroot = to_USHORT(b+0x11);
rtfsl.current_dr.numsecs = to_USHORT(b+0x13);
rtfsl.current_dr.secpfat = (unsigned long) to_USHORT(b+0x16);
rtfsl.current_dr.bytespcluster = (unsigned long) rtfsl.current_dr.bytespsector*rtfsl.current_dr.secpalloc;
rtfsl.current_dr.rootbegin = rtfsl.current_dr.secreserved + rtfsl.current_dr.secpfat*rtfsl.current_dr.numfats;
if (rtfsl.current_dr.numsecs==0)
rtfsl.current_dr.numsecs = to_ULONG(b+0x20);/*X*/ /* # secs if > 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_count<cluster_segment_array_size)
{
cluster_segment_array[segment_count][0]=start_cluster;
cluster_segment_array[segment_count][1]=start_cluster+length-1;
if (segment_length_clusters)
*segment_length_clusters += length;
*start_next_segment=next_cluster;
}
else
break;
segment_count += 1;
start_cluster=next_cluster;
}
return segment_count;
}
#endif
int rtfsl_enumerate_file(struct rtfsl_file *pfile,FileScanCallback pCallback, void *puser_data) /*__apifn__*/
{
unsigned long start_sector,end_sector,nbytes,callback_value;
int current_cluster_segment = RTFSL_CFG_FILE_FRAG_BUFFER_SIZE;
pfile->file_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;
}

563
rtfsliteshell.c Normal file
View File

@ -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 <ctype.h>
#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;
}

24
rtfslitetests.h Normal file
View File

@ -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 <stdio.h>
#define PRINTF printf

65
rtfslmkdir.c Normal file
View File

@ -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;
}

85
rtfslopenpath.c Normal file
View File

@ -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;
}

38
rtfslrename.c Normal file
View File

@ -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;
}

51
rtfslrmdir.c Normal file
View File

@ -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;
}

200
rtfslsystem.c Normal file
View File

@ -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 <windows.h>
#endif
#ifdef __linux__
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
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);
}

96
rtfstlitefileload.c Normal file
View File

@ -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, &current_entry_file);
if (rval== 0)
rval=rtfsl_enumerate_file(&current_entry_file,file_load_callback, (void *) &loadstruct);
return rval;
}

322
rtfstlitetestfileio.c Normal file
View File

@ -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; seekpointer<statstruct.st_size;seekpointer += seekoffset)
{
loadimage=(unsigned char *)load_address;
if ((seekpointer & 0x3ff) == 0)
{
PRINTF("seek test pass %lu pointer: %8.8lu\r", seekoffset, seekpointer);
}
rtfsl_lseek(fd,0,PSEEK_SET);
rtfsl_lseek(fd,seekpointer,PSEEK_SET);
rtfsl_read(fd,test_buffer,1);
if (test_buffer[0] != *(loadimage+seekpointer))
{
PRINTF("\nSeek test compare error at %lu\n",seekpointer);
}
}
}
PRINTF("load-sequential read-seek-read test completed %lu bytes read and verified\n",statstruct.st_size);
}
#endif // #if (DOFILIOREADAPITEST)
free(load_address);
}
#endif
#if (DOFAILSAFEFLUSHTEST&&RTFSL_INCLUDE_FAILSAFE_SUPPORT)
rtfslfs_flush();
#endif
}
#endif

460
rtfstlitetests.c Normal file
View File

@ -0,0 +1,460 @@
/*
* 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"
/* Callback instructions */
#define ROOT_SCAN_TEST_PRINT_FILE_NAMES 1
#define ROOT_SCAN_TEST_BOOTFILETEST 2
#define BOOTFILENAME "BOOTFILEBIN"
#define RENAMEDFILENAME "RENAMEDFILE"
extern int writing;
static unsigned char *path[4] = {(unsigned char*)"RTFSL ",0,0,0};
/*
Failsafe test scenarios
// Create a directory in the journal but not on the medium rtfs reports no directory exists
#define DOFAILSAFEOPENTEST 1
#define DOFAILSAFERESTORETEST 0
#define DOMKDIRTEST 1
#define DORMDIRTEST 0
#define DOFAILSAFEFLUSHTEST 0
// Restore from the journal. Rtfs reports the directory exists
#define DOFAILSAFEOPENTEST 1
#define DOFAILSAFERESTORETEST 1
#define DOMKDIRTEST 0
#define DORMDIRTEST 0
#define DOFAILSAFEFLUSHTEST 0
// Remove the director and flush the journal. Rtfs still reports the directory exists
#define DOFAILSAFEOPENTEST 1
#define DOFAILSAFERESTORETEST 1
#define DOMKDIRTEST 0
#define DORMDIRTEST 0
#define DOFAILSAFEFLUSHTEST 1
// Restore from the journal. Rtfs reports the directory does not
#define DOFAILSAFEOPENTEST 1
#define DOFAILSAFERESTORETEST 1
#define DOMKDIRTEST 0
#define DORMDIRTEST 0
#define DOFAILSAFEFLUSHTEST 0
// Write to the journal file and perform the file read and write tests. There is no record of the fiole in RTFS
#define DOFAILSAFEOPENTEST 1
#define DOFAILSAFERESTORETEST 0
#define DOMKDIRTEST 0
#define DORMDIRTEST 0
#define DOFILEWRITETEST 1
#define DOBOOTFILEEST 1
#define DOFILIOREADAPITEST 1
#define DOFAILSAFEFLUSHTEST 1
// Restore from the journal file RTFS sees the file
#define DOFAILSAFEOPENTEST 1
#define DOFAILSAFERESTORETEST 1
// Delete the to the journal file. The file is still seen in Rtfs
#define DOFAILSAFEOPENTEST 1
#define DOFAILSAFERESTORETEST 0
#define DOMKDIRTEST 0
#define DORMDIRTEST 0
#define DOFILEWRITETEST 0
#define DOFILEDELETETEST 1
#define DOBOOTFILEEST 0
#define DOFILIOREADAPITEST 0
#define DOFAILSAFEFLUSHTEST 1
// Restore from the journal file RTFS no longer sees the file
#define DOFAILSAFEOPENTEST 1
#define DOFAILSAFERESTORETEST 1
*/
/* Compile tiome options for test selection */
#define DOFATSCANTEST 0
#define DOROOTSCANTEST 1
#define DOROOTGFIRSTSCANTEST 1
#define DOFAILSAFEFLUSHTEST 0
#define DOFAILSAFEOPENTEST 1
#define DOFAILSAFESYNCTEST 1
#define DOFAILSAFERESTORETEST 1
#define DOMKDIRTEST 1
#define DORMDIRTEST 0
#define DIRECTORY_FRAGMENT_LENGTH 1 /* One for every other cluster fragmentation but may be larger */
#define DIRECTORY_GAP_FRAGMENT_LENGTH 0 /* Zero for no fragments, or the gap between file fragments */
#define WRITETESTNLONGS 10240
#define DOFILEWRITETEST 1
#define DOSEQUENTIALREADTEST 1
#define DOFILERANDOMWRITETEST 0
#define FILE_FRAGMENT_LENGTH 1 /* One for every other cluster fragmentation but may be larger */
#define FILE_GAP_FRAGMENT_LENGTH 0 /* Zero for no fragments, or the gap between file fragments */
#define DOAPPENDTEST 1 /* If 1 the sequential write test closes and seeks to the end every 1000th write */
#define DORENAMETEST 1
#define DOFILEDELETETEST 0
#if (DORMDIRTEST&&DOFILEDELETETEST)
#error Tests are mutually exclusive
#endif
#define DOBOOTFILEEST 0
#define DOFILIOREADAPITEST 0
#define DOFILERANDOMREADTEST 0
#define DOSETPATHTEST 1
#define DOMULTICHAINSUBDIRECTORYTEST 0 /* Requires DOSETPATH */
#if (RTFSL_INCLUDE_LOAD_ONLY)
#undef DOFATSCANTEST
#undef DOROOTSCANTEST
#undef DOROOTGFIRSTSCANTEST
#undef DOFAILSAFEFLUSHTEST
#undef DOFAILSAFEOPENTEST
#undef DOFAILSAFESYNCTEST
#undef DOFAILSAFERESTORETEST
#define DOFATSCANTEST 0
#define DOROOTSCANTEST 0
#define DOROOTGFIRSTSCANTEST 0
#define DOFAILSAFEFLUSHTEST 0
#define DOFAILSAFEOPENTEST 0
#define DOFAILSAFESYNCTEST 0
#define DOFAILSAFERESTORETEST 0
#undef DOMKDIRTEST
#undef DORMDIRTEST
#define DOMKDIRTEST 0
#define DORMDIRTEST 0
#undef DOFILEWRITETEST
#undef DOFILERANDOMWRITETEST
#undef DOAPPENDTEST
#undef DORENAMETEST
#undef DOFILEDELETETEST
#undef DOSEQUENTIALREADTEST
#define DOSEQUENTIALREADTEST 0
#define DOFILEWRITETEST 0
#define DOFILERANDOMWRITETEST 0
#define DOAPPENDTEST 0
#define DORENAMETEST 0
#define DOFILEDELETETEST 0
#undef DOBOOTFILEEST
#undef DOFILIOREADAPITEST
#undef DOFILERANDOMREADTEST
#define DOBOOTFILEEST 1
#define DOFILIOREADAPITEST 0
#define DOFILERANDOMREADTEST 0
#undef DOSETPATHTEST
#define DOSETPATHTEST 0
#undef DOMULTICHAINSUBDIRECTORYTEST
#define DOMULTICHAINSUBDIRECTORYTEST 0
#endif
//HEREHERE
//.. Test putting next index and bytes free into failsafe buffer so it re-loads
//.. Create failsafe load and failsafe sync functions
//.. Failsafe representation of info sector update
//.. Put checksum of all journalled entities into failsafe file for catching changes outside.
//.. Update of multiple fat copies
//.. Update of FAT32 info sector fields.
//.. done test directory extend
//.. test directory extend with fragments
//.. done test file append (seek to end and write)
//..
unsigned char test_buffer[RTFSL_CFG_MAXBLOCKSIZE];
#if (DOFAILSAFETEST&&RTFSL_INCLUDE_FAILSAFE_SUPPORT)
int rtfslfs_test(void);
#endif
int rootscan_test_callback(struct rtfsl_file const *pcurrent_entry_file, void *puser_data)
{
if (puser_data==(void *)ROOT_SCAN_TEST_PRINT_FILE_NAMES)
{
if (pcurrent_entry_file->rtfsl_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,&current_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; seekpointer<statstruct.st_size;seekpointer += seekoffset)
{
loadimage=(unsigned char *)load_address;
if ((seekpointer & 0x3ff) == 0)
{
PRINTF("seek test pass %d pointer: %8.8ld\r", seekoffset, seekpointer);
}
rtfsl_lseek(fd,0,PSEEK_SET);
rtfsl_lseek(fd,seekpointer,PSEEK_SET);
rtfsl_read(fd,test_buffer,1);
if (test_buffer[0] != *(loadimage+seekpointer))
{
PRINTF("\nSeek test compare error at %ld\n",seekpointer);
}
}
}
}
#endif
PRINTF("load-sequential read-seek-read test completed %ld bytes read and verified\n",statstruct.st_size);
}
#endif // #if (DOFILIOREADAPITEST)
free(load_address);
}
#endif
#if (RTFSL_INCLUDE_WRITE_SUPPORT&&DORMDIRTEST&&RTFSL_INCLUDE_SUBDIRECTORIES&&DOSETPATHTEST)
/* Remove the current working directory */
path[1]=0; /* Set default path one layer deep */
rtfsl_setpath(path);
if (rtfsl_rmdir((unsigned char*)path[0])==0)
{
PRINTF("rmdir succeeded but it should have failed\n");
}
path[1]=path[0]; /* Set default path 2 deep */
rtfsl_setpath(path);
ut_unfill_directory(0);
path[1]=0; /* Set default path one layer deep */
rtfsl_setpath(path);
if (rtfsl_rmdir((unsigned char*)path[0])!=0)
{
PRINTF("rmdir failed even after cleaning directory\n");
return;
}
#endif
#if (DOFAILSAFESYNCTEST&&DOFAILSAFEFLUSHTEST)
#error Mutually exclusive
#endif
#if (RTFSL_INCLUDE_WRITE_SUPPORT&&RTFSL_INCLUDE_SUBDIRECTORIES&&DOFILEDELETETEST)
rtfsl_delete((unsigned char *)BOOTFILENAME);
#endif
#if (DOFAILSAFEFLUSHTEST&&RTFSL_INCLUDE_FAILSAFE_SUPPORT)
rtfslfs_flush();
#endif
#if (DOFAILSAFESYNCTEST&&RTFSL_INCLUDE_FAILSAFE_SUPPORT)
rtfslfs_sync();
rtfsl_setpath(0);
rtfsl_mkdir((unsigned char*)"AFTERSYNC ");
rtfslfs_flush();
PRINTF("Restore and you will see the \\AFTERSYNC directorty \n");
#endif
}

183
rtfstlitetestutils.c Normal file
View File

@ -0,0 +1,183 @@
/*
* 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 "stdlib.h"
struct ut_fill_structure {
int last_index_pointer;
int first_free_pointer;
int eof_pointer;
};
static int ut_fill_callback(struct rtfsl_file const *pcurrent_entry_file, void *puser_data)
{
struct ut_fill_structure *fill_structure= (struct ut_fill_structure *) puser_data;
{
if ((pcurrent_entry_file->rtfsl_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<file_fraglen)
{
rval=fatop_buff_get_frag(start_hint|RTFSL_ALLOC_CLUSTER, &next_cluster, 1);
if (rval<=0)
return rval;
start_hint=next_cluster+1;
if (current_cluster==0||((current_cluster+1)!=next_cluster))
{
current_cluster=next_cluster;
len=1;
}
else
len += 1;
}
if (new_start_hint==0)
new_start_hint=current_cluster;
len=0;
current_cluster=0;
while (len<gap_fraglen)
{
rval=fatop_buff_get_frag(start_hint|RTFSL_ALLOC_CLUSTER, &next_cluster, file_fraglen);
if (rval<=0)
return rval;
if (current_cluster==0||((current_cluster+1)!=next_cluster))
{
current_cluster=next_cluster;
len=1;
}
else
len += 1;
start_hint=next_cluster+1;
}
*(fragrecord+fragnum)=current_cluster;
/* Use write call to allocate gap_fraglen clusters */
value = rtfsl.current_dr.end_cluster_marker|0xf;
for (cluster=*(fragrecord+fragnum); cluster < *(fragrecord+fragnum)+gap_fraglen;cluster++)
{
rval=fatop_buff_get_frag(cluster|RTFSL_WRITE_CLUSTER, &value, 1);
if (rval < 0)
return rval;
}
}
/* Set next_alloc to the start of our fragment chain so when we allocate we'll start where we wanted to */
rtfsl.current_dr.next_alloc=new_start_hint;
return 0;
}