mirror of
https://github.com/peteratebs/rtfsprofatfilesystem.git
synced 2025-06-18 16:55:34 -04:00
first commit
This commit is contained in:
commit
b0003c4cc9
6
License
Normal file
6
License
Normal 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.
|
||||
|
BIN
Manual.word/ApiPlusReferenceGuide.doc
Normal file
BIN
Manual.word/ApiPlusReferenceGuide.doc
Normal file
Binary file not shown.
BIN
Manual.word/ApiReferenceGuide.doc
Normal file
BIN
Manual.word/ApiReferenceGuide.doc
Normal file
Binary file not shown.
BIN
Manual.word/ApplicationsNotes.doc
Normal file
BIN
Manual.word/ApplicationsNotes.doc
Normal file
Binary file not shown.
BIN
Manual.word/CommandShellReference.doc
Normal file
BIN
Manual.word/CommandShellReference.doc
Normal file
Binary file not shown.
BIN
Manual.word/ConfigurationGuide.doc
Normal file
BIN
Manual.word/ConfigurationGuide.doc
Normal file
Binary file not shown.
BIN
Manual.word/DriverAndPortingGuide.doc
Normal file
BIN
Manual.word/DriverAndPortingGuide.doc
Normal file
Binary file not shown.
BIN
Manual.word/FailsafeTechnicalReferenceManual.doc
Normal file
BIN
Manual.word/FailsafeTechnicalReferenceManual.doc
Normal file
Binary file not shown.
BIN
Manual.word/InstallationGuide.doc
Normal file
BIN
Manual.word/InstallationGuide.doc
Normal file
Binary file not shown.
BIN
Manual.word/RTFS_COVER.doc
Normal file
BIN
Manual.word/RTFS_COVER.doc
Normal file
Binary file not shown.
BIN
Manual.word/Thumbs.db
Normal file
BIN
Manual.word/Thumbs.db
Normal file
Binary file not shown.
BIN
Manual.word/readme60.doc
Normal file
BIN
Manual.word/readme60.doc
Normal file
Binary file not shown.
BIN
Manual.word/readme61.doc
Normal file
BIN
Manual.word/readme61.doc
Normal file
Binary file not shown.
BIN
Manual.word/revhst60.doc
Normal file
BIN
Manual.word/revhst60.doc
Normal file
Binary file not shown.
BIN
Manual.word/rtfilesappnote.doc
Normal file
BIN
Manual.word/rtfilesappnote.doc
Normal file
Binary file not shown.
BIN
Manual.word/~$vhst60.doc
Normal file
BIN
Manual.word/~$vhst60.doc
Normal file
Binary file not shown.
BIN
Manual/ApiPlusReferenceGuide.pdf
Normal file
BIN
Manual/ApiPlusReferenceGuide.pdf
Normal file
Binary file not shown.
BIN
Manual/ApiReferenceGuide.pdf
Normal file
BIN
Manual/ApiReferenceGuide.pdf
Normal file
Binary file not shown.
BIN
Manual/ApplicationsNotes.pdf
Normal file
BIN
Manual/ApplicationsNotes.pdf
Normal file
Binary file not shown.
BIN
Manual/CommandShellReference.pdf
Normal file
BIN
Manual/CommandShellReference.pdf
Normal file
Binary file not shown.
BIN
Manual/ConfigurationGuide.pdf
Normal file
BIN
Manual/ConfigurationGuide.pdf
Normal file
Binary file not shown.
BIN
Manual/DriverAndPortingGuide.pdf
Normal file
BIN
Manual/DriverAndPortingGuide.pdf
Normal file
Binary file not shown.
BIN
Manual/FailsafeTechnicalReferenceManual.pdf
Normal file
BIN
Manual/FailsafeTechnicalReferenceManual.pdf
Normal file
Binary file not shown.
BIN
Manual/InstallationGuide.pdf
Normal file
BIN
Manual/InstallationGuide.pdf
Normal file
Binary file not shown.
BIN
Manual/revhst60.pdf
Normal file
BIN
Manual/revhst60.pdf
Normal file
Binary file not shown.
BIN
Manual/rtfilesappnote.pdf
Normal file
BIN
Manual/rtfilesappnote.pdf
Normal file
Binary file not shown.
25
README.MD
Normal file
25
README.MD
Normal 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
28
include/packagebasic.h
Normal 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
28
include/packagepro.h
Normal 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___ */
|
28
include/packageprofailsafe.h
Normal file
28
include/packageprofailsafe.h
Normal 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
28
include/packageproplus.h
Normal 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___ */
|
28
include/packageproplusdvr.h
Normal file
28
include/packageproplusdvr.h
Normal 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___ */
|
28
include/packageproplusdvrfailsafe.h
Normal file
28
include/packageproplusdvrfailsafe.h
Normal 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___ */
|
28
include/packageproplusfailsafe.h
Normal file
28
include/packageproplusfailsafe.h
Normal 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
71
include/portconf.h
Normal 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
103
include/rtexfatprotos.h
Normal 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
153
include/rtexfattypes.h
Normal 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
45
include/rtfs.h
Normal 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
106
include/rtfsarch.h
Normal 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
354
include/rtfsblkmedia.h
Normal 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
323
include/rtfsconf.h
Normal 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
43
include/rtfsconfig.h
Normal 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
108
include/rtfserr.h
Normal 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
497
include/rtfsfailsafe.h
Normal 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
28
include/rtfspackage.h
Normal 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
946
include/rtfsprotos.h
Normal 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
1765
include/rtfstypes.h
Normal file
File diff suppressed because it is too large
Load Diff
53
include/rtfsversion.h
Normal file
53
include/rtfsversion.h
Normal 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
338
rtfscommon/apps/appcmdfs.c
Normal 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 */
|
792
rtfscommon/apps/appcmdshformat.c
Normal file
792
rtfscommon/apps/appcmdshformat.c
Normal 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
2667
rtfscommon/apps/appcmdshrd.c
Normal file
File diff suppressed because it is too large
Load Diff
1419
rtfscommon/apps/appcmdshwr.c
Normal file
1419
rtfscommon/apps/appcmdshwr.c
Normal file
File diff suppressed because it is too large
Load Diff
410
rtfscommon/apps/apputil.c
Normal file
410
rtfscommon/apps/apputil.c
Normal 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
1880
rtfscommon/apps/prfstest.c
Normal file
File diff suppressed because it is too large
Load Diff
128
rtfscommon/apps/protests.h
Normal file
128
rtfscommon/apps/protests.h
Normal 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);
|
361
rtfscommon/apps/protestsrd.c
Normal file
361
rtfscommon/apps/protestsrd.c
Normal 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
2267
rtfscommon/source/apickdsk.c
Normal file
File diff suppressed because it is too large
Load Diff
336
rtfscommon/source/apideltr.c
Normal file
336
rtfscommon/source/apideltr.c
Normal 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 */
|
184
rtfscommon/source/apidirent.c
Normal file
184
rtfscommon/source/apidirent.c
Normal 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 */
|
59
rtfscommon/source/apidiskclose.c
Normal file
59
rtfscommon/source/apidiskclose.c
Normal 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);
|
||||
}
|
86
rtfscommon/source/apidiskflush.c
Normal file
86
rtfscommon/source/apidiskflush.c
Normal 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 */
|
123
rtfscommon/source/apidiskinford.c
Normal file
123
rtfscommon/source/apidiskinford.c
Normal 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
452
rtfscommon/source/apienum.c
Normal 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);
|
||||
}
|
248
rtfscommon/source/apifilmv.c
Normal file
248
rtfscommon/source/apifilmv.c
Normal 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
1249
rtfscommon/source/apifrmat.c
Normal file
File diff suppressed because it is too large
Load Diff
220
rtfscommon/source/apigetwd.c
Normal file
220
rtfscommon/source/apigetwd.c
Normal 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);
|
||||
}
|
415
rtfscommon/source/apigfrst.c
Normal file
415
rtfscommon/source/apigfrst.c
Normal 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);
|
||||
}
|
||||
}
|
179
rtfscommon/source/apigread.c
Normal file
179
rtfscommon/source/apigread.c
Normal 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
428
rtfscommon/source/apiinfo.c
Normal 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, §orsize))
|
||||
sectorsize = 0;
|
||||
return(sectorsize);
|
||||
}
|
||||
|
||||
int pc_cluster_size(byte *drive) /*__apifn__*/
|
||||
{
|
||||
int clustersize, sectorsize;
|
||||
if (!_pc_xxxxx_size(drive, &clustersize, §orsize))
|
||||
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);
|
||||
}
|
53
rtfscommon/source/apiinit.c
Normal file
53
rtfscommon/source/apiinit.c
Normal 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" */
|
||||
}
|
313
rtfscommon/source/apimkdir.c
Normal file
313
rtfscommon/source/apimkdir.c
Normal 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 */
|
1429
rtfscommon/source/apinandregress.c
Normal file
1429
rtfscommon/source/apinandregress.c
Normal file
File diff suppressed because it is too large
Load Diff
281
rtfscommon/source/apipartition.c
Normal file
281
rtfscommon/source/apipartition.c
Normal 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
3614
rtfscommon/source/apiregrs.c
Normal file
File diff suppressed because it is too large
Load Diff
95
rtfscommon/source/apisetattr.c
Normal file
95
rtfscommon/source/apisetattr.c
Normal 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 */
|
353
rtfscommon/source/apisetvol.c
Normal file
353
rtfscommon/source/apisetvol.c
Normal 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);
|
||||
}
|
195
rtfscommon/source/apisetwd.c
Normal file
195
rtfscommon/source/apisetwd.c
Normal 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
181
rtfscommon/source/apistat.c
Normal 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;
|
||||
|
||||
}
|
133
rtfscommon/source/apiunlink.c
Normal file
133
rtfscommon/source/apiunlink.c
Normal 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 */
|
302
rtfscommon/source/csasciird.c
Normal file
302
rtfscommon/source/csasciird.c
Normal 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
|
236
rtfscommon/source/csasciiwr.c
Normal file
236
rtfscommon/source/csasciiwr.c
Normal 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 */
|
483
rtfscommon/source/cscommon.c
Normal file
483
rtfscommon/source/cscommon.c
Normal 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
453
rtfscommon/source/csjisrd.c
Normal 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
3982
rtfscommon/source/csjistab.c
Normal file
File diff suppressed because it is too large
Load Diff
421
rtfscommon/source/csjiswr.c
Normal file
421
rtfscommon/source/csjiswr.c
Normal 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 */
|
9
rtfscommon/source/csstrtab.c
Normal file
9
rtfscommon/source/csstrtab.c
Normal 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";
|
1467
rtfscommon/source/drdynamic.c
Normal file
1467
rtfscommon/source/drdynamic.c
Normal file
File diff suppressed because it is too large
Load Diff
168
rtfscommon/source/prbasicemurd.c
Normal file
168
rtfscommon/source/prbasicemurd.c
Normal 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
|
||||
}
|
75
rtfscommon/source/prbasicemuwr.c
Normal file
75
rtfscommon/source/prbasicemuwr.c
Normal 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 */
|
817
rtfscommon/source/rtdblockrd.c
Normal file
817
rtfscommon/source/rtdblockrd.c
Normal 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) */
|
94
rtfscommon/source/rtdblockwr.c
Normal file
94
rtfscommon/source/rtdblockwr.c
Normal 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 */
|
245
rtfscommon/source/rtdeviord.c
Normal file
245
rtfscommon/source/rtdeviord.c
Normal 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
|
47
rtfscommon/source/rtdeviowr.c
Normal file
47
rtfscommon/source/rtdeviowr.c
Normal 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 */
|
1136
rtfscommon/source/rtdrobjrd.c
Normal file
1136
rtfscommon/source/rtdrobjrd.c
Normal file
File diff suppressed because it is too large
Load Diff
608
rtfscommon/source/rtdrobjwr.c
Normal file
608
rtfscommon/source/rtdrobjwr.c
Normal 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 */
|
469
rtfscommon/source/rteraseblock.c
Normal file
469
rtfscommon/source/rteraseblock.c
Normal 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 */
|
855
rtfscommon/source/rtfatdrvrd.c
Normal file
855
rtfscommon/source/rtfatdrvrd.c
Normal 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) */
|
1298
rtfscommon/source/rtfatdrvwr.c
Normal file
1298
rtfscommon/source/rtfatdrvwr.c
Normal file
File diff suppressed because it is too large
Load Diff
953
rtfscommon/source/rtfblockrd.c
Normal file
953
rtfscommon/source/rtfblockrd.c
Normal 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 */
|
386
rtfscommon/source/rtfblockwr.c
Normal file
386
rtfscommon/source/rtfblockwr.c
Normal 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
Loading…
Reference in New Issue
Block a user