mirror of
https://github.com/akuker/RASCSI.git
synced 2024-06-25 01:29:37 +00:00
* Use foreach * Renaming * Revert "Renaming" This reverts commitb0554b9c0a
. * Manpage updates * Removed obsolete assertions * Replaced QWORD by uint64_t and removed respective typedef * Removed LPCSTR typedef * Removed LPCTSTR typedef * Removed LPTSTR typedef * Renamed SCSI command interface classes * Renamed xm6.h to rascsi.h * Moved interface classes to new interfaces subfolder * Added include * Fixed compilation issues of 64 bit Ubuntu * Renaming * Sort block sizes * protobuf interface description update * Fixed handling for sector size for non-disk devices * Fixed typo * Fixed comment * Translate code commends into English, removing redundant ones (#214) * Comment update * For other bridge interfaces than eth0 IP address and netmask can be provided * Added special rule for testing on x86 PCs * Translated code comments into English, removing some redundant ones in the process, plus fixing typos (#215) * Translate code commends into English, removing redundant ones * - Translated all remaining Japanese code comments in src/raspberrypi/ to English, with the exception of cfilesystem.cpp|h - Removed some redundant comments where the context is obvious from the code - Fixed a few typos and mistakes * Comment update * Removed unused typedefs * Added special rule for testing on x86 PCs * Comment update * Comment update * Updated capacity calculation * Updated protobuf interface to signal parameter support * Simplified protobuf interface * Updated rasctl server info output * Updated logging * protobuf interface has to return block only if it is configurable * Updated block size handling * Improved error message if ID is already in use * Removed typedef * Renamed protobuf interface method * Renaming * Use protobuf::Messsge instead of protobuf::MessageLite * default_image_folder cannot be an empty string, removed obsolete check * Logging update * Made some error messages more concise * Removed magic constant * Updated error message * Comment update * Names of removable media drives must be constant and not contain the capacity * Improved DeviceFactory error handling * More error handing improvements * Interface comment update * Pass interface list to ctapdriver when creating bridge * Moved initialization code * Updated rasctl server information output * Improved handling of MO capacities * Renaming * Comment update * Reject inserting a medium when there is already a medium present (eject first) * Save list of files in use before dry-run * Updated rasctl server info message * Comment update * Fixed typo * Cleaned list handling * Sort devices list by ID *and unit* * Improved block size check * Fixed issue with missing method in old Raspberry Pi OS protobuf implementation * Updated error message * Improve and fix bugs with saving&loading configuration files for rascsi-web (#218) * Translate code commends into English, removing redundant ones * - Translated all remaining Japanese code comments in src/raspberrypi/ to English, with the exception of cfilesystem.cpp|h - Removed some redundant comments where the context is obvious from the code - Fixed a few typos and mistakes * - Store only file path and name to configuration csv - Strip known non-file path strings when reading configuration csv (backwards compatibility) - Validate SCSI ID before attempting to attach a device * Add comment and TODO * Partial translation of cfilesystem.h * Move csv read/write logic into file_cmd.py * Load default.csv on rascsi-web startup * Add rudimentary error handling to config loading/saving * Implement a delete configuration csv file feature. Also rename the delete_image method to delete_file and made it take the full file patch as argument to be consistent with other file operation methods. * Catch the exception when attempting to exclude SCSI id that is already in use from a list of valid SCSI ids * Fix error handling when failing to open a csv file for read or write * Removed unused structures, code and type cleanup * Use unscoped enums for commands * SASI Format opcode is 0x06, not 0x04 (see comment in code) * Removed duplicate command * Code review, data type updates * Data type updated, use #pragma once * Logging update * Renaming * Renaming * Removed duplicate code * Renaming * Refactoring * Removed TODO * Updated logging * Comment update * Comment update * Updated GetEventStatusNotification * Removed goto * Options -h and -v do not require to be the root user (fixes issue #166) * Updated error messages and exception handling * Added number of supported LUNs to protobuf interface * Updated list handling of protobuf interface * Comment update * Improved error handling * Added missing return statement * Allow empty device list * Fixed unnecessary detach_all() when config file isn't read (#221) * Translate code commends into English, removing redundant ones * - Translated all remaining Japanese code comments in src/raspberrypi/ to English, with the exception of cfilesystem.cpp|h - Removed some redundant comments where the context is obvious from the code - Fixed a few typos and mistakes * - Store only file path and name to configuration csv - Strip known non-file path strings when reading configuration csv (backwards compatibility) - Validate SCSI ID before attempting to attach a device * Add comment and TODO * Partial translation of cfilesystem.h * Move csv read/write logic into file_cmd.py * Load default.csv on rascsi-web startup * Add rudimentary error handling to config loading/saving * Implement a delete configuration csv file feature. Also rename the delete_image method to delete_file and made it take the full file patch as argument to be consistent with other file operation methods. * Catch the exception when attempting to exclude SCSI id that is already in use from a list of valid SCSI ids * Fix error handling when failing to open a csv file for read or write * Run detach_all() only after succeeding to open a file for reading * Protecting/unprotecing a non-ready medium is considered not possible * Updated error message * Extract detaching all devices, add parameter list support * Comment update * Fixed typos * Restore files in use if dry-run fails * Feature configurable reserved id for rascsi-web (#223) * Translate code commends into English, removing redundant ones * - Translated all remaining Japanese code comments in src/raspberrypi/ to English, with the exception of cfilesystem.cpp|h - Removed some redundant comments where the context is obvious from the code - Fixed a few typos and mistakes * - Store only file path and name to configuration csv - Strip known non-file path strings when reading configuration csv (backwards compatibility) - Validate SCSI ID before attempting to attach a device * Add comment and TODO * Partial translation of cfilesystem.h * Move csv read/write logic into file_cmd.py * Load default.csv on rascsi-web startup * Add rudimentary error handling to config loading/saving * Implement a delete configuration csv file feature. Also rename the delete_image method to delete_file and made it take the full file patch as argument to be consistent with other file operation methods. * Catch the exception when attempting to exclude SCSI id that is already in use from a list of valid SCSI ids * Fix error handling when failing to open a csv file for read or write * Run detach_all() only after succeeding to open a file for reading * Make the reserved SCSI id configurable through an argument to start.sh; make the rascsi-web service reserve 7 by default to maintain current behavior. * Make it possible to reserve multiple scsi ids in the web ui * Added support for reserved IDs * rasctl output update * Re-ordered logging * Logging update * Make use of the newly introduced 'rasctl -r' to have the webui reserve ids on the backend side upon startup (#224) * Translate code commends into English, removing redundant ones * - Translated all remaining Japanese code comments in src/raspberrypi/ to English, with the exception of cfilesystem.cpp|h - Removed some redundant comments where the context is obvious from the code - Fixed a few typos and mistakes * - Store only file path and name to configuration csv - Strip known non-file path strings when reading configuration csv (backwards compatibility) - Validate SCSI ID before attempting to attach a device * Add comment and TODO * Partial translation of cfilesystem.h * Move csv read/write logic into file_cmd.py * Load default.csv on rascsi-web startup * Add rudimentary error handling to config loading/saving * Implement a delete configuration csv file feature. Also rename the delete_image method to delete_file and made it take the full file patch as argument to be consistent with other file operation methods. * Catch the exception when attempting to exclude SCSI id that is already in use from a list of valid SCSI ids * Fix error handling when failing to open a csv file for read or write * Run detach_all() only after succeeding to open a file for reading * Make use of the new 'rasctl -r' command to reserve IDs on the backend side as well. * Updated string to integer conversions * Improved string to integer conversion * Move string to integer conversion to rasutil * Removed unused variable * Fixed detach, which did not remove the filename from the filenames set * Re-added folder to gitignore * Set/Display patch version * Fix issue where reserved ids were not reserved again when restarting rascsi-service from within the web ui (#226) * Translate code commends into English, removing redundant ones * - Translated all remaining Japanese code comments in src/raspberrypi/ to English, with the exception of cfilesystem.cpp|h - Removed some redundant comments where the context is obvious from the code - Fixed a few typos and mistakes * - Store only file path and name to configuration csv - Strip known non-file path strings when reading configuration csv (backwards compatibility) - Validate SCSI ID before attempting to attach a device * Add comment and TODO * Partial translation of cfilesystem.h * Move csv read/write logic into file_cmd.py * Load default.csv on rascsi-web startup * Add rudimentary error handling to config loading/saving * Implement a delete configuration csv file feature. Also rename the delete_image method to delete_file and made it take the full file patch as argument to be consistent with other file operation methods. * Catch the exception when attempting to exclude SCSI id that is already in use from a list of valid SCSI ids * Fix error handling when failing to open a csv file for read or write * Run detach_all() only after succeeding to open a file for reading * Make use of the new 'rasctl -r' command to reserve IDs on the backend side as well. * Make sure reserved SCSI IDs gets reserved again when restarting rascsi-service from within the web ui * Updated interface comment * Accept daynaport as legacy type * Fixed typo * Remove file from the list of files in use when ejected with a SCSI command * Check for attached device for INSERT, EJECT, PROTECT, UNPROTECT * Fixed error handling * Fixed filepath handling * Added more device shortcuts to rasctl * Fixed function declaration * Extraced ATTACH and DETACH * Extracted INSERT * Simplified ProcessCmd * Comment update * Fixed memory leak * Log information on whether a new device is protected or read-only * Updated errro message * Updated error message * Initialize private fields * Updated rasctl help message * Added DEVICE_INFO to protobuf interface * Improved error handling * DEVICE_INFO supports device list * Updated server info handling * Unified result handling with oneof, all commands now return PbResult * A result can always return a message string * Fixed typo * Simplified sending of commands * Improved error handling * Removed unused code * Updated error handling * Code cleanup * Comment update * Updated logging * Updated error handling * Updated handling of removed status for devices without image file support * Comment update * Fixed typo * Updated logging * Updated parameter handling * Updated setting default interfaces * Revert "Updated setting default interfaces" This reverts commit210abc775d
. * Revert "Updated parameter handling" This reverts commit35302addd5
. * rascsi supports reserving IDs * Updated help message * Replaced BOOL by bool * Logging update * Logging update * Added default parameters to device properties * Return parameters a device was set up with * Improved device initialization * Updated default parameter handling * Updated default parameter handling * Fixed typo * Comment updates * Comment update * Manage default parameters in the respective device * Do not pass empty parameter string * Added supports_params flag * Made comparisons more consistent * Updated error handling * Updated exception handling * Renaming * Comment update * NEC sectors size must be 512 bytes * Updated logging * Updated vendor name handling * Updated handling of media loading/unloading * Added stoppable property and stopped status * Made MO stoppable * Removed duplicate code * Removed duplicate code * Copy read-only property * Renaming * Removed duplicate code, added START/STOP * Improved default parameter handling * Updated load/eject handling * Logging update * Fixed typo * Verified START/STOP UNIT * Updated logging * Updated status handling * Updated status handling * More status handling updates * Logging update * Made instance fields local variables * Made disk_t private * Made some data structures private * Fixed ARM compile issue * Fixed ctapdriver initialization issue * Reset read-only status when opening an image file * Made logging more consistent * Updated log level * Log load/eject on error level for testing * Revert "Log load/eject on error level for testing" This reverts commitd35a15ea8e
. * Assume drive is not ready after having been stopped * Updated status handling * Fixed typo * Rebuild manpage * Fixed issue #234 (MODE SENSE (10) returns wrong mode parameter header) * Removed unused code * Enum data type update * Removed duplicate range check * Removed duplicate code * Removed more duplicate code * Logging update * SCCD sector size was not meant to be configurable * Updated configurable sector size properties * Removed assertion * Improved error handling * Updated error handling * Re-added special error handling only relevant for SASI * Added TODOs * Comment update * Added override modifier * Removed obsolete debug flag (related code was not called) * Comment and logging updates * Removed obsolete try/catch * Revert "Removed obsolete try/catch" This reverts commit39ca12d8b1
. * Comment update * Removed duplicate code * Updated error messages, use more foreach loops * Updated logging * Logging update * README update * Added block_count * Evaluate block size when inserting a media * rasctl display capacity if available * Info message update * Added missing product name to NEC vital product data * MO block size depends on capacity only * Extended property/status display * Property display update * Updated error handling * (Doc only changes) Fix typos and add clarification that SASI is used on Unix workstations Co-authored-by: Daniel Markstedt <markstedt@gmail.com> Co-authored-by: Tony Kuker <akuker@gmail.com>
963 lines
45 KiB
C++
963 lines
45 KiB
C++
//---------------------------------------------------------------------------
|
||
//
|
||
// SCSI Target Emulator RaSCSI (*^..^*)
|
||
// for Raspberry Pi
|
||
//
|
||
// Powered by XM6 TypeG Technology.
|
||
// Copyright (C) 2016-2020 GIMONS
|
||
// [ Host File System for the X68000 ]
|
||
//
|
||
// Note: This functionality is specific to the X68000 operating system.
|
||
// It is highly unlikely that this will work for other platforms.
|
||
//---------------------------------------------------------------------------
|
||
|
||
#pragma once
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Status code definitions
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
#define FS_INVALIDFUNC 0xFFFFFFFF ///< Executed an invalid function
|
||
#define FS_FILENOTFND 0xFFFFFFFE ///< The selected file can not be found
|
||
#define FS_DIRNOTFND 0xFFFFFFFD ///< The selected directory can not be found
|
||
#define FS_OVEROPENED 0xFFFFFFFC ///< There are too many files open
|
||
#define FS_CANTACCESS 0xFFFFFFFB ///< Can not access the direcory or volume
|
||
#define FS_NOTOPENED 0xFFFFFFFA ///< The selected handle is not opened
|
||
#define FS_INVALIDMEM 0xFFFFFFF9 ///< Memory management has been destroyed
|
||
#define FS_OUTOFMEM 0xFFFFFFF8 ///< Insufficient memory for execution
|
||
#define FS_INVALIDPTR 0xFFFFFFF7 ///< Selected an invalid memory management pointer
|
||
#define FS_INVALIDENV 0xFFFFFFF6 ///< Selected an invalid environment
|
||
#define FS_ILLEGALFMT 0xFFFFFFF5 ///< The exeucted file is in an invalid format
|
||
#define FS_ILLEGALMOD 0xFFFFFFF4 ///< Invalid open access mode
|
||
#define FS_INVALIDPATH 0xFFFFFFF3 ///< Mistake in selected file name
|
||
#define FS_INVALIDPRM 0xFFFFFFF2 ///< Called with an invalid parameter
|
||
#define FS_INVALIDDRV 0xFFFFFFF1 ///< Mistake in selected drive
|
||
#define FS_DELCURDIR 0xFFFFFFF0 ///< Unable to delete the current directory
|
||
#define FS_NOTIOCTRL 0xFFFFFFEF ///< Unable to use IOCTRL with the device
|
||
#define FS_LASTFILE 0xFFFFFFEE ///< Can not find any more files
|
||
#define FS_CANTWRITE 0xFFFFFFED ///< Selected file can not be written
|
||
#define FS_DIRALREADY 0xFFFFFFEC ///< Selected directory is already registered
|
||
#define FS_CANTDELETE 0xFFFFFFEB ///< Can not delete because of a file
|
||
#define FS_CANTRENAME 0xFFFFFFEA ///< Can not rename because of a file
|
||
#define FS_DISKFULL 0xFFFFFFE9 ///< Can not create a file because the disk is full
|
||
#define FS_DIRFULL 0xFFFFFFE8 ///< Can not create a file because the directory is full
|
||
#define FS_CANTSEEK 0xFFFFFFE7 ///< Can not seek in the selected location
|
||
#define FS_SUPERVISOR 0xFFFFFFE6 ///< Selected supervisor in supervisor mode
|
||
#define FS_THREADNAME 0xFFFFFFE5 ///< A thread with this name already exists
|
||
#define FS_BUFWRITE 0xFFFFFFE4 ///< Writing to inter-process communication buffers is disallowed
|
||
#define FS_BACKGROUND 0xFFFFFFE3 ///< Unable to start a background process
|
||
#define FS_OUTOFLOCK 0xFFFFFFE0 ///< Insufficient lock space
|
||
#define FS_LOCKED 0xFFFFFFDF ///< Can not access because it is locked
|
||
#define FS_DRIVEOPENED 0xFFFFFFDE ///< Selected drive has an open handler
|
||
#define FS_LINKOVER 0xFFFFFFDD ///< The symbolic link is nested over 16 times
|
||
#define FS_FILEEXIST 0xFFFFFFB0 ///< The file exists
|
||
|
||
#define FS_FATAL_MEDIAOFFLINE 0xFFFFFFA3 ///< No media inserted
|
||
#define FS_FATAL_WRITEPROTECT 0xFFFFFFA2 ///< Write protected
|
||
#define FS_FATAL_INVALIDCOMMAND 0xFFFFFFA1 ///< Invalid command number
|
||
#define FS_FATAL_INVALIDUNIT 0xFFFFFFA0 ///< Invalid unit number
|
||
|
||
#define HUMAN68K_PATH_MAX 96 ///< Longest path allowed in Human68k
|
||
|
||
//===========================================================================
|
||
//
|
||
/// Human68k name space
|
||
//
|
||
//===========================================================================
|
||
namespace Human68k {
|
||
/// File attribute bit
|
||
enum attribute_t {
|
||
AT_READONLY = 0x01, ///< Read only attribute
|
||
AT_HIDDEN = 0x02, ///< Hidden attribute
|
||
AT_SYSTEM = 0x04, ///< System attribute
|
||
AT_VOLUME = 0x08, ///< Volume label attribute
|
||
AT_DIRECTORY = 0x10, ///< Directory attribute
|
||
AT_ARCHIVE = 0x20, ///< Archive attribute
|
||
AT_ALL = 0xFF, ///< All attribute bits are 1
|
||
};
|
||
|
||
/// File open modes
|
||
enum open_t {
|
||
OP_READ = 0, ///< Read
|
||
OP_WRITE = 1, ///< Write
|
||
OP_FULL = 2, ///< Read/Write
|
||
OP_MASK = 0x0F, ///< Decision mask
|
||
OP_SHARE_NONE = 0x10, ///< Sharing forbidden
|
||
OP_SHARE_READ = 0x20, ///< Read sharing
|
||
OP_SHARE_WRITE = 0x30, ///< Write sharing
|
||
OP_SHARE_FULL = 0x40, ///< Read/Write sharing
|
||
OP_SHARE_MASK = 0x70, ///< Sharing decision mask
|
||
OP_SPECIAL = 0x100, ///< Dictionary access
|
||
};
|
||
|
||
/// Seek types
|
||
enum seek_t {
|
||
SK_BEGIN = 0, ///< From the beginning of a file
|
||
SK_CURRENT = 1, ///< From the current location
|
||
SK_END = 2, ///< From the end of the file
|
||
};
|
||
|
||
/// Media byte
|
||
enum media_t {
|
||
MEDIA_2DD_10 = 0xE0, ///< 2DD/10 sector
|
||
MEDIA_1D_9 = 0xE5, ///< 1D/9 sector
|
||
MEDIA_2D_9 = 0xE6, ///< 2D/9 sector
|
||
MEDIA_1D_8 = 0xE7, ///< 1D/8 sector
|
||
MEDIA_2D_8 = 0xE8, ///< 2D/8 sector
|
||
MEDIA_2HT = 0xEA, ///< 2HT
|
||
MEDIA_2HS = 0xEB, ///< 2HS
|
||
MEDIA_2HDE = 0xEC, ///< 2DDE
|
||
MEDIA_1DD_9 = 0xEE, ///< 1DD/9 sector
|
||
MEDIA_1DD_8 = 0xEF, ///< 1DD/8 sector
|
||
MEDIA_MANUAL = 0xF1, ///< Remote drive (manual eject)
|
||
MEDIA_REMOVABLE = 0xF2, ///< Remote drive (removable)
|
||
MEDIA_REMOTE = 0xF3, ///< Remote drive
|
||
MEDIA_DAT = 0xF4, ///< SCSI-DAT
|
||
MEDIA_CDROM = 0xF5, ///< SCSI-CDROM
|
||
MEDIA_MO = 0xF6, ///< SCSI-MO
|
||
MEDIA_SCSI_HD = 0xF7, ///< SCSI-HD
|
||
MEDIA_SASI_HD = 0xF8, ///< SASI-HD
|
||
MEDIA_RAMDISK = 0xF9, ///< RAM disk
|
||
MEDIA_2HQ = 0xFA, ///< 2HQ
|
||
MEDIA_2DD_8 = 0xFB, ///< 2DD/8 sector
|
||
MEDIA_2DD_9 = 0xFC, ///< 2DD/9 sector
|
||
MEDIA_2HC = 0xFD, ///< 2HC
|
||
MEDIA_2HD = 0xFE, ///< 2HD
|
||
};
|
||
|
||
struct namests_t {
|
||
BYTE wildcard; ///< Wildcard array
|
||
BYTE drive; ///< Drive number
|
||
BYTE path[65]; ///< Path (subdirectory +/)
|
||
BYTE name[8]; ///< File name (PADDING 0x20)
|
||
BYTE ext[3]; ///< Extension (PADDING 0x20)
|
||
BYTE add[10]; ///< File name addition (PADDING 0x00)
|
||
|
||
void GetCopyPath(BYTE* szPath) const;
|
||
void GetCopyFilename(BYTE* szFilename) const;
|
||
};
|
||
|
||
struct files_t {
|
||
BYTE fatr; ///< + 0 search attribute; read-only
|
||
// BYTE drive; ///< + 1 drive number; read-only
|
||
DWORD sector; ///< + 2 directory sector; DOS _FILES first address substitute
|
||
// WORD cluster; ///< + 6 directory cluster; details unknown (unused)
|
||
WORD offset; ///< + 8 directory entry; write-only
|
||
// BYTE name[8]; ///< +10 working file name; write-only (unused)
|
||
// BYTE ext[3]; ///< +18 working extension; write-only (unused)
|
||
BYTE attr; ///< +21 file attribute; write-only
|
||
WORD time; ///< +22 last change time of day; write-only
|
||
WORD date; ///< +24 last change date; write-only
|
||
DWORD size; ///< +26 file size; write-only
|
||
BYTE full[23]; ///< +30 full name; write-only
|
||
};
|
||
|
||
struct fcb_t {
|
||
// BYTE pad00[6]; ///< + 0~+ 5 (unused)
|
||
DWORD fileptr; ///< + 6~+ 9 file pointer
|
||
// BYTE pad01[4]; ///< +10~+13 (unused)
|
||
WORD mode; ///< +14~+15 open mode
|
||
// BYTE pad02[16]; ///< +16~+31 (unused)
|
||
// DWORD zero; ///< +32~+35 zeros are written when opened (unused)
|
||
// BYTE name[8]; ///< +36~+43 file name (PADDING 0x20) (unused)
|
||
// BYTE ext[3]; ///< +44~+46 extension (PADDING 0x20) (unused)
|
||
BYTE attr; ///< +47 file attribute
|
||
// BYTE add[10]; ///< +48~+57 file name addition (PADDING 0x00) (unused)
|
||
WORD time; ///< +58~+59 last change time of day
|
||
WORD date; ///< +60~+61 last change date
|
||
// WORD cluster; ///< +62~+63 cluster number (unused)
|
||
DWORD size; ///< +64~+67 file size
|
||
// BYTE pad03[28]; ///< +68~+95 FAT cache (unused)
|
||
};
|
||
|
||
struct capacity_t {
|
||
WORD freearea; ///< + 0 Number of available clusters
|
||
WORD clusters; ///< + 2 Total number of clusters
|
||
WORD sectors; ///< + 4 Number of sectors per cluster
|
||
WORD bytes; ///< + 6 Number of bytes per sector
|
||
};
|
||
|
||
struct ctrldrive_t {
|
||
BYTE status; ///< +13 status
|
||
BYTE pad[3]; ///< Padding
|
||
};
|
||
|
||
struct dpb_t {
|
||
WORD sector_size; ///< + 0 Number of bytes in one sector
|
||
BYTE cluster_size; ///< + 2 Number sectors in one cluster -1
|
||
BYTE shift; ///< + 3 Number of cluster→sector shifts
|
||
WORD fat_sector; ///< + 4 FAT first sector number
|
||
BYTE fat_max; ///< + 6 FAT storage quantity
|
||
BYTE fat_size; ///< + 7 FAT controlled sector number (excluding duplicates)
|
||
WORD file_max; ///< + 8 Number of files in the root directory
|
||
WORD data_sector; ///< +10 First sector number of data storage
|
||
WORD cluster_max; ///< +12 Total number of clusters +1
|
||
WORD root_sector; ///< +14 First sector number of root directory
|
||
// DWORD driverentry; ///< +16 Device driver pointer (unused)
|
||
BYTE media; ///< +20 Media identifier
|
||
// BYTE flag; ///< +21 Flag used by DPB (unused)
|
||
};
|
||
|
||
/// Directory entry struct
|
||
struct dirent_t {
|
||
BYTE name[8]; ///< + 0 File name (PADDING 0x20)
|
||
BYTE ext[3]; ///< + 8 Extension (PADDING 0x20)
|
||
BYTE attr; ///< +11 File attribute
|
||
BYTE add[10]; ///< +12 File name addition (PADDING 0x00)
|
||
WORD time; ///< +22 Last change time of day
|
||
WORD date; ///< +24 Last change date
|
||
WORD cluster; ///< +26 Cluster number
|
||
DWORD size; ///< +28 File size
|
||
};
|
||
|
||
/// IOCTRL parameter union
|
||
union ioctrl_t {
|
||
BYTE buffer[8]; ///< Access in byte units
|
||
DWORD param; ///< Parameter (First 4 bytes)
|
||
WORD media; ///< Media byte (First 2 bytes)
|
||
};
|
||
|
||
/// Command line parameter struct
|
||
/**
|
||
The driver itself is included in the beginning of the argument,
|
||
so setting to a length longer than HUMAN68K_PATH_MAX
|
||
*/
|
||
struct argument_t {
|
||
BYTE buf[256]; ///< Command line argument
|
||
};
|
||
}
|
||
|
||
/// Number of FILES buffers
|
||
/**
|
||
Under normal circumstances it's enough with just a few buffers,
|
||
but Human68k multitasking may lead to multiple threads working
|
||
deeply in the system, which is why this value is set this high.
|
||
|
||
Default is 20 buffers.
|
||
*/
|
||
#define XM6_HOST_FILES_MAX 20
|
||
|
||
/// Number of FCB buffers
|
||
/**
|
||
This decides how many files can be opened at the same time.
|
||
|
||
Default is 100 files.
|
||
*/
|
||
#define XM6_HOST_FCB_MAX 100
|
||
|
||
/// Max number of virtual clusters and sectors
|
||
/**
|
||
Number of virtual sectors used for accessing the first sector of a file entity.
|
||
Allocating a generous amount to exceed the number of threads lzdsys uses for access.
|
||
|
||
Default is 10 sectors.
|
||
*/
|
||
#define XM6_HOST_PSEUDO_CLUSTER_MAX 10
|
||
|
||
/// Number of caches for directory entries
|
||
/**
|
||
Human68k carries out a large number of checks of directory entries when doing an operation
|
||
inside a subdirectory. This specifies the number of caches used to speed up this operation.
|
||
Cache is allocated per drive. The more you add the faster it gets, but use too many
|
||
and the host OS gets under a heavy load, so be careful.
|
||
|
||
Default is 16.
|
||
*/
|
||
#define XM6_HOST_DIRENTRY_CACHE_MAX 16
|
||
|
||
/// Max number of entries that can be stored per directory
|
||
/**
|
||
When a large number of files are stored in a directory, a larger amount of data than
|
||
contemporanous applications can handle will be returned. This may lead to errors such as
|
||
partial data being recognized, performance dropping significantly, or OOM crashes.
|
||
To guard against this, an upper limit is defined here. In the case of a particular
|
||
file manager, the upper limit is 2560 files. This is one good example to use as reference.
|
||
|
||
Default is around 60000 entries. (Upper limit of the FAT root directory)
|
||
*/
|
||
#define XM6_HOST_DIRENTRY_FILE_MAX 65535
|
||
|
||
/// Max number of patterns for file name deduplication
|
||
/**
|
||
The file names on the Human68k side are automatically created based on the file system on
|
||
the host side. However, Human68k have stricter file name length restrictions than the host has.
|
||
Because of this, there is a risk that file name duplication will occur. When this happens,
|
||
WindrvXM will use a certain renaming heuristic to generate alternate file names to resolve
|
||
the duplication. Theoretically, there are over 60 million (36^5) unique file names that
|
||
can be generated by this method. However, in reality any more than a few hundred
|
||
deduplications will take excessive processing time. So here an upper limit to deduplication
|
||
is set in order to maintain system performance. If a system is operated with common sense,
|
||
you should only need a few dozen deduplication patterns, so this value can be kept low
|
||
to further improve performance. In the case deduplication is not carried out, multiple files
|
||
with the same name will be created. When trying to access such files,
|
||
only the first entry will ever be accessed.
|
||
|
||
Default is 36 patterns.
|
||
*/
|
||
#define XM6_HOST_FILENAME_PATTERN_MAX 36
|
||
|
||
/// Duplicate file identification mark
|
||
/**
|
||
A symbol used to distinguish between host and Human68k files.
|
||
Do not use a command shell escape character, or similar protected symbol.
|
||
|
||
Default is '@'.
|
||
*/
|
||
#define XM6_HOST_FILENAME_MARK '@'
|
||
|
||
/// WINDRV operational flags
|
||
/**
|
||
Normally set to 0. When put in the OS trash can for deletion, it is set to 1.
|
||
Other values are reserved for future use.
|
||
Can be used for future extentions such as internal operational flags or mock media byte.
|
||
*/
|
||
enum {
|
||
WINDRV_OPT_REMOVE = 0x00000001, ///< Bit 0: File delete process 0:Directly 1:Trash can
|
||
WINDRV_OPT_ALPHABET = 0x00000020, ///< Bit 5: File name comparison; Alphabet distinction 0:No 1:Yes 0:-C 1:+C
|
||
WINDRV_OPT_COMPARE_LENGTH = 0x00000040, ///< Bit 6: File name comparison; String length (unimplemented) 0:18+3 1:8+3 0:+T 1:-T
|
||
WINDRV_OPT_CONVERT_LENGTH = 0x00000080, ///< Bit 7: File name conversion; String length 0:18+3 1:8+3 0:-A 1:+A
|
||
WINDRV_OPT_CONVERT_SPACE = 0x00000100, ///< Bit 8: File name conversion; Space 0:No 1:'_'
|
||
WINDRV_OPT_CONVERT_BADCHAR = 0x00000200, ///< Bit 9: File name conversion; Invalid char 0:No 1:'_'
|
||
WINDRV_OPT_CONVERT_HYPHENS = 0x00000400, ///< Bit10: File name conversion; Middle hyphen 0:No 1:'_'
|
||
WINDRV_OPT_CONVERT_HYPHEN = 0x00000800, ///< Bit11: File name conversion; Initial hyphen 0:No 1:'_'
|
||
WINDRV_OPT_CONVERT_PERIODS = 0x00001000, ///< Bit12: File name conversion; Middle period 0:No 1:'_'
|
||
WINDRV_OPT_CONVERT_PERIOD = 0x00002000, ///< Bit13: File name conversion; Initial period 0:No 1:'_'
|
||
WINDRV_OPT_REDUCED_SPACE = 0x00010000, ///< Bit16: File name reduction; Space 0:No 1:Reduced
|
||
WINDRV_OPT_REDUCED_BADCHAR = 0x00020000, ///< Bit17: File name reduction; Invalid char 0:No 1:Reduced
|
||
WINDRV_OPT_REDUCED_HYPHENS = 0x00040000, ///< Bit18: File name reduction Middle hyphen 0:No 1:Reduced
|
||
WINDRV_OPT_REDUCED_HYPHEN = 0x00080000, ///< Bit19: File name reduction Initial hyphen 0:No 1:Reduced
|
||
WINDRV_OPT_REDUCED_PERIODS = 0x00100000, ///< Bit20: File name reduction Middle period 0:No 1:Reduced
|
||
WINDRV_OPT_REDUCED_PERIOD = 0x00200000, ///< Bit21: File name reduction Initial period 0:No 1:Reduced
|
||
// Bit24~30 Duplicate file identification mark 0:Automatic 1~127:Chars
|
||
};
|
||
|
||
/// ファイルシステム動作フラグ
|
||
/**
|
||
通常は0にする。リードオンリーでマウントしたいドライブの場合は1にする。
|
||
それ以外の値は将来のための予約とする。
|
||
判定が困難なデバイス(自作USBストレージとか)のための保険用。
|
||
*/
|
||
enum {
|
||
FSFLAG_WRITE_PROTECT = 0x00000001, ///< Bit0: 強制書き込み禁止
|
||
FSFLAG_REMOVABLE = 0x00000002, ///< Bit1: 強制リムーバブルメディア
|
||
FSFLAG_MANUAL = 0x00000004, ///< Bit2: 強制手動イジェクト
|
||
};
|
||
|
||
//===========================================================================
|
||
//
|
||
/// まるっとリングリスト
|
||
///
|
||
/// 先頭(root.next)が最も新しいオブジェクト。
|
||
/// 末尾(root.prev)が最も古い/未使用オブジェクト。
|
||
/// コード効率追求のため、delete時は必ずポインタをアップキャストすること。
|
||
//
|
||
//===========================================================================
|
||
class CRing {
|
||
public:
|
||
// 基本ファンクション
|
||
CRing() { Init(); } ///< デフォルトコンストラクタ
|
||
~CRing() { Remove(); } ///< デストラクタ final
|
||
void Init() { next = prev = this; } ///< 初期化
|
||
|
||
CRing* Next() const { return next; } ///< 次の要素を取得
|
||
CRing* Prev() const { return prev; } ///< 前の要素を取得
|
||
|
||
void Insert(CRing* pRoot)
|
||
{
|
||
// 該当オブジェクトを切り離し
|
||
ASSERT(next);
|
||
ASSERT(prev);
|
||
next->prev = prev;
|
||
prev->next = next;
|
||
// リング先頭へ挿入
|
||
ASSERT(pRoot);
|
||
ASSERT(pRoot->next);
|
||
next = pRoot->next;
|
||
prev = pRoot;
|
||
pRoot->next->prev = this;
|
||
pRoot->next = this;
|
||
}
|
||
///< オブジェクト切り離し & リング先頭へ挿入
|
||
|
||
void InsertTail(CRing* pRoot)
|
||
{
|
||
// 該当オブジェクトを切り離し
|
||
ASSERT(next);
|
||
ASSERT(prev);
|
||
next->prev = prev;
|
||
prev->next = next;
|
||
// リング末尾へ挿入
|
||
ASSERT(pRoot);
|
||
ASSERT(pRoot->prev);
|
||
next = pRoot;
|
||
prev = pRoot->prev;
|
||
pRoot->prev->next = this;
|
||
pRoot->prev = this;
|
||
}
|
||
///< オブジェクト切り離し & リング末尾へ挿入
|
||
|
||
void InsertRing(CRing* pRoot)
|
||
{
|
||
if (next == prev) return;
|
||
|
||
// リング先頭へ挿入
|
||
ASSERT(pRoot);
|
||
ASSERT(pRoot->next);
|
||
pRoot->next->prev = prev;
|
||
prev->next = pRoot->next;
|
||
pRoot->next = next;
|
||
next->prev = pRoot;
|
||
|
||
// 自分自身を空にする
|
||
next = prev = this;
|
||
}
|
||
///< 自分以外のオブジェクト切り離し & リング先頭へ挿入
|
||
|
||
void Remove()
|
||
{
|
||
// 該当オブジェクトを切り離し
|
||
ASSERT(next);
|
||
ASSERT(prev);
|
||
next->prev = prev;
|
||
prev->next = next;
|
||
// 安全のため自分自身を指しておく (何度切り離しても問題ない)
|
||
next = prev = this;
|
||
}
|
||
///< オブジェクト切り離し
|
||
|
||
private:
|
||
CRing* next; ///< 次の要素
|
||
CRing* prev; ///< 前の要素
|
||
};
|
||
|
||
//===========================================================================
|
||
//
|
||
/// ディレクトリエントリ ファイル名
|
||
//
|
||
//===========================================================================
|
||
class CHostFilename {
|
||
public:
|
||
// 基本ファンクション
|
||
CHostFilename(); ///< デフォルトコンストラクタ
|
||
static size_t Offset() { return offsetof(CHostFilename, m_szHost); } ///< オフセット位置取得
|
||
|
||
void SetHost(const TCHAR* szHost); ///< ホスト側の名称を設定
|
||
const TCHAR* GetHost() const { return m_szHost; } ///< ホスト側の名称を取得
|
||
void ConvertHuman(int nCount = -1); ///< Human68k側の名称を変換
|
||
void CopyHuman(const BYTE* szHuman); ///< Human68k側の名称を複製
|
||
BOOL isReduce() const; ///< Human68k側の名称が加工されたか調査
|
||
BOOL isCorrect() const { return m_bCorrect; } ///< Human68k側のファイル名規則に合致しているか調査
|
||
const BYTE* GetHuman() const { return m_szHuman; } ///< Human68kファイル名を取得
|
||
const BYTE* GetHumanLast() const
|
||
{ return m_pszHumanLast; } ///< Human68kファイル名を取得
|
||
const BYTE* GetHumanExt() const { return m_pszHumanExt; }///< Human68kファイル名を取得
|
||
void SetEntryName(); ///< Human68kディレクトリエントリを設定
|
||
void SetEntryAttribute(BYTE nHumanAttribute)
|
||
{ m_dirHuman.attr = nHumanAttribute; } ///< Human68kディレクトリエントリを設定
|
||
void SetEntrySize(DWORD nHumanSize)
|
||
{ m_dirHuman.size = nHumanSize; } ///< Human68kディレクトリエントリを設定
|
||
void SetEntryDate(WORD nHumanDate)
|
||
{ m_dirHuman.date = nHumanDate; } ///< Human68kディレクトリエントリを設定
|
||
void SetEntryTime(WORD nHumanTime)
|
||
{ m_dirHuman.time = nHumanTime; } ///< Human68kディレクトリエントリを設定
|
||
void SetEntryCluster(WORD nHumanCluster)
|
||
{ m_dirHuman.cluster = nHumanCluster; } ///< Human68kディレクトリエントリを設定
|
||
const Human68k::dirent_t* GetEntry() const
|
||
{ return &m_dirHuman; } ///< Human68kディレクトリエントリを取得
|
||
BOOL CheckAttribute(DWORD nHumanAttribute) const; ///< Human68kディレクトリエントリの属性判定
|
||
BOOL isSameEntry(const Human68k::dirent_t* pdirHuman) const
|
||
{ ASSERT(pdirHuman); return memcmp(&m_dirHuman, pdirHuman, sizeof(m_dirHuman)) == 0; }
|
||
///< Human68kディレクトリエントリの一致判定
|
||
|
||
// パス名操作
|
||
static const BYTE* SeparateExt(const BYTE* szHuman); ///< Human68kファイル名から拡張子を分離
|
||
|
||
private:
|
||
static BYTE* CopyName(BYTE* pWrite, const BYTE* pFirst, const BYTE* pLast);
|
||
///< Human68k側のファイル名要素をコピー
|
||
|
||
const BYTE* m_pszHumanLast; ///< 該当エントリのHuman68k内部名の終端位置
|
||
const BYTE* m_pszHumanExt; ///< 該当エントリのHuman68k内部名の拡張子位置
|
||
BOOL m_bCorrect; ///< 該当エントリのHuman68k内部名が正しければ真
|
||
BYTE m_szHuman[24]; ///< 該当エントリのHuman68k内部名
|
||
Human68k::dirent_t m_dirHuman; ///< 該当エントリのHuman68k全情報
|
||
TCHAR m_szHost[FILEPATH_MAX]; ///< 該当エントリのホスト側の名称 (可変長)
|
||
};
|
||
|
||
//===========================================================================
|
||
//
|
||
/// ディレクトリエントリ パス名
|
||
///
|
||
/// Human68k側のパス名は、必ず先頭が/で始まり、末尾が/で終わる。
|
||
/// ユニット番号は持たない。
|
||
/// 高速化のため、ホスト側の名称にはベースパス部分も含む。
|
||
//
|
||
//===========================================================================
|
||
/** @note
|
||
ほとんどのHuman68kのアプリは、ファイルの更新等によってディレクトリエ
|
||
ントリに変更が生じた際、親ディレクトリのタイムスタンプは変化しないも
|
||
のと想定して作られている。
|
||
ところがホスト側のファイルシステムでは親ディレクトリのタイムスタンプ
|
||
も変化してしまうものが主流となってしまっている。
|
||
|
||
このため、ディレクトリのコピー等において、アプリ側は正確にタイムスタ
|
||
ンプ情報などを設定しているにもかかわらず、実行結果では時刻情報が上書
|
||
きされてしまうという惨劇が起きてしまう。
|
||
|
||
そこでディレクトリキャッシュ内にFATタイムスタンプのエミュレーション
|
||
機能を実装した。ホスト側のファイルシステムの更新時にタイムスタンプ情
|
||
報を復元することでHuman68k側の期待する結果と一致させる。
|
||
*/
|
||
class CHostPath: public CRing {
|
||
/// メモリ管理用
|
||
struct ring_t {
|
||
CRing r; ///< 円環
|
||
CHostFilename f; ///< 実体
|
||
};
|
||
|
||
public:
|
||
/// 検索用バッファ
|
||
struct find_t {
|
||
DWORD count; ///< 検索実行回数 + 1 (0のときは以下の値は無効)
|
||
DWORD id; ///< 次回検索を続行するパスのエントリ識別ID
|
||
const ring_t* pos; ///< 次回検索を続行する位置 (識別ID一致時)
|
||
Human68k::dirent_t entry; ///< 次回検索を続行するエントリ内容
|
||
|
||
void Clear() { count = 0; } ///< 初期化
|
||
};
|
||
|
||
// 基本ファンクション
|
||
CHostPath(); ///< デフォルトコンストラクタ
|
||
~CHostPath(); ///< デストラクタ final
|
||
void Clean(); ///< 再利用のための初期化
|
||
|
||
void SetHuman(const BYTE* szHuman); ///< Human68k側の名称を直接指定する
|
||
void SetHost(const TCHAR* szHost); ///< ホスト側の名称を直接指定する
|
||
BOOL isSameHuman(const BYTE* szHuman) const; ///< Human68k側の名称を比較する
|
||
BOOL isSameChild(const BYTE* szHuman) const; ///< Human68k側の名称を比較する
|
||
const TCHAR* GetHost() const { return m_szHost; } ///< ホスト側の名称の獲得
|
||
const CHostFilename* FindFilename(const BYTE* szHuman, DWORD nHumanAttribute = Human68k::AT_ALL) const;
|
||
///< ファイル名を検索
|
||
const CHostFilename* FindFilenameWildcard(const BYTE* szHuman, DWORD nHumanAttribute, find_t* pFind) const;
|
||
///< ファイル名を検索 (ワイルドカード対応)
|
||
BOOL isRefresh(); ///< ファイル変更が行なわれたか確認
|
||
void Refresh(); ///< ファイル再構成
|
||
void Backup(); /// ホスト側のタイムスタンプを保存
|
||
void Restore() const; /// ホスト側のタイムスタンプを復元
|
||
void Release(); ///< 更新
|
||
|
||
// CHostEntryが利用する外部API
|
||
static void InitId() { g_nId = 0; } ///< 識別ID生成用カウンタ初期化
|
||
|
||
private:
|
||
static ring_t* Alloc(size_t nLength); ///< ファイル名領域確保
|
||
static void Free(ring_t* pRing); ///< ファイル名領域解放
|
||
static int Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFirst, const BYTE* pBufLast);
|
||
///< 文字列比較 (ワイルドカード対応)
|
||
|
||
CRing m_cRing; ///< CHostFilename連結用
|
||
time_t m_tBackup; ///< 時刻復元用
|
||
BOOL m_bRefresh; ///< 更新フラグ
|
||
DWORD m_nId; ///< 識別ID (値が変化した場合は更新を意味する)
|
||
BYTE m_szHuman[HUMAN68K_PATH_MAX]; ///< 該当エントリのHuman68k内部名
|
||
TCHAR m_szHost[FILEPATH_MAX]; ///< 該当エントリのホスト側の名称
|
||
|
||
static DWORD g_nId; ///< 識別ID生成用カウンタ
|
||
};
|
||
|
||
//===========================================================================
|
||
//
|
||
/// ファイル検索処理
|
||
///
|
||
/// Human68k側のファイル名を内部Unicodeで処理するのは正直キツい。と
|
||
/// いうわけで、全てBYTEに変換して処理する。変換処理はディレクトリエ
|
||
/// ントリキャッシュが一手に担い、WINDRV側はすべてシフトJISのみで扱
|
||
/// えるようにする。
|
||
/// また、Human68k側名称は、完全にベースパス指定から独立させる。
|
||
///
|
||
/// ファイルを扱う直前に、ディレクトリエントリのキャッシュを生成する。
|
||
/// ディレクトリエントリの生成処理は高コストのため、一度生成したエントリは
|
||
/// 可能な限り維持して使い回す。
|
||
///
|
||
/// ファイル検索は3方式。すべてCHostFiles::Find()で処理する。
|
||
/// 1. パス名のみ検索 属性はディレクトリのみ _CHKDIR _CREATE
|
||
/// 2. パス名+ファイル名+属性の検索 _OPEN
|
||
/// 3. パス名+ワイルドカード+属性の検索 _FILES _NFILES
|
||
/// 検索結果は、ディレクトリエントリ情報として保持しておく。
|
||
//
|
||
//===========================================================================
|
||
class CHostFiles {
|
||
public:
|
||
// 基本ファンクション
|
||
CHostFiles() { SetKey(0); Init(); } ///< デフォルトコンストラクタ
|
||
void Init(); ///< 初期化
|
||
|
||
void SetKey(DWORD nKey) { m_nKey = nKey; } ///< 検索キー設定
|
||
BOOL isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< 検索キー比較
|
||
void SetPath(const Human68k::namests_t* pNamests); ///< パス名・ファイル名を内部で生成
|
||
BOOL isRootPath() const { return m_szHumanPath[1] == '\0'; } ///< ルートディレクトリ判定
|
||
void SetPathWildcard() { m_nHumanWildcard = 1; } ///< ワイルドカードによるファイル検索を有効化
|
||
void SetPathOnly() { m_nHumanWildcard = 0xFF; } ///< パス名のみを有効化
|
||
BOOL isPathOnly() const { return m_nHumanWildcard == 0xFF; } ///< パス名のみ設定か判定
|
||
void SetAttribute(DWORD nHumanAttribute) { m_nHumanAttribute = nHumanAttribute; }
|
||
///< 検索属性を設定
|
||
BOOL Find(DWORD nUnit, class CHostEntry* pEntry); ///< Human68k側でファイルを検索しホスト側の情報を生成
|
||
const CHostFilename* Find(CHostPath* pPath); ///< ファイル名検索
|
||
void SetEntry(const CHostFilename* pFilename); ///< Human68k側の検索結果保存
|
||
void SetResult(const TCHAR* szPath); ///< ホスト側の名称を設定
|
||
void AddResult(const TCHAR* szPath); ///< ホスト側の名称にファイル名を追加
|
||
void AddFilename(); ///< ホスト側の名称にHuman68kの新規ファイル名を追加
|
||
|
||
const TCHAR* GetPath() const { return m_szHostResult; } ///< ホスト側の名称を取得
|
||
|
||
const Human68k::dirent_t* GetEntry() const { return &m_dirHuman; }///< Human68kディレクトリエントリを取得
|
||
|
||
DWORD GetAttribute() const { return m_dirHuman.attr; } ///< Human68k属性を取得
|
||
WORD GetDate() const { return m_dirHuman.date; } ///< Human68k日付を取得
|
||
WORD GetTime() const { return m_dirHuman.time; } ///< Human68k時刻を取得
|
||
DWORD GetSize() const { return m_dirHuman.size; } ///< Human68kファイルサイズを取得
|
||
const BYTE* GetHumanFilename() const { return m_szHumanFilename; }///< Human68kファイル名を取得
|
||
const BYTE* GetHumanResult() const { return m_szHumanResult; } ///< Human68kファイル名検索結果を取得
|
||
const BYTE* GetHumanPath() const { return m_szHumanPath; } ///< Human68kパス名を取得
|
||
|
||
private:
|
||
DWORD m_nKey; ///< Human68kのFILESバッファアドレス 0なら未使用
|
||
DWORD m_nHumanWildcard; ///< Human68kのワイルドカード情報
|
||
DWORD m_nHumanAttribute; ///< Human68kの検索属性
|
||
CHostPath::find_t m_findNext; ///< 次回検索位置情報
|
||
Human68k::dirent_t m_dirHuman; ///< 検索結果 Human68kファイル情報
|
||
BYTE m_szHumanFilename[24]; ///< Human68kのファイル名
|
||
BYTE m_szHumanResult[24]; ///< 検索結果 Human68kファイル名
|
||
BYTE m_szHumanPath[HUMAN68K_PATH_MAX];
|
||
///< Human68kのパス名
|
||
TCHAR m_szHostResult[FILEPATH_MAX]; ///< 検索結果 ホスト側のフルパス名
|
||
};
|
||
|
||
//===========================================================================
|
||
//
|
||
/// ファイル検索領域 マネージャ
|
||
//
|
||
//===========================================================================
|
||
class CHostFilesManager {
|
||
public:
|
||
#ifdef _DEBUG
|
||
// 基本ファンクション
|
||
~CHostFilesManager(); ///< デストラクタ final
|
||
#endif // _DEBUG
|
||
void Init(); ///< 初期化 (ドライバ組込み時)
|
||
void Clean(); ///< 解放 (起動・リセット時)
|
||
|
||
CHostFiles* Alloc(DWORD nKey); ///< 確保
|
||
CHostFiles* Search(DWORD nKey); ///< 検索
|
||
void Free(CHostFiles* pFiles); ///< 解放
|
||
private:
|
||
/// メモリ管理用
|
||
struct ring_t {
|
||
CRing r; ///< 円環
|
||
CHostFiles f; ///< 実体
|
||
};
|
||
|
||
CRing m_cRing; ///< CHostFiles連結用
|
||
};
|
||
|
||
//===========================================================================
|
||
//
|
||
/// FCB処理
|
||
//
|
||
//===========================================================================
|
||
class CHostFcb {
|
||
public:
|
||
// 基本ファンクション
|
||
CHostFcb() { SetKey(0); Init(); } ///< デフォルトコンストラクタ
|
||
~CHostFcb() { Close(); } ///< デストラクタ final
|
||
void Init(); ///< 初期化
|
||
|
||
void SetKey(DWORD nKey) { m_nKey = nKey; } ///< 検索キー設定
|
||
BOOL isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< 検索キー比較
|
||
void SetUpdate() { m_bUpdate = TRUE; } ///< 更新
|
||
BOOL isUpdate() const { return m_bUpdate; } ///< 更新状態取得
|
||
BOOL SetMode(DWORD nHumanMode); ///< ファイルオープンモードを設定
|
||
void SetFilename(const TCHAR* szFilename); ///< ファイル名を設定
|
||
void SetHumanPath(const BYTE* szHumanPath); ///< Human68kパス名を設定
|
||
const BYTE* GetHumanPath() const { return m_szHumanPath; } ///< Human68kパス名を取得
|
||
|
||
BOOL Create(Human68k::fcb_t* pFcb, DWORD nHumanAttribute, BOOL bForce); ///< ファイル作成
|
||
BOOL Open(); ///< ファイルオープン
|
||
BOOL Rewind(DWORD nOffset); ///< ファイルシーク
|
||
DWORD Read(BYTE* pBuffer, DWORD nSize); ///< ファイル読み込み
|
||
DWORD Write(const BYTE* pBuffer, DWORD nSize); ///< ファイル書き込み
|
||
BOOL Truncate(); ///< ファイル切り詰め
|
||
DWORD Seek(DWORD nOffset, DWORD nHumanSeek); ///< ファイルシーク
|
||
BOOL TimeStamp(DWORD nHumanTime); ///< ファイル時刻設定
|
||
BOOL Close(); ///< ファイルクローズ
|
||
|
||
private:
|
||
DWORD m_nKey; ///< Human68kのFCBバッファアドレス (0なら未使用)
|
||
BOOL m_bUpdate; ///< 更新フラグ
|
||
FILE* m_pFile; ///< ホスト側のファイルオブジェクト
|
||
const char* m_pszMode; ///< ホスト側のファイルオープンモード
|
||
bool m_bFlag; ///< ホスト側のファイルオープンフラグ
|
||
BYTE m_szHumanPath[HUMAN68K_PATH_MAX];
|
||
///< Human68kのパス名
|
||
TCHAR m_szFilename[FILEPATH_MAX]; ///< ホスト側のファイル名
|
||
};
|
||
|
||
//===========================================================================
|
||
//
|
||
/// FCB処理 マネージャ
|
||
//
|
||
//===========================================================================
|
||
class CHostFcbManager {
|
||
public:
|
||
#ifdef _DEBUG
|
||
// 基本ファンクション
|
||
~CHostFcbManager(); ///< デストラクタ final
|
||
#endif // _DEBUG
|
||
void Init(); ///< 初期化 (ドライバ組込み時)
|
||
void Clean(); ///< 解放 (起動・リセット時)
|
||
|
||
CHostFcb* Alloc(DWORD nKey); ///< 確保
|
||
CHostFcb* Search(DWORD nKey); ///< 検索
|
||
void Free(CHostFcb* p); ///< 解放
|
||
|
||
private:
|
||
/// メモリ管理用
|
||
struct ring_t {
|
||
CRing r; ///< 円環
|
||
CHostFcb f; ///< 実体
|
||
};
|
||
|
||
CRing m_cRing; ///< CHostFcb連結用
|
||
};
|
||
|
||
//===========================================================================
|
||
//
|
||
/// ホスト側ドライブ
|
||
///
|
||
/// ドライブ毎に必要な情報の保持に専念し、管理はCHostEntryで行なう。
|
||
//
|
||
//===========================================================================
|
||
class CHostDrv
|
||
{
|
||
public:
|
||
// 基本ファンクション
|
||
CHostDrv(); ///< デフォルトコンストラクタ
|
||
~CHostDrv(); ///< デストラクタ final
|
||
void Init(const TCHAR* szBase, DWORD nFlag); ///< 初期化 (デバイス起動とロード)
|
||
|
||
BOOL isWriteProtect() const { return m_bWriteProtect; } ///< 書き込み禁止か?
|
||
BOOL isEnable() const { return m_bEnable; } ///< アクセス可能か?
|
||
BOOL isMediaOffline(); ///< メディアチェック
|
||
BYTE GetMediaByte() const; ///< メディアバイトの取得
|
||
DWORD GetStatus() const; ///< ドライブ状態の取得
|
||
void SetEnable(BOOL bEnable); ///< メディア状態設定
|
||
BOOL CheckMedia(); ///< メディア交換チェック
|
||
void Update(); ///< メディア状態更新
|
||
void Eject(); ///< イジェクト
|
||
void GetVolume(TCHAR* szLabel); ///< ボリュームラベルの取得
|
||
BOOL GetVolumeCache(TCHAR* szLabel) const; ///< キャッシュからボリュームラベルを取得
|
||
DWORD GetCapacity(Human68k::capacity_t* pCapacity); ///< 容量の取得
|
||
BOOL GetCapacityCache(Human68k::capacity_t* pCapacity) const; ///< キャッシュから容量を取得
|
||
|
||
// キャッシュ操作
|
||
void CleanCache(); ///< 全てのキャッシュを更新する
|
||
void CleanCache(const BYTE* szHumanPath); ///< 指定されたパスのキャッシュを更新する
|
||
void CleanCacheChild(const BYTE* szHumanPath); ///< 指定されたパス以下のキャッシュを全て更新する
|
||
void DeleteCache(const BYTE* szHumanPath); ///< 指定されたパスのキャッシュを削除する
|
||
CHostPath* FindCache(const BYTE* szHuman); ///< 指定されたパスがキャッシュされているか検索する
|
||
CHostPath* CopyCache(CHostFiles* pFiles); ///< キャッシュ情報を元に、ホスト側の名称を獲得する
|
||
CHostPath* MakeCache(CHostFiles* pFiles); ///< ホスト側の名称の構築に必要な情報をすべて取得する
|
||
BOOL Find(CHostFiles* pFiles); ///< ホスト側の名称を検索 (パス名+ファイル名(省略可)+属性)
|
||
|
||
private:
|
||
// パス名操作
|
||
static const BYTE* SeparateCopyFilename(const BYTE* szHuman, BYTE* szBuffer);
|
||
///< Human68kフルパス名から先頭の要素を分離・コピー
|
||
|
||
// 排他制御
|
||
void Lock() {}
|
||
void Unlock() {}
|
||
|
||
/// メモリ管理用
|
||
struct ring_t {
|
||
CRing r; ///< 円環
|
||
CHostPath f; ///< 実体
|
||
};
|
||
|
||
BOOL m_bWriteProtect; ///< 書き込み禁止ならTRUE
|
||
BOOL m_bEnable; ///< メディアが利用可能ならTRUE
|
||
DWORD m_nRing; ///< パス名保持数
|
||
CRing m_cRing; ///< CHostPath連結用
|
||
Human68k::capacity_t m_capCache; ///< セクタ情報キャッシュ sectors == 0 なら未キャッシュ
|
||
BOOL m_bVolumeCache; ///< ボリュームラベル読み込み済みならTRUE
|
||
TCHAR m_szVolumeCache[24]; ///< ボリュームラベルキャッシュ
|
||
TCHAR m_szBase[FILEPATH_MAX]; ///< ベースパス
|
||
};
|
||
|
||
//===========================================================================
|
||
//
|
||
/// ディレクトリエントリ管理
|
||
//
|
||
//===========================================================================
|
||
class CHostEntry {
|
||
public:
|
||
// 基本ファンクション
|
||
CHostEntry(); ///< デフォルトコンストラクタ
|
||
~CHostEntry(); ///< デストラクタ final
|
||
void Init(); ///< 初期化 (ドライバ組込み時)
|
||
void Clean(); ///< 解放 (起動・リセット時)
|
||
|
||
// キャッシュ操作
|
||
void CleanCache(); ///< 全てのキャッシュを更新する
|
||
void CleanCache(DWORD nUnit); ///< 指定されたユニットのキャッシュを更新する
|
||
void CleanCache(DWORD nUnit, const BYTE* szHumanPath); ///< 指定されたパスのキャッシュを更新する
|
||
void CleanCacheChild(DWORD nUnit, const BYTE* szHumanPath); ///< 指定されたパス以下のキャッシュを全て更新する
|
||
void DeleteCache(DWORD nUnit, const BYTE* szHumanPath); ///< 指定されたパスのキャッシュを削除する
|
||
BOOL Find(DWORD nUnit, CHostFiles* pFiles); ///< ホスト側の名称を検索 (パス名+ファイル名(省略可)+属性)
|
||
void ShellNotify(DWORD nEvent, const TCHAR* szPath); ///< ホスト側ファイルシステム状態変化通知
|
||
|
||
// ドライブオブジェクト操作
|
||
void SetDrv(DWORD nUnit, CHostDrv* pDrv); ///< ドライブ設定
|
||
BOOL isWriteProtect(DWORD nUnit) const; ///< 書き込み禁止か?
|
||
BOOL isEnable(DWORD nUnit) const; ///< アクセス可能か?
|
||
BOOL isMediaOffline(DWORD nUnit); ///< メディアチェック
|
||
BYTE GetMediaByte(DWORD nUnit) const; ///< メディアバイトの取得
|
||
DWORD GetStatus(DWORD nUnit) const; ///< ドライブ状態の取得
|
||
BOOL CheckMedia(DWORD nUnit); ///< メディア交換チェック
|
||
void Eject(DWORD nUnit); ///< イジェクト
|
||
void GetVolume(DWORD nUnit, TCHAR* szLabel); ///< ボリュームラベルの取得
|
||
BOOL GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const; ///< キャッシュからボリュームラベルを取得
|
||
DWORD GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity); ///< 容量の取得
|
||
BOOL GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity) const;
|
||
///< キャッシュからクラスタサイズを取得
|
||
|
||
/// 定数
|
||
enum {
|
||
DriveMax = 10 ///< ドライブ最大候補数
|
||
};
|
||
|
||
private:
|
||
CHostDrv* m_pDrv[DriveMax]; ///< ホスト側ドライブオブジェクト
|
||
DWORD m_nTimeout; ///< 最後にタイムアウトチェックを行なった時刻
|
||
};
|
||
|
||
//===========================================================================
|
||
//
|
||
/// ホスト側ファイルシステム
|
||
//
|
||
//===========================================================================
|
||
/** @note
|
||
現在の見解。
|
||
|
||
XM6の設計思想とは反するが、class Windrvまたはclass CWindrvに直接
|
||
class CFileSysへのポインタを持たせる方法を模索するべきである。
|
||
これにより、以下のメリットが得られる。
|
||
|
||
メリットその1。
|
||
コマンドハンドラの大量のメソッド群を一ヶ所で集中管理できる。
|
||
コマンドハンドラはホスト側の仕様変更などの要因によって激しく変化する
|
||
可能性が高いため、メソッドの追加削除や引数の変更などのメンテナンスが
|
||
大幅に楽になる。
|
||
|
||
メリットその2。
|
||
仮想関数のテーブル生成・参照処理に関する処理コードを駆逐できる。
|
||
XM6では複数のファイルシステムオブジェクトを同時に使うような実装は
|
||
ありえない。つまりファイルシステムオブジェクトにポリモーフィズムは
|
||
まったく必要ないどころか、ただクロックの無駄となっているだけである。
|
||
|
||
試しに変えてみた。実際効率上がった。
|
||
windrv.h内のFILESYS_FAST_STRUCTUREの値を変えてコンパイラの吐くソース
|
||
を比較すれば一目瞭然。何故私がこんな長文を書こうと思ったのかを理解で
|
||
きるはず。
|
||
|
||
一方ロシアはclass CWindrv内にclass CFileSysを直接設置した。
|
||
(本当はclass CHostを廃止して直接置きたい……良い方法はないものか……)
|
||
*/
|
||
class CFileSys
|
||
{
|
||
public:
|
||
// 基本ファンクション
|
||
CFileSys(); ///< デフォルトコンストラクタ
|
||
virtual ~CFileSys() {}; ///< デストラクタ
|
||
|
||
// 初期化・終了
|
||
void Reset(); ///< リセット (全クローズ)
|
||
void Init(); ///< 初期化 (デバイス起動とロード)
|
||
|
||
// コマンドハンドラ
|
||
DWORD InitDevice(const Human68k::argument_t* pArgument); ///< $40 - デバイス起動
|
||
int CheckDir(DWORD nUnit, const Human68k::namests_t* pNamests); ///< $41 - ディレクトリチェック
|
||
int MakeDir(DWORD nUnit, const Human68k::namests_t* pNamests); ///< $42 - ディレクトリ作成
|
||
int RemoveDir(DWORD nUnit, const Human68k::namests_t* pNamests); ///< $43 - ディレクトリ削除
|
||
int Rename(DWORD nUnit, const Human68k::namests_t* pNamests, const Human68k::namests_t* pNamestsNew);
|
||
///< $44 - ファイル名変更
|
||
int Delete(DWORD nUnit, const Human68k::namests_t* pNamests); ///< $45 - ファイル削除
|
||
int Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD nHumanAttribute);
|
||
///< $46 - ファイル属性取得/設定
|
||
int Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::files_t* pFiles);
|
||
///< $47 - ファイル検索
|
||
int NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles); ///< $48 - ファイル次検索
|
||
int Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, DWORD nHumanAttribute, BOOL bForce);
|
||
///< $49 - ファイル作成
|
||
int Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb);
|
||
///< $4A - ファイルオープン
|
||
int Close(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb); ///< $4B - ファイルクローズ
|
||
int Read(DWORD nKey, Human68k::fcb_t* pFcb, BYTE* pAddress, DWORD nSize);
|
||
///< $4C - ファイル読み込み
|
||
int Write(DWORD nKey, Human68k::fcb_t* pFcb, const BYTE* pAddress, DWORD nSize);
|
||
///< $4D - ファイル書き込み
|
||
int Seek(DWORD nKey, Human68k::fcb_t* pFcb, DWORD nSeek, int nOffset); ///< $4E - ファイルシーク
|
||
DWORD TimeStamp(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb, DWORD nHumanTime);
|
||
///< $4F - ファイル時刻取得/設定
|
||
int GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity); ///< $50 - 容量取得
|
||
int CtrlDrive(DWORD nUnit, Human68k::ctrldrive_t* pCtrlDrive); ///< $51 - ドライブ状態検査/制御
|
||
int GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb); ///< $52 - DPB取得
|
||
int DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize); ///< $53 - セクタ読み込み
|
||
int DiskWrite(DWORD nUnit); ///< $54 - セクタ書き込み
|
||
int Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl); ///< $55 - IOCTRL
|
||
int Flush(DWORD nUnit); ///< $56 - フラッシュ
|
||
int CheckMedia(DWORD nUnit); ///< $57 - メディア交換チェック
|
||
int Lock(DWORD nUnit); ///< $58 - 排他制御
|
||
|
||
void SetOption(DWORD nOption); ///< オプション設定
|
||
DWORD GetOption() const { return m_nOption; } ///< オプション取得
|
||
DWORD GetDefault() const { return m_nOptionDefault; } ///< デフォルトオプション取得
|
||
static DWORD GetFileOption() { return g_nOption; } ///< ファイル名変換オプション取得
|
||
void ShellNotify(DWORD nEvent, const TCHAR* szPath)
|
||
{ m_cEntry.ShellNotify(nEvent, szPath); } ///< ホスト側ファイルシステム状態変化通知
|
||
|
||
/// 定数
|
||
enum {
|
||
DriveMax = CHostEntry::DriveMax ///< ドライブ最大候補数
|
||
};
|
||
|
||
private:
|
||
// 内部補助用
|
||
void InitOption(const Human68k::argument_t* pArgument); ///< オプション初期化
|
||
BOOL FilesVolume(DWORD nUnit, Human68k::files_t* pFiles); ///< ボリュームラベル取得
|
||
|
||
DWORD m_nUnits; ///< 現在のドライブオブジェクト数 (レジューム毎に変化)
|
||
|
||
DWORD m_nOption; ///< 現在の動作フラグ
|
||
DWORD m_nOptionDefault; ///< リセット時の動作フラグ
|
||
|
||
DWORD m_nDrives; ///< ベースパス状態復元用の候補数 (0なら毎回スキャン)
|
||
|
||
DWORD m_nKernel; ///< カーネルチェック用カウンタ
|
||
DWORD m_nKernelSearch; ///< NULデバイスの先頭アドレス
|
||
|
||
DWORD m_nHostSectorCount; ///< 擬似セクタ番号
|
||
|
||
CHostFilesManager m_cFiles; ///< ファイル検索領域
|
||
CHostFcbManager m_cFcb; ///< FCB操作領域
|
||
CHostEntry m_cEntry; ///< ドライブオブジェクトとディレクトリエントリ
|
||
|
||
DWORD m_nHostSectorBuffer[XM6_HOST_PSEUDO_CLUSTER_MAX];
|
||
///< 擬似セクタの指すファイル実体
|
||
|
||
DWORD m_nFlag[DriveMax]; ///< ベースパス状態復元用の動作フラグ候補
|
||
TCHAR m_szBase[DriveMax][FILEPATH_MAX]; ///< ベースパス状態復元用の候補
|
||
static DWORD g_nOption; ///< ファイル名変換フラグ
|
||
};
|