first commit

This commit is contained in:
peteratebs 2015-10-12 08:29:49 -04:00
commit b0003c4cc9
625 changed files with 204242 additions and 0 deletions

6
License Normal file
View File

@ -0,0 +1,6 @@
*
* Copyright 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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Manual.word/RTFS_COVER.doc Normal file

Binary file not shown.

BIN
Manual.word/Thumbs.db Normal file

Binary file not shown.

BIN
Manual.word/readme60.doc Normal file

Binary file not shown.

BIN
Manual.word/readme61.doc Normal file

Binary file not shown.

BIN
Manual.word/revhst60.doc Normal file

Binary file not shown.

Binary file not shown.

BIN
Manual.word/~$vhst60.doc Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Manual/revhst60.pdf Normal file

Binary file not shown.

BIN
Manual/rtfilesappnote.pdf Normal file

Binary file not shown.

25
README.MD Normal file
View File

@ -0,0 +1,25 @@
RTFS FAT file system software library in C
* 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
This project provides FAT and exFAt and journaling capable file system for creating high performance/high reliability applications.
exFAT
Jorunaling and transaction
High performance circular file IO.
Deterministic during file IO.
File region extract and swap.
Disk repair utilities.
Direct DMA API for real time streaming.
A full manual set is provided in the "manuals" subdirectory.

28
include/packagebasic.h Normal file
View File

@ -0,0 +1,28 @@
/*****************************************************************************
*Filename: RTFSPACKAGE.H - header file that identifies purchased options
*
*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc, 2006
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
* Description:
* This file contains tuning that identify purchased options.
* It is included by rtfsconf.h
*
****************************************************************************/
#ifndef __RTFSPACKAGE__
#define __RTFSPACKAGE__ 1
/* rtfspackage.h - Rtfs Basic Option setting. do not change */
#define INCLUDE_RTFS_PROPLUS 0
#define INCLUDE_RTFS_BASIC_ONLY 1
#define INCLUDE_RTFS_FAILSAFE_OPTION 0
#define INCLUDE_RTFS_DVR_OPTION 0
#define INCLUDE_MATH64 0
#endif /* __RTFSPACKAGE___ */

28
include/packagepro.h Normal file
View File

@ -0,0 +1,28 @@
/*****************************************************************************
*Filename: RTFSPACKAGE.H - header file that identifies purchased options
*
*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc, 2006
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
* Description:
* This file contains tuning that identify purchased options.
* It is included by rtfsconf.h
*
****************************************************************************/
#ifndef __RTFSPACKAGE__
#define __RTFSPACKAGE__ 1
/* rtfspackage.h - Rtfs Pro Plus Option setting. do not change */
#define INCLUDE_RTFS_PROPLUS 0
#define INCLUDE_RTFS_BASIC_ONLY 0
#define INCLUDE_RTFS_FAILSAFE_OPTION 0
#define INCLUDE_RTFS_DVR_OPTION 0
#define INCLUDE_MATH64 0
#endif /* __RTFSPACKAGE___ */

View File

@ -0,0 +1,28 @@
/*****************************************************************************
*Filename: RTFSPACKAGE.H - header file that identifies purchased options
*
*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc, 2006
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
* Description:
* This file contains tuning that identify purchased options.
* It is included by rtfsconf.h
*
****************************************************************************/
#ifndef __RTFSPACKAGE__
#define __RTFSPACKAGE__ 1
/* rtfspackage.h - Rtfs Pro with Failsafe Option setting. do not change */
#define INCLUDE_RTFS_PROPLUS 0
#define INCLUDE_RTFS_BASIC_ONLY 0
#define INCLUDE_RTFS_FAILSAFE_OPTION 1
#define INCLUDE_RTFS_DVR_OPTION 0
#define INCLUDE_MATH64 0
#endif /* __RTFSPACKAGE___ */

28
include/packageproplus.h Normal file
View File

@ -0,0 +1,28 @@
/*****************************************************************************
*Filename: RTFSPACKAGE.H - header file that identifies purchased options
*
*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc, 2006
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
* Description:
* This file contains tuning that identify purchased options.
* It is included by rtfsconf.h
*
****************************************************************************/
#ifndef __RTFSPACKAGE__
#define __RTFSPACKAGE__ 1
/* rtfspackage.h - Rtfs Pro Plus Option setting. do not change */
#define INCLUDE_RTFS_PROPLUS 1
#define INCLUDE_RTFS_BASIC_ONLY 0
#define INCLUDE_RTFS_FAILSAFE_OPTION 0
#define INCLUDE_RTFS_DVR_OPTION 0
#define INCLUDE_MATH64 1
#endif /* __RTFSPACKAGE___ */

View File

@ -0,0 +1,28 @@
/*****************************************************************************
*Filename: RTFSPACKAGE.H - header file that identifies purchased options
*
*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc, 2006
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
* Description:
* This file contains tuning that identify purchased options.
* It is included by rtfsconf.h
*
****************************************************************************/
#ifndef __RTFSPACKAGE__
#define __RTFSPACKAGE__ 1
/* rtfspackage.h - Rtfs Pro Plus DVR Option setting. do not change */
#define INCLUDE_RTFS_PROPLUS 1
#define INCLUDE_RTFS_BASIC_ONLY 0
#define INCLUDE_RTFS_FAILSAFE_OPTION 0
#define INCLUDE_RTFS_DVR_OPTION 1
#define INCLUDE_MATH64 1
#endif /* __RTFSPACKAGE___ */

View File

@ -0,0 +1,28 @@
/*****************************************************************************
*Filename: RTFSPACKAGE.H - header file that identifies purchased options
*
*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc, 2006
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
* Description:
* This file contains tuning that identify purchased options.
* It is included by rtfsconf.h
*
****************************************************************************/
#ifndef __RTFSPACKAGE__
#define __RTFSPACKAGE__ 1
/* rtfspackage.h - Rtfs Pro Plus DVR with Failsafe Option setting. do not change */
#define INCLUDE_RTFS_PROPLUS 1
#define INCLUDE_RTFS_BASIC_ONLY 0
#define INCLUDE_RTFS_FAILSAFE_OPTION 1
#define INCLUDE_RTFS_DVR_OPTION 1
#define INCLUDE_MATH64 1
#endif /* __RTFSPACKAGE___ */

View File

@ -0,0 +1,28 @@
/*****************************************************************************
*Filename: RTFSPACKAGE.H - header file that identifies purchased options
*
*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc, 2006
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
* Description:
* This file contains tuning that identify purchased options.
* It is included by rtfsconf.h
*
****************************************************************************/
#ifndef __RTFSPACKAGE__
#define __RTFSPACKAGE__ 1
/* rtfspackage.h - Rtfs Pro Plus with Failsafe Option setting. do not change */
#define INCLUDE_RTFS_PROPLUS 1
#define INCLUDE_RTFS_BASIC_ONLY 0
#define INCLUDE_RTFS_FAILSAFE_OPTION 1
#define INCLUDE_RTFS_DVR_OPTION 0
#define INCLUDE_MATH64 1
#endif /* __RTFSPACKAGE___ */

71
include/portconf.h Normal file
View File

@ -0,0 +1,71 @@
/*****************************************************************************
*Filename: Portconf.h - Dummy file included only by Rtfilesv1.0 drivers
*
*
* EBS - RTFS (Real Time File Manager)
*
* Copyright Peter Van Oudenaren , 1993
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
*
*
* Description:
*
*
*
*
****************************************************************************/
/* portconf.h
This file is only included when supporting device drivers which supported the earlier
device driver model. The latest drivers where released in from "release_candidate60_f_2"
which was formally released as Rtfsilesex1.0.
*/
#define INCLUDE_IDE 0 /* - Include the IDE driver */
#define INCLUDE_PCMCIA 0 /* - Include the pcmcia driver */
#define INCLUDE_PCMCIA_SRAM 0 /* - Include the pcmcia static ram card driver */
#define INCLUDE_COMPACT_FLASH 0 /* - Support compact flash (requires IDE and PCMCIA) */
#define INCLUDE_FLASH_FTL 0 /* - Include the linear flash driver */
#define INCLUDE_ROMDISK 0 /* - Include the rom disk driver */
#define INCLUDE_RAMDISK 0 /* - Include the rom disk driver */
#define INCLUDE_MMCCARD 0 /* - Include the multi media flash card driver */
#define INCLUDE_SMARTMEDIA 0 /* - Include the smart media flash card driver */
#define INCLUDE_FLOPPY 0 /* - Include the floppy disk driver */
#define INCLUDE_HOSTDISK 1 /* - Include the host disk disk simulator */
#define INCLUDE_WINDEV 0 /* - Include windows direct device access */
#define INCLUDE_UDMA 0 /* - Include ultra dma support for the ide driver */
#define INCLUDE_82365_PCMCTRL 0 /* - Include the 82365 pcmcia controller driver */
/* These opcodes must be supported by the device driver's
perform_device_ioctl() routine.
*/
#define DEVCTL_CHECKSTATUS 0
#define DEVCTL_WARMSTART 1
#define DEVCTL_POWER_RESTORE 2
#define DEVCTL_POWER_LOSS 3
#define DEVCTL_FORMAT 4
#define DEVCTL_GET_GEOMETRY 5
#define DEVCTL_REPORT_REMOVE 6
#define DEVCTL_SHUTDOWN 7
/* These codes are to be returned from the device driver's
perform_device_ioctl() function when presented with
DEVCTL_CHECKSTATUS as an opcode.
*/
#define DEVTEST_NOCHANGE 0 /* Status is 'UP' */
#define DEVTEST_NOMEDIA 1 /* The device is empty */
#define DEVTEST_UNKMEDIA 2 /* Contains unknown media */
#define DEVTEST_CHANGED 3 /* Controller recognized and cleared a */
/* change condition */
#define BIN_VOL_LABEL 0x12345678L
void v1_0_poll_devices(void);

103
include/rtexfatprotos.h Normal file
View File

@ -0,0 +1,103 @@
#ifndef __RTFSEXFATPROTOS__
#define __RTFSEXFATPROTOS__ 1
#if (DEBUG_EXFAT_PROBE_ROOT)
void probePrintDirectoryBlock(DDRIVE *pdr, byte *b, dword cluster, dword sector, int nsectors);
void probePrintBootRegion(DDRIVE *pdr);
#endif
void pcexfat_filenameobj_destroy(EXFATFILEPARSEOBJ *pfilenameobj);
BOOLEAN pcexfat_filenameobj_init(DROBJ *pobj, byte *filename, EXFATFILEPARSEOBJ *pfilenameobj, int use_charset);
BOOLEAN pcexfat_findinbyfilenameobj(DROBJ *pobj, EXFATFILEPARSEOBJ *pfilenameobj, BOOLEAN oneshot, int action);
BOOLEAN exfatop_remove_free_region(DDRIVE *pdr, dword cluster, dword ncontig);
BOOLEAN exfatop_add_free_region(DDRIVE *pdr, dword cluster, dword ncontig, BOOLEAN do_erase);
word pcexfat_checksum_util(word Checksum, BOOLEAN isprimary, byte *string);
BOOLEAN pcexfat_link_file_chain(DDRIVE *pdr, REGION_FRAGMENT *pf);
BOOLEAN pcexfat_grow_directory(DROBJ *pobj);
REGION_FRAGMENT *pcexfat_load_root_fragments(DDRIVE *pdrive);
BOOLEAN _pcexfat_bfilio_reduce_size(PC_FILE *pefile, ddword new_size);
DROBJ *pcexfat_fndnode(DDRIVE *pdrive, byte *path, int use_charset);
void pcexfat_initialize_root_finode(DDRIVE *pdrive, FINODE *pfi);
BOOLEAN pcexfat_multi_dir_get(DROBJ *pobj, BLKBUFF **pscan_buff, byte **pscan_data, byte *puser_buffer, dword *n_blocks, BOOLEAN do_increment);
FATBUFF *pc_find_fat_blk_primary(FATBUFFCNTXT *pfatbuffcntxt, dword fat_sector_offset);
void pc_set_fat_blk_primary(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk);
void pc_clear_fat_blk_primary(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk);
FATBUFF *pc_find_fat_blk_secondary (FATBUFFCNTXT *pfatbuffcntxt, dword fat_sector_offset);
void pc_clear_fat_blk_secondary(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk);
void pc_set_fat_blk_secondary (FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk);
void pc_uncommit_fat_blk_queue(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk);
void pc_commit_fat_blk_queue(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk);
void pc_free_fat_blk(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk);
FATBUFF *pc_realloc_fat_blk(DDRIVE *pdrive, FATBUFFCNTXT *pfatbuffcntxt, dword fat_sector_offset);
BOOLEAN pc_write_bam_block_buffer_page(DDRIVE *pdrive, FATBUFF *pblk);
void set_bam_dirty(DDRIVE *pdr);
void clear_bam_dirty(DDRIVE *pdr);
void pc_free_all_bam_buffers(DDRIVE *pdr);
BOOLEAN pcexfat_insert_inode(DROBJ *pobj , DROBJ *pmom, byte _attr, FINODE *infinode, dword initcluster, byte *filename, byte secondaryflags, dword sizehi, dword sizelow, int use_charset);
BOOLEAN pcexfat_checkerased(byte *pi);
void pcexfat_addtoseglist(SEGDESC *s, dword my_block, int my_index);
dword preboot_pcclnext(DDRIVE *pdr, dword cluster, int *error);
void pcexfat_upcase_unicode_string(DDRIVE *pdr, word *to, word *from,int maxcount);
BOOLEAN exfatop_read_upCaseTable(DDRIVE *pdr);
byte *pc_data_in_ubuff(DDRIVE *pdr, dword blockno,byte *puser_buffer, dword user_buffer_first_block,dword user_buffer_n_blocks);
BOOLEAN pcexfat_rmnode(DROBJ *pobj);
BOOLEAN pcexfat_mvnode(DROBJ *old_parent_obj,DROBJ *old_obj,DROBJ *new_parent_obj, byte *filename,int use_charset);
BOOLEAN pcexfat_set_volume(DDRIVE *pdrive, byte *volume_label,int use_charset);
BOOLEAN pcexfat_get_volume(DDRIVE *pdrive, byte *volume_label,int use_charset);
BOOLEAN pcexfat_get_cwd(DDRIVE *pdrive, byte *path, int use_charset);
BOOLEAN pcexfat_set_cwd(DDRIVE *pdrive, byte *name, int use_charset);
BOOLEAN pcexfat_update_by_finode(FINODE *pfi, int entry_index, BOOLEAN set_archive, int set_date_mask, BOOLEAN do_delete);
void pcexfat_update_finode_datestamp(FINODE *pfi, BOOLEAN set_archive, int set_date_mask);
BOOLEAN pcexfat_flush(DDRIVE *pdrive);
dword exfatop_find_contiguous_free_clusters(DDRIVE *pdr, dword startpt, dword endpt, dword min_clusters, dword max_clusters, dword *p_contig, int *is_error);
BOOLEAN rtexfat_i_dskopen(DDRIVE *pdr);
void pc_release_exfat_buffers(DDRIVE *pdr);
BOOLEAN pcexfat_findin( DROBJ *pobj, byte *filename, int action, BOOLEAN oneshot, int use_charset);
byte *pcexfat_seglist2text(DDRIVE * pdrive, SEGDESC *s, byte *lfn, int use_charset);
dword exFatfatop_getdir_frag(DROBJ *pobj, dword startpt, dword *pnext_cluster, dword n_clusters, int *end_of_chain);
dword exFatfatop_getfile_frag(FINODE *pfi, dword startpt, dword *pnext_cluster, dword n_clusters, int *end_of_chain);
BOOLEAN pcexfat_gread(DSTAT *statobj, int blocks_to_read, byte *buffer, int *blocks_read);
BOOLEAN pcexfat_parse_path(DDRIVE *pdrive, byte *outpath, byte *inpath, int use_charset);
BOOLEAN rtexfat_gblk0(DDRIVE *pdr, struct pcblk0 *pbl0b, byte *b);
EXFATDDRIVE *pcexfat_pdrtoexfat(DDRIVE *pdr);
#define PDRTOEXFSTR(X) pcexfat_pdrtoexfat(X)
dword pcexfat_getexNOFATCHAINfirstcluster(DROBJ *pobj);
dword pcexfat_getexNOFATCHAINlastcluster(DROBJ *pobj);
BOOLEAN pcexfat_expand_nochain(FINODE *pefinode);
int pcexfat_bfilio_read(PC_FILE *pefile, byte *in_buff, int count);
BOOLEAN pcexfat_bpefile_ulseek(PC_FILE *pefile, ddword offset, ddword *pnew_offset, int origin);
BOOLEAN pcexfat_bfilio_write(PC_FILE *pefile, byte *in_buff, dword n_bytes, dword *n_written);
BOOLEAN pcexfat_bfilio_chsize(PC_FILE *pefile, ddword dwnew_size);
BOOLEAN _pcexfat_bfilio_flush(PC_FILE *pefile);
BOOLEAN pcexfat_bfilio_load_all_fragments(FINODE *pefinode);
BOOLEAN pc_exfat_check_disk(byte *driveid,DDRIVE *pdr,CHKDISK_STATS *pchkstat);
#define pcexfat_set_volume_dirty(A) /* Implement to set and clear dirty bytes in bpb */
#define pcexfat_clear_volume_dirty(A)
void pcexfat_getsysdate( DATESTR *pcrdate, byte *putcoffset, byte *pmsincrement);
DATESTR dwordToDateStr(dword indword);
dword pc_byte2clmod64(DDRIVE *pdr, dword nbytes_hi, dword nbytes_lo);
ddword pc_fragment_size_64(DDRIVE *pdr,REGION_FRAGMENT *pfragment);
#endif /* __RTFSEXFATPROTOS__ */

153
include/rtexfattypes.h Normal file
View File

@ -0,0 +1,153 @@
#ifndef __RTFSEXFATTYPES__
#define __RTFSEXFATTYPES__ 1
#define EXFATDIRENTSIZE 32
#define EXFATCHARSPERFILENAMEDIRENT 15
#define DEBUG_EXFAT_VERBOSE 0 /* Set to one to turn on diagnostics using rtfs console IO. */
#define DEBUG_EXFAT_PROBE_ROOT 0 /* Set to one to dump root directory info (requires printf) */
#define EXFAT_DIRENTTYPE_EOF 0x00
#define EXFAT_DIRENTTYPE_ALLOCATION_BITMAP 0x81
#define EXFAT_DIRENTTYPE_UPCASE_TABLE 0x82
#define EXFAT_DIRENTTYPE_VOLUME_LABEL 0x83
#define EXFAT_DIRENTTYPE_FILE 0x85
#define EXFAT_DIRENTTYPE_GUID 0xA0
#define EXFAT_DIRENTTYPE_STREAM_EXTENSION 0xC0
#define EXFAT_DIRENTTYPE_FILE_NAME_ENTRY 0xC1
#define EXFAT_DIRENTTYPE_VENDOR_EXTENSION 0xE0
#define EXFAT_DIRENTTYPE_VENDOR_ALLOCATION 0xE1
#define EXFAT_DIRENTTYPE_ABM 0x81 /* Allocation bit map */
#define EXFATDIRENTFIRSTCLOFFSET 20
#define EXFATDIRENTLENGTHOFFSET 24
#define EXFATALLOCATIONPOSSIBLE 0x1
#define EXFATNOFATCHAIN 0x2
#define EXFATEOFCLUSTER 0xffffffff
#define EXFATBADCLUSTER 0xfffffff7
#define STANDARD_UCTABLE_SIZE 5836 /* bytes */
#define STANDARD_UCTABLE_CHECKSUM 0xe619d30d
extern const word cStandarducTableCompressed[STANDARD_UCTABLE_SIZE/2];
extern const word cStandarducTableunCompressed[65536];
/* HEREHERE Ifdefs around "hacks" to expedite getting a working prototype */
/* For now always extend directories, need to study microsoft's scheme they seem to extend only on the end, maybe they recycle at end of cluster. */
/* Commented out, means we reclaim directory entries as needed. */
/* #define EXFAT_EXTEND_DIRECTORIES_FROM_END_ONLY */
typedef struct exfatfileentry {
byte EntryType;
byte SecondaryCount;
word SetChecksum;
word FileAttributes;
byte Reserved1[2];
DATESTR CreateTimeStamp;
DATESTR LastModifiedTimeStamp;
DATESTR LastAccessedTimeStamp;
byte Create10msIncrement;
byte LastModified10msIncrement;
byte CreateUtcOffset;
byte LastModifiedUtcOffset;
byte LastAccessedUtcOffset;
byte Reserved2[7];
} EXFATFILEENTRY;
typedef struct exfatstreamextensionentry {
byte EntryType;
byte GeneralSecondaryFlags;
byte Reserved1;
byte NameLen;
word NameHash;
byte Reserved2[2];
ddword ValidDataLength;
byte Reserved3[4];
dword FirstCluster;
ddword DataLength;
} EXFATSTREAMEXTENSIONENTRY;
typedef struct exfatfilenameentry {
byte EntryType;
byte GeneralSecondaryFlags;
word FileName[15];
} EXFATFILENAMEENTRY;
typedef struct exfatdirscancontrol {
/* Control elements for scanning */
byte expected_entry_type;
byte NameLen;
int NameLenProcessed;
word CheckSumExpected;
byte secondary_entries_expected;
byte secondary_entries_found;
dword spans_sectors[3];
int first_index;
} EXFATDIRSCANCONTROL;
typedef struct exfatdirscan {
byte rawfileentry[32];
byte rawstreamextensionentry[32];
byte rawfilenamedata[512];
/* Control elements for scanning */
EXFATDIRSCANCONTROL control;
} EXFATDIRSCAN;
typedef struct exfatdateext {
byte Create10msIncrement;
byte LastModified10msIncrement;
byte CreateUtcOffset;
byte LastModifiedUtcOffset;
byte LastAccessedUtcOffset;
} EXFATDATEEXT;
/* See pc_allocate_exfat_buffers() and callback code */
typedef struct exfatmountparms {
/* Passed from Rtfs to the callback handler for RTFS_CBS_GETEXFATBUFFERS */
int driveID; /* 0-25 == A:-Z: */
void *pdr; /* Caste to acceess rtf drive structure directly */
dword SectorSizeBytes;
/* Bitmap info passed */
dword BitMapSizeSectors; /* Optimal size for bitmap */
/* UpCase Table Info */
dword UpcaseSizeBytes; /* Size for upcase table */
/* Bitmap Caching stuff returned here */
dword BitMapBufferSizeSectors; /* Returned space for buffering */
int BitMapBufferPageSizeSectors;
void *BitMapBufferCore;
void *BitMapBufferControlCore;
/* UpCase Table stuff returned note must return at least minimum. */
void *UpCaseBufferCore;
} EXFATMOUNTPARMS;
typedef struct exfatfileparseobj {
BLKBUFF *pUpCasedFileNameBuffer;
BLKBUFF *pUnicodeFileNameBuffer;
word *upCasedLfn;
word *UnicodeLfn;
int use_charset;
byte *pInputFile;
int NameSegments;
byte NameLen;
word NameHash;
/* If we are seeking to add to the entry */
int segmentsRequired; /* Find this many free segments please */
SEGDESC Freesegments; /* Here is the answer */
} EXFATFILEPARSEOBJ;
#endif /* __RTFSEXFATTYPES__ */

45
include/rtfs.h Normal file
View File

@ -0,0 +1,45 @@
/*****************************************************************************
*Filename: RTFS.H - Defines & structures for RTFS ms-dos utilities
*
*
* EBS - RTFS (Real Time File Manager)
*
* Copyright Peter Van Oudenaren , 1993
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
*
*
* Description:
*
*
*
*
****************************************************************************/
#ifndef __RTFS__
#define __RTFS__ 1
#include <stdio.h> // Remove if not experimenting
#include "rtfsversion.h" /* defines RTFS_MAJOR_VERSION, RTFS_MINOR_VERSION and RTFS_MINOR_REVISION */
#include "rtfsconf.h" /* Include compile time RTFS configuration, architecture and basic types */
#include "rtfsblkmedia.h"
#include "rtfstypes.h" /* Include basic rtfs declarations with ProPlus elements included if needed */
#if (INCLUDE_EXFAT) /* Include rtexfattypes.h */
#include "rtexfattypes.h"
#endif
#include "rtfserr.h" /* Include errno values */
#include "rtfsprotos.h" /* Include basic rtfs prototypes */
#if (INCLUDE_EXFAT) /* Include rtexfatprotos.h */
#include "rtexfatprotos.h"
#endif
#if (INCLUDE_FAILSAFE_CODE)
#include "rtfsfailsafe.h" /* Include rtfs proplus failsafe declarations */
#endif
#if (INCLUDE_FLASH_MANAGER)
#include "flashmgrcfg.h"
#endif
#endif /* __RTFS__ */

106
include/rtfsarch.h Normal file
View File

@ -0,0 +1,106 @@
/*****************************************************************************
*Filename: RTFSARCH.H - RTFS CPU and Host configuration
*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc, 2006
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
* Description:
* This file contains CPU and Host configuration constants and types
* It is included by rtfsconf.h
*
****************************************************************************/
#ifndef __RTFSARCH__
#define __RTFSARCH__ 1
/* Define RTFS_LINUX or RTFS_WINDOWS if we are running in an emulation environment
select between linux and windows
*/
#ifdef __GNUC__
#define RTFS_LINUX
#endif
#ifdef _MSC_VER
#define RTFS_WINDOWS
#define _CRT_SECURE_NO_WARNINGS 1 /* Disabe warnings about using insecure string functions */
#endif
/* If TMS320C6X we are not running in emulation mode */
/* CPU Configuration section */
#define KS_LITTLE_ENDIAN 1 /* See reference guide for explanation */
#define KS_LITTLE_ODD_PTR_OK 0 /* See reference guide for explanation */
#define INCLUDE_NATIVE_64_TYPE 1 /* ProPlus only, ignore for Pro
See reference guide for explanation */
/* Asserts for unexpected conditions are compiled into Rtfs using the macros
ERTFS_ASSERT(X) and ERTFS_ASSERT_TEST(X) see See rtfsarch.h.
if INCLUDE_DEBUG_TRUE_ASSERT is enabled then these asserts use the compiler's
assert((X)); call otherwise they result in callbacks rtfs_diag_callback() with
arguments RTFS_CBD_ASSERT and RTFS_CBD_ASSERT_TEST respectively. */
#define INCLUDE_DEBUG_TRUE_ASSERT 1
/********************************************************************
TYPES
********************************************************************/
#if (!defined(TRUE))
#define TRUE 1 /* Don't change */
#endif
#if (!defined(FALSE))
#define FALSE 0 /* Don't change */
#endif
typedef unsigned char byte; /* Don't change */
typedef unsigned short word; /* Don't change */
#ifdef _TMS320C6X
/* If TMS320C6X we are not running in emulation mode */
typedef unsigned int dword; /* Don't change */
#define INCLUDE_THREAD_SETENV_SUPPORT 1 /* Use rtfs_port_set_task_env() and rtfs_port_get_task_env() for binding thread to user structure */
#define INCLUDE_THREAD_EXIT_CALLBACK 0 /* Thread exits are supported but configured in project files */
#undef INCLUDE_NATIVE_64_TYPE
#define INCLUDE_NATIVE_64_TYPE 0
#undef KS_LITTLE_ODD_PTR_OK
#define KS_LITTLE_ODD_PTR_OK 0
#define RTFS_CACHE_LINE_SIZE_IN_BYTES 128u
#define RTFS_CACHE_ALIGN_POINTER(POINTER)(void*)(((dword)((POINTER) + ((RTFS_CACHE_LINE_SIZE_IN_BYTES) - (1U)))) & (~((RTFS_CACHE_LINE_SIZE_IN_BYTES) - (1U))))
#else
#define INCLUDE_THREAD_SETENV_SUPPORT 0 /* Use task id for binding thread to user structure */
#define INCLUDE_THREAD_EXIT_CALLBACK 0 /* Set to one if you can support thread exit handling */
typedef unsigned long dword; /* Don't change */
#define RTFS_CACHE_LINE_SIZE_IN_BYTES 0
#define RTFS_CACHE_ALIGN_POINTER(POINTER) (void*)(POINTER)
#endif
#define BOOLEAN int /* Don't change */
#define KS_CONSTANT const
#if (INCLUDE_MATH64) /* ddword type, ProPlus only */
#if (INCLUDE_NATIVE_64_TYPE)
#define ddword unsigned long long
#else
typedef struct _ddword
{
dword hi;
dword lo;
} ddword; /* ddword data type works with the M64XXXX macro package */
#endif
#endif
#if (INCLUDE_DEBUG_TRUE_ASSERT)
#include <assert.h>
#define ERTFS_ASSERT_TEST(X) assert((X));
#define ERTFS_ASSERT(X) assert((X));
#else
#define ERTFS_ASSERT(X) if (!(X)) {rtfs_assert_break();}
#define ERTFS_ASSERT_TEST(X) if (!(X)) {rtfs_assert_test();}
#endif
#endif /* __RTFSARCH__ */
/*
* @(#) ti.rtfs.config; 1, 0, 0, 0,17; 1-20-2009 17:04:20; /db/vtree/library/trees/rtfs/rtfs-a18x/src/
*/

354
include/rtfsblkmedia.h Normal file
View File

@ -0,0 +1,354 @@
/*
Header files.
The media interface sits between Rtfs and a block media driver. It is not desirable for the media driver to include
Rtfs header files or for Rtfs to include media media driver header files, so a single header file, rtfsblkmedia.h, is provided.
This file is included by both systems and includes all prototype and interface parameter definitions.
Data types used to interface between Rtfs and the media layer.
- As much as possible the native types int and void * are used.
- Unsigned 32 bit values are passed using the metatype "dword".
Note: Use fixed bas, max partitions for driveid allocs..
Functions provided by The Rtfs to be called by block media drivers:
Functions provided by Rtfs to be called by block media drivers:
The following functions are to be called by the media driver to interface with Rtfs. Detailed descriptions of the functions and
int pc_ertfs_init(void);
Note: init must call config
- Must be called before the blkmedia interface is used. May be called in the initialization code of the media driver
void pc_rtfs_shutdown(void);
- Called by the media layer to request Rtfs to release all memory and operating system resources.
int pc_rtfs_media_insert(struct rtfs_media_insert_args *pargs);
- Must be called by the media driver when a fixed device is detected at start up or when a removable device is inserted.
the rtfs_media_insert_args structure is described below below.
void pc_rtfs_media_alert(void *devicehandle, int alertcode, void *vargs);
- Called by the device driver to alert Rtfs of status changes for the the device.
Currently called when:
RTFS_ALERT_EJECT - A removable device is ejected or a fixed device is shut down.
RTFS_ALERT_WPSET - When write protect status changes to set.
RTFS_ALERT_WPCLEAR - When write protect status changes to clear.
- Other uses such as power management handshaking may be added at a later time.
Functions provided by the block media driver to be called by Rtfs. These functions are not called directly by Rtfs but are called through
function pointers provided by the media driver in pc_rtfs_media_insert().
int (*device_io) (void *devhandle, void *pdrive, dword sector, void *buffer, dword nsectors, int reading);
int (*device_erase)(void *devhandle, dword start_sector, dword nsectors);
int (*device_ioctl)(void *devhandle, void *pdrive, int opcode, int iArgs, void *vargs);
Detailed interface definitions:
int pc_rtfs_ertfs_init(void) - Instruct Rtfs to allocate global structures and buffers and to allocate and initialize operating system
resources.
One or more two mutex semaphores, depending on configuration values, are allocated by calling rtfs_port_alloc_mutex()
If static allocation is used, (RTFS_CFG_MEM == RTFS_CFG_STATIC), existing structures are simply initialized.
If dynamic allocation is used, (RTFS_CFG_MEM == RTFS_CFG_DYNAMIC), structures are alocated by calling rtfs_port_malloc() and are
then initialized.
Returns 0 if all resources were succesfully initialized.
Returns -1 if resource or memory allocation failed.
void pc_rtfs_shutdown(void) - May be called by the media layer to request Rtfs to release all memory and operating system resources.
Rtfs releases all memory and operating system resources that were allocated by pc_rtfs_init().
Rtfs releases all memory and operating system resources that were allocated by any outstanding mounts.
Rtfs may be reinitialized by calling pc_rtfs_init().
int pc_rtfs_media_insert(struct rtfs_media_insert_args *pargs) - Must be called by the media driver when a fixed device is detected at start
up or when a removable device is inserted.
Media driver must provide a properly initialized rtfs_media_insert_args structure.
Returns 1 if the device mount succeeded.
Returns 0 if rtfs_media_insert_args contains invalid values or if too many devices are mounted for the current configuration to
support, if a calll to rtfs_port_alloc_mutex() fails, or, if RTFS_CFG_MEM == RTFS_CFG_DYNAMIC and a calll to rtfs_port_malloc() faails.
The following fields must be initialized in the rtfs_media_insert_args structure, prior to passing it to pc_rtfs_media_insert().
void *devhandle; This value may not be zero and it must be unique for each device.
It is used as a handle when Rtfs calls the device_io(), device_ioctl() and device_erase() functions.
A convenient pointer or integer indexing scheme should be used calls can be efficiently redirected to the
appropriate underlying device drivers.
The media driver must pass this handle to Rtfs when calling pc_rtfs_media_alert().
int device_type; This field must be initialized with a device type. The device type field is used by code in rtfsdeviceconfig.c
to configure buffering for the device when it is mounted. No other Rtfs modules rely on or know about the
device type filed.
The currently set of device type constants includes BLK_DEVICE_TYPE_MMC, BLK_DEVICE_TYPE_NAND and
BLK_DEVICE_TYPE_USB. To add a new device types you must add a new constant to rtfsblkmedia.h and modify
rtfsdeviceconfig.c.
int unit_number; This field contains the instance of the device type that was just installed. For example if two MMC cards are
installed then pc_rtfs_media_insert() is called twice. In both instance the device_type filed contains BLK_DEVICE_TYPE_MMC,
but the unit_number filed contains 0 and 1 respectively.
int write_protect; This field contains the initial device write protect status. If the device is write protected it should
be set to one, if not it should be cleared. The media driver may inform Rtfs of a change in write
write protect status status by calling pc_rtfs_media_alert() using the arguments RTFS_ALERT_WPSET,
or RTFS_ALERT_WPCLEAR.
int (*device_io) (..) This field must contain a pointer to a function that Rtfs will use to read and write sectors to the media.
The function protoype is:
int device_io(void *devhandle, dword Sector, void *buffer, dword SectorCount, int reading);
- devhandle will be the value passed in the devhandle field of this structure.
- pdrive is void pointer that may be cast to and Rtfs (DDRIVE *) pointer. Intelligient device drivers may
access Rtfs drive structure fields to modify behavior based on the volume region beign accessed.
- Sector, buffer and SectorCount are the sector number buffer to transfer to or from and number
of sectors, respectively.
- reading is 1 if the request is a read or zero iif the request is a write.
The function must return 1 if the request succeeded.
The function must return 0 if the request failed.
int (*device_erase)(..) This field must contain a pointer to a function that Rtfs will use to erase sectors on the media. The function is
only needed for devices with erase blocks, like nand, and it is called only if the eraseblock_size_sectors field
is initialized with a non zero value. For media that does not support erase blocks you may set this value to
zero.
The function protoype is:
int device_erase(void *devhandle, dword start_sector, dword nsectors);
- devhandle is the value passed in the devhandle field of this structure.
- pdrive is void pointer that may be cast to and Rtfs (DDRIVE *) pointer. Intelligient device drivers may
access Rtfs drive structure fields to modify behavior based on the volume region beign accessed.
- Sector, and SectorCount are the sector range to erase. They are guaranteed to be on erase block
boundaries if the media was partitioned and formatted by Rtfs, but the media layer should verify
that the sectors are erase block bound before erasing. If they are not it should return success.
The function must return 1 if the request succeeded.
The function must return 0 if the request failed.
int (*device_ioctl) (..) This field must contain a pointer to a function that Rtfs will call when special operations are
required.
The function protoype is:
int device_ioctl(void *devhandle, int opcode, int iArgs, void *vargs);
- devhandle will be the value passed in the devhandle field of this structure.
- pdrive is void pointer that may be cast to and Rtfs (DDRIVE *) pointer. Intelligient device drivers may
access Rtfs drive structure fields to modify behavior based on the volume region beign accessed.
- opcode is the request.
Current opcodes are:
RTFS_IOCTL_FORMAT - Physically format the device. Just return 1 if no format is needed.
NAND drivers may erase the media from this call.
RTFS_IOCTL_FLUSH - pc_diskflush() was called, flush caches if the driver is caching sectors
- iArgs and vargs are for passing argument from Rtfs to the media driver, they are currently not used.
The function must return 1 if the request succeeded.
The function must return 0 if the request failed.
int (*device_configure)(..)
The function protoype is:
int (*device_configure)(struct rtfs_media_insert_args *pmedia_parms,
struct rtfs_media_resource_request *media_config_block, int sector_buffer_required);
dword media_size_sectors - The total number of addressable sectors logical sectors on the media
dword numheads - HCN reprenenation of media_size_sectors, These values are not used by Rtfs but they are written into
dword numcyl - MBR and BPB records during partitioning and formatting and thus must be valid FAT HCN values.
dword secptrk - The maximum allowable value for numheads is 255, for secptrk is 63 and for numcy is 1023.
dword sector_size_bytes - The sector size in bytes: 512, 2048, etc. Must be >= 512 and a power of 2
dword eraseblock_size_sectors - Sectors per erase block for nand flahs device, 0 for media without erase blocks
*/
#ifndef __RTFSBLKMEDIA__
#define __RTFSBLKMEDIA__
/* To avoid namespace clashes we allow device drivers to build without requiring Rtfs. We use simple types except for 32 bit values.
If rtfs.h is included use the dword declaration. If not typedef dword here */
#ifndef __RTFSARCH__
#ifdef _TMS320C6X
typedef unsigned int dword;
#else
typedef unsigned long dword;
#endif
#endif
/* rtfs_init_resource_reply, Passed by rtfs to rtfs_init_configuration(). Must be initialized and returned Rtfs. */
struct rtfs_init_resource_reply
{
int max_drives; /* The number of drives to support */
int max_scratch_buffers; /* The number of scratch block buffers */
int max_files; /* The maximum number files */
int max_user_contexts; /* The number of user context (seperate current working directory, and errno contexts) */
int max_region_buffers; /* The number of cluster region management objects */
int spare_user_directory_objects; /* Spare directory objects, not user configurable */
int spare_drive_directory_objects; /* Spare directory objects, not user configurable */
int use_dynamic_allocation; /* Set to one to request Rtfs to dynamically allocate system wide resources, otherwise resources are
assigned from static arrays by the function rtfs_init_structures_and_buffers() contained in the
same source file as rtfs_init_configuration() */
int run_single_threaded; /* Set to one to force Rtfs to run single threaded. In single threaded mode all api calls of all drives
use the same semaphore and thus execute sequentially. This eliminates the need for indifual user
buffers and failsafe restore buffers per drive, resulting in reduced memory consumption, with
marginal to no performance degradation in most system */
/* run_single_threaded is selected these values must be provided, single_thread_buffer_size refers to the size of the "user buffer"
to share amongst all drives, while single_thread_fsbuffer_size refers to the failsafe shared restor buffer size.
Note: these values should be large enough to efficiently accomodate the device with the largest buffering requirements.
For best performance systems with nand flash should set single_thread_buffer_size to at least as large as an erase block
and single_thread_fsbuffer_size to at least as large an and erase block plus one sector. */
dword single_thread_buffer_size;
dword single_thread_fsbuffer_size; /* Set to zero if not using failsafe */
/* The following fields are populated with the addresses of free memory blocks large enough to accomodate the configurations
prescribed in the previous fields.
If use_dynamic_allocation is enabled then Rtfs calls the internal subroutine rtfs_dynamic_init_configuration() to allocate the memory.
If use_dynamic_allocation is not enabled then Rtfs calls the subroutine rtfs_init_structures_and_buffers() to assign the pointers from
statically declared memory. */
void *single_thread_buffer;
void *single_thread_fsbuffer;
void *mem_drive_pool;
void *mem_mediaparms_pool;
void *mem_block_pool;
void *mem_block_data;
void *mem_file_pool;
void *mem_finode_pool;
#if (INCLUDE_RTFS_PROPLUS) /* ProPlus specific configuration constatnts */
void *mem_finodeex_pool;
#endif
void *mem_drobj_pool;
void *mem_region_pool;
void *mem_user_pool;
void *mem_user_cwd_pool;
};
/* rtfs_media_resource_reply, Passed by rtfs to rtfs_devcfg_configure_device(). Must be initialized and returned to Rtfs. */
struct rtfs_media_resource_reply
{
int use_dynamic_allocation;
int requested_driveid;
int requested_max_partitions;
int use_fixed_drive_id;
dword device_sector_buffer_size_bytes;
byte *device_sector_buffer_base;
void *device_sector_buffer_data;
};
struct rtfs_volume_resource_request
{
void *devhandle; /* Device driver access Handle */
int device_type; /* Device type returned by device_configure_media() */
int unit_number; /* Unit number type returned by device_configure_media() */
int driveid; /* Drive letter (0 - 25) */
int partition_number; /* Which partition is it */
dword volume_size_sectors; /* Total number of addressable sectors on the partition or media containing the volume */
dword sector_size_bytes; /* Sector size in bytes: 512, 2048, etc */
dword eraseblock_size_sectors;/* Sectors per erase block. Zero for media without erase blocks */
int buffer_sharing_enabled; /* If 1, Rtfs is configured to shared sector buffers and failsafe restore buffers and these buffers are not required */
int failsafe_available; /* If 1, failsafe is availabe and operating policy and failsafe buffering may select failsafe */
};
/* rtfs_volume_resource_reply, Passed by rtfs to rtfs_devcfg_configure_volume(). Must be initialized and returned to Rtfs. */
struct rtfs_volume_resource_reply
{
int use_dynamic_allocation;
dword drive_operating_policy; /* drive operating policy, see Rtfs manual */
dword n_sector_buffers; /* Total number of sector sized buffers (used for director buffers and scratch sectors */
dword n_fat_buffers; /* Total number of FAT buffers */
dword fat_buffer_page_size_sectors; /* Number of sectors per FAT buffer */
dword n_file_buffers; /* Total number of file buffers */
dword file_buffer_size_sectors; /* file buffer size in sectors */
dword fsrestore_buffer_size_sectors;/* Failsafe restore buffer size in sectors */
dword fsindex_buffer_size_sectors; /* Failsafe index buffer size in sectors must be at least 1 */
dword fsjournal_n_blockmaps; /* number of Failsafe sector remap records provided.
Determines the number of outstanding remapped sectors permitted */
/* Memory returned values */
/* These arrays do not require address alignment */
void *blkbuff_memory; /* 1 element must be sizeof(BLKBUFF)(sizeof(BLKBUFF)=40) * (n_sector_buffers) bytes wide */
void *fatbuff_memory; /* 1 element must be sizeof(FATBUFF)(sizeof(FATBUFF)=40) * n_fat_buffers) bytes wide */
void *filebuff_memory; /* 1 element must be sizeof(BLKBUFF)(sizeof(BLKBUFF)=40) * (n_file_buffers) bytes wide */
void *fsfailsafe_context_memory; /* Failsafe context block */
void *fsjournal_blockmap_memory; /* 1 element must be (fsjournal_n_blockmaps * sizeof(FSBLOCKMAP)) bytes. sizeof(FSBLOCKMAP) equals 16 */
/* These arrays do require IO address alignment if that is a system requirement
If dynamic allocation is being used these pointers contain the addresses that were returned from os_port_malloc()
If dynamic allocation is not used these pointers contain addresses of properly alligned data blocks */
byte *sector_buffer_base; /* Unaligned sector buffer heap, returns from malloc */
byte *file_buffer_base; /* Unaligned file buffer heap, returns from malloc */
byte *fat_buffer_base; /* Unaligned fat buffer heap, returns from malloc */
byte *failsafe_buffer_base;
byte *failsafe_indexbuffer_base;
/* These pointers contain arrays do require IO address alignment if that is a system requirement */
void *sector_buffer_memory; /* n_sector_buffers * sector_size bytes wide */
void *file_buffer_memory; /* n_file_buffers * sector_size bytes wide */
void *fat_buffer_memory; /* n_fat_buffers * fat_buffer_page_size_sectors * sector_size bytes wide */
void *failsafe_buffer_memory; /* 1 element must be (fsrestore_buffer_size_sectors * sector_size) bytes */
void *failsafe_indexbuffer_memory; /* 1 element must be sector_size bytes */
};
/* rtfs_media_insert_args structure, must be initialized prior to passing it to pc_rtfs_media_insert(). */
struct rtfs_media_insert_args
{
void *devhandle; /* Handle Rtfs will pass to device_io() and other functions. devhandle is opaque to rtfs */
int device_type; /* Used by blk dev driver layer. device mount sets it, volume mount may use it to configure buffering */
int unit_number; /* which instance of this device */
int write_protect; /* initial write protect state of the device. Rtfs will not write if this is non zero */
int (*device_io) (void *devhandle, void *pdrive, dword sector, void *buffer, dword count, BOOLEAN reading);
int (*device_erase)(void *devhandle, void *pdrive, dword start_sector, dword nsectors);
int (*device_ioctl)(void *devhandle, void *pdrive, int opcode, int iArgs, void *vargs);
int (*device_configure_media) (struct rtfs_media_insert_args *pmedia_parms, struct rtfs_media_resource_reply *media_config_block, int sector_buffer_required);
int (*device_configure_volume)(struct rtfs_volume_resource_request *prequest_block, struct rtfs_volume_resource_reply *preply_block);
dword media_size_sectors; /* Total number of addressable sectors on the media */
dword numheads; /* cylinder, head, sector representation of the media. */
dword numcyl; /* Note: must be valid FAT HCN values. max cyl = 1023, max heads == 255, max sectors = 63 */
dword secptrk;
dword sector_size_bytes; /* Sector size in bytes: 512, 2048, etc */
dword eraseblock_size_sectors; /* Sectors per erase block. Set to zero for media without erase blocks */
};
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __RTFSPROTOS__
int pc_rtfs_ertfs_init(void);
void pc_ertfs_shutdown(void);
#endif
BOOLEAN RTFS_DEVI_io(int driveno, dword sector, void *buffer, word count, BOOLEAN reading);
int pc_rtfs_media_insert(struct rtfs_media_insert_args *pmedia_parms);
void pc_rtfs_media_alert(void *devicehandle, int alertcode, void *vargs);
void rtfs_init_configuration(struct rtfs_init_resource_reply *preply);
void pc_rtfs_free_mutex(dword semaphore);
dword pc_rtfs_alloc_mutex(char* name);
void *pc_rtfs_malloc(dword alloc_size);
#ifdef __cplusplus
}
#endif
/* Alert codes that may be passed to Rtfs from the device driver by pc_rtfs_media_alert() */
#define RTFS_ALERT_EJECT 1
#define RTFS_ALERT_WPSET 2
#define RTFS_ALERT_WPCLEAR 3
/* OPCODES codes passed to the device driver from Rtfs by (*device_io)(*device_io) */
#define RTFS_IOCTL_FORMAT 1
#define RTFS_IOCTL_INITCACHE 2
#define RTFS_IOCTL_FLUSHCACHE 3
#define RTFS_IOCTL_SHUTDOWN 4
#endif /* __RTFSBLKMEDIA__ */
/*
* @(#) ti.rtfs.config; 1, 0, 0, 0,17; 1-20-2009 17:04:20; /db/vtree/library/trees/rtfs/rtfs-a18x/src/
*/

323
include/rtfsconf.h Normal file
View File

@ -0,0 +1,323 @@
/*****************************************************************************
*Filename: RTFSCONF.H - RTFS tuning constants
*
*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc, 2006
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
* Description:
* This file contains tuning constants for configuring RTFS.
* It is included by rtfs.h
*
****************************************************************************/
/* Code sizes.. */
#ifndef __RTFSCONF__
#define __RTFSCONF__ 1
/* This is the release configuration, rtfspackage.h is configured for purchased options */
// #include "rtfspackage.h"
#if (1) /* Option selections for inernal development */
/* Identify purchased options: Use the column of values underneath the package name for the named package.
Rtfs Rtfs Rtfs Rtfs Rtfs Rtfs Rtfs Rtfs Rtfs
BASIC PRO PRO PROPLUS PROPLUS PROPLUS64 PROPLUS64 PROPLUSDVR PROPLUSDVR
FAILSAFE FAILSAFE FAILSAFE FAILSAFE */
#define INCLUDE_RTFS_BASIC_ONLY 0 /* 1 0 0 0 0 0 0 0 0 */
#define INCLUDE_RTFS_PROPLUS 0 /* 0 0 0 1 1 1 1 1 1 */
#define INCLUDE_RTFS_FAILSAFE_OPTION 0 /* 0 0 1 0 1 0 1 0 1 */
#define INCLUDE_RTFS_DVR_OPTION 0 /* 0 0 0 0 0 0 0 1 1 */
#define INCLUDE_EXFAT 0
#define INCLUDE_MATH64 0
#define INCLUDE_FAT64 0
#define INCLUDE_EXFATORFAT64 (INCLUDE_EXFAT||INCLUDE_FAT64)
#if (INCLUDE_EXFATORFAT64||INCLUDE_RTFS_DVR_OPTION)
#undef INCLUDE_MATH64
#define INCLUDE_MATH64 1
#endif
#endif
#if (INCLUDE_RTFS_DVR_OPTION)
#define INCLUDE_EXTENDED_ATTRIBUTES 1
#else
#define INCLUDE_EXTENDED_ATTRIBUTES 0
#endif
#if (INCLUDE_EXFATORFAT64&&(INCLUDE_RTFS_PROPLUS==0))
#if (INCLUDE_RTFS_FAILSAFE_OPTION)
#error Failsafe-exFAT-RtfsPro only is untested
#else
// #error Known error in the regresion test for this combination
#endif
#endif
#define INCLUDE_FLASH_MANAGER 0
#define EXRAM
#define EXFAT_FAVOR_CONTIGUOUS_FILES 1 /* exFat only should be one, set to zero to force exfat to always scavenge clusters from the beginning
otherwise pdr->drive_info.free_contig_pointer is updated as a hint where to allocate from */
/* Note: Not all options are supported for all Rtfs configurations. Consult the porting and
configuration guided for documentation on individual configurations */
/* Character set support */
#define INCLUDE_CS_JIS 1 /* Set to 1 to support JIS (kanji) */
#define INCLUDE_CS_UNICODE 0 /* Set to 1 to support unicode */
#define INCLUDE_CS_ASCII (!INCLUDE_CS_JIS) /* Do not change support ASCII if JIS not enabled */
#if (INCLUDE_EXFATORFAT64) /* Unicode must be on for exFat */
#undef INCLUDE_CS_UNICODE
#define INCLUDE_CS_UNICODE 1 /* Do not change UNICODE must be enabled if Exfat enabled */
#endif
#define INCLUDE_NAND_DRIVER 1 /* See porting and configuration guide for explanation */
#define INCLUDE_TRANSACTION_FILES 0 /* Define 1 to include RTFS PRO PLUS transaction file. INCLUDE_FAILSAFE_CODE must also be enabled */
/* Debug settings */
#define INCLUDE_DEBUG_RUNTIME_STATS 1 /* See porting and configuration guide for explanation */
#define INCLUDE_DEBUG_LEAK_CHECKING 0 /* See porting and configuration guide for explanation */
#define INCLUDE_DEBUG_VERBOSE_ERRNO 0 /* See porting and configuration guide for explanation */
#define INCLUDE_DEBUG_TEST_CODE 1 /* See porting and configuration guide for explanation */
#define INCLUDE_FAT16 1 /* Set to 1 to support 12 and 16 bit FATs */
#define INCLUDE_FAT32 1 /* Set to 1 to support 32 bit FATs */
/* Note: After we implemented VFAT we learned that Microsoft patented
the Win95 VFS implementation. US PATENT # 5,758,352.
Leaving VFAT set to zero will exclude potential patent infringment problems. */
#define INCLUDE_VFAT 1 /* Set to 1 to support long filenames */
#define INCLUDE_BASIC_POSIX_EMULATION (INCLUDE_RTFS_PROPLUS == 0) /* Must select BASIC Posix emulation for Basic Only */
#define INCLUDE_CIRCULAR_FILES INCLUDE_RTFS_DVR_OPTION
#define INCLUDE_FAILSAFE_CODE INCLUDE_RTFS_FAILSAFE_OPTION
#define INCLUDE_FAILSAFE_RUNTIME INCLUDE_RTFS_FAILSAFE_OPTION
#if (!INCLUDE_RTFS_FAILSAFE_OPTION)
#undef INCLUDE_TRANSACTION_FILES
#define INCLUDE_TRANSACTION_FILES 0
#endif
/* Set to one to include high performance freespace manager */
#define INCLUDE_RTFS_FREEMANAGER 1
/* Set to one to include RTFS asyncronous API */
#define INCLUDE_ASYNCRONOUS_API 1
/* Set to 1 to support extended DOS partitions */
#define SUPPORT_EXTENDED_PARTITIONS 1
#if (SUPPORT_EXTENDED_PARTITIONS)
#define RTFS_MAX_PARTITIONS 16 /* Should be no need to change */
#else
#define RTFS_MAX_PARTITIONS 4 /* Do not change */
#endif
/* Set to 1 to support reverse directory enumeration */
#define INCLUDE_REVERSEDIR 0
#define RTFS_CFG_DEFAULT_SECTOR_SIZE_BYTES 512 /* Should be no need to change */
#define RTFS_CFG_LEAN 0 /* See porting and configuration guide for explanation */
#define RTFS_CFG_READONLY 0 /* See porting and configuration guide for explanation */
#define RTFS_CFG_MAX_DIRENTS 32768 /* See porting and configuration guide for explanation */
#if (!INCLUDE_RTFS_PROPLUS)
#undef INCLUDE_TRANSACTION_FILES
#undef INCLUDE_ASYNCRONOUS_API
#define INCLUDE_TRANSACTION_FILES 0
#define INCLUDE_ASYNCRONOUS_API 0
#endif
#if (INCLUDE_RTFS_BASIC_ONLY)
#undef INCLUDE_CS_UNICODE
#undef INCLUDE_VFAT
#undef INCLUDE_FAT16
#undef INCLUDE_FAT32
#undef INCLUDE_RTFS_FREEMANAGER
#define INCLUDE_CS_UNICODE 0
#define INCLUDE_VFAT 0
#define INCLUDE_FAT16 1
#define INCLUDE_FAT32 0
#define INCLUDE_RTFS_FREEMANAGER 0
#endif
#include "rtfsarch.h"
#if (INCLUDE_EXFATORFAT64&&INCLUDE_RTFS_PROPLUS)
#if (INCLUDE_NATIVE_64_TYPE==0)
#error PROPlus for 64 bit file system needS native 64 bit support
#endif
#endif
#define RTFS_FREE_MANAGER_HASHSIZE 32 /* Do not change */
/*
Note: These 2 constants are rather arcane and apply only to
RtfsPro style (po_xxx) functions. They can be left as is
The maximum file size RtfsPro style functions may create
When po_chsize() is called with a size request larger than this it
fails and set errnoto PETOOLARGE. When po_write() is asked to extend
the file beyond this maximum the behavior is determined by the value of
RTFS_TRUNCATE_WRITE_TO_MAX */
#define RTFS_MAX_FILE_SIZE 0xffffffff
/* #define RTFS_MAX_FILE_SIZE 0x80000000 */
/* Set to 1 to force RTFS to truncate po_write() requests to fit within
RTFS_MAX_FILE_SIZE or 0 trigger an error */
#define RTFS_TRUNCATE_WRITE_TO_MAX 1
#if (RTFS_CFG_READONLY) /* Read only file system, disable failsafe, free manager, test code and D=dvr support */
#undef INCLUDE_FAILSAFE_CODE
#define INCLUDE_FAILSAFE_CODE 0
#undef INCLUDE_RTFS_FREEMANAGER
#define INCLUDE_RTFS_FREEMANAGER 0
#undef INCLUDE_DEBUG_TEST_CODE
#define INCLUDE_DEBUG_TEST_CODE 0
#undef INCLUDE_TRANSACTION_FILES
#define INCLUDE_TRANSACTION_FILES 0
#undef INCLUDE_CIRCULAR_FILES
#define INCLUDE_CIRCULAR_FILES 0
#endif
#if (RTFS_CFG_LEAN) /* Lean build set compile time code exclusion. Additional conditional code is
included in the software source code */
#undef INCLUDE_RTFS_FREEMANAGER
#define INCLUDE_RTFS_FREEMANAGER 0
#undef INCLUDE_DEBUG_TEST_CODE
#define INCLUDE_DEBUG_TEST_CODE 0
#undef INCLUDE_TRANSACTION_FILES
#define INCLUDE_TRANSACTION_FILES 0
#undef INCLUDE_CIRCULAR_FILES
#define INCLUDE_CIRCULAR_FILES 0
#undef INCLUDE_DEBUG_VERBOSE_ERRNO
#define INCLUDE_DEBUG_VERBOSE_ERRNO 0
#undef INCLUDE_ASYNCRONOUS_API
#define INCLUDE_ASYNCRONOUS_API 0
#undef SUPPORT_EXTENDED_PARTITIONS
#define SUPPORT_EXTENDED_PARTITIONS 0
#endif
#if (INCLUDE_VFAT)
#define FILENAMESIZE_CHARS 255
#else
#if (INCLUDE_CS_UNICODE)
#error - Unicode requires INCLUDE_VFAT
#endif
#define FILENAMESIZE_CHARS 8
#endif
/* When scanning a directory cluster chain fail if more than this many
clusters are in the chain. (Indicates endless loop) */
#define MAX_CLUSTERS_PER_DIR 4096
#if (INCLUDE_VFAT)
#define EMAXPATH_CHARS 255 /* Maximum path length.Change carefully */
#else
#define EMAXPATH_CHARS 148 /* Maximum path length.Change carefully */
#endif
/* Declare buffer sizes, leave room for terminating NULLs, allign to
four bytes for good form. */
#if (INCLUDE_VFAT)
#if (INCLUDE_CS_UNICODE || INCLUDE_CS_JIS)
#define EMAXPATH_BYTES 524
#define FILENAMESIZE_BYTES 512
#else
#define EMAXPATH_BYTES 264
#define FILENAMESIZE_BYTES 256
#endif
#else /* Not INCLUDE_VFAT */
#if (INCLUDE_CS_UNICODE || INCLUDE_CS_JIS)
#define EMAXPATH_BYTES 300
#define FILENAMESIZE_BYTES 20
#else
#define EMAXPATH_BYTES 152
#define FILENAMESIZE_BYTES 12
#endif
#endif
/* Check for required declarations */
/* Make sure at least one FAT size is enabled */
#if !(INCLUDE_FAT16) && !(INCLUDE_FAT32)
#error At least one FAT size must be selected
#endif
#if (INCLUDE_DEBUG_TEST_CODE)
#if (!INCLUDE_DEBUG_RUNTIME_STATS)
#error If INCLUDE_DEBUG_TEST_CODE is set you must also set INCLUDE_DEBUG_RUNTIME_STATS
#endif
#endif
/* Compile time constants to control device inclusion and inclusion of porting layer subroutines
to reduce the header file count these were moved from a segregated header file.
These constants are only used to configure device driver selection and device driver specific
services in the porting layer, they are not and must not be used by core library source mdoules */
#define INCLUDE_IDE 1 /* - Include the IDE driver */
#define INCLUDE_PCMCIA 0 /* - Include the pcmcia driver */
#define INCLUDE_PCMCIA_SRAM 0 /* - Include the pcmcia static ram card driver */
#define INCLUDE_COMPACT_FLASH 0 /* - Support compact flash (requires IDE and PCMCIA) */
#define INCLUDE_FLASH_FTL 0 /* - Include the linear flash driver */
#define INCLUDE_ROMDISK 0 /* - Include the rom disk driver */
#define INCLUDE_RAMDISK 0 /* - Include the rom disk driver */
#define INCLUDE_MMCCARD 0 /* - Include the multi media flash card driver */
#define INCLUDE_SDCARD 0 /* - Include SD card driver */
#define INCLUDE_SMARTMEDIA 0 /* - Include the smart media flash card driver */
#define INCLUDE_FLOPPY 0 /* - Include the floppy disk driver */
#ifndef _MSC_VER
#define INCLUDE_HOSTDISK 0 /* - Include the host disk disk simulator */
#define INCLUDE_WINDEV 0 /* - Include windows direct device access */
#else
#define INCLUDE_HOSTDISK 1 /* - Include the host disk disk simulator */
#define INCLUDE_WINDEV 1 /* - Include windows direct device access */
#endif
#define INCLUDE_UDMA 0 /* - Include ultra dma support for the ide driver */
#define INCLUDE_82365_PCMCTRL 0 /* - Include the 82365 pcmcia controller driver */
#define INCLUDE_V_1_0_DEVICES 0
#define INCLUDE_V_1_0_CONFIG 0
#if (INCLUDE_V_1_0_DEVICES)
#undef INCLUDE_IDE
#undef INCLUDE_PCMCIA
#undef INCLUDE_PCMCIA_SRAM
#undef INCLUDE_COMPACT_FLASH
#undef INCLUDE_FLASH_FTL
#undef INCLUDE_ROMDISK
#undef INCLUDE_RAMDISK
#undef INCLUDE_MMCCARD
#undef INCLUDE_SMARTMEDIA
#undef INCLUDE_FLOPPY
#undef INCLUDE_HOSTDISK
#undef INCLUDE_WINDEV
#undef INCLUDE_UDMA
#undef INCLUDE_82365_PCMCTRL
#include "portconf.h"
#endif
#endif /* __RTFSCONF__ */

43
include/rtfsconfig.h Normal file
View File

@ -0,0 +1,43 @@
/* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS inc, 2008
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*******************************************************************************/
/* ============================== rtfsconfig.h ============================== */
/* ===== defines to control general behavior of configuration section ======= */
#define RTFS_CFG_SINGLE_THREADED 1 /* If 1, share user and failsafe buffers */
#ifdef DALLOC
/* dynamically allocate system wide resources */
#define RTFS_CFG_INIT_DYNAMIC_ALLOCATION 1
#else
/* do not dynamically allocate system wide resources */
#define RTFS_CFG_INIT_DYNAMIC_ALLOCATION 0
#endif
/* ===== defines to control system wide configuration ====================== */
#define RTFS_CFG_MAX_DRIVES 8 /* Maximum number of mounted volumes */
#define RTFS_CFG_MAX_FILES 20 /* Maximum number of open files */
#define RTFS_CFG_MAX_SCRATCH_BUFFERS 32 /* Minimum four see application notes */
#define RTFS_CFG_MAX_SCRATCH_DIRS 8 /* Minimum one see application notes */
#define RTFS_CFG_MAX_USER_CONTEXTS 3 /* Minimum 1 see application notes */
#define RTFS_CFG_MAX_REGION_BUFFERS 1000 /* See API guide */
#define RTFS_CFG_SINGLE_THREADED_USER_BUFFER_SIZE 64*2048 //32768 /* Only used if SAMPLE_APP_SINGLE_THREADED == 1*/
#define RTFS_CFG_SINGLE_THREADED_FAILSAFE_BUFFER_SIZE 32768 /* Only used if SAMPLE_APP_SINGLE_THREADED == 1*/
#define RTFS_CFG_DIRS_PER_DRIVE 16 /* Extra directory objects required for internal processing */
#define RTFS_CFG_DIRS_PER_USER_CONTEXT 4 /* Do not reduce unless application is fixed and can be verified */
/* ================ end rtfsconfig.h ================================ */
/*
* @(#) ti.rtfs.config; 1, 0, 0, 0,17; 1-20-2009 17:04:20; /db/vtree/library/trees/rtfs/rtfs-a18x/src/
*/

108
include/rtfserr.h Normal file
View File

@ -0,0 +1,108 @@
/*****************************************************************************
*Filename: RTFSERR.H - rtfs errno values
*
*
* EBS - RTFSAPI (Real Time File Manager)
*
* Copyright Peter Van Oudenaren , 1993
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
*
*
* Description:
*
*
*
*
****************************************************************************/
#ifndef __RTFSERR__
#define __RTFSERR__ 1
/* Errno values */
#define PEACCES 1 /* deleting an in-use object or witing to read only object */
#define PEBADF 2 /* Invalid file descriptor*/
#define PEEXIST 3 /* Creating an object that already exists */
#define PENOENT 4 /* File or directory not found */
#define PENOSPC 5 /* Out of space to perform the operation */
#define PESHARE 6 /* Sharing violation */
#define PEINVALIDPARMS 7 /* Missing or invalid parameters */
#define PEINVAL 8 /* Invalid api argument same as PEINVALIDPARMS */
#define PEINVALIDPATH 8 /* Invalid path name used as an argument */
#define PEINVALIDDRIVEID 9 /* Invalid drive specified in an argument */
#define PEIOERRORREAD 10 /* ProOnly Read error performing the API's function */
#define PEIOERRORWRITE 11 /* ProOnly Write error performing the API's function */
#define PECLOSED 12 /* Media failure closed the volume. close the file */
#define PETOOLARGE 13 /* File size exceeds 0xFFFFFFFF */
#define PENOEMPTYERASEBLOCKS 20 /* Out of empty erase blocks and DRVPOL_NAND_SPACE_OPTIMIZE operating mode is not specified */
#define PEEINPROGRESS 21 /* Cant perform operation because ASYNC operation in progress */
#define PENOTMOUNTED 22 /* PROPLUS Only Automount disabled, drive must be mounted*/
#define PEEFIOILLEGALFD 23 /* PROPLUS Only Api call not compatible file descriptor open method */
#define PEDEVICEFAILURE 51/* Driver reports that the device is not working */
#define PEDEVICENOMEDIA 52/* Driver reports that the device is empty */
#define PEDEVICEUNKNOWNMEDIA 53/* Driver reports that the device is not recognized */
#define PEDEVICEWRITEPROTECTED 54/* Driver reports that IO failed because the device is write protected */
#define PEDEVICEADDRESSERROR 55/* Driver reports that IO failed because the sector number or count were wrong */
#define PEINVALIDBPB 60/* No signature found in BPB (please format) */
#define PEIOERRORREADMBR 63/* IO error reading MBR (note: MBR is first to be read on a new insert) */
#define PEIOERRORREADBPB 64/* IO error reading BPB (block 0) */
#define PEIOERRORREADINFO32 65/* IO error reading fat32 INFO struc (BPB extension) */
#define PEIOERRORREADBLOCK 70/* Error reading a directory block */
#define PEIOERRORREADFAT 71/* Error reading a fat block */
#define PEIOERRORWRITEBLOCK 72/* Error writing a directory block */
#define PEIOERRORWRITEFAT 73/* Error writing a fat block */
#define PEIOERRORWRITEINFO32 74/* Error writing FAT32 info block */
#define PEINVALIDCLUSTER 100/* Unexpected cluster suspect volume corruption */
#define PEINVALIDDIR 101/* Unexpected directory content suspect volume corruption */
#define PEINTERNAL 102/* Unexpected condition */
#define PERESOURCEBLOCK 111/* Out of directory buffers */
#define PERESOURCEFATBLOCK 112/* Out of fat buffers */
#define PERESOURCEREGION 113/* PROPLUS Only Out of region structures */
#define PERESOURCEFINODE 114/* Out of finode structures */
#define PERESOURCEDROBJ 115/* Out of drobj structures */
#define PERESOURCEDRIVE 116/* PROPLUS Only Out of drive structures */
#define PERESOURCEFINODEEX 117/* PROPLUS Only Out of extended32 finode structures */
#define PERESOURCESCRATCHBLOCK 119/* Out of scratch buffers */
#define PERESOURCEFILES 120/* PROPLUS Only Out of File Structure */
#define PECFIONOMAPREGIONS 121/* PROPLUS Only Map region buffer too small for pc_cfilio_extract to execute */
#define PERESOURCEHEAP 122/* PROPLUS Only Out of File Structure */
#define PERESOURCESEMAPHORE 123/* PROPLUS Only Out of File Structure */
#define PENOINIT 124/*Module not initialized */
#define PEDYNAMIC 125/*Error with device driver dynamic drive initialization */
#define PERESOURCEEXFAT 126/* PROPLUS Only Out of user supplied exFat structures */
#define PEFSCREATE 130/*Failure opening journal failed */
#define PEFSJOURNALFULL 131/*PROPLUS Only Journal file is full */
#define PEFSIOERRORWRITEJOURNAL 132/*PROPLUS Only Failure writing journal file */
#define PEFSRESTOREERROR 133/*PROPLUS Only Failure restoring from journal file */
#define PEFSRESTORENEEDED 134/*PROPLUS Only Restore required and AUTORESTORE disabled */
#define PEFSIOERRORREADJOURNAL 135/*PROPLUS Only Failure reading journal file */
#define PEFSBUSY 136/*PROPLUS Only Failsafe enable called but already enabled */
#define PEFSMAPFULL 137/*PROPLUS Only Out of MAP buffers */
#define PEFSNOJOURNAL 138/*PROPLUS Only Journal file not found */
#define PEILLEGALERRNO 200 /* Illegal errno used by regression test */
#endif
/*
* @(#) ti.rtfs.config; 1, 0, 0, 0,17; 1-20-2009 17:04:20; /db/vtree/library/trees/rtfs/rtfs-a18x/src/
*/

497
include/rtfsfailsafe.h Normal file
View File

@ -0,0 +1,497 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2005
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
* This file is automatically included in rtfs.h if INCLUDE_FAILSAFE_CODE is enabled
* this file is note intended for inclusion by user code.
*/
/* RTFSFAILSAFE.H - ERTFS-PRO Directory FailSafe routines */
/* Configuration values placed into user_configuration filed */
#define FS_CONFIG_JOURNAL_TO_RESERVED 0x00000001
#define FS_OP_ASYNCRESTORE 0x00000100
#define FS_OP_CLEAR_ASYNC (~FS_OP_ASYNCRESTORE)
/* block map structure. One structure is used for each range of blocks
that are redirectected to the journal.
Two blockmaps may be active at a time.
The first is the list of block replacements whose replacement maps in the
journal file have already been flushed.
The second is the list of block replacements whose replacement maps in the
journal file have not yet been flushed.
*/
typedef struct fsblockmap {
struct fsblockmap *pnext;
dword volume_blockno;
dword journal_blockno;
dword n_replacement_blocks;
} FSBLOCKMAP;
#define FS_MASTER_SIGNATURE_1 0x4641494C /* 'F''A''I''L' */
#define FS_MASTER_SIGNATURE_2 0x53414645 /* 'S''A''F''E' */
/* April-2004 version 2. - substantial rework */
/* December 2005 version 3. - substantial rework */
/* December 2005 version 31. - substantial rework */
#define FS_CURRENT_VERSION 0x00000031
/* Internal field offsets in failsafe master record */
#define FS_MASTER_OFFSET_SIGNATURE_1 0
#define FS_MASTER_OFFSET_SIGNATURE_2 1
#define FS_MASTER_OFFSET_VERSION 2
#define FS_MASTER_OFFSET_FSIZE 3
#define FS_MASTER_OFFSET_SESSION 4
#define FS_MASTER_OFFSET_START_RECORD 5
#define FS_FRAME_TYPE_OPEN 1 /* Must be first */
#define FS_FRAME_TYPE_NULL 2
#define FS_FRAME_TYPE_CLOSED 3
#define FS_FRAME_TYPE_FLUSHED 4
#define FS_FRAME_TYPE_RESTORING 5
#define FS_FRAME_TYPE_RESTORED 6
/* Internal field offsets in failsafe frame record */
#define FS_FRAME_OFFSET_TYPE 0
#define FS_FRAME_OFFSET_FRAME_SEQUENCE 1
#define FS_FRAME_OFFSET_SEGMENT_CHECKSUM 2
#define FS_FRAME_OFFSET_FRAME_CHECKSUM 3
#define FS_FRAME_OFFSET_FRAME_RECORDS 4
#define FS_FRAME_OFFSET_FAT_FREESPACE 5
#define FS_FRAME_OFFSET_SESSION_ID 6
#define FS_FRAME_HEADER_SIZE 7
#define FS_FIRST_INDEX_IN_FRAME FS_FRAME_HEADER_SIZE
/* FSRESTORE Structure part of the failsafe context, but private */
typedef struct fsrestore_buffer {
/* Transfer buffer contains data read from the journal and written to the volume */
byte *transfer_buffer;
dword transfer_buffer_size;
dword first_block_in_buffer;
dword last_block_in_buffer;
dword num_blocks_in_buffer;
} FSRESTORE_BUFFER;
typedef struct fsreplacement_queue {
/* Transfer buffer contains data read from the journal and written to
the volume */
dword file_current_index_block;
dword file_current_index_offset;
struct fsblockmap *mem_current_blockmap;
BOOLEAN used_all_replacement_records;
BOOLEAN all_replacements_queued;
dword total_replacement_records; /* Diagnostic */
dword replacement_records_free; /* Diagnostic */
FSBLOCKMAP *preplacement_freelist;
FSBLOCKMAP *preplacement_extras; /* Used by write to volume processing */
FSBLOCKMAP *preplacements_queued; /* Queued from file index headers or from blockmap */
FSBLOCKMAP *preplacements_buffered; /* Replacements currently in the current buffer */
FSBLOCKMAP *preplacement_fat; /* For looping back */
int num_fats_restored;
} FSREPLACEMENT_QUEUE;
typedef struct fsrestore {
int restore_state;
dword restore_loop_guard;
BOOLEAN restore_from_file;
dword restoring_start_record;
dword restoring_terminal_record;
dword restoring_last_block;
FSRESTORE_BUFFER restore_buffer;
FSREPLACEMENT_QUEUE replacement_queue;
} FSRESTORE;
/* FJOURNAL Structure part of the failsafe context, but private */
typedef struct fsjournal {
dword session_current_checksum;
dword session_current_freespace;
dword session_start_record;
dword frames_free;
dword next_free_frame;
dword wrap_counter;
dword frame_sequence;
dword open_start_record;
dword open_current_frame;
dword open_current_index;
dword open_current_free;
dword open_current_used;
dword open_current_checksum;
dword *journal_buffer_start;
dword *open_index_buffer;
dword buffer_sector_start;
dword replacement_sectors_dirty;
dword open_remapped_blocks;
dword flushed_remapped_blocks;
dword restoring_remapped_blocks;
dword flushed_start_record;
dword flushed_terminal_record;
dword flushed_last_block;
BOOLEAN block_cache_full;
dword num_blockmaps_used;
dword max_blockmaps_used;
struct fsblockmap *blockmap_freelist;
struct fsblockmap *open_blockmap_cache;
struct fsblockmap *flushed_blockmap_cache;
struct fsblockmap *restoring_blockmap_cache;
/* Fragments to be released to the freelist manager after restore */
REGION_FRAGMENT *open_free_fragments;
REGION_FRAGMENT *flushed_free_fragments;
REGION_FRAGMENT *restoring_free_fragments;
} FSJOURNAL;
#define CONTEXT_TO_JOURNAL(CONTEXT) &(CONTEXT->fs_journal)
#define CONTEXT_TO_RESTORE(CONTEXT) &(CONTEXT->fs_restore)
#define FS_DEBUG 0
#if (FS_DEBUG)
void show_status(char *prompt, dword val, int flags);
#define FS_DEBUG_SHOW(X) rtfs_print_one_string((byte *)X,0);
#define FS_DEBUG_SHOWNL(X) rtfs_print_one_string((byte *)X,PRFLG_NL);
#define FS_DEBUG_SHOWINT(PROMPT, VAL) show_status(PROMPT, VAL, 0);
#define FS_DEBUG_SHOWINTNL(PROMPT, VAL) show_status(PROMPT, VAL, PRFLG_NL);
#else
#define FS_DEBUG_SHOW(X)
#define FS_DEBUG_SHOWNL(X)
#define FS_DEBUG_SHOWINT(PROMPT, VAL)
#define FS_DEBUG_SHOWINTNL(PROMPT, VAL)
#endif
typedef struct failsafe_runtime_stats {
dword journaling_active;
dword sync_in_progress;
dword journal_file_size;
dword journal_file_used;
dword journal_max_used;
dword restore_buffer_size;
dword num_blockmaps;
dword num_blockmaps_used;
dword max_blockmaps_used;
dword cluster_frees_pending;
dword reserved_free_clusters;
dword current_frame;
dword current_index;
dword flushed_blocks;
dword open_blocks;
dword restore_pass_count;
dword restoring_blocks;
dword restored_blocks;
dword current_restoring_block;
/* The following field is updated by pc_failsafe_runtime_stats when extended is specified and Failsafe is configured */
dword fat_synchronize_writes;
dword fat_synchronize_blocks_written;
dword dir_synchronize_writes;
dword dir_synchronize_blocks_written;
dword frames_closed;
dword frames_flushed;
dword frames_restoring;
dword restore_data_reads;
dword restore_data_blocks_read;
dword restore_write_calls;
dword restore_blocks_written;
dword volume_block_writes;
dword volume_blocks_written;
dword journal_data_reads;
dword journal_data_blocks_read;
dword journal_data_writes;
dword journal_data_blocks_written;
dword journal_index_writes;
dword journal_index_reads;
dword transaction_buff_hits;
dword transaction_buff_reads;
dword transaction_buff_writes;
} FAILSAFE_RUNTIME_STATS;
BOOLEAN pc_diskio_failsafe_stats(byte *drive_name, FAILSAFE_RUNTIME_STATS *pstats);
/* Fail configuration and context structure */
typedef struct failsafecontext {
dword blockmap_size;
struct fsblockmap *blockmap_core;
byte *user_restore_transfer_buffer;
dword user_restore_transfer_buffer_size;
/* Devices must provide a buffer for the index page. If the buffer is > 1 sector the buffer determines the number of sectors to buffer before flushing the frame */
dword user_index_buffer_size_sectors;
byte *user_open_index_buffer;
byte *assigned_restore_transfer_buffer;
dword assigned_restore_transfer_buffer_size;
dword user_configuration;
dword session_id;
dword operating_flags;
int error_val;
/* Internal elements, not intended to be accessed from user code */
dword journal_file_size;/* In blocks */
dword min_free_blocks; /* Low water of allocated blocks */
DDRIVE *pdrive;
dword fs_frame_size; /* Number of dwords that fit in a disk block, 128 for 512 byte blocks, 256 for 1024 etc. */
dword fs_frame_max_records; /* Number of indeces that fit in a disk block after the header */
dword nv_buffer_handle;
dword nv_cluster_handle;
BOOLEAN nv_raw_mode; /* Set to TRUE if nv_buffer_handle is a raw block number from the beginning of the device */
REGION_FRAGMENT nv_reserved_fragment;
BOOLEAN nv_disable_failsafe; /* nvio layer sets if journal creation failed but mount should proceed without Journaling */
FSRESTORE fs_restore; /* Current restore session */
FSJOURNAL fs_journal; /* Current journal session */
#if (INCLUDE_DEBUG_RUNTIME_STATS)
FAILSAFE_RUNTIME_STATS stats;
#endif
} FAILSAFECONTEXT;
#if (INCLUDE_DEBUG_RUNTIME_STATS)
#define UPDATE_FSRUNTIME_STATS(CTX, FIELD, COUNT) CTX->stats.FIELD += COUNT;
#else
#define UPDATE_FSRUNTIME_STATS(DRIVE, FIELD, COUNT)
#endif
/* Failsafe Header File Status */
#define FS_STATUS_JOURNALING 1
#define FS_STATUS_RESTORING 2
#define FS_STATUS_NEEDS_RESTORE 3
#define FS_STATUS_RESTORED 4
/*
journaling - TRUE if a Failsafe jounaling session is currently active.
journal_file_valid - TRUE if the on disk Journal File is valid
needsflush - TRUE If Failsafe is active and flush is required.
The following BOOLEAN status fields are valid only when Failsafe is
not active (journaling == FALSE) and the Journal file is valid.
(journal_file_valid == TRUE)
out_of_date - TRUE if the freespace on the volume has changed since
the Journal was last flushed.
check_sum_fails - TRUE if the Journal file index block have been
corrupted or tambered with outside of the Failsafe
environment.
restore_required - TRUE if the Failsafe file state is FS_STATUS_RESTORING.
This indictates that a Journal file restore operation,
or the FAT synchronization operation during a Failsafe
commit process was interrupted.
This condition indicates that the volume structure
is currently corrupted and must be restored.
restore_recommended - This condition indicates that the Journal file has
been flushed but the FAT synchronization operation
has not been done yet.
The volume structure is not currently corrupted and all
actions performed during the previous Failsafe session
exist only in the Journal file and not on the volume.
To synchronize the FAT Volume run restore or..
To discard the previous session and start a new
Journalling session just enable Failsafe.
Use ERTFS with Failsafe disabled.
version - Failsafe version number (currently 3)
status - Current Status
FS_STATUS_JOURNALING - if (journaling == TRUE)
The Journal file is currently opened, needsflush
is set to TRUE.
if (journaling == FALSE) this status indicates
the the last Failsafe session was interrupted
before the Journal file was flushed. There is
no volume corruption the operations perfromed
since the last succesful flush are lost.
FS_STATUS_RESTORING - See restore_required
FS_STATUS_NEEDS_RESTORE - See restore_reccomended
FS_STATUS_RESTORED - Journal and FAT are in
synch
numindexblocks - Number of blocks in the journal file reserved for
indexing.
totalremapblocks - Number of blocks in the journal file reserved for
Journalling.
numblocksremapped - Number of FAT and directory blocks currently journalled
journaledfreespace - Volume freespace when Journalling session was opened
currentfreespace - Current volume freespace
journal_block_number- Disk location of journal file if using default NVIO
routines
filesize - The size of the journal file size in 512 byte blocks.
*/
typedef struct fsinfo {
BOOLEAN journaling;
BOOLEAN journal_file_valid;
dword version;
dword numblocksremapped;
dword journaledfreespace;
dword currentfreespace;
dword journal_block_number;
dword filesize;
BOOLEAN needsflush;
BOOLEAN out_of_date;
BOOLEAN check_sum_fails;
BOOLEAN restore_required;
BOOLEAN restore_recommended;
/* Internal values */
dword _start_session_frame; /* First record in the session */
dword _start_restored_frame; /* Records already restored */
dword _last_restored_frame;
dword _first_restoring_frame; /* Records being restored but interrupted */
dword _last_restoring_frame;
dword _first_flushed_frame; /* Records flushed but not restored */
dword _last_flushed_frame;
dword _records_to_restore;
} FSINFO;
/* Return values from fs_api_cb_restore() */
#define FS_CB_RESTORE 0 /* Do not change, must be zero. Tell Failsafe to proceded and restore the volume */
#define FS_CB_ABORT 2 /* Do not change, must be 1 Tell Failsafe to terminate the mount, causing the
API call to fail with errno set to PEFSRESTORENEEDED. */
/* Return values from fs_api_cb_flush() */
#define FS_CB_SYNC 0 /* Do not change, must be 0 Default: Tell Failsafe to flush the journal file and synchronize the FAT volume */
#define FS_CB_FLUSH 2 /* Do not change, must be 2. Tell Failsafe to flush the journal file but not synchronize the FAT volume*/
#define FS_CB_CONTINUE 1 /* Do not change, must be 1 Tell Failsafe to proceded and not restore the volume. */
/* =========================== */
/* Failsafe api prototypes */
/* =========================== */
#ifdef __cplusplus
extern "C" {
#endif
/* rtfsproplusfailsafe\prfsapi.c */
BOOLEAN fs_api_info(byte *drive_name,FSINFO *pinfo);
/* rtfsproplusfailsafe\prfsjournal.c */
BOOLEAN fs_api_enable(byte *drivename, BOOLEAN clear_journal);
BOOLEAN fs_api_disable(byte *drive_name, BOOLEAN abort);
BOOLEAN fs_api_commit(byte *path,BOOLEAN synch_fats);
int fs_api_async_commit_start(byte *path);
void fs_failsafe_disable(DDRIVE *pdrive, int error);
/* rtfsproplusfailsafe\prfsrestore.c */
BOOLEAN fs_api_restore(byte *drive_name);
/* rtfsproplusfailsafe\prfscb.c */
int fs_api_cb_journal_fixed(DDRIVE *pdrive, dword *raw_start_sector, dword *file_size_sectors);
BOOLEAN fs_api_cb_check_fail_on_journal_resize(int driveno);
BOOLEAN fs_api_cb_disable_on_full(DDRIVE *pdrive);
dword fs_api_cb_journal_size(DDRIVE *pdrive);
int fs_api_cb_restore(int driveno);
BOOLEAN fs_api_cb_error_restore_continue(int driveno);
BOOLEAN fs_api_cb_enable(int driveno);
int fs_api_cb_flush(int driveno);
/* =========================== */
/* End Failsafe api prototypes */
/* =========================== */
/* =========================== */
/* Failsafe internal prototypes */
/* =========================== */
/* rtfsproplusfailsafe\prfsjournal.c */
dword _fs_transfer_buffer_size_sectors(FAILSAFECONTEXT *pfscntxt);
BOOLEAN fs_sessioninfo_internal(FAILSAFECONTEXT *pfscntxt, FSINFO *pinfo);
void fs_clear_session_vars(FAILSAFECONTEXT *pfscntxt);
BOOLEAN fs_failsafe_autocommit(DDRIVE *pdrive);
int _fs_api_async_flush_journal(DDRIVE *pdrive);
int _fs_api_async_commit_continue(DDRIVE *pdrive);
BOOLEAN fs_flush_transaction(DDRIVE *pdrive);
BOOLEAN fs_dynamic_config_check(DDRIVE *pdr);
void fs_free_blockmap(FSJOURNAL *pjournal,FSBLOCKMAP *pbm);
void fs_show_journal_session(FAILSAFECONTEXT *pfscntxt);
/* rtfsproplusfailsafe\prfsnvio.c */
BOOLEAN failsafe_reopen_nv_buffer(FAILSAFECONTEXT *pfscntxt, dword raw_start_sector, dword file_size_sectors);
BOOLEAN failsafe_create_nv_buffer(FAILSAFECONTEXT *pfscntxt, dword raw_start_sector, dword file_size_sectors);
BOOLEAN failsafe_nv_buffer_io(FAILSAFECONTEXT *pfscntxt, dword block_no, dword nblocks, byte *pblock,BOOLEAN reading);
BOOLEAN failsafe_nv_buffer_mark(FAILSAFECONTEXT *pfscntxt, byte *pbuffer);
BOOLEAN failsafe_nv_buffer_clear(FAILSAFECONTEXT *pfscntxt, byte *pbuffer);
/* rtfsproplusfailsafe\prfsrestore.c */
BOOLEAN fs_failsafe_autorestore(FAILSAFECONTEXT *pfscntxt);
int fs_restore_from_session_start(FAILSAFECONTEXT *pfscntxt);
int fs_restore_from_session_continue(FAILSAFECONTEXT *pfscntxt);
BOOLEAN fs_fileinfo_internal(FAILSAFECONTEXT *pfscntxt, FSINFO *pinfo);
/* rtfsproplusfailsafe\prfstrio.c */
BOOLEAN _pc_efiliocom_overwrite(PC_FILE *pefile, FINODE *pefinode, byte *pdata, dword n_bytes);
BOOLEAN _pc_check_transaction_buffer(PC_FILE *pefile, dword clusterno);
BOOLEAN fs_failsafe_autocommit(DDRIVE *pdrive);
BOOLEAN fs_flush_transaction(DDRIVE *pdrive);
#ifdef __cplusplus
}
#endif
/* FailSafe internal restore and synchronize routines */
#define FS_MASTER_TYPE_ERROR 1
#define FS_MASTER_TYPE_VALID 2
#define FS_MASTER_ERROR_NOT_FAILSAFE 1
#define FS_MASTER_ERROR_WRONG_VERSION 2
typedef struct fsmasterinfo {
int master_type;
int master_error_type;
dword master_file_version;
dword master_file_size;
dword master_file_start;
dword master_file_session_id;
dword master_start_record;
} FSMASTERINFO;
#ifdef __cplusplus
extern "C" {
#endif
void fs_failsafe_scaleto_blocksize(FAILSAFECONTEXT *pfscntxt);
void fs_mem_master_info(dword *pdw,FSMASTERINFO *pmaster);
void fs_mem_master_init(FAILSAFECONTEXT *pfscntxt, dword *pdw, dword journal_file_size,dword session_id, dword session_start_record);
int fs_restore_from_file_start(FAILSAFECONTEXT *pfscntxt);
int fs_restore_from_file_continue(FAILSAFECONTEXT *pfscntxt);
int fs_restore_from_session_start(FAILSAFECONTEXT *pfscntxt);
int fs_restore_from_session_continue(FAILSAFECONTEXT *pfscntxt);
BOOLEAN fs_sessioninfo_internal(FAILSAFECONTEXT *pfscntxt, FSINFO *pinfo);
BOOLEAN fs_fileinfo_internal(FAILSAFECONTEXT *pfscntxt, FSINFO *pinfo);
BOOLEAN fs_failsafe_autorestore(FAILSAFECONTEXT *pfscntxt);
void fs_failsafe_disable(DDRIVE *pdrive, int error);
void fs_clear_session_vars(FAILSAFECONTEXT *pfscntxt);
void fs_free_blockmap(FSJOURNAL *pjournal,FSBLOCKMAP *pbm);
#ifdef __cplusplus
}
#endif
/* =========================== */
/* End Failsafe internal prototypes */
/* =========================== */

28
include/rtfspackage.h Normal file
View File

@ -0,0 +1,28 @@
/*****************************************************************************
*Filename: RTFSPACKAGE.H - header file that identifies purchased options
*
*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc, 2006
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
* Description:
* This file contains tuning that identify purchased options.
* It is included by rtfsconf.h
*
****************************************************************************/
#ifndef __RTFSPACKAGE__
#define __RTFSPACKAGE__ 1
/* rtfspackage.h - Rtfs Pro Plus Option setting. do not change */
#define INCLUDE_RTFS_PROPLUS 0
#define INCLUDE_RTFS_BASIC_ONLY 0
#define INCLUDE_RTFS_FAILSAFE_OPTION 0
#define INCLUDE_RTFS_DVR_OPTION 0
#define INCLUDE_MATH64 0
#endif /* __RTFSPACKAGE___ */

946
include/rtfsprotos.h Normal file
View File

@ -0,0 +1,946 @@
/*****************************************************************************
*Filename: RTFSPROTOS.H - RTFS common function prototypes
*
*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS, 2007
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
*
*
* Description:
*
*
*
*
****************************************************************************/
#ifndef __RTFSPROTOS__
#define __RTFSPROTOS__ 1
/* =========================== */
/* Rtfs internal prototypes */
/* =========================== */
#ifdef __cplusplus
extern "C" {
#endif
/* Application callbacks */
#define RTFS_CBS_INIT 0
#define RTFS_CBS_PUTS 1
#define RTFS_CBS_GETS 2
#define RTFS_CBS_GETDATE 3
#define RTFS_CBS_POLL_DEVICE_READY 4
/* Exfat buffering and operating parameters are via callback not from the device layer */
#define RTFS_CBS_GETEXFATBUFFERS 5
#define RTFS_CBS_RELEASEEXFATBUFFERS 6
/* Exfat date extensions via callback not from the device layer */
#define RTFS_CBS_UTCOFFSET 7
#define RTFS_CBS_10MSINCREMENT 8
#define RTFS_CBA_INFO_MOUNT_STARTED 0
#define RTFS_CBA_INFO_MOUNT_FAILED 1
#define RTFS_CBA_INFO_MOUNT_COMPLETE 2
#define RTFS_CBA_ASYNC_MOUNT_CHECK 3
#define RTFS_CBA_ASYNC_START 4
#define RTFS_CBA_ASYNC_DRIVE_COMPLETE 5
#define RTFS_CBA_ASYNC_FILE_COMPLETE 6
#define RTFS_CBA_DVR_EXTRACT_RELEASE 7
#define RTFS_CBD_ASSERT 0
#define RTFS_CBD_ASSERT_TEST 1
#define RTFS_CBD_SETERRNO 2
#define RTFS_CBD_IOERROR 3
#define RTFS_CB_FS_RETRIEVE_FIXED_JOURNAL_LOCATION 200
#define RTFS_CB_FS_FAIL_ON_JOURNAL_RESIZE 201
#define RTFS_CB_FS_FAIL_ON_JOURNAL_FULL 202
#define RTFS_CB_FS_RETRIEVE_JOURNAL_SIZE 203
#define RTFS_CB_FS_RETRIEVE_RESTORE_STRATEGY 204
#define RTFS_CB_FS_FAIL_ON_JOURNAL_CHANGED 205
#define RTFS_CB_FS_CHECK_JOURNAL_BEGIN_NOT 206
#define RTFS_CB_FS_RETRIEVE_FLUSH_STRATEGY 207
int rtfs_sys_callback(int cb_code, void *pvargs);
int rtfs_app_callback(int cb_code, int iarg0, int iargs1, int iargs2, void *pvargs);
void rtfs_diag_callback(int cb_code, int iarg0);
int rtfs_failsafe_callback(int cb_code, int driveno, int iarg0, void *pvargs0, void *pvargs1);
#if (INCLUDE_FAILSAFE_RUNTIME)
BOOLEAN pc_failsafe_init(void);
#endif
#if (INCLUDE_CS_UNICODE)
/* Prototypes of unicode / Non-Unicode selectable APIS */
BOOLEAN pc_get_volume_cs(byte *driveid, byte *volume_label,int use_charset);
BOOLEAN pc_set_volume_cs(byte *driveid, byte *volume_label,int use_charset);
BOOLEAN pc_mv_cs(byte *old_name, byte *new_name,int use_charset);
BOOLEAN pc_get_cwd_cs(byte *drive, byte *path, int use_charset);
BOOLEAN pc_pwd_cs(byte *drive, byte *path, int use_charset);
BOOLEAN pc_gfirst_cs(DSTAT *statobj, byte *name, int use_charset);
BOOLEAN pc_glast_cs(DSTAT *statobj, byte *name, int use_charset);
BOOLEAN pc_gnext_cs(DSTAT *statobj, int use_charset);
BOOLEAN pc_gprev_cs(DSTAT *statobj, int use_charset);
BOOLEAN pc_isdir_cs(byte *path, int use_charset);
BOOLEAN pc_isvol_cs(byte *path, int use_charset);
BOOLEAN pc_get_attributes_cs(byte *path, byte *p_return, int use_charset);
BOOLEAN pc_mkdir_cs(byte *name, int use_charset);
BOOLEAN pc_rmdir_cs(byte *name, int use_charset);
BOOLEAN pc_set_attributes_cs(byte *path, byte attributes, int use_charset);
BOOLEAN pc_set_cwd_cs(byte *name, int use_charset);
int pc_stat_cs(byte *name, ERTFS_STAT *pstat, int use_charset);
BOOLEAN pc_unlink_cs(byte *name, int use_charset);
int po_open_cs(byte *name, word flag, word mode, int use_charset);
int pc_get_default_drive_cs(byte *drive_name, int use_charset);
BOOLEAN pc_deltree_cs(byte *name, int use_charset);
int pc_enumerate_cs( /* __apifn__ */
byte * from_path_buffer,
byte * from_pattern_buffer,
byte * spath_buffer,
byte * dpath_buffer,
byte * root_search,
word match_flags,
byte * match_pattern,
int maxdepth,
PENUMCALLBACK pcallback,
int use_charset);
BOOLEAN pc_get_dirent_info_cs(byte *path, DIRENT_INFO *pinfo, int use_charset);
BOOLEAN pc_set_dirent_info_cs(byte *path, DIRENT_INFO *pinfo, int use_charset);
BOOLEAN pc_get_media_parms_cs(byte *path, PDEV_GEOMETRY pgeometry, int use_charset);
BOOLEAN pc_format_media_cs(byte *path, int use_charset);
BOOLEAN pc_format_volume_cs(byte *path, int use_charset);
BOOLEAN pc_format_volume_ex_cs(byte *path, RTFSFMTPARMSEX *pappfmt, int use_charset);
BOOLEAN pc_partition_media_cs(byte *path, struct mbr_specification *pmbrspec, int use_charset);
#else
/* Prototypes of Non-Unicode APIS */
BOOLEAN pc_get_volume(byte *driveid, byte *volume_label);
BOOLEAN pc_set_volume(byte *driveid, byte *volume_label);
BOOLEAN pc_mv(byte *old_name, byte *new_name);
BOOLEAN pc_get_cwd(byte *drive, byte *path);
BOOLEAN pc_pwd(byte *drive, byte *path);
BOOLEAN pc_gfirst(DSTAT *statobj, byte *name);
BOOLEAN pc_glast(DSTAT *statobj, byte *name);
BOOLEAN pc_gnext(DSTAT *statobj);
BOOLEAN pc_gprev(DSTAT *statobj);
BOOLEAN pc_isdir(byte *path);
BOOLEAN pc_isvol(byte *path);
BOOLEAN pc_get_attributes(byte *path, byte *p_return);
BOOLEAN pc_rmdir(byte *name);
BOOLEAN pc_mkdir(byte *name);
BOOLEAN pc_set_attributes(byte *path, byte attributes);
BOOLEAN pc_set_cwd(byte *name);
int pc_stat(byte *name, ERTFS_STAT *pstat);
BOOLEAN pc_unlink(byte *name);
int po_open(byte *name, word flag, word mode);
int pc_get_default_drive(byte *drive_name);
BOOLEAN pc_deltree(byte *name);
int pc_enumerate( /* __apifn__ */
byte * from_path_buffer,
byte * from_pattern_buffer,
byte * spath_buffer,
byte * dpath_buffer,
byte * root_search,
word match_flags,
byte * match_pattern,
int maxdepth,
PENUMCALLBACK pcallback);
BOOLEAN pc_get_dirent_info(byte *path, DIRENT_INFO *pinfo);
BOOLEAN pc_set_dirent_info(byte *path, DIRENT_INFO *pinfo);
BOOLEAN pc_get_media_parms(byte *path, PDEV_GEOMETRY pgeometry);
BOOLEAN pc_format_media(byte *path);
BOOLEAN pc_format_volume(byte *path);
BOOLEAN pc_format_volume_ex(byte *path, RTFSFMTPARMSEX *pappfmt);
BOOLEAN pc_partition_media(byte *path, struct mbr_specification *pmbrspec);
#endif
/* Versions of these entry points are provided by both Pro and ProPlus */
int rtfs_app_entry(void); /* Pro style See apirun.c */
int pc_ertfs_run(void); /* ProPlus style See apirun.c */
int _pc_ertfs_run(void);
void pc_ertfs_shutdown(void);
#if (INCLUDE_EXFATORFAT64)
#define FINODESIZEISZERO(P) ((!ISEXFATORFAT64(P->my_drive)&&P->fsizeu.fsize== 0)||(ISEXFATORFAT64(P->my_drive)&&M64ISZERO(P->fsizeu.fsize64)))
BOOLEAN pcexfat_format_volume(byte *path);
#else
#define FINODESIZEISZERO(P) (P->fsizeu.fsize == 0)
#endif
/* rtfs shell entry point */
void tst_shell(void);
void pc_free_disk_configuration(int drive_number);
int po_read(int fd, byte *in_buff, int count);
int po_write(int fd, byte *buf, int count);
BOOLEAN po_truncate(int fd, dword offset);
int po_chsize(int fd, dword offset);
BOOLEAN po_flush(int fd);
long po_lseek(int fd, long offset, int origin);
BOOLEAN po_ulseek(int fd, dword offset, dword *pnew_offset, int origin);
int po_close(int fd);
int pc_fstat(int fd, ERTFS_STAT *pstat);
BOOLEAN pc_check_automount(DDRIVE *pdr);
BOOLEAN _pc_diskflush(DDRIVE *pdrive);
long pc_free(byte *path, dword *blocks_total, dword *blocks_free);
BOOLEAN pc_raw_read(int driveno, byte *buf, dword blockno, dword nblocks, BOOLEAN raw);
BOOLEAN pc_raw_write(int driveno, byte *buf, dword blockno, dword nblocks, BOOLEAN raw);
/* apickdsk.c */
BOOLEAN pc_check_disk_ex(byte *drive_id, CHKDISK_STATS *pstat, dword chkdsk_opmode, CHKDSK_CONTEXT *pgl, void *scratch_memory, dword scratch_memory_size);
BOOLEAN pc_diskflush(byte *path); /* apidiskflush.c */
BOOLEAN pc_diskclose(byte *driveid, BOOLEAN clear_init);
BOOLEAN pc_diskio_free_list(byte *drivename, int listsize, FREELISTINFO *plist, dword startcluster, dword endcluster, dword threshhold);
BOOLEAN pc_diskio_info(byte *drive_name, DRIVE_INFO *pinfo, BOOLEAN extended);
BOOLEAN pc_diskio_runtime_stats(byte *drive_name, DRIVE_RUNTIME_STATS *pstats, BOOLEAN clear);
int pc_get_file_extents(int fd, int infolistsize, FILESEGINFO *plist, BOOLEAN report_clusters, BOOLEAN raw);
void pc_calculate_chs(dword total, dword *cylinders, int *heads, int *secptrack);/* apifrmat.c */
void pc_gdone(DSTAT *statobj);
BOOLEAN pc_gread(DSTAT *statobj, int blocks_to_read, byte *buffer, int *blocks_read);
BOOLEAN pc_set_default_drive(byte *drive); /* apiinfo.c */
BOOLEAN pc_blocks_free(byte *path, dword *blocks_total, dword *blocks_free);
int pc_cluster_size(byte *drive);
int pc_sector_size(byte *drive);
void pc_drno_to_drname(int driveno, byte *pdrive_name, int use_charset);
int pc_drname_to_drno(byte *drive_name, int use_charset);
int pc_fd_to_driveno(int fd,byte *pdrive_name, int use_charset);
BOOLEAN pc_ertfs_init(void); /* apiinit.c */
BOOLEAN pc_regression_test(byte *driveid, BOOLEAN do_clean);/* apiregress.c */
void pc_finode_stat(FINODE *pi, ERTFS_STAT *pstat);
void rtfs_print_string_1(byte *pstring ,int flags); /* rttermin.c */
void rtfs_print_string_2(byte *pstring,byte *pstr2, int flags);
void rtfs_print_long_1(dword l,int flags);
void rtfs_print_one_string(byte *pstr,int flags);
byte *pc_ltoa(dword num, byte *dest, int number_base);
#if (INCLUDE_CS_UNICODE)
void map_jis_ascii_to_unicode(byte *unicode_to, byte *ascii_from);
BOOLEAN map_unicode_to_jis_ascii(byte *to, byte *from);
#endif
void rtfs_cs_char_copy(byte *to, byte *from, int use_charset);
byte *rtfs_cs_increment(byte *p, int use_charset);
int rtfs_cs_compare(byte *p1, byte *p2, int use_charset);
int rtfs_cs_compare_nc(byte *p1, byte *p2, int use_charset);
int rtfs_cs_ascii_index(byte *p, byte base, int use_charset);
void rtfs_cs_to_unicode(byte *to, byte *p, int use_charset);
void rtfs_cs_unicode_to_cs(byte *to, byte *punicode, int use_charset);
BOOLEAN rtfs_cs_is_eos(byte *p, int use_charset);
BOOLEAN rtfs_cs_is_not_eos(byte *p, int use_charset);
void rtfs_cs_term_string(byte *p, int use_charset);
int rtfs_cs_cmp_to_ascii_char(byte *p, byte c, int use_charset);
void rtfs_cs_assign_ascii_char(byte *p, byte c, int use_charset);
byte *rtfs_cs_goto_eos(byte *p, int use_charset);
BOOLEAN rtfs_cs_ascii_fileparse(byte *filename, byte *fileext, byte *p);
byte *pc_cs_mfile(byte *to, byte *filename, byte *ext, int use_charset);
byte *pc_cs_mfileNT(byte *to, byte *filename, byte *ext, int use_charset, byte ntflags);
byte *rtfs_cs_strcat(byte * targ, byte * src, int use_charset);
int rtfs_cs_strcmp(byte * s1, byte * s2, int use_charset);
int rtfs_cs_strcpy(byte * targ, byte * src, int use_charset);
int rtfs_cs_strlen(byte * string, int use_charset);
void pc_cs_ascii_str2upper(byte *to, byte *from);
void pc_cs_ascii_strn2upper(byte *to, byte *from, int n);
BOOLEAN pc_cs_malias(byte *alias, byte *input_file, int which_try, int use_charset);
BOOLEAN pc_cs_valid_sfn(byte *filename, BOOLEAN case_sensitive);
BOOLEAN pc_cs_validate_filename(byte * name, byte * ext, int use_charset);
BOOLEAN pc_cs_validate_8_3_name(byte * name,int len);
BOOLEAN rtfs_cs_patcmp_8(byte *p, byte *pattern, BOOLEAN dowildcard);
dword pc_finode_cluster(DDRIVE *pdr, FINODE *finode); /* rtcomonglue.c */
void pc_pfinode_cluster(DDRIVE *pdr, FINODE *finode, dword value);
dword pc_get_parent_cluster(DDRIVE *pdrive, DROBJ *pobj);
dword pc_alloc_dir(DDRIVE *pdrive, DROBJ *pmom);
dword pc_grow_dir(DDRIVE *pdrive, DROBJ *pobj, dword *previous_end);
int _pc_file_open(DDRIVE *pdrive, byte *name, word flag, word mode, dword extended, BOOLEAN *created, int use_charset);
BOOLEAN pc_alloc_path_buffers(DDRIVE *pdrive);
void pc_release_path_buffers(DDRIVE *pdrive);
PC_FILE *pc_fd2file(int fd,int flags);
PC_FILE *pc_allocfile(void);
void pc_freefile(PC_FILE *pfile);
BOOLEAN pc_load_file_buffer(FINODE *pfinode, dword new_blockno, BOOLEAN read_buffer);
void pc_release_file_buffer(BLKBUFF *pblk);
BOOLEAN pc_buffered_fileio(FINODE *pfinode, dword start_sector, dword start_byte_offset, dword n_todo, byte *pdata, BOOLEAN reading, BOOLEAN appending);
BOOLEAN pc_flush_file_buffer(FINODE *pfinode);
dword pc_get_media_sector_size(DDRIVE *pdr);
int pc_enum_file(DDRIVE *pdrive, int chore);
void pc_free_all_fil(DDRIVE *pdrive);
BOOLEAN pc_flush_all_fil(DDRIVE *pdrive);
void pc_release_all_prealloc(DDRIVE *pdrive);
int pc_test_all_fil(DDRIVE *pdrive);
BOOLEAN pc_init_drv_fat_info16(DDRIVE *pdr, struct pcblk0 *pbl0);
dword pc_byte2clmod(DDRIVE *pdr, dword nbytes);
dword pc_alloced_bytes_from_clusters(DDRIVE *pdr, dword total_alloced_clusters);
void pc_set_file_dirty(PC_FILE * pfile, BOOLEAN isdirty); /* rtconditionalglue.c */
byte *pc_claim_user_buffer(DDRIVE *pdr, dword *pbuffer_size_blocks, dword minimimum_size_sectors);
void pc_release_user_buffer(DDRIVE *pdr, byte *pbuffer);
BOOLEAN pc_check_file_dirty(PC_FILE * pfile);
void pc_set_file_buffer_dirty(FINODE *pfinode, BOOLEAN isdirty);
BOOLEAN pc_check_file_buffer_dirty(FINODE *pfinode);
void set_fat_dirty(DDRIVE *pdr);
void clear_fat_dirty(DDRIVE *pdr);
BOOLEAN chk_fat_dirty(DDRIVE *pdr);
void set_mount_abort_status(DDRIVE *pdr);
void clear_mount_valid(DDRIVE *pdr);
void clear_mount_abort(DDRIVE *pdr);
void set_mount_valid(DDRIVE *pdr);
BOOLEAN chk_mount_abort(DDRIVE *pdr);
BOOLEAN chk_mount_valid(DDRIVE *pdr);
BOOLEAN pc_update_inode(DROBJ *pobj, BOOLEAN set_archive, int set_date_mask);
FINODE *pc_file2_finode(PC_FILE * pfile);
BOOLEAN pc_force_file_flush(PC_FILE * pfile);
BOOLEAN block_devio_read(DDRIVE *pdrive, dword blockno, byte * buf); /* rtdblock.c */
BOOLEAN block_devio_write(BLKBUFF *pblk);
BOOLEAN block_devio_xfer(DDRIVE *pdrive, dword blockno, byte * buf, dword n_to_xfer, BOOLEAN reading);
BLKBUFF *pc_allocate_blk(DDRIVE *pdrive, BLKBUFFCNTXT *pbuffcntxt);
void pc_release_buf(BLKBUFF *pblk);
void pc_discard_buf(BLKBUFF *pblk);
BLKBUFF *pc_read_blk(DDRIVE *pdrive, dword blockno);
BLKBUFF *pc_sys_sector(DDRIVE *pdr, BLKBUFF *pscratch_buff);
BLKBUFF *pc_scratch_blk(void);
void pc_free_sys_sector(BLKBUFF *pblk);
void pc_free_scratch_blk(BLKBUFF *pblk);
BLKBUFF *pc_init_blk(DDRIVE *pdrive, dword blockno);
void pc_free_all_blk(DDRIVE *pdrive);
BOOLEAN pc_write_blk(BLKBUFF *pblk);
BLKBUFF *pc_find_blk(DDRIVE *pdrive, dword blockno);
void pc_flush_chain_blk(DDRIVE *pdrive, dword cluster);
void pc_initialize_block_pool(BLKBUFFCNTXT *pbuffcntxt, int nblkbuffs, BLKBUFF *pmem_block_pool, byte *raw_buffer_space, dword data_size_bytes);
void debug_check_blocks(BLKBUFFCNTXT *pbuffcntxt, int numblocks, char *where, dword line);
void display_free_lists(char *in_where);
void check_blocks(DDRIVE *pdrive, char *prompt, dword line);
int check_drive_name_mount(byte *name, int use_charset); /* rtdevio.c */
BOOLEAN check_drive_number_mount(int driveno);
DDRIVE *check_drive_by_name(byte *name, int use_charset);
DDRIVE *check_drive_by_number(int driveno, BOOLEAN check_mount);
void release_drive_mount(int driveno);
BOOLEAN release_drive_mount_write(int driveno);
BOOLEAN raw_devio_xfer(DDRIVE *pdr, dword blockno, byte * buf, dword n_to_xfer, BOOLEAN raw, BOOLEAN reading);
DROBJ *_pc_get_user_cwd(DDRIVE *pdrive); /* rtdrobj.c */
DROBJ *pc_fndnode(byte *path, int use_charset);
DROBJ *pc_get_inode( DROBJ *pobj, DROBJ *pmom, byte *filename, byte *fileext, int action, int use_charset);
DROBJ *pc_rget_inode( DROBJ *pobj, DROBJ *pmom, byte *filename, byte *fileext, int action, int use_charset);
DROBJ *pc_get_mom(DROBJ *pdotdot);
DROBJ *pc_mkchild( DROBJ *pmom);
#if (INCLUDE_EXFATORFAT64)
/* Note: This is a new way of doing things for all. Leave conditional until testing is completer */
DROBJ *pc_mknode(DROBJ *pmom ,byte *filename, byte *fileext, byte attributes, FINODE *infinode,int use_charset);
#else
DROBJ *pc_mknode(DROBJ *pmom ,byte *filename, byte *fileext, byte attributes, dword incluster,int use_charset);
#endif
void pc_init_directory_cluster(DROBJ *pobj, byte *pbuffer);
BOOLEAN pc_rmnode( DROBJ *pobj);
void pc_update_finode_datestamp(FINODE *pfinode, BOOLEAN set_archive, int set_date_mask);
BOOLEAN pc_update_by_finode(FINODE *pfinode, int entry_index, BOOLEAN set_archive, int set_date_mask);
void pc_init_inode(FINODE *pdir, KS_CONSTANT byte *filename,
KS_CONSTANT byte *fileext, byte attr,
dword cluster, dword size, DATESTR *crdate);
void pc_ino2dos (DOSINODE *pbuff, FINODE *pdir);
DROBJ *pc_get_root( DDRIVE *pdrive);
dword pc_firstblock( DROBJ *pobj);
BOOLEAN pc_next_block( DROBJ *pobj);
dword pc_l_next_block(DDRIVE *pdrive, dword curblock);
void pc_marki( FINODE *pfi, DDRIVE *pdrive, dword sectorno, int index);
FINODE *pc_scani( DDRIVE *pdrive, dword sectorno, int index);
DROBJ *pc_allocobj(void);
FINODE *pc_alloci(void);
void pc_free_all_drobj( DDRIVE *pdrive);
void pc_free_all_i( DDRIVE *pdrive);
void pc_freei(FINODE *pfi);
void pc_freeobj( DROBJ *pobj);
void pc_dos2inode (FINODE *pdir, DOSINODE *pbuff);
BOOLEAN pc_isavol( DROBJ *pobj);
BOOLEAN pc_isadir( DROBJ *pobj);
BOOLEAN pc_isroot( DROBJ *pobj);
BOOLEAN pc_init_drv_fat_info32(DDRIVE *pdr, struct pcblk0 *pbl0); /* rtfat32.c */
BOOLEAN pc_mkfs32(int driveno, FMTPARMS *pfmt, BOOLEAN use_raw);
BOOLEAN pc_gblk0_32(DDRIVE *pdr, struct pcblk0 *pbl0, byte *b);
BOOLEAN pc_validate_partition_type(byte p_type);
BOOLEAN fat_flushinfo(DDRIVE *pdr);
/* rtfatdrvrd.c */
BOOLEAN fatop_check_freespace(DDRIVE *pdr);
void fatop_close_driver(DDRIVE *pdr);
BOOLEAN fatop_get_cluster(DDRIVE *pdr, dword clno, dword *pvalue);
dword fatop_next_cluster(DDRIVE *pdr, dword cluster);
BOOLEAN fatop_add_free_region(DDRIVE *pdr, dword cluster, dword ncontig, BOOLEAN do_erase);
dword fatop_get_frag_async(DDRIVE *pdr, byte *palt_buffer, dword alt_buffer_size, dword startpt, dword *pnext_cluster, dword n_clusters, int *end_of_chain);
dword fatop_get_frag(DDRIVE *pdr, byte *palt_buffer, dword alt_buffer_size, dword startpt, dword *pnext_cluster, dword n_clusters, int *end_of_chain);
int fatop_page_continue_check_freespace(DDRIVE *pdr);
void fatop_page_start_check_freespace(DDRIVE *pdr);
byte * fatxx_pfswap(DDRIVE *pdr, dword index, BOOLEAN for_write);
void fatop_get_page_masks(DDRIVE *pdr, dword *mask_offset, dword *mask_cl_page, dword *cl_per_block, dword *cl_to_page_shift, dword * bytes_per_entry);
BOOLEAN fatxx_fword(DDRIVE *pdr, dword index, word *pvalue, BOOLEAN putting);
/* rtfatdrvwr.c */
dword fatop_alloc_chain(DDRIVE *pdr, BOOLEAN is_file, dword hint_cluster, dword previous_end, dword *pfirst_new_cluster, dword n_clusters, dword min_clusters);
dword fatop_grow_dir(DDRIVE *pdr, dword previous_end);
dword fatop_alloc_dir(DDRIVE *pdr, dword clhint);
dword fatop_clgrow(DDRIVE *pdr, dword clno, dword *previous_end);
void fatop_truncate_dir(DDRIVE *pdr, DROBJ *pobj, dword cluster, dword previous_end);
void fatop_clrelease_dir(DDRIVE *pdr, dword clno);
BOOLEAN fatop_freechain(DDRIVE *pdr, dword cluster, dword max_clusters_to_free);
BOOLEAN fatop_free_frag(DDRIVE *pdr, dword flags, dword prev_cluster, dword startpt, dword n_contig);
BOOLEAN fatop_remove_free_region(DDRIVE *pdr, dword cluster, dword ncontig);
BOOLEAN fatop_flushfat(DDRIVE *pdr);
BOOLEAN fatop_link_frag(DDRIVE *pdr, byte *palt_buffer, dword alt_buffer_size, dword flags, dword cluster, dword startpt, dword n_contig);
dword fatop_find_contiguous_free_clusters(DDRIVE *pdr, dword startpt, dword endpt, dword min_clusters, dword max_clusters, dword *p_contig, int *is_error, int allocation_scheme);
dword _fatop_find_contiguous_free_clusters(DDRIVE *pdr, dword startpt, dword endpt, dword min_clusters, dword max_clusters, dword *p_contig, int *is_error);
BOOLEAN fatop_pfaxxterm(DDRIVE *pdr, dword clno);
BOOLEAN fatop_pfaxx(DDRIVE *pdr, dword clno, dword value);
#if (INCLUDE_NAND_DRIVER)
/* rteraseblock.c */
BOOLEAN eraseop_erase_blocks(DDRIVE *pdr, dword cluster, dword ncontig);
dword eraseop_find_free_clusters(DDRIVE *pdr, dword startpt, dword endpt, dword min_clusters, dword max_clusters, int allocation_scheme, dword *p_contig, int *is_error);
#endif
/* drdynamic.c */
void pc_rtfs_poll_devices_ready(void);
BOOLEAN pc_rtfs_media_remount(void *devicehandle);
void pc_rtfs_regen_insert_parms(struct rtfs_media_insert_args *prtfs_insert_parms, RTFS_DEVI_MEDIA_PARMS *pmedia_info);
byte *pc_rtfs_iomalloc(dword alloc_size, void **paligned_data);
BOOLEAN rtfs_dynamic_init_configuration(struct rtfs_init_resource_reply *preply);
BOOLEAN RTFS_DEVI_process_mount_parms(DDRIVE *pdr);
BLKBUFF *RTFS_DEVI_alloc_filebuffer(DDRIVE *pdr);
void RTFS_DEVI_release_filebuffer(BLKBUFF *pblk);
BOOLEAN fat_devio_write(DDRIVE *pdrive, dword fat_blockno, dword nblocks, byte *fat_data, int fatnumber); /* rtfblock.c */
BOOLEAN fat_devio_read(DDRIVE *pdrive, dword blockno,dword nblocks, byte *fat_data);
BOOLEAN pc_flush_fat_blocks(DDRIVE *pdrive);
BOOLEAN pc_write_fat_blocks(DDRIVE *pdrive,dword fat_blockno, dword nblocks, byte *fat_data,dword which_copy);
BOOLEAN pc_write_fat_block_buffer_page(DDRIVE *pdrive, FATBUFF *pblk);
int pc_read_fat_blocks (DDRIVE* pdrive, byte* buffer, dword first_block, dword num_blocks);
BOOLEAN pc_initialize_fat_block_pool(FATBUFFCNTXT *pfatbuffcntxt,
int fat_buffer_size, FATBUFF *pfat_buffers,
int fat_hashtbl_size, FATBUFF **pfat_hash_table,
byte **pfat_primary_cache, dword *pfat_primary_index);
void pc_free_all_fat_buffers(DDRIVE *pdrive);
byte *pc_map_fat_stream(DDRIVE *pdrive, dword *return_block_count, dword first_block, dword byte_offset, dword byte_count, byte *alt_buffer, dword alt_buffer_size, BOOLEAN is_a_read);
byte *pc_map_fat_sector(DDRIVE *pdrive, FATBUFFCNTXT *pfatbuffcntxt,dword blockno, int n_dirty, dword usage_flags);
int pc_async_flush_fat_blocks(DDRIVE *pdrive,dword max_flushes_per_pass);
void pc_set_mbuff_dirty(PCMBUFF *pcmb, dword block_offset, int block_count);
void pc_zero_mbuff_dirty(PCMBUFF *pcmb);
BOOLEAN rtfs_resource_init(void); /* rtkernfn.c */
void pc_rtfs_register_poll_devices_ready_handler(RTFS_DEVI_POLL_REQUEST_VECTOR *poll_device_vector, void (*poll_device_ready)(void));
DDRIVE *rtfs_claim_media_and_buffers(int driveno);
void rtfs_release_media_and_buffers(int driveno);
DROBJ *rtfs_get_user_pwd(RTFS_SYSTEM_USER *pu,int driveno, BOOLEAN doclear);
void rtfs_set_user_pwd(RTFS_SYSTEM_USER *pu, DROBJ *pobj);
PRTFS_SYSTEM_USER rtfs_get_system_user(void);
void pc_free_user(void);
void pc_free_other_user(dword taskId);
void pc_free_all_users(int driveno);
void rtfs_set_driver_errno(dword error);
dword rtfs_get_driver_errno(void);
void rtfs_clear_errno(void);
void _rtfs_set_errno(int error);
void _debug_rtfs_set_errno(int error, char *filename, long linenumber);
int get_errno(void);
int pc_num_drives(void);
int pc_num_users(void);
int pc_nuserfiles(void);
BOOLEAN pc_validate_driveno(int driveno);
BOOLEAN pc_memory_init(void);
DDRIVE *pc_memory_ddrive(DDRIVE *pdrive);
DROBJ *pc_memory_drobj(DROBJ *pobj);
FINODE *pc_memory_finode(FINODE *pinode);
void rtfs_kern_gets(byte *buffer);
void rtfs_kern_puts(byte *buffer);
int rtfs_debug_zero(void);
void rtfs_assert_break(void);
void rtfs_assert_test(void);
BOOLEAN pc_i_dskopen(int driveno, BOOLEAN is_async); /* rtlowl.c */
void pc_drive_scaleto_blocksize(DDRIVE *pdr, int bytspsector);
BOOLEAN pc_auto_dskopen(DDRIVE *pdr);
void pc_i_dskopen_complete(DDRIVE *pdr);
int pc_read_partition_table(DDRIVE *pdr, struct mbr_entry_specification *pspec);
BOOLEAN pc_gblk0(DDRIVE *pdr, struct pcblk0 *pbl0);
BOOLEAN pc_clzero(DDRIVE *pdrive, dword cluster);
DDRIVE *pc_drno_to_drive_struct(int driveno);
DDRIVE *pc_drno2dr(int driveno);
BOOLEAN pc_dskfree(int driveno);
dword pc_sec2cluster(DDRIVE *pdrive, dword blockno);
dword pc_sec2index(DDRIVE *pdrive, dword blockno);
dword pc_cl2sector(DDRIVE *pdrive, dword cluster);
/* rtvfatrd.c rtnvfatrd.c */
BOOLEAN pc_findin( DROBJ *pobj, byte *filename, byte *fileext, int action, int use_charset);
BOOLEAN pc_rfindin( DROBJ *pobj, byte *filename, int action, int use_charset, BOOLEAN starting);
byte *pc_nibbleparse(byte *filename, byte *fileext, byte *path, int use_charset);
BOOLEAN pc_parsepath(byte *topath, byte *filename, byte *fileext, byte *path, int use_charset);
BOOLEAN pc_patcmp_vfat(byte *in_pat, byte *name, BOOLEAN dowildcard, int use_charset);
byte pc_cksum(byte *test);
BOOLEAN pc_isdot(byte *fname, byte *fext);
BOOLEAN pc_isdotdot(byte *fname, byte *fext);
BOOLEAN pc_get_lfn_filename(DROBJ *pobj, byte *path, int use_charset);
BOOLEAN pc_multi_dir_get(DROBJ *pobj, BLKBUFF **pscan_buff, byte **pscan_data, byte *puser_buffer, dword *n_blocks, BOOLEAN do_increment);
/* rtvfatwr.c and rtnvfatwr.c */
BOOLEAN pc_insert_inode(DROBJ *pobj , DROBJ *pmom, byte attr, dword initcluster, byte *filename, byte *fileext, int use_charset);
void pc_zero_lfn_info(FINODE *pdir);
BOOLEAN _illegal_lfn_char(byte ch);
BOOLEAN pc_delete_lfn_info(DROBJ *pobj);
/* rtfreemanager.c */
BOOLEAN free_manager_attach(DDRIVE *pdr);
BOOLEAN free_manager_is_attached(DDRIVE *pdr);
dword free_manager_count_frags(DDRIVE *pdr);
void free_manager_close(DDRIVE *pdr);
void free_manager_revert(DDRIVE *pdr);
dword free_manager_find_contiguous_free_clusters(DDRIVE *pdr, dword startpt, dword endpt, dword min_clusters, dword max_clusters, dword *p_contig, int *is_error);
BOOLEAN free_manager_release_clusters(DDRIVE *pdr, dword cluster, dword ncontig, BOOLEAN do_erase);
void free_manager_claim_clusters(DDRIVE *pdr, dword cluster, dword ncontig);
/* rtfragmt.c */
void pc_fraglist_init_freelist(void);
dword pc_fraglist_count_clusters(REGION_FRAGMENT *pf,REGION_FRAGMENT *pfend);
REGION_FRAGMENT *pc_end_fragment_chain(REGION_FRAGMENT *pf);
REGION_FRAGMENT *pc_fraglist_frag_alloc(DDRIVE *pdr, dword frag_start,
dword frag_end,
REGION_FRAGMENT *pnext);
void pc_fraglist_frag_free(REGION_FRAGMENT *pf);
void pc_fraglist_free_list(REGION_FRAGMENT *pf);
REGION_FRAGMENT *pc_fraglist_set_range(REGION_FRAGMENT *inpf, dword start_location, dword end_location, int *is_error);
REGION_FRAGMENT *pc_fraglist_clear_range(REGION_FRAGMENT *inpf, dword start_location, dword end_location, int *is_error);
dword pc_fragment_size_32(DDRIVE *pdr, REGION_FRAGMENT *pf);
BOOLEAN pc_grow_basic_fragment(FINODE *pefinode, dword first_new_cluster, dword nclusters);
/* rtutbyte.c */
BOOLEAN pc_check_dir_end(byte *fname);
byte *pc_strchr(byte *string, byte ch);
BOOLEAN _illegal_alias_char(byte ch);
void copybuff(void *vto, void *vfrom, int size);
void pc_cppad(byte *to, byte *from, int size);
void rtfs_memset(void *pv, byte b, int n);
BOOLEAN rtfs_bytecomp(byte *p1, byte *p2, int n);
int pc_path_to_driveno(byte *path, int use_charset); /* rtutil.c */
int pc_parse_raw_drive(byte *path, int use_charset);
byte *pc_parsedrive(int *driveno, byte *path, int use_charset);
byte *pc_mpath(byte *to, byte *path, byte *filename, int use_charset);
BOOLEAN pc_search_csl(byte *set, byte *string);
BOOLEAN name_is_reserved(byte *filename);
void RTFS_ARGSUSED_PVOID(void * p);
void RTFS_ARGSUSED_INT(int i);
void RTFS_ARGSUSED_DWORD(dword l);
dword to_DWORD( byte *from);
word to_WORD( byte *from);
void fr_WORD( byte *to, word from);
void fr_DWORD( byte *to, dword from);
#if (INCLUDE_MATH64)
void to_DDWORD(ddword *to, byte *from);
void fr_DDWORD( byte *to, ddword from);
ddword m64_native_set32(dword a, dword b);
ddword m64_lshift(ddword b, dword c);
ddword m64_rshift(ddword b, dword c);
ddword m64_minus(ddword b, ddword c);
ddword m64_minus32(ddword b, dword c);
ddword m64_plus(ddword b, ddword c);
ddword m64_plus32(ddword b, dword c);
ddword m64_set32(dword hi, dword lo);
#endif
void *rtfs_port_malloc(int nbytes); /* portkern.c (target specific) */
void rtfs_port_free(void *pbytes);
dword rtfs_port_alloc_mutex(char *mutex_name);
void rtfs_port_free_mutex(dword handle);
void rtfs_port_claim_mutex(dword handle);
void rtfs_port_release_mutex(dword handle);
dword rtfs_port_alloc_signal(void);
void rtfs_port_shutdown(void);
void rtfs_port_set_task_env(void *pusercontext);
void *rtfs_port_get_task_env(dword taskId);
void rtfs_port_clear_signal(dword handle);
int rtfs_port_test_signal(dword handle, int timeout);
void rtfs_port_set_signal(dword handle);
void rtfs_port_sleep(int sleeptime);
dword rtfs_port_elapsed_zero(void);
int rtfs_port_elapsed_check(dword zero_val, int timeout);
dword rtfs_port_get_taskid(void);
void rtfs_port_disable(void);
void rtfs_port_enable(void);
void rtfs_port_exit(void);
DATESTR *pc_getsysdate(DATESTR * pd);
/* In prefiocom but should be global for Pro */
dword truncate_32_count(dword file_pointer, dword count);
dword truncate_32_sum(dword val1, dword val2);
#ifdef __cplusplus
}
#endif
/* =========================== */
/* End Rtfs internal prototypes */
/* =========================== */
#define rtfs_set_errno(ERROR,CALLER, LINENUMBER) _debug_rtfs_set_errno(ERROR, CALLER, LINENUMBER)
#if (INCLUDE_DEBUG_RUNTIME_STATS)
#define UPDATE_RUNTIME_STATS(DRIVE, FIELD, COUNT) DRIVE->drive_rtstats.FIELD += COUNT;
#else
#define UPDATE_RUNTIME_STATS(DRIVE, FIELD, COUNT)
#endif
#if (INCLUDE_CS_UNICODE)
/* Unicode API */
#define pc_mv_uc(A,B) pc_mv_cs((A),(B),CS_CHARSET_UNICODE)
#define pc_get_volume_uc(A,B) pc_get_volume_cs((A),(B),CS_CHARSET_UNICODE)
#define pc_set_volume_uc(A,B) pc_set_volume_cs((A),(B),CS_CHARSET_UNICODE)
#define pc_get_cwd_uc(A,B) pc_get_cwd_cs((A),(B),CS_CHARSET_UNICODE)
#define pc_pwd_uc(A,B) pc_pwd_cs((A),(B),CS_CHARSET_UNICODE)
#define pc_gfirst_uc(A,B) pc_gfirst_cs((A),(B),CS_CHARSET_UNICODE)
#define pc_glast_uc(A,B) pc_glast_cs((A),(B),CS_CHARSET_UNICODE)
#define pc_gnext_uc(A) pc_gnext_cs((A),CS_CHARSET_UNICODE)
#define pc_gprev_uc(A) pc_gprev_cs((A),CS_CHARSET_UNICODE)
#define pc_isdir_uc(A) pc_isdir_cs((A),CS_CHARSET_UNICODE)
#define pc_isvol_uc(A) pc_isvol_cs((A),CS_CHARSET_UNICODE)
#define pc_get_attributes_uc(A,B) pc_get_attributes_cs((A),(B),CS_CHARSET_UNICODE)
#define pc_mkdir_uc(A) pc_mkdir_cs((A),CS_CHARSET_UNICODE)
#define pc_rmdir_uc(A) pc_rmdir_cs((A),CS_CHARSET_UNICODE)
#define pc_set_attributes_uc(A,B) pc_set_attributes_cs((A),(B),CS_CHARSET_UNICODE)
#define pc_set_cwd_uc(A) pc_set_cwd_cs((A),CS_CHARSET_UNICODE)
#define pc_stat_uc(A,B) pc_stat_cs((A),(B),CS_CHARSET_UNICODE)
#define pc_unlink_uc(A) pc_unlink_cs((A),CS_CHARSET_UNICODE)
#define po_open_uc(A,B,C) po_open_cs((A),(B),(C), CS_CHARSET_UNICODE)
#define pc_get_default_drive_uc(A) pc_get_default_drive_cs((A), CS_CHARSET_UNICODE)
#define pc_deltree_uc(A) pc_deltree_cs((A),CS_CHARSET_UNICODE)
#define pc_enumerate_uc(A,B,C,D,E,F,G,H,I) pc_enumerate_cs((A),(B),(C),(D),(E),(F),(G),(H),(I),CS_CHARSET_UNICODE)
#define pc_get_dirent_info_uc(A,B) pc_get_dirent_info_cs((A),(B),CS_CHARSET_UNICODE)
#define pc_set_dirent_info_uc(A,B) pc_set_dirent_info_cs((A),(B),CS_CHARSET_UNICODE)
#define pc_get_media_parms_uc(A,B) pc_get_media_parms_cs((A),(B),CS_CHARSET_UNICODE)
#define pc_format_media_uc(A) pc_format_media_cs((A),CS_CHARSET_UNICODE)
#define pc_format_volume_uc(A) pc_format_volume_cs((A),CS_CHARSET_UNICODE)
#define pc_format_volume_ex_uc(A, B) pc_format_volume_ex_cs((A), (B), CS_CHARSET_UNICODE)
#define pc_partition_media_uc(A,B) pc_partition_media_cs((A),(B), CS_CHARSET_UNICODE)
/* Non-Unicode API */
#define pc_mv(A,B) pc_mv_cs((A),(B),CS_CHARSET_NOT_UNICODE)
#define pc_get_volume(A,B) pc_get_volume_cs((A),(B),CS_CHARSET_NOT_UNICODE)
#define pc_set_volume(A,B) pc_set_volume_cs((A),(B),CS_CHARSET_NOT_UNICODE)
#define pc_get_cwd(A,B) pc_get_cwd_cs((A),(B),CS_CHARSET_NOT_UNICODE)
#define pc_pwd(A,B) pc_pwd_cs((A),(B),CS_CHARSET_NOT_UNICODE)
#define pc_gfirst(A,B) pc_gfirst_cs((A),(B),CS_CHARSET_NOT_UNICODE)
#define pc_glast(A,B) pc_glast_cs((A),(B),CS_CHARSET_NOT_UNICODE)
#define pc_gnext(A) pc_gnext_cs((A) ,CS_CHARSET_NOT_UNICODE)
#define pc_gprev(A) pc_gprev_cs((A) ,CS_CHARSET_NOT_UNICODE)
#define pc_isdir(A) pc_isdir_cs((A),CS_CHARSET_NOT_UNICODE)
#define pc_isvol(A) pc_isvol_cs((A),CS_CHARSET_NOT_UNICODE)
#define pc_get_attributes(A,B) pc_get_attributes_cs((A),(B),CS_CHARSET_NOT_UNICODE)
#define pc_mkdir(A) pc_mkdir_cs((A),CS_CHARSET_NOT_UNICODE)
#define pc_rmdir(A) pc_rmdir_cs((A),CS_CHARSET_NOT_UNICODE)
#define pc_set_attributes(A,B) pc_set_attributes_cs((A), (B),CS_CHARSET_NOT_UNICODE)
#define pc_set_cwd(A) pc_set_cwd_cs((A),CS_CHARSET_NOT_UNICODE)
#define pc_stat(A,B) pc_stat_cs((A),(B),CS_CHARSET_NOT_UNICODE)
#define pc_unlink(A) pc_unlink_cs((A),CS_CHARSET_NOT_UNICODE)
#define po_open(A,B,C) po_open_cs((A),(B),(C), CS_CHARSET_NOT_UNICODE)
#define pc_get_default_drive(A) pc_get_default_drive_cs((A), CS_CHARSET_NOT_UNICODE)
#define pc_deltree(A) pc_deltree_cs((A),CS_CHARSET_NOT_UNICODE)
#define pc_enumerate(A,B,C,D,E,F,G,H,I) pc_enumerate_cs((A),(B),(C),(D),(E),(F),(G),(H),(I),CS_CHARSET_NOT_UNICODE)
#define pc_get_dirent_info(A,B) pc_get_dirent_info_cs((A),(B),CS_CHARSET_NOT_UNICODE)
#define pc_set_dirent_info(A,B) pc_set_dirent_info_cs((A),(B),CS_CHARSET_NOT_UNICODE)
#define pc_get_media_parms(A,B) pc_get_media_parms_cs((A),(B),CS_CHARSET_NOT_UNICODE)
#define pc_format_media(A) pc_format_media_cs((A),CS_CHARSET_NOT_UNICODE)
#define pc_format_volume(A) pc_format_volume_cs((A),CS_CHARSET_NOT_UNICODE)
#define pc_format_volume_ex(A, B) pc_format_volume_ex_cs((A), (B), CS_CHARSET_NOT_UNICODE)
#define pc_partition_media(A,B) pc_partition_media_cs((A),(B), CS_CHARSET_NOT_UNICODE)
#endif
#if (INCLUDE_CS_UNICODE)
#define CS_CHARSET_ARGS use_charset /* Extracts character set from passed parameters */
#else
#define CS_CHARSET_ARGS CS_CHARSET_NOT_UNICODE /* Default character set do not change */
#endif
#if (INCLUDE_RTFS_PROPLUS) /* Include additional ProPlus internal declarations */
/* =========================== */
/* RtfsProPlus prototypes */
/* =========================== */
#ifdef __cplusplus
extern "C" {
#endif
/* ============================ */
/* ProPlus API Prototypes */
/* ============================ */
#if (INCLUDE_CS_UNICODE)
/* Prototypes of unicode / Non-Unicode selectable APIS */
int pc_cfilio_open_cs(byte *name, word flag, EFILEOPTIONS *poptions,int use_charset);
int pc_efilio_async_unlink_start_cs(byte *filename,int use_charset);
int pc_efilio_open_cs(byte *name, word flag, word mode, EFILEOPTIONS *poptions, int use_charset);
#else
/* Prototypes of Non-Unicode APIS */
int pc_cfilio_open(byte *name, word flag, EFILEOPTIONS *poptions);
int pc_efilio_async_unlink_start(byte *filename);
int pc_efilio_open(byte *name, word flag, word mode, EFILEOPTIONS *poptions);
#endif
/* rtfsproplustests\efishell.c */
void efio_shell(void);
/* rtfsproplus\prapiasy.c */
int pc_async_continue(int driveno, int target_state, int steps);
int pc_diskio_async_flush_start(byte *path);
int pc_diskio_async_mount_start(byte *diskid);
int pc_efilio_async_flush_start(int fd);
int pc_efilio_async_close_start(int fd);
/* rtfsproplus\prapiefi.c */
BOOLEAN pc_efilio_settime(int fd,word new_time, word new_date);
BOOLEAN pc_efilio_flush(int fd);
BOOLEAN pc_efilio_lseek(int fd, dword offset_hi, dword offset_lo, int origin, dword *pnewoffset_hi, dword *pnewoffset_lo);
#if (INCLUDE_MATH64)
ddword pc_efilio_lseek64(int fd, ddword offset, int origin);
#endif
BOOLEAN pc_efilio_chsize(int fd, dword newsize_hi, dword newsize_lo);
BOOLEAN pc_efilio_read(int fd, byte *buf, dword count, dword *nread);
BOOLEAN pc_efilio_write(int fd, byte *buff, dword count, dword *nwritten);
BOOLEAN pc_efilio_setalloc(int fd, dword cluster, dword reserve_count);
BOOLEAN pc_efilio_setbuff(byte *path, byte *buffer, dword buffer_size_blocks);
int pc_efilio_get_file_extents(int fd, int infolistsize, FILESEGINFO *plist, BOOLEAN report_clusters, BOOLEAN raw);
/* rtfsproplus\prapilinext.c */
BOOLEAN pc_efilio_extract(int fd1, int fd2, dword n_clusters);
BOOLEAN pc_efilio_swap(int fd1, int fd2, dword n_clusters);
BOOLEAN pc_efilio_remove(int fd1, dword n_clusters);
/* rtfsproplus\prfastio.c */
BOOLEAN pc_efilio_fpos_sector(int fd, BOOLEAN isreadfp, BOOLEAN raw, dword *psectorno, dword *psectorcount);
/* rtfsproplus\proplusglue.c */
BOOLEAN pc_bytes_to_clusters(int driveno, dword bytes_hi, dword bytes_lo, dword *pcluster_mod);
BOOLEAN pc_clusters_to_bytes(int driveno, dword n_clusters, dword *pbytes_hi, dword *pbytes_lo);
void pc_subtract_64(dword hi_1, dword lo_1, dword hi_0, dword lo_0, dword *presult_hi, dword *presult_lo);
void pc_add_64(dword hi_1, dword lo_1, dword hi_0, dword lo_0, dword *presult_hi, dword *presult_lo);
dword pc_cluster_to_sector(int driveno, dword cluster, BOOLEAN raw);
dword pc_sector_to_cluster(int driveno, dword sector, BOOLEAN raw);
void pc_clusters2bytes64(DDRIVE *pdr, dword n_clusters, dword *pbytes_hi, dword *pbytes_lo);
/* ============================ */
/* End ProPlus API Prototypes */
/* ============================ */
/* ============================ */
/* ProPlus Internal Prototypes */
/* ============================ */
/* rtfsproplus\prapiasy.c */
BOOLEAN _pc_check_if_async(PC_FILE *pefile);
dword _get_operating_flags(PC_FILE *pefile);
void _set_asy_operating_flags(PC_FILE *pefile, dword new_operating_flags, int success);
/* rtfsproplus\prapicfi.c */
BOOLEAN _pc_cfilio_read(PC_FILE *preaderefile, byte *buff, dword count, dword *nread);
BOOLEAN _pc_cfilio_write(PC_FILE *pwriterefile, byte *buff, dword count, dword *nwritten);
dword _pc_cfilio_get_max_write_count(PC_FILE *pwriterefile, dword count);
dword _pc_cfilio_get_max_read_count(PC_FILE *pefile, dword count);
PC_FILE *pc_cfilio_fd2file(int fd, BOOLEAN unlock);
void pc_cfilio_clear_open_flags(PC_FILE *pefile, word flags);
void pc_cfilio_set_open_flags(PC_FILE *pefile, word flags);
ddword pc_efilio_get_fp_ddw(PC_FILE *pefile);
ddword pc_cfilio_get_fp_ddw(PC_FILE *pefile);
ddword pc_cfilio_get_file_size_ddw(PC_FILE *pefile);
/* rtfsproplus\prapicsk.c */
BOOLEAN _pc_cfilio_lseek(PC_FILE *pwriterefile, int which_pointer, dword offset_hi, dword offset_lo, int origin, dword *poffset_hi, dword *poffset_lo);
BOOLEAN _pc_cstreamio_lseek(PC_FILE *pwriterefile, int which_pointer, ddword offset_ddw, int origin, ddword *poffset_ddw);
/* rtfsproplus\prapiefi.c */
int _pc_efilio_open(DDRIVE *pdrive, byte *name, word flag, word mode, EFILEOPTIONS *poptions, int use_charset);
BOOLEAN _pc_efilio_flush_file_buffer(PC_FILE *pefile);
BOOLEAN _pc_efilio_flush(PC_FILE *pefile);
void _pc_efilio_free_excess_clusters(PC_FILE *pefile);
BOOLEAN pc_efilio_close(int fd);
PC_FILE *pc_efilio_start_close(int fd, BOOLEAN *is_aborted);
BOOLEAN _pc_efilio_close(PC_FILE *pefile);
void _pc_cfilio_set_file_size(PC_FILE *pefile, dword dstart, dword length_hi, dword length_lo);
dword _pc_efilio_first_cluster(PC_FILE *pefile);
dword _pc_efilio_last_cluster(PC_FILE *pefile);
void _pc_efilio_reset_seek(PC_FILE *pefile);
void _pc_efilio_coalesce_fragments(PC_FILE *pefile);
BOOLEAN _pc_efilio_lseek(PC_FILE *pefile, dword offset_hi, dword offset_lo, int origin, dword *pnewoffset_hi, dword *pnewoffset_lo);
BOOLEAN _pc_efilio_read(PC_FILE *pefile, byte *buf, dword count, dword *nread);
BOOLEAN _pc_efilio_write(PC_FILE *pefile, byte *buff, dword count, dword *nwritten);
BOOLEAN pc_efilio_fstat(int fd, ERTFS_EFILIO_STAT *pestat);
BOOLEAN _pc_efilio_fstat(PC_FILE *pefile, ERTFS_EFILIO_STAT *pestat);
BOOLEAN _pc_check_efile_open_mode(PC_FILE *pefile);
void fatop_page_start_check_freespace(DDRIVE *pdr);
#if (INCLUDE_CIRCULAR_FILES)
/* rtfsproplus\prapicfi.c */
BOOLEAN pc_cfilio_close(int fd);
BOOLEAN pc_cfilio_read(int fd, byte *buff, dword count, dword *nread);
BOOLEAN pc_cfilio_write(int fd, byte *buff, dword count, dword *nwritten);
BOOLEAN pc_cfilio_setalloc(int fd, dword cluster, dword reserve_count);
/* rtfsproplus\prapicsk.c */
BOOLEAN pc_cfilio_lseek(int fd, int which_pointer, dword offset_hi, dword offset_lo, int origin, dword *poffset_hi, dword *poffset_lo);
BOOLEAN pc_cstreamio_lseek(int fd, int which_pointer, dword offset_hi, dword offset_lo, int origin, dword *poffset_hi, dword *poffset_lo);
BOOLEAN pc_cfilio_extract(int circ_fd, int linear_fd, dword length_hi, dword length_lo,byte *header_buffer, int header_size);
/* rtfsproplus\prapiext.c */
BOOLEAN pc_cfilio_release_all_remap_files(PC_FILE *preaderefile, int abort);
BOOLEAN pc_cfilio_remap_region_purge(PC_FILE *preaderefile,ddword purge_start_ddw, ddword purge_length_ddw);
BOOLEAN pc_cfilio_remap_read(PC_FILE *preaderefile,
ddword reader_file_pointer_ddw,
byte *buf,
dword read_count,
REMAP_RECORD *remap_record);
void pc_cfilio_check_remap_read(PC_FILE *preaderefile,ddword data_start_ddw,ddword data_length_ddw,
ddword *bytes_to_region_ddw,ddword *byte_offset_in_region_ddw,
ddword *bytes_in_region_ddw, REMAP_RECORD **preturn);
void pc_remap_free_list(PC_FILE *preaderefile, REMAP_RECORD *premap);
void pc_cfilio_remap_region_init(PC_FILE *preaderefile,REMAP_RECORD *premap_records,int num_records);
void pc_cfilio_release_remap_file(PC_FILE *premapfile, int abort);
#endif /* (INCLUDE_CIRCULAR_FILES) */
/* rtfsproplus\prasyint.c */
int _pc_async_step(DDRIVE *pdrive, int target_state, int steps);
/* rtfsproplus\prefi32.c */
int _pc_efilio32_open(DDRIVE *pdr,byte *name, word flag, word mode, EFILEOPTIONS *poptions, int use_charset);
void pc_efilio32_open_error(PC_FILE *pefile);
BOOLEAN pc_efilio32_open_complete(PC_FILE *pefile);
int pc_efilio_async_open32_continue(PC_FILE *pefile);
BOOLEAN _pc_efilio32_common_fstat(PC_FILE *pefile, ERTFS_EFILIO_STAT *pestat);
BOOLEAN _pc_efilio32_close(PC_FILE *pefile);
BOOLEAN _pc_efilio32_settime(PC_FILE *pefile,word new_time, word new_date);
BOOLEAN _pc_efilio32_flush(PC_FILE *pefile,dword max_clusters_per_pass);
BOOLEAN _pc_efilio32_read(PC_FILE *pefile, byte *buf, dword count, dword *nread);
/* rtfsproplus\preficom.c */
void _pc_efiliocom_sync_current_fragment(PC_FILE *pefile,FINODE *peffinode);
BOOLEAN _pc_efiliocom_write(PC_FILE *pefile,FINODE *peffinode, byte *buff, dword count, dword *nwritten);
void _pc_efiliocom_reset_seek(PC_FILE *pefile,FINODE *peffinode);
BOOLEAN _pc_efiliocom_lseek(PC_FILE *pefile,FINODE *peffinode, dword offset_hi, dword offset, int origin, dword *pnewoffset_hi,dword *pnewoffset);
BOOLEAN _pc_efiliocom_io(PC_FILE *pefile,FINODE *peffinode, byte *pdata, dword n_bytes, BOOLEAN reading, BOOLEAN appending);
BOOLEAN _pc_efiliocom_resize_current_fragment(PC_FILE *pefile,FINODE *peffinode,dword new_size);
/* rtfsproplus\prefinode.c */
int pc_efinode_async_load_continue(FINODE *pefinode);
dword _pc_efinode_count_to_link(FINODE *pefinode,dword allocation_policy);
BOOLEAN _pc_efinode_queue_cluster_links(FINODE *pefinode, dword allocation_policy);
void _pc_efinode_coalesce_fragments(FINODE *pefinode);
BOOLEAN load_efinode_fragment_list(FINODE *pefinode);
BOOLEAN load_efinode_fragments_until(FINODE *pefinode, llword offset);
void pc_free_excess_clusters(FINODE *pefinode);
void pc_free_efinode(FINODE *pefinode);
BOOLEAN pc_efinode_link_or_delete_cluster_chain(FINODE *pefinode, dword flags, dword max_clusters_per_pass);
BOOLEAN pc_efinode_delete_cluster_chain(FINODE *pefinode, dword max_clusters_per_pass);
BOOLEAN _pc_efinode_truncate_finode(FINODE *pfi);
void _pc_efinode_set_file_size(FINODE *pefinode, dword length_hi, dword length_lo);
BOOLEAN _pc_efinode_chsize(FINODE *pefinode, dword newsize_hi, dword newsize_lo);
REGION_FRAGMENT *pc_region_file_find_free_chain(
DDRIVE *pdrive,
dword allocation_policy,
dword alloc_start_hint,
dword chain_size,
int *p_is_error);
/* rtfsproplus\prfragmt.c */
dword pc_frag_chain_delete_or_link(DDRIVE *pdr,
dword flags,
REGION_FRAGMENT *pf,
dword prev_end_chain,
dword start_contig,
dword clusters_to_process);
REGION_FRAGMENT *pc_fraglist_find_next_cluster(REGION_FRAGMENT *pfstart,REGION_FRAGMENT *pfend ,dword this_cluster,dword *pnext_cluster,dword *pstart_offset);
REGION_FRAGMENT *pc_fragment_seek_clusters(REGION_FRAGMENT *pf,dword n_clusters, dword *region_base_offset);
REGION_FRAGMENT *pc_fraglist_split(DDRIVE *pdr, REGION_FRAGMENT *pfstart,dword n_clusters,int *is_error);
REGION_FRAGMENT *pc_fraglist_find_cluster(REGION_FRAGMENT *pfstart,REGION_FRAGMENT *pfend ,dword cluster);
void pc_fraglist_coalesce(REGION_FRAGMENT *pfstart);
dword pc_fraglist_count_list(REGION_FRAGMENT *pf,REGION_FRAGMENT *pfend);
BOOLEAN pc_fraglist_remove_free_region(DDRIVE *pdr, REGION_FRAGMENT *pf);
BOOLEAN pc_fraglist_add_free_region(DDRIVE *pdr, REGION_FRAGMENT *pf);
BOOLEAN pc_fraglist_fat_free_list(DDRIVE *pdr, REGION_FRAGMENT *pf);
/* rtfsproplus\prmath64.c */
BOOLEAN return_false(void);
ddword pc_byte2ddwclmodbytes(DDRIVE *pdr, ddword nbytes64);
ddword pc_alloced_bytes_from_clusters_64(DDRIVE *pdr, dword total_alloced_clusters);
FINODE_EXTENDED *pc_memory_finode_ex(FINODE_EXTENDED *pinode);
dword pc_byte2clmodbytes(DDRIVE *pdr, dword nbytes);
dword pc_byte2cloff(DDRIVE *pdr, dword nbytes);
dword pc_byte2cloffbytes(DDRIVE *pdr, dword nbytes);
#ifdef __cplusplus
}
#endif
/* =========================== */
/* End RtfsPro Plus prototypes */
/* =========================== */
#if (INCLUDE_CS_UNICODE)
/* Unicode API */
#define pc_cfilio_open_uc(A,B,C) pc_cfilio_open_cs((A),(B),(C),CS_CHARSET_UNICODE)
#define pc_efilio_async_unlink_start_uc(A) pc_efilio_async_unlink_start_cs((A), CS_CHARSET_UNICODE)
#define pc_efilio_open_uc(A,B,C,D) pc_efilio_open_cs((A),(B),(C),(D),CS_CHARSET_UNICODE)
/* Non-Unicode API */
#define pc_cfilio_open(A,B,C) pc_cfilio_open_cs((A),(B),(C),CS_CHARSET_NOT_UNICODE)
#define pc_efilio_async_unlink_start(A) pc_efilio_async_unlink_start_cs((A), CS_CHARSET_NOT_UNICODE)
#define pc_efilio_open(A,B,C,D) pc_efilio_open_cs((A),(B),(C),(D),CS_CHARSET_NOT_UNICODE)
#endif
#endif
#if (INCLUDE_MATH64) /* ddword type, ProPlus only */
ddword po_lseek64(int fd, ddword offset, int origin);
ddword m64_native_set32(dword a, dword b);
#endif
#if (INCLUDE_EXTENDED_ATTRIBUTES)
#define RTFS_EXTATTRIBUTE_SIGNATURE "RTFSEXTENTENDEDATTRIBUTE"
#define RTFS_EXTATTRIBUTE_SIGNATURE_SIZE 24
#define RTFS_EXTATTRIBUTE_RECORD_SIZE 28
dword pc_efilio32_get_dstart(PC_FILE *pefile);
BOOLEAN pc_efilio32_set_dstart(PC_FILE *pefile, dword dstart);
#endif
#if (INCLUDE_FAT64 && !INCLUDE_EXFAT)
BOOLEAN exfatop_remove_free_region(DDRIVE *pdr, dword cluster, dword ncontig);
BOOLEAN exfatop_add_free_region(DDRIVE *pdr, dword cluster, dword ncontig, BOOLEAN do_erase);
#define pcexfat_set_volume_dirty(A) /* Implement to set and clear dirty bytes in bpb */
#define pcexfat_clear_volume_dirty(A)
dword pc_byte2clmod64(DDRIVE *pdr, dword nbytes_hi, dword nbytes_lo);
ddword pc_fragment_size_64(DDRIVE *pdr,REGION_FRAGMENT *pfragment);
#define EXFATALLOCATIONPOSSIBLE 0x1
#define EXFATNOFATCHAIN 0x2
BOOLEAN pcexfat_insert_inode(DROBJ *pobj , DROBJ *pmom, byte _attr, FINODE *infinode, dword initcluster, byte *filename, byte secondaryflags, dword sizehi, dword sizelow, int use_charset);
BOOLEAN pcexfat_grow_directory(DROBJ *pobj);
void pcexfat_update_finode_datestamp(FINODE *pfi, BOOLEAN set_archive, int set_date_mask);
#endif
#endif /* _RTFSPROTOS_*/

1765
include/rtfstypes.h Normal file

File diff suppressed because it is too large Load Diff

53
include/rtfsversion.h Normal file
View File

@ -0,0 +1,53 @@
/*****************************************************************************
*Filename: RTFSVERSION.H -
*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc, 2007
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*
* Description:
* This file contains the Rtfs Version number
*
****************************************************************************/
#ifndef __RTFSVERSION__
#define __RTFSVERSION__ 1
#define RTFS_MAJOR_VERSION 6
#define RTFS_MINOR_VERSION 2
/* #define RTFS_MINOR_VERSION 1 */
/* Version 6.0.d - December 2007
#define RTFS_MINOR_REVISION 'd'
Version 6.0.f - July 2008
#define RTFS_MINOR_REVISION 'f'
*/
/* Version 6.1.a - July 2008
#define RTFS_MINOR_REVISION 'a'
*/
/* Version 6.1.b - November 2008
#define RTFS_MINOR_REVISION 'b'
*/
/* Version 6.1.d - April 2009
#define RTFS_MINOR_REVISION 'd'
*/
/* Version 6.1.e - June 2009
#define RTFS_MINOR_REVISION 'e'
*/
/* Version 6.1.e - June 2009
#define RTFS_MINOR_REVISION 'e'
*/
/* Version 6.2.a - March 2012 */
#define RTFS_MINOR_REVISION 'a'
#endif

338
rtfscommon/apps/appcmdfs.c Normal file
View File

@ -0,0 +1,338 @@
/**************************************************************************
APPCMDFS.C - Interactive failsafe commands. Called by the command
shell for RtfsPro and RtfsProPlus
*****************************************************************************
<TEST> Test File: rtfscommon/apps/appcmdshfs.c
<TEST> Description: Interactive command commands that call Rtfs ProPlus failsafe subroutines.
*/
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
/* Control failsafe
failsafe DRIVEID: command
Control Failsafe operations for the disk.
usage:
fs command D:
*/
#if (INCLUDE_FAILSAFE_CODE)
#if (INCLUDE_ASYNCRONOUS_API) /* ProPlus use async API to commit */
extern int do_async; /* If TRUE use asynchs versions of API calls */
BOOLEAN _do_async_complete(int driveno, BOOLEAN manual);
#endif
#if (INCLUDE_DEBUG_TEST_CODE)
void pc_fstest_main(byte *pdriveid);
#endif
/* See apputil.c */
void show_status(char *prompt, dword val, int flags);
long rtfs_atol(byte * s);
int rtfs_atoi(byte * s);
int parse_args(int agc, byte **agv, char *input_template);
int rtfs_args_arg_count(void);
dword rtfs_args_val_hi(int this_arg);
dword rtfs_args_val_lo(int this_arg);
byte *rtfs_args_val_text(int this_arg);
void use_args(int agc, byte **agv);
byte *pc_ltoa(dword num, byte *dest, int number_base);
#define _rtfs_cs_strcmp(A,B,C) rtfs_cs_strcmp((byte *) (A) , (byte *) (B), C)
extern FAILSAFECONTEXT *gl_failsafe_contexts[26];
/*
<TEST> Procedure: do_efile_failsafe()
<TEST> Description: Manually perform Failsafe commands
<TEST> Invoke by typing "fs" in the extended command shell or "FS" in the basic command shell with the following options
<TEST> abort - Abort the current mount without flushing
<TEST> exit - Flush journal file and FAT stop journalling
<TEST> enter - Begin Journalling
<TEST> jcommit - Flush journal file but not FAT
<TEST> Stops journalling and aborts
<TEST> Leaves a restorable Journal
<TEST> jflush - Flush journal file but not FAT
<TEST> Continue journalling
<TEST> commit - Flush journal file and synchronize FAT volume
<TEST> info - Display information about current Failsafe Session
<TEST> clear - Reset Journal IO statistics
<TEST> restore - Restore the volume from current Journal File
*/
extern int fs_flush_behavior; /* In user callback section but used by shell to modify behavior */
int do_efile_failsafe(int agc, byte **agv)
{
FSINFO fsinfo;
byte *pdriveid,*pcommandstring;
int drivenumber;
DDRIVE *pdr;
FAILSAFECONTEXT *pfscntxt;
/* delete filename */
if (!parse_args(agc, agv,"TT"))
{
usage:
rtfs_print_one_string((byte *)" usage:", PRFLG_NL);
rtfs_print_one_string((byte *)" fs command D:", PRFLG_NL);
rtfs_print_one_string((byte *)" where command is:", PRFLG_NL);
rtfs_print_one_string((byte *)" ", PRFLG_NL);
rtfs_print_one_string((byte *)" autodisable - Disable auto Failsafe. Failsafe is controlled by FS command", PRFLG_NL);
rtfs_print_one_string((byte *)" autoenable - Return control to auto Failsafe.", PRFLG_NL);
rtfs_print_one_string((byte *)" abort - Abort the current mount without flushing", PRFLG_NL);
rtfs_print_one_string((byte *)" exit - Flush journal file and FAT stop journalling", PRFLG_NL);
rtfs_print_one_string((byte *)" enter - Begin Journalling ", PRFLG_NL);
rtfs_print_one_string((byte *)" jcommit - Flush journal file but not FAT ", PRFLG_NL);
rtfs_print_one_string((byte *)" Stops journalling and aborts ", PRFLG_NL);
rtfs_print_one_string((byte *)" Leaves a restorable Journal ", PRFLG_NL);
rtfs_print_one_string((byte *)" jflush - Flush journal file but not FAT ", PRFLG_NL);
rtfs_print_one_string((byte *)" Continue journalling ", PRFLG_NL);
rtfs_print_one_string((byte *)" commit - Flush journal file and synchronize FAT volume ", PRFLG_NL);
rtfs_print_one_string((byte *)" info - Display information about current Failsafe Session", PRFLG_NL);
rtfs_print_one_string((byte *)" clear - Reset Journal IO statistics", PRFLG_NL);
rtfs_print_one_string((byte *)" restore - Restore the volume from current Journal File", PRFLG_NL);
#if (INCLUDE_DEBUG_TEST_CODE)
rtfs_print_one_string((byte *)" test - Run Failsafe test suite", PRFLG_NL);
#endif
return(-1);
}
pcommandstring = rtfs_args_val_text(0);
if (!pcommandstring)
goto usage;
if (rtfs_args_arg_count() == 2)
{
pdriveid = rtfs_args_val_text(1);
drivenumber = *pdriveid - 'A';
if (drivenumber < 0 || drivenumber > 25)
goto usage;
}
else
{
goto usage;
}
/* Make sure we are mounted so we can access the pdr structure */
pc_set_default_drive(rtfs_args_val_text(1));
pc_set_cwd((byte *)"\\");
pdr = pc_drno_to_drive_struct(drivenumber);
if (pdr)
pfscntxt = (FAILSAFECONTEXT *) pdr->du.user_failsafe_context;
else
pfscntxt = 0;
if (_rtfs_cs_strcmp(pcommandstring,"autodisable", CS_CHARSET_NOT_UNICODE) == 0)
{
if (!pdr)
{
rtfs_print_one_string((byte *)" No drive found : ", PRFLG_NL);
return(0);
}
rtfs_print_one_string((byte *)" Warning ..............: ", PRFLG_NL);
rtfs_print_one_string((byte *)" To return to automatic mode you must", PRFLG_NL);
rtfs_print_one_string((byte *)" restart or invoke the autoenable command ", PRFLG_NL);
fs_flush_behavior = FS_CB_CONTINUE;
pdr->du.drive_operating_policy |= DRVPOL_DISABLE_AUTOFAILSAFE;
pdr->drive_info.drive_operating_flags |= DRVPOL_DISABLE_AUTOFAILSAFE;
/* Abort Journalling and current mount */
fs_api_disable(pdriveid, TRUE);
return(0);
}
else if (_rtfs_cs_strcmp(pcommandstring,"autoenable", CS_CHARSET_NOT_UNICODE) == 0)
{
if (!pdr)
{
rtfs_print_one_string((byte *)" No drive found : ", PRFLG_NL);
return(0);
}
pdr->du.drive_operating_policy &= ~DRVPOL_DISABLE_AUTOFAILSAFE;
pdr->drive_info.drive_operating_flags &= ~DRVPOL_DISABLE_AUTOFAILSAFE;
fs_flush_behavior = FS_CB_SYNC;
/* Abort Journalling and current mount */
fs_api_disable(pdriveid, TRUE);
return(0);
}
else if (pdr && !(pdr->du.drive_operating_policy & DRVPOL_DISABLE_AUTOFAILSAFE))
{
rtfs_print_one_string((byte *)" Warning ..............: ", PRFLG_NL);
rtfs_print_one_string((byte *)" enter, abort, exit, jcommit, jflush, commit and restore commands may not do", PRFLG_NL);
rtfs_print_one_string((byte *)" what you expect until you invoke the autodisable command", PRFLG_NL);
}
#if (INCLUDE_DEBUG_TEST_CODE)
if (_rtfs_cs_strcmp(pcommandstring,"test", CS_CHARSET_NOT_UNICODE) == 0)
{
pc_fstest_main(pdriveid);
return(0);
}
#endif
if (_rtfs_cs_strcmp(pcommandstring,"abort", CS_CHARSET_NOT_UNICODE) == 0)
{
/* Abort Journalling and current mount */
fs_api_disable(pdriveid, TRUE);
return(0);
}
if (_rtfs_cs_strcmp(pcommandstring,"exit", CS_CHARSET_NOT_UNICODE) == 0)
{
/* Commit Failsafe then exit failsafe mode */
fs_api_disable(pdriveid, FALSE);
return(0);
}
else if (_rtfs_cs_strcmp(pcommandstring,"enter", CS_CHARSET_NOT_UNICODE) == 0)
{
/* _do_efile_apply_config(); */
fs_api_enable(pdriveid, TRUE);
}
else if (_rtfs_cs_strcmp(pcommandstring,"jcommit", CS_CHARSET_NOT_UNICODE) == 0)
{
/* Two arguments are
1 Update FAT structures
2 Clear Journal File (only valid if update FAT is true
*/
/* Flush and close journal file but don't update FAT Don't clear the
journal file */
fs_api_commit(pdriveid, FALSE);
/* Abort Journalling and current mount */
fs_api_disable(pdriveid, TRUE);
}
else if (_rtfs_cs_strcmp(pcommandstring,"jflush", CS_CHARSET_NOT_UNICODE) == 0)
{
/* Two arguments are
1 Update FAT structures
2 Clear Journal File (only valid if update FAT is true
*/
/* Flush and close journal file but don't update FAT Don't clear the
journal file */
fs_api_commit(pdriveid, FALSE);
}
else if (_rtfs_cs_strcmp(pcommandstring,"clear", CS_CHARSET_NOT_UNICODE) == 0)
{ /* Clear IO statistics */
if (pfscntxt)
{
#if (INCLUDE_DEBUG_RUNTIME_STATS)
rtfs_memset(&pfscntxt->stats, 0, sizeof(pfscntxt->stats));
#endif
}
}
else if (_rtfs_cs_strcmp(pcommandstring,"commit", CS_CHARSET_NOT_UNICODE) == 0)
{
/* Three arguments are
1 FLUSH FailSafe file,
2 Update FAT structures
3 Clear Journal File
*/
/* Flush journal file and update FAT so the journal and the
disk volume are in sync, don't clear the journal file, we
can still look at it.
*/
#if (INCLUDE_ASYNCRONOUS_API) /* ProPlus use async API to commit */
if (do_async)
{
int ret_val;
ret_val = fs_api_async_commit_start(pdriveid);
if (ret_val == PC_ASYNC_ERROR)
rtfs_print_one_string((byte *)" Cannot start async", PRFLG_NL);
else if (ret_val == PC_ASYNC_COMPLETE)
rtfs_print_one_string((byte *)" Up to date", PRFLG_NL);
else if (ret_val == PC_ASYNC_CONTINUE)
{
if (!_do_async_complete(pc_path_to_driveno(pdriveid, CS_CHARSET_NOT_UNICODE),FALSE))
rtfs_print_one_string((byte *)" async commit complete failed", PRFLG_NL);
}
return(0);
}
#endif
fs_api_commit(pdriveid, TRUE);
return(0);
}
else if (_rtfs_cs_strcmp(pcommandstring,"info", CS_CHARSET_NOT_UNICODE) == 0)
{
/* Not enable, stat the journal file */
if (!fs_api_info(pdriveid, &fsinfo))
{
rtfs_print_one_string((byte *)"Journal not active and No Journal File Found", PRFLG_NL);
return(0);
}
if (fsinfo.journaling)
{
rtfs_print_one_string((byte *)"Failsafe Journalling active", PRFLG_NL);
rtfs_print_one_string((byte *)" Needs Flush ..............: ", 0);
if (fsinfo.needsflush)
rtfs_print_one_string((byte *)" YES", PRFLG_NL);
else
rtfs_print_one_string((byte *)" NO", PRFLG_NL);
}
else
{
rtfs_print_one_string((byte *)"Failsafe Journalling not active", PRFLG_NL);
if (!fsinfo.journal_file_valid)
{
rtfs_print_one_string((byte *)"No Journal File", PRFLG_NL);
if (fsinfo.check_sum_fails)
rtfs_print_one_string((byte *)"Checksum Error", PRFLG_NL);
return(0);
}
}
{
byte version_in_hex[32];
pc_ltoa(fsinfo.version, &version_in_hex[0], 16);
rtfs_print_one_string((byte *)" Failsafe Version ..............: ", 0);
rtfs_print_one_string((byte *)version_in_hex, PRFLG_NL);
}
show_status(" File Size .....................: ",
fsinfo.filesize, PRFLG_NL);
show_status(" Occupied replacement Blocks ...: ",
fsinfo.numblocksremapped, PRFLG_NL);
show_status(" File Drive Freespace Signature.: ",
fsinfo.journaledfreespace, PRFLG_NL);
show_status(" Current Drive Freespace .......: ",
fsinfo.currentfreespace, PRFLG_NL);
show_status(" Journal File Location .......: ",
fsinfo.journal_block_number, PRFLG_NL);
if (fsinfo.out_of_date)
rtfs_print_one_string((byte *)"Journal File older than FAT", PRFLG_NL);
if (pfscntxt)
{
#if (!INCLUDE_DEBUG_RUNTIME_STATS)
rtfs_print_one_string((byte *)"INCLUDE_DEBUG_RUNTIME_STATS is disabled", PRFLG_NL);
#else
rtfs_print_one_string((byte *)" Journal File IO History .......: ", PRFLG_NL);
show_status(" Index block read calls .......: ", pfscntxt->stats.journal_index_reads, PRFLG_NL);
show_status(" Index block write calls .......: ", pfscntxt->stats.journal_index_writes, PRFLG_NL);
show_status(" Data block read calls .......: ", pfscntxt->stats.journal_data_reads, PRFLG_NL);
show_status(" Data blocks read .......: ", pfscntxt->stats.journal_data_blocks_read, PRFLG_NL);
show_status(" Data block write calls .......: ", pfscntxt->stats.journal_data_writes, PRFLG_NL);
show_status(" Data blocks written .......: ", pfscntxt->stats.journal_data_blocks_written, PRFLG_NL);
show_status(" Restore Read Calls .......: ", pfscntxt->stats.restore_data_reads, PRFLG_NL);
show_status(" Restore blocks read .......: ", pfscntxt->stats.restore_data_blocks_read, PRFLG_NL);
show_status(" Restore write calls .......: ", pfscntxt->stats.restore_write_calls, PRFLG_NL);
show_status(" Restore blocks written .......: ", pfscntxt->stats.restore_blocks_written, PRFLG_NL);
#endif
}
return(0);
}
else if (_rtfs_cs_strcmp(pcommandstring,"restore", CS_CHARSET_NOT_UNICODE) == 0)
{
/* do restore, do clear journal after restore */
fs_api_restore(pdriveid);
return(0);
}
else
{
goto usage;
}
return(0);
}
#endif /* (INCLUDE_FAILSAFE_CODE) */
#endif /* Exclude from build if read only */

View File

@ -0,0 +1,792 @@
/**************************************************************************
APPTSTSH.C - Command driven test shell for embedded file manager.
Summary
TSTSH
Description
Interactive shell program designed to allow testing of the file manager.
Returns
Example:
*****************************************************************************
*/
/*
<TEST> Test File: rtfscommon/apps/appcmdshformat.c
*/
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
#define DISPLAY_ERRNO(ROUTINE)
/* See apputil.c */
long rtfs_atol(byte * s);
int rtfs_atoi(byte * s);
void use_args(int agc, byte **agv);
static int _ask_user_for_partitions(byte *working_buffer, dword *psizeincylindersarray, byte *ppartitiontypes, dword total_cylinders, dword sectors_per_cylinder);
static DDRIVE *_choose_drive(char *prompt, byte *path);
BOOLEAN tstsh_is_yes(byte *p);
byte *pc_ltoa(dword num, byte *dest, int number_base);
void rtfs_print_prompt_user(byte *prompt, byte *buf);
/* FORMAT*/
/*
<TEST> Procedure: doformat() - Format volumes.
<TEST> Invoke by typing "FORMAT" in the command shell
<TEST>
*/
#if (INCLUDE_EXFATORFAT64)
void probe_exfat_format_parms(byte *path);
int doprobeexfatformat(int agc, byte **agv)
{
DDRIVE *pdr;
byte path[10];
use_args(agc, agv);
/* Select the device, check media and clear change conditions */
pdr = _choose_drive("Enter the drive to probe as A:, B: etc ", path);
if (!pdr)
return(-1);
#ifdef RTFS_WINDOWS
probe_exfat_format_parms(path);
#endif
return(0);
}
int doexfatformat(int agc, byte **agv)
{
DDRIVE *pdr;
byte path[10];
use_args(agc, agv);
/* Select the device, check media and clear change conditions */
pdr = _choose_drive("Enter the drive to format as A:, B: etc ", path);
if (!pdr)
return(-1);
if (pcexfat_format_volume(path))
{
RTFS_PRINT_STRING_1((byte *)"ExFat Format Succeeded.", PRFLG_NL);
return(0);
}
else
{
RTFS_PRINT_STRING_1((byte *)"ExFat Format Failed.", PRFLG_NL);
return(-1);
}
}
#endif
int doformat(int agc, byte **agv)
{
byte buf[80];
DDRIVE *pdr;
byte path[10];
BOOLEAN use_extended_format = FALSE;
RTFSFMTPARMSEX parms_ex;
BOOLEAN status;
use_args(agc, agv);
rtfs_memset(&parms_ex, 0, sizeof(parms_ex));
/* Select the device, check media and clear change conditions */
pdr = _choose_drive("Enter the drive to format as A:, B: etc ", path);
if (!pdr)
return(-1);
rtfs_print_prompt_user((byte *)"Zero Volume Blocks ? (Y/N) ", buf); /* "Show directories(Y/N) " */
if (tstsh_is_yes(buf))
{
parms_ex.scrub_volume = TRUE;
use_extended_format = TRUE;
}
rtfs_print_prompt_user((byte *)"Specify FAT size, Cluster size, etc ? (Y/N) ", buf); /* "Show directories(Y/N) " */
if (tstsh_is_yes(buf))
{
use_extended_format = TRUE;
RTFS_PRINT_STRING_1((byte *)"All Values must be provided ", PRFLG_NL);
do {
rtfs_print_prompt_user((byte *)"Cluster size: 12, 16, 32 ", buf); /* "Show directories(Y/N) " */
parms_ex.bits_per_cluster = (unsigned char) rtfs_atoi(buf);
} while (parms_ex.bits_per_cluster != 12 && parms_ex.bits_per_cluster != 16 && parms_ex.bits_per_cluster != 32);
rtfs_print_prompt_user((byte *)"# of root dir entries (normally 512 for FAT12, FAT16, must be 0 for FAT32 ", buf);
parms_ex.numroot = (unsigned short) rtfs_atoi(buf);
do {
rtfs_print_prompt_user((byte *)"Number of FATS on the disk, 1 or 2 Must be 2 if using Failsafe ", buf);
parms_ex.numfats = (unsigned char) rtfs_atoi(buf);
} while (parms_ex.numfats != 1 && parms_ex.numfats != 2);
do {
rtfs_print_prompt_user((byte *)"Reserved sectors must be >= 1 for FAT16, >= 32 For FAT32 ", buf);
parms_ex.secreserved = (unsigned char) rtfs_atoi(buf);
} while (parms_ex.secreserved < 1);
do {
rtfs_print_prompt_user((byte *)"Sectors per cluster (1, 2, 4, 8, 16, 32, 64 or 128) ", buf);
parms_ex.secpalloc = (unsigned char) rtfs_atoi(buf);
} while (parms_ex.secpalloc != 1 && parms_ex.secpalloc != 2 &&
parms_ex.secpalloc != 4 && parms_ex.secpalloc != 8 &&
parms_ex.secpalloc != 16 && parms_ex.secpalloc != 32 &&
parms_ex.secpalloc != 64 && parms_ex.secpalloc != 128);
}
RTFS_PRINT_STRING_1((byte *)"Calling pc_format_volume()", PRFLG_NL);
if (use_extended_format)
{
RTFS_PRINT_STRING_1((byte *)"Calling pc_format_volume_ex()", PRFLG_NL);
status = pc_format_volume_ex(path, &parms_ex);
}
else
{
RTFS_PRINT_STRING_1((byte *)"Calling pc_format_volume()", PRFLG_NL);
status = pc_format_volume(path);
}
if (!status)
{
rtfs_print_prompt_user((byte *)"Format: Format volume failed. Press return", buf);
return(-1);
}
return (0);
}
/*
<TEST> Procedure: dodeviceformat() - Perform device level format
<TEST> Invoke by typing "DEVICEFORMAT" in the command shell
<TEST>
*/
int dodeviceformat(int agc, byte **agv)
{
byte working_buffer[100];
DDRIVE *pdr;
byte path[10];
use_args(agc, agv);
/* Select the device, check media and clear change conditions */
pdr = _choose_drive("Enter the drive to perfrom device level format on A:, B: etc ", path);
if (!pdr)
return(-1);
/* Call the low level media format. ? */
{
RTFS_PRINT_STRING_1((byte *)"Calling media format", PRFLG_NL); /* "Calling media format" */
if (!pc_format_media(path))
{
DISPLAY_ERRNO("pc_format_media")
rtfs_print_prompt_user((byte *)"Format: Media format failed. Press return", working_buffer); /* "Format: Media format failed. Press return" */
return(-1);
}
}
return(0);
}
static BOOLEAN _process_partition_list(byte *path, int num_partitions, dword sectors_per_cylinder, dword sectors_per_track, dword *psizeincylinders, byte *ppartitiontypes);
/*
<TEST> Procedure: dofdisk() - Partion a device
<TEST> Invoke by typing "FDISK" in the command shell
<TEST>
*/
int dofdisk(int agc, byte **agv) /*__fn__*/
{
byte working_buffer[100];
DDRIVE *pdr;
byte path[10];
DEV_GEOMETRY geometry;
use_args(agc, agv);
/* Select the device, check media and clear change conditions */
pdr = _choose_drive("Enter the drive to partition A:, B: etc ", path);
if (!pdr)
return(-1);
/* Partition the drive */
{
dword total_cylinders, sectors_per_cylinder;
int num_partitions;
dword sizeincylinders[16];
byte partitiontypes[16];
/* Get geometry information and then call _ask_user_for_partitions() to populate two arrays:
dword sizeincylinders[] (size in cylinders of each partition)
byte partitiontypes[] (type of each each partition) */
rtfs_memset(&geometry, 0, sizeof(geometry));
if (!pc_get_media_parms(path, &geometry))
{
rtfs_print_prompt_user((byte *)"Format: get media geometry failed. Press return", working_buffer);
return(-1);
}
/* Cylinder align */
sectors_per_cylinder = (dword) (geometry.dev_geometry_heads & 0xff);
sectors_per_cylinder *= geometry.dev_geometry_secptrack;
total_cylinders = geometry.dev_geometry_lbas/sectors_per_cylinder;
/* Ask the user for the sizes in cylinders and types of partitions */
num_partitions = _ask_user_for_partitions(&working_buffer[0], &sizeincylinders[0], &partitiontypes[0], total_cylinders, sectors_per_cylinder);
/* Convert the input values to partition specifications and call pc_partition_media() */
if (!_process_partition_list(path, num_partitions, sectors_per_cylinder, geometry.dev_geometry_secptrack, &sizeincylinders[0], &partitiontypes[0]))
{
RTFS_PRINT_STRING_1((byte *)"pc_partition_media() failed.", PRFLG_NL);
return(-1);
}
}
return (0);
}
/* Convert input values to partition specifications and call pc_partition_media() */
static BOOLEAN _process_partition_list(byte *path, int num_partitions, dword sectors_per_cylinder, dword sectors_per_track, dword *psizeincylinders, byte *ppartitiontypes)
{
int which_partition, which_mbr_index;
dword current_start_cylinder;
struct mbr_specification mbrspecs[16];
/* Clear the specifications */
rtfs_memset(&mbrspecs[0], 0, sizeof(mbrspecs));
mbrspecs[0].mbr_sector_location = 0; /* The mbr is always at sector zero */
if (num_partitions)
mbrspecs[0].device_mbr_count = 1; /* There will be at least one master mbr */
else
mbrspecs[0].device_mbr_count = 0; /* Clear the partition table */
which_mbr_index = 0;
current_start_cylinder = 0;
for (which_partition = 0; which_partition < num_partitions; which_partition++)
{
#if (SUPPORT_EXTENDED_PARTITIONS)
if (which_partition == 3 && num_partitions > 4)
{ /* Extended partition required initialize the extended partition entry at offset 3 */
int i; dword total_cylinders;
mbrspecs[0].entry_specifications[3].partition_start = (current_start_cylinder * sectors_per_cylinder);
mbrspecs[0].entry_specifications[3].partition_type = 0x05;
mbrspecs[0].entry_specifications[3].partition_boot = 0x00;
/* Count all the cylinders in the extended partition and update the size field */
total_cylinders = 0;
for (i = 4; i <= num_partitions; i++)
total_cylinders += *(psizeincylinders+i);
mbrspecs[0].entry_specifications[3].partition_size = total_cylinders*sectors_per_cylinder;
/* Done filling the primary partition - start with extended partitions */
which_mbr_index = 1;
}
#endif
if (which_mbr_index == 0)
{ /* Inside the mbr - start the volume at head 1 sector 0 */
mbrspecs[which_mbr_index].entry_specifications[which_partition].partition_start = (current_start_cylinder * sectors_per_cylinder)+sectors_per_track;
mbrspecs[which_mbr_index].entry_specifications[which_partition].partition_size = (*(psizeincylinders+which_partition) * sectors_per_cylinder)-sectors_per_track+1;
mbrspecs[which_mbr_index].entry_specifications[which_partition].partition_type = *(ppartitiontypes+which_partition);
mbrspecs[which_mbr_index].entry_specifications[which_partition].partition_boot = 0x80;
}
#if (SUPPORT_EXTENDED_PARTITIONS)
else
{
mbrspecs[0].device_mbr_count += 1; /* Update mbr count in the first record (mbrspecs[0].device_mbr_count-1) =='s number of extended partitions */
mbrspecs[which_mbr_index].device_mbr_count = 0; /* not used */
/* Where to write this extended boot record */
mbrspecs[which_mbr_index].mbr_sector_location = (current_start_cylinder * sectors_per_cylinder);
/* Entry zero of the ebr contains the relative offset to the BPB and the number of usable sectors beyond that */
mbrspecs[which_mbr_index].entry_specifications[0].partition_start = sectors_per_track;
mbrspecs[which_mbr_index].entry_specifications[0].partition_size = (*(psizeincylinders+which_partition) * sectors_per_cylinder)
- sectors_per_track + 1;
/* Entry one of the ebr contains the address of the next ebr minus the first sector in the extended partition */
if ((which_partition + 1) == num_partitions)
{ /* If this is the last partition set the start location and size of the next partition to zero */
mbrspecs[which_mbr_index].entry_specifications[1].partition_start = 0;
mbrspecs[which_mbr_index].entry_specifications[1].partition_size = 0;
}
else
{ /* The next ebr resides at the current cylinder plus the size of the current partition */
mbrspecs[which_mbr_index].entry_specifications[1].partition_start =
(current_start_cylinder + *(psizeincylinders+which_partition)) * sectors_per_cylinder;
/* Subtract the first sector of the first extended partition so it is a relative offset */
mbrspecs[which_mbr_index].entry_specifications[1].partition_start -= mbrspecs[1].mbr_sector_location;
/* Entry one of the ebr contains the size of the next partition in the size field */
mbrspecs[which_mbr_index].entry_specifications[1].partition_size =
(*(psizeincylinders+which_partition+1) * sectors_per_cylinder);
}
which_mbr_index += 1; /* Each partition has its own ebr */
}
#endif
current_start_cylinder = current_start_cylinder + *(psizeincylinders+which_partition);
}
return (pc_partition_media(path, &mbrspecs[0]));
}
/* Ask the user for the drive id to device format, format or partition */
static DDRIVE *_choose_drive(char *prompt, byte *path)
{
byte buf[10];
DDRIVE *pdr;
int driveno;
rtfs_print_prompt_user((byte *)prompt, path);
pdr = 0;
driveno = pc_parse_raw_drive(path, CS_CHARSET_NOT_UNICODE);
if (driveno != -1)
pdr = pc_drno_to_drive_struct(driveno);
if (!pdr)
{
rtfs_print_prompt_user((byte *)"Invalid drive selection, press return", buf);
return(0);
}
return(pdr);
}
/* Ask the user for partition sizes and partition types . */
static int _ask_user_for_partitions(byte *working_buffer, dword *psizeincylindersarray, byte *ppartitiontypes, dword total_cylinders, dword sectors_per_cylinder)
{
dword cylinders_remaining,requested_cylinders_this_partition;
int partition_count = 0;
cylinders_remaining = total_cylinders;
RTFS_PRINT_STRING_1((byte *)" Please provide partitioning instructions.. ", PRFLG_NL);
RTFS_PRINT_STRING_1((byte *)" ========================================== ", PRFLG_NL);
RTFS_PRINT_STRING_1((byte *)" ", PRFLG_NL);
RTFS_PRINT_STRING_1((byte *)" Note: press X to exit or C to eliminate the partition table.. ", PRFLG_NL);
RTFS_PRINT_STRING_1((byte *)" ============================================================= ", PRFLG_NL);
while (cylinders_remaining)
{
RTFS_PRINT_STRING_1((byte *)"Defining partition number : ", 0);
RTFS_PRINT_LONG_1((dword) partition_count, PRFLG_NL);
RTFS_PRINT_STRING_1((byte *)"This many cylinders remain: ", 0);
RTFS_PRINT_LONG_1((dword) cylinders_remaining, PRFLG_NL);
RTFS_PRINT_STRING_1((byte *)"This many sectors remain: ", 0);
RTFS_PRINT_LONG_1((dword) cylinders_remaining*sectors_per_cylinder, PRFLG_NL);
#if (SUPPORT_EXTENDED_PARTITIONS)
if (partition_count == 3)
RTFS_PRINT_STRING_1((byte *)"An extended partition will be created if you do not select all..", PRFLG_NL);
#else
if (partition_count == 3)
RTFS_PRINT_STRING_1((byte *)"Last available partition space will be wasted if you do not select all..", PRFLG_NL);
#endif
RTFS_PRINT_STRING_1((byte *)"Type X to exit or C to eliminate the partition table.. ", PRFLG_NL);
rtfs_print_prompt_user((byte *)"Select the number of cylinders for this partition or return for all:", working_buffer);
if (working_buffer[0] == 'X' || working_buffer[0] == 'x')
break; /* psizeincylindersarray, and ppartitiontypesreturn are complete for "partiton count" entries. break and return */
if (working_buffer[0] == 'C' || working_buffer[0] == 'c')
return (0); /* Will clear the partition */
if (!working_buffer[0])
requested_cylinders_this_partition = cylinders_remaining;
else
requested_cylinders_this_partition = (dword)rtfs_atol(working_buffer);
if (requested_cylinders_this_partition == 0 || requested_cylinders_this_partition > cylinders_remaining)
requested_cylinders_this_partition = cylinders_remaining;
*(psizeincylindersarray+partition_count) = requested_cylinders_this_partition;
/* Now ask the usr for the type.
if > 0xffff sectors it can be 0x0c or 0x06
otherwise it can be 0x04 or 0x01 */
{
dword logical_sectors_this_partition;
byte this_entry_type;
this_entry_type = 0;
logical_sectors_this_partition = (requested_cylinders_this_partition * sectors_per_cylinder);
if (logical_sectors_this_partition > 0xffff)
{ /* Select partition type */
while (this_entry_type != 0x0c && this_entry_type != 0x06)
{
rtfs_print_prompt_user((byte *)"Select the partition type 0.) FAT32(0x0c), 1.) FAT16(0x06): ", working_buffer);
if (working_buffer[0] == '0') this_entry_type = 0x0c;
else if (working_buffer[0] == '1') this_entry_type = 0x06;
}
}
else
{
while (this_entry_type != 0x04 && this_entry_type != 0x01)
{
rtfs_print_prompt_user((byte *)"Select the partition type 0.) FAT16(0x04), 1.) FAT12(0x01): ", working_buffer);
if (working_buffer[0] == '0') this_entry_type = 0x04;
else if (working_buffer[0] == '1') this_entry_type = 0x01;
}
}
*(ppartitiontypes+partition_count) = this_entry_type;
}
partition_count += 1;
cylinders_remaining -= requested_cylinders_this_partition;
}
return(partition_count);
}
static dword debug_dump_mbr(byte *pdata, BOOLEAN is_primary);
int dodumpmbr(int agc, byte **agv)
{
DDRIVE *pdr;
byte path[10];
BLKBUFF * scratch;
BLKBUFF bbuf_scratch; /* Used by pc_sys_sector build a buffer structure with core from the driver level */
dword sector_number;
use_args(agc, agv);
/* Select the device, check media and clear change conditions */
pdr = _choose_drive("Enter the drive to read A:, B: etc ", path);
if (!pdr)
return(-1);
scratch = pc_sys_sector(pdr, &bbuf_scratch);
/* Read location 0 */
sector_number = 0;
if (!raw_devio_xfer(pdr, sector_number, scratch->data, 1, TRUE, TRUE))
{
rtfs_print_one_string((byte *)"Read failed", PRFLG_NL);
pc_free_sys_sector(scratch);
return(-1);
}
/* Dump the primary, not printing extended paartitions yet */
sector_number = debug_dump_mbr(scratch->data, TRUE);
pc_free_sys_sector(scratch);
return (0);
}
static void debug_dump_bpb(DDRIVE *pdr, dword sector, byte *p, int depth);
int dodumpbpb(int agc, byte **agv)
{
DDRIVE *pdr;
byte path[10];
BLKBUFF * scratch;
BLKBUFF bbuf_scratch; /* Used by pc_sys_sector build a buffer structure with core from the driver level */
dword sector_number;
int partition_status;
struct mbr_entry_specification mbr_specs[RTFS_MAX_PARTITIONS];
use_args(agc, agv);
/* Select the device, check media and clear change conditions */
pdr = _choose_drive("Enter the drive to read A:, B: etc ", path);
if (!pdr)
return(-1);
/* Read the partition table. If one is found the following fields will be set in the drive structure:
pdr->drive_info.partition_base, pdr->drive_info.partition_size, pdr->drive_info.partition_type */
partition_status = pc_read_partition_table(pdr, &mbr_specs[0]);
if (partition_status >= pdr->partition_number)
sector_number = pdr->drive_info.partition_base;
else
sector_number = 0;
scratch = pc_sys_sector(pdr, &bbuf_scratch);
if (!raw_devio_xfer(pdr, sector_number, scratch->data, 1, TRUE, TRUE))
{
rtfs_print_one_string((byte *)"Read failed", PRFLG_NL);
pc_free_sys_sector(scratch);
return(-1);
}
debug_dump_bpb(pdr, sector_number, scratch->data, 0);
pc_free_sys_sector(scratch);
return (0);
}
int dohackwin7(int agc, byte **agv)
{
DDRIVE *pdr;
byte path[10];
byte buf[10];
BLKBUFF * scratch;
BLKBUFF bbuf_scratch; /* Used by pc_sys_sector build a buffer structure with core from the driver level */
dword sector_number;
byte *p;
use_args(agc, agv);
/* Select the device, check media and clear change conditions */
pdr = _choose_drive("Enter the drive to read A:, B: etc ", path);
if (!pdr)
return(-1);
scratch = pc_sys_sector(pdr, &bbuf_scratch);
/* Read location 0 */
sector_number = 0;
if (!raw_devio_xfer(pdr, sector_number, scratch->data, 1, TRUE, TRUE))
{
rtfs_print_one_string((byte *)"Read failed", PRFLG_NL);
pc_free_sys_sector(scratch);
return(-1);
}
p = (byte *) scratch->data;
p += 510;
if (to_WORD((byte *) p) == 0xAA55)
{
rtfs_print_prompt_user((byte *)"Do you want to write to the device with Rtfs ? (Y/N) ", buf);
if (tstsh_is_yes(buf))
{
rtfs_print_one_string((byte *)"Invalidating MBR so the volume is writeable", PRFLG_NL);
fr_WORD(p, 0xAA66);
}
else
{
rtfs_print_one_string((byte *)"Fixing MBR so volume is readable on windows", PRFLG_NL);
fr_WORD(p, 0xAA55);
}
}
else
{
rtfs_print_one_string((byte *)"No signature on media, not changing it..", PRFLG_NL);
pc_free_sys_sector(scratch);
return(-1);
}
/* Dump the primary, not printing extended paartitions yet */
if (!raw_devio_xfer(pdr, sector_number, scratch->data, 1, TRUE, FALSE))
{
rtfs_print_one_string((byte *)"Write failed", PRFLG_NL);
pc_free_sys_sector(scratch);
return(-1);
}
pc_free_sys_sector(scratch);
return (0);
}
static word debug_unpack_sec_field(word cyl);
static word debug_unpack_cyl_field(word cyl);
static void dump_print(char *prompt, dword val, int radix, BOOLEAN newline);
static void debug_dump_info_structure(DDRIVE *pdr, dword sector, byte *p);
/*
static void debug_dump_fats(DDRIVE *pdr, FMTPARMS *pfmt, byte *pbuffer, dword buffer_size_bytes);
static void debug_dump_roots(DDRIVE *pdr, FMTPARMS *pfmt, byte *pbuffer, dword buffer_size_bytes);
*/
static void debug_dump_bpb(DDRIVE *pdr, dword sector, byte *p, int depth)
{
byte buff[32];
dump_print(" DOS Boot sig (0xe9) : ", (dword ) *p, 16, TRUE);
copybuff(buff, p+3, 8);
buff[8] = 0;
rtfs_print_one_string((byte *) " OEM Name :", 0);
rtfs_print_one_string((byte *)buff, PRFLG_NL);
dump_print(" Bytes per sector :", (dword) (to_WORD(p+0xb)), 10, TRUE);
dump_print(" Sectors per cluster :", (dword) *(p+0xd), 10, TRUE);
dump_print(" Reserved sectors :", (dword) (to_WORD(p+0xe)), 10, TRUE);
dump_print(" Number of fats :", (dword)*(p+0x10),20, TRUE);
dump_print(" Num Root :", (dword) (to_WORD(p+0x11)), 10, TRUE);
dump_print(" Total Sector(16) :", (dword) (to_WORD(p+0x13)), 10, TRUE);
dump_print(" Media Description :", (dword) *(p+0x15), 16, TRUE);
dump_print(" Total Sector(32) :", (dword) (to_DWORD(p+0x20)), 10, TRUE);
dump_print(" Sector per track :", (dword) (to_WORD(p+0x18)), 10, TRUE);
dump_print(" Heads :", (dword) (to_WORD(p+0x1a)), 10, TRUE);
dump_print(" NumHide :", (dword) (to_DWORD(p+0x1c)), 10, TRUE);
dump_print(" DOS 4 Ext Sig :", (dword) *(p+0x26), 16, TRUE);
dump_print(" DOS 7 Ext Sig :", (dword) *(p+0x42), 16, TRUE);
if (*(p+0x26) == 0x29) /* Use MS-DOS 4.0 Extended parameter block for FAT12 and Fat16 */
{
rtfs_print_one_string((byte *)" MSDOS-4.0 EPB detected ", PRFLG_NL);
dump_print(" Sector per FAT :", (dword) (to_WORD(p+0x16)), 10, TRUE);
dump_print(" Drive :", (dword) *(p+0x24), 10, TRUE);
dump_print(" Binary Volume :", to_DWORD(p+0x27), 16, TRUE);
rtfs_print_one_string((byte *) " Text Volume :", 0);
copybuff(buff, p+0x2b, 11);
buff[11] = 0;
rtfs_print_one_string((byte *) &buff[0], PRFLG_NL);
rtfs_print_one_string((byte *) " Filesys Type :", 0);
copybuff(buff, p+0x36, 8);
buff[8] = 0;
rtfs_print_one_string((byte *) &buff[0], PRFLG_NL);
}
if (*(p+0x42) == 0x29) /* Use MS-DOS 7.0 Extended parameter block FAT32 */
{
rtfs_print_one_string((byte *)" MSDOS-7.0 EPB detected ", PRFLG_NL);
dump_print(" Sector per FAT :", to_DWORD(p+0x24), 10, TRUE);
dump_print(" Flags and Version :", to_DWORD(p+0x28), 16, TRUE);
dump_print(" Root Start Cluster :", to_DWORD(p+0x2c), 10, TRUE);
dump_print(" Info Sector :", to_WORD(p+0x30), 10, TRUE);
dump_print(" BackupBPB Sector :", to_DWORD(p+0x32), 10, TRUE);
dump_print(" Drive :", *(p+0x40), 10, TRUE);
dump_print(" Binary Volume :", to_DWORD(p+0x43), 16, TRUE);
rtfs_print_one_string((byte *) " Text Volume :", 0);
copybuff(buff, p+0x47, 11);
buff[11] = 0;
rtfs_print_one_string((byte *) &buff[0], PRFLG_NL);
rtfs_print_one_string((byte *) " Filesys Type :", 0);
copybuff(buff, p+0x52, 8);
buff[8] = 0;
rtfs_print_one_string((byte *) &buff[0], PRFLG_NL);
}
if (*(p+0x26) != 0x29 && *(p+0x42) != 0x29)
{
rtfs_print_one_string((byte *)" No valid EB signature found ", PRFLG_NL);
}
dump_print( " Signature (aa55 ?) :", (dword) (to_WORD(p+0x1fe)), 16, TRUE);
/* FAT32 */
if (*(p+0x42) == 0x29) /* Use MS-DOS 7.0 Extended parameter block FAT32 */
{
dword info_sector, backup_info_sector, backup_boot_sector;
backup_boot_sector = sector + (dword) (to_WORD(p+0x32));
info_sector = sector + (dword) (to_WORD(p+0x30));
backup_info_sector = backup_boot_sector + (dword) (to_WORD(p+0x30));
rtfs_print_one_string((byte *)" Dumping Backup Boot Sector ", PRFLG_NL);
if (depth == 0)
{
debug_dump_bpb(pdr, backup_boot_sector, p, 1);
rtfs_print_one_string((byte *)" Dumping Info Sector ", PRFLG_NL);
debug_dump_info_structure(pdr, info_sector, p);
rtfs_print_one_string((byte *)" Dumping Backup Info Sector ", PRFLG_NL);
debug_dump_info_structure(pdr, backup_info_sector, p);
}
}
}
static void debug_dump_info_structure(DDRIVE *pdr, dword sector, byte *p)
{
if (!raw_devio_xfer(pdr, sector, p, 1, TRUE, TRUE))
{
rtfs_print_one_string((byte *)"Read failed", PRFLG_NL);
}
dump_print( "Signature 1 (Should be: 0x41615252):", to_DWORD(p), 16, TRUE);
dump_print( "Signature 2 :", to_DWORD(p+0x01e4), 16, TRUE);
dump_print( "Free clusters :", to_DWORD(p+0x01e8), 10, TRUE);
dump_print( "First Free cluster :", to_DWORD(p+0x01ec), 10, TRUE);
dump_print( "Signature 3 :", to_DWORD(p+0x01fe), 16, TRUE);
}
/*
static void debug_dump_fats(DDRIVE *pdr, FMTPARMS *pfmt, byte *pbuffer)
{
rtfs_print_one_string((byte *)"Dump FATs, fix me", PRFLG_NL);
}
static void debug_dump_roots(DDRIVE *pdr, FMTPARMS *pfmt, byte *pbuffer)
{
rtfs_print_one_string((byte *)"Dump Roots, fix me", PRFLG_NL);
}
*/
static dword debug_dump_mbr(byte *pdata, BOOLEAN is_primary)
{
int i;
byte *pentry;
byte *ptable;
dword return_sector,dw;
RTFS_ARGSUSED_INT(is_primary);
ptable = pdata + 0x1be;
/* The table has four 16 bit partition table entries followed by the signature
Each entry in the table has the followin fields
byte Name width
0 boot 1
1 s_head 1
2 s_cyl 2
4 p_typ 1
5 e_head 1
6 e_cyl; 2
8 r_sec 4
12 p_size 4
*/
return_sector = 0;
pentry = ptable;
for(i = 0; i < 4; i++)
{
word w;
dw = to_DWORD(pentry+12); /* Print the entry if it has a size */
if (dw)
{
dump_print("Partition # ---->", i, 10, TRUE);
dump_print("Boot == ", *pentry, 16, FALSE);
dump_print("Type == ", *(pentry+4), 16, FALSE);
dw = to_DWORD(pentry+12);
dump_print("Size == ", dw, 10, FALSE);
dw = to_DWORD(pentry+8);
if (*(pentry+4) == 0x5 || *(pentry+4) == 0xF)
{
dump_print("Extended Partition starts at == ", dw, 10, TRUE);
return_sector = dw;
}
else
dump_print("Start == ", dw, 10, TRUE);
dump_print("SHead == ", *(pentry+1), 10, FALSE);
w = to_WORD(pentry+2);
dump_print("Packed Cyl = ", w, 16, FALSE);
dump_print("Sector = ", debug_unpack_sec_field(w), 10, FALSE);
dump_print("Cylinder = ", debug_unpack_cyl_field(w), 10, TRUE);
dump_print("EHead == ", *(pentry+5), 10, FALSE);
w = to_WORD(pentry+6);
dump_print("Packed Cyl = ", w, 16, FALSE);
dump_print("Sector = ", debug_unpack_sec_field(w), 10, FALSE);
dump_print("Cylinder = ", debug_unpack_cyl_field(w), 10, TRUE);
dw = to_DWORD(pentry+8);
}
pentry += 16;
}
dw = to_WORD(ptable + 64);
dump_print("Signature ", dw, 16, TRUE);
/* Now for the signature */
return(return_sector);
}
static word debug_unpack_sec_field(word cyl)
{
return(cyl & 0x3f);
}
static word debug_unpack_cyl_field(word cyl)
{
word low, hi;
low = (word)((cyl>>8) & 0xff); /* Low 8 bit to from hibite */
hi = (word)((cyl<<2) & 0x0300); /* hi 2 bits from bits 6&7 of low */
low |= hi;
return(low);
}
static void dump_print(char *prompt, dword val, int radix, BOOLEAN newline)
{
byte buff[32];
pc_ltoa(val, &buff[0], radix);
rtfs_print_one_string((byte *)prompt, 0);
if (newline)
rtfs_print_one_string((byte *)buff, PRFLG_NL);
else
{
rtfs_print_one_string((byte *)buff, 0);
rtfs_print_one_string((byte *)" , ",0);
}
}
#endif /* Exclude from build if read only */

2667
rtfscommon/apps/appcmdshrd.c Normal file

File diff suppressed because it is too large Load Diff

1419
rtfscommon/apps/appcmdshwr.c Normal file

File diff suppressed because it is too large Load Diff

410
rtfscommon/apps/apputil.c Normal file
View File

@ -0,0 +1,410 @@
/**************************************************************************
APPUTIL.C - Parse and other utility functions for Pro and ProPlus command shells
Takes parsed argc, argv arguments and a parse template
and saves "typed" versions of arguments
The can be
*
* rtfs_print_prompt_user() -
*
* This routine is called when the ERTFS demo programs and critical error handlr routine
* requires console input from the user. It takes as input a prompt id (this is a numeric
* handle to the prompt strings in the prompts string table prompt_table[]
* in portstr.c and the address of a buffer where to place the console
* input.
*
* This routine displays the prompt by calling rtfs_print_one_string() and then
* calls the target specific routine tm_gets_rtfs() to recieve the console
* input.
*
* For example a sequence of strings might fill.
*
* FILLFILE TEST.DAT MYPATTERN 100
* CAT TEST.DAT
* DELETE TEST.BAT
*
* If you do not wish to use the interactive test programs you need
* not implement this function.
*****************************************************************************
*/
#include "rtfs.h"
long rtfs_atol(byte * s);
void rtfs_print_prompt_user(byte *prompt, byte *buf);
typedef struct dispatcher_text {
byte *cmd;
int (*proc)( int argc, byte **argv);
byte *helpstr;
} DISPATCHER_TEXT;
extern byte working_buf[512]; /* Not sector size dependant used by lex: must be global */
/* Miscelaneous functions */
/* PRFLG_NL means skip a line */
void show_status(char *prompt, dword val, int flags)
{
rtfs_print_one_string((byte *)prompt,0);
rtfs_print_long_1(val,flags);
}
static byte *gnext(byte *p,byte termat);
/* ******************************************************************** */
/* get next command; process history log */
void *lex(void *_pcmds, int *agc, byte **agv,byte *initial_cmd,byte *raw_input)
{
byte *cmd,*p;
DISPATCHER_TEXT *pcmds_start,*pcmds;
*agc = 0;
/* "CMD>" */
if (initial_cmd)
rtfs_cs_strcpy(working_buf, initial_cmd, CS_CHARSET_NOT_UNICODE);
else
rtfs_print_prompt_user((byte *)"CMD> ", working_buf);
if (raw_input)
rtfs_cs_strcpy(raw_input,working_buf, CS_CHARSET_NOT_UNICODE);
pcmds = (DISPATCHER_TEXT *) _pcmds;
pcmds_start = pcmds;
p = cmd = &working_buf[0];
p = gnext(p, ' ');
/* Keep grabbing tokens until there are none left */
while (p)
{
if (CS_OP_CMP_ASCII(p,'"', CS_CHARSET_NOT_UNICODE))
{ /* Quoted string.. find the end quote and terminate */
CS_OP_TERM_STRING(p, CS_CHARSET_NOT_UNICODE);
CS_OP_INC_PTR(p, CS_CHARSET_NOT_UNICODE);
*agv++ = p;
*agc += 1;
p = gnext(p,'"');
}
else
{
*agv++ = p;
*agc += 1;
p = gnext(p,' ');
}
}
{
DISPATCHER_TEXT *pcmds_txt;
pcmds_txt = (DISPATCHER_TEXT *) pcmds;
while (pcmds_txt->cmd)
{
if (rtfs_cs_strcmp(cmd,pcmds_txt->cmd, CS_CHARSET_NOT_UNICODE) == 0)
return ((void *)pcmds_txt);
pcmds_txt++;
}
}
/* No match return ??? */
return ((void *)pcmds_start);
}
/* Null term the current token and return a pointer to the next
termat is '"' for a quoted string, otherwise it is ' '
*/
static byte *gnext(byte *p,byte termat) /*__fn__*/
{
/* GET RID OF LEADING SPACES */
while (CS_OP_CMP_ASCII(p,' ', CS_CHARSET_NOT_UNICODE))
CS_OP_INC_PTR(p, CS_CHARSET_NOT_UNICODE);
while (CS_OP_IS_NOT_EOS(p, CS_CHARSET_NOT_UNICODE))
{
if (CS_OP_CMP_ASCII(p,termat, CS_CHARSET_NOT_UNICODE))
{
CS_OP_TERM_STRING(p, CS_CHARSET_NOT_UNICODE); /* Null it and look at next */
CS_OP_INC_PTR(p, CS_CHARSET_NOT_UNICODE);
break;
}
CS_OP_INC_PTR(p, CS_CHARSET_NOT_UNICODE);
}
/* GET RID OF TRAILING SPACES */
while (CS_OP_CMP_ASCII(p,' ', CS_CHARSET_NOT_UNICODE))
CS_OP_INC_PTR(p, CS_CHARSET_NOT_UNICODE);
if (CS_OP_IS_EOS(p, CS_CHARSET_NOT_UNICODE)) /* All done */
return(0);
return (p);
}
/* Argument parsing structures */
#define MAX_ARGS 20
typedef struct one_arg
{
dword val_hi;
dword val_lo;
byte *val_text;
} ONE_ARG;
typedef struct parsed_args
{
int argc;
ONE_ARG argv[MAX_ARGS];
} PARSED_ARGS;
PARSED_ARGS args;
static BOOLEAN parse_numeric_input(byte *input_buffer,dword *val_hi, dword *val_lo);
static byte *strip_if_quoted_input(byte *input_buffer);
static byte *strip_if_quoted_input(byte *input_buffer)
{
byte *p_in,*p_out,*ret_val;
ret_val = p_out = p_in = input_buffer;
if (*p_in == '\"')
{
p_in++;
ret_val++;
do
{
if (*p_in == '\"')
{
*p_out = 0;
break;
}
else
*p_out++ = *p_in;
} while (*p_in++);
}
return(ret_val);
}
static BOOLEAN parse_numeric_input(byte *input_buffer,dword *val_hi, dword *val_lo)
{
dword gigs, kilos, ones;
int n_commas;
byte parse_buf[3][20];
byte *p_out,*p_in;
n_commas = 0;
parse_buf[0][0] = 0; parse_buf[1][0] = 0; parse_buf[2][0] = 0;
p_in = input_buffer;
p_out = &parse_buf[n_commas][0];
*val_lo = *val_hi = 0;
p_in = input_buffer;
if (*p_in == ',' || ( (*p_in >= '0') && (*p_in <= '9')) )
;
else
return(FALSE);
while (*p_in)
{
if (*p_in == ',')
{
n_commas += 1;
if (n_commas == 3)
{
n_commas = 2;
break;
}
p_out = &parse_buf[n_commas][0];
}
else
{
*p_out++ = *p_in;
*p_out = 0;
}
p_in++;
}
if (n_commas >= 2)
{
gigs = rtfs_atol(&parse_buf[0][0]);
kilos = rtfs_atol(&parse_buf[1][0]);
ones = rtfs_atol(&parse_buf[2][0]);
}
else if (n_commas >= 1)
{
gigs = 0;
kilos = rtfs_atol(&parse_buf[0][0]);
ones = rtfs_atol(&parse_buf[1][0]);
}
else
{
gigs = 0;
kilos = 0;
ones = rtfs_atol(&parse_buf[0][0]);
}
{
#if (INCLUDE_RTFS_PROPLUS) /* Proplus only Parse 64 bit file offset inputs */
ddword ltemp_ddw;
ltemp_ddw = M64SET32(0,gigs);
ltemp_ddw = M64LSHIFT(ltemp_ddw,30);
kilos *= 1024;
kilos += ones;
ltemp_ddw = M64PLUS32(ltemp_ddw,kilos);
*val_lo = M64LOWDW(ltemp_ddw);
if (val_hi)
*val_hi = M64HIGHDW(ltemp_ddw);
#else
dword ltemp;
ltemp = gigs << 30;
kilos *= 1024;
kilos += ones;
ltemp += kilos;
*val_lo = ltemp;
if (val_hi)
*val_hi = 0;
#endif
}
return(TRUE);
}
int parse_args(int agc, byte **agv, char *input_template)
{
byte *pt;
char *pi;
rtfs_memset(&args, 0, sizeof(args));
args.argc = 0;
pi = input_template;
while (agc)
{
if (parse_numeric_input(*agv,&(args.argv[args.argc].val_hi),
&(args.argv[args.argc].val_lo)))
args.argv[args.argc].val_text = 0;
else
args.argv[args.argc].val_text = strip_if_quoted_input(*agv);
if (pi)
{
pt = args.argv[args.argc].val_text;
if (*pi == 'B') /* Must be 'Y' or 'N' */
{
if (!pt)
return(0);
if (*pt == 'Y' || *pt == 'y')
args.argv[args.argc].val_lo = 1;
else if (*pt == 'N' || *pt == 'n')
args.argv[args.argc].val_lo = 0;
else
return(0);
}
else if (*pi == 'I') /* must be a number */
{
if (pt)
return(0);
}
else if (*pi == 'T') /* must be text */
{
args.argv[args.argc].val_text = strip_if_quoted_input(*agv);
if (!args.argv[args.argc].val_text)
return(0);
}
pi++;
}
args.argc += 1;
agc--; agv++;
}
return(args.argc);
}
int rtfs_args_arg_count(void)
{
return(args.argc);
}
dword rtfs_args_val_hi(int this_arg)
{
return (args.argv[this_arg].val_hi);
}
dword rtfs_args_val_lo(int this_arg)
{
return (args.argv[this_arg].val_lo);
}
#if (INCLUDE_CS_UNICODE)
/* Map argument to unicode if needed.
Which_uarg tells us which unicode sbuffer to use, since we may need a few */
byte unicode_shellbuffs[2][512];
byte *rtfs_args_val_utext(int this_arg, int which_uarg)
{
rtfs_print_one_string((byte *)"Converting to unicode: ", 0);;
rtfs_print_one_string((byte *) args.argv[this_arg].val_text, PRFLG_NL);
map_jis_ascii_to_unicode(&unicode_shellbuffs[which_uarg][0], args.argv[this_arg].val_text);
{
byte *b;
word *p;
p = (word *)&unicode_shellbuffs[which_uarg][0];
b = args.argv[this_arg].val_text;
while (b && *b)
{
if (*b == '}')
{
*p = 0x1234;
rtfs_print_one_string((byte *)"Converting } to unicode 0x1234",0);
}
b++; p++;
}
}
return(&unicode_shellbuffs[which_uarg][0]);
}
#endif
byte *rtfs_args_val_text(int this_arg)
{
return (args.argv[this_arg].val_text);
}
void use_args(int agc, byte **agv){
RTFS_ARGSUSED_INT(agc);
RTFS_ARGSUSED_PVOID((void *)agv);
}
long rtfs_atol(byte * s);
int rtfs_atoi(byte * s)
{
return((int)rtfs_atol(s));
}
long rtfs_atol(byte * s)
{
long n;
BOOLEAN neg;
int index;
/* skip over tabs and spaces */
while ( CS_OP_CMP_ASCII(s,' ', CS_CHARSET_NOT_UNICODE) || CS_OP_CMP_ASCII(s,'\t', CS_CHARSET_NOT_UNICODE) )
CS_OP_INC_PTR(s, CS_CHARSET_NOT_UNICODE);
n = 0;
neg = FALSE;
if (CS_OP_CMP_ASCII(s,'-', CS_CHARSET_NOT_UNICODE))
{
neg = TRUE;
CS_OP_INC_PTR(s, CS_CHARSET_NOT_UNICODE);
}
while (CS_OP_IS_NOT_EOS(s, CS_CHARSET_NOT_UNICODE))
{
index = CS_OP_ASCII_INDEX(s, '0', CS_CHARSET_NOT_UNICODE);
if (index >= 0 && index <= 9)
{
n = n * 10;
n += (long) index;
CS_OP_INC_PTR(s, CS_CHARSET_NOT_UNICODE);
}
else
break;
}
if (neg)
n = 0 - n;
return(n);
}
void rtfs_print_prompt_user(byte *prompt, byte *buf)
{
rtfs_print_one_string(prompt,0);
*buf = 0;
rtfs_kern_gets(buf);
}

1880
rtfscommon/apps/prfstest.c Normal file

File diff suppressed because it is too large Load Diff

128
rtfscommon/apps/protests.h Normal file
View File

@ -0,0 +1,128 @@
/* protests.h - This file is required only by the test and shell applications code
provided in the packages\apps subdirectory. It is included in the common include
subdirectory to eliminate the need to specify multiple include paths */
#include <stdlib.h>
extern byte *test_driveid;
extern int test_drivenumber;
#define MAX_USER_BUFFER_SIZE_BLOCKS 2048 /* 1 Meg */
#define DEFAULT_USER_BUFFER_SIZE_BLOCKS 128 /* 64 k */
#define DEFAULT_FAT_PAGESIZE 8
#define DEFAULT_NUM_FAT_BUFFERS 16 /* 16 * DEFAULT_FAT_PAGESIZE */
/* Failsafe constants, ignored if not enabled */
#define MAX_BLOCKMAPSIZE 128
#define DEFAULT_BLOCKMAPSIZE 128
/* number of 512 byte, dword alligned pages */
#define MAX_PAGE_BUFFER_SIZE 10
#define DEFAULT_PAGE_BUFFER_SIZE 10
#define MAX_RESTORE_BUFFER_SIZE 64
#define DEFAULT_RESTORE_BUFFER_SIZE 64
#define TEST_DRIVE_STRUCT() pc_drno2dr(TEST_DRIVE_NO)
#define TEST_FILE_STRUCT(fd) (prtfs_cfg->mem_file_pool+fd)
#define TEST_FILE64 (byte *) "test_64"
#define RENAMED_TEST_FILE64 (byte *) "renamed_test_64"
#define TEST_FILE32 (byte *) "test_32"
#define SMALL_FILE (byte *) "small_file"
#define SMALL_FILE_SIZE 1024 /* dwords in "small file test " */
#define FILESIZE_64 0x80000000 /* 2 gig * 4 == 8 gig */
/* #define FILESIZE_32 0x100000 */
#define TEST_BUFFER_SIZE 0x10000
#undef FILESIZE_32
#define FILESIZE_32 0x1000
extern byte *data_buffer;
extern dword data_buffer_size_dw;
/* extended IO routines set these variables in debug mode
when allocating clusters, the regression test uses them to
verify that clusters where allocated as expected */
extern dword debug_first_efile_cluster_allocated;
extern dword debug_last_efile_cluster_allocated;
extern dword debug_num_transaction_buffer_loads;
typedef struct pro_test_checkpoint {
dword info_block1_cksum;
dword info_block2_cksum;
dword fat1_cksum;
dword fat1_zero_count;
dword fat2_cksum;
dword fat2_zero_count;
dword directories_num_clusters;
dword directories_cksum;
} PRO_TEST_CHECKPOINT;
#define PRO_TEST_ANNOUNCE(X) pro_test_announce((byte *) X)
/* rtfsproplustests\prlinexttest.c */
void test_efilio_extract(byte *pdriveid);
/* rtfsproplustests\prtranstest.c */
void test_efilio_transactions(byte *pdriveid);
/* rtfsproplustests\prasytest.c */
void test_asynchronous_api(byte *pdriveid);
/* rtfsproplustests\prcftest.c */
void pc_cfilio_test(byte *pdriveid);
/* rtfsproplustests\preftest.c */
void pc_efilio_test(byte *pdriveid);
/* rtfsproplustests\prfstest.c */
void pc_fstest_main(byte *pdriveid);
void fstest_free_current_config();
/* rtfsproplustests\protests.c */
DDRIVE *test_drive_structure(void);
BOOLEAN pro_test_free_manager_atached(void);
BOOLEAN set_test_drive(byte *driveid);
dword pro_test_bytes_per_cluster(void);
dword pro_test_dwrand(void);
void pro_test_announce(byte *message);
void pro_test_print_dword(char *prompt, dword val, int flag);
void pro_test_print_two_dwords(char *prompt_1, dword val_1,
char *prompt_2, dword val_2,int flag);
BOOLEAN pro_test_compare_checkpoints(PRO_TEST_CHECKPOINT *pcheck1,PRO_TEST_CHECKPOINT *pcheck2);
void pro_test_mark_checkpoint(int drive_no, PRO_TEST_CHECKPOINT *pcheck);
void *pro_test_malloc(int n_bytes);
void pro_test_free(void *p);
dword pro_test_check_buffer_dwords(dword *dw, dword value, dword count);
void pro_test_set_buffer_dwords(dword *dw, dword value, dword count);
void pro_test_fill_buffer_dwords(dword *dw, dword value, dword count);
void pro_test_alloc_data_buffer(void);
void pro_test_free_data_buffer(void);
int pro_test_efile_create(byte *filename, dword options,dword min_clusters_per_allocation);
int pro_test_efile_fill(byte *filename,dword options,dword test_file_size_dw,BOOLEAN do_io, BOOLEAN do_close);
BOOLEAN pro_test_read_n_dwords(int fd, dword value, dword size_dw,
dword *pnread, BOOLEAN check_value);
BOOLEAN pro_test_write_n_dwords(int fd, dword value, dword size_dw,
dword *pnwritten, BOOLEAN do_increment, byte *buffer);
BOOLEAN test_if_fat12(void);
BOOLEAN test_fat64(void);
dword pro_test_operating_policy(void);
dword pro_test_bytes_per_sector(void);
void pro_test_set_mount_parameters(DDRIVE *ptest_drive, struct rtfs_volume_resource_reply *pconfig,
dword drive_operating_policy,
dword sector_size_bytes,
dword device_sector_size_sectors,
dword n_sector_buffers,
dword n_fat_buffers,
dword fat_buffer_page_size_sectors,
dword fsjournal_n_blockmaps,
dword fsindex_buffer_size_sectors,
dword fsrestore_buffer_size_sectors);
void pro_test_release_mount_parameters(DDRIVE *ptest_drive);
struct save_mount_context {
RTFS_DEVI_VOLUME_MOUNT_PARMS saved_mount_parms;
dword saved_exclusive_semaphore;
void *saved_device_sector_buffer;
byte *saved_device_sector_buffer_base;
dword saved_device_sector_buffer_size;
};
void pro_test_save_mount_context(DDRIVE *ptest_drive,struct save_mount_context *psave_context);
void pro_test_restore_mount_context(DDRIVE *ptest_drive,struct save_mount_context *psave_context);

View File

@ -0,0 +1,361 @@
/* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* PROTESTS.C - RtfsProPLus Tests, common routines */
#include "rtfs.h"
#include "protests.h"
byte test_driveid_buffer[8];
byte *test_driveid;
int test_drivenumber;
byte *data_buffer;
dword data_buffer_size_dw;
void pro_test_announce(byte *message)
{
RTFS_PRINT_STRING_1((byte *)message, PRFLG_NL);
}
DDRIVE *test_drive_structure()
{
return(pc_drno_to_drive_struct(test_drivenumber)); /* BUGFIX */
}
BOOLEAN set_test_drive(byte *driveid)
{
if (!pc_set_default_drive(driveid))
{
pro_test_announce((byte *) "Invalid drive identifier :");
pro_test_announce(driveid);
return(FALSE);
}
else
{
test_driveid = test_driveid_buffer;
test_drivenumber = pc_parse_raw_drive(driveid, CS_CHARSET_NOT_UNICODE);
/* Copy 6 bytes enough for unicode or ascii */
copybuff(test_driveid_buffer,driveid,6);
return(TRUE);
}
}
void *pro_test_malloc(int n_bytes)
{
void *p;
p = rtfs_port_malloc(n_bytes);
if (!p) {ERTFS_ASSERT_TEST(rtfs_debug_zero())}
return(p);
}
void pro_test_free(void *p)
{
rtfs_port_free(p);
}
BOOLEAN test_if_fat12(void)
{
DRIVE_INFO drive_info_stats;
if (!pc_diskio_info((byte *)test_driveid, &drive_info_stats, FALSE))
{ ERTFS_ASSERT_TEST(rtfs_debug_zero()) }
if (drive_info_stats.fat_entry_size == 12)
return(TRUE);
return(FALSE);
}
dword pro_test_operating_policy(void)
{
DRIVE_INFO drive_info_stats;
drive_info_stats.drive_operating_policy = 0;
if (!pc_diskio_info((byte *)test_driveid, &drive_info_stats, FALSE))
{ ERTFS_ASSERT_TEST(rtfs_debug_zero()) }
return(drive_info_stats.drive_operating_policy);
}
void pro_test_alloc_data_buffer(void)
{
if (!data_buffer)
{
data_buffer_size_dw = TEST_BUFFER_SIZE; /* 64 k dwords (256 k) */
data_buffer = (byte *) pro_test_malloc(data_buffer_size_dw*4);
}
}
void pro_test_free_data_buffer(void)
{
if (data_buffer)
pro_test_free(data_buffer);
data_buffer = 0;
}
dword pro_test_bytes_per_sector(void)
{
dword byte_per_cluster;
byte_per_cluster = (dword) test_drive_structure()->drive_info.bytespsector;
return(byte_per_cluster);
}
dword pro_test_bytes_per_cluster(void)
{
dword byte_per_cluster;
byte_per_cluster = (dword) (test_drive_structure()->drive_info.secpalloc);
byte_per_cluster *= test_drive_structure()->drive_info.bytespsector;
return(byte_per_cluster);
}
BOOLEAN pro_test_compare_checkpoints(PRO_TEST_CHECKPOINT *pcheck1,PRO_TEST_CHECKPOINT *pcheck2)
{
if
(
pcheck1->info_block1_cksum != pcheck2->info_block1_cksum ||
pcheck1->info_block2_cksum != pcheck2->info_block2_cksum ||
pcheck1->fat1_cksum != pcheck2->fat1_cksum ||
pcheck1->fat1_zero_count != pcheck2->fat1_zero_count ||
pcheck1->fat2_cksum != pcheck2->fat2_cksum ||
pcheck1->fat2_zero_count != pcheck2->fat2_zero_count ||
pcheck1->directories_num_clusters != pcheck2->directories_num_clusters ||
pcheck1->directories_cksum != pcheck2->directories_cksum
)
return(FALSE);
else
return(TRUE);
}
static dword pro_test_checksum(byte *user_buffer, int n_bytes);
static dword pro_test_count_zeroes(byte *user_buffer, int n_bytes);
static void mount_drive(byte *drivename)
{
#if (INCLUDE_ASYNCRONOUS_API)
int driveno,status;
driveno = pc_diskio_async_mount_start(drivename);
ERTFS_ASSERT_TEST(driveno!=-1)
status = pc_async_continue(driveno,DRV_ASYNC_IDLE, 0);
ERTFS_ASSERT_TEST(status == PC_ASYNC_COMPLETE)
#else
if (check_drive_name_mount(drivename, CS_CHARSET_NOT_UNICODE))
{
ERTFS_ASSERT_TEST(rtfs_debug_zero());
}
/* release from check mount */
rtfs_release_media_and_buffers(pc_parse_raw_drive(drivename, CS_CHARSET_NOT_UNICODE));
#endif
}
void pro_test_mark_checkpoint(int drive_no, PRO_TEST_CHECKPOINT *pcheck)
{
byte *user_buffer;
dword user_buffer_size;
DDRIVE *pdr;
pdr = check_drive_by_number(drive_no, TRUE);
if (!pdr)
{
mount_drive(test_driveid);
pdr = check_drive_by_number(drive_no, TRUE);
if (!pdr)
{ERTFS_ASSERT_TEST(rtfs_debug_zero())}
}
user_buffer = pc_claim_user_buffer(pdr, &user_buffer_size, 0); /* released at cleanup */
if (!user_buffer) {ERTFS_ASSERT_TEST(rtfs_debug_zero())}
rtfs_memset(pcheck, 0, sizeof(*pcheck));
/* Check_sum info blocks */
if (pdr->drive_info.fasize == 8)
{
if (!raw_devio_xfer(pdr, (dword) pdr->drive_info.infosec, user_buffer, 1, FALSE, TRUE))
{ERTFS_ASSERT_TEST(rtfs_debug_zero())}
pcheck->info_block1_cksum = pro_test_checksum(user_buffer, test_drive_structure()->drive_info.bytespsector);
if (!raw_devio_xfer(pdr, (dword) pdr->drive_info.infosec + 6, user_buffer, 1, FALSE, TRUE))
{ERTFS_ASSERT_TEST(rtfs_debug_zero())}
pcheck->info_block2_cksum = pro_test_checksum(user_buffer, test_drive_structure()->drive_info.bytespsector);
}
/* Check_sum FAT blocks */
{
dword i, n_blocks_left, block_no, n_blocks;
n_blocks = pdr->drive_info.secpfat;
block_no = pdr->drive_info.fatblock;
n_blocks_left = n_blocks;
while (n_blocks_left)
{
dword blocks_to_read;
byte *puser_buff;
blocks_to_read = n_blocks_left;
if (user_buffer_size < blocks_to_read)
blocks_to_read = user_buffer_size;
if (!raw_devio_xfer(pdr, block_no, user_buffer, blocks_to_read, FALSE, TRUE))
{ERTFS_ASSERT_TEST(rtfs_debug_zero())}
puser_buff = user_buffer;
/* Don't checksum the first 8 bytes of the FAT.. On a 1 FAT format we will write the journal info here */
pcheck->fat1_zero_count += pro_test_count_zeroes(puser_buff+8, test_drive_structure()->drive_info.bytespsector-8);
pcheck->fat1_cksum += pro_test_checksum(puser_buff+8, test_drive_structure()->drive_info.bytespsector-8);
puser_buff += test_drive_structure()->drive_info.bytespsector;
for (i = 1; i < blocks_to_read; i++, puser_buff += test_drive_structure()->drive_info.bytespsector)
{
pcheck->fat1_zero_count += pro_test_count_zeroes(puser_buff, test_drive_structure()->drive_info.bytespsector);
pcheck->fat1_cksum += pro_test_checksum(puser_buff, test_drive_structure()->drive_info.bytespsector);
}
n_blocks_left -= blocks_to_read;
block_no += blocks_to_read;
}
pcheck->fat2_zero_count = 0;
pcheck->fat2_cksum = 0;
/* Checksum the second fat if there is one */
if (pdr->drive_info.numfats > 1)
{
n_blocks = pdr->drive_info.secpfat;
block_no = pdr->drive_info.fatblock + n_blocks;
n_blocks_left = n_blocks;
while (n_blocks_left)
{
dword blocks_to_read;
byte *puser_buff;
blocks_to_read = n_blocks_left;
if (user_buffer_size < blocks_to_read)
blocks_to_read = user_buffer_size;
if (!raw_devio_xfer(pdr, block_no, user_buffer, blocks_to_read, FALSE, TRUE))
{ERTFS_ASSERT_TEST(rtfs_debug_zero())}
puser_buff = user_buffer;
/* Don't checksum the first 8 bytes of the FAT.. we will write the journal info here */
pcheck->fat2_zero_count += pro_test_count_zeroes(puser_buff+8, test_drive_structure()->drive_info.bytespsector-8);
pcheck->fat2_cksum += pro_test_checksum(puser_buff+8, test_drive_structure()->drive_info.bytespsector-8);
puser_buff += test_drive_structure()->drive_info.bytespsector;
for (i = 1; i < blocks_to_read; i++, puser_buff += test_drive_structure()->drive_info.bytespsector)
{
pcheck->fat2_zero_count += pro_test_count_zeroes(puser_buff, test_drive_structure()->drive_info.bytespsector);
pcheck->fat2_cksum += pro_test_checksum(puser_buff, test_drive_structure()->drive_info.bytespsector);
}
n_blocks_left -= blocks_to_read;
block_no += blocks_to_read;
}
}
}
/* Check_sum directory blocks */
{ /* Not doing yet, need to traverse from root. */
pcheck->directories_num_clusters = 0;
pcheck->directories_cksum = 0;
}
pc_release_user_buffer(pdr, user_buffer);
release_drive_mount(drive_no);/* Release lock, unmount if aborted */
}
/* dword checksum on a block. sum up (pos * content), not just pos
this is a better test for uniqueness */
static dword pro_test_checksum(byte *user_buffer, int n_bytes)
{
dword *pdw,i,cksum, ndwords;
cksum = 0;
pdw = (dword *) user_buffer;
ndwords = (dword)(n_bytes/4);
for (i = 1; i < ndwords + 1; i++, pdw++)
cksum += (i * *pdw);
return(cksum);
}
static dword pro_test_count_zeroes(byte *user_buffer, int n_bytes)
{
dword *pdw,i,zeroes,ndwords;
zeroes = 0;
pdw = (dword *) user_buffer;
ndwords = (dword)(n_bytes/4);
for (i = 0; i < ndwords; i++, pdw++)
if (!*pdw)
zeroes += 1;
return(zeroes);
}
DRIVE_INFO test_drive_infostruct; /* Drive info structure shered by test */
BOOLEAN RTFS_DEVI_copy_volume_resource_reply(DDRIVE *pdr, struct rtfs_volume_resource_reply *preply, dword sector_size_bytes);
void pc_rtfs_free(void *p); /* See drdynamic.c */
static BOOLEAN test_dsk_config_active;
void pro_test_set_mount_parameters(DDRIVE *ptest_drive, struct rtfs_volume_resource_reply *pconfig,
dword drive_operating_policy,
dword sector_size_bytes,
dword device_sector_size_sectors,
dword n_sector_buffers,
dword n_fat_buffers,
dword fat_buffer_page_size_sectors,
dword fsjournal_n_blockmaps,
dword fsindex_buffer_size_sectors,
dword fsrestore_buffer_size_sectors)
{
/* Configure drive operating conditions. This configuration is applied by:
init_drive_for_asynchronous_test()
Which is called multiple times with differing operating policies*/
rtfs_memset(pconfig, 0, sizeof(*pconfig));
/* Free the current configuration if we changed it */
pro_test_release_mount_parameters(ptest_drive);
/* Set the media info shared buffer to 32 sectors */
ptest_drive->pmedia_info->device_sector_buffer_size = sector_size_bytes*device_sector_size_sectors;
ptest_drive->pmedia_info->device_sector_buffer_base = pc_rtfs_iomalloc(ptest_drive->pmedia_info->device_sector_buffer_size, &ptest_drive->pmedia_info->device_sector_buffer);
pconfig->drive_operating_policy = drive_operating_policy;
pconfig->use_dynamic_allocation = 1;
pconfig->n_sector_buffers = n_sector_buffers;
pconfig->n_fat_buffers = n_fat_buffers;
pconfig->fat_buffer_page_size_sectors = fat_buffer_page_size_sectors;
#if (INCLUDE_FAILSAFE_CODE)
/* Use larger blockmap than default, this is required if the free manager is disabled and FAT buffers are
modified during cluster allocations, if the free manager is enabled clusters are allocated from
the free cluster pool, some tests rely on this, allocating large numbers of clusters during write and
anticipate a journal full condition during file flush */
pconfig->fsjournal_n_blockmaps = fsjournal_n_blockmaps;
pconfig->fsrestore_buffer_size_sectors = fsrestore_buffer_size_sectors;
pconfig->fsindex_buffer_size_sectors = fsindex_buffer_size_sectors;
#endif
if (!RTFS_DEVI_copy_volume_resource_reply(ptest_drive, pconfig, sector_size_bytes))
{
ERTFS_ASSERT_TEST(rtfs_debug_zero())
}
test_dsk_config_active = TRUE;
}
void pro_test_release_mount_parameters(DDRIVE *ptest_drive)
{
if (test_dsk_config_active)
{
/* Free the temorarilly allocated media buffer and volume configuration */
pc_rtfs_free(ptest_drive->pmedia_info->device_sector_buffer_base);
pc_free_disk_configuration(ptest_drive->driveno);
test_dsk_config_active = FALSE;
}
}
void pro_test_save_mount_context(DDRIVE *ptest_drive,struct save_mount_context *psave_context)
{
psave_context->saved_mount_parms = ptest_drive->mount_parms;
/* Disable shared buffer mode for user buffer and failsafe restore buffer
just clearing the semaphore is enough the shared buffers won't be touched. */
psave_context->saved_exclusive_semaphore = prtfs_cfg->rtfs_exclusive_semaphore;
psave_context->saved_device_sector_buffer_base = ptest_drive->pmedia_info->device_sector_buffer_base;
psave_context->saved_device_sector_buffer = ptest_drive->pmedia_info->device_sector_buffer;
psave_context->saved_device_sector_buffer_size = ptest_drive->pmedia_info->device_sector_buffer_size;
}
void pro_test_restore_mount_context(DDRIVE *ptest_drive,struct save_mount_context *psave_context)
{
ptest_drive->mount_parms = psave_context->saved_mount_parms;
prtfs_cfg->rtfs_exclusive_semaphore = psave_context->saved_exclusive_semaphore;
ptest_drive->pmedia_info->device_sector_buffer_base = psave_context->saved_device_sector_buffer_base;
ptest_drive->pmedia_info->device_sector_buffer = psave_context->saved_device_sector_buffer;
ptest_drive->pmedia_info->device_sector_buffer_size = psave_context->saved_device_sector_buffer_size;
}

2267
rtfscommon/source/apickdsk.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,336 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APIDELTR.C - Contains user api level source code.
The following routines are included:
pc_deltree - Delete an entire directory tree.
*/
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
/****************************************************************************
PC_DELTREE - Delete a directory tree.
Description
Delete the directory specified in name, all subdirectories of that
directory, and all files contained therein. Fail if name is not a
directory, or is read only.
Returns
Returns TRUE if the directory was successfully removed.
errno will be set to one of these values
0 - No error
PEINVALIDDRIVEID- Drive component of path is invalid
PEINVALIDPATH - Path specified by name is badly formed.
PENOENT - Can't find path specified by name.
PEACCES - Directory or one of its subdirectories is read only or
in use.
An ERTFS system error
*****************************************************************************/
/* Remove a directory */
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_deltree_cs(byte *name, int use_charset)
#else
BOOLEAN pc_deltree(byte *name)
#endif
{
DROBJ *parent_obj;
DROBJ *pobj;
DROBJ *pdotdot;
DROBJ *pchild;
BOOLEAN is_exfat = FALSE;
BOOLEAN ret_val;
DDRIVE *pdrive;
byte *path;
byte *filename;
byte fileext[4];
int driveno;
int p_set_errno;
int dir_depth;
DROBJ **dirstack = 0;
BLKBUFF *dirstack_buffer = 0;
int exfat_max_depth = 0;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
parent_obj = 0;
pchild = 0;
pobj = 0;
pdotdot = 0;
ret_val = FALSE;
dir_depth = 1;
p_set_errno = 0;
rtfs_clear_errno(); /* pc_deltree: clear error status */
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(name, CS_CHARSET_ARGS);
if (driveno < 0)
{ /* pc_deltree: errno was by check_drive */
return(FALSE);
}
pdrive = pc_drno2dr(driveno);
#if (INCLUDE_EXFATORFAT64)
if ( ISEXFATORFAT64(pdrive) )
{
is_exfat = TRUE;
dirstack_buffer = pc_scratch_blk();
if (!dirstack_buffer)
{
ret_val = FALSE;
goto errex;
}
dirstack = (DROBJ **)dirstack_buffer->data;
rtfs_memset(dirstack,0,512);
exfat_max_depth = 512/sizeof(DROBJ *);
}
#endif
/* Allocate scratch buffers in the DRIVE structure. */
if (!pc_alloc_path_buffers(pdrive))
goto errex;
path = pdrive->pathname_buffer;
filename = pdrive->filename_buffer;
/* Get out the filename and d:parent */
if (!pc_parsepath(path,filename,fileext,name, CS_CHARSET_ARGS))
{
p_set_errno = PEINVALIDPATH;
/*rtfs_set_errno(PEINVALIDPATH, __FILE__, __LINE__ */
goto errex;
}
/* Find the parent and make sure it is a directory \ */
parent_obj = pc_fndnode(path, CS_CHARSET_ARGS);
if (!parent_obj)
goto errex; /* pc_fndnode set errno */
if (!pc_isadir(parent_obj))
{
p_set_errno = PENOENT;
/*rtfs_set_errno(PENOENT, __FILE__, __LINE__ */
goto errex;
}
/* Find the file and init the structure */
pobj = pc_get_inode(0, parent_obj, filename, (byte*)fileext, GET_INODE_MATCH, CS_CHARSET_ARGS);
if (!pobj)
goto errex; /* pc_get_inode set errno */
if ( !pc_isadir(pobj) || (pobj->finode->opencount > 1) ||
(pobj->finode->fattribute & ARDONLY ))
{
p_set_errno = PEACCES;
/*rtfs_set_errno(PEACCES, __FILE__, __LINE__); */
goto errex;
}
/* Search through the directory. look at all files */
/* Call pc_get_inode with 0 to give us an obj */
if (is_exfat)
dirstack[dir_depth] = pobj;
while (dir_depth > 0)
{
if (pchild)
pc_freeobj(pchild);
pchild = pc_get_inode(0, pobj, 0 , 0, GET_INODE_STAR, CS_CHARSET_ARGS);
if (pdotdot) {
pc_freeobj(pdotdot);
pdotdot = 0;
}
if (pchild)
{
do
{
/* delete all nodes which are not subdirs;
step into all subdirs and destroy their contents. */
if (!(pc_isdot(pchild->finode->fname, pchild->finode->fext) ) )
{
if (!(pc_isdotdot(pchild->finode->fname, pchild->finode->fext) ) )
{
if (pc_isadir(pchild))
{
if ( (pchild->finode->opencount > 1) ||
(pchild->finode->fattribute&ARDONLY) )
{
p_set_errno = PEACCES;
/*rtfs_set_errno(PEACCES, __FILE__, __LINE__); */
ret_val = FALSE;
goto errex;
}
dir_depth++;
if (is_exfat)
{
if (dir_depth >= exfat_max_depth)
{
p_set_errno = PEINVALIDPATH;
goto errex; /* pc_get_inode set errno */
}
dirstack[dir_depth] = pchild;
}
else
pc_freeobj(pobj);
pobj = pchild; /* enter first subdir */
pchild = 0;
goto start_over;
}
else
{
/* Be sure it is not the root. Since the root is an abstraction
we can not delete it plus Check access permissions */
if ( pc_isroot(pchild) || (pchild->finode->opencount > 1) ||
(pchild->finode->fattribute&(ARDONLY|AVOLUME|ADIRENT)))
{
p_set_errno = PEACCES;
/*rtfs_set_errno(PEACCES, __FILE__, __LINE__); */
ret_val = FALSE;
goto errex;
}
else
{
/* Remove the file */
/* calculate max number of clusters to release.
Add bytespcluster-1 in case we are not on a cluster boundary */
ret_val = pc_rmnode(pchild);
if (!ret_val)
goto errex; /* pc_rmnode sets errno */
goto start_over;
}
}
}
else
{
if (pdotdot)
pc_freeobj(pdotdot);
pdotdot = pc_get_mom(pchild);
}
}
}
while (pc_get_inode(pchild, pobj, 0 , 0, GET_INODE_STAR, CS_CHARSET_ARGS));
}
/* When we get here we just processed a leaf that has no files.
Also it is the first entry in it's parent directory, so we pop up one level
and remove the first entry.
*/
if (get_errno() != PENOENT)
goto errex; /* pc_get_inode set errno */
/* dir empty; step out and delete */
if (pobj) {
pc_freeobj(pobj);
pobj = 0;
}
if (pchild) {
pc_freeobj(pchild);
pchild = 0;
}
dir_depth--;
if (is_exfat)
{
pdotdot = dirstack[dir_depth];
}
if (dir_depth > 0)
{
if (!pdotdot)
{
p_set_errno = PEINVALIDCLUSTER;
/*rtfs_set_errno(PEINVALIDCLUSTER, __FILE__, __LINE__); */
goto errex;
}
pchild = pc_get_inode(0, pdotdot, 0 , 0, GET_INODE_STAR, CS_CHARSET_ARGS);
if (pchild)
{
do
{
if (!(pc_isdot(pchild->finode->fname, pchild->finode->fext) ) )
{
if (!(pc_isdotdot(pchild->finode->fname, pchild->finode->fext) ) )
{
ret_val = pc_rmnode(pchild); /* remove the directory */
if (!ret_val)
goto errex; /* pc_mnode set errno */
if (is_exfat)
{
int ldir_depth;
for (ldir_depth = 0; ldir_depth < exfat_max_depth; ldir_depth++)
if (dirstack[ldir_depth] == pchild)
{
pc_freeobj(dirstack[ldir_depth]);
dirstack[ldir_depth] = 0;
break;
}
}
break;
}
}
} while (pc_get_inode(pchild, pdotdot, 0, 0, GET_INODE_STAR, CS_CHARSET_ARGS));
}
else
{
if (get_errno() != PENOENT)
goto errex; /* pc_get_inode set errno */
}
pobj = pdotdot;
pdotdot = 0;
}
else
{
pobj = pc_get_inode(0, parent_obj, filename, (byte*)fileext, GET_INODE_MATCH, CS_CHARSET_ARGS);
if (!pobj)
goto errex; /* pc_mnode set errno */
ret_val = pc_rmnode(pobj); /* Remove the directory */
if (!ret_val)
goto errex; /* pc_mnode set errno */
}
start_over:
;
}
errex:
if (dirstack_buffer)
pc_free_scratch_blk(dirstack_buffer);
if (pdotdot)
pc_freeobj(pdotdot);
if (pchild)
pc_freeobj(pchild);
if (pobj)
pc_freeobj(pobj);
if (parent_obj)
pc_freeobj(parent_obj);
pc_release_path_buffers(pdrive);
if (is_exfat)
{
for (dir_depth = 0; dir_depth < exfat_max_depth; dir_depth++)
{
if (dirstack[dir_depth])
{
pc_freeobj(dirstack[dir_depth]);
dirstack[dir_depth] = 0;
}
}
}
if (ret_val)
rtfs_clear_errno();
else if (p_set_errno)
rtfs_set_errno(p_set_errno,__FILE__, __LINE__);
if (!release_drive_mount_write(driveno))/* Release lock, unmount if aborted */
ret_val = FALSE;
return(ret_val);
}
#endif /* Exclude from build if read only */

View File

@ -0,0 +1,184 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APIDIRENT.C - Contains directory access functions and change functions */
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
/*****************************************************************************
pc_get_dirent_info - Retrieve low level directory entry information
Description
Given a file or directory name and a dirent_info buffer fill the buffer with low level
directory entry information. This structure can be examined and it can be modified
and passed to pc_set_dirent_info to change the entry.
The dirent_info structure is:
typedef struct dirent_info {
byte fattribute;
dword fcluster;
word ftime;
word fdate;
dword fsize;
dword my_block;
int my_index;
} DIRENT_INFO;
Returns
Returns TRUE if successful otherwise it returns FALSE.
****************************************************************************/
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_get_dirent_info_cs(byte *path, DIRENT_INFO *pinfo, int use_charset)
#else
BOOLEAN pc_get_dirent_info(byte *path, DIRENT_INFO *pinfo)
#endif
{
DROBJ *pobj;
BOOLEAN ret_val;
int driveno;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
rtfs_clear_errno(); /* pc_set_attributes: clear error status */
if (!path || !pinfo)
{
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__);
/*rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__); */
return(FALSE);
}
driveno = check_drive_name_mount(path, CS_CHARSET_ARGS);
if (driveno < 0)
{ /* errno was set by check_drive */
return (FALSE);
}
ret_val = FALSE;
/* pc_fndnode will set errno */
pobj = pc_fndnode(path, CS_CHARSET_ARGS);
if (pobj)
{
pinfo->fattribute = pobj->finode->fattribute;
pinfo->fcluster = pc_finode_cluster(pobj->pdrive, pobj->finode);
pinfo->ftime = pobj->finode->ftime;
pinfo->fdate = pobj->finode->fdate;
#if (INCLUDE_EXFATORFAT64)
if (ISEXFATORFAT64(pobj->pdrive))
pinfo->fsize64 = pobj->finode->fsizeu.fsize64;
else
#endif
pinfo->fsize = pobj->finode->fsizeu.fsize;
pinfo->my_block = pobj->finode->my_block;
pinfo->my_index = pobj->finode->my_index;
ret_val = TRUE;
pc_freeobj(pobj);
}
if (!release_drive_mount_write(driveno))/* Release lock, unmount if aborted */
ret_val = FALSE;
return (ret_val);
}
/*****************************************************************************
pc_set_dirent_info - Change low level directory entry information
Description
Given a file or directory name and a dirent_info buffer, update the on disk directory
with the values in dirent_info structure is.
To use this function you should first call pc_get_dirent_info, to retrieve low level directory entry information,
then change the fields you wish to modify and then call the function to apply the changes.
For example, to move the contents from "Fila A" to "File B" you could perform the following.
DIRENT_INFO fileainfo, filebinfo;
pc_get_dirent_info("File A", &fileainfo);
pc_get_dirent_info("File B", &filebinfo);
fileainfo.fcluster = filebinfo.fcluster;
fileainfo.fsize = filebinfo.fcfsize;
fileainfo.fcluster = 0;
fileainfo.fsize = 0;
pc_set_dirent_info("File A", &fileainfo);
pc_set_dirent_info("File B", &filebinfo);
The entries in the dirent_info structure that may be changed by pc_set_dirent_info are:
fattribute,fcluster,ftime and fdate;
Note: This is a very low level function that could cause serious problems if used incorrectly.
Returns
Returns TRUE if successful otherwise it returns FALSE.
****************************************************************************/
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_set_dirent_info_cs(byte *path, DIRENT_INFO *pinfo, int use_charset)
#else
BOOLEAN pc_set_dirent_info(byte *path, DIRENT_INFO *pinfo)
#endif
{
DROBJ *pobj;
BOOLEAN ret_val;
int driveno;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
rtfs_clear_errno(); /* pc_set_attributes: clear error status */
if (!path || !pinfo)
{
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__);
/*rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__); */
return(FALSE);
}
driveno = check_drive_name_mount(path, CS_CHARSET_ARGS);
if (driveno < 0)
{ /* errno was set by check_drive */
return (FALSE);
}
ret_val = FALSE;
/* pc_fndnode will set errno */
pobj = pc_fndnode(path, CS_CHARSET_ARGS);
if (pobj)
{
/* Be sure it exists and is a normal directory or file and is not open */
if (pc_isroot(pobj) || (pobj->finode->opencount > 1))
{
rtfs_set_errno(PEACCES, __FILE__, __LINE__);
}
else
{
pobj->finode->fattribute = pinfo->fattribute;
pc_pfinode_cluster(pobj->pdrive, pobj->finode, pinfo->fcluster);
pobj->finode->ftime = pinfo->ftime;
pobj->finode->fdate = pinfo->fdate;
#if (INCLUDE_EXFATORFAT64)
if (ISEXFATORFAT64(pobj->pdrive))
pobj->finode->fsizeu.fsize64 = pinfo->fsize64;
else
#endif
pobj->finode->fsizeu.fsize = pinfo->fsize;
/* Now flush the changed directory entry */
if (pc_update_inode(pobj, FALSE, 0))
ret_val = TRUE;
}
pc_freeobj(pobj);
}
if (!release_drive_mount_write(driveno))/* Release lock, unmount if aborted */
ret_val = FALSE;
return (ret_val);
}
#endif /* Exclude from build if read only */

View File

@ -0,0 +1,59 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APIDISK.C - Contains drive oriented api function */
#include "rtfs.h"
/****************************************************************************
PC_DISKCLOSE - Unmount a drive
Description
If an application may call this functions to force an unconditional
close, "unmount" of a disk. Buffers are not flush and all shared buffers
are released.
If you wish to flush the disk before closing it call pc_diskflush() first.
BOOLEAN clear_init - If clear_init is TRUE, all buffers and configuration
values provided by pc_diskio_configure() are cleared and
the buffers provided to pc_diskio_configure() may be freed.
pc_diskio_configure() must be called again to use the
drive.
Returns
TRUE if the drive id was valid.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID- Drive component is invalid
****************************************************************************/
BOOLEAN pc_diskclose(byte *driveid, BOOLEAN clear_init)
{
int driveno;
DDRIVE *pdr;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
/* Make sure its a valid drive number */
rtfs_clear_errno(); /* pc_diskflush: clear error status */
driveno = check_drive_name_mount(driveid, CS_CHARSET_NOT_UNICODE);
if (driveno < 0)
return(FALSE);
pdr = pc_drno_to_drive_struct(driveno);
pc_dskfree(driveno); /* Release buffers */
if (clear_init)
{
rtfs_memset(&pdr->du, 0, sizeof(pdr->du));
/* Release configuration if the drive was configure through pc_ertfs_run or dynamically */
pc_free_disk_configuration(driveno);
}
rtfs_release_media_and_buffers(driveno);
return(TRUE);
}

View File

@ -0,0 +1,86 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APIDISK.C - Contains drive oriented api function */
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
/****************************************************************************
PC_DISKFLUSH - Flush the FAT and all files on a disk
Description
If an application may call this functions to force all files
to be flushed and the fat to be flushed. After this call returns
the disk image is synchronized with RTFSs internal view of the
voulme.
Returns
TRUE if the disk flushed else no
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID- Drive component is invalid
An ERTFS system error
****************************************************************************/
BOOLEAN pc_diskflush(byte *path) /*__apifn__*/
{
int driveno;
DDRIVE *pdrive;
BOOLEAN ret_val;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
rtfs_clear_errno(); /* pc_diskflush: clear error status */
ret_val = FALSE;
driveno = check_drive_name_mount(path, CS_CHARSET_NOT_UNICODE);
/* if error, errno was set by check_drive */
if (driveno >= 0)
{ /* This is a top level call so override the AUTOFLUSH policy */
/* Find the drive */
pdrive = pc_drno2dr(driveno);
if (pdrive)
{
ret_val = _pc_diskflush(pdrive); /* Call Pro or ProPlus versions */
#if (INCLUDE_RTFS_PROPLUS)
/* The user called this routine explicitly so tell the devie driver to flush the cache for this volume if it has one */
pdrive->pmedia_info->device_ioctl(pdrive->pmedia_info->devhandle, (void *) pdrive, RTFS_IOCTL_FLUSHCACHE, 0 , 0);
#endif
}
if (!release_drive_mount_write(driveno))/* Release lock, unmount if aborted */
ret_val = FALSE;
}
return(ret_val);
}
/* Internal flush, called by pc_diskflush() API call and internally by Failsafe */
BOOLEAN _pc_diskflush(DDRIVE *pdrive) /*__apifn__*/
{
BOOLEAN ret_val;
ret_val = FALSE;
if (pdrive)
{
if (pc_flush_all_fil(pdrive))
{
#if (INCLUDE_EXFATORFAT64)
if (ISEXFATORFAT64(pdrive))
return pcexfat_flush(pdrive);
#endif
/* Call pc_flush_fat_blocks() instead of fatop_flushfat() because fatop_flushfat() tests
DRVPOL_NO_AUTOFLUSH and returns without flushing if it is true. .. pc_flush_fat_blocks() forces a
flush regardless of the auto-flush policy */
if (pc_flush_fat_blocks(pdrive))
ret_val = TRUE;
}
}
return(ret_val);
}
#endif /* Exclude from build if read only */

View File

@ -0,0 +1,123 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APIDISK.C - Contains drive oriented api function */
#include "rtfs.h"
BOOLEAN pc_diskio_info(byte *drive_name, DRIVE_INFO *pinfo, BOOLEAN extended)
{
int driveno;
DDRIVE *pdr;
BOOLEAN ret_val;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
rtfs_clear_errno(); /* clear error status */
if (!pinfo)
{
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__);
return(FALSE);
}
rtfs_memset(pinfo, 0, sizeof(*pinfo));
/* assume failure to start */
ret_val = FALSE;
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(drive_name, CS_CHARSET_NOT_UNICODE);
/* if error check_drive errno was set by check_drive */
if (driveno >= 0)
{
pdr = pc_drno2dr(driveno);
if (!pdr)
rtfs_set_errno(PEINVALIDDRIVEID, __FILE__, __LINE__); /* pc_free: no valid drive present */
else
{
rtfs_memset((void *) pinfo, 0, sizeof(*pinfo));
pinfo->drive_operating_policy = pdr->du.drive_operating_policy;
pinfo->cluster_size = pdr->drive_info.secpalloc;
pinfo->sector_size = (dword) pdr->drive_info.bytespsector;
#if (INCLUDE_NAND_DRIVER) /* Implement pc_mkfs_dynamic() for dynamic mode */
pinfo->erase_block_size = pdr->pmedia_info->eraseblock_size_sectors;
#else
pinfo->erase_block_size = 0;
#endif
pinfo->total_clusters = pdr->drive_info.maxfindex-1;
pinfo->free_clusters = pdr->drive_info.known_free_clusters;
pinfo->fat_entry_size = (dword) (pdr->drive_info.fasize * 4); /* Store in nibbles, change to bits */
pinfo->drive_opencounter = pdr->drive_opencounter;
#if (INCLUDE_RTFS_FREEMANAGER)
pinfo->free_manager_enabled = (BOOLEAN) CHECK_FREEMG_OPEN(pdr);
pinfo->region_buffers_total = (dword)prtfs_cfg->cfg_NREGIONS;
pinfo->region_buffers_free = prtfs_cfg->region_buffers_free;
pinfo->region_buffers_low_water = prtfs_cfg->region_buffers_low_water;
#endif
#if (INCLUDE_EXFATORFAT64)
if (ISEXFATORFAT64(pdr))
pinfo->is_exfat = TRUE;
#endif
if (extended)
{
#if (INCLUDE_RTFS_FREEMANAGER)
pinfo->free_fragments = free_manager_count_frags(pdr);
#endif
}
ret_val = TRUE;
}
release_drive_mount(driveno);/* Release lock, unmount if aborted */
}
return(ret_val);
}
BOOLEAN pc_diskio_runtime_stats(byte *drive_name, DRIVE_RUNTIME_STATS *pstats, BOOLEAN clear)
{
BOOLEAN ret_val;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
rtfs_clear_errno(); /* clear error status */
rtfs_memset(pstats, 0, sizeof(*pstats));
if (!pstats)
{
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__);
return(FALSE);
}
ret_val = TRUE;
#if (INCLUDE_DEBUG_RUNTIME_STATS)
{
int driveno;
DDRIVE *pdr;
/* assume failure to start */
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(drive_name, CS_CHARSET_NOT_UNICODE);
/* if error check_drive errno was set by check_drive */
if (driveno >= 0)
{
pdr = pc_drno2dr(driveno);
if (!pdr)
{
rtfs_set_errno(PEINVALIDDRIVEID, __FILE__, __LINE__); /* pc_free: no valid drive present */
ret_val = FALSE;
}
else
{
copybuff((void *)pstats, (void *) &pdr->drive_rtstats, sizeof(*pstats));
/* Now clear the statistics if requesst */
if (clear)
{
rtfs_memset((void *) &pdr->drive_rtstats, 0, sizeof(pdr->drive_rtstats));
}
}
release_drive_mount(driveno);/* Release lock, unmount if aborted */
}
}
#else
RTFS_ARGSUSED_INT((int) clear);
RTFS_ARGSUSED_PVOID((void *) drive_name);
#endif
return(ret_val);
}

452
rtfscommon/source/apienum.c Normal file
View File

@ -0,0 +1,452 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* File APIENUM.C */
/* pc_enumerate - List select all directory entries that match rules and
* allow a callback routine to process each on.
*
* Description - This routine traverses a subdirectory tree. It tests each
* directory entry to see if it matches user supplied selection criteria.
* if it does match the criteria a user supplied callback function is
* called with the full path name of the directory entry and a pointer
* to a DSTAT structure that contains detailed information about the
* directory entry. (see the manual page for a detailed description of the
* DSTAT structure.
*
* Selection criteria - Two arguments are used to determine the selection
* criteria. On is a flags word that specifies attributes the other is
* a pattern that specifies a wild card pattern.
* The flags argument contains a bitwise or of one or more of the following:
* MATCH_DIR - Select directory entries
* MATCH_VOL - Select volume labels
* MATCH_FILES - Select files
* MATCH_DOT - Select the '.' entry MATH_DIR must be true also
* MATCH_DOTDOT - Select the '..' entry MATCH_DIR must be true also
*
* The selection pattern is a standard wildcard pattern such as '*.*' or
* *.txt.
* Note: Patterns don't work the same for VFAT and DOS 8.3. If VFAT is
* enable the pattern *.* will return any file name that has a '.' in it
* in 8.3 systems it returns all files.
*
* Note: pc_enumerate() requires a fair amount of buffer space to function.
* Instead of allocating the space internally we require that the application
* pass two buffers of size EMAXPATH_BYTES in to the function. See below.
*
* Se
* Summary:
*
* int pc_enumerate(
* byte * from_pattern_buffer - pointer to a scratch buffer of size EMAXPATH_BYTES
* byte * spath_buffer - pointer to a scratch buffer of size EMAXPATH_BYTES
* byte * dpath_buffer - pointer to a scratch buffer of size EMAXPATH_BYTES
* byte * root_search - Root of the search IE C:\ or C:\USR etc.
* word match_flags - Selection flags (see above)
* byte match_pattern - Match pattern (see above)
* int maxdepth - Maximum depth of the traversal.
* Note: to scan only one level set this to
* 1. For all levels set it to 99
* PENUMCALLBACK pcallback - User callback function. (see below)
*
* Return value
* pc_enumerate() returns 0 unless the callback function returns a non-
* zero value at any point. If the callback returns a non-zero value the
* scan terminates imediately and returns the returned value to the
* application.
*
* errno is set to one of the following
* pc_enumerate() does not set errno
*
*
* About the callback.
*
* The callback function is a function that returns an integer and is passed
* the fully qualified path to the current directory entry and a DSTAT
* structure. The callback fuction must return 0 if it wishes the scan to
* continue or any other integer value to stop the scan and return the
* callback's return value to the application layer.
*
* Examples
*
* The next two function implement a multilevel directory scan.
* int rdir_callback(byte *path, DSTAT *d) {MY_PRINTF("%s\n", path);return(0);}
*
* rdir(byte *path, byte *pattern)
* {
* pc_enumerate(from_path,from_pattern,spath,dpath,path,
* (MATCH_DIR|MATCH_VOL|MATCH_FILES), pattern, 99, rdir_callback);
* }
*
* Poor mans deltree package
* int delfile_callback(byte *path, DSTAT *d) {
* pc_unlink(path); return(0);
* }
* int deldir_callback(byte *path, DSTAT *d) {
* pc_rmdir(path); return(0);
* }
*
*
* deltree(byte *path)
* {
* int i;
* ==> First delete all of the files
* pc_enumerate(from_path,from_pattern,spath,dpath,path,
* (MATCH_FILES), "*",99, delfile_callback);
* i = 0;
* ==> Now delete all of the dirs.. deleting path won't work until the
* ==> tree is empty
* while(!pc_rmdir(path) && i++ < 50)
* pc_enumerate(from_path,from_pattern,spath,dpath,path,
* (MATCH_DIR), "*", 99, deldir_callback);
* }
*
*/
#include "rtfs.h"
#if (!INCLUDE_VFAT)
BOOLEAN rtfs_cs_patcmp_8(byte *p, byte *pattern, BOOLEAN dowildcard);
BOOLEAN rtfs_cs_patcmp_3(byte *p, byte *pattern, BOOLEAN dowildcard);
#endif
static int get_parent_path(byte *parent, byte *path, int use_charset);
static int dirscan_isdot(DSTAT *statobj);
static int dirscan_isdotdot(DSTAT *statobj);
#define COMPILED_MAX_DEPTH 128
#if (INCLUDE_CS_UNICODE)
int pc_enumerate_cs( /* __apifn__ */
byte * from_path_buffer,
byte * from_pattern_buffer,
byte * spath_buffer,
byte * dpath_buffer,
byte * root_search,
word match_flags,
byte * match_pattern,
int maxdepth,
PENUMCALLBACK pcallback,
int use_charset)
#else
int pc_enumerate( /* __apifn__ */
byte * from_path_buffer,
byte * from_pattern_buffer,
byte * spath_buffer,
byte * dpath_buffer,
byte * root_search,
word match_flags,
byte * match_pattern,
int maxdepth,
PENUMCALLBACK pcallback)
#endif
{
int dir_index[COMPILED_MAX_DEPTH];
dword dir_block[COMPILED_MAX_DEPTH];
int depth;
DSTAT statobj;
int process_it;
int dodone;
int call_back;
int ret_val;
int step_into_dir;
byte all_files[8];
/* Guard against endless looping */
#define MAX_LOOP_COUNT 327680 /* A lot but we may be enumerating a large tree */
dword loop_count = 0;
#if (!INCLUDE_VFAT)
int i;
/* IN 8.3 systems we parse the match pattern into file and ext parts */
byte filepat[9];
byte extpat[9];
#endif
if (!from_path_buffer ||!from_pattern_buffer || !spath_buffer || !dpath_buffer || !root_search || !match_pattern)
{
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__);
return(-1);
}
#if (!INCLUDE_VFAT)
rtfs_cs_ascii_fileparse(filepat, extpat, (byte *)match_pattern);
for(i = 0; i < 8; i++) if (filepat[i]==' ') filepat[i]=0;
for(i = 0; i < 3; i++) if (extpat[i]==' ') extpat[i]=0;
#endif
/* Create the "ALL" search pattern */
{
byte *p;
p = &all_files[0];
CS_OP_ASSIGN_ASCII(p,'*', CS_CHARSET_ARGS); /* * */
CS_OP_INC_PTR(p, CS_CHARSET_ARGS);
#if (!INCLUDE_VFAT)
CS_OP_ASSIGN_ASCII(p,'.', CS_CHARSET_ARGS); /* *.* */
CS_OP_INC_PTR(p, CS_CHARSET_ARGS);
CS_OP_ASSIGN_ASCII(p,'*', CS_CHARSET_ARGS);
CS_OP_INC_PTR(p, CS_CHARSET_ARGS);
#endif
CS_OP_TERM_STRING(p, CS_CHARSET_ARGS);
}
ret_val = 0;
rtfs_cs_strcpy((byte *)from_path_buffer, (byte *) root_search, CS_CHARSET_ARGS);
depth = 0;
if (maxdepth > COMPILED_MAX_DEPTH)
return(0);
pc_mpath(from_pattern_buffer, from_path_buffer, all_files, CS_CHARSET_ARGS);
dir_index[0] = 0;
dir_block[0] = 0;
do
{
if (loop_count++ > MAX_LOOP_COUNT)
goto endless_loop;
dodone = 0;
step_into_dir = 0;
#if (INCLUDE_EXFATORFAT64)
if (match_flags&MATCH_SYSSCAN)
statobj.search_backwards_if_magic=SYS_SCAN_MAGIC_NUMBER;
#endif
#if (INCLUDE_CS_UNICODE)
if (pc_gfirst_cs(&statobj, (byte *)from_pattern_buffer, CS_CHARSET_ARGS))
#else
if (pc_gfirst(&statobj, (byte *)from_pattern_buffer))
#endif
{
dodone = 1;
process_it = 0;
do
{
if (loop_count++ > MAX_LOOP_COUNT)
goto endless_loop;
step_into_dir = 0;
if (!dir_block[depth] || ((dir_block[depth] ==
((DROBJ *) (statobj.pobj))->blkinfo.my_block ) &&
(dir_index[depth] ==
((DROBJ *) (statobj.pobj))->blkinfo.my_index )))
process_it = 1;
if (process_it)
{
call_back = 1;
/* Don't report directories if not requested */
if ((statobj.fattribute & ADIRENT) &&
!(match_flags & MATCH_DIR) )
call_back = 0;
/* Don't report volumes if not requested */
if (call_back && (statobj.fattribute & AVOLUME) &&
!(match_flags & MATCH_VOL) )
call_back = 0;
/* Don't report plain files if not requested */
if (call_back && !(statobj.fattribute & (AVOLUME|ADIRENT)) &&
!(match_flags & MATCH_FILES) )
call_back = 0;
/* Don't report DOT if not requested */
if (call_back && dirscan_isdot(&statobj) && !(match_flags & MATCH_DOT))
call_back = 0;
/* Don't report DOTDOT if not requested */
if (call_back && dirscan_isdotdot(&statobj) && !(match_flags & MATCH_DOTDOT))
call_back = 0;
if (call_back)
{
/* Take it if the pattern match work */
#if (INCLUDE_VFAT)
/* Under INCLUDE_VFAT do a pattern match on the long file name */
if (statobj.lfname[0])
call_back = pc_patcmp_vfat(match_pattern, statobj.lfname, TRUE, CS_CHARSET_ARGS);
else
call_back = pc_patcmp_vfat(match_pattern, (byte *)(statobj.filename), TRUE, CS_CHARSET_ARGS);
#else
/* Non INCLUDE_VFAT uses 8.3 matching conventions */
rtfs_cs_ascii_fileparse(filepat, extpat, (byte *)match_pattern);
call_back =
rtfs_cs_patcmp_8((byte *)&statobj.fname[0], (byte *)&filepat[0] , TRUE);
call_back = call_back &&
rtfs_cs_patcmp_3((byte *)&statobj.fext[0], (byte *)&extpat[0] , TRUE);
#endif
}
/* Construct the full path */
#if (INCLUDE_VFAT)
pc_mpath(dpath_buffer, from_path_buffer, (byte *)statobj.lfname, CS_CHARSET_ARGS);
#else
pc_mpath(dpath_buffer, from_path_buffer, (byte *)statobj.filename, CS_CHARSET_ARGS);
#endif
#if (INCLUDE_EXFATORFAT64)
if (match_flags&MATCH_SYSSCAN)
call_back=1; /*A system scan takes all */
#endif
if (call_back && pcallback)
{
/* If the callback returns non zero he says quit */
ret_val = pcallback(dpath_buffer, &statobj);
#if (INCLUDE_EXFATORFAT64)
if ((match_flags&MATCH_SYSSCAN)&&(statobj.pobj&&((DROBJ *)(statobj.pobj))->finode))
{ /* If inside EXFAT system, gfirst et al did not release the finode, so do it now */
pc_freei(((DROBJ *)(statobj.pobj))->finode); /* Release the current */
((DROBJ *)(statobj.pobj))->finode = 0;
}
#endif
if (ret_val)
{
pc_gdone(&statobj);
goto ex_it;
}
}
}
/* If it is a subdirectory and we are still in our depth range
then process the subdirectory */
if (process_it && (depth < maxdepth) &&
!dirscan_isdot(&statobj) &&
!dirscan_isdotdot(&statobj))
{
/* Construct the full path */
#if (INCLUDE_VFAT)
pc_mpath(spath_buffer, from_path_buffer, (byte *)statobj.lfname, CS_CHARSET_ARGS);
#else
pc_mpath(spath_buffer, from_path_buffer, (byte *)statobj.filename, CS_CHARSET_ARGS);
#endif
if (statobj.fattribute & ADIRENT) /* Changed from (AVOLUME | ADIRENT) which was an obscure problem having no side effects except when the volume label is all spaces (something windows allows apparently) */
{
#if (INCLUDE_CS_UNICODE)
if (pc_gnext_cs(&statobj, CS_CHARSET_ARGS))
#else
if (pc_gnext(&statobj))
#endif
{
/* Mark where we are */
dir_block[depth] = ((DROBJ *) (statobj.pobj))->blkinfo.my_block;
dir_index[depth] = ((DROBJ *) (statobj.pobj))->blkinfo.my_index;
dodone = 0;
pc_gdone(&statobj);
}
else
{
dodone = 0;
pc_gdone(&statobj);
dir_index[depth] = -1;
}
depth += 1;
dir_block[depth] = 0;
dir_index[depth] = 0;
rtfs_cs_strcpy((byte *)from_path_buffer, (byte *)spath_buffer, CS_CHARSET_ARGS);
pc_mpath(from_pattern_buffer, from_path_buffer, all_files, CS_CHARSET_ARGS);
/* Force it to stay in the loop but not execute
gnext.. execute gfirst instead */
step_into_dir = 1;
break;
} /* (statobj.fattribute & (AVOLUME | ADIRENT)) */
} /* if (process_it && (depth < maxdepth) .... */
/* pc_gnext will not execute if step_into_dir is non zero */
#if (INCLUDE_CS_UNICODE)
} while (pc_gnext_cs(&statobj, CS_CHARSET_ARGS)); /* or get the next file in dir */
#else
} while (pc_gnext(&statobj)); /* or get the next file in dir */
#endif
if (!step_into_dir)
{
/* We broke out so we're done with this level */
dir_index[depth] = -1;
/* If we broke out and pc_gdone is needed */
if (dodone)
pc_gdone(&statobj);
}
} /* if (pc_gfirst(&statobj, (byte *)from_pattern_buffer)) */
else
{
/* gfirst failed so we're done with this level */
dir_index[depth] = -1;
}
if (!step_into_dir)
{
while (depth > 0 && dir_index[depth] == -1)
{
if (!get_parent_path(from_path_buffer, from_path_buffer, CS_CHARSET_ARGS))
goto endless_loop;
pc_mpath(from_pattern_buffer, from_path_buffer, all_files, CS_CHARSET_ARGS);
depth--;
}
}
/* Keep trying unless we are in the root of the search and hit EOF */
} while (!(depth == 0 && dir_index[0] == -1));
ex_it:
return (ret_val);
endless_loop:
rtfs_set_errno(PEINVALIDDIR, __FILE__, __LINE__);
return (-1);
}
static int get_parent_path(byte *parent, byte *path, int use_charset) /*__fn__*/
{
byte *last_backslash = 0;
byte *parent_init = parent;
int size = 0;
while (CS_OP_IS_NOT_EOS(path, use_charset))
{
size++;
if (CS_OP_CMP_ASCII(path,'\\', use_charset))
{
last_backslash = parent;
}
CS_OP_CP_CHR(parent,path, use_charset);
CS_OP_INC_PTR(parent, use_charset);
CS_OP_INC_PTR(path, use_charset);
}
/* This is to prevent catastrophie if caller ignores failure */
CS_OP_TERM_STRING(parent, use_charset);
//if (size < 3)
// return (0);
/* Replace the last backslash with NULL. Unless we are at the top.. we will increment
first and leave it at the top as \\ so \FRED yields \ */
if (last_backslash && last_backslash == parent_init)
CS_OP_INC_PTR(last_backslash, use_charset);
if (last_backslash)
{
CS_OP_TERM_STRING(last_backslash, use_charset);
}
return (1);
}
/************************************************************************
* *
* File system abstraction layer *
* *
************************************************************************/
static int dirscan_isdot(DSTAT *statobj)
{
char *p;
p = (char *)statobj->filename;
if (*p=='.' && *(p+1) == 0)
return(1);
else
return(0);
}
static int dirscan_isdotdot(DSTAT *statobj)
{
char *p;
p = (char *)statobj->filename;
if (*p=='.' && *(p+1) == '.' && *(p+2) == 0)
return(1);
else
return(0);
}

View File

@ -0,0 +1,248 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APIFILEMV.C - Contains user api level source code.
The following routines are included:
pc_mv - Rename a file.
pc_unlink - Delete a file.
*/
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
/***************************************************************************
PC_MV - Rename a file.
Description
Renames the file in path (name) to newname. Fails if name is invalid,
newname already exists or path not found.
01-07-99 - Rewrote to support moving files between subdirectories
no longer supports renaming subdirectories or volumes
Returns
Returns TRUE if the file was renamed. Or no if the name not found.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID- Drive component is invalid or they are not the same
PEINVALIDPATH - Path specified by old_name or new_name is badly formed.
PEACCESS - File or directory in use, or old_name is read only
PEEXIST - new_name already exists
An ERTFS system error
***************************************************************************/
/* Rename a file */
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_mv_cs(byte *old_name, byte *new_name,int use_charset)
#else
BOOLEAN pc_mv(byte *old_name, byte *new_name)
#endif
{
int old_driveno;
DROBJ *old_obj;
DROBJ *old_parent_obj;
DROBJ *dot_dot_obj;
byte *path;
byte *filename;
byte fileext[4];
int new_driveno;
DROBJ *new_obj;
DROBJ *new_parent_obj;
BOOLEAN ret_val;
DDRIVE *pdrive;
int p_set_errno;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
p_set_errno = 0;
/* Drives must be the same */
if ( !pc_parsedrive( &old_driveno, old_name, CS_CHARSET_ARGS) ||
!pc_parsedrive( &new_driveno, new_name, CS_CHARSET_ARGS) ||
old_driveno != new_driveno)
{
rtfs_set_errno(PEINVALIDDRIVEID, __FILE__, __LINE__);
return(FALSE);
}
/* Get the drive and make sure it is mounted */
old_driveno = check_drive_name_mount(old_name, CS_CHARSET_ARGS);
if (old_driveno < 0)
{
/* errno was set by check_drive */
return(FALSE);
}
rtfs_clear_errno(); /* pc_mv: clear error status */
dot_dot_obj = 0;
old_obj = 0;
old_parent_obj = 0;
new_obj = 0;
new_parent_obj = 0;
ret_val = FALSE;
pdrive = pc_drno2dr(old_driveno);
/* Allocate scratch buffers in the DRIVE structure. */
if (!pc_alloc_path_buffers(pdrive))
goto errex;
path = pdrive->pathname_buffer;
filename = pdrive->filename_buffer;
/* Get out the filename and d:parent */
if (!pc_parsepath(path, filename,fileext,old_name, CS_CHARSET_ARGS))
{
p_set_errno = PEINVALIDPATH;
/*rtfs_set_errno(PEINVALIDPATH" __FILE__, __LINE__);*/
goto errex;
}
/* Find the parent and make sure it is a directory */
old_parent_obj = pc_fndnode(path, CS_CHARSET_ARGS);
if (!old_parent_obj)
goto errex; /* pc_fndinode - set errno */
if (!pc_isadir(old_parent_obj))
{
p_set_errno = PENOENT;
/*rtfs_set_errno(PENOENT, __FILE__, __LINE__); */
goto errex;
}
/* Find the file */
old_obj = pc_get_inode(0, old_parent_obj,
filename, (byte*)fileext, GET_INODE_MATCH, CS_CHARSET_ARGS);
if (!old_obj)
goto errex; /* pc_get_inode - set errno */
/* Be sure it exists and is a normal directory or file and is not open */
if (pc_isroot(old_obj) || (old_obj->finode->opencount > 1) ||
(old_obj->finode->fattribute&(ARDONLY|AVOLUME)))
{
p_set_errno = PEACCES;
/*rtfs_set_errno(PEACCES, __FILE__, __LINE__); */
goto errex;
}
#if (INCLUDE_EXFATORFAT64)
if (!ISEXFATORFAT64(pdrive) && old_obj->finode->fattribute & ADIRENT)
#else
if (old_obj->finode->fattribute & ADIRENT)
#endif
{
/* Bug fix November 2009. Previous method failed with unicode because we were passing the ascii ".."
and matching on UNICODE. This always failed so you could not rename a directory using the unicode interface.
An efficient solution is to pass GET_INODE_DOTDOT for a search command and eliminate string argument preparation and passing. */
dot_dot_obj = pc_get_inode(0, old_obj, 0, 0, GET_INODE_DOTDOT, CS_CHARSET_ARGS);
if (!dot_dot_obj)
goto errex;
}
/* At this point old_obj contains the file we are renaming */
/* See if the new directory entry already exists */
new_obj = pc_fndnode(new_name, CS_CHARSET_ARGS);
if (new_obj)
{
p_set_errno = PEEXIST;
/*rtfs_set_errno(PEEXIST, __FILE__, __LINE__); */
goto errex;
}
rtfs_clear_errno(); /* pc_mv - clear errno condition after failed pc_fndnode */
/* Get out the filename and d:parent */
if (!pc_parsepath(path,filename,fileext,new_name, CS_CHARSET_ARGS))
{
p_set_errno = PEINVALIDPATH;
/*rtfs_set_errno(PEINVALIDPATH, __FILE__, __LINE__); */
goto errex;
}
/* Find the parent and make sure it is a directory */
new_parent_obj = pc_fndnode(path, CS_CHARSET_ARGS);
if (!new_parent_obj || !pc_isadir(new_parent_obj) || pc_isavol(new_parent_obj))
{
p_set_errno = PEINVALIDPATH;
goto errex;
}
#if (INCLUDE_EXFATORFAT64)
if (ISEXFATORFAT64(pdrive))
{ /* Call exfat move routine, it sets errno if an error occurs. */
rtfs_clear_errno();
p_set_errno = 0;
ret_val = pcexfat_mvnode(old_parent_obj,old_obj,new_parent_obj, filename,use_charset);
goto errex;
}
/* Create the new entry and assign cluster to it. If it is a directory
.. will be linked correctly */
new_obj = pc_mknode( new_parent_obj, filename, fileext, old_obj->finode->fattribute, old_obj->finode,CS_CHARSET_ARGS);
#else
{
dword cluster;
/* The cluster value old */
cluster = pc_finode_cluster(old_obj->pdrive,old_obj->finode);
/* Create the new entry and assign cluster to it. If it is a directory
.. will be linked correctly */
new_obj = pc_mknode( new_parent_obj, filename, fileext, old_obj->finode->fattribute, cluster,CS_CHARSET_ARGS);
}
#endif
if (!new_obj)
goto errex;
/* Copy the old directory entry stuf over */
new_obj->finode->fattribute = old_obj->finode->fattribute;
new_obj->finode->reservednt = old_obj->finode->reservednt;
new_obj->finode->create10msincrement = old_obj->finode->create10msincrement;
new_obj->finode->ftime = old_obj->finode->ftime;
new_obj->finode->fdate = old_obj->finode->fdate;
new_obj->finode->ctime = old_obj->finode->ctime;
new_obj->finode->cdate = old_obj->finode->cdate;
new_obj->finode->adate = old_obj->finode->adate;
new_obj->finode->atime = old_obj->finode->atime;
new_obj->finode->fsizeu.fsize = old_obj->finode->fsizeu.fsize;
/* Update the new inode. Do not set archive bit or change date */
if (!pc_update_inode(new_obj, FALSE, 0))
goto errex;
if (new_obj->finode->fattribute & ADIRENT)
{
dword cltemp;
/* If we are renaming a directory then update '..' */
cltemp = pc_get_parent_cluster(pdrive, new_obj);
dot_dot_obj->finode->fclusterhi = (word)(cltemp >> 16);
dot_dot_obj->finode->fcluster = (word)cltemp ;
if (!pc_update_inode(dot_dot_obj, FALSE, 0))
goto errex;
}
/* Set the old cluster value to zero */
pc_pfinode_cluster(old_obj->pdrive,old_obj->finode,0);
/* Delete the old but won't delete any clusters */
if (!pc_rmnode(old_obj))
goto errex;
p_set_errno = 0;
ret_val = TRUE;
/* Good conditions fall through here, error exits jump to here */
errex:
if (old_parent_obj)
pc_freeobj(old_parent_obj);
if (dot_dot_obj)
pc_freeobj(dot_dot_obj);
if (old_obj)
pc_freeobj(old_obj);
if (new_parent_obj)
pc_freeobj(new_parent_obj);
if (new_obj)
pc_freeobj(new_obj);
pc_release_path_buffers(pdrive);
/* Set errno if we have one and not set by lower level already */
if ((p_set_errno) && !get_errno())
rtfs_set_errno(p_set_errno, __FILE__, __LINE__);
if (!release_drive_mount_write(old_driveno))/* Release lock, unmount if aborted */
ret_val = FALSE;
return(ret_val);
}
#endif /* Exclude from build if read only */

1249
rtfscommon/source/apifrmat.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,220 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APIGETWD.C - Contains user api level source code.
The following routines are included:
pc_get_cwd - Get string representation of current working dir.
*/
#include "rtfs.h"
/*****************************************************************************
PC_get_cwd - Return a string containing the current working directory for
a drive.
Description
Fill in a string with the full path name of the current working directory.
Return FALSE if something went wrong.
If *drive is null or an invalid drive specifier the default drive is used.
Returns
Returns the path name in path. The function returns TRUE on success
no on failure.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID- Drive component is invalid
An ERTFS system error
****************************************************************************/
static BOOLEAN pc_l_pwd(byte *path, DROBJ *pobj, int use_charset);
static BOOLEAN pc_gm_name(byte *path, DROBJ *parent_obj, DROBJ *pdotdot, int use_charset);
static BOOLEAN _pc_pwd(byte *drive, byte *path, int use_charset);
/* RtfsProPlus uses pc_get_cwd() while Pro uses pc_pwd() - Provide both */
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_get_cwd_cs(byte *drive, byte *path, int use_charset)
{
return(_pc_pwd(drive, path,CS_CHARSET_ARGS));
}
BOOLEAN pc_pwd_cs(byte *drive, byte *path, int use_charset)
{
return(_pc_pwd(drive, path,CS_CHARSET_ARGS));
}
#else
BOOLEAN pc_get_cwd(byte *drive, byte *path)
{
return(_pc_pwd(drive, path,CS_CHARSET_ARGS));
}
BOOLEAN pc_pwd(byte *drive, byte *path)
{
return(_pc_pwd(drive, path,CS_CHARSET_ARGS));
}
#endif
static BOOLEAN _pc_pwd(byte *drive, byte *path, int use_charset)
{
int driveno;
DDRIVE *pdrive;
DROBJ *pobj;
BOOLEAN ret_val;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
ret_val = FALSE;
rtfs_clear_errno(); /* pc_pwd: clear error status */
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(drive, use_charset);
if (driveno < 0)
{
/* errno was set by check_drive */
goto return_error;
}
/* Find the drive */
pdrive = pc_drno2dr(driveno);
if (pdrive)
{
#if (INCLUDE_EXFATORFAT64)
if (ISEXFATORFAT64(pdrive) )
{
ret_val = pcexfat_get_cwd(pdrive, path, use_charset);
}
else
#endif
{
pobj = _pc_get_user_cwd(pdrive);
/* _pc_get_user_cwd sets errno */
if (pobj)
{
ret_val = pc_l_pwd(path, pobj, use_charset);
}
}
}
release_drive_mount(driveno);/* Release lock, unmount if aborted */
return_error: /* Does not have to be an error to get here */
return(ret_val);
}
static BOOLEAN pc_l_pwd(byte *path, DROBJ *pobj, int use_charset) /*__fn__*/
{
#define OBJDEPTH 32
DROBJ *parentlist[OBJDEPTH]; /* List of drobjs to the top */
DROBJ *dotdotlist[OBJDEPTH]; /* List of drobjs to the top */
int objcnt;
BOOLEAN ret_val;
int i;
DROBJ *tpobj;
ret_val = FALSE;
/* If it is the root we are done */
if (pc_isroot(pobj))
{
CS_OP_ASSIGN_ASCII(path,'\\', use_charset);
CS_OP_INC_PTR(path, use_charset);
CS_OP_TERM_STRING(path, use_charset);
pc_freeobj(pobj);
return(TRUE);
}
/* Build a list of drobjs for directories and a drobj for the .. in
the directories */
tpobj = pobj;
/* Zero the object lists in case we terminate incorrectly */
for (objcnt = 0; objcnt < OBJDEPTH; objcnt++)
dotdotlist[objcnt] = parentlist[objcnt] = 0;
for (objcnt = 0; objcnt < OBJDEPTH; objcnt++)
{
/* get dotdot */
tpobj = pc_get_inode(0, tpobj, 0, 0, GET_INODE_DOTDOT,use_charset);
dotdotlist[objcnt] = tpobj;
if (!tpobj)
goto clean_and_go;
/* Get the parent directory */
tpobj = pc_get_mom(tpobj);
parentlist[objcnt] = tpobj;
if (!tpobj)
goto clean_and_go;
if (pc_isroot(tpobj))
break;
}
if (objcnt >= OBJDEPTH)
{
objcnt = OBJDEPTH-1;
goto clean_and_go;
}
/* Start at the root and work backwards in the list of parents getting
the names. (note: the get name algorithm needs the parent of the
current directory and the .. of the directory */
for (i = objcnt; i >= 0; i--)
{
CS_OP_ASSIGN_ASCII(path,'\\', use_charset);
CS_OP_INC_PTR(path,use_charset);
CS_OP_TERM_STRING(path,use_charset);
if (!pc_gm_name(path , parentlist[i],dotdotlist[i], use_charset))
goto clean_and_go;
path = CS_OP_GOTO_EOS(path,use_charset);
}
ret_val = TRUE;
clean_and_go:
for (i = objcnt; i >= 0; i--)
{
if (parentlist[i])
pc_freeobj(parentlist[i]);
if (dotdotlist[i])
pc_freeobj(dotdotlist[i]);
}
pc_freeobj(pobj);
return(ret_val);
}
static BOOLEAN pc_gm_name(byte *path, DROBJ *parent_obj, DROBJ *pdotdot, int use_charset) /*__fn__*/
{
DROBJ *pchild;
dword clusterno;
dword fcluster;
BOOLEAN ret_val;
ret_val = FALSE;
clusterno = pc_sec2cluster(pdotdot->pdrive, pdotdot->blkinfo.my_frstblock);
pchild = pc_get_inode(0, parent_obj, 0, 0, GET_INODE_STAR,use_charset);
if (pchild)
{
do
{
fcluster = pc_finode_cluster(pdotdot->pdrive,pchild->finode);
if (fcluster == clusterno)
{
/* Get a long file name if none revert to the 8.3 name */
if (!pc_get_lfn_filename(pchild,path, use_charset))
pc_cs_mfile (path, pchild->finode->fname, pchild->finode->fext, use_charset);
ret_val = TRUE;
break;
}
}
while (pc_get_inode(pchild, parent_obj, 0, 0, GET_INODE_STAR,use_charset));
}
if (pchild)
{
pc_freeobj(pchild);
}
return(ret_val);
}

View File

@ -0,0 +1,415 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APIGFRST.C - Contains user api level source code.
The following routines are included:
pc_gfirst - Get stats on the first file to match a pattern.
pc_gnext - Get stats on the next file to match a pattern.
pc_gdone - Free resources used by pc_gfirst/pc_gnext.
pc_upstat - Copy directory entry info to a user s stat buffer
*/
#include "rtfs.h"
#if (INCLUDE_CS_UNICODE)
static BOOLEAN _pc_gfirst_cs(DSTAT *statobj, byte *name, int use_charset);
#else
static BOOLEAN _pc_gfirst(DSTAT *statobj, byte *name);
#endif
#if (INCLUDE_REVERSEDIR)
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_glast_cs(DSTAT *statobj, byte *name, int use_charset)
#else
BOOLEAN pc_glast(DSTAT *statobj, byte *name) /*__apifn__*/
#endif
{
statobj->search_backwards_if_magic = SEARCH_BACKWARDS_MAGIC_NUMBER;
#if (INCLUDE_CS_UNICODE)
return (_pc_gfirst_cs(statobj, name, use_charset));
#else
return(_pc_gfirst(statobj, name));
#endif
}
#endif
/***************************************************************************
PC_GFIRST - Get first entry in a directory to match a pattern.
Description
Given a pattern which contains both a path specifier and a search pattern
fill in the structure at statobj with information about the file and set
up internal parts of statobj to supply appropriate information for calls
to pc_gnext.
Examples of patterns are:
D:\USR\RELEASE\NETWORK\*.C
D:\USR\BIN\UU*.*
D:MEMO_?.*
D:*.*
Returns
Returns TRUE if a match was found otherwise FALSE. (see also the pcls.c
utility.)
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID- Drive component is invalid
PEINVALIDPATH - Path specified badly formed.
PENOENT - Not found, no match
An ERTFS system error
****************************************************************************/
static void pc_upstat(DSTAT *statobj, int use_charset);
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_gfirst_cs(DSTAT *statobj, byte *name, int use_charset)
#else
BOOLEAN pc_gfirst(DSTAT *statobj, byte *name) /*__apifn__*/
#endif
{
#if (INCLUDE_EXFATORFAT64)
if (statobj->search_backwards_if_magic!=SYS_SCAN_MAGIC_NUMBER) /* system scan overrides default behavior */
#endif
statobj->search_backwards_if_magic = 0;
#if (INCLUDE_CS_UNICODE)
return (_pc_gfirst_cs(statobj, name, use_charset));
#else
return(_pc_gfirst(statobj, name));
#endif
}
#if (INCLUDE_CS_UNICODE)
static BOOLEAN _pc_gfirst_cs(DSTAT *statobj, byte *name, int use_charset)
#else
static BOOLEAN _pc_gfirst(DSTAT *statobj, byte *name) /*__apifn__*/
#endif
{
byte *mompath;
byte *filename;
byte fileext[4];
int driveno;
DDRIVE *pdrive;
BOOLEAN ret_val;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
rtfs_clear_errno(); /* po_gfirst: clear error status */
{
dword save_magic = statobj->search_backwards_if_magic;
rtfs_memset((byte *) statobj,0,sizeof(*statobj));
/* statobj->pobj = 0; */
/* statobj->pmom = 0; */
statobj->search_backwards_if_magic = save_magic;
}
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(name, CS_CHARSET_ARGS);
if (driveno < 0)
{
/* errno was set by check_drive */
return(FALSE);
}
pdrive = pc_drno2dr(driveno);
ret_val = FALSE;
/* Allocate scratch buffers in the DRIVE structure. */
if (!pc_alloc_path_buffers(pdrive))
goto errex;
mompath = pdrive->pathname_buffer;
filename = pdrive->filename_buffer;
rtfs_memset((byte *)&fileext[0],0,sizeof(fileext)); /* Zero fill fileext because we will not use it */
/* Get out the filename and d:parent */
if (!pc_parsepath(mompath,filename,fileext,name, CS_CHARSET_ARGS))
{
rtfs_set_errno(PEINVALIDPATH, __FILE__, __LINE__);
goto errex;
}
/* Save the pattern. we will need it in pc_gnext */
copybuff(statobj->pname, filename, FILENAMESIZE_BYTES);
copybuff(statobj->pext, fileext, 4);
/* Copy over the path. we will need it later */
copybuff(statobj->path, mompath, EMAXPATH_BYTES);
/* Find the file and init the structure */
statobj->pmom = (void *) pc_fndnode(mompath, CS_CHARSET_ARGS);
/* pc_fndnode will set errno */
if (statobj->pmom)
/* Found it. Check access permissions */
{
if(pc_isadir((DROBJ *)(statobj->pmom)))
{
#if (INCLUDE_REVERSEDIR)
/* Now find pattern in the directory */
if (statobj->search_backwards_if_magic == SEARCH_BACKWARDS_MAGIC_NUMBER)
statobj->pobj = (void *) pc_rget_inode(0, (DROBJ *)(statobj->pmom), filename, (byte*) fileext, GET_INODE_WILD, CS_CHARSET_ARGS);
else
#endif
statobj->pobj = (void *) pc_get_inode(0, (DROBJ *)(statobj->pmom), filename, (byte*) fileext, GET_INODE_WILD, CS_CHARSET_ARGS);
if (statobj->pobj)
{
/* And update the stat structure */
pc_upstat(statobj, CS_CHARSET_ARGS);
/* remember the drive number. used by gnext et al. */
statobj->driveno = driveno;
#if (INCLUDE_EXFATORFAT64)
if (statobj->search_backwards_if_magic!=SYS_SCAN_MAGIC_NUMBER) /* EXFAT system scan uses and then frees the finode at a higher layer */
#endif
{
pc_freei(((DROBJ *)(statobj->pobj))->finode); /* Release the current */
((DROBJ *)(statobj->pobj))->finode = 0;
}
statobj->drive_opencounter = pdrive->drive_opencounter;
ret_val = TRUE;
goto errex;
}
else
{
/* pc_gfirst: if statobj->pobj is 0 pc_get_inode() has set errno to PENOENT or
to an internal or IO error status
if PENOENT set we will clear errno */
if (get_errno() == PENOENT)
rtfs_clear_errno(); /* pc_gfirst: file not found in directory
set errno to zero and return FALSE */
}
}
else
rtfs_set_errno(PENOENT, __FILE__, __LINE__); /* pc_gfirst: Path not a directory, report not found */
}
/* If it gets here we had a problem ret_val is false */
if (statobj->pmom)
pc_freeobj((DROBJ *)statobj->pmom);
rtfs_memset((byte *) statobj,0,sizeof(*statobj));
errex:
pc_release_path_buffers(pdrive);
release_drive_mount(driveno);/* Release lock, unmount if aborted */
return(ret_val);
}
/****************************************************************************
PC_GNEXT - Get next entry in a directory that matches a pattern.
Description
Given a pointer to a DSTAT structure that has been set up by a call to
pc_gfirst(), search for the next match of the original pattern in the
original path. Return TRUE if found and update statobj for subsequent
calls to pc_gnext.
Returns
Returns TRUE if a match was found otherwise FALSE.
errno is set to one of the following
0 - No error
PEINVALIDPARMS - statobj argument is not valid
PENOENT - Not found, no match (normal termination of scan)
An ERTFS system error
****************************************************************************/
#if (INCLUDE_REVERSEDIR)
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_gprev_cs(DSTAT *statobj, int use_charset)
#else
BOOLEAN pc_gprev(DSTAT *statobj)
#endif
{
statobj->search_backwards_if_magic = SEARCH_BACKWARDS_MAGIC_NUMBER;
#if (INCLUDE_CS_UNICODE)
return pc_gnext_cs(statobj, use_charset);
#else
return pc_gnext(statobj);
#endif
}
#endif
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_gnext_cs(DSTAT *statobj, int use_charset)
#else
BOOLEAN pc_gnext(DSTAT *statobj)
#endif
{
DROBJ *nextobj;
DDRIVE *pdrive;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
/* see if the drive is still mounted. Do not use pmom et al. since they
may be purged */
if (!statobj || !statobj->pmom)
{
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__); /* pc_gnext: statobj is not valid */
return(FALSE);
}
pdrive = check_drive_by_number(statobj->driveno, TRUE);
if (!pdrive)
return(FALSE);
if (statobj->drive_opencounter != pdrive->drive_opencounter)
{
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__); /* pc_gnext: statobj is not valid */
release_drive_mount(statobj->driveno);/* Release lock, unmount if aborted */
return(FALSE);
}
rtfs_clear_errno(); /* po_gnext: clear error status */
#if (INCLUDE_REVERSEDIR)
/* Now find the next instance of pattern in the directory */
if (statobj->search_backwards_if_magic == SEARCH_BACKWARDS_MAGIC_NUMBER)
nextobj = pc_rget_inode((DROBJ *)(statobj->pobj), (DROBJ *)(statobj->pmom), statobj->pname, statobj->pext, GET_INODE_WILD, CS_CHARSET_ARGS);
else
#endif
nextobj = pc_get_inode((DROBJ *)(statobj->pobj), (DROBJ *)(statobj->pmom),
statobj->pname, statobj->pext, GET_INODE_WILD, CS_CHARSET_ARGS);
if (nextobj)
{
statobj->pobj = (void *)nextobj;
/* And update the stat structure */
pc_upstat(statobj, CS_CHARSET_ARGS);
#if (INCLUDE_EXFATORFAT64)
if (statobj->search_backwards_if_magic!=SYS_SCAN_MAGIC_NUMBER) /* EXFAT system scan uses and then frees the finode at a higher layer */
#endif
{
pc_freei(((DROBJ *)(statobj->pobj))->finode); /* Release the current */
((DROBJ *)(statobj->pobj))->finode = 0;
}
release_drive_mount(statobj->driveno);/* Release lock, unmount if aborted */
return(TRUE);
}
else
{
if (get_errno() == PENOENT)
rtfs_clear_errno(); /* get_inode: file not found in directory
set errno to zero and return FALSE */
/* pc_gnext: nextobj is 0 pc_get_inode() has set errno to PENOENT or to an internal or IO error status */
release_drive_mount(statobj->driveno);/* Release lock, unmount if aborted */
return(FALSE);
}
}
/***************************************************************************
PC_GDONE - Free internal resources used by pc_gnext and pc_gfirst.
Description
Given a pointer to a DSTAT structure that has been set up by a call to
pc_gfirst() free internal elements used by the statobj.
NOTE: You MUST call this function when done searching through a
directory.
Returns
Nothing
errno is set to one of the following
0 - No error
PEINVALIDPARMS - statobj argument is not valid
****************************************************************************/
void pc_gdone(DSTAT *statobj) /*__apifn__*/
{
DDRIVE *pdrive;
VOID_CHECK_MEM() /* Make sure memory is initted */
/* see if the drive is still mounted. Do not use pmom et al. since they
may be purged */
/* see if the drive is still mounted. Do not use pmom et al. since they
may be purged */
if (!statobj || !statobj->pmom)
{
return;
}
pdrive = check_drive_by_number(statobj->driveno, TRUE);
if (!pdrive)
return;
if (statobj->drive_opencounter != pdrive->drive_opencounter)
{
release_drive_mount(statobj->driveno);/* Release lock, unmount if aborted */
return;
}
if (statobj->pobj)
{
pc_freeobj((DROBJ *)statobj->pobj);
}
if (statobj->pmom)
pc_freeobj((DROBJ *)statobj->pmom);
release_drive_mount(statobj->driveno);/* Release lock, unmount if aborted */
rtfs_memset((byte *) statobj,0,sizeof(*statobj));
}
/****************************************************************************
PC_UPSTAT - Copy private information to public fields for a DSTAT struc.
Description
Given a pointer to a DSTAT structure that contains a pointer to an
initialized DROBJ structure, load the public elements of DSTAT with
name filesize, date of modification et al. (Called by pc_gfirst &
pc_gnext)
Returns
Nothing
****************************************************************************/
/* Copy internal stuf so the outside world can see it */
static void pc_upstat(DSTAT *statobj, int use_charset) /*__fn__*/
{
DROBJ *pobj;
FINODE *pi;
pobj = (DROBJ *)(statobj->pobj);
pi = pobj->finode;
copybuff( statobj->fname, pi->fname, 8);
statobj->fname[8] = 0;
copybuff( statobj->fext, pi->fext, 3);
statobj->fext[3] = 0;
/* put null termed 8.3 file.ext into statobj */
pc_cs_mfile((byte *)statobj->filename, (byte *)statobj->fname,
(byte *)statobj->fext, CS_CHARSET_NOT_UNICODE);
statobj->fattribute = pi->fattribute;
statobj->ftime = pi->ftime;
statobj->fdate = pi->fdate;
statobj->ctime = pi->ctime;
statobj->cdate = pi->cdate;
statobj->adate = pi->adate;
statobj->atime = pi->atime;
#if (INCLUDE_EXFATORFAT64)
if (ISEXFATORFAT64(pobj->pdrive))
{
statobj->fsize = M64LOWDW(pi->fsizeu.fsize64);
statobj->fsize_hi = M64HIGHDW(pi->fsizeu.fsize64);
statobj->fname[0] = 0;
statobj->fext[0] = 0;
}
else
#endif
{
statobj->fsize = pi->fsizeu.fsize;
statobj->fsize_hi = 0;
}
statobj->my_block = pi->my_block;
statobj->my_index = pi->my_index;
/* Get the lfn value for this object. If none available make
an ASCII or UNICODE copy of the short name in lfn */
if (!pc_get_lfn_filename(pobj, (byte *)statobj->lfname, use_charset))
{
statobj->lfname[0] = statobj->lfname[1] = 0;
pc_cs_mfileNT((byte *)statobj->lfname, (byte *)statobj->fname,
(byte *)statobj->fext, use_charset,pobj->finode->reservednt);
}
}

View File

@ -0,0 +1,179 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APIGREAD.C - Contains user api level source code.
The following routines are included:
pc_gread - Read bytes from file or directory in DSTAT
*/
#include "rtfs.h"
/****************************************************************************
PC_GREAD - Read bytes from file or directory in DSTAT
Description
Given a pointer to a DSTAT structure that has been set up by a call to
pc_gfirst(), or pc_gnext() read original path. Return TRUE if found and update statobj for subsequent
calls to pc_gnext.
Returns
Returns TRUE if a match was found otherwise FALSE.
errno is set to one of the following
0 - No error
PEINVALIDPARMS - statobj argument is not valid
PENOENT - Not found, no match (normal termination of scan)
An ERTFS system error
****************************************************************************/
BOOLEAN pc_gread(DSTAT *statobj, int blocks_to_read, byte *buffer, int *blocks_read) /*__apifn__*/
{
BOOLEAN ret_val;
DDRIVE *pdrive;
FINODE *pfi;
#if (INCLUDE_RTFS_PROPLUS)
REGION_FRAGMENT *pf = 0;
#endif
dword cluster_no;
int bytes_per_cluster,blocks_per_cluster,blocks_left;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
/* see if the drive is still mounted. */
if (!buffer || !blocks_read || !statobj || !statobj->pmom)
{
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__); /* pc_gnext: statobj is not valid */
return(FALSE);
}
pdrive = check_drive_by_number(statobj->driveno, TRUE);
if (!pdrive)
return(FALSE);
if (statobj->drive_opencounter != pdrive->drive_opencounter)
{
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__); /* pc_gnext: statobj is not valid */
release_drive_mount(statobj->driveno);/* Release lock, unmount if aborted */
return(FALSE);
}
rtfs_clear_errno(); /* po_gread: clear error status */
ret_val = TRUE;
#if (INCLUDE_EXFATORFAT64)
if (ISEXFATORFAT64(pdrive))
{
ret_val = pcexfat_gread(statobj, blocks_to_read, buffer, blocks_read);
release_drive_mount(statobj->driveno);/* Release lock, unmount if aborted */
return(ret_val);
}
#endif
*blocks_read = 0;
cluster_no = 0;
pfi = pc_scani(pdrive, statobj->my_block, statobj->my_index);
if (pfi)
{
cluster_no = pc_finode_cluster(pdrive, pfi);
#if (INCLUDE_RTFS_PROPLUS)
/* If it's an extended finode use the fragment list.. */
if (pfi->e.x)
{
if (pfi->operating_flags & FIOP_LOAD_AS_NEEDED)
{
llword offset;
offset.val32 = blocks_to_read << pdrive->drive_info.log2_bytespsec;
if (!load_efinode_fragments_until(pfi, offset))
ret_val = FALSE;
else
pf = pfi->e.x->pfirst_fragment;
}
else
pf = pfi->e.x->pfirst_fragment;
if (pf)
cluster_no = pf->start_location;
}
#endif
pc_freei(pfi);
}
else
{ /* No inode in the inode list. read the entry from disk */
BLKBUFF *pblk;
pblk = pc_read_blk(pdrive, statobj->my_block);
if (!pblk)
{
ret_val = FALSE;
}
else
{
FINODE scratch_finode;
DOSINODE *pi;
pi = (DOSINODE *) pblk->data;
pi += statobj->my_index;
pc_dos2inode (&scratch_finode, pi);
cluster_no = pc_finode_cluster(pdrive, &scratch_finode);
pc_release_buf(pblk);
}
}
blocks_per_cluster = pdrive->drive_info.secpalloc;
bytes_per_cluster = blocks_per_cluster << pdrive->drive_info.log2_bytespsec;
blocks_left = blocks_to_read;
while (cluster_no && blocks_left)
{
dword blockno;
int n_to_read;
n_to_read = blocks_per_cluster;
if (n_to_read > blocks_left)
n_to_read = blocks_left;
blockno = pc_cl2sector(pdrive,cluster_no);
if (!blockno || !block_devio_xfer(pdrive, blockno, buffer, n_to_read, TRUE))
{
ret_val = FALSE;
break;
}
*blocks_read += n_to_read;
blocks_left -= n_to_read;
if (!blocks_left)
break;
buffer += bytes_per_cluster;
#if (INCLUDE_RTFS_PROPLUS)
if (pf)
{
cluster_no += 1;
if (cluster_no > pf->end_location)
{
pf = pf->pnext;
if (pf)
cluster_no = pf->start_location;
else
cluster_no = 0;
}
}
else
#endif
{
dword next_cluster;
int end_of_chain;
end_of_chain = 0;
if (!fatop_get_frag(pdrive, 0, 0, cluster_no, &next_cluster, 1, &end_of_chain))
{
ret_val = FALSE;
break;
}
if (end_of_chain)
cluster_no = 0;
else
cluster_no = next_cluster;
}
}
release_drive_mount(statobj->driveno);/* Release lock, unmount if aborted */
return(ret_val);
}

428
rtfscommon/source/apiinfo.c Normal file
View File

@ -0,0 +1,428 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APIINFO.C - Contains user api level source code.
The following routines are included:
pc_set_default_drive - Set the default drive number.
pc_free - Calculate and return the free space on a disk.
pc_isdir - Determine if a path is a directory.
pc_isvol - Determine if a path is a volume
pc_get_attributes - Get File Attributes
pc_getdfltdrvno - Get the default drive number.
*/
#include "rtfs.h"
/***************************************************************************
PC_SET_DEFAULT_DRIVE - Set the current default drive.
Description
Use this function to set the current default drive that will be used
when a path specifier does not contain a drive specifier.
Note: The default default is zero (drive A:)
Returns
Return FALSE if the drive is out of range.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID - Driveno is incorrect
****************************************************************************/
/* Set the currently stored default drive */
BOOLEAN pc_set_default_drive(byte *drive) /*__apifn__*/
{
int drive_no;
rtfs_clear_errno(); /* pc_set_default_drive: clear error status */
/* get drive no */
drive_no = pc_parse_raw_drive(drive, CS_CHARSET_NOT_UNICODE);
if ( ( drive_no < 0) || !pc_validate_driveno(drive_no))
{
rtfs_set_errno(PEINVALIDDRIVEID, __FILE__, __LINE__);/* pc_set_default_drive: invalid argument */
return(FALSE);
}
else
{
rtfs_get_system_user()->dfltdrv = drive_no+1;
return(TRUE);
}
}
/****************************************************************************
PC_FREE - Count the number of free bytes remaining on a disk
Description
Given a path containing a valid drive specifier count the number
of free bytes on the drive. The function also takes two additional
argument that point to location that will be loaded with the
total number of blocks on the drive and the total number of
free clusters
Returns
The number of free bytes or zero if the drive is full, -1 if not open,
or out of range.
dword *blocks_total - Contains the total block count
dword *blocks_free - Contain the total count of free blocks.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID - Driveno is incorrect
An ERTFS system error
*****************************************************************************/
/* RTFS Pro version of pc_free returns long.. not a good solution */
long pc_free(byte *path, dword *blocks_total, dword *blocks_free) /*__apifn__*/
{
if (!pc_blocks_free(path, blocks_total, blocks_free))
return(-1);
else
return((long)(*blocks_free * pc_sector_size(path)));
}
/* Return # blocks free on a drive */
BOOLEAN pc_blocks_free(byte *path, dword *blocks_total, dword *blocks_free) /*__apifn__*/
{
int driveno;
DDRIVE *pdr;
BOOLEAN ret_val;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
rtfs_clear_errno(); /* po_free: clear error status */
/* assume failure to start */
ret_val = FALSE;
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(path, CS_CHARSET_NOT_UNICODE);
/* if error check_drive errno was set by check_drive */
if (driveno >= 0)
{
pdr = pc_drno2dr(driveno);
if (!pdr)
{
rtfs_set_errno(PEINVALIDDRIVEID, __FILE__, __LINE__); /* pc_free: no valid drive present */
}
else
{
*blocks_free = pdr->drive_info.known_free_clusters;
*blocks_free *= pdr->drive_info.secpalloc; /* Size of each fat */
*blocks_total = pdr->drive_info.maxfindex - 1; /* Number of entries in the fat */
*blocks_total *= pdr->drive_info.secpalloc; /* Size of each fat */
/* Return number of free sectors */
ret_val = TRUE;
}
release_drive_mount(driveno);/* Release lock, unmount if aborted */
}
return(ret_val);
}
/*****************************************************************************
PC_ISDIR - Test if a path name is a directory
Description
Test to see if a path specification ends at a subdirectory or a
file.
Note: \ is a directory.
Returns
Returns TRUE if it is a directory.
****************************************************************************/
#define ISDIR 1
#define ISVOL 2
static BOOLEAN pc_is(int op, byte *path, int use_charset) /*__fn__*/
{
DROBJ *pobj;
BOOLEAN ret_val = FALSE;
int driveno;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
rtfs_clear_errno(); /* pc_isdir/pc_isvol: clear errno */
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(path, use_charset);
/* if check_drive failed errno was set by check_drive */
if (driveno >= 0)
{
pobj = pc_fndnode(path, use_charset);
/* pc_isdir/pc_isvol: if pc_fndnode fails it will set errno */
if (pobj)
{
if (op == ISDIR)
ret_val = pc_isadir(pobj);
else if (op == ISVOL)
ret_val = pc_isavol(pobj);
pc_freeobj(pobj);
}
release_drive_mount(driveno);/* Release lock, unmount if aborted */
}
return (ret_val);
}
/*****************************************************************************
PC_ISDIR - Test if a path name is a directory
Description
Test to see if a path specification ends at a subdirectory.
Returns
Returns TRUE if it is a directory.
errno is set to one of the following
0 - No error
PENOENT - Path not found
An ERTFS system error
****************************************************************************/
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_isdir_cs(byte *path, int use_charset) /*__apifn__*/
{
return(pc_is(ISDIR, path,CS_CHARSET_ARGS));
}
#else
BOOLEAN pc_isdir(byte *path) /*__apifn__*/
{
return(pc_is(ISDIR, path,CS_CHARSET_ARGS));
}
#endif
/*****************************************************************************
PC_ISVOL - Test if a path name is a volume entry
Description
Test to see if a path specification ends at a volume label
Returns
Returns TRUE if it is a volume
errno is set to one of the following
0 - No error
PENOENT - Path not found
An ERTFS system error
****************************************************************************/
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_isvol_cs(byte *path, int use_charset) /*__apifn__*/
{
return(pc_is(ISVOL, path,CS_CHARSET_ARGS));
}
#else
BOOLEAN pc_isvol(byte *path) /*__apifn__*/
{
return(pc_is(ISVOL, path,CS_CHARSET_ARGS));
}
#endif
/*****************************************************************************
pc_get_attributes - Get File Attributes
Description
Given a file or directory name return the directory entry attributes
associated with the entry.
The following values are returned:
BIT Nemonic
0 ARDONLY
1 AHIDDEN
2 ASYSTEM
3 AVOLUME
4 ADIRENT
5 ARCHIVE
6-7 Reserved
Returns
Returns TRUE if successful otherwise it returns FALSE
errno is set to one of the following
0 - No error
PENOENT - Path not found
An ERTFS system error
****************************************************************************/
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_get_attributes_cs(byte *path, byte *p_return, int use_charset) /*__apifn__*/
#else
BOOLEAN pc_get_attributes(byte *path, byte *p_return) /*__apifn__*/
#endif
{
DROBJ *pobj;
BOOLEAN ret_val = FALSE;
int driveno;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
rtfs_clear_errno(); /* pc_get_attributes: clear errno */
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(path, CS_CHARSET_ARGS);
if (driveno < 0)
{
/* pc_get_attributes: if check_drive failed errno was set by check_drive */
return (FALSE);
}
pobj = pc_fndnode(path, CS_CHARSET_ARGS);
/* if pc_fndnode fails it will set errno */
if (pobj)
{
if ( pc_isroot(pobj))
*p_return = ADIRENT;
else
*p_return = pobj->finode->fattribute;
pc_freeobj(pobj);
ret_val = TRUE;
}
release_drive_mount(driveno);/* Release lock, unmount if aborted */
return (ret_val);
}
/***************************************************************************
PC_GETDFLTDRVNO - Return the current default drive.
Description
Use this function to get the current default drive when a path specifier
does not contain a drive specifier.
see also pc_setdfltdrvno()
Returns
Return the current default drive.
pc_getdfltdrvno() does not set errno
*****************************************************************************/
/* Return the currently stored default drive */
#if (INCLUDE_CS_UNICODE)
int pc_get_default_drive_cs(byte *drive_name, int use_charset) /*__apifn__*/
#else
int pc_get_default_drive(byte *drive_name) /*__apifn__*/
#endif
{
int drive_number;
CHECK_MEM(int, 0) /* Make sure memory is initted */
if (!rtfs_get_system_user()->dfltdrv)
{
drive_number = prtfs_cfg->default_drive_id;
if (drive_number) /* Stored a 1 - 27, zero means not set */
drive_number -= 1;
}
else
drive_number = rtfs_get_system_user()->dfltdrv-1;
if (drive_name)
pc_drno_to_drname(drive_number, drive_name, CS_CHARSET_ARGS);
return(drive_number);
}
/* PC_CLUSTER_SIZE - Return the number of bytes per cluster for a drive
Description
This function will return the cluster size mounted device
named in the argument.
Returns
The cluster size or zero if the device is not mounted.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID- Drive name is invalid
*****************************************************************************/
static BOOLEAN _pc_xxxxx_size(byte *drive, int *pclustersize, int *psectorsize);
int pc_sector_size(byte *drive) /*__apifn__*/
{
int sectorsize, clustersize;
if (!_pc_xxxxx_size(drive, &clustersize, &sectorsize))
sectorsize = 0;
return(sectorsize);
}
int pc_cluster_size(byte *drive) /*__apifn__*/
{
int clustersize, sectorsize;
if (!_pc_xxxxx_size(drive, &clustersize, &sectorsize))
clustersize = 0;
return(clustersize);
}
static BOOLEAN _pc_xxxxx_size(byte *drive, int *pclustersize, int *psectorsize)
{
int driveno;
DDRIVE *pdrive;
CHECK_MEM(int, 0) /* Make sure memory is initted */
rtfs_clear_errno(); /* pc_cluster_size: clear error status */
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(drive, CS_CHARSET_NOT_UNICODE);
if (driveno < 0)
{
/* errno was set by check_drive */
return(FALSE);
}
pdrive = pc_drno2dr(driveno);
*pclustersize = pdrive->drive_info.bytespcluster;
*psectorsize = pdrive->drive_info.bytespsector;
release_drive_mount(driveno);/* Release lock, unmount if aborted */
return(TRUE);
}
void pc_drno_to_drname(int driveno, byte *pdrive_name, int use_charset)
{
byte c,*p;
p = pdrive_name;
c = (byte) ('A' + driveno);
CS_OP_ASSIGN_ASCII(p,c, use_charset);
CS_OP_INC_PTR(p, use_charset);
CS_OP_ASSIGN_ASCII(p,':', use_charset);
CS_OP_INC_PTR(p, use_charset);
CS_OP_TERM_STRING(p, use_charset);
}
int pc_drname_to_drno(byte *drive_name, int use_charset)
{
return(pc_parse_raw_drive(drive_name, use_charset));
}
int pc_fd_to_driveno(int fd,byte *pdrive_name, int use_charset)
{
PC_FILE *pfile;
int driveno;
pfile = pc_fd2file(fd, 0);
if (pfile && pfile->pobj)
{
driveno = pfile->pobj->pdrive->driveno;
rtfs_release_media_and_buffers(driveno);
if (pdrive_name)
pc_drno_to_drname(driveno, pdrive_name, use_charset);
}
else
{
driveno = -1;
if (pdrive_name)
{
*pdrive_name = 0;
*(pdrive_name+1) = 0;
}
}
return(driveno);
}

View File

@ -0,0 +1,53 @@
/*****************************************************************************
*Filename: APIINIT.C - RTFS Inititialization and device attach
*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS inc, 1993 - 2006
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
#include "rtfs.h"
/* Initialize ERTFS and optionally attach default device drivers.
This routine must be called before other ERTFS API routines are used.
In the default environment this routine is called by rtfs_run(),
(aiprun.c) the top level entry point for ERTFS provided applications.
*/
BOOLEAN pc_ertfs_init(void)
{
struct rtfs_init_resource_reply system_configuration;
/* Call the user configuration manager */
/* Let the callback layer initialize itself if it needs to */
rtfs_sys_callback(RTFS_CBS_INIT,0);
rtfs_memset(&system_configuration, 0, sizeof(system_configuration));
rtfs_init_configuration(&system_configuration);
/* Set up the rtfs configuration structure from the information in the the user configuration block
dynamically allocate memory if user requested it */
if (!rtfs_dynamic_init_configuration(&system_configuration))
return(FALSE);
/* Call the memory and RTOS resource initiatilization function */
if (!pc_memory_init())
return(FALSE);
#if (INCLUDE_FAILSAFE_RUNTIME)
return(pc_failsafe_init());
#else
return(TRUE);
#endif
}
void print_device_names(void)
{
RTFS_PRINT_STRING_1((byte *)"ERTFS Device List",PRFLG_NL); /* "ERTFS Device List" */
RTFS_PRINT_STRING_1((byte *)"=================",PRFLG_NL); /* "=================" */
RTFS_PRINT_STRING_1((byte *)"Name Logging Disabled",PRFLG_NL); /* "Name Logging Disabled" */
}

View File

@ -0,0 +1,313 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APIMKDIR.C - Contains user api level source code.
The following routines are included:
pc_mkdir - Create a directory.
pc_rmdir - Delete a directory.
*/
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
/***************************************************************************
PC_MKDIR - Create a directory.
Description
Create a sudirectory in the path specified by name. Fails if a
file or directory of the same name already exists or if the path
is not found.
Returns
Returns TRUE if it was able to create the directory, otherwise
it returns FALSE.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID- Drive component is invalid
PEINVALIDPATH - Path specified badly formed.
PENOENT - Path to new directory not found
PEEXIST - File or directory of this name already exists
An ERTFS system error
****************************************************************************/
#if(INCLUDE_CS_UNICODE)
BOOLEAN pc_mkdir_cs(byte *name, int use_charset)
#else
BOOLEAN pc_mkdir(byte *name)
#endif
{
DROBJ *pobj;
DROBJ *parent_obj;
byte *path;
byte *filename;
byte fileext[4];
BOOLEAN ret_val;
int driveno;
DDRIVE *pdrive;
int p_set_errno;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
parent_obj = 0;
pobj = 0;
p_set_errno = 0;
ret_val = FALSE;
rtfs_clear_errno(); /* pc_mkdir: clear error status */
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(name, CS_CHARSET_ARGS);
if (driveno < 0)
{
/* errno was set by check_drive */
return(FALSE);
}
pdrive = pc_drno2dr(driveno);
/* Allocate scratch buffers in the DRIVE structure. */
if (!pc_alloc_path_buffers(pdrive))
goto errex;
path = pdrive->pathname_buffer;
filename = pdrive->filename_buffer;
/* Get out the filename and d:parent */
if (!pc_parsepath(path,filename,fileext,name, CS_CHARSET_ARGS))
{
p_set_errno = PEINVALIDPATH;
/*rtfs_set_errno(PEINVALIDPATH, __FILE__, __LINE__)); */
goto errex;
}
/* Find the parent and make sure it is a directory \ */
/* pc_fndnode set errno */
parent_obj = pc_fndnode(path, CS_CHARSET_ARGS);
if (!parent_obj)
goto errex;
/* Lock the parent */
if (!pc_isadir(parent_obj) || pc_isavol(parent_obj))
{
p_set_errno = PENOENT; /* Path is not a directory */
/*rtfs_set_errno(PENOENT, __FILE__, __LINE__); */
goto errex;
}
/* Fail if the directory exists */
pobj = pc_get_inode(0, parent_obj, filename,(byte*) fileext, GET_INODE_MATCH, CS_CHARSET_ARGS);
if (pobj)
{
p_set_errno = PEEXIST; /* Exclusive fail */
/*rtfs_set_errno(PEEXIST, __FILE__, __LINE__); */
goto errex;
}
else
{
if (get_errno() != PENOENT) /* If pobj is NULL we abort on abnormal errors */
goto errex;
rtfs_clear_errno(); /* pc_mkdir: clear PENOENT error status */
pobj = pc_mknode( parent_obj,filename, fileext, ADIRENT, 0, CS_CHARSET_ARGS);
if (pobj)
{
p_set_errno = 0;
ret_val = TRUE;
}
else
{
/* pc_mknode has set errno */
goto errex;
}
}
errex:
if (pobj)
pc_freeobj(pobj);
if (parent_obj)
{
pc_freeobj(parent_obj);
}
pc_release_path_buffers(pdrive);
if (p_set_errno)
rtfs_set_errno(p_set_errno, __FILE__, __LINE__);
if (!release_drive_mount_write(driveno))/* Release lock, unmount if aborted */
ret_val = FALSE;
return(ret_val);
}
/****************************************************************************
PC_RMDIR - Delete a directory.
Description
Delete the directory specified in name. Fail if name is not a directory,
is read only or contains more than the entries . and ..
Returns
Returns TRUE if the directory was successfully removed.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID- Drive component is invalid
PEINVALIDPATH - Path specified badly formed.
PENOENT - Directory not found
PEACCESS - Directory is in use or is read only
An ERTFS system error
*****************************************************************************/
/* Remove a directory */
#if(INCLUDE_CS_UNICODE)
BOOLEAN pc_rmdir_cs(byte *name, int use_charset)
#else
BOOLEAN pc_rmdir(byte *name)
#endif
{
DROBJ *parent_obj;
DROBJ *pobj;
DROBJ *pchild;
BOOLEAN ret_val;
byte *path;
byte *filename;
byte fileext[4];
int driveno;
DDRIVE *pdrive;
int p_set_errno;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
parent_obj = 0;
pchild = 0;
pobj = 0;
rtfs_clear_errno(); /* pc_rmdir: clear error status */
ret_val = FALSE;
p_set_errno = 0;
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(name, CS_CHARSET_ARGS);
if (driveno < 0)
{
/* errno was set by check_drive */
return(FALSE);
}
pdrive = pc_drno2dr(driveno);
/* Allocate scratch buffers in the DRIVE structure. */
if (!pc_alloc_path_buffers(pdrive))
goto errex;
path = pdrive->pathname_buffer;
filename = pdrive->filename_buffer;
/* Get out the filename and d:parent */
if (!pc_parsepath(path,filename,fileext,name, CS_CHARSET_ARGS))
{
p_set_errno = PEINVALIDPATH;
/*rtfs_set_errno( PEINVALIDPATH, __FILE__, __LINE__); */
goto errex;
}
/* Don't allow removal of . or .. PEACCES (by definition we are busy */
if (pc_isdot(filename,fileext) || pc_isdotdot(filename,fileext))
{
p_set_errno = PEACCES;
/*rtfs_set_errno(PEACCESS, __FILE__, __LINE__); */
goto errex;
}
/* Find the parent and make sure it is a directory \ */
parent_obj = pc_fndnode(path,CS_CHARSET_ARGS);
if (!parent_obj)
{
goto errex; /* pc_fndnode set errno */
}
if (!pc_isadir(parent_obj))
{
p_set_errno = PEACCES;
/*rtfs_set_errno(PEACCESS, __FILE__, __LINE__); */
goto errex;
}
/* Find the file and init the structure */
pobj = pc_get_inode(0, parent_obj, filename, (byte*)fileext,GET_INODE_MATCH, CS_CHARSET_ARGS);
if (!pobj)
{
/* pc_get_inode() has set errno to PENOENT or to an internal or IO error status */
goto errex;
}
if ( !pc_isadir(pobj) || (pobj->finode->opencount > 1) ||
(pobj->finode->fattribute & ARDONLY ))
{
p_set_errno = PEACCES;
/*rtfs_set_errno(PEACCESS, __FILE__, __LINE__); */
goto errex;
}
/* Search through the directory. look at all files */
/* Any file that is not . or .. is a problem */
/* Call pc_get_inode with 0 to give us an obj */
pchild = pc_get_inode(0, pobj, 0, 0, GET_INODE_STAR, CS_CHARSET_ARGS);
if (pchild)
{
do
{
if (!(pc_isdot(pchild->finode->fname, pchild->finode->fext) ) )
if (!(pc_isdotdot(pchild->finode->fname, pchild->finode->fext) ) )
{
p_set_errno = PEACCES;
/*rtfs_set_errno(PEACCESS, __FILE__, __LINE__); */
ret_val = FALSE;
goto errex;
}
}
while (pc_get_inode(pchild, pobj, 0, 0, GET_INODE_STAR, CS_CHARSET_ARGS));
}
/* If either of the above calls to pc_get_inode() failed due to
an error other than PENOENT then we have an error condition
Continue if the error was PEINVALIDCLUSTER that means that
the chain is corrupted. In this case proceed to delete the
directory too
*/
p_set_errno = get_errno();
if (!p_set_errno || (p_set_errno == PENOENT)) /* normal scan termination */
{
p_set_errno = 0;
rtfs_clear_errno(); /* Clear errno so others can use it */
ret_val = pc_rmnode(pobj);
}
else if (p_set_errno == PEINVALIDCLUSTER) /* termination because of bad
cluster */
{
/* Clear p_set_errno, errno is already PEINVALIDCLUSTER, if rmnode
overwrites errno that will be the value, otherwise rmnode and
children will set errno to another value */
p_set_errno = 0;
pc_rmnode(pobj);
ret_val = FALSE;
}
else /* Scan terminated due to IO error or internal error */
ret_val = FALSE;
errex:
if (pchild)
pc_freeobj(pchild);
if (pobj)
pc_freeobj(pobj);
if (parent_obj)
pc_freeobj(parent_obj);
if (ret_val)
rtfs_clear_errno();
else if (p_set_errno)
rtfs_set_errno(p_set_errno, __FILE__, __LINE__);
pc_release_path_buffers(pdrive);
if (!release_drive_mount_write(driveno))/* Release lock, unmount if aborted */
ret_val = FALSE;
return(ret_val);
}
#endif /* Exclude from build if read only */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,281 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 2000
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
/***************************************************************************
PC_PARTITION_MEDIA - Write partition table
BOOLEAN pc_partition_media(byte *path, struct mbr_specification *pmbrspec)
Description
Given a drive ID and one or more mbr specifications, write the information in the
mbr specification to the media.
If the underlying device driver provides dynamic partitioning instructions then pmbrspec
is ignored and is provided by the device driver.
Typically one specification structure is provided. This is used to initialize the primary boot record.
struct mbr_specification {
int device_mbr_count - Only used in the first specification. This must contain 1 if there is only one
partition table. If extended partitons required this must be 1 plus the
number of EBR (extended boot record) specifications to follow
dword mbr_sector_location - Location of this primary or extended boot record. (0 for the primary)
- An array of four structures specifying the filed for this record
struct mbr_entry_specification entry_specifications[4];
where (struct mbr_entry_specification) contains the following fields:
dword partition_start;
dword partition_size;
byte partition_type;
byte partition_boot;
If extended partitions are desired then one additional mbr_specification structure is required per virtual
volume in the extended partition.
If the user is providing the specifications they must be provided in a contiguous array pointed to by pmbrspec.
If the device driver is dynamically providing the specifications it will be called once for each specification it
needs, passing the index number as an argument.
Returns
Returns TRUE if it was able to perform the operation otherwise FALSE.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID- Drive component is invalid
PEINVALIDPARMS - Inconsistent or missing parameters
PEIOERRORWRITE - Error writing partition table
An ERTFS system error
****************************************************************************/
static BOOLEAN partition_provided(DDRIVE *pdr, DEV_GEOMETRY *pgeometry,struct mbr_specification *pmbrspec);
BOOLEAN _pc_get_media_parms(DDRIVE *pdr, PDEV_GEOMETRY pgeometry);
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_partition_media_cs(byte *path , struct mbr_specification *pmbrspec, int use_charset)
#else
BOOLEAN pc_partition_media(byte *path, struct mbr_specification *pmbrspec)
#endif
{
DEV_GEOMETRY geometry;
DDRIVE *pdr;
void *devhandle;
BOOLEAN ret_val;
CHECK_MEM(BOOLEAN, 0)
rtfs_clear_errno(); /* pc_partition_media: clear error status */
if (!path || !pmbrspec) /* Make sure it s a valid drive number */
{
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__);
return(FALSE);
}
pdr = check_drive_by_name(path, CS_CHARSET_ARGS);
if (!pdr)
return(FALSE);
devhandle = pdr->pmedia_info->devhandle;
/* Get media size, we ignore the size values but use heads and sectors per track. _pc_get_media_parms returns valid
values (either real or synthesized) */
if (!_pc_get_media_parms(pdr, &geometry))
ret_val = FALSE;
else
ret_val = partition_provided(pdr,&geometry,pmbrspec);
rtfs_release_media_and_buffers(pdr->driveno);
if (devhandle) /* re-mount the media, re-read partition tables */
pc_rtfs_media_remount(devhandle);
return(ret_val);
}
static BOOLEAN pc_write_mbr_spec(DDRIVE *pdr, PDEV_GEOMETRY pgeometry, struct mbr_specification *pspec);
/* static BOOLEAN partition_provided(DDRIVE *pdr, DEV_GEOMETRY *pgeometry,struct mbr_specification *pmbrspec)
Format and write master boot record and any extended boot records.
The mbr specifications were provided by the user
*/
static BOOLEAN partition_provided(DDRIVE *pdr, DEV_GEOMETRY *pgeometry,struct mbr_specification *pmbrspec)
{
if (!pmbrspec)
{
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__);
return(FALSE);
}
if (!pmbrspec->device_mbr_count) /* device_mbr_count == 0 is a paramater option to clear the MBR */
return(pc_write_mbr_spec(pdr, pgeometry, 0));
else
{ /* primary mbr specified */
if (!pc_write_mbr_spec(pdr, pgeometry, pmbrspec))
return(FALSE);
/* Check if more mbrs to follow, if this is true then the caller is partitioning the
drive with extended partitions. Each of these additional mbrs must reside inside an extended partition */
if (pmbrspec->device_mbr_count > 1)
{
int extended_mbr_count, mbr_index;
extended_mbr_count = pmbrspec->device_mbr_count-1;
pmbrspec++;
for (mbr_index = 1; mbr_index <= extended_mbr_count; mbr_index++, pmbrspec++)
{ /* write extended mbrs */
if (!pc_write_mbr_spec(pdr, pgeometry, pmbrspec))
return(FALSE);
}
}
}
return(TRUE);
}
static word pack_cylinder_field(word cyl, word sec);
static word _lba_to_cylinder(dword lba_val, PDEV_GEOMETRY pgeometry);
static void mbr_entry_specification_to_mbr(byte *ptable,PDEV_GEOMETRY pgeometry, struct mbr_specification *pspec);
static BOOLEAN pc_write_mbr_spec(DDRIVE *pdr, PDEV_GEOMETRY pgeometry, struct mbr_specification *pspec)
{
BLKBUFF *pscratch;
BLKBUFF bbuf_scratch; /* Used by pc_sys_sector build a buffer structure with core from the driver level */
BOOLEAN ret_val;
dword mbr_sector_location;
/* Grab some working space - pass the drive parameter so it allocates a sector buffer */
pscratch = pc_sys_sector(pdr,&bbuf_scratch);
if (!pscratch)
return(FALSE); /* pc_scratch_blk set errno */
ret_val = FALSE;
rtfs_memset(pscratch->data, 0, pgeometry->bytespsector);
/* Now copy the partition information into the buffer */
/* The info starts at buf[1be] */
if (pgeometry && pspec) /* if they are zero just clear the partition table */
{
mbr_entry_specification_to_mbr((pscratch->data + 0x1be), pgeometry, pspec);
mbr_sector_location = pspec->mbr_sector_location;
#if (INCLUDE_WINDEV)
if (pdr->driveno==('P'-'A')) /* P: is the host drive */
{
rtfs_print_one_string((byte *)"INCLUDE_WINDEV is enabled", PRFLG_NL);
rtfs_print_one_string((byte*)"Use private boot signature, call hackwin7 to make the volume accessable on windows", PRFLG_NL);
fr_WORD((pscratch->data + 510), 0xAA66);
}
#endif
}
else
mbr_sector_location = 0; /* Clearing the MBR. mbr_specification is not valid */
/* write to pspec->mbr_sector_location */
if (raw_devio_xfer(pdr, mbr_sector_location, pscratch->data, 1, TRUE, FALSE))
ret_val = TRUE;
else
{
if (!get_errno())
rtfs_set_errno(PEIOERRORWRITE, __FILE__, __LINE__); /* pc_partition_media: write failed */
}
pc_free_sys_sector(pscratch);
return(ret_val);
}
static word pack_cylinder_field(word cyl, word sec)
{
word utemp, utemp2;
utemp = (word)((cyl & 0xff) << 8); /* Low 8 bit to hi bite */
utemp2 = (word)((cyl >> 2) & 0xc0); /* Hi 2 bits to bits 6 + 7 */
utemp |= utemp2;
utemp |= sec;
return(utemp);
}
/* Given a 32 bit sector address, divide it by (heads * secptrack) to convert it to the cylinder number.
If the result is > 1023, truncate it to 1023.
The value will be correct if "lba_val" is an exact multiple of (heads * secptrack), and <= 1023, otherwise it won't */
static word _lba_to_cylinder(dword lba_val, PDEV_GEOMETRY pgeometry)
{
dword ltemp;
if (pgeometry->dev_geometry_heads == 0 || pgeometry->dev_geometry_secptrack == 0) /* Won't happen */
ltemp = 1023;
else
{
ltemp = lba_val;
ltemp /= pgeometry->dev_geometry_heads;
ltemp /= pgeometry->dev_geometry_secptrack;
if (ltemp > 1023)
ltemp = 1023;
}
return((word) (ltemp & 0xffff) );
}
/* Convert an lba value to hcn.
cyl is between 1 and 123
sec is the same as in the geomerty stucture (1 <= sec <= 63)_
head is between the same as in the geomerty stucture (0 <= head <= 255)_
Note: sec and head will always be correct. cyl will be truncated to 1023 if sector is too
large to represent as (1023 * 63 * 255)
*/
static void _lba_to_chs(dword sector, PDEV_GEOMETRY pgeometry, word *cyl, word *sec, byte *head)
{
*cyl = _lba_to_cylinder(sector, pgeometry);
*sec = (word) (pgeometry->dev_geometry_secptrack & 0x3f);
*head = (byte) (pgeometry->dev_geometry_heads & 0xff);
}
static void mbr_entry_specification_to_mbr(byte *ptable,PDEV_GEOMETRY pgeometry, struct mbr_specification *pspec)
{
int i;
word cyl, sec;
byte head;
byte *pentry;
/* The table has four 16 bit partition table entries followed by the signature
Each entry in the table has the followin fields
byte Name width
0 boot 1
1 s_head 1
2 s_cyl 2
4 p_typ 1
5 e_head 1
6 e_cyl; 2
8 r_sec 4
12 p_size 4
*/
pentry = ptable;
for(i = 0; i < 4; i++)
{
if (pspec->entry_specifications[i].partition_size)
{
*pentry = pspec->entry_specifications[i].partition_boot;
/* calculate valid values for starting cyl, sec. head */
_lba_to_chs(pspec->entry_specifications[i].partition_start, pgeometry, &cyl, &sec, &head);
*(pentry+1) = head;
fr_WORD((byte *)(pentry+2), pack_cylinder_field(cyl, sec));
*(pentry+4) = pspec->entry_specifications[i].partition_type;
/* calculate partition end and valid values for ending cyl, sec. head */
{ dword partition_end;
partition_end = pspec->entry_specifications[i].partition_start + pspec->entry_specifications[i].partition_size - 1;
_lba_to_chs(partition_end, pgeometry, &cyl, &sec, &head);
}
*(pentry+5) = head;
fr_WORD(pentry+6, pack_cylinder_field(cyl, sec));
fr_DWORD(pentry+8, pspec->entry_specifications[i].partition_start);
fr_DWORD(pentry+12, pspec->entry_specifications[i].partition_size);
}
pentry += 16;
}
/* Now for the signature */
fr_WORD(ptable+64, 0xAA55);
}
#endif /* Exclude from build if read only */

3614
rtfscommon/source/apiregrs.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,95 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APISETATTR.C - Contains pc_set_attributes function */
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
/*****************************************************************************
pc_set_attributes - Set File Attributes
Description
Given a file or directory name return set directory entry attributes
associated with the entry.
The following values may be set:
BIT Nemonic
0 ARDONLY
1 AHIDDEN
2 ASYSTEM
5 ARCHIVE
Note: bits 3 & 4 (AVOLUME,ADIRENT) may not be changed.
Returns
Returns TRUE if successful otherwise it returns FALSE.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID- Drive component is invalid
PEINVALIDPATH - Path specified badly formed.
PENOENT - Path not found
PEACCESS - Object is read only
PEINVALIDPARMS - attribute argument is invalid
An ERTFS system error
****************************************************************************/
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_set_attributes_cs(byte *path, byte attributes, int use_charset)
#else
BOOLEAN pc_set_attributes(byte *path, byte attributes)
#endif
{
DROBJ *pobj;
BOOLEAN ret_val;
int driveno;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
rtfs_clear_errno(); /* pc_set_attributes: clear error status */
if ((attributes&(0x40|0x80)) !=0 ) /* Illegal */
{
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__);
/*rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__); */
return(FALSE);
}
driveno = check_drive_name_mount(path, CS_CHARSET_ARGS);
if (driveno < 0)
{ /* errno was set by check_drive */
return (FALSE);
}
ret_val = FALSE;
/* pc_fndnode will set errno */
pobj = pc_fndnode(path, CS_CHARSET_ARGS);
if (pobj)
{
/* Change the attributes if legal */
if (
(attributes & (AVOLUME|ADIRENT)) == /* Still same type */
(pobj->finode->fattribute & (AVOLUME|ADIRENT)))
{
pobj->finode->fattribute = attributes;
/* Overwrite the existing inode. Do not set archive/date */
/* pc_update_inode() will set errno */
ret_val = pc_update_inode(pobj, FALSE, 0);
}
else
rtfs_set_errno(PEACCES, __FILE__, __LINE__);
/*rtfs_set_errno(PEACCES, __FILE__, __LINE__); */
pc_freeobj(pobj);
}
if (!release_drive_mount_write(driveno))/* Release lock, unmount if aborted */
ret_val = FALSE;
return (ret_val);
}
#endif /* Exclude from build if read only */

View File

@ -0,0 +1,353 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APISETVOL.C - Contains user api level source code.
The following routines are included:
pc_set_volume - Set Volume label.
pc_get_volume - Retrieve Volume label.
*/
#include "rtfs.h"
static DROBJ *pc_find_volume(DROBJ *proot_obj);
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
/***************************************************************************
pc_set_volume - Set Volume label.
Description
BOOLEAN pc_set_volume(byte *drive_id, byte *volume_label)
Create a volume label or rename the current volume label.
The volume label is a directory entry in the root directory of the volume.
Returns
Returns TRUE if it was able to create or chenge the volume label.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID- Drive component is invalid
PEINVALIDPARMS - The label must contain only valid short file name characters. Lower case characters are converted to upper case.
An ERTFS system error
****************************************************************************/
static void pc_cp_volume_to8dot3(byte *to, byte *from);
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_set_volume_cs(byte *driveid, byte *volume_label,int use_charset)
#else
BOOLEAN pc_set_volume(byte *driveid, byte *volume_label)
#endif
{
DROBJ *pobj, *root_obj;
byte *path;
byte *filename;
byte fileext[4];
BOOLEAN ret_val;
int driveno;
DDRIVE *pdrive;
int p_set_errno;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
root_obj = 0;
pobj = 0;
p_set_errno = 0;
ret_val = FALSE;
rtfs_clear_errno(); /* pc_mkdir: clear error status */
if (!volume_label)
{
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__);
return(FALSE);
}
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(driveid, CS_CHARSET_ARGS);
if (driveno < 0)
{
/* errno was set by check_drive */
return(FALSE);
}
pdrive = pc_drno2dr(driveno);
#if (INCLUDE_EXFATORFAT64)
if (ISEXFATORFAT64(pdrive))
{
ret_val = pcexfat_set_volume(pdrive, volume_label,CS_CHARSET_ARGS);
release_drive_mount(driveno);/* Release lock, unmount if aborted */
return(ret_val);
}
#endif
/* Allocate scratch buffers in the DRIVE structure. */
if (!pc_alloc_path_buffers(pdrive))
goto errex;
path = pdrive->pathname_buffer;
filename = pdrive->filename_buffer;
/* Take the volume label string and make it into a short file name and extension */
pc_cp_volume_to8dot3(path, volume_label);
if (!pc_cs_valid_sfn(path, FALSE)) /* Verify the result is a valid file name, not case sensitive */
{
bad_path:
p_set_errno = PEINVALIDPARMS;
goto errex;
}
/* Get the file and extension padded to 8 3 with spaces */
if (!rtfs_cs_ascii_fileparse(filename, &fileext[0], path))
goto bad_path;
/* Get the root, if an error, errno is set below */
root_obj = pc_get_root(pdrive);
if (!root_obj)
goto errex;
/* Search the root for a volume label */
pobj = pc_find_volume(root_obj);
/* We found it, just change the name and update the directory entry */
if (pobj)
{
copybuff( pobj->finode->fname, filename, 8);
copybuff( pobj->finode->fext, &fileext[0], 3);
if (pc_update_inode(pobj, TRUE, DATESETUPDATE))
ret_val = TRUE;
}
else
{
if (get_errno() != PENOENT) /* If pobj is NULL we abort on abnormal errors */
goto errex;
rtfs_clear_errno();
#if (!INCLUDE_VFAT)
pobj = pc_mknode( root_obj,filename, fileext, AVOLUME, 0, CS_CHARSET_NOT_UNICODE);
#else
pobj = pc_mknode( root_obj, path, fileext, AVOLUME, 0, CS_CHARSET_NOT_UNICODE);
#endif
if (pobj)
{
p_set_errno = 0;
ret_val = TRUE;
}
else
{
/* pc_mknode has set errno */
goto errex;
}
}
errex:
if (pobj)
pc_freeobj(pobj);
if (root_obj)
pc_freeobj(root_obj);
pc_release_path_buffers(pdrive);
if (p_set_errno)
rtfs_set_errno(p_set_errno, __FILE__, __LINE__);
if (!release_drive_mount_write(driveno))/* Release lock, unmount if aborted */
ret_val = FALSE;
return(ret_val);
}
/* Take the volume label string and make it into a short file name and extesion */
static void pc_cp_volume_to8dot3(byte *to, byte *from)
{
int n_file_chars,n_ext_chars,i;
byte *p;
BOOLEAN dofile = TRUE;
*to = 0;
/* Calculate how many characters before and after a seperating period are needed for valid 8.3
this method also accounts for 2 byte JIS codes */
n_file_chars = n_ext_chars = 0;
p = from;
while (*p)
{
byte *next;
int n_chars;
next = p + 1;
CS_OP_INC_PTR(p, CS_CHARSET_NOT_UNICODE);
if (next == p)
n_chars = 1;
else
n_chars = 2;
if (dofile)
{
if ((n_file_chars + n_chars) <= 8)
{
n_file_chars += n_chars;
}
else
dofile = FALSE; /* FALL Through and do extension */
}
if (!dofile)
{
if (n_ext_chars + n_chars <= 3)
{
n_ext_chars += n_chars;
}
else
break;
}
}
/* Now block copy based on character counts */
for (i = 0; i < n_file_chars; i++)
{
*to++ = *from++;
*to = 0;
}
/* add .ext if needed */
if (n_ext_chars)
{
*to++ = (byte) '.';
*to = 0;
for (i = 0; i < n_ext_chars; i++)
{
*to++ = *from++;
*to = 0;
}
}
}
#endif /* Exclude from build if read only */
/***************************************************************************
pc_get_volume - Get Volume label.
Description
BOOLEAN pc_get_volume(byte *drive_id, byte *volume_label_buffer)
Retrieve the volume label and place it in the volume_label_buffer.
The volume label is a directory entry in the root directory of the volume.
Returns
Returns TRUE if it was able to retrieve the volume label.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID- Drive component is invalid
PEINVALIDPARMS - volume_lable buffer not provided.
An ERTFS system error
****************************************************************************/
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_get_volume_cs(byte *driveid, byte *volume_label,int use_charset)
#else
BOOLEAN pc_get_volume(byte *driveid, byte *volume_label)
#endif
{
DROBJ *pobj, *root_obj;
BOOLEAN ret_val;
int i,driveno;
DDRIVE *pdrive;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
if (!volume_label)
{
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__);
return(FALSE);
}
rtfs_clear_errno();
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(driveid, CS_CHARSET_ARGS);
if (driveno < 0)
return(FALSE); /* errno was set by check_drive */
root_obj = 0;
pobj = 0;
ret_val = FALSE;
pdrive = pc_drno2dr(driveno);
if (!pdrive) /* Won't happen */
goto errex;
#if (INCLUDE_EXFATORFAT64)
if (ISEXFATORFAT64(pdrive))
{
ret_val = pcexfat_get_volume(pdrive, volume_label, CS_CHARSET_ARGS);
release_drive_mount(driveno);/* Release lock, unmount if aborted */
return(ret_val);
}
#endif
/* Get the root, if an error, errno is set below */
root_obj = pc_get_root(pdrive);
if (!root_obj)
goto errex;
/* Search the root for a volume label */
pobj = pc_find_volume(root_obj);
/* We found it copy the results to volume_label */
if (pobj)
{
byte filename[10],fileext[4];
copybuff( &filename[0], pobj->finode->fname, 8);
copybuff( &fileext[0],pobj->finode->fext, 3);
/* Replace trailing spaces with null terminate and then concatonate the name and extension
Works for both JIS and ASCII */
filename[8] = fileext[3] = 0;
for(i = 7; i > 0; i--)
{
if (filename[i] == (byte) ' ')
filename[i] = 0;
else
break;
}
for(i = 3; i > 0; i--)
{
if (fileext[i] == (byte) ' ')
fileext[i] = 0;
else
break;
}
rtfs_cs_strcpy(volume_label, &filename[0], CS_CHARSET_NOT_UNICODE);
rtfs_cs_strcat(volume_label, &fileext[0], CS_CHARSET_NOT_UNICODE);
ret_val = TRUE;
}
errex:
if (pobj)
pc_freeobj(pobj);
if (root_obj)
pc_freeobj(root_obj);
release_drive_mount(driveno); /* Release lock, unmount if aborted */
return(ret_val);
}
/* Search the root for the volume label, if found return an initialized drobj. If not found and no system errors errno is set to PENOENT */
static DROBJ *pc_find_volume(DROBJ *proot_obj)
{
DROBJ *pobj;
byte filename[10],fileext[4];
pobj = pc_get_inode(0, proot_obj, &filename[0], &fileext[0], GET_INODE_STAR, CS_CHARSET_NOT_UNICODE);
while (pobj)
{
if (pc_isavol(pobj))
break;
pobj = pc_get_inode(pobj, proot_obj, &filename[0], &fileext[0], GET_INODE_STAR, CS_CHARSET_NOT_UNICODE);
}
return(pobj);
}

View File

@ -0,0 +1,195 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APISETCWD.C - Contains user api level source code.
The following routines are included:
pc_set_cwd - Set the current working directory.
*/
#include "rtfs.h"
/***************************************************************************
PC_SET_CWD - Set the current working directory for a drive.
Description
Find path. If it is a subdirectory make it the current working
directory for the drive.
Returns
Returns TRUE if the current working directory was changed.
errno is set to one of the following
0 - No error
PEINVALIDPATH - Path specified badly formed.
PENOENT - Path not found
PEINVALIDDIR - Not a directory
An ERTFS system error
****************************************************************************/
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_set_cwd_cs(byte *name, int use_charset)
#else
BOOLEAN pc_set_cwd(byte *name)
#endif
{
DROBJ *pobj;
int driveno;
DDRIVE *pdrive;
DROBJ *parent_obj;
byte fileext[4];
byte *path, *pfilename, *pfileext;
BOOLEAN is_dot, is_dotdot;
BOOLEAN ret_val;
int p_set_errno;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
rtfs_clear_errno(); /* pc_set_cwd: clear error status */
ret_val = FALSE;
p_set_errno = 0;
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(name, CS_CHARSET_ARGS);
if (driveno < 0)
{ /* errno was set by check_drive */
return(FALSE);
}
pdrive = pc_drno2dr(driveno);
/* Allocate scratch buffers in the DRIVE structure. */
if (!pc_alloc_path_buffers(pdrive))
goto errex;
path = pdrive->pathname_buffer;
pfilename = pdrive->filename_buffer;
pfileext = &fileext[0];
#if (INCLUDE_EXFATORFAT64)
if (ISEXFATORFAT64(pdrive))
{
ret_val = pcexfat_set_cwd(pdrive, name, CS_CHARSET_ARGS);
goto errex;
}
#endif
/* Get out the filename and d:parent */
if (!pc_parsepath(path, pfilename,pfileext,name, CS_CHARSET_ARGS))
{
p_set_errno = PEINVALIDPATH;
/*rtfs_set_errno(PEINVALIDPATH, __FILE__, __LINE__); */
goto errex;
}
/* Find the parent and make sure it is a directory */
parent_obj = pc_fndnode(path, CS_CHARSET_ARGS);
if (!parent_obj)
goto errex; /* pc_fndnode set errno */
if (!pc_isadir(parent_obj))
{
p_set_errno = PEACCES; /* Path is not a directory */
/*rtfs_set_errno(PEACCESS, __FILE__, __LINE__); Path is not a directory */
goto errex;
}
is_dot=is_dotdot=FALSE;
if (CS_OP_CMP_ASCII(pfilename,'.', CS_CHARSET_ARGS))
{
byte *pfilename_plus_1;
pfilename_plus_1 = pdrive->filename_buffer;
CS_OP_INC_PTR(pfilename_plus_1, CS_CHARSET_ARGS);
if (CS_OP_IS_EOS(pfilename_plus_1, CS_CHARSET_ARGS) || CS_OP_CMP_ASCII(pfilename_plus_1,' ', CS_CHARSET_ARGS))
is_dot=TRUE;
else if (CS_OP_CMP_ASCII(pfilename_plus_1,'.', CS_CHARSET_ARGS))
{
CS_OP_INC_PTR(pfilename_plus_1, CS_CHARSET_ARGS);
if (CS_OP_IS_EOS(pfilename_plus_1, CS_CHARSET_ARGS) || CS_OP_CMP_ASCII(pfilename_plus_1,' ', CS_CHARSET_ARGS))
is_dotdot=TRUE;
}
}
/* Get the directory */
/* April 2012 Fixed bug that skipped the directory entry when the first charcter is a space */
/* Wrong if (CS_OP_CMP_ASCII(pfilename,'\0', CS_CHARSET_ARGS) || CS_OP_CMP_ASCII(pfilename,' ', CS_CHARSET_ARGS))*/
if (CS_OP_CMP_ASCII(pfilename,'\0', CS_CHARSET_ARGS))
{
pobj = parent_obj;
}
else if (is_dotdot)
{
if (pc_isroot(parent_obj))
pobj = parent_obj;
else
{
pobj = pc_get_inode(0, parent_obj, 0, 0, GET_INODE_DOTDOT, CS_CHARSET_ARGS);
/* If the request is cd .. then we just found the .. directory entry
we have to call get_mom to access the parent. */
pc_freeobj(parent_obj);
if (!pobj) /* pc_get_inode() has set errno to PENOENT or to an internal or IO error status */
goto errex;
parent_obj = pobj;
/* Find parent_objs parent. By looking back from .. */
pobj = pc_get_mom(parent_obj);
pc_freeobj(parent_obj);
if (!pobj)
{ /* if pc_get_mom() set errno, use it otherwise set PENOENT */
if (!get_errno())
p_set_errno = PENOENT; /* Not found */
/*rtfs_set_errno(PENOENT, __FILE__, __LINE__); */
goto errex;
}
}
}
else if (is_dot)
{
pobj = parent_obj;
}
else
{
pobj = pc_get_inode(0, parent_obj, pfilename, pfileext, GET_INODE_MATCH, CS_CHARSET_ARGS);
pc_freeobj(parent_obj);
}
if (!pobj)
{
/* pc_get_inode set errno */
goto errex;
}
else if (!pc_isadir(pobj))
{
pc_freeobj(pobj);
p_set_errno = PENOENT; /* Path is not a directory */
/*rtfs_set_errno(PENOENT, __FILE__, __LINE__); */
goto errex;
}
driveno = pobj->pdrive->driveno;
{
DROBJ *ptemp;
RTFS_SYSTEM_USER *pu;
pu = rtfs_get_system_user();
ptemp = rtfs_get_user_pwd(pu, driveno, TRUE); /* Get cwd for driveno and clear it */
if (ptemp)
{
pc_freeobj(ptemp); /* Free it */
}
rtfs_set_user_pwd(pu, pobj); /* Set cwd to pobj */
}
ret_val = TRUE;
errex:
pc_release_path_buffers(pdrive);
release_drive_mount(driveno);/* Release lock, unmount if aborted */
if (p_set_errno)
rtfs_set_errno(p_set_errno, __FILE__, __LINE__);
return(ret_val);
}

181
rtfscommon/source/apistat.c Normal file
View File

@ -0,0 +1,181 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APISTAT.C - Contains user api level source code.
The following routines are included:
pc_fstat - Obtain statistics on an open file
pc_stat - Obtain statistics on a path.
*/
#include "rtfs.h"
/****************************************************************************
PC_STAT - Obtain statistics on a path.
Description
This routine searches for the file or directory provided in the first
argument. If found it fills in the stat structure as described here.
st_dev - The entry s drive number
st_mode;
S_IFMT type of file mask
S_IFCHR character special (unused)
S_IFDIR directory
S_IFBLK block special (unused)
S_IFREG regular (a file)
S_IWRITE Write permitted
S_IREAD Read permitted.
st_rdev - The entry s drive number
st_size - file size
st_atime - creation date in DATESTR format
st_mtime - creation date in DATESTR format
st_ctime - creation date in DATESTR format
t_blksize - optimal blocksize for I/O (cluster size)
t_blocks - blocks allocated for file
fattributes - The DOS attributes. This is non-standard but supplied
if you want to look at them
Returns
Returns 0 if all went well otherwise it returns -1.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID- Drive component is invalid
PENOENT - File or directory not found
An ERTFS system error
****************************************************************************/
#if (INCLUDE_CS_UNICODE)
int pc_stat_cs(byte *name, ERTFS_STAT *pstat, int use_charset)
#else
int pc_stat(byte *name, ERTFS_STAT *pstat)
#endif
{
DROBJ *pobj;
int driveno;
int ret_val;
CHECK_MEM(int, -1) /* Make sure memory is initted */
rtfs_clear_errno(); /* pc_stat: clear error status */
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(name, CS_CHARSET_ARGS);
if (driveno < 0)
{ /* errno was set by check_drive */
return(-1);
}
/* pc_fndnode will set errno */
pobj = pc_fndnode(name, CS_CHARSET_ARGS);
if (pobj)
{
if (pobj->isroot)
{
pstat->st_rdev =
pstat->st_dev = pobj->finode->my_drive->driveno;
pstat->st_ino = 0;
pstat->fattribute = ADIRENT;
pstat->st_mode = S_IFDIR;
pstat->st_nlink = 1; /* (always 1) */
pstat->st_size = 0; /* file size, in bytes */
pstat->st_atime.date = pstat->st_atime.time = 0;
pstat->st_mtime = pstat->st_atime; /* last modification */
pstat->st_ctime = pstat->st_atime; /* last status change */
pstat->st_blksize = (dword) pobj->finode->my_drive->drive_info.bytespcluster;
pstat->st_blocks = 0;
}
else
{
/* cal pc_finode_stat() to update the stat structure */
pc_finode_stat(pobj->finode, pstat);
}
ret_val = 0;
}
else
ret_val = -1;
if (pobj)
pc_freeobj(pobj);
release_drive_mount(driveno);/* Release lock, unmount if aborted */
return(ret_val);
}
/****************************************************************************
PC_FINODE_STAT - Convert finode information to stat info for stat and fstat
Description
Given a pointer to a FINODE and a ERTFS_STAT structure
load ERTFS_STAT with filesize, date of modification et al. Interpret
the fattributes field of the finode to fill in the st_mode field of the
the stat structure.
Returns
Nothing
****************************************************************************/
void pc_finode_stat(FINODE *pi, ERTFS_STAT *pstat) /*__fn__*/
{
rtfs_memset(pstat, 0 , sizeof(*pstat));
pstat->st_dev = pi->my_drive->driveno; /* (drive number, rtfs) */
pstat->st_ino = 0; /* inode number (0) */
pstat->st_mode = 0; /* (see S_xxxx below) */
/* Store away the DOS file attributes in case someone needs them */
pstat->fattribute = pi->fattribute;
pstat->st_mode |= S_IREAD;
if(!(pstat->fattribute & ARDONLY))
pstat->st_mode |= S_IWRITE;
if (pstat->fattribute & ADIRENT)
pstat->st_mode |= S_IFDIR;
if (!(pstat->fattribute & (AVOLUME|ADIRENT)))
pstat->st_mode |= S_IFREG;
pstat->st_nlink = 1; /* (always 1) */
pstat->st_rdev = pstat->st_dev; /* (drive number, rtfs) */
pstat->st_size_hi = 0;
/* optimal buffering size. is a cluster */
pstat->st_blksize = (dword) pi->my_drive->drive_info.bytespcluster;
#if (INCLUDE_EXFATORFAT64)
if (ISEXFATORFAT64(pi->my_drive))
{
pstat->st_size = M64LOWDW(pi->fsizeu.fsize64);
pstat->st_size_hi = M64HIGHDW(pi->fsizeu.fsize64);
/* blocks (sectors) is file size / byts per sector. with round up */
{
ddword fsize_ddw,blocks_ddw;
/* 64 bit version of (dword) ((pi->fsize + 511)>>9); */
fsize_ddw = M64SET32(pstat->st_size_hi, pstat->st_size);
fsize_ddw = M64PLUS32(fsize_ddw, (dword) pi->my_drive->drive_info.bytespsector-1);
blocks_ddw = M64RSHIFT(fsize_ddw, (dword) pi->my_drive->drive_info.log2_bytespsec);
pstat->st_blocks = (dword) M64LOWDW(blocks_ddw);
}
}
else
#endif
{
pstat->st_size = pi->fsizeu.fsize; /* file size, in bytes */
/* blocks (sectors) is file size / byts per sector. with round up */
pstat->st_blocks = (dword) ((pstat->st_size + (pi->my_drive->drive_info.bytespsector-1))>>pi->my_drive->drive_info.log2_bytespsec);
}
pstat->st_atime.date = pi->adate; /* last access */
pstat->st_atime.time = pi->atime;
pstat->st_ctime.date = pi->cdate; /* Created */
pstat->st_ctime.time = pi->ctime;
pstat->st_mtime.date = pi->fdate; /* Modified */
pstat->st_mtime.time = pi->ftime;
}

View File

@ -0,0 +1,133 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2007
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APIUNLINK.C - Contains user api level file IO source code.
PC_UNLINK - Delete a file.
*/
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
/****************************************************************************
PC_UNLINK - Delete a file.
Description
Delete the file in name. Fail if not a simple file,if it is open,
does not exist or is read only.
Returns
Returns TRUE if it successfully deleted the file.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID- Drive component is invalid
PEINVALIDPATH - Path specified badly formed.
PENOENT - Can't find file to delete
PEACCESS - File in use, is read only or is not a simple file.
An ERTFS system error
***************************************************************************/
/* Delete a file */
#if (INCLUDE_CS_UNICODE)
BOOLEAN pc_unlink_cs(byte *name, int use_charset)
#else
BOOLEAN pc_unlink(byte *name)
#endif
{
DROBJ *pobj;
DROBJ *parent_obj;
BOOLEAN ret_val;
DDRIVE *pdrive;
byte *path;
byte *filename;
byte fileext[4];
int driveno;
int p_errno;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
ret_val = FALSE;
parent_obj = 0;
pobj = 0;
p_errno = 0;
rtfs_clear_errno(); /* pc_unlink: clear error status */
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(name, CS_CHARSET_ARGS);
if (driveno < 0)
{
/* errno was set by check_drive */
return(FALSE);
}
pdrive = pc_drno2dr(driveno);
/* Allocate scratch buffers in the DRIVE structure. */
if (!pc_alloc_path_buffers(pdrive))
goto errex;
path = pdrive->pathname_buffer;
filename = pdrive->filename_buffer;
/* Get out the filename and d:parent */
if (!pc_parsepath(path, filename,fileext,name, CS_CHARSET_ARGS))
{
p_errno = PEINVALIDPATH;
goto errex;
}
/* Find the parent and make sure it is a directory */
parent_obj = pc_fndnode(path, CS_CHARSET_ARGS);
if (!parent_obj)
goto errex; /* pc_fndnode set errno */
if (!pc_isadir(parent_obj) || pc_isavol(parent_obj))
{
p_errno = PEACCES;
goto errex;
}
/* Find the file */
pobj = pc_get_inode(0, parent_obj, filename, (byte*)fileext, GET_INODE_MATCH, CS_CHARSET_ARGS);
/* if pc_get_inode() fails it sets errno to PENOENT or to an internal or IO error status */
if (pobj)
{
if (pc_isroot(pobj) || (pobj->finode->opencount > 1) ||
(pobj->finode->fattribute&(ARDONLY|AVOLUME)))
{
access_error:
p_errno = PEACCES;
ret_val = FALSE;
goto errex;
}
if (pobj->finode->fattribute&ADIRENT)
{
goto access_error;
}
else
{ /* pc_rmnode sets errno */
ret_val = pc_rmnode(pobj);
}
}
errex:
pc_release_path_buffers(pdrive);
if (pobj)
pc_freeobj(pobj);
if (parent_obj)
{
pc_freeobj(parent_obj);
}
/* Set errno if we have one and not set by lower level already */
if (ret_val)
rtfs_clear_errno();
else if ((p_errno) && !get_errno())
rtfs_set_errno(p_errno, __FILE__, __LINE__);
if (!release_drive_mount_write(driveno))/* Release lock, unmount if aborted */
ret_val = FALSE;
return(ret_val);
}
#endif /* Exclude from build if read only */

View File

@ -0,0 +1,302 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 2002
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
* UTILASCI.C - Contains ASCII string manipulation and character
* conversion routines
*/
#include "rtfs.h"
#if (INCLUDE_CS_ASCII)
static void pc_ascii_byte2upper(byte *to, byte *from);
int ascii_cs_strcpy(byte * targ, byte * src);
int ascii_cs_strlen(byte * string);
byte *ascii_goto_eos(byte *p);
byte * ascii_cs_strcat(byte * targ, byte * src) /*__fn__*/
{
byte *pappend;
pappend = ascii_goto_eos(targ);
ascii_cs_strcpy(pappend, src);
return targ;
}
/* compares 2 strings; returns 0 if they match */
int ascii_cs_strcmp(byte * s1, byte * s2)
{
int index=0;
while (s1[index] && s2[index] && s1[index] == s2[index])
{
index++;
}
if (!s1[index] && !s2[index]) return 0;
if (s1[index] < s2[index]) return -1;
else return 1;
}
int ascii_cs_strcpy(byte * targ, byte * src)
{
int loop_cnt=0;
do
{
targ[loop_cnt] = src[loop_cnt];
} while(src[loop_cnt++]);
return loop_cnt;
}
/* return number of ascii chars in a string */
int ascii_cs_strlen(byte * string) /*__fn__*/
{
int len=0;
while (string[len] != 0) len++;
return len;
}
/* Macros here */
byte *ascii_goto_eos(byte *p)
{
while (*p) p++;
return(p);
}
int ascii_ascii_index(byte *p, byte base)
{
byte c;
pc_ascii_byte2upper(&c, p);
return((int) (c - base));
}
int ascii_compare_nc(byte *p1, byte *p2)
{
byte c,d;
if (*p1 == *p2)
return(1);
else
{
pc_ascii_byte2upper(&c, p1);
pc_ascii_byte2upper(&d, p2);
return(c == d);
}
}
/* Version of MFILE that converts path from byte orientation to
native char set before returning. pc_mfile and pc_cs_mfile are
the same for ascii */
byte *ascii_cs_mfile(byte *to, byte *filename, byte *ext, byte ntflags)
{
byte *p;
int i;
byte *retval = to;
/* ntflags specify if basename and/0r ext should be stired in lower case. Bit 4 (0x10) means lowercase extension and bit 3 (0x8) lowercase basename
if the lowercase bit is set or in 0x20 to ascii letter to force lower case */
byte extcasemask,namecasemask;
extcasemask = (ntflags & 0x10);
namecasemask= (ntflags & 0x08);
p = filename;
i = 0;
while(*p)
{
if (*p == ' ')
break;
else
{
byte c=*p++;
c=CS_APPLY_NT_CASEMASK(namecasemask,c);
*to++ = c;
i++;
}
if (i == 8)
break;
}
if (p != filename)
{
p = ext;
if (*p && *p != ' ')
*to++ = '.';
i = 0;
while(p && *p)
{
if (*p == ' ')
break;
else
{
byte c=*p++;
c=CS_APPLY_NT_CASEMASK(extcasemask,c);
*to++ = c;
i++;
}
if (i == 3)
break;
}
}
*to = '\0';
return (retval);
}
/***************************************************************************
PC_FILEPARSE - Parse a file xxx.yyy into filename/pathname
Description
Take a file named XXX.YY and return SPACE padded NULL terminated
filename [XXX ] and fileext [YY ] components. If the name or ext are
less than [8,3] characters the name/ext is space filled and null termed.
If the name/ext is greater than [8,3] the name/ext is truncated. '.'
is used to seperate file from ext, the special cases of . and .. are
also handled.
Returns
Returns TRUE
****************************************************************************/
/* UNICODE - Called by pc_malias not by others if vfat - Okay as ascii */
/* UNICODE - pc_enum usage is probably incorrect */
/* Take a string xxx[.yy] and put it into filename and fileext */
/* Note: add a check legal later */
BOOLEAN pc_ascii_fileparse(byte *filename, byte *fileext, byte *p) /* __fn__*/
{
int i;
/* Defaults */
rtfs_memset(filename, ' ', 8);
filename[8] = '\0';
rtfs_memset(fileext, ' ', 3);
fileext[3] = '\0';
/* Special cases of . and .. */
if (*p == '.')
{
*filename = '.';
if (*(p+1) == '.')
{
*(++filename) = '.';
return (TRUE);
}
else if (*(p + 1) == '\0')
return (TRUE);
else
return (FALSE);
}
i = 0;
while (*p)
{
if (*p == '.')
{
p++;
break;
}
else
if (i++ < 8)
*filename++ = *p;
p++;
}
i = 0;
while (*p)
{
if (i++ < 3)
*fileext++ = *p;
p++;
}
return (TRUE);
}
#if (!INCLUDE_VFAT) /* Small piece of compile time INCLUDE_VFAT vs's NONVFAT code */
BOOLEAN pc_ascii_patcmp_8(byte *p, byte *pattern, BOOLEAN dowildcard) /* __fn__*/
{
int size = 8;
/* Kludge. never match a deleted file */
if (*p == PCDELETE)
return (FALSE);
else if (*pattern == PCDELETE) /* But E5 in the Pattern matches 0x5 */
{
if (*p == 0x5)
{
size -= 1;
p++;
pattern++;
}
else
return (FALSE);
}
while (size--)
{
if(dowildcard)
{
if (*pattern == '*') /* '*' matches the rest of the name */
return (TRUE);
if (*pattern != '?' && !ascii_compare_nc(pattern,p))
return (FALSE);
}
else
{
if (!ascii_compare_nc(pattern,p))
return (FALSE);
}
p++;
pattern++;
}
return (TRUE);
}
BOOLEAN pc_ascii_patcmp_3(byte *p, byte *pattern, BOOLEAN dowildcard) /* __fn__*/
{
int size = 3;
while (size--)
{
if(dowildcard)
{
if (*pattern == '*') /* '*' matches the rest of the name */
return (TRUE);
if (*pattern != '?' && !ascii_compare_nc(pattern,p))
return (FALSE);
}
else
{
if (!ascii_compare_nc(pattern,p))
return (FALSE);
}
p++;
pattern++;
}
return (TRUE);
}
#endif /* INCLUDE_VFAT */
static void pc_ascii_byte2upper(byte *to, byte *from) /* __fn__*/
{
byte c;
c = *from;
if ((c >= 'a') && (c <= 'z'))
c = (byte) ('A' + c - 'a');
*to = c;
}
void pc_ascii_str2upper(byte *to, byte *from)
{
while(*from)
pc_ascii_byte2upper(to++, from++);
*to = '\0';
}
void pc_ascii_strn2upper(byte *to, byte *from, int n)
{
int i;
for (i = 0; i < n; i++,to++, from++)
pc_ascii_byte2upper(to, from);
}
#endif

View File

@ -0,0 +1,236 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 2002
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
* UTILASCI.C - Contains ASCII string manipulation and character
* conversion routines
*/
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
#if (INCLUDE_CS_ASCII)
/***************************************************************************
PC_VALID_SFN - See if filename is a valid short file name
Description
Determines validity of a short file name based on the following criteria:
- the file name must be between 0 and 8 characters
- the file extension must be between 0 and 3 characters
- the file name must not begin with a period
- it must not be a reserved DOS file name
- it must not contain any characters that are illegal within sfn's
Returns
TRUE if filename is a valid sfn, FALSE otherwise
****************************************************************************/
BOOLEAN ascii_valid_sfn(byte *filename, BOOLEAN case_sensitive)
{
int len,period_count,ext_start;
byte name_part[9];
BOOLEAN badchar;
if(name_is_reserved(filename)) return(FALSE);
name_part[0] = 0;
for(len=0,badchar=FALSE,period_count=0,ext_start=0; filename[len]!=0; len++)
{
if(_illegal_alias_char(filename[len])) badchar = TRUE;
if (case_sensitive && (filename[len] >= (byte) 'a' && filename[len] <= (byte) 'z'))
badchar = TRUE;
if(filename[len] == '.')
{
ext_start = len+1;
period_count++;
}
else
{
if (!ext_start && len < 8)
{
name_part[len] = filename[len];
name_part[len+1] = 0;
}
}
}
/* check if the file name part contains a reserved name */
if(name_is_reserved(name_part)) return(FALSE);
if( (filename[0] == ' ') || /* 1st char is a space */
(len == 0) || /* no name */
badchar || /* contains illegal chars */
(period_count > 1) || /* contains more than one extension */
((len-ext_start)>3 && period_count>0) || /* extension is longer than 3 chars */
(period_count==0 && len > 8) || /* name is longer than 8 chars */
(ext_start > 9) || /* name is longer than 8 chars */
(ext_start==1) ) return(FALSE); /* no name; 1st char is a period */
return(TRUE);
}
#if (INCLUDE_VFAT) /* Small piece of compile time VFAT vs's NONVFAT code */
/***************************************************************************
PC_VALID_LFN - See if filename is a valid long file name
Description
Determines validity of a long file name based on the following criteria:
- the file must be between 0 and 256 characters in length
- it must not be a reserved DOS file name
- it must not contain any characters that are illegal within lfn's
Returns
TRUE if filename is a valid lfn, FALSE otherwise
*****************************************************************************/
BOOLEAN pc_ascii_validate_filename(byte * filename, byte * ext)
{
int len,n;
byte name_part[9];
RTFS_ARGSUSED_PVOID((void *) ext);
name_part[0] = 0;
for(n=0,len=0; filename[n]!=0; len++,n++)
{
if(_illegal_lfn_char(filename[n]))
return(FALSE);
else
{
if (len < 5) /* handles lpt1, aux, con etc */
{
if(filename[len] == '.')
{
name_part[len] = 0;
if(name_is_reserved(name_part)) return(FALSE);
}
else
{
name_part[len] = filename[len];
if (filename[len+1] == 0)
{
name_part[len+1] = 0;
if(name_is_reserved(name_part)) return(FALSE);
}
}
}
}
}
if( (len == 0) || (len > 255) ) return(FALSE);
return(TRUE);
}
BOOLEAN pc_ascii_malias(byte *alias, byte *input_file, int which_try)
{
int n,i,s;
byte filename[9],fileext[4];
/* Fill filename[8] with spaces before we start. */
rtfs_memset(filename, ' ', 8);
/* Check if invalid short file name. Ignore case. If contains lower case we fix it later ! */
if ((which_try == -1) && !pc_cs_valid_sfn((byte *)input_file, FALSE))
return(FALSE);
/* Process the ASCII alias name */
while(*input_file=='.' || *input_file==' ') input_file++;
/* find extension start */
for(n=0,i=0; input_file[n]!=0; n++) /* i holds the position right */
{ /* after the last period */
if(input_file[n]=='.') i=n+1;
}
if(i>0 && input_file[i]!=0){
/* copy extension to fileext[] */
for(n=i,s=0; input_file[n]!=0 && s<3; n++)
{
if(input_file[n]!=' ')
{
if(_illegal_alias_char(input_file[n]))
{
fileext[s++] = '_';
}
else
fileext[s++] = input_file[n];
}
}
fileext[s]=0;} else { i=512; fileext[0]=0; } /* null terminate, not sector size dependent */
/* copy file name to filename[], filtering out spaces, periods and
replacing characters illegal in alias names with '_' */
for(n=0,s=0; n<i && input_file[n]!=0 && s<8; n++)
{
if(input_file[n]!=' ' && input_file[n]!='.')
{
if(_illegal_alias_char(input_file[n]) || input_file[n]>127)
{
filename[s++] = '_';
}
else
filename[s++] = input_file[n];
}
}
for(;s<8;s++) /* pad with spaces */
{
filename[s] = ' ';
}
filename[8]=0; /* null terminate filename[] */
pc_cs_ascii_str2upper(filename,filename);
pc_cs_ascii_str2upper(fileext,fileext);
if (which_try != -1)
{
/* append (TEXT[])i to filename[] */
for(n=7,s=which_try; s>0 && n>0; s/=10,n--)
{
filename[n] = (byte)(((byte)s%10)+'0');
}
if(n==0 && s>0)
return(FALSE);
else
filename[n]='~';
}
/* copy filename[] to alias[], filtering out spaces */
for(n=0,s=0; s<8; s++)
{
if(filename[s]!=' ')
alias[n++]=filename[s];
}
if(fileext[0] != 0)
{
alias[n++]='.'; /* insert separating period */
/* copy fileext[] to alias[] */
for(s=0; fileext[s]!=0; s++,n++)
{
alias[n]=fileext[s];
}
}
alias[n]=0; /* null terminate alias[] */
return(TRUE);
}
#endif
#if (!INCLUDE_VFAT) /* Small piece of compile time INCLUDE_VFAT vs's NONVFAT code */
BOOLEAN pc_ascii_validate_8_3_name(byte * name,int len) /*__fn__*/
{
int i;
int last;
last = len-1;
for (i = 0; i < len; i++)
{
/* If we hit a space make sure the rest of the string is spaces */
if (name[i] == ' ')
{
for (; i < len; i++)
{
if (name[i] != ' ')
return(FALSE);
}
break;
}
}
return(TRUE);
}
#endif /* INCLUDE_VFAT */
#endif
#endif /* Exclude from build if read only */

View File

@ -0,0 +1,483 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 2002
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
* UTILASCI.C - Contains ASCII string manipulation and character
* conversion routines
*/
#include "rtfs.h"
#if (INCLUDE_CS_UNICODE)
/* csunicodrd.c */
int unicode_cs_strcmp(byte * s1, byte * s2);
byte * unicode_cs_strcat(byte * targ, byte * src);
int unicode_cs_strcpy(byte * targ, byte * src);
int unicode_cs_strlen(byte * string);
byte *unicode_goto_eos(byte *p);
int unicode_ascii_index(byte *p, byte base);
int unicode_compare_nc(byte *p1, byte *p2);
int unicode_compare(byte *p1, byte *p2);
int unicode_cmp_to_ascii_char(byte *p, byte c);
void unicode_assign_ascii_char(byte *p, byte c);
void lfn_chr_to_unicode(byte *to, byte *fr);
void unicode_chr_to_lfn(byte *to, byte *fr);
byte *unicode_cs_mfile(byte *to, byte *filename, byte *ext, byte ntflags);
/* csunicodwr.c */
BOOLEAN pc_unicode_validate_filename(byte * name, byte * ext);
BOOLEAN pc_unicode_malias(byte *alias, byte *input_file, int which_try);
#endif
#if (INCLUDE_CS_JIS)
/* csjisrd.c */
int jis_cs_strcmp(byte * s1, byte * s2);
byte * jis_cs_strcat(byte * targ, byte * src);
int jis_cs_strcpy(byte * targ, byte * src);
int jis_cs_strlen(byte * string);
byte *jis_goto_eos(byte *p);
int jis_ascii_index(byte *p, byte base);
int jis_compare_nc(byte *p1, byte *p2);
void pc_jis_strn2upper(byte *to, byte *from, int n);
int jis_char_length(byte *p);
int jis_char_copy(byte *to, byte *from);
byte *jis_increment(byte *p);
int jis_compare(byte *p1, byte *p2);
void pc_jis_str2upper(byte *to, byte *from);
byte *jis_cs_mfile(byte *to, byte *filename, byte *extint, byte ntflags);
BOOLEAN pc_jis_fileparse(byte *filename, byte *fileext, byte *p);
BOOLEAN pc_jis_patcmp_8(byte *p, byte *pattern, BOOLEAN dowildcard);
BOOLEAN pc_jis_patcmp_3(byte *p, byte *pattern, BOOLEAN dowildcard);
/* csjiswr.c */
BOOLEAN jis_valid_sfn(byte *filename, BOOLEAN case_sensitive);
BOOLEAN pc_jis_validate_filename(byte * filename, byte * ext);
BOOLEAN pc_jis_malias(byte *alias, byte *input_file, int which_try);
BOOLEAN pc_jis_validate_8_3_name(byte * name,int len);
/* csjistap.c */
void jis_to_unicode(byte *to, byte *p);
int unicode_to_jis(byte *pjis, byte *punicode, BOOLEAN *is_default);
#else
/* csasciird.c */
byte * ascii_cs_strcat(byte * targ, byte * src);
int ascii_cs_strcmp(byte * s1, byte * s2);
int ascii_cs_strcpy(byte * targ, byte * src);
int ascii_cs_strlen(byte * string);
byte *ascii_goto_eos(byte *p);
int ascii_ascii_index(byte *p, byte base);
int ascii_compare_nc(byte *p1, byte *p2);
byte *ascii_cs_mfile(byte *to, byte *filename, byte *ext, byte ntflags);
BOOLEAN pc_ascii_fileparse(byte *filename, byte *fileext, byte *p);
BOOLEAN pc_ascii_patcmp_8(byte *p, byte *pattern, BOOLEAN dowildcard);
BOOLEAN pc_ascii_patcmp_3(byte *p, byte *pattern, BOOLEAN dowildcard);
void pc_ascii_str2upper(byte *to, byte *from);
void pc_ascii_strn2upper(byte *to, byte *from, int n);
/* csasciiwr.c */
BOOLEAN ascii_valid_sfn(byte *filename,BOOLEAN case_sensitive);
BOOLEAN pc_ascii_validate_filename(byte * filename, byte * ext);
BOOLEAN pc_ascii_malias(byte *alias, byte *input_file, int which_try);
BOOLEAN pc_ascii_validate_8_3_name(byte * name,int len);
#endif
/* CS_OP_CP_CHR(TO,FR,CS) rtfs_cs_char_copy((TO),(FR), CS) */
void rtfs_cs_char_copy(byte *to, byte *from, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
{
{*(to)=*(from);*((to)+1)=*((from)+1);}
return;
}
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
#if (INCLUDE_CS_JIS)
jis_char_copy(to,from);
#else
*to = *from;
#endif
}
/* #define CS_OP_INC_PTR(P,CS) rtfs_cs_increment((P), CS) */
byte *rtfs_cs_increment(byte *p, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
return(p+2);
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
#if (INCLUDE_CS_JIS)
return(jis_increment(p));
#else
return(p+1);
#endif
}
/* #define CS_OP_CMP_CHAR(P1, P2,CS) rtfs_cs_compare((P1), (P2), CS) */
int rtfs_cs_compare(byte *p1, byte *p2, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
return(unicode_compare(p1,p2));
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
#if (INCLUDE_CS_JIS)
return(jis_compare(p1,p2));
#else
return ((int)(*p1==*p2));
#endif
}
/* #define CS_OP_CMP_CHAR_NC(P1, P2,CS) ascii_compare_nc((P1), (P2)) */
int rtfs_cs_compare_nc(byte *p1, byte *p2, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
return(unicode_compare_nc(p1,p2));
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
#if (INCLUDE_CS_JIS)
return(jis_compare_nc(p1,p2));
#else
return(ascii_compare_nc(p1,p2));
#endif
}
/* #define CS_OP_ASCII_INDEX(P,C,CS) rtfs_cs_ascii_index(P,C, CS) */
int rtfs_cs_ascii_index(byte *p, byte base, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
return(unicode_ascii_index(p, base));
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
#if (INCLUDE_CS_JIS)
return(jis_ascii_index(p, base));
#else
return(ascii_ascii_index(p, base));
#endif
}
/* #define CS_OP_TO_LFN(TO, FROM,CS) rtfs_cs_to_unicode(TO, FROM, CS) */
void rtfs_cs_to_unicode(byte *to, byte *p, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
{
unicode_chr_to_lfn(to, p);
return;
}
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
#if (INCLUDE_CS_JIS)
jis_to_unicode(to, p);
#else
{*to = *p; *(to+1) = 0;}
#endif
}
/* #define CS_OP_LFI_TO_TXT(TO, FROM,CS) rtfs_cs_unicode_to_cs(TO, FROM, CS) */
void rtfs_cs_unicode_to_cs(byte *to, byte *punicode, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
{
lfn_chr_to_unicode(to, punicode);
return;
}
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
#if (INCLUDE_CS_JIS)
{
BOOLEAN btemp;
unicode_to_jis(to, punicode, &btemp);
}
#else
*to = *punicode;
#endif
}
/* #define CS_OP_IS_EOS(P,CS) rtfs_cs_is_eos(P, CS) */
BOOLEAN rtfs_cs_is_eos(byte *p, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
return((BOOLEAN)(*p == 0 && *(p +1) == 0));
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
return((BOOLEAN)(*p == 0));
}
/* #define CS_OP_IS_NOT_EOS(P,CS) rtfs_cs_is_not_eos(P, CS) */
BOOLEAN rtfs_cs_is_not_eos(byte *p, int use_charset)
{
return(!rtfs_cs_is_eos(p,use_charset));
}
/* #define CS_OP_TERM_STRING(P,CS) rtfs_cs_term_string(P, CS) */
void rtfs_cs_term_string(byte *p, int use_charset)
{
*p=0;
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
{
*(p +1)=0;
}
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
}
/* #define CS_OP_CMP_ASCII(P,C,CS) rtfs_cs_cmp_to_ascii((P),C,CS) */
int rtfs_cs_cmp_to_ascii_char(byte *p, byte c, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
return(unicode_cmp_to_ascii_char(p, c));
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
return((int)(*p == c));
}
/* #define CS_OP_ASSIGN_ASCII(P,C,CS) rtfs_cs_assign_ascii((P),C,CS) */
void rtfs_cs_assign_ascii_char(byte *p, byte c, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
{
unicode_assign_ascii_char(p, c);
return;
}
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
*p = c;
}
/* #define CS_OP_GOTO_EOS(P,CS) rtfs_cs_goto_eos((P),CS) */
byte *rtfs_cs_goto_eos(byte *p, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
return(unicode_goto_eos(p));
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
#if (INCLUDE_CS_JIS)
return(jis_goto_eos(p));
#else
return(ascii_goto_eos(p));
#endif
}
BOOLEAN rtfs_cs_ascii_fileparse(byte *filename, byte *fileext, byte *p)
{
#if (INCLUDE_CS_JIS)
return(pc_jis_fileparse(filename, fileext, p));
#else
return(pc_ascii_fileparse(filename, fileext, p));
#endif
}
byte *pc_cs_mfile(byte *to, byte *filename, byte *ext, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
return(unicode_cs_mfile(to, filename, ext,0));
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
#if (INCLUDE_CS_JIS)
return(jis_cs_mfile(to, filename, ext,0));
#else
return(ascii_cs_mfile(to, filename, ext,0));
#endif
}
/* Create a "x.y" string from fname and fext sections of 8.3 directory, being mindful of flags in the reserve field that
specify forcing lower case for filename, extension or both */
byte *pc_cs_mfileNT(byte *to, byte *filename, byte *ext, int use_charset, byte ntflags)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
return(unicode_cs_mfile(to, filename, ext,ntflags));
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
#if (INCLUDE_CS_JIS)
return(jis_cs_mfile(to, filename, ext,ntflags));
#else
return(ascii_cs_mfile(to, filename, ext,ntflags));
#endif
}
byte *rtfs_cs_strcat(byte * targ, byte * src, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
return(unicode_cs_strcat(targ, src));
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
#if (INCLUDE_CS_JIS)
return(jis_cs_strcat(targ, src));
#else
return(ascii_cs_strcat(targ, src));
#endif
}
int rtfs_cs_strcmp(byte * s1, byte * s2, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
return(unicode_cs_strcmp(s1, s2));
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
#if (INCLUDE_CS_JIS)
return(jis_cs_strcmp(s1, s2));
#else
return(ascii_cs_strcmp(s1, s2));
#endif
}
int rtfs_cs_strcpy(byte * targ, byte * src, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
return(unicode_cs_strcpy(targ, src));
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
#if (INCLUDE_CS_JIS)
return(jis_cs_strcpy(targ, src));
#else
return(ascii_cs_strcpy(targ, src));
#endif
}
int rtfs_cs_strlen(byte * string, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
return(unicode_cs_strlen(string));
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
#if (INCLUDE_CS_JIS)
return(jis_cs_strlen(string));
#else
return(ascii_cs_strlen(string));
#endif
}
void pc_cs_ascii_str2upper(byte *to, byte *from)
{
#if (INCLUDE_CS_JIS)
pc_jis_str2upper(to, from);
#else
pc_ascii_str2upper(to, from);
#endif
}
void pc_cs_ascii_strn2upper(byte *to, byte *from, int n)
{
#if (INCLUDE_CS_JIS)
pc_jis_strn2upper(to, from, n);
#else
pc_ascii_strn2upper(to, from, n);
#endif
}
#if (INCLUDE_VFAT && !RTFS_CFG_READONLY) /* Excluded from build if read only */
BOOLEAN pc_cs_malias(byte *alias, byte *input_file, int which_try, int use_charset)
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
return (pc_unicode_malias(alias, input_file, which_try));
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
#if (INCLUDE_CS_JIS)
return (pc_jis_malias(alias, input_file, which_try));
#else
return (pc_ascii_malias(alias, input_file, which_try));
#endif
}
#endif
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
BOOLEAN pc_cs_valid_sfn(byte *filename, BOOLEAN case_sensitive)
{
#if (INCLUDE_CS_JIS)
return(jis_valid_sfn(filename, case_sensitive));
#else
return(ascii_valid_sfn(filename, case_sensitive));
#endif
}
#endif
#if (INCLUDE_VFAT) /* Small piece of compile time INCLUDE_VFAT vs's NONVFAT code */
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
BOOLEAN pc_cs_validate_filename(byte * name, byte * ext, int use_charset) /*__fn__*/
{
#if (INCLUDE_CS_UNICODE)
if (use_charset == CS_CHARSET_UNICODE)
return(pc_unicode_validate_filename(name, ext));
#else
RTFS_ARGSUSED_INT(use_charset);
#endif
#if (INCLUDE_CS_JIS)
return(pc_jis_validate_filename(name, ext));
#else
return(pc_ascii_validate_filename(name, ext));
#endif
}
#endif
#endif
#if (!INCLUDE_VFAT) /* Small piece of compile time INCLUDE_VFAT vs's NONVFAT code */
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
BOOLEAN pc_cs_validate_8_3_name(byte * name,int len) /*__fn__*/
{
#if (INCLUDE_CS_JIS)
return(pc_jis_validate_8_3_name(name,len));
#else
return(pc_ascii_validate_8_3_name(name,len));
#endif
}
BOOLEAN pc_cs_validate_filename(byte * name, byte * ext, int use_charset) /*__fn__*/
{
byte sfn_buffer[14]; /* Only uses 13 but keep declarations even */
RTFS_ARGSUSED_INT(use_charset);
if (!(pc_cs_validate_8_3_name(name,8) && pc_cs_validate_8_3_name(ext,3)) )
return(FALSE);
pc_cs_mfile(sfn_buffer, name, ext, CS_CHARSET_NOT_UNICODE);
/* Check for valid file name, ignore case */
return (pc_cs_valid_sfn(sfn_buffer, FALSE));
}
#endif /* #if (!RTFS_CFG_READONLY) */
BOOLEAN rtfs_cs_patcmp_8(byte *p, byte *pattern, BOOLEAN dowildcard)
{
#if (INCLUDE_CS_JIS)
return(pc_jis_patcmp_8(p, pattern,dowildcard));
#else
return(pc_ascii_patcmp_8(p, pattern,dowildcard));
#endif
}
BOOLEAN rtfs_cs_patcmp_3(byte *p, byte *pattern, BOOLEAN dowildcard)
{
#if (INCLUDE_CS_JIS)
return(pc_jis_patcmp_3(p, pattern,dowildcard));
#else
return(pc_ascii_patcmp_3(p, pattern,dowildcard));
#endif
}
#endif

453
rtfscommon/source/csjisrd.c Normal file
View File

@ -0,0 +1,453 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 2002
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* JIS.C - Contains Japanese string manipulation and character conversion routines */
/* See also jistab.c */
#include "rtfs.h"
#if (INCLUDE_CS_JIS)
static byte * rtfs_jis_strcat(byte * targ, byte * src);
static int rtfs_jis_strcpy(byte * targ, byte * src);
static void pc_jis_byte2upper(byte *to, byte *from);
int jis_compare(byte *p1, byte *p2);
byte *jis_increment(byte *p);
int jis_char_length(byte *p);
/* compares 2 strings; returns 0 if they match */
int jis_cs_strcmp(byte * s1, byte * s2) /*__fn__*/
{
while (*s1 && *s2)
{
if (!jis_compare(s1, s2))
return(1);
s1 = jis_increment(s1);
s2 = jis_increment(s2);
}
if (!*s1 && !*s2)
return(0);
else
return(1);
}
byte * jis_cs_strcat(byte * targ, byte * src) /*__fn__*/
{
/* Call the byte oriented function */
return(rtfs_jis_strcat(targ, src));
}
/* This works because JIS has no ZERO in hi byte of 16 bit jis chars */
int jis_cs_strcpy(byte * targ, byte * src)
{
/* Call the byte oriented function */
return (rtfs_jis_strcpy(targ, src));
}
/* return number of jis chars in a string */
int jis_cs_strlen(byte * string) /*__fn__*/
{
int len=0;
while (*string)
{
string = jis_increment(string);
len++;
}
return len;
}
/* Macros here */
byte *jis_goto_eos(byte *p)
{
while (*p)
p = jis_increment(p);
return(p);
}
int jis_ascii_index(byte *p, byte base)
{
byte c;
pc_jis_byte2upper(&c, p);
return((int) (c - base));
}
int jis_compare_nc(byte *p1, byte *p2)
{
byte c,d;
if (jis_compare(p1, p2))
return(1);
else if (jis_char_length(p1)==1 && jis_char_length(p2)==1)
{
pc_jis_byte2upper(&c, p1);
pc_jis_byte2upper(&d, p2);
return(c == d);
}
else
return(0);
}
void pc_jis_strn2upper(byte *to, byte *from, int n) /* __fn__*/
{
int i;
byte c;
for (i = 0; i < n; i++)
{
if (jis_char_length(from) == 2)
{
*to++ = *from++;
*to++ = *from++;
}
else
{
c = *from++;
if ((c >= 'a') && (c <= 'z'))
c = (byte) ('A' + c - 'a');
*to++ = c;
}
}
}
/* Return the length of a JIS character, 1 or 2 */
int jis_char_length(byte *p)
{
if ((*p >= 0x81 && *p <= 0x9f) || (*p >= 0xe0 && *p <= 0xfc))
return(2);
else
return(1);
}
/* Copy JIS character, 1 or 2 bytes */
int jis_char_copy(byte *to, byte *from)
{
int len;
len = jis_char_length(from);
*to++ = *from++;
if (len == 2)
*to++ = *from++;
return(len);
}
/* Advance a pointer to the next JIS character in a string */
byte *jis_increment(byte *p)
{
return(p + jis_char_length(p));
}
/* return number of jis chars in a string */
/* Return 1 if p1 and p2 are the same */
int jis_compare(byte *p1, byte *p2)
{
/* If 1st char same and (len is 1 or 2nd char the same */
return ( (*p1 == *p2) && (jis_char_length(p1)==1 || (*(p1+1) == *(p2+1))) );
}
void pc_jis_str2upper(byte *to, byte *from) /* __fn__*/
{
byte c;
while(*from)
{
if (jis_char_length(from) == 2)
{
*to++ = *from++;
*to++ = *from++;
}
else
{
c = *from++;
if ((c >= 'a') && (c <= 'z'))
c = (byte) ('A' + c - 'a');
*to++ = c;
}
}
*to = '\0';
}
/***************************************************************************
PC_MFILE - Build a file spec (xxx.yyy) from a file name and extension
Description
Fill in to with a concatenation of file and ext. File and ext are
not assumed to be null terminated but must be blank filled to [8,3]
chars respectively. 'to' will be a null terminated string file.ext.
ASCII character function only. Unicode not required
Returns
A pointer to 'to'.
****************************************************************************/
byte *jis_cs_mfile(byte *to, byte *filename, byte *ext, byte ntflags)
{
byte *p;
int i,l;
byte *retval = to;
/* ntflags specify if basename and/0r ext should be stired in lower case. Bit 4 (0x10) means lowercase extension and bit 3 (0x8) lowercase basename
if the lowercase bit is set or in 0x20 to ascii letter to force lower case */
byte extcasemask,namecasemask;
extcasemask = (ntflags & 0x10);
namecasemask= (ntflags & 0x08);
p = filename;
i = 0;
while(*p)
{
l = jis_char_length(p);
if (*p == ' ')
break;
else
{
byte c;
if (l == 2)
{
if (i>6)
break;
*to++ = *p++;
c=*p++;
}
else
{
c=*p++;
c=CS_APPLY_NT_CASEMASK(namecasemask,c); /* Convert to lower case if NT flags in DOS inode specified. */
}
*to++ = c;
i += l;
}
if (i == 8)
break;
}
if (p != filename)
{
p = ext;
if (*p && *p != ' ')
*to++ = '.';
i = 0;
while(p && *p)
{
l = jis_char_length(p);
if (*p == ' ')
break;
else
{
byte c;
if (l == 2)
{
if (i>1)
break;
*to++ = *p++;
c=*p++;
}
else
{
c=*p++;
c=CS_APPLY_NT_CASEMASK(extcasemask,c); /* Convert to lower case if NT flags in DOS inode specified. */
}
*to++ = c;
i += l;
}
if (i == 3)
break;
}
}
*to = '\0';
return (retval);
}
/***************************************************************************
PC_FILEPARSE - Parse a file xxx.yyy into filename/pathname
Description
Take a file named XXX.YY and return SPACE padded NULL terminated
filename [XXX ] and fileext [YY ] components. If the name or ext are
less than [8,3] characters the name/ext is space filled and null termed.
If the name/ext is greater than [8,3] the name/ext is truncated. '.'
is used to seperate file from ext, the special cases of . and .. are
also handled.
Returns
Returns TRUE
****************************************************************************/
/* Take a string xxx[.yy] and put it into filename and fileext */
/* Note: add a check legal later */
BOOLEAN pc_jis_fileparse(byte *filename, byte *fileext, byte *p) /* __fn__*/
{
int i;
int l;
/* Defaults */
rtfs_memset(filename, ' ', 8);
filename[8] = '\0';
rtfs_memset(fileext, ' ', 3);
fileext[3] = '\0';
/* Special cases of . and .. */
if (*p == '.')
{
*filename = '.';
if (*(p+1) == '.')
{
*(++filename) = '.';
return (TRUE);
}
else if (*(p + 1) == '\0')
return (TRUE);
else
return (FALSE);
}
i = 0;
while (*p)
{
l = jis_char_length(p);
if (*p == '.')
{
p++;
break;
}
else
{
if (i + l <= 8)
{
jis_char_copy(filename, p);
filename += l;
i += l;
}
p += l;
}
}
i = 0;
while (*p)
{
l = jis_char_length(p);
if (i + l <= 3)
{
jis_char_copy(fileext, p);
fileext += l;
i += l;
}
p += l;
}
return (TRUE);
}
static int rtfs_jis_strcpy(byte * targ, byte * src) /*__fn__*/
{
int loop_cnt=0;
do
{
targ[loop_cnt] = src[loop_cnt];
} while(src[loop_cnt++]);
return loop_cnt;
}
/* This works because JIS has no ZERO in hi byte of 16 bit jis chars */
static byte * rtfs_jis_strcat(byte * targ, byte * src) /*__fn__*/
{
byte *pappend;
pappend = jis_goto_eos(targ);
rtfs_jis_strcpy(pappend, src);
return targ;
}
static void pc_jis_byte2upper(byte *to, byte *from)
{
byte c;
c = *from;
if ((c >= 'a') && (c <= 'z'))
c = (byte) ('A' + c - 'a');
*to = c;
}
#if (!INCLUDE_VFAT) /* Small piece of compile time INCLUDE_VFAT vs's NONVFAT code */
BOOLEAN pc_jis_patcmp_8(byte *p, byte *pattern, BOOLEAN dowildcard) /* __fn__*/
{
int size = 8;
byte save_char;
byte *save_p;
BOOLEAN ret_val;
/* never match a deleted file */
if (*p == PCDELETE)
return (FALSE);
save_p = p;
save_char = *p;
if(save_char == 0x05)
*p = 0xe5; /* JIS KANJI char */
ret_val = TRUE;
while (size > 0)
{
if(dowildcard)
{
if (*pattern == '*') /* '*' matches the rest of the name */
goto ret;
if (*pattern != '?' && !jis_compare_nc(pattern,p))
{
ret_val = FALSE;
goto ret;
}
}
else
{
if (!jis_compare_nc(pattern,p))
{
ret_val = FALSE;
goto ret;
}
}
size -= jis_char_length(p);
p = jis_increment(p);
pattern = jis_increment(pattern);
}
ret:
*save_p = save_char;
return(ret_val);
}
BOOLEAN pc_jis_patcmp_3(byte *p, byte *pattern, BOOLEAN dowildcard) /* __fn__*/
{
int size = 3;
BOOLEAN ret_val;
ret_val = TRUE;
while (size > 0)
{
if(dowildcard)
{
if (*pattern == '*') /* '*' matches the rest of the name */
goto ret;
if (*pattern != '?' && !jis_compare_nc(pattern,p))
{
ret_val = FALSE;
goto ret;
}
}
else
{
if (!jis_compare_nc(pattern,p))
{
ret_val = FALSE;
goto ret;
}
}
size -= jis_char_length(p);
p = jis_increment(p);
pattern = jis_increment(pattern);
}
ret:
return(ret_val);
}
#endif
#endif

3982
rtfscommon/source/csjistab.c Normal file

File diff suppressed because it is too large Load Diff

421
rtfscommon/source/csjiswr.c Normal file
View File

@ -0,0 +1,421 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 2002
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* JIS.C - Contains Japanese string manipulation and character conversion routines */
/* See also jistab.c */
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
#if (INCLUDE_CS_JIS)
static BOOLEAN _illegal_jis_alias_char(byte *p);
#if (INCLUDE_VFAT)
static BOOLEAN _illegal_jis_lfn_char(byte *p);
#endif
byte *jis_increment(byte *p);
int jis_char_length(byte *p);
/* Return TRUE if illegal for an 8 dot 3 file */
static BOOLEAN _illegal_jis_file_char(byte *p, int islfn)
{
byte c;
/* {[0-80(asci)][81-9f(2byte)][a0{illegal)][a1-df(Katakana)][e0-fc(2byte)][fd-ff{illegal)] */
if (jis_char_length(p) == 1)
{
c = *p;
/* Test for valid chars. Note: we accept lower case because that
is patched in pc_ino2dos() at a lower level */
if ( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') )
return(FALSE); /* Valid */
if (c >= 0xa1 && c <= 0xdf) /* Katakana */
return(FALSE); /* Valid */
if (islfn)
return (_illegal_lfn_char(c)); /* same as ascii */
return (_illegal_alias_char(c)); /* same as ascii */
}
else /* length is 2 */
{
p++;
c = *p;
if (c >= 0x40 && c <= 0x7e)
return(FALSE); /* Valid */
if (c >= 0x80 && c <= 0xfc)
return(FALSE); /* Valid */
return(TRUE); /* Invalid */
}
}
/* Return TRUE if illegal for an 8 dot 3 file */
static BOOLEAN _illegal_jis_alias_char(byte *p)
{
return(_illegal_jis_file_char(p, 0));
}
/*****************************************************************************
PC_VALID_SFN - See if filename is a valid short file name
Description
Determines validity of a short file name based on the following criteria:
- the file name must be between 0 and 8 characters
- the file extension must be between 0 and 3 characters
- the file name must not begin with a period
- it must not be a reserved DOS file name
- it must not contain any characters that are illegal within sfn's
Returns
TRUE if filename is a valid sfn, FALSE otherwise
*****************************************************************************/
BOOLEAN jis_valid_sfn(byte *filename, BOOLEAN case_sensitive) /* __fn__ */
{
int len,period_count,ext_start;
BOOLEAN badchar;
byte name_part[9];
int char_len;
byte *pname;
if(name_is_reserved(filename)) return(FALSE);
pname = filename;
len = 0;
badchar=FALSE;
period_count=0;
ext_start=0;
name_part[0] = 0;
while(*pname)
{
if(_illegal_jis_alias_char(pname)) badchar = TRUE;
if(*pname == '.')
{
ext_start = len+1;
period_count++;
}
char_len = jis_char_length(pname);
if (!ext_start && len < 8)
{
if (char_len == 2) /* end the test name for reserved */
name_part[len] = 0;
else
name_part[len] = *pname;
name_part[len+1] = 0;
}
if (case_sensitive && char_len == 1 && (*pname >= (byte) 'a' && *pname <= (byte) 'z'))
badchar = TRUE;
pname += char_len;
len += char_len;
}
if(name_is_reserved(name_part)) return(FALSE);
if( (filename[0] == ' ') || /* 1st char is a space */
(len == 0) || /* no name */
badchar || /* contains illegal chars */
(period_count > 1) || /* contains more than one extension */
((len-ext_start)>3 && period_count>0) || /* extension is longer than 3 chars */
(period_count==0 && len > 8) || /* name is longer than 8 chars */
(ext_start > 9) || /* name is longer than 8 chars */
(ext_start==1) ) return(FALSE); /* no name; 1st char is a period */
return(TRUE);
}
#if (INCLUDE_VFAT) /* Small piece of compile time INCLUDE_VFAT vs's NONVFAT code */
static BOOLEAN _illegal_jis_lfn_char(byte *p)
{
return(_illegal_jis_file_char(p, 1));
}
/***************************************************************************
validate_filename - See if filename is a valid long file name
Description
Determines validity of a long file name based on the following criteria:
- the file must be between 0 and 256 characters in length
- it must not be a reserved DOS file name
- it must not contain any characters that are illegal within lfn's
Returns
TRUE if filename is a valid lfn, FALSE otherwise
*****************************************************************************/
BOOLEAN pc_jis_validate_filename(byte * filename, byte * ext)
{
int len;
byte name_part[9];
RTFS_ARGSUSED_PVOID((void *) ext);
for(len=0; *filename; len++)
{
if (_illegal_jis_lfn_char(filename))
return(FALSE);
if (len < 5) /* handles lpt1, aux, con etc */
{
if(*filename == '.')
{
name_part[len] = 0;
if(name_is_reserved(name_part)) return(FALSE);
}
else
{
name_part[len] = *filename;
if (*(filename+1) == 0)
{
name_part[len+1] = 0;
if(name_is_reserved(name_part)) return(FALSE);
}
}
}
filename = jis_increment(filename);
}
if( (len == 0) || (len > 255) ) return(FALSE);
return(TRUE);
}
/* JIS Version */
BOOLEAN pc_jis_malias(byte *alias, byte *input_file, int which_try) /*__fn__*/
{
int n,s;
byte filename[10],fileext[4];
byte *p_in, *p_in_ext, *p_temp, *p_temp_2;
int char_len, jis_ext_len;
/* Fill filename[8] with spaces before we start. */
rtfs_memset(filename, ' ', 8);
/* Check if invalid short file name. Ignore case. If contains lower case we'll fix it later ! */
if ((which_try == -1) && !pc_cs_valid_sfn((byte *)input_file, FALSE))
return(FALSE);
/* Process the JIS alias name */
p_in = input_file;
while(*p_in =='.' || *p_in ==' ') p_in = jis_increment(p_in);
/* find extension start */
/* p_in_ext holds the position right */
/* after the last period (or it is 0 */
p_in_ext = 0;
p_temp = p_in;
while(*p_temp)
{
if (*p_temp =='.')
{
p_temp = jis_increment(p_temp);
p_in_ext = p_temp;
}
else
p_temp = jis_increment(p_temp);
}
p_temp_2 = &fileext[0];
jis_ext_len = 0; /* We'll use this later to append ext to alias */
if(p_in_ext && *p_in_ext!=0){
/* copy extension to fileext[] */
p_temp = p_in_ext;
for(s=0; *p_temp!=0 && s<3;p_temp+=char_len)
{
char_len = jis_char_length(p_temp);
if(*p_temp!=' ')
{
/* finish if 2 bite jis overflows 3 */
if(s==2&&char_len==2)
{
break;
}
/* use '_' if illegal*/
else if(_illegal_jis_alias_char(p_temp))
{
*p_temp_2++ = '_';
s += 1;
}
else
{
*p_temp_2++ = *p_temp;
if (char_len==2)
*p_temp_2++ = *(p_temp+1);
s += char_len;
}
}
}
jis_ext_len = s; /* Save for later. bytes in */
}
*p_temp_2 = 0; /* NULL terminate extention */
/* copy file name to filename[], filtering out spaces, periods and
replacing characters illegal in alias names with '_' */
p_temp = input_file;
p_temp_2 = filename;
for(s=0; *p_temp!=0 && s<8; p_temp += char_len)
{
if (p_in_ext && p_temp>=p_in_ext) /* hit extension ? */
break;
char_len = jis_char_length(p_temp);
/* break and use ' ' if 2 bite jis overflows 8 character limit */
/* Bug fix 2-1-07 , was if(s==5&&char_len==2) */
if(s==7&&char_len==2)
{
filename[7] = ' '; /* shift-jis first bytes clear */
break;
}
else if(*p_temp!=' ' && *p_temp !='.')
{
if(_illegal_jis_alias_char(p_temp))
{
*p_temp_2++ = '_';
s += 1;
}
else
{
*p_temp_2++ = *p_temp;
if (char_len==2)
*p_temp_2++ = *(p_temp+1);
s += char_len;
}
}
}
/* Null terminate the file at length 8, the alias digits will be right justified in
file name and the result will be copied, stripping out spaces */
filename[8]=0;
pc_cs_ascii_str2upper(filename,filename);
pc_cs_ascii_str2upper(fileext,fileext);
/* append (TEXT[])i to filename[] */
if (which_try != -1)
{
/* June 2013 - Change integrated at the suggestion of AI corp. ifed out version failed in certain situations */
#if (0)
for(n=7,s=which_try; s>0 && n>0; s/=10,n--)
{
filename[n] = (byte)(((byte)s%10)+'0');
}
if(n==0 && s>0)
return(FALSE);
else
filename[n]='~';
#else
int l;
for (l=0,s=which_try; s>0; s/=10,l++);
if (l > 6) return(FALSE);
for (n=0; n<8; n++) {
char_len = jis_char_length(&filename[n]);
if (char_len == 2) {
if ((n+1) == (7-l)) {
filename[n] = '~';
filename[7] = ' ';
n = 6;
break;
} else if (n == (7-l)) {
filename[n] = '~';
n = 7;
break;
}
n++;
} else {
if (n == (7-l)) {
filename[n] = '~';
n = 7;
break;
}
}
}
for(s=which_try; s>0 && n>0; s/=10,n--)
{
filename[n] = (byte)(((byte)s%10)+'0');
}
#endif
}
p_temp_2 = alias;
p_temp = filename;
/* copy filename[] to alias[], filtering out spaces */
s = 0;
while(*p_temp)
{
char_len = jis_char_length(p_temp);
if (s == 7 && char_len == 2)
break;
if(*p_temp!=' ')
{
*p_temp_2++=*p_temp++;
if (char_len == 2)
*p_temp_2++=*p_temp++;
s += char_len;
if (s == 8)
break;
}
else
p_temp++;
}
if(jis_ext_len != 0)
{
*p_temp_2++='.'; /* insert separating period */
/* copy fileext[] to alias[] */
for(s=0; s < jis_ext_len; s++)
{
*p_temp_2++ = fileext[s];
}
}
*p_temp_2=0; /* null terminate alias[] */
return(TRUE);
}
#endif
#if (!INCLUDE_VFAT) /* Small piece of compile time INCLUDE_VFAT vs's NONVFAT code */
BOOLEAN pc_jis_validate_8_3_name(byte * name,int len) /*__fn__*/
{
int i;
int last;
last = len-1;
for (i = 0; i < len; i++)
{
/* If we hit a space make sure the rest of the string is spaces */
if (name[i] == ' ')
{
for (; i < len; i++)
{
if (name[i] != ' ')
return(FALSE);
}
break;
}
else
{
if (_illegal_jis_alias_char(&name[i]))
return(FALSE);
/* If it is a 2 byte char advance i */
if (jis_char_length(&name[i])==2)
{
if (i == last)
return(FALSE); /* two byte at the end. no good */
i++;
}
}
}
return(TRUE);
}
#endif
#endif
#endif /* Exclude from build if read only */

View File

@ -0,0 +1,9 @@
#include "rtfs.h"
/* “MSWIN4.1”, is the recommended setting, because it is the setting least likely to cause compatibility problems. */
KS_CONSTANT byte * pustring_sys_oemname = (byte *) "MSWIN4.1";
KS_CONSTANT byte * pustring_sys_volume_label = (byte *) "VOLUMELABEL";
KS_CONSTANT byte * pustring_sys_badlfn = (byte *) "\\/:*?\"<>|";
KS_CONSTANT byte * pustring_sys_badalias = (byte *) "\\/:*?\"<>| ,;=+[]";
KS_CONSTANT byte * pustring_sys_ucreserved_names = (byte *) "CON,PRN,NUL,AUX,LPT1,LPT2,LPT3,LPT4,COM1,COM2,COM3,COM4";
KS_CONSTANT byte * pustring_sys_lcreserved_names = (byte *) "con,prn,nul,aux,lpt1,lpt2,lpt3,lpt4,com1,com2,com3,com4";

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,168 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* PRBASICEMU.C - Emulate RTFS Basic API Routines in RtfsProPlus */
#include "rtfs.h"
#if (INCLUDE_BASIC_POSIX_EMULATION)
int pc_bfilio_fstat(int fd, ERTFS_STAT *pstat);
int pc_bfilio_close(int fd);
BOOLEAN pc_bfilio_ulseek(int fd, dword offset, dword *pnew_offset, int origin);
int pc_bfilio_read(int fd, byte *in_buff, int count);
int pc_bfilio_open_cs(byte *name, word flag, word mode, int use_charset);
int pc_bfilio_fstat(int fd, ERTFS_STAT *pstat);
#endif
#if (INCLUDE_CS_UNICODE)
int po_open_cs(byte *name, word flag, word mode, int use_charset)
#else
int po_open(byte *name, word flag, word mode)
#endif
{
#if (INCLUDE_BASIC_POSIX_EMULATION)
#if (INCLUDE_CS_UNICODE)
return(pc_bfilio_open_cs(name, flag, mode, CS_CHARSET_ARGS));
#else
return(pc_bfilio_open_cs(name, flag, mode, CS_CHARSET_NOT_UNICODE));
#endif
#else
EFILEOPTIONS basic_options;
rtfs_memset(&basic_options, 0, sizeof(basic_options));
basic_options.allocation_policy = PCE_LOAD_AS_NEEDED;
#if (INCLUDE_CS_UNICODE)
return(pc_efilio_open_cs(name, flag, mode, &basic_options, CS_CHARSET_ARGS));
#else
return(pc_efilio_open(name, flag, mode, &basic_options));
#endif
#endif
}
int po_read(int fd, byte *in_buff, int count) /*__apifn__*/
{
if (!count)
{
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__);
return(-1);
}
#if (INCLUDE_BASIC_POSIX_EMULATION)
return (pc_bfilio_read(fd, in_buff, count));
#else
{
dword nread, count_dw;
count_dw = (dword) count;
if (pc_efilio_read(fd, in_buff, count_dw, &nread))
{
return((int)nread);
}
else
return(-1);
}
#endif
}
long po_lseek(int fd, long offset, int origin) /*__apifn__*/
{
dword offset_dw, newoffset_lo;
#if (!INCLUDE_BASIC_POSIX_EMULATION)
dword newoffset_hi;
#endif
if (origin == PSEEK_SET) /* offset from beginning of file */
{
if (offset < 0)
{
/* Negative seek from beginning is an error */
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__); /* Set it to illegal, it should be cleared */
return(-1L);
}
}
else if (origin == PSEEK_CUR) /* offset from current file pointer */
{
if (offset < 0)
{
origin = PSEEK_CUR_NEG;
offset *= -1;
}
}
else if (origin == PSEEK_END) /* offset from end of file */
{
if (offset <= 0)
{
offset *= -1;
}
else
{
/* Positive seek from end is an error */
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__); /* Set it to illegal, it should be cleared */
return(-1L);
}
}
offset_dw = (dword) offset;
#if (INCLUDE_BASIC_POSIX_EMULATION)
if (!pc_bfilio_ulseek(fd, offset_dw, &newoffset_lo, origin))
#else
if (!pc_efilio_lseek(fd, 0, offset_dw, origin, &newoffset_hi, &newoffset_lo))
#endif
return(-1);
else
return((long) newoffset_lo);
}
#if (INCLUDE_MATH64)
ddword pc_bfilio_lseek64(int fd, ddword offset, int origin);
ddword po_lseek64(int fd, ddword offset, int origin)
{
#if (INCLUDE_BASIC_POSIX_EMULATION)
return(pc_bfilio_lseek64(fd, offset, origin));
#else
return pc_efilio_lseek64(fd, offset, origin);
#endif
}
#endif
BOOLEAN po_ulseek(int fd, dword offset, dword *pnew_offset, int origin) /*__apifn__*/
{
#if (INCLUDE_BASIC_POSIX_EMULATION)
return(pc_bfilio_ulseek(fd, offset, pnew_offset, origin));
#else
dword newoffset_hi;
return(pc_efilio_lseek(fd, 0, offset, origin, &newoffset_hi, pnew_offset));
#endif
}
int po_close(int fd) /*__apifn__*/
{
#if (INCLUDE_BASIC_POSIX_EMULATION)
return(pc_bfilio_close(fd));
#else
if (pc_efilio_close(fd))
return(0);
else
return(-1);
#endif
}
int pc_fstat(int fd, ERTFS_STAT *pstat) /*__apifn__*/
{
#if (INCLUDE_BASIC_POSIX_EMULATION)
return(pc_bfilio_fstat(fd, pstat));
#else
ERTFS_EFILIO_STAT estat;
if (!pc_efilio_fstat(fd, &estat))
return(-1);
else
{
*pstat = estat.stat_struct;
return(0);
}
#endif
}

View File

@ -0,0 +1,75 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* PRBASICEMU.C - Emulate RTFS Basic API Routines in RtfsProPlus */
#include "rtfs.h"
#define INCLUDE_BASIC_IO 1
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
#if (INCLUDE_BASIC_POSIX_EMULATION)
int pc_bfilio_write(int fd, byte *buf, int count);
BOOLEAN pc_bfilio_flush(int fd);
BOOLEAN pc_bfilio_chsize(int fd, dword offset);
#endif
int po_write(int fd, byte *buf, int count) /*__apifn__*/
{
#if (INCLUDE_BASIC_POSIX_EMULATION)
return(pc_bfilio_write(fd, buf, count));
#else
dword nwritten, count_dw;;
count_dw = (dword) count;
if (pc_efilio_write(fd, buf, count_dw, &nwritten))
{
return((int)nwritten);
}
else
return(-1);
#endif
}
BOOLEAN po_flush(int fd) /*__apifn__*/
{
#if (INCLUDE_BASIC_POSIX_EMULATION)
return(pc_bfilio_flush(fd));
#else
return(pc_efilio_flush(fd));
#endif
}
BOOLEAN po_truncate(int fd, dword offset)
{
#if (INCLUDE_BASIC_POSIX_EMULATION)
return(pc_bfilio_chsize(fd, offset));
#else
return(pc_efilio_chsize(fd, 0, offset));
#endif
}
int po_chsize(int fd, dword offset) /*__apifn__*/
{
#if (INCLUDE_BASIC_POSIX_EMULATION)
if (!pc_bfilio_chsize(fd, offset))
return(-1);
else
return(0);
#else
if (!pc_efilio_chsize(fd, 0, offset))
return(-1);
else
return(0);
#endif
}
#endif /* Exclude from build if read only */

View File

@ -0,0 +1,817 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* RTDBLOCK.C - ERTFS-PRO and ProPlus Directory and scrath block buffering routines */
#include "rtfs.h"
static void pc_add_blk(BLKBUFFCNTXT *pbuffcntxt, BLKBUFF *pinblk);
static void pc_release_blk(BLKBUFFCNTXT *pbuffcntxt, BLKBUFF *pinblk);
/* Debugging tools to be removed in he final product */
#define DEBUG_BLOCK_CODE 0
void debug_check_blocks(BLKBUFFCNTXT *pbuffcntxt, int numblocks, char *where, dword line);
void debug_check_fat(FATBUFFCNTXT *pfatbuffcntxt, char *where);
void debug_break(char *where, dword line, char *message);
#if (DEBUG_BLOCK_CODE)
#define DEBUG_CHECK_BLOCKS(X,Y,Z) debug_check_blocks(X,Y,Z,0);
#else
#define DEBUG_CHECK_BLOCKS(X,Y,Z)
#endif
BOOLEAN block_devio_read(DDRIVE *pdrive, dword blockno, byte * buf)
{
#if (INCLUDE_FAILSAFE_RUNTIME)
if (prtfs_cfg->pfailsafe)
return(prtfs_cfg->pfailsafe->block_devio_read(pdrive, blockno, buf));
#endif
UPDATE_RUNTIME_STATS(pdrive, dir_buff_reads, 1)
return(raw_devio_xfer(pdrive, blockno, buf, 1, FALSE, TRUE));
}
/* Multi block transfer to the block or fat area */
BOOLEAN block_devio_xfer(DDRIVE *pdrive, dword blockno, byte * buf, dword n_to_xfer, BOOLEAN reading)
{
#if (INCLUDE_FAILSAFE_RUNTIME)
if (prtfs_cfg->pfailsafe)
return(prtfs_cfg->pfailsafe->block_devio_xfer(pdrive, blockno, buf, n_to_xfer, reading));
#endif
#if (INCLUDE_DEBUG_RUNTIME_STATS)
if (reading)
{
UPDATE_RUNTIME_STATS(pdrive, dir_direct_reads, 1)
UPDATE_RUNTIME_STATS(pdrive, dir_direct_blocks_read, n_to_xfer)
}
else
{
UPDATE_RUNTIME_STATS(pdrive, dir_direct_writes, 1)
UPDATE_RUNTIME_STATS(pdrive, dir_direct_blocks_written, n_to_xfer)
}
#endif
return(raw_devio_xfer(pdrive, blockno, buf, n_to_xfer, FALSE, reading));
}
/*****************************************************************************
pc_release_buf - Unlock a block buffer.
Description
Give back a buffer to the system buffer pool so that it may
be re-used. If was_err is TRUE this means that the data in the
buffer is invalid so discard the buffer from the buffer pool.
Returns
Nothing
***************************************************************************/
void pc_release_buf(BLKBUFF *pblk)
{
if (!pblk)
return;
DEBUG_CHECK_BLOCKS(pblk->pdrive->pbuffcntxt, pblk->pdrive->pbuffcntxt->num_blocks, "Release")
ERTFS_ASSERT(chk_mount_valid(pblk->pdrive))
ERTFS_ASSERT(pblk->block_state == DIRBLOCK_UNCOMMITTED)
if (pblk->block_state != DIRBLOCK_UNCOMMITTED)
return;
OS_CLAIM_FSCRITICAL()
if (pblk->use_count)
{
pblk->use_count -= 1;
/* 03-07-07 Changed. No longer increment num_free if usecount goes to zero */
}
OS_RELEASE_FSCRITICAL()
}
/*****************************************************************************
pc_discard_buf - Put a buffer back on the free list.
Description
Check if a buffer is in the buffer pool, unlink it from the
buffer pool if it is.
Put the buffer on the free list.
Returns
Nothing
***************************************************************************/
void pc_discard_buf(BLKBUFF *pblk)
{
BLKBUFFCNTXT *pbuffcntxt;
if (!pblk)
return;
/*note:pblk->pdrive must not be 0. if so, use pc_free_scratch_buffer() */
ERTFS_ASSERT(pblk->block_state != DIRBLOCK_FREE)
if (pblk->block_state == DIRBLOCK_FREE)
return;
OS_CLAIM_FSCRITICAL()
pbuffcntxt = pblk->pdrive->drive_state.pbuffcntxt;
DEBUG_CHECK_BLOCKS(pbuffcntxt, pbuffcntxt->num_blocks, "Discard 1")
if (pblk->block_state == DIRBLOCK_UNCOMMITTED)
{
/* Release it from the buffer pool */
pc_release_blk(pbuffcntxt, pblk);
/* If there's a next make sure we are the prev */
ERTFS_ASSERT(!pblk->pnext || (pblk->pnext->pprev == pblk))
/* If there's a prev make sure we're the next */
ERTFS_ASSERT(!pblk->pprev || (pblk->pprev->pnext == pblk))
/* Unlink it from the populated pool double check link integrity */
if (pblk->pnext && pblk->pnext->pprev == pblk)
pblk->pnext->pprev = pblk->pprev;
if (pblk->pprev && pblk->pprev->pnext == pblk)
pblk->pprev->pnext = pblk->pnext;
if (pbuffcntxt->ppopulated_blocks == pblk)
pbuffcntxt->ppopulated_blocks = pblk->pnext;
}
pblk->block_state = DIRBLOCK_FREE;
pblk->pnext = pbuffcntxt->pfree_blocks;
pbuffcntxt->num_free += 1;
pbuffcntxt->pfree_blocks = pblk;
OS_RELEASE_FSCRITICAL()
DEBUG_CHECK_BLOCKS(pbuffcntxt, pbuffcntxt->num_blocks, "Discard 2")
}
/****************************************************************************
PC_READ_BLK - Allocate and read a BLKBUFF, or get it from the buffer pool.
Description
Use pdrive and blockno to determine what block to read. Read the block
or get it from the buffer pool and return the buffer.
Note: After reading, you own the buffer. You must release it by
calling pc_release_buff() or pc_discard_buff() before it may be
used for other blocks.
Returns
Returns a valid pointer or NULL if block not found and not readable.
*****************************************************************************/
BLKBUFF *pc_read_blk(DDRIVE *pdrive, dword blockno) /*__fn__*/
{
BLKBUFF *pblk;
BLKBUFFCNTXT *pbuffcntxt;
if ( !pdrive || (blockno >= pdrive->drive_info.numsecs) )
return(0);
OS_CLAIM_FSCRITICAL()
DEBUG_CHECK_BLOCKS(pdrive->pbuffcntxt, pdrive->pbuffcntxt->num_blocks, "Read 1")
/* Try to find it in the buffer pool */
pblk = pc_find_blk(pdrive, blockno);
if (pblk)
{
UPDATE_RUNTIME_STATS(pdrive, dir_buff_hits, 1)
pdrive->drive_state.pbuffcntxt->stat_cache_hits += 1;
DEBUG_CHECK_BLOCKS(pdrive->drive_state.pbuffcntxt, pdrive->pbuffcntxt->num_blocks, "Read 2")
pblk->use_count += 1;
OS_RELEASE_FSCRITICAL()
}
else
{
pdrive->drive_state.pbuffcntxt->stat_cache_misses += 1;
/* Allocate, read, stitch into the populated list, and the buffer pool */
pblk = pc_allocate_blk(pdrive, pdrive->drive_state.pbuffcntxt);
OS_RELEASE_FSCRITICAL()
if (pblk)
{
if (block_devio_read(pdrive, blockno, pblk->data))
{
pbuffcntxt = pdrive->drive_state.pbuffcntxt;
pblk->use_count = 1;
pblk->block_state = DIRBLOCK_UNCOMMITTED;
pblk->blockno = blockno;
pblk->pdrive = pdrive;
/* Put in front of populated list (it's new) */
OS_CLAIM_FSCRITICAL()
pblk->pprev = 0;
pblk->pnext = pbuffcntxt->ppopulated_blocks;
if (pbuffcntxt->ppopulated_blocks)
pbuffcntxt->ppopulated_blocks->pprev = pblk;
pbuffcntxt->ppopulated_blocks = pblk;
pc_add_blk(pbuffcntxt, pblk); /* Add it to the buffer pool */
DEBUG_CHECK_BLOCKS(pdrive->pbuffcntxt, pdrive->pbuffcntxt->num_blocks, "Read 3")
OS_RELEASE_FSCRITICAL()
}
else
{
/* set errno to IO error unless devio set PEDEVICE */
if (!get_errno())
rtfs_set_errno(PEIOERRORREADBLOCK, __FILE__, __LINE__); /* pc_read_blk device read error */
pc_discard_buf(pblk);
DEBUG_CHECK_BLOCKS(pdrive->pbuffcntxt, pdrive->pbuffcntxt->num_blocks, "Read 4")
pblk = 0;
}
}
}
DEBUG_CHECK_BLOCKS(pdrive->pbuffcntxt, pdrive->pbuffcntxt->num_blocks, "Read 5")
return(pblk);
}
/***************************************************************************
PC_SYS_SECTOR - Return a buffer large enough to hold a sector for scratch purposes.
Description
Use the device driver to allocate a sector buffer. If the driver does not
have allocator support then allocate a scratch buffer.
When done call void pc_free_sys_sector(pblk) to clean up
Returns
Returns a blkbuf if one is available or NULL
****************************************************************************/
/* Allocate a scratch sector buffer */
BLKBUFF *pc_sys_sector(DDRIVE *pdr, BLKBUFF *pscratch_buff) /*__fn__*/
{
dword buffer_size_sectors;
if (!pdr)
return(0);
/* Zero the scratch buffer to be sure we can't possibly get a match */
rtfs_memset(pscratch_buff,(byte) 0, sizeof(*pscratch_buff));
/* dynamic drivers use the user buffer which will contain at least one sector */
pscratch_buff->data = pc_claim_user_buffer(pdr, &buffer_size_sectors, 1);
if (pscratch_buff->data)
{
pscratch_buff->pdrive = pdr;
pscratch_buff->pdrive_owner = pdr;
pscratch_buff->data_size_bytes = buffer_size_sectors * pdr->pmedia_info->sector_size_bytes;
return(pscratch_buff);
}
else
return(0);
}
/* Free a scratch sector, which may have been allocated by the driver or it may be a shared scratch block */
void pc_free_sys_sector(BLKBUFF *pscratch_buff)
{
/* pc_sys_sector() uses the user buffer so release it here */
pc_release_user_buffer(pscratch_buff->pdrive_owner, pscratch_buff->data);
}
/***************************************************************************
PC_SCRATCH_BLK - Return a block for scratch purposes.
Description
Use the block buffer pool as a heap of default sector sized memory locations
When done call void pc_free_scratch_buf(pblk) to clean up
Returns
Returns a blkbuf if one is available or NULL
****************************************************************************/
/* Allocate a scratch buffer from the shared (amongst drives) buffer pool */
BLKBUFF *pc_scratch_blk(void) /*__fn__*/
{
BLKBUFF *pblk;
OS_CLAIM_FSCRITICAL()
pblk = pc_allocate_blk(0, &prtfs_cfg->buffcntxt);
if (pblk)
{
pblk->pdrive_owner = 0;
prtfs_cfg->buffcntxt.scratch_alloc_count += 1;
#if (INCLUDE_DEBUG_LEAK_CHECKING)
{
BLKBUFFCNTXT *pbuffcntxt;
pbuffcntxt = &prtfs_cfg->buffcntxt;
pblk->pnext = pbuffcntxt->pscratch_blocks;
pbuffcntxt->pscratch_blocks = pblk;
}
#endif
}
OS_RELEASE_FSCRITICAL()
/* Remember the source for when we release it */
pblk->pdrive_owner = 0;
return (pblk);
}
/* Free a scratch buffer to the shared (amongst drives) buffer pool */
void pc_free_scratch_blk(BLKBUFF *pblk)
{
BLKBUFFCNTXT *pbuffcntxt;
OS_CLAIM_FSCRITICAL()
pbuffcntxt = &prtfs_cfg->buffcntxt;
#if (INCLUDE_DEBUG_LEAK_CHECKING)
if (pblk == pbuffcntxt->pscratch_blocks)
pbuffcntxt->pscratch_blocks = pblk->pnext;
else
{
BLKBUFF *pblk_scan;
pblk_scan = pbuffcntxt->pscratch_blocks;
while (pblk_scan)
{
if (pblk_scan->pnext == pblk)
{
pblk_scan->pnext = pblk->pnext;
break;
}
pblk_scan = pblk_scan->pnext;
}
}
#endif
pblk->pnext = pbuffcntxt->pfree_blocks;
pbuffcntxt->pfree_blocks = pblk;
pblk->block_state = DIRBLOCK_FREE;
pbuffcntxt->num_free += 1;
pbuffcntxt->scratch_alloc_count -= 1;
OS_RELEASE_FSCRITICAL()
}
/***************************************************************************
PC_INIT_BLK - Zero a BLKBUFF and add it to the buffer pool
Description
Allocate and zero a BLKBUFF and add it to the to the buffer pool.
Note: After initializing you own the buffer. You must release it by
calling pc_release_buff() or pc_discard_buf() before it may be used
for other blocks.
Returns
Returns a valid pointer or NULL if no core.
****************************************************************************/
BLKBUFF *pc_init_blk(DDRIVE *pdrive, dword blockno) /*__fn__*/
{
BLKBUFF *pblk;
BLKBUFFCNTXT *pbuffcntxt;
if ( !pdrive || (blockno >= pdrive->drive_info.numsecs) )
return(0);
/* Find it in the buffer pool */
OS_CLAIM_FSCRITICAL()
DEBUG_CHECK_BLOCKS(pdrive->pbuffcntxt, pdrive->pbuffcntxt->num_blocks, "Init 1")
pblk = pc_find_blk(pdrive, blockno);
if (pblk)
{
pblk->use_count += 1;
OS_RELEASE_FSCRITICAL()
}
else
{
/* Allocate, read, stitch into the populated list, and the buffer pool */
DEBUG_CHECK_BLOCKS(pdrive->pbuffcntxt, pdrive->pbuffcntxt->num_blocks, "Init 2")
pblk = pc_allocate_blk(pdrive, pdrive->drive_state.pbuffcntxt);
OS_RELEASE_FSCRITICAL()
if (pblk)
{
DEBUG_CHECK_BLOCKS(pdrive->pbuffcntxt, pdrive->pbuffcntxt->num_blocks-1, "Init 2_a")
pbuffcntxt = pdrive->drive_state.pbuffcntxt;
pblk->use_count = 1;
pblk->block_state = DIRBLOCK_UNCOMMITTED;
pblk->blockno = blockno;
pblk->pdrive = pdrive;
/* Put in front of populated list (it's new) */
OS_CLAIM_FSCRITICAL()
pblk->pprev = 0;
pblk->pnext = pbuffcntxt->ppopulated_blocks;
if (pbuffcntxt->ppopulated_blocks)
pbuffcntxt->ppopulated_blocks->pprev = pblk;
pbuffcntxt->ppopulated_blocks = pblk;
pc_add_blk(pbuffcntxt, pblk); /* Add it to the buffer pool */
OS_RELEASE_FSCRITICAL()
DEBUG_CHECK_BLOCKS(pdrive->pbuffcntxt, pdrive->pbuffcntxt->num_blocks, "Init 3")
}
}
if (pblk)
rtfs_memset(pblk->data, (byte) 0, pblk->data_size_bytes);
return(pblk);
}
/****************************************************************************
PC_FREE_ALL_BLK - Release all buffers associated with a drive
Description
Use pdrive to find all buffers in the buffer pool associated with the
drive. Mark them as unused, called by dsk_close.
If any are locked, print a debug message in debug mode to warn the
programmer.
Returns
Nothing
****************************************************************************/
void pc_free_all_blk(DDRIVE *pdrive) /*__fn__*/
{
BLKBUFFCNTXT *pbuffcntxt;
BLKBUFF *pblk;
BOOLEAN deleting;
if (!pdrive)
return;
pbuffcntxt = pdrive->drive_state.pbuffcntxt;
DEBUG_CHECK_BLOCKS(pbuffcntxt, pbuffcntxt->num_blocks, "Free all 1")
do
{
deleting = FALSE;
OS_CLAIM_FSCRITICAL()
pblk = pbuffcntxt->ppopulated_blocks;
while (pblk)
{
if (pblk->pdrive == pdrive)
{
OS_RELEASE_FSCRITICAL()
pc_discard_buf(pblk);
OS_CLAIM_FSCRITICAL()
deleting = TRUE;
break;
}
else
pblk = pblk->pnext;
}
OS_RELEASE_FSCRITICAL()
} while (deleting);
DEBUG_CHECK_BLOCKS(pbuffcntxt, pbuffcntxt->num_blocks, "Free all 2")
}
/* Add a block to the block buffer pool */
static void pc_add_blk(BLKBUFFCNTXT *pbuffcntxt, BLKBUFF *pinblk)
{
int hash_index;
hash_index = (int) (pinblk->blockno&BLOCK_HASHMASK);
pinblk->pnext2 = pbuffcntxt->blk_hash_tbl[hash_index];
pbuffcntxt->blk_hash_tbl[hash_index] = pinblk;
}
/* Remove a block from the block buffer pool */
static void pc_release_blk(BLKBUFFCNTXT *pbuffcntxt, BLKBUFF *pinblk)
{
int hash_index;
BLKBUFF *pblk;
hash_index = (int) (pinblk->blockno&BLOCK_HASHMASK);
pblk = pbuffcntxt->blk_hash_tbl[hash_index];
if (pblk == pinblk)
pbuffcntxt->blk_hash_tbl[hash_index] = pinblk->pnext2;
else
{
while (pblk)
{
if (pblk->pnext2==pinblk)
{
pblk->pnext2 = pinblk->pnext2;
break;
}
pblk = pblk->pnext2;
}
}
}
/* Find a block in the block buffer pool */
BLKBUFF *pc_find_blk(DDRIVE *pdrive, dword blockno)
{
BLKBUFFCNTXT *pbuffcntxt;
int hash_index;
BLKBUFF *pblk;
pbuffcntxt = pdrive->drive_state.pbuffcntxt;
hash_index = (int) (blockno&BLOCK_HASHMASK);
pblk = pbuffcntxt->blk_hash_tbl[hash_index];
while (pblk)
{
if (pblk->blockno == blockno && pblk->pdrive == pdrive)
{
if (pblk->block_state == DIRBLOCK_UNCOMMITTED)
{ /* Put in front of populated list (it's the last touched) */
/* Unlink it from the populated pool */
if (pbuffcntxt->ppopulated_blocks != pblk)
{ /* Since we aren't the root we know pprev is good */
pblk->pprev->pnext = pblk->pnext; /* Unlink. */
if (pblk->pnext)
pblk->pnext->pprev = pblk->pprev;
pblk->pprev = 0; /* link in front*/
pblk->pnext = pbuffcntxt->ppopulated_blocks;
if (pbuffcntxt->ppopulated_blocks)
pbuffcntxt->ppopulated_blocks->pprev = pblk;
pbuffcntxt->ppopulated_blocks = pblk;
}
}
return(pblk);
}
pblk=pblk->pnext2;
}
return(0);
}
/* Allocate a block or re-use an un-committed one */
BLKBUFF *pc_allocate_blk(DDRIVE *pdrive, BLKBUFFCNTXT *pbuffcntxt)
{
BLKBUFF *pfreeblk,*puncommitedblk, *pfoundblk, *pblkscan;
int populated_but_uncommited;
/* Note: pdrive may be NULL, do not dereference the pointer */
pfreeblk = pfoundblk = puncommitedblk = 0;
populated_but_uncommited = 0;
/* Use blocks that are on the freelist first */
if (pbuffcntxt->pfree_blocks)
{
pfreeblk = pbuffcntxt->pfree_blocks;
pbuffcntxt->pfree_blocks = pfreeblk->pnext;
pbuffcntxt->num_free -= 1;
}
/* Scan the populated list. Count the number of uncommited blocks to set low water marks
and, if we haven't already allocated a block from the free list, select a replacement block. */
if (pbuffcntxt->ppopulated_blocks)
{
int loop_guard = 0;
/* Count UNCOMMITED blocks and find the oldest UNCOMMITED block in the list */
pblkscan = pbuffcntxt->ppopulated_blocks;
while (pblkscan)
{
if (pblkscan->block_state == DIRBLOCK_UNCOMMITTED && !pblkscan->use_count)
{
puncommitedblk = pblkscan;
populated_but_uncommited += 1;
}
pblkscan = pblkscan->pnext;
/* Guard against endless loop */
if (loop_guard++ > pbuffcntxt->num_blocks)
{
rtfs_set_errno(PEINTERNAL, __FILE__, __LINE__); /* pc_allocate_blk: Internal error*/
return(0);
}
}
/* If we don't already have a free block we'll reuse the oldest uncommitted block so release it */
if (!pfreeblk && puncommitedblk)
{
pc_release_blk(pbuffcntxt, puncommitedblk); /* Remove it from buffer pool */
/* Unlink it from the populated pool */
if (puncommitedblk->pnext)
puncommitedblk->pnext->pprev = puncommitedblk->pprev;
if (puncommitedblk->pprev)
puncommitedblk->pprev->pnext = puncommitedblk->pnext;
if (pbuffcntxt->ppopulated_blocks == puncommitedblk)
pbuffcntxt->ppopulated_blocks = puncommitedblk->pnext;
}
}
if (pfreeblk)
pfoundblk = pfreeblk;
else
pfoundblk = puncommitedblk;
if (pfoundblk)
{ /* Put in a known state */
/* 03-07-2007 using a different method to calculate low water mark. Previous method
undercounted the worst case buffer allocation requirements */
if (pbuffcntxt->num_free + populated_but_uncommited < pbuffcntxt->low_water)
pbuffcntxt->low_water = pbuffcntxt->num_free + populated_but_uncommited;
pfoundblk->use_count = 0;
pfoundblk->block_state = DIRBLOCK_ALLOCATED;
pfoundblk->pdrive = pdrive;
}
else
{
pbuffcntxt->num_alloc_failures += 1;
rtfs_set_errno(PERESOURCEBLOCK, __FILE__, __LINE__); /* pc_allocate_blk out of resources */
}
return(pfoundblk);
}
/* Initialize and populate a block buffer context structure
Called from pc_memory_init() to initialize the shared block buffer pool.
May also be called by device drivers that provide dynamic configuration.
BOOLEAN pc_initialize_block_pool(
BLKBUFFCNTXT *pbuffcntxt - Block buffer context, there is 1 globally shared context but device drivers may
allocate drive specific contexts.
int nblkbuffs - Number of buffers
BLKBUFF *pmem_block_pool - Pointer to enough space to hold nblkbuffs time the size of the BLKBUFF control structure
byte *raw_buffer_space - Optional pointer to enough space to hold nblkbuffs time the size of the BLKBUFF control structure
Note: This parameter is optional for device drivers.
If the device drivers populates the pdata field of each individual control structure
before calling it calls pmem_block_pool then it should pass 0 for the
raw_buffer_space parameter.
This method may be used to populate the buffers with memory addresses located
on device specific address boundaries.
dword data_size_bytes - Size of each block buffer in bytes.
Note: This field is not ioptional.
It must equal the sector size in bytes and always be provided.
*/
void pc_initialize_block_pool(BLKBUFFCNTXT *pbuffcntxt, int nblkbuffs, BLKBUFF *pmem_block_pool, byte *raw_buffer_space, dword data_size_bytes)
{
int i;
BLKBUFF *pblk;
rtfs_memset(pbuffcntxt,(byte) 0, sizeof(BLKBUFFCNTXT));
/* First clear all the buffer control structures, preserve the data field in case it was provided to us */
pblk = pmem_block_pool;
for (i = 0; i < nblkbuffs; i++, pblk++)
{
byte *saved_buffer_address;
saved_buffer_address = pblk->data;
rtfs_memset(pblk,(byte) 0, sizeof(BLKBUFF));
pblk->data = saved_buffer_address;
pblk->data_size_bytes = data_size_bytes;
}
/* Save the initial value in case we have to delete it */
pbuffcntxt->assigned_free_buffers = pmem_block_pool;
/* Make the provided block pool array our free list */
pbuffcntxt->pfree_blocks = pmem_block_pool;
/* Link all control structures together into a list a free list */
pblk = pmem_block_pool;
for (i = 0; i < (nblkbuffs-1); i++, pblk++)
pblk->pnext = pblk+1;
pblk->pnext = 0;
/* If raw_buffer_space was passed in then set the buffer addresses in the control structures to offsets in
raw_buffer_space. raw_buffer_space must be at least (nblkbuffs * data_size_bytes) bytes wide.
If the drive was configured from the application layer raw_buffer_space will point to buffer space.
If the drive was configured by a device driver ioctl call then raw_buffer_space will not point to
buffer space and the control structures' pdata filed will be valid already */
if (raw_buffer_space)
{
pblk = pmem_block_pool;
for (i = 0; i < nblkbuffs; i++, pblk++)
{
pblk->data = raw_buffer_space;
raw_buffer_space += data_size_bytes;
}
}
/* Set up the rest. The hash table was already zeroed when the structure was zeroed, the hash table size
and mask are now a fixed size */
pbuffcntxt->num_blocks = nblkbuffs;
pbuffcntxt->num_free = nblkbuffs;
pbuffcntxt->low_water = nblkbuffs;
pbuffcntxt->num_alloc_failures = 0;
}
#if (DEBUG_BLOCK_CODE)
void debug_check_blocks(BLKBUFFCNTXT *pbuffcntxt, int numblocks, char *where, dword line)
{
BLKBUFF *pblk;
BLKBUFF *pblk_prev;
int nb = 0;
int nfreelist = 0;
int npopulatedlist = 0;
int i;
pblk = pbuffcntxt->pfree_blocks;
while (pblk)
{
nb += 1;
/* Check for bad freelist */
ERTFS_ASSERT(nb <= numblocks)
pblk = pblk->pnext;
}
nfreelist = nb;
pblk = pbuffcntxt->ppopulated_blocks;
ERTFS_ASSERT(nb <= numblocks)
if (pblk && pblk->pprev)
{
/* Bad populated root */
ERTFS_ASSERT(0)
}
while (pblk)
{
npopulatedlist += 1;
nb += 1;
/* Check for Bad populated list */
ERTFS_ASSERT(nb <= numblocks)
pblk = pblk->pnext;
}
/* Add in outstanding scratch allocates */
nb += pbuffcntxt->scratch_alloc_count;
/* Check for leaks */
ERTFS_ASSERT(nb == numblocks)
if (pbuffcntxt->ppopulated_blocks)
{
pblk_prev = pblk = pbuffcntxt->ppopulated_blocks;
pblk = pblk->pnext;
while (pblk)
{
/* Check for Bad link in populated list */
ERTFS_ASSERT(pblk->pprev == pblk_prev)
pblk_prev = pblk;
pblk = pblk->pnext;
}
}
for (i = 0; i < BLOCK_HASHSIZE; i++)
{
nb = 0;
pblk = pbuffcntxt->blk_hash_tbl[i];
while (pblk)
{
/* Check for Block in wrong hash slot */
ERTFS_ASSERT(i == (int) (pblk->blockno&BLOCK_HASHMASK))
nb += 1;
/* Check for loop in hash table */
ERTFS_ASSERT(nb <= numblocks)
pblk = pblk->pnext2;
}
}
}
/* Diagnostic to display list list contents for FINODE and DROBJ pools.
display_free_lists(char *in_where)
Prints:
FINODES on FREE list, FINODES on in use list.
Drobj structures on freelist,
drob structure count marked free by scanning the drobj pool sequentially
BLKBUFF buffer free count, and low water count
BLKBUFF buffers counted on populated list
BLKBUFF buffers counted on free list
If populated count and free list don't add up the remainder will be scratch
buffers.
To Do: Add counters for scratch buffer allocation and frees.
Useful for validating that no leaks are occuring.
*/
#define DEBUGPRINTF printf
void display_free_lists(char *in_where)
{
FINODE *pfi;
DROBJ *pobj;
struct blkbuff *pblk;
int j, i, objcount, finodecount,populated_block_count,free_list_count;
objcount = finodecount = i = populated_block_count = free_list_count = 0;
pfi = prtfs_cfg->mem_finode_freelist;
while (pfi)
{
i++;
pfi = pfi->pnext;
}
finodecount = 0;
pfi = prtfs_cfg->inoroot;
while (pfi)
{
finodecount++;
pfi = pfi->pnext;
}
DEBUGPRINTF("%-10.10s:INODES free:%4.4d in-use:%4.4d total:%4.4d \n", in_where, i,finodecount,prtfs_cfg->cfg_NFINODES);
i = 0;
pobj = prtfs_cfg->mem_drobj_freelist;
while (pobj)
{
i++;
pobj = (DROBJ *) pobj->pdrive;
}
pobj = prtfs_cfg->mem_drobj_pool;
objcount = 0;
for (j = 0; j < prtfs_cfg->cfg_NDROBJS; j++, pobj++)
{
if (!pobj->is_free)
objcount += 1;
}
DEBUGPRINTF("%-10.10s:DROBJS free:%4.4d in-use:%4.4d total:%4.4d \n", in_where, i,objcount, prtfs_cfg->cfg_NDROBJS);
pblk = prtfs_cfg->buffcntxt.ppopulated_blocks; /* uses pnext/pprev */
populated_block_count = 0;
while (pblk)
{
populated_block_count += 1;
pblk = pblk->pnext;
}
DEBUGPRINTF("%-10.10s:BLKBUFS free:%4.4d in-use:%4.4d low w:%4.4d scratch:%4.4d total:%4.4d \n",in_where,
prtfs_cfg->buffcntxt.num_free,
populated_block_count,
prtfs_cfg->buffcntxt.low_water,
prtfs_cfg->buffcntxt.scratch_alloc_count,
prtfs_cfg->buffcntxt.num_blocks);
pblk = prtfs_cfg->buffcntxt.pfree_blocks;
free_list_count = 0;
while (pblk)
{
free_list_count += 1;
pblk = pblk->pnext;
}
if (free_list_count != prtfs_cfg->buffcntxt.num_free)
{
DEBUGPRINTF("%-10.10s:Error num_freelist == %d but %d elements on the freelist\n",in_where, prtfs_cfg->buffcntxt.num_free, free_list_count);
}
}
/* May be called to detect buffer pool leaks */
void check_blocks(DDRIVE *pdrive, char *prompt, dword line)
{
debug_check_blocks(pdrive->pbuffcntxt, pdrive->pbuffcntxt->num_blocks, prompt, line);
}
#endif /* (DEBUG_BLOCK_CODE) */

View File

@ -0,0 +1,94 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* RTDBLOCK.C - ERTFS-PRO and ProPlus Directory and scrath block buffering routines */
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
BOOLEAN block_devio_write(BLKBUFF *pblk)
{
#if (INCLUDE_FAILSAFE_RUNTIME)
if (prtfs_cfg->pfailsafe)
return(prtfs_cfg->pfailsafe->block_devio_write(pblk));
#endif
UPDATE_RUNTIME_STATS(pblk->pdrive, dir_buff_writes, 1)
return(raw_devio_xfer(pblk->pdrive,pblk->blockno, pblk->data, (int) 1, FALSE, FALSE));
}
/***************************************************************************
PC_WRITE_BLK - Flush a BLKBUFF to disk.
Description
Use pdrive and blockno information in pblk to flush its data buffer
to disk.
Returns
Returns TRUE if the write succeeded.
****************************************************************************/
/* Write */
BOOLEAN pc_write_blk(BLKBUFF *pblk) /*__fn__*/
{
if (!block_devio_write(pblk))
{
/* set errno to IO error unless devio set PEDEVICE */
if (!get_errno())
rtfs_set_errno(PEIOERRORWRITEBLOCK, __FILE__, __LINE__); /* pc_write_blk device write error */
return(FALSE);
}
else
{
return(TRUE);
}
}
/* Tomo */
/* Traverse a cluster chain and make sure that all blocks in the cluster
chain are flushed from the buffer pool. This is required when deleting
a directory since it is possible, although unlikely, that blocks used in
the directory may be used in a file. This may cause the buffered
block to be different from on-disk block.
Called by pc_rmnode
*/
void pc_flush_chain_blk(DDRIVE *pdrive, dword cluster)
{
dword i;
dword blockno;
BLKBUFF *pblk;
if ( cluster < 2 || cluster > pdrive->drive_info.maxfindex)
return;
while (cluster != FAT_EOF_RVAL) /* End of chain */
{
blockno = pc_cl2sector(pdrive, cluster);
if (blockno)
{
for (i = 0; i < pdrive->drive_info.secpalloc; i++, blockno++)
{
/* Find it in the buffer pool */
OS_CLAIM_FSCRITICAL()
pblk = pc_find_blk(pdrive, blockno);
if (pblk)
pblk->use_count += 1;
OS_RELEASE_FSCRITICAL()
if (pblk)
{
pc_discard_buf(pblk);
}
}
}
/* Consult the fat for the next cluster */
cluster = fatop_next_cluster(pdrive, cluster);
if (cluster == 0) /* clnext detected error */
break;
}
}
#endif /* Exclude from build if read only */

View File

@ -0,0 +1,245 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* rtdevio.c - Media check functions and device io wrapper functions
*
*
*/
#include "rtfs.h"
#if (INCLUDE_RTFS_PROPLUS) /* pc_check_automount() */
BOOLEAN pc_check_automount(DDRIVE *pdr);
#endif
/* Check if a drive id is valid and mount the drive. This is an internal
routine that is called by other api calls
If it fails, return -1 with the drive not claimed.
If it succeeds return the drive number with the drive claimed.
The caller will call release_drive_mount(driveno) to release it
*/
int check_drive_name_mount(byte *name, int use_charset) /*__fn__*/
{
int driveno;
/* Get the drive and make sure it is mounted */
if (pc_parsedrive( &driveno, name, use_charset))
{
if (check_drive_by_number(driveno, TRUE))
return(driveno);
}
return(-1);
}
DDRIVE *check_drive_by_name(byte *name, int use_charset) /*__fn__*/
{
int driveno;
/* Get the drive and make sure it is installed, don't worry if it's mounted */
if (pc_parsedrive( &driveno, name, use_charset))
{
return(check_drive_by_number(driveno, FALSE));
}
return(0);
}
/* Check if a drive id is valid and mount the drive. This is an internal
routine that is called by other api calls
If it fails, return -1 with the drive not claimed.
If it succeeds return the drive number with the drive claimed.
The caller will call release_drive_mount(driveno) to release it
*/
DDRIVE *check_drive_by_number(int driveno, BOOLEAN check_mount) /*__fn__*/
{
if (!pc_validate_driveno(driveno))
{
rtfs_set_errno(PEINVALIDDRIVEID, __FILE__, __LINE__); /* Check drive called with bad drive name */
}
else
{
DDRIVE *pdr;
/* Get the drive and make sure it is mounted */
pdr = rtfs_claim_media_and_buffers(driveno);
if (!pdr)
return(0);
/* If just checking vor installed media, we're there */
if (!check_mount)
return(pdr);
#if (INCLUDE_RTFS_PROPLUS) /* ProPlus check if mount in progress */
if (pdr->drive_state.drive_async_state == DRV_ASYNC_MOUNT)
{
rtfs_set_errno(PEEINPROGRESS, __FILE__, __LINE__);
goto release_buffers_and_fail;
}
#endif
/* If an abort request is pending, executed it */
if (chk_mount_valid(pdr) && chk_mount_abort(pdr))
pc_dskfree(pdr->driveno); /* Clears mount valid */
if (chk_mount_valid(pdr)) /* already mounted */
return(pdr);
#if (INCLUDE_RTFS_PROPLUS) /* pc_check_automount() ProPlus may want to mount asyncronously */
if (!pc_check_automount(pdr)) /* Check if automount is disabled (always enabled for Pro) */
goto release_buffers_and_fail;
#endif
/* pc_auto_dskopen() calls dskopen and performs any automatic failsafe operations */
if (pc_auto_dskopen(pdr))
return(pdr);
#if (INCLUDE_RTFS_PROPLUS)
release_buffers_and_fail:
#endif
rtfs_release_media_and_buffers(driveno); /* check_drive_number_mount release */
}
return(0);
}
/* Release a drive that was claimed by a succesful call to
check_drive_name_mount, or check_drive_number_mount
If the the operation queued an abort request then
free the drive an all it's structures
*/
void release_drive_mount(int driveno)
{
DDRIVE *pdr;
pdr = pc_drno_to_drive_struct(driveno);
if (pdr && chk_mount_abort(pdr))
{
pc_dskfree(driveno);
}
rtfs_release_media_and_buffers(driveno); /* release_drive_mount release */
}
/*
* Note: The the logical drive must be claimed before this routine is
* called and later released by the caller.
*/
/* If test mode is enabled include code to force read or write errors if requested */
#if (INCLUDE_DEBUG_TEST_CODE && INCLUDE_RTFS_PROPLUS)
static BOOLEAN _raw_devio_xfer(DDRIVE *pdr, dword blockno, byte * buf, dword n_to_xfer, BOOLEAN raw, BOOLEAN reading) /* __fn__ */
#else
BOOLEAN raw_devio_xfer(DDRIVE *pdr, dword blockno, byte * buf, dword n_to_xfer, BOOLEAN raw, BOOLEAN reading) /* __fn__ */
#endif
{
int driveno;
dword ltemp, nbytes;
word n_w_to_xfer;
driveno = pdr->driveno;
/* Bug Fix. 1-28-02 thanks to Kerry Krouse. This code was inside the
loop, which caused retries to fail
*/
/* Removed test of if (pdr->drive_flags & DRIVE_FLAGS_PARTITIONED). partition_base will be zero if the device is not partitioned */
{
if (!raw)
blockno += pdr->drive_info.partition_base;
}
ltemp = n_to_xfer;
/* Loop, allowing n blocks to be a long value while driver interace is
still short */
while (ltemp)
{
if (ltemp > 0xffff)
n_w_to_xfer = (word) 0xffff;
else
n_w_to_xfer = (word) (ltemp & 0xffff);
if (RTFS_DEVI_io(driveno, blockno, buf, n_w_to_xfer, reading))
{
nbytes = (dword) n_w_to_xfer;
nbytes <<= pdr->drive_info.log2_bytespsec;
buf += nbytes;
blockno += n_w_to_xfer;
/* Calculate loop counter here so we can fall through with counters updated */
ltemp -= n_w_to_xfer; /* Will break out when zero */
}
else
{
rtfs_diag_callback(RTFS_CBD_IOERROR, driveno);
return(FALSE);
}
}
return(TRUE);
}
#if (INCLUDE_DEBUG_TEST_CODE && !INCLUDE_RTFS_PROPLUS)
void rtfs_devio_log_io(DDRIVE *pdr, int io_access_type,dword io_block, dword io_count)
{
RTFS_ARGSUSED_PVOID((void *) pdr);
RTFS_ARGSUSED_INT((int) io_block);
RTFS_ARGSUSED_INT((int) io_count);
RTFS_ARGSUSED_INT((int) io_access_type);
}
#endif
#if (INCLUDE_DEBUG_TEST_CODE && INCLUDE_RTFS_PROPLUS)
/* This is test code that forces a read or write error that was queued up earlier.
Used for RTFS Pro Plus test modules only */
byte error_data[RTFS_CFG_DEFAULT_SECTOR_SIZE_BYTES] = "ERRORERRORERRORERRORERRORERRORERRORERRORERRORERRORERRORERRORERROR";
BOOLEAN raw_devio_xfer(DDRIVE *pdr, dword blockno, byte * buf, dword n_to_xfer, BOOLEAN raw, BOOLEAN reading) /* __fn__ */
{
/* If run-time tests are enabled see if we need to simulate a read or
write error - If so, process as many blocks normally as allowed
and then simulate the error */
if (pdr->du.iostats.force_io_error_now)
{
dword force_error_on;
force_error_on = pdr->du.iostats.force_io_error_now-1;
ERTFS_ASSERT(force_error_on <= n_to_xfer)
pdr->du.iostats.force_io_error_now = 0;
/* Transfer non error blocks if any */
if (force_error_on > 1)
{
if (!_raw_devio_xfer(pdr, blockno, buf, force_error_on-1, raw, reading))
return(FALSE);
}
/* If it's a write, put down a bad block at the error location */
if (!reading)
{
_raw_devio_xfer(pdr, blockno+force_error_on-1, error_data, 1, raw, FALSE);
}
pdr->du.iostats.io_errors_forced += 1;
return(FALSE);
}
else
{
return(_raw_devio_xfer(pdr, blockno, buf, n_to_xfer, raw, reading));
}
}
void rtfs_devio_log_io(DDRIVE *pdr, int io_access_type,dword io_block, dword io_count)
{
dword old_count;
RTFS_ARGSUSED_INT((int) io_block);
old_count = pdr->du.iostats.blocks_transferred[io_access_type];
pdr->du.iostats.blocks_transferred[io_access_type] += io_count;
/* Set pdr->du.iostats.force_io_error_now to >= 1 to force an IO error when raw_devio_xfer() executes */
if (io_access_type && pdr->du.iostats.force_io_error_on_type==io_access_type
&& pdr->du.iostats.force_io_error_when
&& (pdr->du.iostats.blocks_transferred[io_access_type] >= pdr->du.iostats.force_io_error_when))
{
pdr->du.iostats.force_io_error_now = 1 + pdr->du.iostats.force_io_error_when - old_count;
pdr->du.iostats.force_io_error_when = 0;
}
else
pdr->du.iostats.force_io_error_now = 0;
}
#endif

View File

@ -0,0 +1,47 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* rtdevio.c - Media check functions and device io wrapper functions
*
*
*/
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
BOOLEAN release_drive_mount_write(int driveno)
{
DDRIVE *pdr;
BOOLEAN ret_val;
ret_val = TRUE;
pdr = pc_drno_to_drive_struct(driveno);
if (pdr)
{
if (chk_mount_abort(pdr))
pc_dskfree(driveno);
else
{
/* If Failsafe autocommit is enabled, commit if needed and return status
If Failsafe autocommit is not enabled returns success */
#if (INCLUDE_FAILSAFE_RUNTIME) /* Call failsafe autocommit */
if (prtfs_cfg->pfailsafe)
{
ret_val = prtfs_cfg->pfailsafe->fs_failsafe_autocommit(pdr);
if (chk_mount_abort(pdr)) /* If an IO error was detected during autocommit free the drive so we re-mount */
pc_dskfree(driveno);
}
#endif
}
}
rtfs_release_media_and_buffers(driveno); /* release_drive_mount release */
return(ret_val);
}
#endif /* Exclude from build if read only */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,608 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* RTDROBJ.C - Directory object manipulation routines */
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
/**************************************************************************
PC_MKNODE - Create an empty subdirectory or file.
Description
Creates a file or subdirectory inode depending on the flag values in
attributes. A pointer to an inode is returned for further processing. See
po_open(),po_close(), pc_mkdir() et al for examples.
Note: After processing, the DROBJ must be released by calling pc_freeobj.
Returns
Returns a pointer to a DROBJ structure for further use, or NULL if the
inode name already exists or path not found.
**************************************************************************/
/* Make a node from path and attribs create and fill in pobj */
/* Note: the parent directory is locked before this routine is called */
void pc_init_directory_cluster(DROBJ *pobj, byte *pbuffer);
#if (INCLUDE_EXFATORFAT64)
/* Note: This is a new way of doing things for all. Leave conditional until testing is completer */
DROBJ *pc_mknode(DROBJ *pmom ,byte *filename, byte *fileext, byte attributes, FINODE *infinode,int use_charset) /*__fn__*/
#else
DROBJ *pc_mknode(DROBJ *pmom ,byte *filename, byte *fileext, byte attributes, dword incluster,int use_charset) /*__fn__*/
#endif
{
DROBJ *pobj;
BOOLEAN ret_val, use_ubuff,initialize_fat_dir_cluster;
dword new_cluster,cluster;
dword user_buffer_size;
byte *puser_buffer;
BLKBUFF *pbuff;
DDRIVE *pdrive;
byte attr;
#if (INCLUDE_EXFATORFAT64)
dword incluster = 0;
#endif
ret_val = TRUE;
new_cluster = 0;
pobj = 0;
pbuff = 0;
puser_buffer = 0;
initialize_fat_dir_cluster = FALSE;
if (!pmom || !pmom->pdrive)
{
rtfs_set_errno(PEINTERNAL, __FILE__, __LINE__); /* pc_mknode: Internal error*/
return (0);
}
/* Make sure the file/directory name is legal */
if (!pc_cs_validate_filename(filename, fileext, use_charset))
{
rtfs_set_errno(PEINVALIDPATH, __FILE__, __LINE__);
return (0);
}
pdrive = pmom->pdrive;
#if (INCLUDE_EXFATORFAT64)
if (infinode)
incluster = pc_finode_cluster(pmom->pdrive, infinode);
#endif
use_ubuff = FALSE;
cluster = incluster;
if (attributes & ADIRENT)
{
/*Unless renaming a directory we grab a cluster for a new dir */
if (!incluster)
{
/* pc_alloc_dir will set errno */
cluster = pc_alloc_dir(pdrive,pmom);
if (!cluster)
goto clean_and_fail;
else
{
new_cluster = cluster; /* Remeber so we can release if we fail */
}
#if (INCLUDE_EXFATORFAT64) /* Should be a wrapper function */
if ( ISEXFATORFAT64(pdrive) )
{
pcexfat_set_volume_dirty(pdrive);
#if (EXFAT_FAVOR_CONTIGUOUS_FILES) /* Update free_contig_pointer for exfat if enabled */
/* Update location to allocate file data from if necessary */
if (new_cluster >= pdrive->drive_info.free_contig_pointer)
pdrive->drive_info.free_contig_pointer = new_cluster + 1;
if (pdrive->drive_info.free_contig_pointer >= pdrive->drive_info.maxfindex)
pdrive->drive_info.free_contig_pointer = pdrive->drive_info.free_contig_base;
#endif
}
#endif
/* Use the user buffer if we are creating a directory and it large enough to hold a whole cluster */
puser_buffer = pc_claim_user_buffer(pdrive, &user_buffer_size,(dword) pdrive->drive_info.secpalloc); /* released on cleanup */
if (puser_buffer)
use_ubuff = TRUE;
}
}
/* For a subdirectory. First make it a simple file. We will change the
attribute after all is clean */
attr = attributes;
if (attr & ADIRENT)
attr = ANORMAL;
/* Allocate an empty DROBJ and FINODE to hold the new file */
pobj = pc_allocobj();
if (!pobj)
{
goto clean_and_fail;
}
/* Set up the drive link */
pobj->pdrive = pmom->pdrive;
/* Load the inode copy name,ext,attr,cluster, size,datetime */
/* Convert pobj to native and stitch it in to mom */
#if (INCLUDE_EXFATORFAT64)
if ( ISEXFATORFAT64(pdrive) )
{
byte secondaryflags;
dword size_hi, size_lo;
size_hi = size_lo = 0;
if (attributes & ADIRENT)
size_lo = (dword) pdrive->drive_info.bytespcluster;
secondaryflags = EXFATALLOCATIONPOSSIBLE;
secondaryflags |= EXFATNOFATCHAIN;
*pobj->finode = *pmom->finode;
if (!pcexfat_insert_inode(pobj , pmom, attributes, infinode, cluster, filename, secondaryflags, size_hi, size_lo, use_charset))
{ /* If it failed due to PENOSPC try to grow the directory and try again */
if (get_errno() != PENOSPC)
goto clean_and_fail;
rtfs_clear_errno();
if (!pcexfat_grow_directory(pmom))
goto clean_and_fail;
if (!pcexfat_insert_inode(pobj , pmom, attributes, infinode, cluster, filename, secondaryflags, size_hi, size_lo, use_charset))
goto clean_and_fail;
}
pcexfat_clear_volume_dirty(pdrive);
}
else
#endif
{
if (!pc_insert_inode(pobj , pmom, attr, cluster, filename, fileext,use_charset))
goto clean_and_fail;
}
if ( attributes & ADIRENT)
initialize_fat_dir_cluster = TRUE;
new_cluster = 0; /* Will not release now since part of tree */
/* Now if we are creating subdirectory we have to make the DOT and DOT DOT
inodes and then change pobj s attribute to ADIRENT
The DOT and DOTDOT are not buffered inodes. We are simply putting
the to disk */
if ( initialize_fat_dir_cluster)
{
if (use_ubuff)
{ /* A create, not a rename and user buffer holds the whole cluster zero the cluster and initialize . and .. */
dword n_blocks, blockno;
n_blocks = (dword) pdrive->drive_info.secpalloc;
blockno = pc_cl2sector(pdrive , cluster);
rtfs_memset(puser_buffer, (byte) 0,n_blocks<<pdrive->drive_info.log2_bytespsec);
#if (INCLUDE_EXFATORFAT64)
if (!ISEXFATORFAT64(pdrive))
pc_init_directory_cluster(pobj, puser_buffer);
#else
pc_init_directory_cluster(pobj, puser_buffer);
#endif
if (!block_devio_xfer(pdrive,blockno, puser_buffer, n_blocks, FALSE))
goto clean_and_fail;
}
else
{ /* Use the block buffer pool.. if user buffer is too small or we are moving a subdirectory */
if (incluster)
pbuff = pc_read_blk( pdrive , pc_cl2sector(pdrive , incluster));
else
{
/* If no user buffer use the block buffer system to zero the first cluster */
if (!pc_clzero( pdrive , cluster ) )
goto clean_and_fail;
#if (INCLUDE_EXFATORFAT64)
if (ISEXFATORFAT64(pdrive))
goto first_cluster_initialized;
#endif
/* If now get a block to place . and .. */
pbuff = pc_init_blk( pdrive , pc_cl2sector(pdrive , cluster));
}
if (!pbuff)
goto clean_and_fail;
/* Update . and .. overides existing if moving a directory */
pc_init_directory_cluster(pobj, pbuff->data);
/* Write the cluster out */
if ( !pc_write_blk ( pbuff ) )
goto clean_and_fail;
pc_release_buf(pbuff);
#if (INCLUDE_EXFATORFAT64)
first_cluster_initialized:
#endif
pbuff = 0;
}
#if (INCLUDE_EXFATORFAT64)
if ( ISEXFATORFAT64(pdrive) )
; /* No need to change the attribute type on exFat directories because there is no back link (..) */
else
#endif
{
/* And write the node out with the original attributes */
pobj->finode->fattribute = (byte)(attributes|ARCHIVE);
/* Convert to native. Overwrite the existing inode.Set archive/date */
if (!pc_update_inode(pobj, TRUE, DATESETCREATE|DATESETUPDATE|DATESETACCESS))
{
goto clean_and_fail;
}
}
}
if (puser_buffer)
pc_release_user_buffer(pdrive, puser_buffer);
ret_val = fatop_flushfat(pdrive);
if (ret_val)
{
return (pobj);
}
else
{
pc_freeobj(pobj);
return (0);
}
clean_and_fail:
if (pbuff)
pc_discard_buf(pbuff);
if (puser_buffer)
pc_release_user_buffer(pdrive, puser_buffer);
if (pobj)
pc_freeobj(pobj);
if (new_cluster)
{
fatop_clrelease_dir(pdrive , new_cluster);
}
return (0);
}
/* Init DOT and DOT DOT directory entries in the buffer */
void pc_init_directory_cluster(DROBJ *pobj, byte *pbuffer)
{
DDRIVE *pdrive;
DOSINODE *pdinodes;
FINODE lfinode;
dword cluster, cltemp;
DATESTR crdate;
byte dot_str[4]; /* Make DOT and DOTDOT strings */
byte null_str[4];
pdrive = pobj->pdrive;
cluster = pc_finode_cluster(pdrive, pobj->finode);
/* Make the DOT and DOT DOT inodes */
pdinodes = (DOSINODE *) pbuffer;
/* Load DOT and DOTDOT in native form */
/* DOT first. It points to the begining of this sector */
dot_str[0] = (byte) '.';dot_str[1]=0;
null_str[0] = 0;
/* Load the time and date stamp to be used for "." and ".."
from the subdirectory that we are creating. In this way
the three directory entries will all have the same timestamp
value */
crdate.time = pobj->finode->ftime;
crdate.date = pobj->finode->fdate;
pc_init_inode( &lfinode, dot_str,null_str, ADIRENT|ARCHIVE,
cluster, /*size*/ 0L , &crdate);
/* And to the buffer in intel form */
pc_ino2dos (pdinodes, &lfinode);
/* Now DOTDOT points to mom s cluster */
cltemp = pc_get_parent_cluster(pdrive, pobj);
dot_str[0] = (byte)'.';dot_str[1] = (byte)'.';
dot_str[2] = 0;
null_str[0] = 0;
pc_init_inode( &lfinode, dot_str, null_str, ADIRENT|ARCHIVE, cltemp,
/*size*/ 0L , &crdate);
/* And to the buffer in intel form */
pc_ino2dos (++pdinodes, &lfinode );
}
/***************************************************************************
PC_CLZERO - Fill a disk cluster with zeroes
Description
Write zeroes into the cluster at clusterno on the drive pointed to by
pdrive. Used to zero out directory and data file clusters to eliminate
any residual data.
Returns
Returns FALSE on a write erro.
****************************************************************************/
/* Write zeros to all blocks in a cluster */
BOOLEAN pc_clzero(DDRIVE *pdrive, dword cluster) /*__fn__*/
{
BOOLEAN ret_val;
dword currbl,n_left,n_todo;
dword user_buffer_size;
byte *puser_buffer;
currbl = pc_cl2sector(pdrive , cluster);
if (!currbl)
return (FALSE);
puser_buffer = pc_claim_user_buffer(pdrive, &user_buffer_size, 0); /* released on cleanup */
if (!puser_buffer)
return (FALSE);
/* Fill as much of the cluster as we can per write */
ret_val = FALSE;
n_left = pdrive->drive_info.secpalloc;
while (n_left)
{
n_todo = n_left;
if (n_todo > user_buffer_size)
n_todo = user_buffer_size;
rtfs_memset(puser_buffer, (byte) 0,n_todo<<pdrive->drive_info.log2_bytespsec);
ret_val = block_devio_xfer(pdrive, currbl, puser_buffer, n_todo, FALSE);
if (!ret_val)
break;
n_left -= n_todo;
currbl += n_todo;
}
pc_release_user_buffer(pdrive, puser_buffer);
return(ret_val);
}
/***************************************************************************
PC_RMNODE - Delete an inode unconditionally.
Description
Delete the inode at pobj and flush the file allocation table. Does not
check file permissions or if the file is already open. (see also pc_unlink
and pc_rmdir). The inode is marked deleted on the disk and the cluster
chain associated with the inode is freed. (Un-delete wo not work)
Returns
Returns TRUE if it successfully deleted the inode an flushed the fat.
*****************************************************************************/
/* Delete a file / dir or volume. Do not check for write access et al */
/* Note: the parent directory is locked before this routine is called */
BOOLEAN pc_rmnode( DROBJ *pobj) /*__fn__*/
{
dword cluster;
DDRIVE *pdrive;
BOOLEAN is_a_dir;
/* Do not delete anything that has multiple links */
if (pobj->finode->opencount > 1)
{
rtfs_set_errno(PEACCES, __FILE__, __LINE__); /* pc_rmnode() - directory entry is in use */
err_ex:
return (FALSE);
}
#if (INCLUDE_EXFATORFAT64)
if (ISEXFATORFAT64(pobj->pdrive))
{
return(pcexfat_rmnode(pobj));
}
#endif
is_a_dir = pc_isadir(pobj);
pdrive = pobj->pdrive;
/* Mark it deleted and unlink the cluster chain */
pobj->finode->fname[0] = PCDELETEESCAPE;
cluster = pc_finode_cluster(pdrive,pobj->finode);
if (!pc_delete_lfn_info(pobj)) /* Delete lonf file name info associated with DROBJ */
goto err_ex;
/* We free up store right away. Do not leave cluster pointer
hanging around to cause problems. */
pc_pfinode_cluster(pdrive,pobj->finode,0);
/* Convert to native. Overwrite the existing inode.Set archive/date */
if (pc_update_inode(pobj, FALSE, 0))
{
/* If there is no cluster chain to delete don't call freechain */
if (!cluster)
return(TRUE);
/* And clear up the space */
/* If it is a directory make sure the blocks contained within the
cluster chain are flushed from the block buffer pool */
if (is_a_dir)
pc_flush_chain_blk(pdrive, cluster);
/* Set min to 0 and max to 0xffffffff to eliminate range checking on the
cluster chain and force removal of all clusters */
if (!fatop_freechain(pdrive, cluster, LARGEST_DWORD))
{
/* If freechain failed still flush the fat in INVALID CLUSTER
was the failure condition */
if (get_errno() == PEINVALIDCLUSTER)
fatop_flushfat(pobj->pdrive);
return(FALSE);
}
else if ( fatop_flushfat(pobj->pdrive) )
return (TRUE);
}
/* If it gets here we had a problem */
return(FALSE);
}
/**************************************************************************
PC_UPDATE_INODE - Flush an inode to disk
Summary
Description
Read the disk inode information stored in pobj and write it to
the block and offset on the disk where it belongs. The disk is
first read to get the block and then the inode info is merged in
and the block is written. (see also pc_mknode() )
Returns
Returns TRUE if all went well, no on a write error.
*****************************************************************************
*/
/* Take a DROBJ that contains correct my_index & my_block. And an inode.
Load the block. Copy the inode in and write it back out */
/* Update the timestamp fields, called by routines that read/write/modify when the entry is accessed */
void pc_update_finode_datestamp(FINODE *pfinode, BOOLEAN set_archive, int set_date_mask) /*__fn__*/
{
DATESTR crdate;
#if (INCLUDE_EXFATORFAT64)
if (ISEXFATORFAT64(pfinode->my_drive))
{
pcexfat_update_finode_datestamp(pfinode, set_archive, set_date_mask);
return;
}
#endif
OS_CLAIM_FSCRITICAL()
/* Set the archive bit and the date */
if (set_archive)
pfinode->fattribute |= ARCHIVE;
if (set_date_mask)
{ /* Need to update FAT modified support */
pc_getsysdate(&crdate);
if (set_date_mask & DATESETCREATE)
{
pfinode->ctime = crdate.time;
pfinode->cdate = crdate.date;
}
if (set_date_mask & DATESETUPDATE)
{
pfinode->ftime = crdate.time;
pfinode->fdate = crdate.date;
}
if (set_date_mask & DATESETACCESS)
{
pfinode->atime = crdate.time;
pfinode->adate = crdate.date;
}
}
OS_RELEASE_FSCRITICAL()
}
BOOLEAN pc_update_by_finode(FINODE *pfinode, int entry_index, BOOLEAN set_archive, int set_date_mask) /*__fn__*/
{
BLKBUFF *pbuff;
DOSINODE *pi;
#if (INCLUDE_EXFATORFAT64)
if ( ISEXFATORFAT64(pfinode->my_drive) )
{
return (pcexfat_update_by_finode(pfinode, entry_index, set_archive, set_date_mask, FALSE)); /* Delete == FALSE */
}
#endif
if ( entry_index >= pfinode->my_drive->drive_info.inopblock || entry_index < 0 ) /* Index into block */
{
rtfs_set_errno(PEINTERNAL, __FILE__, __LINE__); /* pc_update_inode: Internal error, illegal inode index */
return (FALSE);
}
/* Set the archive bit and the datestamp according to caller's instructions */
pc_update_finode_datestamp(pfinode, set_archive, set_date_mask);
/* Read the data */
pbuff = pc_read_blk(pfinode->my_drive, pfinode->my_block);
if (pbuff)
{
pi = (DOSINODE *) pbuff->data;
/* Copy it off and write it */
pc_ino2dos( (pi+entry_index), pfinode );
if (!pc_write_blk(pbuff))
{
pc_discard_buf(pbuff);
return (FALSE);
}
else
{
pc_release_buf(pbuff);
return (TRUE);
}
}
return (FALSE);
}
/* Load an in memory inode up with user supplied values */
void pc_init_inode(FINODE *pdir, KS_CONSTANT byte *filename,
KS_CONSTANT byte *fileext, byte attr,
dword cluster, dword size, DATESTR *crdate)
{
/* Copy the file names and pad with spaces */
pc_cppad(pdir->fname,(byte*)filename,8);
pc_cppad(pdir->fext,(byte*)fileext,3);
pdir->fattribute = attr;
pdir->reservednt = 0;
pdir->create10msincrement = 0;
pdir->ftime = crdate->time;
pdir->fdate = crdate->date;
pdir->ctime = crdate->time;
pdir->cdate = crdate->date;
pdir->adate = crdate->date;
pdir->atime = crdate->time;
/* Note: fclusterhi is of resarea in fat 16 system and cluster>>16 is 0*/
pdir->fclusterhi = (word)(cluster >> 16);
pdir->fcluster = (word) cluster;
pdir->fsizeu.fsize = size;
pc_zero_lfn_info(pdir);
}
/***************************************************************************
PC_INO2DOS - Convert an in memory inode to a dos disk entry.
Description
Take in memory native format inode information and copy it to a
buffer. Translate the inode to INTEL byte ordering during the transfer.
Returns
Nothing
***************************************************************************/
/* Un-Make a disk directory entry */
/* Convert an inmem inode to dos form. */
void pc_ino2dos (DOSINODE *pbuff, FINODE *pdir) /*__fn__*/
{
pc_cs_ascii_strn2upper((byte *)&pbuff->fname[0],(byte *)&pdir->fname[0],8); /*X*/
pc_cs_ascii_strn2upper((byte *)&pbuff->fext[0],(byte *)&pdir->fext[0],3); /*X*/
pbuff->fattribute = pdir->fattribute; /*X*/
/* If the first character is 0xE5 (valid kanji) convert it to 0x5 */
if (pdir->fname[0] == PCDELETE) /* 0XE5 */
pbuff->fname[0] = 0x5;
/* If rmnode wants us to delete the file set it to 0xE5 */
if (pdir->fname[0] == PCDELETEESCAPE)
pbuff->fname[0] = PCDELETE;
pbuff->reservednt = pdir->reservednt;
pbuff->create10msincrement = pdir->create10msincrement;;
#if (KS_LITTLE_ENDIAN)
pbuff->ftime = pdir->ftime;
pbuff->fdate = pdir->fdate;
pbuff->ctime = pdir->ctime;
pbuff->cdate = pdir->cdate;
pbuff->adate = pdir->adate;
pbuff->fcluster = pdir->fcluster;
/* Note: fclusterhi is of resarea in fat 16 system */
pbuff->fclusterhi = pdir->fclusterhi;
pbuff->fsize = pdir->fsizeu.fsize;
#else
fr_WORD((byte *) &pbuff->ftime,pdir->ftime); /*X*/
fr_WORD((byte *) &pbuff->fdate,pdir->fdate); /*X*/
fr_WORD((byte *) &pbuff->ctime,pdir->ctime);
fr_WORD((byte *) &pbuff->cdate,pdir->cdate);
fr_WORD((byte *) &pbuff->adate,pdir->adate);
fr_WORD((byte *) &pbuff->fcluster,pdir->fcluster); /*X*/
/* Note: fclusterhi is of resarea in fat 16 system */
fr_WORD((byte *) &pbuff->fclusterhi,pdir->fclusterhi); /*X*/
fr_DWORD((byte *) &pbuff->fsize,pdir->fsizeu.fsize); /*X*/
#endif
}
#endif /* Exclude from build if read only */

View File

@ -0,0 +1,469 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2008
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* RTERASEBLOCK.C - Erase block aware functions, shared by Pro and Pro Plus.
*/
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
#if (INCLUDE_NAND_DRIVER) /* rteraseblock.c source file is needed only for dynamic mode */
dword get_clusters_per_erase_block(DDRIVE *pdr);
static BOOLEAN erase_block_if_free(DDRIVE *pdr, dword eb_start_cluster,dword clusters_per_erase_block, dword erase_block_size_sectors);
static void get_erase_block_boundaries(DDRIVE *pdr, dword cluster, dword *pstart, dword *pend);
static BOOLEAN erase_logical_sectors(DDRIVE *pdr, dword start_sector, dword n_sectors);
/* BOOLEAN eraseop_erase_blocks(DDRIVE *pdr, BOOLEAN is_file, dword start_cluster, dword n_clusters)
Inputs: dword cluster, dword ncontig - cluster range to erase
Outputs -
Returns TRUE if no errors
Erase the erase blocks containing the range start_cluster to (start_cluster + n_clusters - 1).
If the start or end clusters are not erase block bound, only erase the block if all other clusters
in the erase block are also free.
If the drive does no have erase blocks then simply return success
*/
BOOLEAN eraseop_erase_blocks(DDRIVE *pdr, dword cluster, dword ncontig)
{
if (pdr && pdr->pmedia_info->eraseblock_size_sectors)
{
dword erase_block_size_sectors, cluster_size_sectors, first_eb_cluster, last_eb_cluster;
cluster_size_sectors = (dword) (pdr->drive_info.secpalloc); /* byte to dword */
erase_block_size_sectors = pdr->pmedia_info->eraseblock_size_sectors;
if (!cluster_size_sectors || !erase_block_size_sectors) /* Defensive won't happen */
return(TRUE); /* Something is wrong, but return TRUE, if driver is down it will be caught again */
else if (cluster_size_sectors >= erase_block_size_sectors)
{ /* Clusters >= erase block size. They must be erase block bound */
if (!erase_logical_sectors(pdr, pc_cl2sector(pdr, cluster), ncontig << pdr->drive_info.log2_secpalloc) )
goto return_error;
}
else
{ /* erase block contains multiple clusters */
dword n_left, clusters_per_erase_block;
clusters_per_erase_block = get_clusters_per_erase_block(pdr);
if (!clusters_per_erase_block)
goto return_error; /* Defensive, won't happen */
n_left = ncontig;
while (n_left)
{
/* Get the boundaries of the current erase block */
get_erase_block_boundaries(pdr, cluster, &first_eb_cluster, &last_eb_cluster);
if (cluster != first_eb_cluster || n_left < clusters_per_erase_block)
{ /* If not spanning a whole erase block, call partial erase block routine to erase it only the whole block is free */
dword n_used;
if (!erase_block_if_free(pdr, first_eb_cluster, clusters_per_erase_block, erase_block_size_sectors))
goto return_error;
/* Subtract the number of cluster to the end of the erase block from n_left, truncate if we overshoot */
n_used = last_eb_cluster - cluster + 1;
if (n_left > n_used)
{
n_left -= n_used;
cluster = last_eb_cluster + 1;
}
else
n_left = 0;
}
else
{ /* If spanning a whole erase block, call full erase block routine to erase it */
if (!erase_logical_sectors(pdr, pc_cl2sector(pdr, first_eb_cluster), erase_block_size_sectors))
goto return_error;
/* Subtract clusters_per_erase_block from n_left, will not overshoot */
n_left -= clusters_per_erase_block;
cluster = first_eb_cluster + clusters_per_erase_block;
}
}
}
}
return(TRUE);
return_error:
return(FALSE);
}
#define EB_PARTIAL 1
#define EB_EMPTY 2
#define EB_PARTIALOREMPTY 3
#define EB_FULL 4
#define EB_COMPLETE 5
/* Search for cluster(s) in freespace without regard to allocation_scheme */
static dword _find_free_clusters(DDRIVE *pdr, dword start_point, dword last_eb_cluster, dword min_clusters, dword max_clusters, dword *p_contig, int *is_error)
{
*p_contig = 0; /* Bug Fix July 2010. Clear the n_contig value (upper level was consulting it even with return value indicating none found */
#if (INCLUDE_RTFS_FREEMANAGER)
/* Search ram based free manager for clusters to allocate.. if the ram based manager is shut down
free_manager_find_contiguous_free_clusters() will perform FAT scans for free clusters but exclude
free clusters that are reserved by Failsafe */
return(free_manager_find_contiguous_free_clusters(pdr, start_point, last_eb_cluster, min_clusters, max_clusters, p_contig, is_error));
#else
/* Call FAT scan routine */
return(_fatop_find_contiguous_free_clusters(pdr, start_point, last_eb_cluster, min_clusters, max_clusters, p_contig, is_error));
#endif
}
/* Search for cluster(s) in freespace taking into consideration the allocation_scheme
if (allocation_scheme == ALLOC_CLUSTERS_ALIGNED) - Allocate for fastest writing
Take clusters from empty erase blocks first, use partial as a last resort
if (allocation_scheme == ALLOC_CLUSTERS_UNALIGNED) - Allocate for garbage collecting partially used erase blocks
Take clusters from partially empty erase blocks first, use empties as a last resort
otherwise
Take the first cluster(s) that fulfill the request (traditional algorithm)
This routine is only called if the drive has erase blocks
*/
dword eraseop_find_free_clusters(DDRIVE *pdr, dword startpt, dword endpt, dword min_clusters, dword max_clusters, int allocation_scheme, dword *p_contig, int *is_error)
{
dword clusters_per_erase_block;
dword current_start_point, first_free_eb_cluster, first_eb_cluster, last_eb_cluster, num_free_cluster_in_eb;
dword cur_empty_contiguous_clusters, cur_empty_start_cluster;
dword max_empty_contiguous_clusters, max_empty_start_cluster;
dword cur_partial_contiguous_clusters, cur_partial_start_cluster;
dword max_partial_contiguous_clusters, max_partial_start_cluster;
int do_close_on, do_process_on, do_return_processing;
int search_precedence;
dword ret_val = 0;
/* Intialize return values and scan values */
clusters_per_erase_block = get_clusters_per_erase_block(pdr);
*p_contig = 0;
cur_empty_contiguous_clusters = cur_empty_start_cluster = 0;
max_empty_contiguous_clusters = max_empty_start_cluster = 0;
cur_partial_contiguous_clusters = cur_partial_start_cluster = 0;
max_partial_contiguous_clusters = max_partial_start_cluster = 0;
/* Determine the search algorithm */
if (allocation_scheme == ALLOC_CLUSTERS_ALIGNED)
search_precedence = EB_EMPTY; /* Take clusters from empty erase blocks first, use partial as a last resort */
else if (allocation_scheme == ALLOC_CLUSTERS_UNALIGNED)
search_precedence = EB_PARTIAL; /* Take clusters from partially empty erase blocks first, use empties as a last resort */
else
search_precedence = EB_PARTIALOREMPTY; /* Take the first cluster(s) that fulfill the request */
/* Intialize state values */
do_return_processing = do_close_on = do_process_on = 0;
/* Get the first and last clusters in the current erase block */
get_erase_block_boundaries(pdr, startpt, &first_eb_cluster, &last_eb_cluster);
/* Start search algorithm at the beginning of the erase block */
current_start_point = first_eb_cluster;
/* Start at current_start_point and retrieve the first free group of clusters return up to the number of clusters left in the current erase block.
retrieve:
num_free_cluster_in_eb - Number of free clusters found between current_start_point and the end of the erase block.
first_free_eb_cluster - First free cluster between current_start_point and the end of the erase block or zero
*/
/* The way we use the memory manager we report multiple PENOSPC space errors in debug mode so clear them */
first_free_eb_cluster = _find_free_clusters(pdr, current_start_point, last_eb_cluster, 1, (last_eb_cluster - current_start_point + 1), &num_free_cluster_in_eb, is_error);
if (!first_free_eb_cluster)
num_free_cluster_in_eb = 0;
if (*is_error)
goto restore_errno_and_exit;
for(;;)
{
dword last_current_start_point;
last_current_start_point = current_start_point; /* Defensive, test endless loops */
/* First test if our last scan finished and we have to process close and return */
do_close_on = 0;
if (do_process_on == EB_COMPLETE)
{ /* If we finished scan, check close processing and exit */
if (cur_partial_contiguous_clusters)
do_close_on = EB_PARTIAL;
else if (cur_empty_contiguous_clusters)
do_close_on = EB_EMPTY;
/* After close processing we will break out */
}
/* Decide what to do with free clusters in this erase blocs "num_free_cluster_in_eb" */
else if (num_free_cluster_in_eb == clusters_per_erase_block)
{ /* current_start_point is on a boundary and all clusters in erase blocks are free */
if (cur_partial_contiguous_clusters)
do_close_on = EB_PARTIAL;
do_process_on = EB_EMPTY;
}
else if (num_free_cluster_in_eb == 0)
{ /* All clusters in erase blocks are already allocated close any free segments and skip to the next */
if (cur_partial_contiguous_clusters)
do_close_on = EB_PARTIAL;
else if (cur_empty_contiguous_clusters)
do_close_on = EB_EMPTY;
do_process_on = EB_FULL;
}
else
{ /* Only some clusters in erase blocks are free */
if (cur_empty_contiguous_clusters)
do_close_on = EB_EMPTY; /* close segments from empty erase blocks */
else
{
if (cur_partial_contiguous_clusters && first_free_eb_cluster != first_eb_cluster)
do_close_on = EB_PARTIAL; /* close segments from partial erase block because we are not adjacent */
}
do_process_on = EB_PARTIAL;
}
/* Process strings that just closed if there are any */
if (do_close_on == EB_EMPTY)
{ /* If we hit a new maximum process it */
if (cur_empty_contiguous_clusters > max_empty_contiguous_clusters)
{
max_empty_contiguous_clusters = cur_empty_contiguous_clusters;
max_empty_start_cluster = cur_empty_start_cluster;
/* Return the string if our new max is >= the minimum required and we are looking for empty blocks */
if (max_empty_contiguous_clusters >= min_clusters)
{
if (search_precedence == EB_EMPTY || search_precedence == EB_PARTIALOREMPTY)
{
do_return_processing = EB_EMPTY;
break;
}
}
}
cur_empty_contiguous_clusters = 0; /* Close so we start a new tally next time we process an empty block */
}
else if (do_close_on == EB_PARTIAL)
{ /* If we hit a new maximum process it */
if (cur_partial_contiguous_clusters > max_partial_contiguous_clusters)
{
max_partial_contiguous_clusters = cur_partial_contiguous_clusters;
max_partial_start_cluster = cur_partial_start_cluster;
/* Return the string if our new max is >= the minimum required. and we are looking for partial blocks */
if (max_partial_contiguous_clusters >= min_clusters)
{
if (search_precedence == EB_PARTIAL || search_precedence == EB_PARTIALOREMPTY)
{
do_return_processing = EB_PARTIAL;
break;
}
}
}
cur_partial_contiguous_clusters = 0; /* Close so we start a new tally next time we process a partial block */
}
/* Process the values we placed in first_free_eb_cluster and num_free_cluster_in_eb
and advance start pointer and if necessary the erase block */
if (do_process_on == EB_COMPLETE)
{
break;
}
else if (do_process_on == EB_EMPTY)
{
if (!cur_empty_contiguous_clusters)
cur_empty_start_cluster = first_free_eb_cluster;
cur_empty_contiguous_clusters += num_free_cluster_in_eb;
/* If we hit a new maximum process it if we haven't hit the outer maximum already */
if (cur_empty_contiguous_clusters > max_empty_contiguous_clusters &&
max_empty_contiguous_clusters < max_clusters)
{
/* If the new maximum is as large as we need, process possible imediate return */
max_empty_contiguous_clusters = cur_empty_contiguous_clusters;
max_empty_start_cluster = cur_empty_start_cluster;
if (max_empty_contiguous_clusters >= max_clusters)
{
if (search_precedence == EB_EMPTY || search_precedence == EB_PARTIALOREMPTY)
{
do_return_processing = EB_EMPTY;
break;
}
}
}
/* Advance pointers by a full erase block */
first_eb_cluster += clusters_per_erase_block;
last_eb_cluster += clusters_per_erase_block;
current_start_point += clusters_per_erase_block;
}
else if (do_process_on == EB_PARTIAL)
{
if (!cur_partial_contiguous_clusters)
cur_partial_start_cluster = first_free_eb_cluster;
cur_partial_contiguous_clusters += num_free_cluster_in_eb;
/* If we hit a new maximum process it if we haven't hit the outer maximum already */
if (cur_partial_contiguous_clusters > max_partial_contiguous_clusters &&
max_partial_contiguous_clusters < max_clusters)
{
/* If the new maximum is as large as we need, process possible imediate return */
max_partial_contiguous_clusters = cur_partial_contiguous_clusters;
max_partial_start_cluster = cur_partial_start_cluster;
if (max_partial_contiguous_clusters >= max_clusters)
{
if (search_precedence == EB_PARTIAL || search_precedence == EB_PARTIALOREMPTY)
{
do_return_processing = EB_PARTIAL;
break;
}
}
}
/* Advance by the number we found (can not be zero)*/
current_start_point += num_free_cluster_in_eb;
/* Advance the erase block if we advanced */
if (current_start_point > last_eb_cluster)
{
first_eb_cluster += clusters_per_erase_block;
last_eb_cluster += clusters_per_erase_block;
}
}
else if (do_process_on == EB_FULL)
{ /* Erase block was empty, advance pointers by a full erase block */
first_eb_cluster += clusters_per_erase_block;
last_eb_cluster += clusters_per_erase_block;
current_start_point += clusters_per_erase_block;
}
/* get first_free_eb_cluster and num_free_cluster_in_eb from the next erase block */
if (current_start_point > endpt)
{ /* Past the end EB_COMPLETE state in next loop will allow close processing and then break out */
do_process_on = EB_COMPLETE;
}
/* Check if this erase block is the last one in our range */
else if (endpt <= last_eb_cluster)
{
/* Only find up to (endpt-current_start_point+1) free clusters */
first_free_eb_cluster = _find_free_clusters(pdr, current_start_point, last_eb_cluster, 1, (endpt-current_start_point+1), &num_free_cluster_in_eb, is_error);
if (*is_error)
goto restore_errno_and_exit;
do_process_on = 0;
}
else
{
/* Find up to clusters_per_erase_block free clusters */
first_free_eb_cluster = _find_free_clusters(pdr, current_start_point, last_eb_cluster, 1, clusters_per_erase_block, &num_free_cluster_in_eb, is_error);
if (*is_error)
goto restore_errno_and_exit;
do_process_on = 0;
}
if (current_start_point <= last_current_start_point) /* Defensive, test endless loops */
{
*is_error = 1;
rtfs_set_errno(PEINTERNAL, __FILE__, __LINE__);
ERTFS_ASSERT(0)
goto restore_errno_and_exit;
}
}
/* Process returns */
{
dword n_contig;
if (do_return_processing == EB_PARTIAL)
{
n_contig = max_partial_contiguous_clusters;
ret_val = max_partial_start_cluster;
}
else if (do_return_processing == EB_EMPTY)
{
n_contig = max_empty_contiguous_clusters;
ret_val = max_empty_start_cluster;
}
else
{
n_contig = 0;
ret_val = 0;
}
/* Truncate contiguous_clusters if > max_clusters */
if (max_clusters && n_contig > max_clusters)
n_contig = max_clusters;
*p_contig = n_contig;
}
restore_errno_and_exit:
if (*is_error == 0 && ret_val)
rtfs_clear_errno(); /* clear error status */
return(ret_val);
}
dword get_clusters_per_erase_block(DDRIVE *pdr)
{
dword erase_block_size_sectors, cluster_size_sectors;
cluster_size_sectors = (dword) (pdr->drive_info.secpalloc); /* byte to dword */
erase_block_size_sectors = pdr->pmedia_info->eraseblock_size_sectors;
if (!cluster_size_sectors || !erase_block_size_sectors) /* Defensive, won't happen */
return(1);
return(erase_block_size_sectors / cluster_size_sectors); /* cluster_size_sectors is not zero */
}
/* erase an erase block if all clusters in it are free if pdr->pmedia_info->device_erase is unavailable return success*/
static BOOLEAN erase_block_if_free(DDRIVE *pdr, dword eb_start_cluster,dword clusters_per_erase_block, dword erase_block_size_sectors)
{
dword n_free, found_cluster;
int is_error;
is_error = 0;
if (!pdr->pmedia_info->device_erase)
return(TRUE);
n_free = _find_free_clusters(pdr, eb_start_cluster, eb_start_cluster + clusters_per_erase_block-1,
clusters_per_erase_block, clusters_per_erase_block, &found_cluster, &is_error);
if (is_error)
return(FALSE);
if (n_free >= clusters_per_erase_block)
{
if (!erase_logical_sectors(pdr, pc_cl2sector(pdr, eb_start_cluster), erase_block_size_sectors))
return(FALSE);
}
return(TRUE);
}
static BOOLEAN erase_logical_sectors(DDRIVE *pdr, dword start_sector, dword n_sectors)
{
/* Removed test of if (pdr->drive_flags & DRIVE_FLAGS_PARTITIONED). partition_base will be zero if the device is not partitioned */
start_sector += pdr->drive_info.partition_base;
if (!pdr->pmedia_info->device_erase ||
!pdr->pmedia_info->device_erase(pdr->pmedia_info->devhandle, (void *) pdr, start_sector, n_sectors) )
return(FALSE);
return(TRUE);
}
/* return start and end clusters of the erase block containing "cluster" */
static void get_erase_block_boundaries(DDRIVE *pdr, dword cluster, dword *pstart, dword *pend)
{
dword erase_block_size_sectors, cluster_size_sectors;
cluster_size_sectors = (dword) (pdr->drive_info.secpalloc); /* byte to dword */
erase_block_size_sectors = pdr->pmedia_info->eraseblock_size_sectors;
*pstart = *pend = cluster;
if (!erase_block_size_sectors) /* no erase blocks */
return;
if (!cluster_size_sectors) /* Defensive, won't happen */
return;
if (cluster_size_sectors >= erase_block_size_sectors) /* The cluster overlaps erase blocks, so it is on a boundary */
return;
else
{ /* The cluster size is less than the erase block size (but the erase block size is a multiple of the cluster size) */
dword clusters_per_eb, cluster_offsetmask,cluster_basemask;
clusters_per_eb = get_clusters_per_erase_block(pdr);
cluster_offsetmask = clusters_per_eb-1;
cluster_basemask = ~cluster_offsetmask;
{ /* Normalize the cluster number sinece the first cluster actually has the index 2 */
dword _cluster;
/* Normalize the cluster number since the first cluster actually has the index 2 */
_cluster = cluster - 2;
/* And with the base mask to get the next lowest cluster on an erase block boundary */
_cluster = _cluster & cluster_basemask;
/* Add the 2 back in */
*pstart = _cluster + 2;
/* Add in (clusters_per_eb-1) to get the end */
*pend = *pstart + clusters_per_eb - 1;
}
}
}
#endif /* (INCLUDE_NAND_DRIVER) */
#endif /* Exclude from build if read only */

View File

@ -0,0 +1,855 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* RTFATDRV.C - Low level FAT management functions, shared by Pro and Pro Plus.
*/
#include "rtfs.h"
static BOOLEAN fatop_buff_check_freespace(DDRIVE *pdr);
dword _fatop_get_frag(DDRIVE *pdr, byte *palt_buffer, dword alt_buffer_size, dword startpt, dword *pnext_cluster, dword n_clusters, int *end_of_chain, BOOLEAN is_async);
static dword fatop_buff_get_frag(DDRIVE *pdr, dword start_cluster, dword *pnext_cluster, dword n_clusters, int *end_of_chain);
#if (RTFS_CFG_LEAN)
#define INCLUDE_FATPAGE_DRIVER 0
#else
#define INCLUDE_FATPAGE_DRIVER 1
#endif
#if (INCLUDE_FATPAGE_DRIVER) /* Declare friend functions to rtfatdrv.c provided by ProPlus */
static dword fatop_page_get_frag(DDRIVE *pdr, byte *palt_buffer, dword alt_buffer_size, dword startpt, dword *pnext_cluster, dword n_clusters, int *end_of_chain, BOOLEAN is_async);
static BOOLEAN fatop_page_check_freespace(DDRIVE *pdr);
#endif
#if (INCLUDE_FAT32)
static BOOLEAN fatxx_pfgdword(DDRIVE *pdr, dword index, dword *value);
#endif
/******************************************************************************
fatop_check_freespace - Load fat free space at mount time
Description
Scan the FAT and determine the number of free clusters.
Returns
FALSE if an io error occurred during fat swapping, else TRUE
*****************************************************************************/
static BOOLEAN fatop_buff_check_freespace(DDRIVE *pdr);
BOOLEAN fatop_check_freespace(DDRIVE *pdr)
{
pdr->drive_info.known_free_clusters = 0;
#if (INCLUDE_FATPAGE_DRIVER)
if (pdr->drive_info.fasize != 3)
return(fatop_page_check_freespace(pdr));
#endif
return(fatop_buff_check_freespace(pdr));
}
static BOOLEAN fatop_buff_check_freespace(DDRIVE *pdr)
{
dword i;
dword start,nxt;
dword freecount = 0;
start = 0;
for (i = 2 ; i <= pdr->drive_info.maxfindex; i++)
{
if (!fatop_get_cluster(pdr, i, &nxt)) /* Any (ifree) */
return(FALSE);
if (nxt == 0)
{
if (!start) {start = i; freecount = 0; }
freecount++;
}
else
{
if (start)
{
if (!fatop_add_free_region(pdr, start, freecount, FALSE))
return(FALSE);
start = 0;
}
}
}
if (start)
if (!fatop_add_free_region(pdr, start, freecount, FALSE))
return(FALSE);
return(TRUE);
}
/* Called when the driver open count goes to zero. NO-OP Under rtfspro.. */
void fatop_close_driver(DDRIVE *pdr)
{
#if (INCLUDE_RTFS_FREEMANAGER) /* fatop_close_driver() release free regions */
free_manager_close(pdr); /* Claim semaphoire before releaseing */
#else
RTFS_ARGSUSED_PVOID((void *) pdr); /* Not used by Pro */
#endif
}
/* Retrieve a value from the fat */
BOOLEAN fatop_get_cluster(DDRIVE *pdr, dword clno, dword *pvalue) /*__fatfn__*/
{
dword nibble,index, offset, result;
byte c;
union align1 {
byte wrdbuf[4]; /* Temp storage area */
word fill[2];
} u;
union align2 {
byte wrdbuf2[4]; /* Temp storage area */
word fill[2];
} u2;
if ((clno < 2) || (clno > pdr->drive_info.maxfindex) )
{
rtfs_set_errno(PEINVALIDCLUSTER, __FILE__, __LINE__); /* fatop_get_cluster: bad cluster value internal error */
return (FALSE);
}
result = 0;
if (pdr->drive_info.fasize == 3) /* 3 nibble ? */
{
nibble = (word)(clno * 3);
index = (word)(nibble >> 2);
offset = (word)(clno & 0x03);
/* Read the first word */
if (!fatxx_fword( pdr, index, (word *) &u.wrdbuf[0], FALSE ))
return(FALSE);
/*
| W0 | W1 | W2 |
A1 A0 B0 A2 B2 B1 C1 C0 D0 C2 D2 D1
xx xx xx
*/
if (offset == 0) /* (A2 << 8) | A1 A2 */
{
/* BYTE 0 == s Low byte, byte 1 low nibble == s high byte */
u.wrdbuf[1] &= 0x0f;
result = u.wrdbuf[1];
result <<= 8;
result |= u.wrdbuf[0];
}
/*
| W0 | W1 | W2 |
A1 A0 B0 A2 B2 B1 C1 C0 D0 C2 D2 D1
xx xx xx
*/
else if (offset == 1) /* (B1 B2 << 4) | B0 */
{
/* BYTE 2 == High byte Byte 1 high nibb == low nib */
if (!fatxx_fword( pdr, (word)(index+1), (word *) &u2.wrdbuf2[0], FALSE ))
return(FALSE);
c = (byte) (u.wrdbuf[1] >> 4);
result = u2.wrdbuf2[0];
result <<= 4;
result |= c;
}
/*
| W0 | W1 | W2 |
A1 A0 B0 A2 B2 B1 C1 C0 D0 C2 D2 D1
xx xx xx
*/
else if (offset == 2) /*(C2 << 8) | C1 C2 */
{
if (!fatxx_fword( pdr, (word)(index+1), (word *) &u2.wrdbuf2[0], FALSE ))
return(FALSE);
/* BYTE 1 == s Low byte, byte 2 low nibble == s high byte */
result = (word) (u2.wrdbuf2[0] & 0x0f);
result <<= 8;
result |= u.wrdbuf[1];
}
/*
| W0 | W1 | W2 |
A1 A0 B0 A2 B2 B1 C1 C0 D0 C2 D2 D1
xx xx xx
*/
else if (offset == 3) /* (D2 D1) << 4 | D0 */
{
result = u.wrdbuf[1];
result <<= 4;
c = u.wrdbuf[0];
c >>= 4;
result |= c;
}
}
else if (pdr->drive_info.fasize == 8) /* 32 BIT fat. ret the value at 4 * clno */
{
#if (INCLUDE_FAT32)
#if KS_LITTLE_ENDIAN
if (!fatxx_pfgdword( pdr, clno, (dword *) &result ))
return (FALSE);
#else
if ( fatxx_pfgdword( pdr, clno, (dword *) &u.wrdbuf[0] ))
result = (dword) to_DWORD(&u.wrdbuf[0]);
else
return (FALSE);
#endif
#else
return (FALSE);
#endif
}
else /* 16 BIT fat. ret the value at 2 * clno */
{
if ( fatxx_fword( pdr, clno, (word *) &u.wrdbuf[0], FALSE ))
result = (dword) to_WORD(&u.wrdbuf[0]); /*X*/ /* And use the product as index */
else
return (FALSE);
}
#if (INCLUDE_EXFAT) /* FAT64 does not use cluster chains */
if (!ISEXFAT(pdr) )
#endif
{
result &= 0x0fffffff;
}
*pvalue = result;
return (TRUE);
}
dword fatop_next_cluster(DDRIVE *pdr, dword cluster)
{
dword nxt;
if (!fatop_get_cluster(pdr, cluster, &nxt))
return(0);
#if (INCLUDE_EXFAT) /* FAT64 does not use cluster chains */
if ( ISEXFAT(pdr) )
{
if (nxt >= 0xfffffff7)
nxt = FAT_EOF_RVAL; /* end of chain */
}
else
#endif
{
if ( (pdr->drive_info.fasize == 3 && nxt >= 0xff8) ||
(pdr->drive_info.fasize == 4 && nxt >= 0xfff8) ||
(pdr->drive_info.fasize == 8 && nxt >= 0x0ffffff8))
nxt = FAT_EOF_RVAL; /* end of chain */
}
if (nxt != FAT_EOF_RVAL && (nxt < 2 || nxt > pdr->drive_info.maxfindex) )
{
rtfs_set_errno(PEINVALIDCLUSTER, __FILE__, __LINE__);
return (0);
}
return(nxt);
}
BOOLEAN fatop_add_free_region(DDRIVE *pdr, dword cluster, dword ncontig, BOOLEAN do_erase)
{
if (cluster > pdr->drive_info.maxfindex || (cluster+ncontig-1) > pdr->drive_info.maxfindex)
{
ERTFS_ASSERT(rtfs_debug_zero())
return(TRUE);
}
#if (INCLUDE_RTFS_FREEMANAGER)
free_manager_release_clusters(pdr, cluster, ncontig, do_erase);
#else
#if (INCLUDE_NAND_DRIVER) /* calling eraseop_erase_blocks() in dynamic mode */
/* If the free manager is included it erased blocks if necessary
If not we have to do it here */
if (do_erase)
eraseop_erase_blocks(pdr, cluster, ncontig);
#else
RTFS_ARGSUSED_INT((int)do_erase);
#endif
#endif
pdr->drive_info.known_free_clusters = pdr->drive_info.known_free_clusters + ncontig;
ERTFS_ASSERT(pdr->drive_info.known_free_clusters < pdr->drive_info.maxfindex)
#if (INCLUDE_EXFATORFAT64)
if (!ISEXFATORFAT64(pdr) ) /* Update free_contig_pointer if not exfat */
#endif
{
/* Update Pro style free pointer hints. Exfat updates this field differently */
if (cluster >= pdr->drive_info.free_contig_base && cluster <= pdr->drive_info.free_contig_pointer)
pdr->drive_info.free_contig_pointer = cluster;
}
return(TRUE);
}
/****************************************************************************
fatop_get_frag - Return as many contiguous clusters as possible.
Description
Starting at start_cluster return the number of contiguous clusters
allocated in the chain containing start_cluster or n_clusters,
whichever is less.
Returns
Returns the number of contiguous clusters found. Or zero on an error.
This function should always return at least one. (start_cluster). Unless
an error occurs.
The dword at *pnext_cluster is filled with on of the following:
. If we went beyond a contiguous section it contains
the first cluster in the next segment of the chain.
. If we are still in a section it contains
the next cluster in the current segment of the chain.
. If we are at the end of the chain it contains the last cluster
in the chain.
****************************************************************************/
dword _fatop_get_frag(DDRIVE *pdr, byte *palt_buffer, dword alt_buffer_size, dword startpt, dword *pnext_cluster, dword n_clusters, int *end_of_chain, BOOLEAN is_async);
dword fatop_get_frag_async(DDRIVE *pdr, byte *palt_buffer, dword alt_buffer_size, dword startpt, dword *pnext_cluster, dword n_clusters, int *end_of_chain)
{
return(_fatop_get_frag(pdr, palt_buffer, alt_buffer_size, startpt, pnext_cluster, n_clusters, end_of_chain, TRUE));
}
dword fatop_get_frag(DDRIVE *pdr, byte *palt_buffer, dword alt_buffer_size, dword startpt, dword *pnext_cluster, dword n_clusters, int *end_of_chain)
{
return(_fatop_get_frag(pdr, palt_buffer, alt_buffer_size, startpt, pnext_cluster, n_clusters, end_of_chain, FALSE));
}
dword _fatop_get_frag(DDRIVE *pdr, byte *palt_buffer, dword alt_buffer_size, dword startpt, dword *pnext_cluster, dword n_clusters, int *end_of_chain, BOOLEAN is_async)
{
/* Truncate the end point to the end of the fat. This allows us to
signify scan to end of fat by passing maxfindex as nclusters */
if (n_clusters > pdr->drive_info.maxfindex)
n_clusters = pdr->drive_info.maxfindex-startpt + 1;
else if ((startpt + n_clusters-1) > pdr->drive_info.maxfindex)
n_clusters = pdr->drive_info.maxfindex-startpt + 1;
if ((startpt < 2) || startpt > pdr->drive_info.maxfindex)
{
rtfs_set_errno(PEINVALIDCLUSTER, __FILE__, __LINE__);
return (0);
}
#if (INCLUDE_FATPAGE_DRIVER)
if (pdr->drive_info.fasize != 3)
return(fatop_page_get_frag(pdr, palt_buffer, alt_buffer_size, startpt, pnext_cluster, n_clusters,end_of_chain, is_async));
#else
RTFS_ARGSUSED_PVOID((void *) palt_buffer);
RTFS_ARGSUSED_DWORD(alt_buffer_size);
RTFS_ARGSUSED_INT((int)is_async);
#endif
return(fatop_buff_get_frag(pdr, startpt, pnext_cluster, n_clusters,end_of_chain));
}
/****************************************************************************
fatop_buff_get_frag - Return as many contiguous clusters as possible.
Description
Starting at start_cluster return the number of contiguous clusters
allocated in the chain containing start_cluster or n_clusters,
whichever is less.
Returns
Returns the number of contiguous clusters found. Or zero on an error.
This function should always return at least one. (start_cluster). Unless
an error occurs.
The word at *pnext_cluster is filled with on of the following:
. If we went beyond a contiguous section it contains
the first cluster in the next segment of the chain.
. If we are still in a section it contains
the next cluster in the current segment of the chain.
. If we are at the end of the chain it contains the last cluster
in the chain.
****************************************************************************/
static dword fatop_buff_get_frag(DDRIVE *pdr, dword start_cluster, dword *pnext_cluster, dword n_clusters, int *end_of_chain)
{
dword clno, next_cluster;
dword n_contig;
dword value;
value = 0;
clno = start_cluster;
n_contig = 1;
*pnext_cluster = 0;
/* Get each FAT entry. If its value points to the next contiguous entry
continue. Otherwise we have reached the end of the contiguous chain.
At which point we return the number of contig s found and by reference
the address of the FAT entry beginning the next chain segment.
*/
*end_of_chain = 0;
for (;;)
{
next_cluster = fatop_next_cluster(pdr, clno);
if (!next_cluster) /* fatop_next_cluster detected an error */
return(0);
/* check for end markers set next cluster to the last
cluster in the chain if we are at the end */
if (next_cluster == FAT_EOF_RVAL) /* fatop_next_cluster detected end */
{
*end_of_chain = 1;
value = clno;
break;
}
else if (next_cluster == ++clno)
{
value = next_cluster;
if (n_contig >= n_clusters)
break;
n_contig++;
}
else /* (next_cluster != ++clno) and we know it is not an error condition */
{
value = next_cluster;
break;
}
}
*pnext_cluster = value;
return (n_contig);
}
/* Put or get a WORD value into the fat at index */
BOOLEAN fatxx_fword(DDRIVE *pdr, dword index, word *pvalue, BOOLEAN putting) /*__fatfn__*/
{
word *ppage;
word offset;
/* Make sure we have access to the page. Mark it for writing (if a put) */
ppage = (word *)fatxx_pfswap(pdr,index,putting);
if (!ppage)
return(FALSE);
else
{
/* there are 256 * sectorsize entries per page */
offset = (word) (index & pdr->drive_info.cl16maskblock);
if (putting)
ppage[offset] = *pvalue;
else
*pvalue = ppage[offset];
}
return(TRUE);
}
#if (INCLUDE_FAT32)
/* Get a DWORD value from the fat at index */
static BOOLEAN fatxx_pfgdword(DDRIVE *pdr, dword index, dword *value) /*__fatfn__*/
{
dword *ppage;
dword offset;
/* Make sure we have access to the page. Do not Mark it for writing */
ppage = (dword *)fatxx_pfswap(pdr,index,FALSE);
if (!ppage)
return(FALSE);
else
{
/* there are 128 entries per page */
offset = (dword) (index & pdr->drive_info.cl32maskblock);
*value = ppage[(int)offset];
}
return(TRUE);
}
#endif
/***************************************************************************
PC_FATSW - Map in a page of the FAT
****************************************************************************/
/* Swap in the page containing index */
/* Note: The caller locks the fat before calling this routine */
byte * fatxx_pfswap(DDRIVE *pdr, dword index, BOOLEAN for_write) /*__fatfn__*/
{
dword sector_offset_in_fat;
dword flags;
if (pdr->drive_info.fasize == 8)
sector_offset_in_fat = (dword)(index >> (pdr->drive_info.log2_bytespsec-2)); /* Divide by (bytes per sector/4) */
else
sector_offset_in_fat = (word) (index >> (pdr->drive_info.log2_bytespsec-1));/* Divide by (bytes per sector/2) */
if (sector_offset_in_fat >= pdr->drive_info.secpfat) /* Check range */
return (0);
if (for_write)
flags = FATPAGEWRITE|FATPAGEREAD;
else
flags = FATPAGEREAD;
/* The 4th argument is the number of sectors in the buffer to set dirty on a write */
return (pc_map_fat_sector(pdr, &pdr->fatcontext, sector_offset_in_fat, 1, flags));
}
#if (INCLUDE_FATPAGE_DRIVER) /* Page oriented FAT16 or FAT 32 routines */
/* Declare friend functions to rtfatdrv.c provided by ProPlus */
void fatop_get_page_masks(DDRIVE *pdr, dword *mask_offset, dword *mask_cl_page, dword *cl_per_sector, dword *cl_to_page_shift, dword * bytes_per_entry)
{
if (pdr->drive_info.fasize == 8)
{
*mask_offset = pdr->drive_info.cl32maskblock;
*mask_cl_page = ~(*mask_offset);
*cl_per_sector = pdr->drive_info.clpfblock32;
*cl_to_page_shift = pdr->drive_info.log2_bytespsec - 2;
*bytes_per_entry = 4;
}
else
{
*mask_offset = pdr->drive_info.cl16maskblock;
*mask_cl_page = ~(*mask_offset);
*cl_per_sector = pdr->drive_info.clpfblock16;
*cl_to_page_shift = pdr->drive_info.log2_bytespsec - 1;
*bytes_per_entry = 2;
}
}
/* Called by: fatop_get_frag() */
static dword fatop_page_get_frag(DDRIVE *pdr, byte *palt_buffer, dword alt_buffer_size, dword startpt, dword *pnext_cluster, dword n_clusters, int *end_of_chain, BOOLEAN is_async)
{
dword mask_offset, mask_cl_page, cl_per_sector, cl_to_page_shift,bytes_per_entry;
dword i,n_clusters_left;
dword mapped_sector_count,cluster_offset_in_page, byte_offset_in_page, first_sector_offset_to_map;
byte *mapped_data,*pb;
dword current_cluster, num_this_page,n_contig;
dword term32;
#if (INCLUDE_EXFAT) /* FAT64 does not use cluster chains */
if (ISEXFAT(pdr))
term32 = (dword)0xfffffff8;
else
#endif
term32 = (dword)0xffffff8;
/* Get masks based on cluster size */
fatop_get_page_masks(pdr, &mask_offset, &mask_cl_page, &cl_per_sector, &cl_to_page_shift, &bytes_per_entry);
/* Get starting cluster, offsets, blocks etc */
cluster_offset_in_page = startpt&mask_offset;
byte_offset_in_page = cluster_offset_in_page*bytes_per_entry;
first_sector_offset_to_map = startpt>>cl_to_page_shift;
current_cluster = startpt;
n_contig = 1;
n_clusters_left = n_clusters;
while (n_clusters_left)
{
/* get a pointer to first_sector_offset_to_map and the number of blocks in the buffer
Only atteempts to map up to n_clusters_left*bytes_per_entry.
will return the optional buffer passed in in palt_buffer
if the clusters are aligned for efficient streaming and the clusters are not already
cached. Otherwise uses the fat buffer pool */
mapped_data = pc_map_fat_stream(pdr, &mapped_sector_count, first_sector_offset_to_map, byte_offset_in_page,
n_clusters_left*bytes_per_entry, palt_buffer, alt_buffer_size, TRUE);
if (!mapped_data) /* Error accessing the fat buffer (io error during read ?) errno was set below.. */
goto map_error;
if (mapped_data == palt_buffer)
{ /* pc_map_fat_stream() returned palt_buffer, meaning that the next "mapped_sector_count" blocks
are unmapped and we should read them. If mapped_data != palt_buffer then we know that
"mapped_sector_count" blocks at mapped data are cached in the fat buffer pool */
if (pc_read_fat_blocks (pdr, mapped_data, pdr->drive_info.fatblock+first_sector_offset_to_map, mapped_sector_count) < 0)
goto map_error;
}
first_sector_offset_to_map += mapped_sector_count; /* the next block we will want */
pb = mapped_data; /* set up pb for pointer access */
/* test as many as we can starting from cluster_offset_in_page (always zero after first iteration) */
num_this_page = mapped_sector_count<<cl_to_page_shift;
if (cluster_offset_in_page)
{
num_this_page -= cluster_offset_in_page;
pb += byte_offset_in_page; /* set up pb for pointer access */
byte_offset_in_page = 0; /* only first iteration may not be on a boundary */
cluster_offset_in_page = 0;
}
if (num_this_page > n_clusters_left)
num_this_page = n_clusters_left;
/* If it is async process at most one page.. */
if (is_async)
n_clusters = num_this_page;
if (pdr->drive_info.fasize == 8)
{
dword nxt_dw;
dword *pdw = (dword *) pb;
for (i = 0; i < num_this_page; i++)
{
/* July 2012.. this is a bug under exFat
nxt_dw = to_DWORD((byte *)pdw) & 0x0fffffff;
*/
nxt_dw = to_DWORD((byte *)pdw) & (term32|0xf);
current_cluster += 1;
if (nxt_dw != current_cluster)
{
current_cluster -= 1;
done_32:
if (nxt_dw >= term32)
{
*end_of_chain = 1;
*pnext_cluster = current_cluster;
}
else if (nxt_dw < 2 || nxt_dw > pdr->drive_info.maxfindex)
goto link_error; /* Handles 0xffffff6 and 0xffffff7 (reserved and bad */
else
{
*end_of_chain = 0;
*pnext_cluster = nxt_dw;
}
return(n_contig);
}
if (n_contig >= n_clusters)
goto done_32;
n_contig++;
pdw += 1;
}
}
else /* if (pdr->fasize == 4) */
{
word *pw = (word *) pb;
word clno_w, nxt_w;
clno_w = (word) (current_cluster&0xffff);
for (i = 0; i < num_this_page; i++)
{
nxt_w = to_WORD((byte *)pw);
clno_w += 1;
if (nxt_w != clno_w)
{
clno_w -= 1;
done_16:
if (nxt_w >= 0xfff8)
{
*end_of_chain = 1;
*pnext_cluster = (dword) clno_w;
}
else if (nxt_w < 2 || nxt_w > pdr->drive_info.maxfindex)
goto link_error; /* Handles 0xfff6 and 0xfff7 (reserved and bad */
else
{
*end_of_chain = 0;
*pnext_cluster = (dword) nxt_w;
}
return(n_contig);
}
if (n_contig >= n_clusters)
goto done_16;
n_contig++;
pw += 1;
}
current_cluster = (dword) clno_w;
}
n_clusters_left -= num_this_page;
}
link_error:
rtfs_set_errno(PEINVALIDCLUSTER, __FILE__, __LINE__);
return (0);
map_error:
return (0);
}
void fatop_page_start_check_freespace(DDRIVE *pdr)
{
#if (INCLUDE_RTFS_PROPLUS) /* Proplus set up async check_freespace(DDRIVE *pdr) */
pdr->drive_state.drv_async_current_fatblock = pdr->drive_info.fatblock;
pdr->drive_state.drv_async_current_cluster = 2;
pdr->drive_state.drv_async_region_start = 0;
pdr->drive_state.drv_async_region_length = 0;
#else
RTFS_ARGSUSED_PVOID((void *) pdr); /* Not used by Pro */
#endif
}
/******************************************************************************
fatop_page_check_freespace - Load fat free space at mount time
Description
Scan the FAT and determine the number of free clusters.
Returns
FALSE if an io error occurred during fat swapping, else TRUE
*****************************************************************************/
static BOOLEAN fatop_page_check_freespace(DDRIVE *pdr)
{
int status;
fatop_page_start_check_freespace(pdr);
do {
status = fatop_page_continue_check_freespace(pdr);
} while (status == PC_ASYNC_CONTINUE);
if (status != PC_ASYNC_COMPLETE)
return(FALSE);
else
return(TRUE);
}
byte *pc_get_raw_fat_buffer(DDRIVE *pdrive, dword *pbuffer_size_sectors);
int fatop_page_continue_check_freespace(DDRIVE *pdr)
{
dword max_sector, num_sectors, entries_per_buffer, next_page, buffer_size_sectors, user_buffer_size_sectors,
cluster, regionlength, region_start,current_fatsector;
int ret_val;
byte *pubuff, *pbuffer;
BOOLEAN finished;
dword *pdw;
word *pw;
ret_val = PC_ASYNC_ERROR;
user_buffer_size_sectors = 0;
#if (INCLUDE_RTFS_PROPLUS) /* ProPlus - re-enter and continue asynchronous check_freespace */
cluster = pdr->drive_state.drv_async_current_cluster;
regionlength = pdr->drive_state.drv_async_region_length;
region_start = pdr->drive_state.drv_async_region_start;
current_fatsector = pdr->drive_state.drv_async_current_fatblock;
#else /* Process synchronously from start to finish */
cluster = 2;
regionlength = 0;
region_start = 0;
current_fatsector = pdr->drive_info.fatblock;
#endif
/* Get pbuffer and user_buffer_size_sectors
If the user provided fat buffer space the fat buffer pool is not in use so we can use the whole fat buffer as
a transfer buffer get the user buffer, if it is smaller than the FAT buffer, release it and use the fat buffer
If the driver provided fat buffers there is no continuous buffer pool space so we must use the user buffer.
Note: The driver is required to provide a user buffer. if it support dynam
*/
/* Get user buffer and user_buffer_size_sectors */
pubuff = pc_claim_user_buffer(pdr, &user_buffer_size_sectors, 0); /* released on cleanup */
if (!pubuff)
user_buffer_size_sectors = 0;
{
byte * pfat_buffer;
dword fat_buffer_size_sectors;
/* Get fat buffer and fat _buffer_size_sectors */
pfat_buffer = pc_get_raw_fat_buffer(pdr, &fat_buffer_size_sectors);
if (user_buffer_size_sectors > fat_buffer_size_sectors)
{
pbuffer = pubuff; /* user buffer larger than fat buffer, buffer_size_sectors was set in pc_claim_user_buffer() */
buffer_size_sectors = user_buffer_size_sectors;
}
else
{ /* fat buffer larger than user buffer */
pbuffer = pfat_buffer;
buffer_size_sectors = fat_buffer_size_sectors;
}
}
/* Get number of blocks and number of clusters */
if (pdr->drive_info.fasize == 8)
{
entries_per_buffer = buffer_size_sectors << (pdr->drive_info.log2_bytespsec-2); /* Multiplies the number of sectors in a page times the number of dwords in a sector */
max_sector = pdr->drive_info.fatblock + ((pdr->drive_info.maxfindex+pdr->drive_info.clpfblock32-1) >> (pdr->drive_info.log2_bytespsec-2));
}
else
{
entries_per_buffer = buffer_size_sectors << (pdr->drive_info.log2_bytespsec-1); /* Multiplies the number of sectors in a page times the number of words in a sector */
max_sector = pdr->drive_info.fatblock + ((pdr->drive_info.maxfindex+pdr->drive_info.clpfblock16-1) >> (pdr->drive_info.log2_bytespsec-1));
}
num_sectors = buffer_size_sectors;
finished = FALSE;
while (!finished) /* This loops until finished for RTFSPro, ProPlus returns an async statrus */
{
pdw = (dword *) pbuffer; pw = (word *) pbuffer;
next_page = cluster + entries_per_buffer;
if (cluster == 2) {next_page -= 2; pw += 2; pdw += 2;};/* offset cluster 2 in page appropriately */
if (next_page > pdr->drive_info.maxfindex)
next_page = pdr->drive_info.maxfindex+1;
/* April 2012 Fixed bug: If the number of sectors in the fat are 1 sector larger than
a multiple of buffer_size_sectors, the last sector in the FAT is ignored.
if (current_fatsector + buffer_size_sectors >= max_sector)
* {
* finished = TRUE;
* num_sectors = max_sector - current_fatsector;
* }
*/
if (current_fatsector + buffer_size_sectors > max_sector)
{
finished = TRUE;
num_sectors = max_sector - current_fatsector + 1;
}
/* Call pc_read_fat_blocks() */
if (pc_read_fat_blocks (pdr, pbuffer, current_fatsector, num_sectors) < 0)
{
rtfs_set_errno(PEIOERRORREADFAT, __FILE__, __LINE__);
ret_val = PC_ASYNC_ERROR;
goto cleanup;
}
else
{
if (pdr->drive_info.fasize == 8)
{
for (;cluster < next_page; cluster++, pdw++)
{
if (*pdw==0)
{
if (!regionlength) region_start = cluster;
regionlength++;
}
else if (regionlength)
{
if (!fatop_add_free_region(pdr, region_start, regionlength, FALSE))
{
ret_val = PC_ASYNC_ERROR;
goto cleanup;
}
region_start = 0;
regionlength = 0;
}
}
}
else /* if (pdr->fasize == 4) */
{
for (;cluster < next_page; cluster++, pw++)
{
if (*pw==0)
{
if (!regionlength) region_start = cluster;
regionlength++;
}
else if (regionlength)
{
if (!fatop_add_free_region(pdr, region_start, regionlength, FALSE))
{
ret_val = PC_ASYNC_ERROR;
goto cleanup;
}
region_start = 0;
regionlength = 0;
}
}
}
}
if (finished)
{
if (regionlength)
{
/* Add to free cache if enabled */
if (!fatop_add_free_region(pdr, region_start, regionlength, FALSE))
{
ret_val = PC_ASYNC_ERROR;
goto cleanup;
}
}
ret_val = PC_ASYNC_COMPLETE;
break;
/* Fall through to cleanup; */
}
else
{
current_fatsector += num_sectors;
#if (INCLUDE_RTFS_PROPLUS) /* ProPlus - breakout, but first prepare to reenter asynchronous check_freespace */
pdr->drive_state.drv_async_current_cluster = cluster;
pdr->drive_state.drv_async_region_length = regionlength;
pdr->drive_state.drv_async_current_fatblock = current_fatsector;
pdr->drive_state.drv_async_region_start = region_start;
ret_val = PC_ASYNC_CONTINUE;
break;
#endif
}
}
cleanup:
if (pubuff)
pc_release_user_buffer(pdr, pubuff);
return(ret_val);
}
#endif /* (INCLUDE_FATPAGE_DRIVER) */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,953 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* RTBLOCK.C - ERTFS-PRO and ProPlus merged fat sector buffering routines
This file contains FAT buffering code common to RTFS Pro and RTFS ProPlus
This code is used by Pro for all FAT accesses and by ProPlus for most
FAT accesses. In ProPlus extended file operations use a differnt method.
This version of FAT buffering (May 2007) contains several improvements including:
Uses the sector buffering algorithm from ProPlus, which is simplified
without reducing performance
Paging - Supports multi sector FAT buffering and media transfers.
Note: The paging is not yet a runtime configuration and must be
configured with the FAT_PAGE_SIZE_BLOCKS, compile constant in this
file (see below).
Note: This release includes a new structure of type PCMBUFF. This is a
multisector buffer container with support for marking individual bits
dirty. To test all possible combinations of dirty bits a test named
pc_test_mbuff_dirty() was devised. This code is included in the file
but it is conditionally excluded for the compilation
The FAT buffering scheme works as follows:
Buffer structures - The FATBUFF structure an rtfsmbuff structure and some additional
fields that are used to link it in the "committed" list and a cache list.
The committed list contains FAT buffers that are mapped to sector on the media. Stored
in ascending order.
Caching -
The cache lists are list of buffers who share the same hash value. This hashing method
provides faster lookup. The hashing function simply masks off the upper bytes of the
fat sector number.
The secondary cache is an array of list linked lists of FAT buffers. The sector numbers of
all buffers in the list all having the same hahsing value.
A primary cache contains two arrays containing the last sector number accessed in a hash group
and a pointer to the buffer. This primary hash eliminates secondary cache lookups when sequential
cluster accesses are being performed.
Hashing performance is a more significant factor for Rtfs Pro ProPlus and is configurable under
Pro but uses a fixed size under ProPlus.
Paging -
Pages are read from the media into the PCMBUFF data structure contained in the FAT buffer using
multi-sector reads.
When pages are modified, they are written to the FAT writing only the individual changed sectors.
If a continguous sectors are marked dirty they are written with multi-sector writes.
The dirty sector management is performed by the following functions using data structures in the
PCMBUFF structure:
void pc_set_mbuff_dirty(PCMBUFF *pcmb, dword sector_offset, int sector_count)
void pc_zero_mbuff_dirty(PCMBUFF *pcmb)
int pc_get_clear_mbuff_dirty(PCMBUFF *pcmb, int *pfirst_dirty)
Block buffering algorithm -
The FAT driver code in prfatdiver.c, rtfatdiver.c, and proplusfatdriver.c calls pc_map_fat_sector()
to map in a sector of the FAT and return a pointer to it.
pc_map_fat_sector() calculates the page number that the sector resides in. It then calulates the
hash index of the first sector in the page and checks the primary cache and if necessary,
the secondary cache for the page. If the page is found a pointer to the data within the
page is returned.
If a page is not found, it is read into a free or re-allocated PCMBUFF buffer and the page is
inserted into the secondary cache and into the comitted list in sector order. If there are no free
fat buffers to read the data into, a fat buffer is reallocated by calling pc_realloc_fat_blk().
This routine recycles the least recently used "non dirty" page. If all pages are dirty it writes
and the recycles the least recently used dirty page.
The last page accessed is always placed in the primary cache.
If the access is for "write", pc_set_mbuff_dirty() is called to mark the individual sector dirty
in the PCMBUFF memebr of the FAT buffer. A bit map is kept of the individual dirty sectors within
the page. This bitmap is consulted when the page is later flushed.
Failsafe Interaction -
If Failsafe is enabled FAT page reads and writes are performed by the Failsafe module instead of
by simple calls to the devio layer to access the media.
If Failsafe is enabled the routines fat_devio_write() and fat_devio_read() are provided by
Failsafe. These routines redirect writes to the journal file and for reads the journal is
consulted first. If the required sector is not in the journal it is then read from the
media.
*/
#include "rtfs.h"
#if (RTFS_CFG_LEAN)
#define INCLUDE_MULTI_BLOCKS_PERBUFFER 0
#define INCLUDE_FATSTREAM_DRIVER 0
#else
#define INCLUDE_MULTI_BLOCKS_PERBUFFER 1
#define INCLUDE_FATSTREAM_DRIVER 1
#endif
/* Configure the page size. Uncomment the 2 lines associated with the page size
to select that page size
Note: Page size may be 1,2,4,8,16 or 32.
The optimal page size to select is dependant on the media and driver.
Fat sectors are read from the media in "page size" chunks.
If performing multi sector reads are significantly faster than multiple single
sector reads then increasing page size should improve performance. On ATA devices
performance of many functions doubles as the page size doubles.
*/
/* Mark primary cache empty with hi 4 bit clear and low 28 bits set.
needed to be changed because the sector at the page boundary can be now be zero,
so we select a non zero value that can not match a real sector number and set
the hi 4 flag bits to clear. The previous value of zero is not usable because
the paging algorithm comes up with sector numbers of zero */
#define FAT_PRIMARY_CACHE_EMPTY 0x0ffffffful
#define DEBUG_FAT_BUFFERING 0
#if (DEBUG_FAT_BUFFERING)
void assert_not_on_queue(DDRIVE *pdrive, FATBUFF *pblk);
void assert_on_queue(DDRIVE *pdrive, FATBUFF *pblk);
#define ASSERT_ON_QUEUE(DRIVE, BLOCK) assert_on_queue(DRIVE, BLOCK);
#define ASSERT_NOT_ON_QUEUE(DRIVE, BLOCK) assert_not_on_queue(DRIVE, BLOCK);
#else
#define ASSERT_ON_QUEUE(DRIVE, BLOCK)
#define ASSERT_NOT_ON_QUEUE(DRIVE, BLOCK)
#endif
FATBUFF *pc_find_fat_blk_primary(FATBUFFCNTXT *pfatbuffcntxt, dword fat_sector_offset); // DONE
void pc_set_fat_blk_primary(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk); // DONE
void pc_clear_fat_blk_primary(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk); // DONE
FATBUFF *pc_find_fat_blk_secondary (FATBUFFCNTXT *pfatbuffcntxt, dword fat_sector_offset); // DONE
void pc_clear_fat_blk_secondary(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk); // DONE
void pc_set_fat_blk_secondary (FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk); // DONE
void pc_uncommit_fat_blk_queue(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk); // DONE
void pc_commit_fat_blk_queue(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk); // DONE
void pc_free_fat_blk(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk); // DONE
FATBUFF *pc_realloc_fat_blk(DDRIVE *pdrive, FATBUFFCNTXT *pfatbuffcntxt, dword fat_sector_offset); // DONE
#if (INCLUDE_MULTI_BLOCKS_PERBUFFER)
int fat_sector_clip(DDRIVE *pdrive, FATBUFFCNTXT *pfatbuffcntxt, dword fat_sector_offset); // DONE
#endif
#if (INCLUDE_NAND_DRIVER) /* Implement pc_set_mbuff_all_dirty() if any FAT sector is dirty in an erase blocks */
/* Sets the whole mbuff dirty. Called when Rtfs is configure to flush all sectors in a page buffer with a single write */
void pc_set_mbuff_all_dirty(PCMBUFF *pcmb, dword block_count)
{
pcmb->block_count = (int) block_count;
pcmb->dirty_count = pcmb->block_count;
pcmb->dirty_block_offset = 0;
pcmb->dirty_bitmap = 0xffffffff;
}
#endif
/* Read sector fromthe FAT, sectorno is offset from start of volume */
BOOLEAN fat_devio_read(DDRIVE *pdrive, dword sectorno,dword nsectors, byte *fat_data)
{
BOOLEAN ret_val;
#if (INCLUDE_FAILSAFE_RUNTIME)
if (prtfs_cfg->pfailsafe)
return(prtfs_cfg->pfailsafe->fat_devio_read(pdrive, sectorno, nsectors, fat_data));
#endif
UPDATE_RUNTIME_STATS(pdrive, fat_reads, 1)
UPDATE_RUNTIME_STATS(pdrive, fat_blocks_read, nsectors)
ret_val = raw_devio_xfer(pdrive, sectorno, fat_data, nsectors, FALSE, TRUE);
return(ret_val);
}
/* Read from the fat into a byte buffer first_sector is offset from volume start not FAT start */
int pc_read_fat_blocks (DDRIVE* pdrive, byte* buffer, dword first_sector, dword num_sectors)
{
if (!fat_devio_read(pdrive, first_sector, num_sectors, buffer))
{
rtfs_set_errno(PEIOERRORREADFAT, __FILE__, __LINE__);
return -1;
}
return 0;
}
/* Create the FAT buffer free list from a contiguos block of fat buffer control structures
that are provided in a memory area pointed to by pblk, containing space for user_num_fat_buffers control structures.
if "provided_buffers" is non zero then it points
If provided_buffers is non zero, it points to a contiguous section of memory that is
(fat_buffer_page_size_bytes * user_num_fat_buffers) bytes wide.
Split the data into user_num_fat_buffers seperate buffers of fat_buffer_page_size_bytes bytes each and assign the
addresses in the control block.
If provided_buffers is zero, the device driver already assigned the addresses in the control block, so preserve
the address pointers.
*/
void _pc_link_buffer_and_freelist(FATBUFF *pblk, int user_num_fat_buffers, byte *provided_buffers, dword fat_buffer_page_size_bytes)
{
int i;
byte *save_pdata;
for (i = 0; i < (user_num_fat_buffers-1); i++, pblk++)
{
save_pdata = pblk->fat_data_buff.pdata;
rtfs_memset(pblk,(byte) 0, sizeof(FATBUFF));
if (provided_buffers)
{
pblk->fat_data_buff.pdata = provided_buffers;
provided_buffers += fat_buffer_page_size_bytes;
}
else
pblk->fat_data_buff.pdata = save_pdata;
pblk->pnext = pblk+1;
}
save_pdata = pblk->fat_data_buff.pdata;
rtfs_memset(pblk,(byte) 0, sizeof(FATBUFF));
if (provided_buffers)
pblk->fat_data_buff.pdata = provided_buffers;
else
pblk->fat_data_buff.pdata = save_pdata;
pblk->pnext = 0;
}
/* Reset the fat buffer cache */
void pc_free_all_fat_buffers(DDRIVE *pdrive)
{
FATBUFFCNTXT *pfatbuffcntxt;
pfatbuffcntxt = &pdrive->fatcontext;
/* Clear stats */
pfatbuffcntxt->stat_primary_cache_hits =
pfatbuffcntxt->stat_secondary_cache_hits =
pfatbuffcntxt->stat_secondary_cache_loads =
pfatbuffcntxt->stat_secondary_cache_swaps = 0;
pfatbuffcntxt->lru_counter = 0;
/* Clear hash tables */
/* Primary hash table size is a compile time option in ProPlus */
pfatbuffcntxt->fat_blk_hash_tbl = &pfatbuffcntxt->fat_blk_hash_tbl_core[0];
pfatbuffcntxt->primary_mapped_sectors = &pfatbuffcntxt->primary_sectormap_core[0];
pfatbuffcntxt->primary_mapped_buffers = &pfatbuffcntxt->primary_buffmap_core[0];
pfatbuffcntxt->hash_size = FAT_HASH_SIZE;
pfatbuffcntxt->hash_mask = (dword)(pfatbuffcntxt->hash_size-1);
/* Initialize secondary FAT cache (these are linked lists of FATBUFS) the number of lists
is divided by the cache size to reduce traversales per lookup */
rtfs_memset(pfatbuffcntxt->fat_blk_hash_tbl,0, sizeof(FATBUFF *)*pfatbuffcntxt->hash_size);
/* Initialize primary FAT cache - This speeds up sequential cluster accesss from the same fat sector
by eliminating scanning the secondary hashed lists.. */
/* The last sector number accessed in a hash group is stored in pfatbuffcntxt->primary_mapped_sectors[hash_index]..
If no sector is in the primary cache at an index pfatbuffcntxt->primary_mapped_buffers[hash_index] will be
NULL and pfatbuffcntxt->primary_mapped_sectors[hash_index]; will contain FAT_PRIMARY_CACHE_EMPTY */
{
dword *pdw;
int i;
/* needed to be changed because the sector at the page boundary can be now be zero,
and we can no longer use zero as an empty indicator.. */
pdw = (dword *) pfatbuffcntxt->primary_mapped_sectors;
for (i = 0; i < pfatbuffcntxt->hash_size; i++, pdw++)
{
*pdw = FAT_PRIMARY_CACHE_EMPTY;
}
}
rtfs_memset(pfatbuffcntxt->primary_mapped_buffers,(byte) 0, sizeof(FATBUFF *)*pfatbuffcntxt->hash_size);
pfatbuffcntxt->pcommitted_buffers = 0;
/* Create a freelist from pdrive->du.user_num_fat_buffers control structures provided in
pdrive->du.fat_buffer_structures.
If the drive was configured by pc_diskio_configure() and not by the device driver, then
link the data buffer space provided in pdrive->du.user_fat_buffer_data to the control structures
If the drive was the device driver the data fields are already established */
#if (!INCLUDE_MULTI_BLOCKS_PERBUFFER)
/* Make sure page size is 1 if multi sector fat buffering is not enabled */
pdrive->du.fat_buffer_pagesize = 1;
#endif
pfatbuffcntxt->fat_buffer_page_size_sectors = pdrive->du.fat_buffer_pagesize;
pfatbuffcntxt->fat_buffer_page_mask = 0xffffffff - (pfatbuffcntxt->fat_buffer_page_size_sectors-1);
{ /* Call _pc_link_buffer_and_freelist() with raw buffer space and page size zero because buffer
control blocks were set up by the device driver */
pfatbuffcntxt->pfree_buffers = (struct fatbuff *) pdrive->mount_parms.fatbuff_memory;
_pc_link_buffer_and_freelist(pfatbuffcntxt->pfree_buffers, (int) pdrive->mount_parms.n_fat_buffers, 0, 0);
}
}
/* This is called when disk freespace is scanned. The fat buffer is not being used so we use it
as a large transfer buffer to maximize disk read sizes */
byte *pc_get_raw_fat_buffer(DDRIVE *pdrive, dword *pbuffer_size_sectors)
{
*pbuffer_size_sectors = 0;
if (pdrive->du.user_fat_buffer_data)
{
*pbuffer_size_sectors = pdrive->du.user_num_fat_buffers;
return (pdrive->du.user_fat_buffer_data);
}
return (0);
}
/* Find the first sector between first_sector and last_sector that is currently mapped
This is used by FAT stream access funtion to detect if any sectors in the stream are buffered
and should be read from the fat buffer */
#if (INCLUDE_FATSTREAM_DRIVER)
static dword pc_find_first_fat_blk(DDRIVE *pdrive, dword first_sector_offset, dword last_sector_offset)
{
FATBUFF *pblk_scan;
int page_size, loop_guard;
page_size = pdrive->fatcontext.fat_buffer_page_size_sectors;
pblk_scan = pdrive->fatcontext.pcommitted_buffers;
loop_guard = pdrive->du.user_num_fat_buffers;
/* Scan up to where our last interesting sector is >= the the first sector in the buffer */
while (pblk_scan && loop_guard--)
{
if (last_sector_offset < pblk_scan->fat_data_buff.first_blockno) /* buffer before range */
pblk_scan = pblk_scan->pnext;
else if (pblk_scan->fat_data_buff.first_blockno > last_sector_offset) /* buffer beyond the range */
return(0);
else
{
if (first_sector_offset <= pblk_scan->fat_data_buff.first_blockno) /* range straddles buffer start */
return (pblk_scan->fat_data_buff.first_blockno);
else
{
dword last_in_buffer;
last_in_buffer = pblk_scan->fat_data_buff.first_blockno + page_size-1;
if (first_sector_offset <= last_in_buffer) /* range intersects buffer middle */
return (first_sector_offset);
else
pblk_scan = pblk_scan->pnext;
}
}
}
return(0);
}
/* byte *pc_map_fat_stream()
Internal function, synchronizes user buffer FAT accesses with the FAt buffer pool
and returns the buffer addresses and ranges for cluster access
Determine the buffer address of a cluster.
If the FAT buffer pool is used and it is a write operation sets appropriate dirty bits for flushing
If an alternate buffer is supplied decides decides if the alternate user supplied buffer should be
used or if the FAT buffer pool should be used. The decision is based on the boundaries and size of
of the cluster range and what is already buffered.
The FAT buffer pool is used if:
No alternate buffer is supplied.
The sector at first_sector_offset is already buffered
byte_offset is non-zero (not sector aligned)
The byte range is < 1 sector
If the FAT buffer pool is used the returned sector count may be up to the width of a
FAT buffer page.
The Alternate buffer is used if:
An alternate buffer is supplied.
The sectors are aligned so they overlap one or more full FAT sectors and they occupy
one or more full FAT buffer pages.
If Alternate buffer is used the returned sector count may be up to alt_buffer_size
, smaller if the range fits in a smaller sector range or if sectors withing the range are
already buffered. These buffered sectors should then be retrieved by calling the function
again after processing the user buffer
If the alternate buffer is selected the return pointer is always alt_buffer..
If alt_buffer is returned and the operation is a read, the caller must read.
If alt_buffer is returned and the operation is a write, the caller is not required to first read
the sector because the operation is guaranteed to overwrite the whole region.
byte *pc_map_fat_stream(
DDRIVE *pdrive,
dword *return_sector_count,
dword first_sector_offset,
dword byte_offset,
dword byte_count,
byte *alt_buffer,
dword alt_buffer_size,
BOOLEAN is_a_read)
*/
byte *pc_map_fat_stream(DDRIVE *pdrive, dword *return_sector_count, dword first_sector_offset, dword byte_offset, dword byte_count, byte *alt_buffer, dword alt_buffer_size, BOOLEAN is_a_read)
{
BOOLEAN use_fat_pool;
dword last_sector_offset, n_sectors, first_mapped_sector;
dword first_page_boundary,sector_offset_in_page;
byte *return_pointer;
/* pdrive->drive_info.bytespsector was set before this was called */
ERTFS_ASSERT(pdrive->drive_info.bytespsector != 0)
/* Calculate sector counts and offsets */
n_sectors = (byte_offset + byte_count + pdrive->drive_info.bytespsector-1)/pdrive->drive_info.bytespsector;
last_sector_offset = first_sector_offset+n_sectors-1;
first_page_boundary = first_sector_offset & pdrive->fatcontext.fat_buffer_page_mask;
sector_offset_in_page = first_sector_offset - first_page_boundary;
/* Clip the range if any sectors are mapped */
first_mapped_sector = pc_find_first_fat_blk(pdrive, first_sector_offset, last_sector_offset);
if (first_mapped_sector)
n_sectors = first_mapped_sector - first_sector_offset + 1;
/* See if we need to use the buffer pool, and if so do we have to read it */
use_fat_pool = FALSE;
/* If the drive is configured for page write mode and we are accessing the fat area
to perform a write, then select use_fat_pool. For NAND this means it disables writing
multiple contiguous sectors using the potentially larger user buffer and always ripples
fat table writes through the FAT buffer pool, which should be configured by the driver to be
erase block aligned */
#if (INCLUDE_NAND_DRIVER) /* Force use of FAT buffer pool in dynamic mode with erase blocks */
if (pdrive->pmedia_info->eraseblock_size_sectors)
{
use_fat_pool = TRUE;
}
else
#endif
{
if (alt_buffer == 0) /* Use fat buffers if no buffer provided */
use_fat_pool = TRUE;
else if (byte_offset) /* Use fat buffers if byte offset into a sector */
use_fat_pool = TRUE;
else if ((sector_offset_in_page+n_sectors) <= pdrive->fatcontext.fat_buffer_page_size_sectors)
/* Or if the whole request fits in one buffer */
use_fat_pool = TRUE;
}
if (use_fat_pool)
{ /* Using the buffer pool, set read flags and dirty flags */
dword usage_flags;
/* clip the sector count to the sectors to the end of the page
or the requested sector count, whichever is less */
*return_sector_count = pdrive->fatcontext.fat_buffer_page_size_sectors - sector_offset_in_page;
if (*return_sector_count > n_sectors)
*return_sector_count = n_sectors;
usage_flags = 0;
if (!is_a_read) /* Set write flag if requested */
usage_flags = FATPAGEWRITE;
/* Add in read flag if we need to */
if (is_a_read) /* read because it is a read request */
usage_flags |= FATPAGEREAD;
else if (byte_offset || sector_offset_in_page) /* read because not overwriting the start of buffer */
usage_flags |= FATPAGEREAD;
/* We are starting at the first byte in the buffer, read if we are not overwriting every
byte in the page */
else if (byte_count < (pdrive->fatcontext.fat_buffer_page_size_sectors<<pdrive->drive_info.log2_bytespsec))
usage_flags |= FATPAGEREAD; /* read because not overwriting the end of buffer */
/* The 3rd argument is the number of sectors in the buffer to set dirty if it is a write */
return_pointer = pc_map_fat_sector(pdrive, &pdrive->fatcontext, first_sector_offset, (int) *return_sector_count, usage_flags);
}
else
{ /* Use the input buffer, clip the number of sectors if in range already mapped
or if the sector count is more than the buffer size */
/* We are bursting, but we can only do complete sectors. We know the left cluster is alligned,
and n_sectors > 1, check the right side and reduce the sector count if we need to
the next iteration will finish. */
dword ltemp;
ltemp = byte_offset + byte_count;
/* if (ltemp & 0xfff) :LB: - Seems like this was a bug.. should have been 0x1ff */
if (ltemp & pdrive->drive_info.bytemasksec)
n_sectors -= 1;
if (first_mapped_sector)
*return_sector_count = first_mapped_sector - first_sector_offset; /* will never be > n_sectors */
else
*return_sector_count = n_sectors;
if (*return_sector_count > alt_buffer_size)
*return_sector_count = alt_buffer_size;
return_pointer = alt_buffer;
}
return(return_pointer);
}
#else
byte *pc_map_fat_stream(DDRIVE *pdrive, dword *return_sector_count, dword first_sector_offset, dword byte_offset, dword byte_count, byte *alt_buffer, dword alt_buffer_size, BOOLEAN is_a_read)
{ /* Using the buffer pool, set read flags and dirty flags */
dword usage_flags;
*return_sector_count = 1;
usage_flags |= FATPAGEREAD; /* read because not overwriting the end of buffer */
if (!is_a_read)
usage_flags = FATPAGEWRITE;
if (!return_sector_count) /* Won't execute */
{
RTFS_ARGSUSED_PVOID((void *) alt_buffer);
RTFS_ARGSUSED_DWORD(byte_offset);
RTFS_ARGSUSED_DWORD(byte_count);
RTFS_ARGSUSED_DWORD(alt_buffer_size);
}
return(pc_map_fat_sector(pdrive, &pdrive->fatcontext, first_sector_offset, (int) *return_sector_count, usage_flags));
}
#endif /* INCLUDE_FATSTREAM_DRIVER */
byte *pc_map_fat_sector(DDRIVE *pdrive, FATBUFFCNTXT *pfatbuffcntxt, dword sector_offset_in_fat, int n_dirty, dword usage_flags)
{
FATBUFF *pblk;
dword new_sector_offset_in_page;
dword page_offset_boundary;
/* Using paging method to reduce the count of individual read and writes */
/* Convert sector number to the sector number at the page boundary,
remember the offset to sector that we want in the page */
page_offset_boundary = sector_offset_in_fat & pfatbuffcntxt->fat_buffer_page_mask;
new_sector_offset_in_page = sector_offset_in_fat - page_offset_boundary;
sector_offset_in_fat = page_offset_boundary;
/* Check the cache for the sector */
/* Check the primary */
pblk = pc_find_fat_blk_primary(pfatbuffcntxt, page_offset_boundary);
if (!pblk)
{ /* Check the secondary */
pblk = pc_find_fat_blk_secondary(pfatbuffcntxt, page_offset_boundary);
}
if (!pblk)
{
pblk = pc_realloc_fat_blk(pdrive, pfatbuffcntxt, page_offset_boundary);
if (!pblk)
{
/* No sectors available. */
rtfs_set_errno(PERESOURCEFATBLOCK, __FILE__, __LINE__);
return(0);
}
else
{
if (usage_flags & FATPAGEREAD)
{ /* The sector we are accessing may be offset inside the buffer, because it is
not on the page boundary, so move the data pointer to return */
int clipped_sector_count;
#if (INCLUDE_MULTI_BLOCKS_PERBUFFER)
clipped_sector_count = fat_sector_clip(pdrive, pfatbuffcntxt, page_offset_boundary);
if (!clipped_sector_count) /* This will not happen */
return(0);
#else
clipped_sector_count = 1;
#endif
if (!fat_devio_read(pdrive, pdrive->drive_info.fatblock+page_offset_boundary, clipped_sector_count, pblk->fat_data_buff.pdata))
{ /* The read failed. Put on the the free list */
rtfs_set_errno(PEIOERRORREADFAT, __FILE__, __LINE__);
pc_free_fat_blk(pfatbuffcntxt, pblk);
return(0);
}
pfatbuffcntxt->stat_secondary_cache_loads += 1;
}
pc_set_fat_blk_primary(pfatbuffcntxt, pblk);
pc_set_fat_blk_secondary(pfatbuffcntxt, pblk);
pc_commit_fat_blk_queue(pfatbuffcntxt, pblk);
}
}
if (usage_flags & FATPAGEWRITE)
{ /* If just switching to dirty, update the count of dirty fat mbuffs */
if (!(pblk->fat_data_buff.dirty_count))
{
pfatbuffcntxt->num_dirty += 1;
/* Set drive status to "must flush fat" */
set_fat_dirty(pdrive);
}
/* Mark the sector offest dirty in the buffer */
#if (INCLUDE_NAND_DRIVER) /* Call pc_set_mbuff_all_dirty() if any FAT sector is dirty in an erase blocks */
if (pdrive->pmedia_info->eraseblock_size_sectors)
{ /* In this mode we want to write all sectors when we flush the page. So set all dirty */
pc_set_mbuff_all_dirty(&pblk->fat_data_buff, pfatbuffcntxt->fat_buffer_page_size_sectors);
}
else
#endif
{ /* In this mode we want to write only dirty sectors when we flush the page. So set specific sectors dirty */
pc_set_mbuff_dirty(&pblk->fat_data_buff, new_sector_offset_in_page, n_dirty);
}
}
pblk->lru_counter = pfatbuffcntxt->lru_counter++;
/* If we get here we have a sector for sure and it is in the secondary
cache. Put it in the primary cache. Harmless if already there */
pc_set_fat_blk_primary(pfatbuffcntxt, pblk);
/* The sector we are accessing may be offset inside the buffer, because it is
not on the page boundary, so move the data pointer to return */
{
byte *pfatdata;
pfatdata = pblk->fat_data_buff.pdata;
pfatdata += (new_sector_offset_in_page<<pdrive->drive_info.log2_bytespsec);
return(pfatdata);
}
}
FATBUFF *pc_find_fat_blk_primary(FATBUFFCNTXT *pfatbuffcntxt, dword fat_sector_offset)
{
dword hash_index;
FATBUFF *pblk;
dword b;
hash_index = fat_sector_offset&pfatbuffcntxt->hash_mask;
b = *(pfatbuffcntxt->primary_mapped_sectors+hash_index);
pblk = 0;
if (b != FAT_PRIMARY_CACHE_EMPTY && b == fat_sector_offset)
{
pblk = *(pfatbuffcntxt->primary_mapped_buffers+hash_index);
if (pblk)
{
pfatbuffcntxt->stat_primary_cache_hits += 1;
}
else /* Should never happen.. something is wrong but just clear it and return miss */
*(pfatbuffcntxt->primary_mapped_sectors+hash_index) = FAT_PRIMARY_CACHE_EMPTY;
}
return(pblk);
}
void pc_set_fat_blk_primary(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk)
{
dword hash_index,fat_sector_offset;
fat_sector_offset = pblk->fat_data_buff.first_blockno;
hash_index = (fat_sector_offset&pfatbuffcntxt->hash_mask);
*(pfatbuffcntxt->primary_mapped_sectors+hash_index) = fat_sector_offset;
*(pfatbuffcntxt->primary_mapped_buffers+hash_index) = pblk;
}
void pc_clear_fat_blk_primary(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk)
{
dword hash_index,fat_sector_offset;
;
fat_sector_offset = pblk->fat_data_buff.first_blockno;
hash_index = fat_sector_offset&pfatbuffcntxt->hash_mask;
if (*(pfatbuffcntxt->primary_mapped_sectors+hash_index) == fat_sector_offset)
{
*(pfatbuffcntxt->primary_mapped_sectors+hash_index) = FAT_PRIMARY_CACHE_EMPTY;
*(pfatbuffcntxt->primary_mapped_buffers+hash_index) = 0;
}
}
FATBUFF *pc_find_fat_blk_secondary (FATBUFFCNTXT *pfatbuffcntxt, dword fat_sector_offset)
{
dword hash_index;
FATBUFF *pblk;
hash_index = fat_sector_offset& pfatbuffcntxt->hash_mask;
pblk = *(pfatbuffcntxt->fat_blk_hash_tbl+hash_index);
while (pblk)
{
if (pblk->fat_data_buff.first_blockno == fat_sector_offset)
{
pfatbuffcntxt->stat_secondary_cache_hits += 1;
return(pblk);
}
else
pblk=pblk->pnext_hash;
}
return(0);
}
/* Place on the hash list in sector order */
void pc_clear_fat_blk_secondary(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk)
{
ERTFS_ASSERT(pblk->pnext_hash != pblk)
ERTFS_ASSERT(pblk->pprev_hash != pblk)
if (pblk->pprev_hash)
pblk->pprev_hash->pnext_hash = pblk->pnext_hash;
else
{
dword hash_index;
hash_index = pblk->fat_data_buff.first_blockno&pfatbuffcntxt->hash_mask;
*(pfatbuffcntxt->fat_blk_hash_tbl+hash_index) = pblk->pnext_hash;
}
if (pblk->pnext_hash)
pblk->pnext_hash->pprev_hash = pblk->pprev_hash;
ERTFS_ASSERT(pblk->pnext_hash != pblk)
ERTFS_ASSERT(pblk->pprev_hash != pblk)
pblk->pprev_hash = 0;
pblk->pnext_hash = 0;
}
void pc_set_fat_blk_secondary (FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk)
{
FATBUFF *pblk_scan;
dword hash_index;
ERTFS_ASSERT(pblk->pnext_hash != pblk)
ERTFS_ASSERT(pblk->pprev_hash != pblk)
/* Put on the hash list */
hash_index = pblk->fat_data_buff.first_blockno&pfatbuffcntxt->hash_mask;
/* Put on the committed list */
if (!*(pfatbuffcntxt->fat_blk_hash_tbl+hash_index))
{
*(pfatbuffcntxt->fat_blk_hash_tbl+hash_index) = pblk;
pblk->pprev_hash = 0;
pblk->pnext_hash = 0;
}
else
{
pblk_scan = *(pfatbuffcntxt->fat_blk_hash_tbl+hash_index);
while (pblk_scan)
{
ERTFS_ASSERT(pblk_scan->pnext_hash != pblk_scan)
ERTFS_ASSERT(pblk_scan->pprev_hash != pblk_scan)
if (pblk->fat_data_buff.first_blockno < pblk_scan->fat_data_buff.first_blockno)
{/* insert before scan */
pblk->pnext_hash = pblk_scan;
pblk->pprev_hash = pblk_scan->pprev_hash;
if (pblk_scan->pprev_hash)
pblk_scan->pprev_hash->pnext_hash = pblk;
else
pfatbuffcntxt->fat_blk_hash_tbl[hash_index] = pblk;
pblk_scan->pprev_hash = pblk;
break;
}
else if (pblk_scan->pnext_hash == 0)
{/* insert after scan */
pblk->pprev_hash = pblk_scan;
pblk->pnext_hash = 0;
pblk_scan->pnext_hash = pblk;
break;
}
else
pblk_scan = pblk_scan->pnext_hash;
}
}
ERTFS_ASSERT(pblk->pnext_hash != pblk)
ERTFS_ASSERT(pblk->pprev_hash != pblk)
}
void pc_uncommit_fat_blk_queue(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk)
{
ASSERT_ON_QUEUE(pdrive, pblk)
if (pblk->pprev)
pblk->pprev->pnext = pblk->pnext;
else
{
pfatbuffcntxt->pcommitted_buffers = pblk->pnext;
}
if (pblk->pnext)
pblk->pnext->pprev = pblk->pprev;
pblk->pprev = 0;
pblk->pnext = 0;
ASSERT_NOT_ON_QUEUE(pdrive, pblk)
}
/* Place on the fat list in sector order */
void pc_commit_fat_blk_queue(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk)
{
FATBUFF *pblk_scan;
ERTFS_ASSERT(pblk->pnext != pblk)
ERTFS_ASSERT(pblk->pprev != pblk)
ASSERT_NOT_ON_QUEUE(pfatbuffcntxt, pblk)
/* Put on the committed list */
if (!pfatbuffcntxt->pcommitted_buffers)
{
pfatbuffcntxt->pcommitted_buffers = pblk;
pblk->pprev = 0;
pblk->pnext = 0;
}
else
{
pblk_scan = pfatbuffcntxt->pcommitted_buffers;
while (pblk_scan)
{
ERTFS_ASSERT(pblk_scan->pnext != pblk_scan)
ERTFS_ASSERT(pblk_scan->pprev != pblk_scan)
if (pblk->fat_data_buff.first_blockno < pblk_scan->fat_data_buff.first_blockno)
{/* insert before scan */
pblk->pnext = pblk_scan;
pblk->pprev = pblk_scan->pprev;
if (pblk_scan->pprev)
pblk_scan->pprev->pnext = pblk;
else
pfatbuffcntxt->pcommitted_buffers = pblk;
pblk_scan->pprev = pblk;
ASSERT_ON_QUEUE(pfatbuffcntxt, pblk)
break;
}
else if (pblk_scan->pnext == 0)
{/* insert after scan */
pblk->pprev = pblk_scan;
pblk->pnext = 0;
pblk_scan->pnext = pblk;
ASSERT_ON_QUEUE(pfatbuffcntxt, pblk)
break;
}
else
pblk_scan = pblk_scan->pnext;
}
}
ASSERT_ON_QUEUE(pfatbuffcntxt->pcommitted_buffers, pblk)
ERTFS_ASSERT(pblk->pnext != pblk)
ERTFS_ASSERT(pblk->pprev != pblk)
}
void pc_free_fat_blk(FATBUFFCNTXT *pfatbuffcntxt, FATBUFF *pblk)
{
if (pfatbuffcntxt->pfree_buffers)
pblk->pnext = pfatbuffcntxt->pfree_buffers;
else
pblk->pnext = 0;
pfatbuffcntxt->pfree_buffers = pblk;
}
FATBUFF *pc_realloc_fat_blk(DDRIVE *pdrive, FATBUFFCNTXT *pfatbuffcntxt, dword fat_sector_offset)
{
FATBUFF *pblk;
FATBUFF *pblk_lru;
pblk = pfatbuffcntxt->pfree_buffers;
if (pblk)
{
pfatbuffcntxt->pfree_buffers = pblk->pnext;
}
else
{
FATBUFF *pblk_scan;
pblk_lru = pblk_scan = pfatbuffcntxt->pcommitted_buffers;
while (pblk_scan)
{
ERTFS_ASSERT(pblk_scan->pnext != pblk_scan)
ERTFS_ASSERT(pblk_scan->pprev != pblk_scan)
if (pblk_lru->lru_counter > pblk_scan->lru_counter)
pblk_lru = pblk_scan;
if (pblk_scan->fat_data_buff.dirty_count == 0)
{
if (!pblk || pblk->lru_counter > pblk_scan->lru_counter)
pblk = pblk_scan;
}
pblk_scan = pblk_scan->pnext;
}
if (!pblk)
{ /* None available swap the oldest */
if (pblk_lru)
{
int r;
#if (INCLUDE_EXFATORFAT64)
/* July 2012 bug fix. call pc_write_bam_block_buffer_page to update the BAM, was previously overwrting the FAT */
if (ISEXFATORFAT64(pdrive)&&pfatbuffcntxt==&pdrive->exfatextension.bambuffcntxt)
{
r=pc_write_bam_block_buffer_page(pdrive,pblk_lru);
}
else
#endif
r=pc_write_fat_block_buffer_page(pdrive,pblk_lru);
if (r)
{
pfatbuffcntxt->stat_secondary_cache_swaps += 1;
UPDATE_RUNTIME_STATS(pdrive, fat_buffer_swaps, 1)
pfatbuffcntxt->num_dirty -= 1;
#if (INCLUDE_EXFATORFAT64)
/* July 2012 bug fix. update bam flush requirements if we are operating on a bit map */
if (ISEXFATORFAT64(pdrive)&&pfatbuffcntxt==&pdrive->exfatextension.bambuffcntxt)
{
if (pfatbuffcntxt->num_dirty == 0)
clear_bam_dirty(pdrive);
}
else
#endif
{
/* 04-06-2010 - Clear DRVOP_FAT_IS_DIRTY if dirty count goes to zero,
was triggering an assert that num_dirty == 0 but the dirty bit it still set */
if (pfatbuffcntxt->num_dirty == 0)
clear_fat_dirty(pdrive);
}
pblk = pblk_lru;
}
}
}
if (pblk)
{ /* Swapping out, clear caches and remove from the sector number ordered list */
pc_clear_fat_blk_primary(pfatbuffcntxt, pblk);
pc_clear_fat_blk_secondary(pfatbuffcntxt, pblk);
pc_uncommit_fat_blk_queue(pfatbuffcntxt, pblk);
}
}
if (pblk)
{
pblk->fat_data_buff.first_blockno = fat_sector_offset;
pblk->fat_data_buff.block_count = pfatbuffcntxt->fat_buffer_page_size_sectors;
pc_zero_mbuff_dirty(&pblk->fat_data_buff);
pblk->pnext=pblk->pprev=pblk->pnext_hash=pblk->pprev_hash = 0;
ERTFS_ASSERT(pblk->pnext != pblk)
ERTFS_ASSERT(pblk->pprev != pblk)
}
return(pblk);
}
#if (INCLUDE_MULTI_BLOCKS_PERBUFFER)
int fat_sector_clip(DDRIVE *pdrive, FATBUFFCNTXT *pfatbuffcntxt, dword fat_sector_offset)
{
dword secpfat;
int clipped_sectorcount;
clipped_sectorcount = pfatbuffcntxt->fat_buffer_page_size_sectors;
secpfat = (dword) pdrive->drive_info.secpfat;
if ( (fat_sector_offset + clipped_sectorcount) > secpfat)
{
clipped_sectorcount = secpfat - fat_sector_offset;
}
return(clipped_sectorcount);
}
#endif
#if (DEBUG_FAT_BUFFERING)
void assert_not_on_queue(DDRIVE *pdrive, FATBUFF *pblk)
{
FATBUFF *pblk_scan;
pblk_scan = pfatbuffcntxt->pcommitted_buffers;
while(pblk_scan)
{
ERTFS_ASSERT(pblk_scan != pblk)
pblk_scan = pblk_scan->pnext;
}
}
void assert_on_queue(DDRIVE *pdrive, FATBUFF *pblk)
{
FATBUFF *pblk_scan;
int num_on = 0;
pblk_scan = pfatbuffcntxt->pcommitted_buffers;
while(pblk_scan)
{
if (pblk_scan == pblk)
{
num_on += 1;
ERTFS_ASSERT(num_on == 1)
}
pblk_scan = pblk_scan->pnext;
}
ERTFS_ASSERT(num_on == 1)
}
#endif /* DEBUG_FAT_BUFFERING */

View File

@ -0,0 +1,386 @@
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* RTBLOCK.C - ERTFS-PRO and ProPlus merged fat block buffering routines
This file contains FAT buffering code common to RTFS Pro and RTFS ProPlus
This code is used by Pro for all FAT accesses and by ProPlus for most
FAT accesses. In ProPlus extended file operations use a differnt method.
*/
#include "rtfs.h"
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
#if (RTFS_CFG_LEAN)
#define INCLUDE_MULTI_BLOCKS_PERBUFFER 0
#else
#define INCLUDE_MULTI_BLOCKS_PERBUFFER 1
#endif
/* Configure the page size. Uncomment the 2 lines associated with the page size
to select that page size
Note: Page size may be 1,2,4,8,16 or 32.
The optimal page size to select is dependant on the media and driver.
Fat blocks are read from the media in "page size" chunks.
If performing multi block reads are significantly faster than multiple single
block reads then increasing page size should improve performance. On ATA devices
performance of many functions doubles as the page size doubles.
*/
/* Mark primary cache empty with hi 4 bit clear and low 28 bits set.
needed to be changed because the block at the page boundary can be now be zero,
so we select a non zero value that can not match a real block number and set
the hi 4 flag bits to clear. The previous value of zero is not usable because
the paging algorithm comes up with block numbers of zero */
#define FAT_PRIMARY_CACHE_EMPTY 0x0ffffffful
#define DEBUG_FAT_BUFFERING 0
#if (DEBUG_FAT_BUFFERING)
void assert_not_on_queue(DDRIVE *pdrive, FATBUFF *pblk);
void assert_on_queue(DDRIVE *pdrive, FATBUFF *pblk);
#define ASSERT_ON_QUEUE(DRIVE, BLOCK) assert_on_queue(DRIVE, BLOCK);
#define ASSERT_NOT_ON_QUEUE(DRIVE, BLOCK) assert_not_on_queue(DRIVE, BLOCK);
#else
#define ASSERT_ON_QUEUE(DRIVE, BLOCK)
#define ASSERT_NOT_ON_QUEUE(DRIVE, BLOCK)
#endif
#if (INCLUDE_MULTI_BLOCKS_PERBUFFER)
int pc_get_clear_mbuff_dirty(PCMBUFF *pcmb, int *pfirst_dirty);
#endif
/* Write block to the FAT, blockno is offset from start of volume */
BOOLEAN fat_devio_write(DDRIVE *pdrive, dword fat_blockno, dword nblocks, byte *fat_data, int fatnumber)
{
dword blockno;
#if (INCLUDE_FAILSAFE_RUNTIME)
if (prtfs_cfg->pfailsafe)
return(prtfs_cfg->pfailsafe->fat_devio_write(pdrive, fat_blockno, nblocks, fat_data, fatnumber));
#endif
if (fatnumber)
blockno = fat_blockno+pdrive->drive_info.secpfat;
else
{
blockno = fat_blockno;
}
UPDATE_RUNTIME_STATS(pdrive, fat_writes, 1)
UPDATE_RUNTIME_STATS(pdrive, fat_blocks_written, nblocks)
return(raw_devio_xfer(pdrive, blockno, fat_data, nblocks, FALSE, FALSE));
}
BOOLEAN pc_flush_fat_blocks(DDRIVE *pdrive)
{
if (pc_async_flush_fat_blocks(pdrive,0) == PC_ASYNC_COMPLETE)
return(TRUE);
else
return(FALSE);
}
/* Write a fat buffer to disk, first clip the blocks if necessary so the write does not go
beyond the FAT */
BOOLEAN pc_write_fat_block_buffer_page(DDRIVE *pdrive, FATBUFF *pblk)
{
#if (INCLUDE_MULTI_BLOCKS_PERBUFFER)
byte *pclipped_data;
dword volume_blockno;
int n_dirty_blocks,dirty_block_offset;
/* Check for dirty blocks in the buffer, get count and clear status */
n_dirty_blocks = pc_get_clear_mbuff_dirty(&pblk->fat_data_buff, &dirty_block_offset);
while (n_dirty_blocks)
{
volume_blockno = pblk->fat_data_buff.first_blockno+pdrive->drive_info.fatblock;
pclipped_data = pblk->fat_data_buff.pdata;
if (dirty_block_offset)
{
volume_blockno += dirty_block_offset;
pclipped_data += (dirty_block_offset<<pdrive->drive_info.log2_bytespsec);
}
if (!pc_write_fat_blocks(pdrive, volume_blockno, n_dirty_blocks, pclipped_data,0x3))
return(FALSE);
n_dirty_blocks = pc_get_clear_mbuff_dirty(&pblk->fat_data_buff, &dirty_block_offset);
}
#else
if (pblk->fat_data_buff.dirty_count)
{
if (!pc_write_fat_blocks(pdrive, pblk->fat_data_buff.first_blockno+pdrive->drive_info.fatblock, 1, pblk->fat_data_buff.pdata,0x3))
return(FALSE);
pc_zero_mbuff_dirty(&pblk->fat_data_buff);
}
#endif
return(TRUE);
}
/* Write blocks to the FAT, blockno is offset from start of volume */
BOOLEAN pc_write_fat_blocks(DDRIVE *pdrive,dword fat_blockno, dword nblocks, byte *fat_data,dword which_copy)
{
if (which_copy & 0x1)
{
if (!fat_devio_write(pdrive,fat_blockno, nblocks, fat_data,0))
{
/* set errno to PEDEVICE unless devio set errno */
io_error:
if (!get_errno())
rtfs_set_errno(PEIOERRORWRITEFAT, __FILE__, __LINE__); /* flush_fat device write error */
return(FALSE);
}
}
if (which_copy & 0x2 && pdrive->drive_info.numfats >= 2)
{ /* Write the second copy */
if (!fat_devio_write(pdrive,fat_blockno, nblocks, fat_data,1))
goto io_error;
}
return(TRUE);
}
int pc_async_flush_fat_blocks(DDRIVE *pdrive,dword max_flushes_per_pass)
{
FATBUFF *pblk;
dword num_flushed;
if (!chk_fat_dirty(pdrive))
return(PC_ASYNC_COMPLETE);
ERTFS_ASSERT(pdrive->fatcontext.num_dirty > 0)
if (pdrive->drive_info.fasize == 3) /* For FAT12 convert to synchronous */
max_flushes_per_pass = 0;
pblk = pdrive->fatcontext.pcommitted_buffers;
ERTFS_ASSERT(pblk)
num_flushed = 0;
while (pblk)
{
if (pblk->fat_data_buff.dirty_count)
{
if (max_flushes_per_pass && (num_flushed >= max_flushes_per_pass))
return(PC_ASYNC_CONTINUE);
if (!pc_write_fat_block_buffer_page(pdrive,pblk))
return(PC_ASYNC_ERROR);
pc_zero_mbuff_dirty(&pblk->fat_data_buff);
pdrive->fatcontext.num_dirty -= 1;
num_flushed += 1;
}
pblk = pblk->pnext;
}
if (!pblk)
{
clear_fat_dirty(pdrive);
if (!fat_flushinfo(pdrive))
return(PC_ASYNC_ERROR);
return(PC_ASYNC_COMPLETE);
}
else if (pdrive->fatcontext.num_dirty)
return(PC_ASYNC_CONTINUE);
else
{
return(PC_ASYNC_COMPLETE);
}
}
/* RTFS mbuff support package.. Each FAT block buffer pool entry (FATBUFF)
contains a pcmbuff structure, which supports buffering up to 32 blocks
per FATBUFF structure. Blocks are read into the the mbuff structures
in mutiblock reads. Writes can be multiblock but a dirty count and
dirty bitmap are provided to allow writing only the blocks in the
page that have been modified.
The following routines are provided:
void pc_set_mbuff_dirty() - Mark one or more blocks in the mbuff dirty
void pc_zero_mbuff_dirty() - Clear dirty status for all blocks
pc_get_clear_mbuff_dirty() - Retrieve the next contiguous dirty blocks
in the mbuff and clear the dirty status.
*/
#define DEBUG_MBUFFS 0
#if (DEBUG_MBUFFS)
int countbits(dword d, int *first_bit, int *last_bit)
{
dword dirty_bit;
int i, dirty_count;
dirty_bit = 1;
dirty_count = 0;
*first_bit = 0;
*last_bit = 0;
for (i = 0; i < 32; i++)
{
if (d & dirty_bit)
{
if (!dirty_count)
*first_bit = i;
dirty_count += 1;
*last_bit = i;
}
dirty_bit <<= 1;
}
return(dirty_count);
}
void check_mbuff(PCMBUFF *pcmb)
{
int dirty_count, first_bit, last_bit;
/* Check if marked "all dirty" first */
if (pcmb->block_count == pcmb->dirty_count && pcmb->dirty_block_offset == 0 && pcmb->dirty_bitmap == 0xffffffff)
return;
dirty_count = countbits(pcmb->dirty_bitmap, &first_bit, &last_bit);
ERTFS_ASSERT(dirty_count != pcmb->dirty_count)
if (dirty_count)
{
ERTFS_ASSERT(first_bit == pcmb->dirty_block_offset)
}
}
#define DEBUG_CHECK_MBUFF(X) check_mbuff(X);
#else
#define DEBUG_CHECK_MBUFF(X)
#endif
/* Sets sepcific sectors in the mbuff dirty called when Rtfs is configure to flush only dirty sectors in a page buffer with multiple writes */
void pc_set_mbuff_dirty(PCMBUFF *pcmb, dword block_offset, int block_count)
{
#if (INCLUDE_MULTI_BLOCKS_PERBUFFER)
dword dirty_bit;
int block_offset_int;
block_offset_int = (int) block_offset;
DEBUG_CHECK_MBUFF(pcmb)
/* Remember the numerically first dirty block, (speeds flush) */
if (pcmb->dirty_bitmap == 0 || block_offset_int < pcmb->dirty_block_offset)
pcmb->dirty_block_offset = block_offset;
/* Set dirty bits */
dirty_bit = 1;
dirty_bit <<= block_offset_int;
while(block_count--)
{
/* Defensive - test dirty bit for zero so we dont bump dirty count if args are wrong */
if (dirty_bit && !(dirty_bit & pcmb->dirty_bitmap))
{ /* Up the dirty count and set dirty if not done already */
pcmb->dirty_count += 1;
pcmb->dirty_bitmap |= dirty_bit;
}
dirty_bit <<= 1;
}
DEBUG_CHECK_MBUFF(pcmb)
#else
RTFS_ARGSUSED_INT(block_count);
RTFS_ARGSUSED_DWORD(block_offset);
pcmb->dirty_count = 1;
#endif
}
void pc_zero_mbuff_dirty(PCMBUFF *pcmb)
{
pcmb->dirty_count = 0;
pcmb->dirty_block_offset = 0;
pcmb->dirty_bitmap = 0;
}
#if (INCLUDE_MULTI_BLOCKS_PERBUFFER)
int pc_get_clear_mbuff_dirty(PCMBUFF *pcmb, int *pfirst_dirty)
{
DEBUG_CHECK_MBUFF(pcmb)
if (!pcmb->dirty_count)
return(0);
*pfirst_dirty = pcmb->dirty_block_offset; /* Should be correct */
if (pcmb->dirty_count == 1)
{ /* Special case, one block dirty */
pc_zero_mbuff_dirty(pcmb);
return(1);
}
else if ((pcmb->dirty_block_offset + pcmb->dirty_count) == pcmb->block_count)
{ /* Special case, all blocks dirty to the end */
int ret_dirty_count;
ret_dirty_count =pcmb->dirty_count;
pc_zero_mbuff_dirty(pcmb);
return(ret_dirty_count);
}
else
{ /* Return the next group of dirty blocks from the bitmap, there will be more to follow. */
dword dirty_bit_test,dirty_bit_clear;
int dirty_count;
/* Test and clear dirty bits */
dirty_bit_test = 1;
dirty_bit_test <<= pcmb->dirty_block_offset;
dirty_bit_clear = ~dirty_bit_test;
/* Defensive programming first_dirty_block should be dirty. should not happen */
ERTFS_ASSERT((dirty_bit_test & pcmb->dirty_bitmap) != 0)
if (!(dirty_bit_test & pcmb->dirty_bitmap))
{
pc_zero_mbuff_dirty(pcmb);
return(0);
}
/* Count contiguous dirty bits starting from pcmb->dirty_block_offset..
and clear the bits as we count them */
dirty_count = 0;
while (dirty_bit_test & pcmb->dirty_bitmap)
{
dirty_count += 1;
pcmb->dirty_bitmap &= dirty_bit_clear;
dirty_bit_test <<= 1;
dirty_bit_clear <<= 1;
}
/* Defensive programming dirty_count should not be zero. should not happen */
ERTFS_ASSERT((dirty_count != 0))
if (!dirty_count)
{
pc_zero_mbuff_dirty(pcmb);
return(0);
}
pcmb->dirty_count -= dirty_count;
/* Should never go < 0 */
ERTFS_ASSERT(pcmb->dirty_count >= 0)
if (pcmb->dirty_count < 0)
{
ERTFS_ASSERT(pcmb->dirty_bitmap == 0)
pc_zero_mbuff_dirty(pcmb);
return(0);
}
else
{
int clean_count;
/* Find the next dirty block for next time */
pcmb->dirty_block_offset += dirty_count;
clean_count = 0;
while (dirty_bit_test && ((dirty_bit_test & pcmb->dirty_bitmap) == 0))
{
clean_count += 1;
dirty_bit_test <<= 1;
}
pcmb->dirty_block_offset += clean_count; /* now contains the first dirty block */
/* Defensive programming intervening clean bits should not be zero. should not happen */
ERTFS_ASSERT((clean_count != 0))
if (!clean_count)
{
pc_zero_mbuff_dirty(pcmb);
}
}
DEBUG_CHECK_MBUFF(pcmb)
return(dirty_count);
}
}
#endif /* #if (INCLUDE_MULTI_BLOCKS_PERBUFFER) */
#endif /* Exclude from build if read only */

Some files were not shown because too many files have changed in this diff Show More