From 8a3642bf9a420be8df8bb0fb9d1c55e9dbe21785 Mon Sep 17 00:00:00 2001
From: Daniel Markstedt
Date: Tue, 14 Sep 2021 19:51:12 -0700
Subject: [PATCH] Move to protobuf for the webapp, major overhaul to
easyinstall.sh, code comment translations (#229)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Making saving and loading config files work with protobuf
* Formatted the Status column, and fixed the available ID logic
* Updated handling of removed status for devices without image file support
* Comment update
* Fixed typo
* Updated logging
* Updated handling of removed status for devices without image file support
* Comment update
* Fixed typo
* Updated logging
* Better handling of device status
* Updated parameter handling
* Updated setting default interfaces
* Revert "Updated setting default interfaces"
This reverts commit 210abc775d9a79dd0c631cf3877966a2923f4d5b.
* Revert "Updated parameter handling"
This reverts commit 35302addd59f5f5e1cc032888ba32dcbb426a846.
* Abort with a 404 if rascsi is not running. Use any protobuf response to determine whether rascsi is running (should hardly be required anymore due to the other change, but just in case).
* Move id reservation back into __main__
* Remove check for device type when validating Removed image
* Leverage device property data for better status messages
* Remove redundant string sanitation when reading config csv file
* Clean up device list generation
* Cleanup
* Remove duplicates before building valid scsi id list
* Fully translated cfilesystem.h code comments to English; partially translated cfilesystem.cpp
* rascsi supports reserving IDs
* Updated help message
* Replaced BOOL by bool
* Logging update
* Logging update
* Cleanup
* Restructure the easyinstall.sh script to combine the install/update flows, and disallow installing the webapp by itself
* Remove redundant steps handled in Makefile
* Add the functionality to specify connect_type through a parameter
* Add validation to the argument parser allowing only STANDARD and FULLSPEC as options
* Complete translation of code comments for cfilesystem.h; partial translation for cfilesystem.cpp
* Cleanup
* Merge parts of the Network Assistant script by sonique6784; fix the run_choice startup parameter
* Improve on the network setup messages
* Fix routing address
* Add checks for previous configuration; cleanup
* Cleanup
* Remove redundant step in wired setup. Improve messages.
* Cleanup
* Added default parameters to device properties
* Return parameters a device was set up with
* Add flows for configuring custom network settings; adopting some logic by sonique6784
* Improved device initialization
* Updated default parameter handling
* Updated default parameter handling
* Fixed typo
* Comment updates
* Comment update
* Make iso generation work again, and add error handling to urllib actions
* Manage default parameters in the respective device
* Print available network interfaces. Clean up step and improve descriptive messages.
* Make the script clean up previous configurations
* Make the script only show relevant interfaces
* Partial translation of cfilesystem.cpp
* Do not pass empty parameter string
* Added supports_params flag
* Completely translate code comments in cfilesystem.cpp
* Show rascsi-web status after installing
* Refactoring
* Made comparisons more consistent
* Updated error handling
* Updated exception handling
* Made comparisons more consistent
* Updated error handling
* Overlooked code comment translation
* Renaming
* Better error handling for socket connection
* Disable two NEC hd image types due to issue#232
* Comment update
* NEC sectors size must be 512 bytes
* Updated logging
* Updated vendor name handling
* Updated handling of media loading/unloading
* Comment update
* NEC sectors size must be 512 bytes
* Updated logging
* Updated vendor name handling
* Updated handling of media loading/unloading
* Better handling of removable disks in the web ui
* Added stoppable property and stopped status
* Made MO stoppable
* Removed duplicate code
* Removed duplicate code
* Copy read-only property
* Renaming
* Add an assistant for reserving scsi ids
* Don't show action if no device attached
* Implement a device_info app path, and cut down on device columns always shown
* Cleanup
* 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
* 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
* Fast forward instead of rebase existing git repo
* Fixed ctapdriver initialization issue
* Reset read-only status when opening an image file
* Cleanup
* Cleanup
* Made logging more consistent
* Updated log level
* Cleanup
* Log load/eject on error level for testing
* Revert "Log load/eject on error level for testing"
This reverts commit d35a15ea8e520517d25e1e1054ad1aeda9f85f2e.
* Assume drive is not ready after having been stopped
* Updated status handling
* Make the csv config files store all relevant device data for reading
* Read 9 column csv config files
* 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
* Better error handling for csv reading and writing
* 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 commit 39ca12d8b153c706316ce79f4fec65c9abc60024.
* Comment update
* Removed duplicate code
* Updated error messages, use more foreach loops
* Avoid storing RaSCSI generated product info in config file
* Updated logging
* Logging update
* Save config files in json instead of csv
* Fix bugs with json config loading
* Refactoring & remove unused code
* Refactoring
* Display upper case file endings in file management list
* Only show product vendor for non-RaSCSI devices in the device list
* Translate code comment
* Refactoring
* Fix bad identation
* Improve valid file extension handling
* Add validation when attaching removable media
* Display valid file endings under the file list
* Cleanup
* Don't store 0 block size
* Fix indentation
* Read and write config files in key:pair format
* Add section for controlling logging
* README update
* Added block_count
* Cleanup, fix typos
* Support attaching CD-ROM with custom block size
* Evaluate block size when inserting a media
* rasctl display capacity if available
* Info message update
* Use kwargs for device attachment
* Fix bugs in attach_image kwargs; make config file more readable
* POC for attaching device with profile
* Only list product types valid for the particular image file
* Perform validation of HDD image size based on the product profile
* Implement sidecar config files for drive images.
* Added missing product name to NEC vital product data
* MO block size depends on capacity only
* Better error handling for device sidecar config loading
* Extended property/status display
* Property display update
* Updated error handling
* Handle image sizes in bytes internally
* Revert change
* Resolve bad merge
Co-authored-by: Uwe Seimet
---
.gitignore | 1 +
easyinstall.sh | 396 +++++--
src/raspberrypi/devices/cfilesystem.cpp | 1426 +++++++++++------------
src/raspberrypi/devices/cfilesystem.h | 714 ++++++------
src/raspberrypi/fileio.cpp | 2 +-
src/web/file_cmds.py | 161 ++-
src/web/pi_cmds.py | 9 +
src/web/ractl_cmds.py | 408 +++++--
src/web/requirements.txt | 1 +
src/web/settings.py | 16 +-
src/web/static/style.css | 7 +-
src/web/templates/index.html | 122 +-
src/web/web.py | 273 +++--
13 files changed, 1999 insertions(+), 1537 deletions(-)
diff --git a/.gitignore b/.gitignore
index 69e06bf4..3e78e42d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ core
*.swp
__pycache__
src/web/current
+src/web/rascsi_interface_pb2.py
src/oled_monitor/current
src/raspberrypi/hfdisk/
*~
diff --git a/easyinstall.sh b/easyinstall.sh
index d9cc1505..012d7bf6 100755
--- a/easyinstall.sh
+++ b/easyinstall.sh
@@ -20,6 +20,32 @@ logo="""
echo -e $logo
}
+function showMacNetworkWired(){
+logo="""
+ .-~-.-~~~-.~-.\n
+ ╔═══════╗ .( )\n
+ ║|¯¯¯¯¯|║ / \`.\n
+ ║|_____|║>--------------<~ . )\n
+ ║ . __ ║ ( :'-'\n
+ ╚╦═════╦╝ ~-.________.:'\n
+ ¯¯¯¯¯¯¯\n
+"""
+echo -e $logo
+}
+
+function showMacNetworkWireless(){
+logo="""
+ .-~-.-~~~-.~-.\n
+ ╔═══════╗ .( .( )\n
+ ║|¯¯¯¯¯|║ .( .( / \`.\n
+ ║|_____|║ .o o ~ . )\n
+ ║ . __ ║ '( '( ( :'-'\n
+ ╚╦═════╦╝ '( ~-.________.:'\n
+ ¯¯¯¯¯¯¯\n
+"""
+echo -e $logo
+}
+
VIRTUAL_DRIVER_PATH=/home/pi/images
HFS_FORMAT=/usr/bin/hformat
HFDISK_BIN=/usr/bin/hfdisk
@@ -41,18 +67,19 @@ function initialChecks() {
fi
}
+# install all dependency packages for RaSCSI Service
function installPackages() {
sudo apt-get update && sudo apt install git libspdlog-dev libpcap-dev genisoimage python3 python3-venv nginx libpcap-dev protobuf-compiler bridge-utils python3-dev libev-dev libevdev2 -y
}
-# install all dependency packages for RaSCSI Service
# compile and install RaSCSI Service
function installRaScsi() {
- installPackages
+ sudo systemctl stop rascsi
cd ~/RASCSI/src/raspberrypi
- make all CONNECT_TYPE=FULLSPEC
- sudo make install CONNECT_TYPE=FULLSPEC
+ make clean
+ make all CONNECT_TYPE=${CONNECT_TYPE-FULLSPEC}
+ sudo make install CONNECT_TYPE=${CONNECT_TYPE-FULLSPEC}
sudoIsReady=$(sudo grep -c "rascsi" /etc/sudoers)
@@ -71,7 +98,39 @@ www-data ALL=NOPASSWD: /sbin/shutdown, /sbin/reboot
sudo systemctl start rascsi
}
+# install everything required to run an HTTP server (Nginx + Python Flask App)
+function installRaScsiWebInterface() {
+ echo "Compiling the Python protobuf library..."
+ [ -f ~/RASCSI/src/web/rascsi_interface.proto ] && rm ~/RASCSI/src/web/rascsi_interface.proto
+ protoc -I=/home/pi/RASCSI/src/raspberrypi/ --python_out=/home/pi/RASCSI/src/web/ rascsi_interface.proto
+
+ sudo cp -f ~/RASCSI/src/web/service-infra/nginx-default.conf /etc/nginx/sites-available/default
+ sudo cp -f ~/RASCSI/src/web/service-infra/502.html /var/www/html/502.html
+
+ sudo usermod -a -G pi www-data
+
+ sudo systemctl reload nginx
+
+ echo "Installing the rascsi-web.service configuration..."
+ sudo cp ~/RASCSI/src/web/service-infra/rascsi-web.service /etc/systemd/system/rascsi-web.service
+
+ sudo systemctl daemon-reload
+ sudo systemctl enable rascsi-web
+ sudo systemctl start rascsi-web
+}
+
+function createImagesDir() {
+ if [ -d $VIRTUAL_DRIVER_PATH ]; then
+ echo "The $VIRTUAL_DRIVER_PATH directory already exists."
+ else
+ echo "The $VIRTUAL_DRIVER_PATH directory does not exist; creating..."
+ mkdir -p $VIRTUAL_DRIVER_PATH
+ chmod -R 775 $VIRTUAL_DRIVER_PATH
+ fi
+}
+
function stopOldWebInterface() {
+ sudo systemctl stop rascsi-web
APACHE_STATUS=$(sudo systemctl status apache2 &> /dev/null; echo $?)
if [ "$APACHE_STATUS" -eq 0 ] ; then
echo "Stopping old Apache2 RaSCSI Web..."
@@ -80,28 +139,6 @@ function stopOldWebInterface() {
fi
}
-# install everything required to run an HTTP server (Nginx + Python Flask App)
-function installRaScsiWebInterface() {
- stopOldWebInterface
- installPackages
-
- sudo cp -f ~/RASCSI/src/web/service-infra/nginx-default.conf /etc/nginx/sites-available/default
- sudo cp -f ~/RASCSI/src/web/service-infra/502.html /var/www/html/502.html
-
- mkdir -p $VIRTUAL_DRIVER_PATH
- chmod -R 775 $VIRTUAL_DRIVER_PATH
- groups www-data
- sudo usermod -a -G pi www-data
- groups www-data
-
- sudo systemctl reload nginx
-
- sudo cp ~/RASCSI/src/web/service-infra/rascsi-web.service /etc/systemd/system/rascsi-web.service
- sudo systemctl daemon-reload
- sudo systemctl enable rascsi-web
- sudo systemctl start rascsi-web
-}
-
function updateRaScsiGit() {
echo "Updating checked out branch $GIT_REMOTE/$GIT_BRANCH"
cd ~/RASCSI
@@ -112,8 +149,7 @@ function updateRaScsiGit() {
stashed=1
fi
- git fetch $GIT_REMOTE
- git rebase $GIT_REMOTE/$GIT_BRANCH
+ git pull --ff-only
if [ $stashed -eq 1 ]; then
echo "Reapplying local changes..."
@@ -121,33 +157,14 @@ function updateRaScsiGit() {
fi
}
-function updateRaScsi() {
- updateRaScsiGit
- installPackages
- sudo systemctl stop rascsi
-
- cd ~/RASCSI/src/raspberrypi
-
- make clean
- make all CONNECT_TYPE=FULLSPEC
- sudo make install CONNECT_TYPE=FULLSPEC
- sudo systemctl start rascsi
-}
-
-function updateRaScsiWebInterface() {
- stopOldWebInterface
- updateRaScsiGit
- sudo cp -f ~/RASCSI/src/web/service-infra/nginx-default.conf /etc/nginx/sites-available/default
- sudo cp -f ~/RASCSI/src/web/service-infra/502.html /var/www/html/502.html
- echo "Restarting rascsi-web services..."
- sudo systemctl restart rascsi-web
- sudo systemctl restart nginx
-}
-
function showRaScsiStatus() {
sudo systemctl status rascsi | tee
}
+function showRaScsiWebStatus() {
+ sudo systemctl status rascsi-web | tee
+}
+
function createDrive600MB() {
createDrive 600 "HD600"
}
@@ -184,6 +201,22 @@ function formatDrive() {
fi
# Inject hfdisk commands to create Drive with correct partitions
+ # https://www.codesrc.com/mediawiki/index.php/HFSFromScratch
+ # i initialize partition map
+ # continue with default first block
+ # C Create 1st partition with type specified next)
+ # continue with default
+ # 32 32 blocks (required for HFS+)
+ # Driver_Partition Partition Name
+ # Apple_Driver Partition Type (available types: Apple_Driver, Apple_Driver43, Apple_Free, Apple_HFS...)
+ # C Create 2nd partition with type specified next
+ # continue with default first block
+ # continue with default block size (rest of the disk)
+ # ${volumeName} Partition name provided by user
+ # Apple_HFS Partition Type
+ # w Write partition map to disk
+ # y Confirm partition table
+ # p Print partition map
(echo i; echo ; echo C; echo ; echo 32; echo "Driver_Partition"; echo "Apple_Driver"; echo C; echo ; echo ; echo "${volumeName}"; echo "Apple_HFS"; echo w; echo y; echo p;) | $HFDISK_BIN "$diskPath"
partitionOk=$?
@@ -242,55 +275,208 @@ function createDrive() {
fi
}
+function setupWiredNetworking() {
+ echo "Setting up wired network..."
+
+ LAN_INTERFACE=eth0
+
+ echo "$LAN_INTERFACE will be configured for network forwarding with DHCP."
+ echo ""
+ echo "WARNING: If you continue, the IP address of your Pi may change upon reboot."
+ echo "Please make sure you will not lose access to the Pi system."
+ echo ""
+ echo "Do you want to proceed with network configuration using the default settings? Y/n"
+ read REPLY
+
+ if [ "$REPLY" == "N" ] || [ "$REPLY" == "n" ]; then
+ echo "Available wired interfaces on this system:"
+ ip -o addr show scope link | awk '{split($0, a); print $2}' | grep eth
+ echo "Please type the wired interface you want to use and press Enter:"
+ read -r SELECTED
+ LAN_INTERFACE=$SELECTED
+ fi
+
+ if [ $(grep -c "^denyinterfaces" /etc/dhcpcd.conf) -ge 1 ]; then
+ echo "WARNING: Network forwarding may already have been configured. Proceeding will overwrite the configuration."
+ echo "Press enter to continue or CTRL-C to exit"
+ read REPLY
+ sudo sed -i /^denyinterfaces/d /etc/dhcpcd.conf
+ fi
+ sudo echo "denyinterfaces $LAN_INTERFACE" >> /etc/dhcpcd.conf
+ echo "Modified /etc/dhcpcd.conf"
+
+ # default config file is made for eth0, this will set the right net interface
+ sudo bash -c 'sed s/eth0/'"$LAN_INTERFACE"'/g /home/pi/RASCSI/src/raspberrypi/os_integration/rascsi_bridge > /etc/network/interfaces.d/rascsi_bridge'
+ echo "Modified /etc/network/interfaces.d/rascsi_bridge"
+
+ echo "Configuration completed!"
+ echo "Please make sure you attach ia DaynaPORT network adapter to the RaSCSI configuration."
+ echo "Either use the Web UI, or do this on the command line (assuming SCSI ID 6): \"rascsi -ID 6 -t scdp $LAN_INTERFACE\""
+ echo ""
+ echo "We need to reboot your Pi"
+ echo "Press Enter to reboot or CTRL-C to exit"
+ read
+
+ echo "Rebooting..."
+ sleep 3
+ sudo reboot
+}
+
+function setupWirelessNetworking() {
+ NETWORK="10.10.20"
+ IP=$NETWORK.2 # Macintosh or Device IP
+ NETWORK_MASK="255.255.255.0"
+ CIDR="24"
+ ROUTER_IP=$NETWORK.1
+ ROUTING_ADDRESS=$NETWORK.0/$CIDR
+ WLAN_INTERFACE="wlan0"
+
+ echo "$WLAN_INTERFACE will be configured for network forwarding with static IP assignment."
+ echo "Configure your Macintosh or other device with the following:"
+ echo "IP Address (static): $IP"
+ echo "Router Address: $ROUTER_IP"
+ echo "Subnet Mask: $NETWORK_MASK"
+ echo "DNS Server: Any public DNS server"
+ echo ""
+ echo "Do you want to proceed with network configuration using the default settings? Y/n"
+ read REPLY
+
+ if [ "$REPLY" == "N" ] || [ "$REPLY" == "n" ]; then
+ echo "Available wireless interfaces on this system:"
+ ip -o addr show scope link | awk '{split($0, a); print $2}' | grep wlan
+ echo "Please type the wireless interface you want to use and press Enter:"
+ read -r WLAN_INTERFACE
+ echo "Base IP address (ex. 10.10.20):"
+ read -r NETWORK
+ echo "CIDR for Subnet Mask (ex. '24' for 255.255.255.0):"
+ read -r CIDR
+ ROUTER_IP=$NETWORK.1
+ ROUTING_ADDRESS=$NETWORK.0/$CIDR
+ fi
+
+
+ if [ $(grep -c "^net.ipv4.ip_forward=1" /etc/sysctl.conf) -ge 1 ]; then
+ echo "WARNING: Network forwarding may already have been configured. Proceeding will overwrite the configuration."
+ echo "Press enter to continue or CTRL-C to exit"
+ read REPLY
+ else
+ sudo bash -c 'echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf'
+ echo "Modified /etc/sysctl.conf"
+ fi
+
+ sudo iptables --flush
+ sudo iptables -t nat -F
+ sudo iptables -X
+ sudo iptables -Z
+ sudo iptables -P INPUT ACCEPT
+ sudo iptables -P OUTPUT ACCEPT
+ sudo iptables -P FORWARD ACCEPT
+ sudo iptables -t nat -A POSTROUTING -o $WLAN_INTERFACE -s $ROUTING_ADDRESS -j MASQUERADE
+
+ # Check if iptables-persistent is installed
+ IPTABLES_PERSISTENT=$(dpkg -s iptables-persistent | grep Status | grep -c "install ok")
+ if [ $IPTABLES_PERSISTENT -eq 0 ]; then
+ sudo apt-get install iptables-persistent --assume-yes
+ else
+ sudo iptables-save --file /etc/iptables/rules.v4
+ fi
+ echo "Modified /etc/iptables/rules.v4"
+
+ echo "Configuration completed!"
+ echo ""
+ echo "Please make sure you attach a DaynaPORT network adapter to the RaSCSI configuration"
+ echo "Either use the Web UI, or do this on the command line (assuming SCSI ID 6): \"rascsi -ID 6 -t scdp $WLAN_INTERFACE:$ROUTER_IP/$CIDR\""
+ echo ""
+ echo "We need to reboot your Pi"
+ echo "Press Enter to reboot or CTRL-C to exit"
+ read REPLY
+
+ echo "Rebooting..."
+ sleep 3
+ sudo reboot
+}
+
+function reserveScsiIds() {
+ if [ ! -f /etc/systemd/system/rascsi-web.service ]; then
+ echo "This feature depends on the RaSCSI Web UI being installed. Please install RaSCSI Web before continuing."
+ exit
+ fi
+
+ sudo systemctl stop rascsi-web
+ echo "Please type the SCSI ID(s) that you want to reserve and press Enter:"
+ echo "The input should be a string of digits without separators, e.g. \"017\" for IDs 0, 1, and 7."
+ read -r RESERVED_IDS
+ sudo sed -i /^ExecStart=/d /etc/systemd/system/rascsi-web.service
+ sudo sed -i "8 i ExecStart=/home/pi/RASCSI/src/web/start.sh --reserved_ids=$RESERVED_IDS" /etc/systemd/system/rascsi-web.service
+
+ sudo systemctl daemon-reload
+ sudo systemctl start rascsi-web
+}
+
function runChoice() {
case $1 in
0)
- echo "Installing RaSCSI Service + Web interface"
+ echo "Installing / Updating RaSCSI Service (${CONNECT_TYPE-FULLSPEC}) + Web interface + 600MB Drive"
+ stopOldWebInterface
+ updateRaScsiGit
+ createImagesDir
+ installPackages
installRaScsi
installRaScsiWebInterface
createDrive600MB
showRaScsiStatus
- echo "Installing RaSCSI Service + Web interface - Complete!"
+ showRaScsiWebStatus
+ echo "Installing / Updating RaSCSI Service (${CONNECT_TYPE-FULLSPEC}) + Web interface + 600MB Drive - Complete!"
;;
1)
- echo "Installing RaSCSI Service"
+ echo "Installing / Updating RaSCSI Service (${CONNECT_TYPE-FULLSPEC}) + Web interface"
+ stopOldWebInterface
+ updateRaScsiGit
+ createImagesDir
+ installPackages
installRaScsi
+ installRaScsiWebInterface
showRaScsiStatus
- echo "Installing RaSCSI Service - Complete!"
+ showRaScsiWebStatus
+ echo "Installing / Updating RaSCSI Service (${CONNECT_TYPE-FULLSPEC}) + Web interface - Complete!"
;;
2)
- echo "Installing RaSCSI Web interface"
- installRaScsiWebInterface
- echo "Installing RaSCSI Web interface - Complete!"
- ;;
+ echo "Installing / Updating RaSCSI Service (${CONNECT_TYPE-FULLSPEC})"
+ updateRaScsiGit
+ createImagesDir
+ installPackages
+ installRaScsi
+ showRaScsiStatus
+ echo "Installing / Updating RaSCSI Service (${CONNECT_TYPE-FULLSPEC}) - Complete!"
+ ;;
3)
- echo "Updating RaSCSI Service + Web interface"
- updateRaScsi
- updateRaScsiWebInterface
- showRaScsiStatus
- echo "Updating RaSCSI Service + Web interface - Complete!"
- ;;
- 4)
- echo "Updating RaSCSI Service"
- updateRaScsi
- showRaScsiStatus
- echo "Updating RaSCSI Service - Complete!"
- ;;
- 5)
- echo "Updating RaSCSI Web interface"
- updateRaScsiWebInterface
- echo "Updating RaSCSI Web interface - Complete!"
- ;;
- 6)
echo "Creating a 600MB drive"
createDrive600MB
echo "Creating a 600MB drive - Complete!"
;;
- 7)
+ 4)
echo "Creating a custom drive"
createDriveCustom
echo "Creating a custom drive - Complete!"
;;
+ 5)
+ echo "Configuring wired network bridge"
+ showMacNetworkWired
+ setupWiredNetworking
+ echo "Configuring wired network bridge - Complete!"
+ ;;
+ 6)
+ echo "Configuring wifi network bridge"
+ showMacNetworkWireless
+ setupWirelessNetworking
+ echo "Configuring wifi network bridge - Complete!"
+ ;;
+ 7)
+ echo "Reserving SCSI IDs"
+ reserveScsiIds
+ showRaScsiWebStatus
+ echo "Reserving SCSI IDs - Complete!"
+ ;;
-h|--help|h|help)
showMenu
;;
@@ -314,25 +500,53 @@ function readChoice() {
function showMenu() {
echo ""
echo "Choose among the following options:"
- echo "INSTALL"
- echo " 0) install RaSCSI Service + web interface + 600MB Drive (recommended)"
- echo " 1) install RaSCSI Service (initial)"
- echo " 2) install RaSCSI Web interface"
- echo "UPDATE"
- echo " 3) update RaSCSI Service + web interface (recommended)"
- echo " 4) update RaSCSI Service"
- echo " 5) update RaSCSI Web interface"
- echo "CREATE EMPTY DRIVE"
- echo " 6) 600MB drive (recommended)"
- echo " 7) custom drive size (up to 4000MB)"
+ echo "INSTALL/UPDATE RASCSI (${CONNECT_TYPE-FULLSPEC} version)"
+ echo " 0) install or update RaSCSI Service + web interface + 600MB Drive (recommended)"
+ echo " 1) install or update RaSCSI Service + web interface"
+ echo " 2) install or update RaSCSI Service"
+ echo "CREATE EMPTY DRIVE IMAGE"
+ echo " 3) 600MB drive (recommended)"
+ echo " 4) custom drive size (up to 4000MB)"
+ echo "NETWORK ASSISTANT"
+ echo " 5) configure network forwarding over Ethernet (DHCP)"
+ echo " 6) configure network forwarding over WiFi (static IP)"
+ echo "MISCELLANEOUS"
+ echo " 7) reserve SCSI IDs"
}
+# parse arguments
+while [ "$1" != "" ]; do
+ PARAM=`echo $1 | awk -F= '{print $1}'`
+ VALUE=`echo $1 | awk -F= '{print $2}'`
+ case $PARAM in
+ -c | --connect_type)
+ CONNECT_TYPE=$VALUE
+ ;;
+ -r | --run_choice)
+ RUN_CHOICE=$VALUE
+ ;;
+ *)
+ echo "ERROR: unknown parameter \"$PARAM\""
+ exit 1
+ ;;
+ esac
+ case $VALUE in
+ FULLSPEC | STANDARD | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7)
+ ;;
+ *)
+ echo "ERROR: unknown option \"$VALUE\""
+ exit 1
+ ;;
+ esac
+ shift
+done
showRaSCSILogo
initialChecks
-if [ -z "${1}" ]; then # $1 is unset, show menu
+
+if [ -z "${RUN_CHOICE}" ]; then # RUN_CHOICE is unset, show menu
showMenu
readChoice
else
- runChoice "$1"
+ runChoice "$RUN_CHOICE"
fi
diff --git a/src/raspberrypi/devices/cfilesystem.cpp b/src/raspberrypi/devices/cfilesystem.cpp
index bc939147..c1b3e06a 100644
--- a/src/raspberrypi/devices/cfilesystem.cpp
+++ b/src/raspberrypi/devices/cfilesystem.cpp
@@ -154,45 +154,45 @@ void Human68k::namests_t::GetCopyFilename(BYTE* szFilename) const
for (i = 0; i < 8; i++) {
BYTE c = name[i];
if (c == ' ') {
- // ファイル名中にスペースが出現した場合、以降のエントリが続いているかどうか確認
- /// @todo 8+3文字とTewntyOne互換モードで動作を変えるべき
- // add[0] が有効な文字なら続ける
+ // Check that the file name continues after a space is detected
+ /// TODO: Should change this function to be compatible with 8+3 chars and TwentyOne
+ // Continue if add[0] is a valid character
if (add[0] != '\0')
goto next_name;
- // name[i] より後に空白以外の文字が存在するなら続ける
+ // Continue if a non-space character exists after name[i]
for (size_t j = i + 1; j < 8; j++) {
if (name[j] != ' ')
goto next_name;
}
- // ファイル名終端なら転送終了
+ // Exit if the file name ends
break;
}
next_name:
*p++ = c;
}
- // 全ての文字を読み込むと、ここで i >= 8 となる
+ // At this point, the number of read characters becomes i >= 8
- // ファイル名本体が8文字以上なら追加部分も加える
+ // If the body of the file name exceeds 8 characters, add the extraneous part
if (i >= 8) {
- // ファイル名追加部分転送
+ // Transfer the extraneous part
for (i = 0; i < 10; i++) {
BYTE c = add[i];
if (c == '\0')
break;
*p++ = c;
}
- // 全ての文字を読み込むと、ここで i >= 10 となる
+ // At this point, the number of read characters becomes i >= 10
}
- // 拡張子が存在する場合は転送
+ // Transfer the file extension if it exists
if (ext[0] != ' ' || ext[1] != ' ' || ext[2] != ' ') {
*p++ = '.';
for (i = 0; i < 3; i++) {
BYTE c = ext[i];
if (c == ' ') {
- // 拡張子中にスペースが出現した場合、以降のエントリが続いているかどうか確認
- /// @todo 8+3文字とTewntyOne互換モードで動作を変えるべき
- // ext[i] より後に空白以外の文字が存在するなら続ける
+ // Check that the file extension continues after a space is detected
+ /// TODO: Should change this function to be compatible with 8+3 chars and TwentyOne
+ // Continue if a non-space character exists after ext[i]
for (size_t j = i + 1; j < 3; j++) {
if (ext[j] != ' ')
goto next_ext;
@@ -216,14 +216,8 @@ void Human68k::namests_t::GetCopyFilename(BYTE* szFilename) const
//
//===========================================================================
-//---------------------------------------------------------------------------
-//
-// Default constructor
-//
-//---------------------------------------------------------------------------
CHostDrv::CHostDrv()
{
- // Initialization
m_bWriteProtect = FALSE;
m_bEnable = FALSE;
m_capCache.sectors = 0;
@@ -233,11 +227,6 @@ CHostDrv::CHostDrv()
m_nRing = 0;
}
-//---------------------------------------------------------------------------
-//
-// Final destructor
-//
-//---------------------------------------------------------------------------
CHostDrv::~CHostDrv()
{
CHostPath* p;
@@ -291,7 +280,7 @@ void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
} else {
pClear = NULL;
}
- if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // 厳密には 0x81~0x9F 0xE0~0xEF
+ if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // To be precise: 0x81~0x9F 0xE0~0xEF
p++;
if (*p == _T('\0'))
break;
@@ -424,17 +413,17 @@ void CHostDrv::GetVolume(TCHAR* szLabel)
//---------------------------------------------------------------------------
//
-/// キャッシュからボリュームラベルを取得
+/// Get volume label from cache
///
-/// キャッシュされているボリュームラベル情報を転送する。
-/// キャッシュ内容が有効ならTRUEを、無効ならFALSEを返す。
+/// Transfer the cached volume label information.
+/// If the cache contents are valid return TRUE, if invalid return FALSE.
//
//---------------------------------------------------------------------------
BOOL CHostDrv::GetVolumeCache(TCHAR* szLabel) const
{
ASSERT(szLabel);
- // 内容を転送
+ // Transfer contents
strcpy(szLabel, m_szVolumeCache);
return m_bVolumeCache;
@@ -442,7 +431,7 @@ BOOL CHostDrv::GetVolumeCache(TCHAR* szLabel) const
//---------------------------------------------------------------------------
//
-/// 容量の取得
+/// Get Capacity
//
//---------------------------------------------------------------------------
DWORD CHostDrv::GetCapacity(Human68k::capacity_t* pCapacity)
@@ -459,18 +448,18 @@ DWORD CHostDrv::GetCapacity(Human68k::capacity_t* pCapacity)
clusters = 0xFFFF;
sectors = 64;
- // パラメータ範囲想定
+ // Estimated parameter range
ASSERT(freearea <= 0xFFFF);
ASSERT(clusters <= 0xFFFF);
ASSERT(sectors <= 64);
- // キャッシュ更新
+ // Update cache
m_capCache.freearea = (WORD)freearea;
m_capCache.clusters = (WORD)clusters;
m_capCache.sectors = (WORD)sectors;
m_capCache.bytes = 512;
- // 内容を転送
+ // Transfer contents
memcpy(pCapacity, &m_capCache, sizeof(m_capCache));
return nFree;
@@ -478,17 +467,17 @@ DWORD CHostDrv::GetCapacity(Human68k::capacity_t* pCapacity)
//---------------------------------------------------------------------------
//
-/// キャッシュから容量を取得
+/// Get capacity from the cache
///
-/// キャッシュされている容量情報を転送する。
-/// キャッシュ内容が有効ならTRUEを、無効ならFALSEを返す。
+/// Transfer the capacity data stored in cache.
+/// If the contents of the cache is valid return TRUE, is invalid return FALSE.
//
//---------------------------------------------------------------------------
BOOL CHostDrv::GetCapacityCache(Human68k::capacity_t* pCapacity) const
{
ASSERT(pCapacity);
- // 内容を転送
+ // Transfer contents
memcpy(pCapacity, &m_capCache, sizeof(m_capCache));
return m_capCache.sectors != 0;
@@ -496,7 +485,7 @@ BOOL CHostDrv::GetCapacityCache(Human68k::capacity_t* pCapacity) const
//---------------------------------------------------------------------------
//
-/// 全てのキャッシュを更新する
+/// Update all cache
//
//---------------------------------------------------------------------------
void CHostDrv::CleanCache()
@@ -511,7 +500,7 @@ void CHostDrv::CleanCache()
//---------------------------------------------------------------------------
//
-/// 指定されたパスのキャッシュを更新する
+/// Update the cache for the specified path
//
//---------------------------------------------------------------------------
void CHostDrv::CleanCache(const BYTE* szHumanPath)
@@ -529,7 +518,7 @@ void CHostDrv::CleanCache(const BYTE* szHumanPath)
//---------------------------------------------------------------------------
//
-/// 指定されたパス以下のキャッシュを全て更新する
+/// Update the cache below and including the specified path
//
//---------------------------------------------------------------------------
void CHostDrv::CleanCacheChild(const BYTE* szHumanPath)
@@ -548,7 +537,7 @@ void CHostDrv::CleanCacheChild(const BYTE* szHumanPath)
//---------------------------------------------------------------------------
//
-/// 指定されたパスのキャッシュを削除する
+/// Delete the cache for the specified path
//
//---------------------------------------------------------------------------
void CHostDrv::DeleteCache(const BYTE* szHumanPath)
@@ -567,18 +556,18 @@ void CHostDrv::DeleteCache(const BYTE* szHumanPath)
//---------------------------------------------------------------------------
//
-/// 指定されたパスがキャッシュされているか検索する
+/// Check if the specified path is cached
///
-/// 所有するキャシュバッファの中から完全一致で検索し、見つかればその名称を返す。
-/// ファイル名を除外しておくこと。
-/// 必ず上位で排他制御を行なうこと。
+/// Check if whether it is a perfect match with the cache buffer, and return the name if found.
+/// File names are excempted.
+/// Make sure to lock from the top.
//
//---------------------------------------------------------------------------
CHostPath* CHostDrv::FindCache(const BYTE* szHuman)
{
ASSERT(szHuman);
- // 所持している全てのファイル名の中から完全一致するものを検索
+ // Find something that matches perfectly with either of the stored file names
for (CHostPath* p = (CHostPath*)m_cRing.Next(); p != &m_cRing;) {
if (p->isSameHuman(szHuman))
return p;
@@ -590,11 +579,11 @@ CHostPath* CHostDrv::FindCache(const BYTE* szHuman)
//---------------------------------------------------------------------------
//
-/// キャッシュ情報を元に、ホスト側の名称を獲得する
+/// Get the host side name from cached data.
///
-/// パスがキャッシュにあるか確認。なければエラー。
-/// 見つかったキャッシュの更新チェック。更新が必要ならエラー。
-/// 必ず上位で排他制御を行なうこと。
+/// Confirm if the path is cached. If not, throw an error.
+/// Carry out an update check on found cache. If an update is needed, throw an error.
+/// Make sure to lock from the top.
//
//---------------------------------------------------------------------------
CHostPath* CHostDrv::CopyCache(CHostFiles* pFiles)
@@ -602,21 +591,21 @@ CHostPath* CHostDrv::CopyCache(CHostFiles* pFiles)
ASSERT(pFiles);
ASSERT(strlen((const char*)pFiles->GetHumanPath()) < HUMAN68K_PATH_MAX);
- // キャッシュ検索
+ // Find in cache
CHostPath* pPath = FindCache(pFiles->GetHumanPath());
if (pPath == NULL) {
- return NULL; // エラー: キャッシュなし
+ return NULL; // Error: No cache
}
- // リング先頭へ移動
+ // Move to the beginning of the ring
pPath->Insert(&m_cRing);
- // キャッシュ更新チェック
+ // Cache update check
if (pPath->isRefresh()) {
- return NULL; // エラー: キャッシュ更新が必要
+ return NULL; // Error: Cache update is required
}
- // ホスト側のパス名を保存
+ // Store the host side path
pFiles->SetResult(pPath->GetHost());
return pPath;
@@ -624,22 +613,22 @@ CHostPath* CHostDrv::CopyCache(CHostFiles* pFiles)
//---------------------------------------------------------------------------
//
-/// ホスト側の名称の構築に必要な情報をすべて取得する
+/// Get all the data required for a host side name structure
///
-/// ファイル名は省略可能。(普通は指定しない)
-/// 必ず上位で排他制御を行なうこと。
-/// ベースパス末尾にパス区切り文字をつけないよう注意。
-/// ファイルアクセスが多発する可能性があるときは、VMスレッドの動作を開始させる。
+/// File names can be abbreviated. (Normally not selected)
+/// Make sure to lock from the top.
+/// Be careful not to append the path separator char to the end of the base path.
+/// Initiate VM threads when there is a chance of multiple file accesses.
///
-/// 使いかた:
-/// CopyCache()してエラーの場合はMakeCache()する。必ず正しいホスト側のパスが取得できる。
+/// How to use:
+/// When CopyCache() throws an error execute MakeCache(). It ensures you get a correct host side path.
///
-/// ファイル名とパス名をすべて分離する。
-/// 上位ディレクトリから順に、キャッシュされているかどうか確認。
-/// キャッシュされていれば破棄チェック。破棄した場合未キャッシュ扱いとなる。
-/// キャッシュされていなければキャッシュを構築。
-/// 順番にすべてのディレクトリ・ファイル名に対して行ない終了。
-/// エラーが発生した場合はNULLとなる。
+/// Split all file names and path names.
+/// Confirm that it's cached from the top level directory down.
+/// If it's cached, do a destruction check. If it was destroyed, treat it as uncached.
+/// If it isn't cached, build cache.
+/// Exit after processing all directory and file names in order.
+/// Make it NULL is an error is thrown.
//
//---------------------------------------------------------------------------
CHostPath* CHostDrv::MakeCache(CHostFiles* pFiles)
@@ -650,7 +639,7 @@ CHostPath* CHostDrv::MakeCache(CHostFiles* pFiles)
ASSERT(m_szBase);
ASSERT(strlen(m_szBase) < FILEPATH_MAX);
- BYTE szHumanPath[HUMAN68K_PATH_MAX]; // ルートから順にパス名が入る
+ BYTE szHumanPath[HUMAN68K_PATH_MAX]; // Path names are entered in order from the route
szHumanPath[0] = '\0';
size_t nHumanPath = 0;
@@ -661,35 +650,35 @@ CHostPath* CHostDrv::MakeCache(CHostFiles* pFiles)
CHostPath* pPath;
const BYTE* p = pFiles->GetHumanPath();
for (;;) {
- // パス区切りを追加
+ // Add path separators
if (nHumanPath + 1 >= HUMAN68K_PATH_MAX)
- return NULL; // エラー: Human68kパスが長すぎる
+ return NULL; // Error: The Human68k path is too long
szHumanPath[nHumanPath++] = '/';
szHumanPath[nHumanPath] = '\0';
if (nHostPath + 1 >= FILEPATH_MAX)
- return NULL; // エラー: ホスト側のパスが長すぎる
+ return NULL; // Error: The host side path is too long
szHostPath[nHostPath++] = _T('/');
szHostPath[nHostPath] = _T('\0');
- // ファイルいっこいれる
- BYTE szHumanFilename[24]; // ファイル名部分
+ // Insert one file
+ BYTE szHumanFilename[24]; // File name part
p = SeparateCopyFilename(p, szHumanFilename);
if (p == NULL)
- return NULL; // エラー: ファイル名読み込み失敗
+ return NULL; // Error: Failed to read file name
size_t n = strlen((const char*)szHumanFilename);
if (nHumanPath + n >= HUMAN68K_PATH_MAX)
- return NULL; // エラー: Human68kパスが長すぎる
+ return NULL; // Error: The Human68k path is too long
- // 該当パスがキャッシュされているか?
+ // Is the relevant path cached?
pPath = FindCache(szHumanPath);
if (pPath == NULL) {
- // キャッシュ最大数チェック
+ // Check for max number of cache
if (m_nRing >= XM6_HOST_DIRENTRY_CACHE_MAX) {
- // 最も古いキャッシュを破棄して再利用
+ // Destroy the oldest cache and reuse it
pPath = (CHostPath*)m_cRing.Prev();
- pPath->Clean(); // 全ファイル解放 更新チェック用ハンドルも解放
+ pPath->Clean(); // Release all files. Release update check handlers.
} else {
- // 新規登録
+ // Register new
pPath = new CHostPath;
ASSERT(pPath);
m_nRing++;
@@ -697,43 +686,42 @@ CHostPath* CHostDrv::MakeCache(CHostFiles* pFiles)
pPath->SetHuman(szHumanPath);
pPath->SetHost(szHostPath);
- // 状態更新
+ // Update status
pPath->Refresh();
}
- // キャッシュ更新チェック
+ // Cache update check
if (pPath->isRefresh()) {
- // 更新
Update();
- // 状態更新
+ // Update status
pPath->Refresh();
}
- // リング先頭へ
+ // Into the beginning of the ring
pPath->Insert(&m_cRing);
- // ファイル名がなければここで終了
+ // Exit if there is not file name
if (n == 0)
break;
- // 次のパスを検索
- // パスの途中ならディレクトリかどうか確認
+ // Find the next path
+ // Confirm if directory from the middle of the path
const CHostFilename* pFilename;
if (*p != '\0')
pFilename = pPath->FindFilename(szHumanFilename, Human68k::AT_DIRECTORY);
else
pFilename = pPath->FindFilename(szHumanFilename);
if (pFilename == NULL)
- return NULL; // エラー: 途中のパス名/ファイル名が見つからない
+ return NULL; // Error: Could not find path or file names in the middle
- // パス名を連結
+ // Link path name
strcpy((char*)szHumanPath + nHumanPath, (const char*)szHumanFilename);
nHumanPath += n;
n = strlen(pFilename->GetHost());
if (nHostPath + n >= FILEPATH_MAX)
- return NULL; // エラー: ホスト側のパスが長すぎる
+ return NULL; // Error: Host side path is too long
strcpy(szHostPath + nHostPath, pFilename->GetHost());
nHostPath += n;
@@ -742,7 +730,7 @@ CHostPath* CHostDrv::MakeCache(CHostFiles* pFiles)
break;
}
- // ホスト側のパス名を保存
+ // Store the host side path name
pFiles->SetResult(szHostPath);
return pPath;
@@ -750,52 +738,50 @@ CHostPath* CHostDrv::MakeCache(CHostFiles* pFiles)
//---------------------------------------------------------------------------
//
-/// ホスト側の名称を検索 (パス名+ファイル名(省略可)+属性)
+/// Find host side name (path name + file name (can be abbeviated) + attribute)
///
-/// あらかじめ全てのHuman68k用パラメータを設定しておくこと。
+/// Set all Human68k parameters once more.
//
//---------------------------------------------------------------------------
BOOL CHostDrv::Find(CHostFiles* pFiles)
{
ASSERT(pFiles);
- // 排他制御開始
Lock();
- // パス名獲得およびキャッシュ構築
+ // Get path name and build cache
CHostPath* pPath = CopyCache(pFiles);
if (pPath == NULL) {
pPath = MakeCache(pFiles);
if (pPath == NULL) {
Unlock();
CleanCache();
- return FALSE; // エラー: キャッシュ構築失敗
+ return FALSE; // Error: Failed to build cache
}
}
- // ホスト側のパス名を保存
+ // Store host side path
pFiles->SetResult(pPath->GetHost());
- // パス名のみなら終了
+ // Exit if only path name
if (pFiles->isPathOnly()) {
Unlock();
- return TRUE; // 正常終了: パス名のみ
+ return TRUE; // Normal exit: only path name
}
- // ファイル名検索
+ // Find file name
const CHostFilename* pFilename = pFiles->Find(pPath);
if (pFilename == NULL) {
Unlock();
- return FALSE; // エラー: ファイル名が獲得できません
+ return FALSE; // Error: Could not get file name
}
- // Human68k側の検索結果保存
+ // Store the Human68k side search results
pFiles->SetEntry(pFilename);
- // ホスト側のフルパス名保存
+ // Store the host side full path name
pFiles->AddResult(pFilename->GetHost());
- // 排他制御終了
Unlock();
return TRUE;
@@ -803,15 +789,10 @@ BOOL CHostDrv::Find(CHostFiles* pFiles)
//===========================================================================
//
-// ディレクトリエントリ ファイル名
+// Directory entry: File name
//
//===========================================================================
-//---------------------------------------------------------------------------
-//
-/// デフォルトコンストラクタ
-//
-//---------------------------------------------------------------------------
CHostFilename::CHostFilename()
{
m_bCorrect = FALSE;
@@ -821,7 +802,7 @@ CHostFilename::CHostFilename()
//---------------------------------------------------------------------------
//
-/// ホスト側の名称を設定
+/// Set host side name
//
//---------------------------------------------------------------------------
void CHostFilename::SetHost(const TCHAR* szHost)
@@ -834,7 +815,7 @@ void CHostFilename::SetHost(const TCHAR* szHost)
//---------------------------------------------------------------------------
//
-/// Human68k側のファイル名要素をコピー
+/// Copy the Human68k file name elements
//
//---------------------------------------------------------------------------
BYTE* CHostFilename::CopyName(BYTE* pWrite, const BYTE* pFirst, const BYTE* pLast) // static
@@ -852,15 +833,15 @@ BYTE* CHostFilename::CopyName(BYTE* pWrite, const BYTE* pFirst, const BYTE* pLas
//---------------------------------------------------------------------------
//
-/// Human68k側の名称を変換
+/// Convert the Human68k side name
///
-/// あらかじめSetHost()を実行しておくこと。
-/// 18+3の命名規則に従った名前変換を行なう。
-/// ファイル名先頭および末尾の空白は、Human68kで扱えないため自動的に削除される。
-/// ディレクトリエントリの名前部分を、ファイル名変換時の拡張子の位置情報を使って生成する。
-/// その後、ファイル名の異常判定を行なう。(スペース8文字だけのファイル名など)
-/// ファイル名の重複判定は行なわないので注意。これらの判定は上位クラスで行なう。
-/// TwentyOne version 1.36c modified +14 patchlevel9以降の拡張子規則に対応させる。
+/// Once more, execute SetHost().
+/// Carry out name conversion to the 18+3 standard.
+/// Automatically delete spaces in the beginning and end of the names, since Human68k can't handle them.
+/// The directory entry name segment is created at the time of conversion using knowledge of the location of the file name extension.
+/// Afterwards, a file name validity check is performed. (Ex. file names consisting of 8 spaces only.)
+/// No file name duplication check is performed so be careful. Such validation is carried out in classes higher up.
+/// Adhers to the naming standards of: TwentyOne version 1.36c modified +14 patchlevel9 or later
//
//---------------------------------------------------------------------------
void CHostFilename::ConvertHuman(int nCount)
@@ -868,10 +849,10 @@ void CHostFilename::ConvertHuman(int nCount)
char szHost[FILEPATH_MAX];
- // 特殊ディレクトリ名の場合は変換しない
+ // Don't do conversion for special directory names
if (m_szHost[0] == _T('.') &&
(m_szHost[1] == _T('\0') || (m_szHost[1] == _T('.') && m_szHost[2] == _T('\0')))) {
- strcpy((char*)m_szHuman, m_szHost); /// @warning Unicode時要修正 → 済
+ strcpy((char*)m_szHuman, m_szHost);
m_bCorrect = TRUE;
m_pszHumanLast = m_szHuman + strlen((const char*)m_szHuman);
@@ -879,17 +860,17 @@ void CHostFilename::ConvertHuman(int nCount)
return;
}
- size_t nMax = 18; // ベース部分(ベース名と拡張子名)のバイト数
+ size_t nMax = 18; // Number of bytes for the base segment (base name and extension)
DWORD nOption = CFileSys::GetFileOption();
if (nOption & WINDRV_OPT_CONVERT_LENGTH)
nMax = 8;
- // ベース名部分の補正準備
+ // Preparations to adjust the base name segment
BYTE szNumber[8];
BYTE* pNumber = NULL;
if (nCount >= 0) {
pNumber = &szNumber[8];
- for (DWORD i = 0; i < 5; i++) { // 最大5+1桁まで (ベース名先頭2バイトは必ず残す)
+ for (DWORD i = 0; i < 5; i++) { // Max 5+1 digits (always leave the first 2 bytes of the base name)
int n = nCount % 36;
nMax--;
pNumber--;
@@ -906,8 +887,7 @@ void CHostFilename::ConvertHuman(int nCount)
*pNumber = c;
}
- // 文字変換
- /// @warning Unicode未対応。いずれUnicodeの世界に飮まれた時はここで変換を行なう → 済
+ // Char conversion
BYTE szHuman[FILEPATH_MAX];
const BYTE* pFirst = szHuman;
const BYTE* pLast;
@@ -928,7 +908,7 @@ void CHostFilename::ConvertHuman(int nCount)
if (nOption & WINDRV_OPT_CONVERT_SPACE)
c = '_';
else if (pWrite == szHuman)
- continue; // 先頭の空白は無視
+ continue; // Ignore spaces in the beginning
break;
case '=':
case '+':
@@ -951,7 +931,7 @@ void CHostFilename::ConvertHuman(int nCount)
c = '_';
break;
case '.':
- if (pRead - 1 == pPeriod) { // Human68k拡張子は例外とする
+ if (pRead - 1 == pPeriod) { // Make exception for Human68k extensions
pExt = pWrite;
break;
}
@@ -976,76 +956,76 @@ void CHostFilename::ConvertHuman(int nCount)
pLast = pWrite - 1;
}
- // 拡張子補正
+ // Adjust extensions
if (pExt) {
- // 末尾の空白を削除する
+ // Delete spaces at the end
while (pExt < pLast - 1 && *(pLast - 1) == ' ') {
pLast--;
BYTE* p = (BYTE*)pLast;
*p = '\0';
}
- // 変換後に実体がなくなった場合は削除
+ // Delete if the file name disappeared after conversion
if (pExt + 1 >= pLast) {
pLast = pExt;
BYTE* p = (BYTE*)pLast;
- *p = '\0'; // 念のため
+ *p = '\0'; // Just in case
}
} else {
pExt = pLast;
}
- // 登場人物紹介
+ // Introducing the cast of characters
//
- // pFirst: 俺はリーダー。ファイル名先頭
- // pCut: 通称フェイス。最初のピリオドの出現位置 その後ベース名終端位置となる
- // pSecond: よぉおまちどう。俺様こそマードック。拡張子名の開始位置。だから何。
- // pExt: B・A・バラカス。Human68k拡張子の天才だ。でも、3文字より長い名前は勘弁な。
- // 最後のピリオドの出現位置 該当しなければpLastと同じ値
+ // pFirst: I'm the glorious leader. The start of the file name.
+ // pCut: A.k.a. Phase. Location of the initial period. Afterwards becomes the end of the base name.
+ // pSecond: Hello there! I'm the incredible Murdock. The start of the file name extension. What's it to you?
+ // pExt: B.A. Baracus. The Human68k extension genius. But don't you dare giving me more than 3 chars, fool.
+ // The location of the final period. If not applicable, gets the same value as pLast.
//
// ↓pFirst ↓pStop ↓pSecond ← ↓pExt
// T h i s _ i s _ a . V e r y . L o n g . F i l e n a m e . t x t \0
- // ↑pCut ← ↑pCut初期位置 ↑pLast
+ // ↑pCut ← ↑pCut initial location ↑pLast
//
- // 上記の場合、変換後は This.Long.Filename.txt となる
+ // The above example becomes "This.Long.Filename.txt" after conversion
- // 1文字目判定
+ // Evaluate first char
const BYTE* pCut = pFirst;
- const BYTE* pStop = pExt - nMax; // 拡張子名は最大17バイトとする(ベース名を残す)
+ const BYTE* pStop = pExt - nMax; // Allow for up to 17 bytes for extension (leave base name)
if (pFirst < pExt) {
- pCut++; // 必ず1バイトはベース名を使う
+ pCut++; // 1 byte always uses the base name
BYTE c = *pFirst;
- if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // 厳密には 0x81~0x9F 0xE0~0xEF
- pCut++; // ベース名 最小2バイト
- pStop++; // 拡張子名 最大16バイト
+ if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // Specifically 0x81~0x9F 0xE0~0xEF
+ pCut++; // Base name. At least 2 bytes.
+ pStop++; // File extension. Max 16 bytes.
}
}
if (pStop < pFirst)
pStop = pFirst;
- // ベース名判定
- pCut = (BYTE*)strchr((const char*)pCut, '.'); // SJIS2バイト目は必ず0x40以上なので問題ない
+ // Evaluate base name
+ pCut = (BYTE*)strchr((const char*)pCut, '.'); // The 2nd byte of Shift-JIS is always 0x40 or higher, so this is ok
if (pCut == NULL)
pCut = pLast;
if ((size_t)(pCut - pFirst) > nMax)
- pCut = pFirst + nMax; // 後ほどSJIS2バイト判定/補正を行なう ここで判定してはいけない
+ pCut = pFirst + nMax; // Execute Shift-JIS 2 byte evaluation/adjustment later. Not allowed to do it here.
- // 拡張子名判定
+ // Evaluate extension
const BYTE* pSecond = pExt;
const BYTE* p;
for (p = pExt - 1; pStop < p; p--) {
if (*p == '.')
- pSecond = p; // SJIS2バイト目は必ず0x40以上なので問題ない
+ pSecond = p; // The 2nd byte of Shift-JIS is always 0x40 or higher, so this is ok
}
- // ベース名を短縮
- size_t nExt = pExt - pSecond; // 拡張子名部分の長さ
+ // Shorten base name
+ size_t nExt = pExt - pSecond; // Length of extension segment
if ((size_t)(pCut - pFirst) + nExt > nMax)
pCut = pFirst + nMax - nExt;
- // 2バイト文字の途中ならさらに短縮
+ // If in the middle of a 2 byte char, shorten even further
for (p = pFirst; p < pCut; p++) {
BYTE c = *p;
- if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // 厳密には 0x81~0x9F 0xE0~0xEF
+ if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // Specifically 0x81~0x9F 0xE0~0xEF
p++;
if (p >= pCut) {
pCut--;
@@ -1054,31 +1034,31 @@ void CHostFilename::ConvertHuman(int nCount)
}
}
- // 名前の結合
+ // Joining the name
BYTE* pWrite = m_szHuman;
- pWrite = CopyName(pWrite, pFirst, pCut); // ベース名を転送
+ pWrite = CopyName(pWrite, pFirst, pCut); // Transfer the base name
if (pNumber)
- pWrite = CopyName(pWrite, pNumber, &szNumber[8]); // 補正文字を転送
- pWrite = CopyName(pWrite, pSecond, pExt); // 拡張子名を転送
- m_pszHumanExt = pWrite; // 拡張子位置保存
- pWrite = CopyName(pWrite, pExt, pLast); // Human68k拡張子を転送
- m_pszHumanLast = pWrite; // 終端位置保存
+ pWrite = CopyName(pWrite, pNumber, &szNumber[8]); // Transfer the adjustment char
+ pWrite = CopyName(pWrite, pSecond, pExt); // Transfer the extension name
+ m_pszHumanExt = pWrite; // Store the extention position
+ pWrite = CopyName(pWrite, pExt, pLast); // Transfer the Human68k extension
+ m_pszHumanLast = pWrite; // Store the end position
*pWrite = '\0';
- // 変換結果の確認
+ // Confirm the conversion results
m_bCorrect = TRUE;
- // ファイル名本体が存在しなければ不合格
+ // Fail if the base file name does not exist
if (m_pszHumanExt <= m_szHuman)
m_bCorrect = FALSE;
- // ファイル名本体が1文字以上でかつ空白で終了していれば不合格
- // ファイル名本体が8文字以上の場合、理論上は空白での終了が表現可
- // 能だが、Human68kでは正しく扱えないため、これも不合格とする
+ // Fail if the base file name is more than 1 char and ends with a space
+ // While it is theoretically valid to have a base file name exceed 8 chars,
+ // Human68k is unable to handle it, so failing this case too.
else if (m_pszHumanExt[-1] == ' ')
m_bCorrect = FALSE;
- // 変換結果が特殊ディレクトリ名と同じなら不合格
+ // Fail if the conversion result is the same as a special directory name
if (m_szHuman[0] == '.' &&
(m_szHuman[1] == '\0' || (m_szHuman[1] == '.' && m_szHuman[2] == '\0')))
m_bCorrect = FALSE;
@@ -1086,9 +1066,9 @@ void CHostFilename::ConvertHuman(int nCount)
//---------------------------------------------------------------------------
//
-/// Human68k側の名称を複製
+/// Human68k side name duplication
///
-/// ファイル名部分の情報を複製し、ConvertHuman()相当の初期化動作を行なう。
+/// Duplicates the file name segment data, then executes the correspoding initialization with ConvertHuman().
//
//---------------------------------------------------------------------------
void CHostFilename::CopyHuman(const BYTE* szHuman)
@@ -1104,15 +1084,15 @@ void CHostFilename::CopyHuman(const BYTE* szHuman)
//---------------------------------------------------------------------------
//
-/// Human68kディレクトリエントリを設定
+/// Set Human68k directory entry
///
-/// ConvertHuman()で設定済みのファイル名をディレクトリエントリに反映する。
+/// Apply the set file name to the directory entry with ConvertHuman().
//
//---------------------------------------------------------------------------
void CHostFilename::SetEntryName()
{
- // ファイル名設定
+ // Set file name
BYTE* p = m_szHuman;
size_t i;
for (i = 0; i < 8; i++) {
@@ -1141,18 +1121,18 @@ void CHostFilename::SetEntryName()
//---------------------------------------------------------------------------
//
-/// Human68k側の名称が加工されたか調査
+/// Investigate if the Human68k side name has been processed
//
//---------------------------------------------------------------------------
BOOL CHostFilename::isReduce() const
{
- return strcmp((char *)m_szHost, (const char*)m_szHuman) != 0; /// @warning Unicode時要修正 → 済
+ return strcmp((char *)m_szHost, (const char*)m_szHuman) != 0;
}
//---------------------------------------------------------------------------
//
-/// Human68kディレクトリエントリの属性判定
+/// Evaluate Human68k directory entry attribute
//
//---------------------------------------------------------------------------
BOOL CHostFilename::CheckAttribute(DWORD nHumanAttribute) const
@@ -1167,26 +1147,26 @@ BOOL CHostFilename::CheckAttribute(DWORD nHumanAttribute) const
//---------------------------------------------------------------------------
//
-/// Human68kファイル名から拡張子を分離
+/// Split the extension from Human68k file name
//
//---------------------------------------------------------------------------
const BYTE* CHostFilename::SeparateExt(const BYTE* szHuman) // static
{
- // ファイル名の長さを獲得
+ // Obtain the file name length
size_t nLength = strlen((const char*)szHuman);
const BYTE* pFirst = szHuman;
const BYTE* pLast = pFirst + nLength;
- // Human68k拡張子の位置を確認
- const BYTE* pExt = (BYTE*)strrchr((const char*)pFirst, '.'); // SJIS2バイト目は必ず0x40以上なので問題ない
+ // Confirm the position of the Human68k extension
+ const BYTE* pExt = (BYTE*)strrchr((const char*)pFirst, '.'); // The 2nd byte of Shift-JIS is always 0x40 or higher, so this is ok
if (pExt == NULL)
pExt = pLast;
- // ファイル名が20~22文字かつ19文字目が'.'かつ'.'で終了というパターンを特別扱いする
+ // Special handling of the pattern where the file name is 20~22 chars, and the 19th char is '.' or ends with '.'
if (20 <= nLength && nLength <= 22 && pFirst[18] == '.' && pFirst[nLength - 1] == '.')
pExt = pFirst + 18;
- // 拡張子の文字数を計算 (-1:なし 0:ピリオドだけ 1~3:Human68k拡張子 4以上:拡張子名)
+ // Calculate the number of chars in the extension (-1:None 0:Only period 1~3:Human68k extension 4 or above:extension name)
size_t nExt = pLast - pExt - 1;
- // '.' が文字列先頭以外に存在して、かつ1~3文字の場合のみ拡張子とみなす
+ // Consider it an extension only when '.' is anywhere except the beginning of the string, and between 1~3 chars long
if (pExt == pFirst || nExt < 1 || nExt > 3)
pExt = pLast;
@@ -1195,17 +1175,12 @@ const BYTE* CHostFilename::SeparateExt(const BYTE* szHuman) // static
//===========================================================================
//
-// ディレクトリエントリ パス名
+// Directory entry: path name
//
//===========================================================================
-DWORD CHostPath::g_nId; ///< 識別ID生成用カウンタ
+DWORD CHostPath::g_nId; ///< Identifier creation counter
-//---------------------------------------------------------------------------
-//
-/// デフォルトコンストラクタ
-//
-//---------------------------------------------------------------------------
CHostPath::CHostPath()
{
m_bRefresh = TRUE;
@@ -1213,16 +1188,11 @@ CHostPath::CHostPath()
m_tBackup = FALSE;
#ifdef _DEBUG
- // 必ず値が更新されるので初期化不要 (デバッグ時の初期動作確認用)
+ // Initialization is not required because this value always gets updated (used for debugging or initialization operation)
m_nId = 0;
#endif // _DEBUG
}
-//---------------------------------------------------------------------------
-//
-/// デストラクタ final
-//
-//---------------------------------------------------------------------------
CHostPath::~CHostPath()
{
Clean();
@@ -1230,11 +1200,11 @@ CHostPath::~CHostPath()
//---------------------------------------------------------------------------
//
-/// ファイル名領域確保
+/// File name memory allocation
///
-/// ほとんどのケースでは、ホスト側ファイル名の長さはバッファ最大長に
-/// 比べて非常に短い。さらにファイル名は大量に生成される可能性がある。
-/// そのため文字数に応じた可変長で確保する。
+/// In most cases, the length of the host side file name is way shorter
+/// than the size of the buffer. In addition, file names may be created in huge volumes.
+/// Therefore, allocate variable lengths that correspond to the number of chars.
//
//---------------------------------------------------------------------------
CHostPath::ring_t* CHostPath::Alloc(size_t nLength) // static
@@ -1245,14 +1215,14 @@ CHostPath::ring_t* CHostPath::Alloc(size_t nLength) // static
ring_t* p = (ring_t*)malloc(n);
ASSERT(p);
- p->r.Init(); // 榛名は大丈夫です!
+ p->r.Init(); // This is nothing to worry about!
return p;
}
//---------------------------------------------------------------------------
//
-// ファイル名領域解放
+// Release file name allocations
//
//---------------------------------------------------------------------------
void CHostPath::Free(ring_t* pRing) // static
@@ -1265,7 +1235,7 @@ void CHostPath::Free(ring_t* pRing) // static
//---------------------------------------------------------------------------
//
-/// 再利用のための初期化
+/// Initialize for reuse
//
//---------------------------------------------------------------------------
void CHostPath::Clean()
@@ -1273,7 +1243,7 @@ void CHostPath::Clean()
Release();
- // 全ファイル名を解放
+ // Release all file names
ring_t* p;
while ((p = (ring_t*)m_cRing.Next()) != (ring_t*)&m_cRing) {
Free(p);
@@ -1282,7 +1252,7 @@ void CHostPath::Clean()
//---------------------------------------------------------------------------
//
-/// Human68k側の名称を直接指定する
+/// Specify Human68k side names directly
//
//---------------------------------------------------------------------------
void CHostPath::SetHuman(const BYTE* szHuman)
@@ -1295,7 +1265,7 @@ void CHostPath::SetHuman(const BYTE* szHuman)
//---------------------------------------------------------------------------
//
-/// ホスト側の名称を直接指定する
+/// Specify host side names directly
//
//---------------------------------------------------------------------------
void CHostPath::SetHost(const TCHAR* szHost)
@@ -1308,7 +1278,7 @@ void CHostPath::SetHost(const TCHAR* szHost)
//---------------------------------------------------------------------------
//
-/// 文字列比較 (ワイルドカード対応)
+/// Compare arrays (supports wildcards)
//
//---------------------------------------------------------------------------
int CHostPath::Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFirst, const BYTE* pBufLast)
@@ -1318,59 +1288,59 @@ int CHostPath::Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFi
ASSERT(pBufFirst);
ASSERT(pBufLast);
- // 文字比較
+ // Compare chars
BOOL bSkip0 = FALSE;
BOOL bSkip1 = FALSE;
for (const BYTE* p = pFirst; p < pLast; p++) {
- // 1文字読み込み
+ // Read 1 char
BYTE c = *p;
BYTE d = '\0';
if (pBufFirst < pBufLast)
d = *pBufFirst++;
- // 比較のための文字補正
+ // Ajust char for comparison
if (bSkip0 == FALSE) {
- if (bSkip1 == FALSE) { // cもdも1バイト目
- if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // 厳密には 0x81~0x9F 0xE0~0xEF
+ if (bSkip1 == FALSE) { // First byte for both c and d
+ if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // Specifically 0x81~0x9F 0xE0~0xEF
bSkip0 = TRUE;
}
- if ((0x80 <= d && d <= 0x9F) || 0xE0 <= d) { // 厳密には 0x81~0x9F 0xE0~0xEF
+ if ((0x80 <= d && d <= 0x9F) || 0xE0 <= d) { // Specifically 0x81~0x9F 0xE0~0xEF
bSkip1 = TRUE;
}
if (c == d)
- continue; // 高確率で判定完了する
+ continue; // Finishes the evaluation here with high probability
if ((CFileSys::GetFileOption() & WINDRV_OPT_ALPHABET) == 0) {
if ('A' <= c && c <= 'Z')
- c += 'a' - 'A'; // 小文字化
+ c += 'a' - 'A'; // To lower case
if ('A' <= d && d <= 'Z')
- d += 'a' - 'A'; // 小文字化
+ d += 'a' - 'A'; // To lower case
}
- // バックスラッシュをスラッシュに統一して比較する
+ // Unify slashes and backslashes for comparison
if (c == '\\') {
c = '/';
}
if (d == '\\') {
d = '/';
}
- } else { // cだけが1バイト目
- if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // 厳密には 0x81~0x9F 0xE0~0xEF
+ } else { // Only c is first byte
+ if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // Specifically 0x81~0x9F 0xE0~0xEF
bSkip0 = TRUE;
}
bSkip1 = FALSE;
}
} else {
- if (bSkip1 == FALSE) { // dだけが1バイト目
+ if (bSkip1 == FALSE) { // Only d is first byte
bSkip0 = FALSE;
- if ((0x80 <= d && d <= 0x9F) || 0xE0 <= d) { // 厳密には 0x81~0x9F 0xE0~0xEF
+ if ((0x80 <= d && d <= 0x9F) || 0xE0 <= d) { // Specifically 0x81~0x9F 0xE0~0xEF
bSkip1 = TRUE;
}
- } else { // cもdも2バイト目
+ } else { // Second byte for both c and d
bSkip0 = FALSE;
bSkip1 = FALSE;
}
}
- // 比較
+ // Compare
if (c == d)
continue;
if (c == '?')
@@ -1385,78 +1355,72 @@ int CHostPath::Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFi
//---------------------------------------------------------------------------
//
-/// Human68k側の名称を比較する
+/// Compare Human68k side name
//
//---------------------------------------------------------------------------
BOOL CHostPath::isSameHuman(const BYTE* szHuman) const
{
ASSERT(szHuman);
- // 文字数計算
+ // Calulate number of chars
size_t nLength = strlen((const char*)m_szHuman);
size_t n = strlen((const char*)szHuman);
- // 文字数チェック
+ // Check number of chars
if (nLength != n)
return FALSE;
- // Human68kパス名の比較
+ // Compare Human68k path name
return Compare(m_szHuman, m_szHuman + nLength, szHuman, szHuman + n) == 0;
}
-//---------------------------------------------------------------------------
-//
-/// Human68k側の名称を比較する
-//
-//---------------------------------------------------------------------------
BOOL CHostPath::isSameChild(const BYTE* szHuman) const
{
ASSERT(szHuman);
- // 文字数計算
+ // Calulate number of chars
size_t nLength = strlen((const char*)m_szHuman);
size_t n = strlen((const char*)szHuman);
- // 文字数チェック
+ // Check number of chars
if (nLength < n)
return FALSE;
- // Human68kパス名の比較
+ // Compare Human68k path name
return Compare(m_szHuman, m_szHuman + n, szHuman, szHuman + n) == 0;
}
//---------------------------------------------------------------------------
//
-/// ファイル名を検索
+/// Find file name
///
-/// 所有するキャシュバッファの中から検索し、見つかればその名称を返す。
-/// パス名を除外しておくこと。
-/// 必ず上位で排他制御を行なうこと。
+/// Check if whether it is a perfect match with the cache buffer, and return the name if found.
+/// Path names are excempted.
+/// Make sure to lock from the top.
//
//---------------------------------------------------------------------------
const CHostFilename* CHostPath::FindFilename(const BYTE* szHuman, DWORD nHumanAttribute) const
{
ASSERT(szHuman);
- // 文字数計算
+ // Calulate number of chars
const BYTE* pFirst = szHuman;
size_t nLength = strlen((const char*)pFirst);
const BYTE* pLast = pFirst + nLength;
- // 所持している全てのファイル名の中から完全一致するものを検索
+ // Find something that matches perfectly with either of the stored file names
const ring_t* p = (ring_t*)m_cRing.Next();
for (; p != (ring_t*)&m_cRing; p = (ring_t*)p->r.Next()) {
- // 属性チェック
if (p->f.CheckAttribute(nHumanAttribute) == 0)
continue;
- // 文字数計算
+ // Calulate number of chars
const BYTE* pBufFirst = p->f.GetHuman();
const BYTE* pBufLast = p->f.GetHumanLast();
size_t nBufLength = pBufLast - pBufFirst;
- // 文字数チェック
+ // Check number of chars
if (nLength != nBufLength)
continue;
- // ファイル名チェック
+ // File name check
if (Compare(pFirst, pLast, pBufFirst, pBufLast) == 0)
return &p->f;
}
@@ -1466,11 +1430,11 @@ const CHostFilename* CHostPath::FindFilename(const BYTE* szHuman, DWORD nHumanAt
//---------------------------------------------------------------------------
//
-/// ファイル名を検索 (ワイルドカード対応)
+/// Find file name (with wildcard support)
///
-/// 所有するバッファの中から検索し、見つかればその名称を返す。
-/// パス名を除外しておくこと。
-/// 必ず上位で排他制御を行なうこと。
+/// Check if whether it is a perfect match with the cache buffer, and return the name if found.
+/// Path names are excempted.
+/// Make sure to lock from the top.
//
//---------------------------------------------------------------------------
const CHostFilename* CHostPath::FindFilenameWildcard(const BYTE* szHuman, DWORD nHumanAttribute, find_t* pFind) const
@@ -1478,23 +1442,23 @@ const CHostFilename* CHostPath::FindFilenameWildcard(const BYTE* szHuman, DWORD
ASSERT(szHuman);
ASSERT(pFind);
- // 検索ファイル名を本体とHuman68k拡張子に分ける
+ // Split the base file name and Human68k file extension
const BYTE* pFirst = szHuman;
const BYTE* pLast = pFirst + strlen((const char*)pFirst);
const BYTE* pExt = CHostFilename::SeparateExt(pFirst);
- // 開始地点へ移動
+ // Move to the start position
const ring_t* p = (ring_t*)m_cRing.Next();
if (pFind->count > 0) {
if (pFind->id == m_nId) {
- // ディレクトリエントリが同一なら、前回の位置から即継続
+ // If the same directory entry, continue right away from the previous position
p = pFind->pos;
} else {
- // 開始地点をディレクトリエントリ内容から検索する
+ // Find the start position in the directory entry contents
DWORD n = 0;
for (;; p = (ring_t*)p->r.Next()) {
if (p == (ring_t*)&m_cRing) {
- // 同一エントリが見つからなかった場合、回数から推定 (念のため)
+ // Extrapolate from the count when the same entry isn't found (just in case)
p = (ring_t*)m_cRing.Next();
n = 0;
for (; p != (ring_t*)&m_cRing; p = (ring_t*)p->r.Next()) {
@@ -1505,7 +1469,7 @@ const CHostFilename* CHostPath::FindFilenameWildcard(const BYTE* szHuman, DWORD
break;
}
if (p->f.isSameEntry(&pFind->entry)) {
- // 同一エントリを発見
+ // Same entry is found
pFind->count = n;
break;
}
@@ -1514,28 +1478,27 @@ const CHostFilename* CHostPath::FindFilenameWildcard(const BYTE* szHuman, DWORD
}
}
- // ファイル検索
+ // Find files
for (; p != (ring_t*)&m_cRing; p = (ring_t*)p->r.Next()) {
pFind->count++;
- // 属性チェック
if (p->f.CheckAttribute(nHumanAttribute) == 0)
continue;
- // ファイル名を本体とHuman68k拡張子に分ける
+ // Split the base file name and Human68k file extension
const BYTE* pBufFirst = p->f.GetHuman();
const BYTE* pBufLast = p->f.GetHumanLast();
const BYTE* pBufExt = p->f.GetHumanExt();
- // 本体比較
+ // Compare base file name
if (Compare(pFirst, pExt, pBufFirst, pBufExt))
continue;
- // Human68k拡張子比較
- // 拡張子.???の場合は、Human68k拡張子のピリオドなしにもマッチさせる
+ // Compare Human68k extension
+ // In the case of a '.???' extension, match the Human68k extension without period.
if (strcmp((const char*)pExt, ".???") == 0 ||
Compare(pExt, pLast, pBufExt, pBufLast) == 0) {
- // 次の候補のディレクトリエントリ内容を記録
+ // Store the contents of the next candidate's directory entry
const ring_t* pNext = (ring_t*)p->r.Next();
pFind->id = m_nId;
pFind->pos = pNext;
@@ -1555,7 +1518,7 @@ const CHostFilename* CHostPath::FindFilenameWildcard(const BYTE* szHuman, DWORD
//---------------------------------------------------------------------------
//
-/// ファイル変更が行なわれたか確認
+/// Confirm that the file update has been carried out
//
//---------------------------------------------------------------------------
BOOL CHostPath::isRefresh()
@@ -1566,7 +1529,7 @@ BOOL CHostPath::isRefresh()
//---------------------------------------------------------------------------
//
-/// ASCIIソート関数
+/// ASCII sort function
//
//---------------------------------------------------------------------------
int AsciiSort(const dirent **a, const dirent **b)
@@ -1576,31 +1539,31 @@ int AsciiSort(const dirent **a, const dirent **b)
//---------------------------------------------------------------------------
//
-/// ファイル再構成
+/// Reconstruct the file
///
-/// ここで初めて、ホスト側のファイルシステムの観測が行なわれる。
-/// 必ず上位で排他制御を行なうこと。
+/// Here we carry out the first host side file system observation.
+/// Always lock from the top.
//
//---------------------------------------------------------------------------
void CHostPath::Refresh()
{
ASSERT(strlen(m_szHost) + 22 < FILEPATH_MAX);
- // タイムスタンプ保存
+ // Store time stamp
Backup();
TCHAR szPath[FILEPATH_MAX];
strcpy(szPath, m_szHost);
- // 更新フラグ変更
+ // Update refresh flag
m_bRefresh = FALSE;
- // 以前のキャッシュ内容を保存
+ // Store previous cache contents
CRing cRingBackup;
m_cRing.InsertRing(&cRingBackup);
- // ファイル名登録
- /// @todo ファイル重複処理をホスト側APIを経由せずに全て自前で処理する。
+ // Register file name
+ /// TODO: Process file duplication by ourselves rather than using the host API.
BOOL bUpdate = FALSE;
struct dirent **pd = NULL;
int nument = 0;
@@ -1616,7 +1579,7 @@ void CHostPath::Refresh()
maxent = nument;
}
- // 最上位ディレクトリならカレントとパレントを対象外とする
+ // When at the top level directory, exclude current and parent
struct dirent* pe = pd[i];
if (m_szHuman[0] == '/' && m_szHuman[1] == 0) {
if (strcmp(pe->d_name, ".") == 0 || strcmp(pe->d_name, "..") == 0) {
@@ -1624,60 +1587,60 @@ void CHostPath::Refresh()
}
}
- // ファイル名を獲得
+ // Get file name
strcpy(szFilename, U2S(pe->d_name));
- // ファイル名領域確保
+ // Allocate file name memory
ring_t* pRing = Alloc(strlen(szFilename));
CHostFilename* pFilename = &pRing->f;
pFilename->SetHost(szFilename);
- // 以前のキャッシュ内容に該当するファイル名があればそのHuman68k名称を優先する
+ // If there is a relevant file name in the previous cache, prioritize that for the Human68k name
ring_t* pCache = (ring_t*)cRingBackup.Next();
for (;;) {
if (pCache == (ring_t*)&cRingBackup) {
- pCache = NULL; // 該当するエントリなし
- bUpdate = TRUE; // 新規エントリと確定
+ pCache = NULL; // No relevant entry
+ bUpdate = TRUE; // Confirm new entry
pFilename->ConvertHuman();
break;
}
if (strcmp(pFilename->GetHost(), pCache->f.GetHost()) == 0) {
- pFilename->CopyHuman(pCache->f.GetHuman()); // Human68k名称のコピー
+ pFilename->CopyHuman(pCache->f.GetHuman()); // Copy Human68k name
break;
}
pCache = (ring_t*)pCache->r.Next();
}
- // 新規エントリの場合はファイル名重複をチェックする
- // ホスト側のファイル名から変更があったか、Human68kで表現できないファイル名の場合は
- // 以下のチェックを全てパスするファイル名を新たに生成する
- // ・正しいファイル名であること
- // ・過去のエントリに同名のものが存在しないこと
- // ・同名の実ファイル名が存在しないこと
- if (pFilename->isReduce() || !pFilename->isCorrect()) { // ファイル名変更が必要か確認
+ // If there is a new entry, carry out file name duplication check.
+ // If the host side file name changed, or if Human68k cannot express the file name,
+ // generate a new file name that passes all the below checks:
+ // - File name correctness
+ // - No duplicated names in previous entries
+ // - No entity with the same name exists
+ if (pFilename->isReduce() || !pFilename->isCorrect()) { // Confirm that file name update is required
for (DWORD n = 0; n < XM6_HOST_FILENAME_PATTERN_MAX; n++) {
- // 正しいファイル名かどうか確認
+ // Confirm file name validity
if (pFilename->isCorrect()) {
- // 過去のエントリと一致するか確認
+ // Confirm match with previous entry
const CHostFilename* pCheck = FindFilename(pFilename->GetHuman());
if (pCheck == NULL) {
- // 一致するものがなければ、実ファイルが存在するか確認
+ // If no match, confirm existence of real file
strcpy(szPath, m_szHost);
- strcat(szPath, (const char*)pFilename->GetHuman()); /// @warning Unicode時要修正 → 済
+ strcat(szPath, (const char*)pFilename->GetHuman());
struct stat sb;
if (stat(S2U(szPath), &sb))
- break; // 利用可能パターンを発見
+ break; // Discover available patterns
}
}
- // 新しい名前を生成
+ // Generate new name
pFilename->ConvertHuman(n);
}
}
- // ディレクトリエントリ名称
+ // Directory entry name
pFilename->SetEntryName();
- // 情報取得
+ // Get data
strcpy(szPath, m_szHost);
strcat(szPath, U2S(pe->d_name));
@@ -1685,7 +1648,6 @@ void CHostPath::Refresh()
if (stat(S2U(szPath), &sb))
continue;
- // 属性
BYTE nHumanAttribute = Human68k::AT_ARCHIVE;
if (S_ISDIR(sb.st_mode))
nHumanAttribute = Human68k::AT_DIRECTORY;
@@ -1693,11 +1655,9 @@ void CHostPath::Refresh()
nHumanAttribute |= Human68k::AT_READONLY;
pFilename->SetEntryAttribute(nHumanAttribute);
- // サイズ
DWORD nHumanSize = (DWORD)sb.st_size;
pFilename->SetEntrySize(nHumanSize);
- // 日付時刻
WORD nHumanDate = 0;
WORD nHumanTime = 0;
struct tm* pt = localtime(&sb.st_mtime);
@@ -1708,25 +1668,24 @@ void CHostPath::Refresh()
pFilename->SetEntryDate(nHumanDate);
pFilename->SetEntryTime(nHumanTime);
- // クラスタ番号設定
pFilename->SetEntryCluster(0);
- // 以前のキャッシュ内容と比較
+ // Compare with previous cached contents
if (pCache) {
if (pCache->f.isSameEntry(pFilename->GetEntry())) {
- Free(pRing); // 今回作成したエントリは破棄し
- pRing = pCache; // 以前のキャッシュ内容を使う
+ Free(pRing); // Destroy entry that was created here
+ pRing = pCache; // Use previous cache
} else {
- Free(pCache); // 次回の検索対象から除外
- bUpdate = TRUE; // 一致しなければ更新あり
+ Free(pCache); // Remove from the next search target
+ bUpdate = TRUE; // Flag for update if no match
}
}
- // リング末尾へ追加
+ // Add to end of ring
pRing->r.InsertTail(&m_cRing);
}
- // ディレクトリエントリを解放
+ // Release directory entry
if (pd) {
for (int i = 0; i < nument; i++) {
free(pd[i]);
@@ -1734,14 +1693,14 @@ void CHostPath::Refresh()
free(pd);
}
- // 残存するキャッシュ内容を削除
+ // Delete remaining cache
ring_t* p;
while ((p = (ring_t*)cRingBackup.Next()) != (ring_t*)&cRingBackup) {
- bUpdate = TRUE; // 削除によってエントリ数の減少が判明
+ bUpdate = TRUE; // Confirms the decrease in entries due to deletion
Free(p);
}
- // 更新が行なわれたら識別IDを変更
+ // Update the identifier if the update has been carried out
if (bUpdate)
m_nId = ++g_nId;
// ASSERT(m_nId);
@@ -1749,7 +1708,7 @@ void CHostPath::Refresh()
//---------------------------------------------------------------------------
//
-/// ホスト側のタイムスタンプを保存
+/// Store the host side time stamp
//
//---------------------------------------------------------------------------
void CHostPath::Backup()
@@ -1762,7 +1721,7 @@ void CHostPath::Backup()
size_t len = strlen(szPath);
m_tBackup = 0;
- if (len > 1) { // ルートディレクトリの場合は何もしない
+ if (len > 1) { // Don't do anything if it is the root directory
len--;
ASSERT(szPath[len] == _T('/'));
szPath[len] = _T('\0');
@@ -1774,7 +1733,7 @@ void CHostPath::Backup()
//---------------------------------------------------------------------------
//
-/// ホスト側のタイムスタンプを復元
+/// Restore the host side time stamp
//
//---------------------------------------------------------------------------
void CHostPath::Restore() const
@@ -1801,7 +1760,7 @@ void CHostPath::Restore() const
//---------------------------------------------------------------------------
//
-/// 更新
+/// Update
//
//---------------------------------------------------------------------------
void CHostPath::Release()
@@ -1812,15 +1771,10 @@ void CHostPath::Release()
//===========================================================================
//
-// ディレクトリエントリ管理
+// Manage directory entries
//
//===========================================================================
-//---------------------------------------------------------------------------
-//
-/// デフォルトコンストラクタ
-//
-//---------------------------------------------------------------------------
CHostEntry::CHostEntry()
{
for (size_t n = 0; n < DriveMax; n++) {
@@ -1830,17 +1784,12 @@ CHostEntry::CHostEntry()
m_nTimeout = 0;
}
-//---------------------------------------------------------------------------
-//
-/// デストラクタ final
-//
-//---------------------------------------------------------------------------
CHostEntry::~CHostEntry()
{
Clean();
#ifdef _DEBUG
- // オブジェクト確認
+ // Confirm object
for (size_t n = 0; n < DriveMax; n++) {
ASSERT(m_pDrv[n] == NULL);
}
@@ -1849,14 +1798,14 @@ CHostEntry::~CHostEntry()
//---------------------------------------------------------------------------
//
-/// 初期化 (ドライバ組込み時)
+/// Initialize (when the driver is installed)
//
//---------------------------------------------------------------------------
void CHostEntry::Init()
{
#ifdef _DEBUG
- // オブジェクト確認
+ // Confirm object
for (size_t n = 0; n < DriveMax; n++) {
ASSERT(m_pDrv[n] == NULL);
}
@@ -1865,13 +1814,13 @@ void CHostEntry::Init()
//---------------------------------------------------------------------------
//
-/// 解放 (起動・リセット時)
+/// Release (at startup and reset)
//
//---------------------------------------------------------------------------
void CHostEntry::Clean()
{
- // オブジェクト削除
+ // Delete object
for (size_t n = 0; n < DriveMax; n++) {
delete m_pDrv[n];
m_pDrv[n] = NULL;
@@ -1880,7 +1829,7 @@ void CHostEntry::Clean()
//---------------------------------------------------------------------------
//
-/// 全てのキャッシュを更新する
+/// Update all cache
//
//---------------------------------------------------------------------------
void CHostEntry::CleanCache()
@@ -1896,7 +1845,7 @@ void CHostEntry::CleanCache()
//---------------------------------------------------------------------------
//
-/// 指定されたユニットのキャッシュを更新する
+/// Update the cache for the specified unit
//
//---------------------------------------------------------------------------
void CHostEntry::CleanCache(DWORD nUnit)
@@ -1909,7 +1858,7 @@ void CHostEntry::CleanCache(DWORD nUnit)
//---------------------------------------------------------------------------
//
-/// 指定されたパスのキャッシュを更新する
+/// Update the cache for the specified path
//
//---------------------------------------------------------------------------
void CHostEntry::CleanCache(DWORD nUnit, const BYTE* szHumanPath)
@@ -1923,7 +1872,7 @@ void CHostEntry::CleanCache(DWORD nUnit, const BYTE* szHumanPath)
//---------------------------------------------------------------------------
//
-/// 指定されたパス以下のキャッシュを全て更新する
+/// Update all cache for the specified path and below
//
//---------------------------------------------------------------------------
void CHostEntry::CleanCacheChild(DWORD nUnit, const BYTE* szHumanPath)
@@ -1937,7 +1886,7 @@ void CHostEntry::CleanCacheChild(DWORD nUnit, const BYTE* szHumanPath)
//---------------------------------------------------------------------------
//
-/// 指定されたパスのキャッシュを削除する
+/// Delete cache for the specified path
//
//---------------------------------------------------------------------------
void CHostEntry::DeleteCache(DWORD nUnit, const BYTE* szHumanPath)
@@ -1951,7 +1900,7 @@ void CHostEntry::DeleteCache(DWORD nUnit, const BYTE* szHumanPath)
//---------------------------------------------------------------------------
//
-/// ホスト側の名称を検索 (パス名+ファイル名(省略可)+属性)
+/// Find host side names (path name + file name (can be abbreviated) + attribute)
//
//---------------------------------------------------------------------------
BOOL CHostEntry::Find(DWORD nUnit, CHostFiles* pFiles)
@@ -1967,7 +1916,7 @@ void CHostEntry::ShellNotify(DWORD, const TCHAR*) {}
//---------------------------------------------------------------------------
//
-/// ドライブ設定
+/// Drive settings
//
//---------------------------------------------------------------------------
void CHostEntry::SetDrv(DWORD nUnit, CHostDrv* pDrv)
@@ -1980,7 +1929,7 @@ void CHostEntry::SetDrv(DWORD nUnit, CHostDrv* pDrv)
//---------------------------------------------------------------------------
//
-/// 書き込み禁止か?
+/// Is it write-protected?
//
//---------------------------------------------------------------------------
BOOL CHostEntry::isWriteProtect(DWORD nUnit) const
@@ -1993,7 +1942,7 @@ BOOL CHostEntry::isWriteProtect(DWORD nUnit) const
//---------------------------------------------------------------------------
//
-/// アクセス可能か?
+/// Is it accessible?
//
//---------------------------------------------------------------------------
BOOL CHostEntry::isEnable(DWORD nUnit) const
@@ -2006,7 +1955,7 @@ BOOL CHostEntry::isEnable(DWORD nUnit) const
//---------------------------------------------------------------------------
//
-/// メディアチェック
+/// Media check
//
//---------------------------------------------------------------------------
BOOL CHostEntry::isMediaOffline(DWORD nUnit)
@@ -2019,7 +1968,7 @@ BOOL CHostEntry::isMediaOffline(DWORD nUnit)
//---------------------------------------------------------------------------
//
-/// メディアバイトの取得
+/// Get media byte
//
//---------------------------------------------------------------------------
BYTE CHostEntry::GetMediaByte(DWORD nUnit) const
@@ -2032,7 +1981,7 @@ BYTE CHostEntry::GetMediaByte(DWORD nUnit) const
//---------------------------------------------------------------------------
//
-/// ドライブ状態の取得
+/// Get drive status
//
//---------------------------------------------------------------------------
DWORD CHostEntry::GetStatus(DWORD nUnit) const
@@ -2045,7 +1994,7 @@ DWORD CHostEntry::GetStatus(DWORD nUnit) const
//---------------------------------------------------------------------------
//
-/// メディア交換チェック
+/// Media change check
//
//---------------------------------------------------------------------------
BOOL CHostEntry::CheckMedia(DWORD nUnit)
@@ -2058,7 +2007,7 @@ BOOL CHostEntry::CheckMedia(DWORD nUnit)
//---------------------------------------------------------------------------
//
-/// イジェクト
+/// Eject
//
//---------------------------------------------------------------------------
void CHostEntry::Eject(DWORD nUnit)
@@ -2071,7 +2020,7 @@ void CHostEntry::Eject(DWORD nUnit)
//---------------------------------------------------------------------------
//
-/// ボリュームラベルの取得
+/// Get volume label
//
//---------------------------------------------------------------------------
void CHostEntry::GetVolume(DWORD nUnit, TCHAR* szLabel)
@@ -2084,7 +2033,7 @@ void CHostEntry::GetVolume(DWORD nUnit, TCHAR* szLabel)
//---------------------------------------------------------------------------
//
-/// キャッシュからボリュームラベルを取得
+/// Get volume label from cache
//
//---------------------------------------------------------------------------
BOOL CHostEntry::GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const
@@ -2097,7 +2046,7 @@ BOOL CHostEntry::GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const
//---------------------------------------------------------------------------
//
-/// 容量の取得
+/// Get capacity
//
//---------------------------------------------------------------------------
DWORD CHostEntry::GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity)
@@ -2110,7 +2059,7 @@ DWORD CHostEntry::GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity)
//---------------------------------------------------------------------------
//
-/// キャッシュからクラスタサイズを取得
+/// Get cluster size from cache
//
//---------------------------------------------------------------------------
BOOL CHostEntry::GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity) const
@@ -2123,13 +2072,13 @@ BOOL CHostEntry::GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity)
//---------------------------------------------------------------------------
//
-/// Human68kフルパス名から先頭の要素を分離・コピー
+/// Split and copy the first element from the Human68k full path name
///
-/// Human68kフルパス名の先頭の要素をパス区切り文字を除外して取得する。
-/// 書き込み先バッファは23バイト必要。
-/// Human68kパスは必ず/で開始すること。
-/// 途中/が2つ以上連続して出現した場合はエラーとする。
-/// 文字列終端が/だけの場合は空の文字列として処理し、エラーにはしない。
+/// Get the first element from the Human68k full path name and delete the path separator char.
+/// 23 bytes is required in the buffer to write to.
+/// A Human68k path always starts with a '/'.
+/// Throw an error if 2 '/' appears in sequence.
+/// If the array ends with a '/' treat it as an empty array and don't trow an error.
//
//---------------------------------------------------------------------------
const BYTE* CHostDrv::SeparateCopyFilename(const BYTE* szHuman, BYTE* szBuffer) // static
@@ -2140,60 +2089,55 @@ const BYTE* CHostDrv::SeparateCopyFilename(const BYTE* szHuman, BYTE* szBuffer)
const size_t nMax = 22;
const BYTE* p = szHuman;
- BYTE c = *p++; // 読み込み
+ BYTE c = *p++; // Read
if (c != '/' && c != '\\')
- return NULL; // エラー: 不正なパス名
+ return NULL; // Error: Invalid path name
- // ファイルいっこいれる
+ // Insert one file
size_t i = 0;
for (;;) {
- c = *p; // 読み込み
+ c = *p; // Read
if (c == '\0')
- break; // 文字列終端なら終了 (終端位置を返す)
+ break; // Exit if at the end of an array (return the end position)
if (c == '/' || c == '\\') {
if (i == 0)
- return NULL; // エラー: パス区切り文字が連続している
- break; // パスの区切りを読んだら終了 (文字の位置を返す)
+ return NULL; // Error: Two separator chars appear in sequence
+ break; // Exit after reading the separator (return the char position)
}
p++;
if (i >= nMax)
- return NULL; // エラー: 1バイト目がバッファ終端にかかる
- szBuffer[i++] = c; // 書き込み
+ return NULL; // Error: The first byte hits the end of the buffer
+ szBuffer[i++] = c; // Read
- if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // 厳密には0x81~0x9Fと0xE0~0xEF
- c = *p++; // 読み込み
+ if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // Specifically 0x81~0x9F and 0xE0~0xEF
+ c = *p++; // Read
if (c < 0x40)
- return NULL; // エラー: 不正なSJIS2バイト目
+ return NULL; // Error: Invalid Shift-JIS 2nd byte
if (i >= nMax)
- return NULL; // エラー: 2バイト目がバッファ終端にかかる
- szBuffer[i++] = c; // 書き込み
+ return NULL; // Error: The second byte hits the end of the buffer
+ szBuffer[i++] = c; // Read
}
}
- szBuffer[i] = '\0'; // 書き込み
+ szBuffer[i] = '\0'; // Read
return p;
}
//===========================================================================
//
-// ファイル検索処理
+// File search processing
//
//===========================================================================
-//---------------------------------------------------------------------------
-//
-/// 初期化
-//
-//---------------------------------------------------------------------------
void CHostFiles::Init()
{
}
//---------------------------------------------------------------------------
//
-/// パス名・ファイル名を内部で生成
+/// Generate path and file name internally
//
//---------------------------------------------------------------------------
void CHostFiles::SetPath(const Human68k::namests_t* pNamests)
@@ -2209,7 +2153,7 @@ void CHostFiles::SetPath(const Human68k::namests_t* pNamests)
//---------------------------------------------------------------------------
//
-/// Human68k側でファイルを検索しホスト側の情報を生成
+/// Find file on the Human68k side and create data on the host side
//
//---------------------------------------------------------------------------
BOOL CHostFiles::Find(DWORD nUnit, CHostEntry* pEntry)
@@ -2221,7 +2165,7 @@ BOOL CHostFiles::Find(DWORD nUnit, CHostEntry* pEntry)
//---------------------------------------------------------------------------
//
-/// ファイル名検索
+/// Find file name
//
//---------------------------------------------------------------------------
const CHostFilename* CHostFiles::Find(CHostPath* pPath)
@@ -2236,23 +2180,23 @@ const CHostFilename* CHostFiles::Find(CHostPath* pPath)
//---------------------------------------------------------------------------
//
-/// Human68k側の検索結果保存
+/// Store the Human68k side search results
//
//---------------------------------------------------------------------------
void CHostFiles::SetEntry(const CHostFilename* pFilename)
{
ASSERT(pFilename);
- // Human68kディレクトリエントリ保存
+ // Store Human68k directory entry
memcpy(&m_dirHuman, pFilename->GetEntry(), sizeof(m_dirHuman));
- // Human68kファイル名保存
+ // Stire Human68k file name
strcpy((char*)m_szHumanResult, (const char*)pFilename->GetHuman());
}
//---------------------------------------------------------------------------
//
-/// ホスト側の名称を設定
+/// Set host side name
//
//---------------------------------------------------------------------------
void CHostFiles::SetResult(const TCHAR* szPath)
@@ -2265,7 +2209,7 @@ void CHostFiles::SetResult(const TCHAR* szPath)
//---------------------------------------------------------------------------
//
-/// ホスト側の名称にファイル名を追加
+/// Add file name to the host side name
//
//---------------------------------------------------------------------------
void CHostFiles::AddResult(const TCHAR* szPath)
@@ -2278,31 +2222,25 @@ void CHostFiles::AddResult(const TCHAR* szPath)
//---------------------------------------------------------------------------
//
-/// ホスト側の名称にHuman68kの新規ファイル名を追加
+/// Add a new Human68k file name to the host side name
//
//---------------------------------------------------------------------------
void CHostFiles::AddFilename()
{
ASSERT(strlen(m_szHostResult) + strlen((const char*)m_szHumanFilename) < FILEPATH_MAX);
- /// @warning Unicode未対応。いずれUnicodeの世界に飮まれた時はここで変換を行なう → 済
strncat(m_szHostResult, (const char*)m_szHumanFilename, ARRAY_SIZE(m_szHumanFilename));
}
//===========================================================================
//
-// ファイル検索領域 マネージャ
+// File search memory manager
//
//===========================================================================
#ifdef _DEBUG
-//---------------------------------------------------------------------------
-//
-/// デストラクタ final
-//
-//---------------------------------------------------------------------------
CHostFilesManager::~CHostFilesManager()
{
- // 実体が存在しないことを確認 (念のため)
+ // Confirm that the entity does not exist (just in case)
ASSERT(m_cRing.Next() == &m_cRing);
ASSERT(m_cRing.Prev() == &m_cRing);
}
@@ -2310,17 +2248,17 @@ CHostFilesManager::~CHostFilesManager()
//---------------------------------------------------------------------------
//
-/// 初期化 (ドライバ組込み時)
+/// Initialization (when the driver is installed)
//
//---------------------------------------------------------------------------
void CHostFilesManager::Init()
{
- // 実体が存在しないことを確認 (念のため)
+ // Confirm that the entity does not exist (just in case)
ASSERT(m_cRing.Next() == &m_cRing);
ASSERT(m_cRing.Prev() == &m_cRing);
- // メモリ確保
+ // Allocate memory
for (DWORD i = 0; i < XM6_HOST_FILES_MAX; i++) {
ring_t* p = new ring_t;
ASSERT(p);
@@ -2330,54 +2268,43 @@ void CHostFilesManager::Init()
//---------------------------------------------------------------------------
//
-/// 解放 (起動・リセット時)
+/// Release (at startup and reset)
//
//---------------------------------------------------------------------------
void CHostFilesManager::Clean()
{
- // メモリ解放
+ // Release memory
CRing* p;
while ((p = m_cRing.Next()) != &m_cRing) {
delete (ring_t*)p;
}
}
-//---------------------------------------------------------------------------
-//
-/// 確保
-//
-//---------------------------------------------------------------------------
CHostFiles* CHostFilesManager::Alloc(DWORD nKey)
{
ASSERT(nKey);
- // 末尾から選択
+ // Select from the end
ring_t* p = (ring_t*)m_cRing.Prev();
- // リング先頭へ移動
+ // Move to the start of the ring
p->r.Insert(&m_cRing);
- // キーを設定
p->f.SetKey(nKey);
return &p->f;
}
-//---------------------------------------------------------------------------
-//
-/// 検索
-//
-//---------------------------------------------------------------------------
CHostFiles* CHostFilesManager::Search(DWORD nKey)
{
- // ASSERT(nKey); // DPB破損により検索キーが0になることもある
+ // ASSERT(nKey); // The search key may become 0 due to DPB damage
- // 該当するオブジェクトを検索
+ // Find the relevant object
ring_t* p = (ring_t*)m_cRing.Next();
for (; p != (ring_t*)&m_cRing; p = (ring_t*)p->r.Next()) {
if (p->f.isSameKey(nKey)) {
- // リング先頭へ移動
+ // Move to the start of the ring
p->r.Insert(&m_cRing);
return &p->f;
}
@@ -2386,35 +2313,25 @@ CHostFiles* CHostFilesManager::Search(DWORD nKey)
return NULL;
}
-//---------------------------------------------------------------------------
-//
-/// 解放
-//
-//---------------------------------------------------------------------------
void CHostFilesManager::Free(CHostFiles* pFiles)
{
ASSERT(pFiles);
- // 解放
+ // Release
pFiles->SetKey(0);
pFiles->Init();
- // リング末尾へ移動
+ // Move to the end of the ring
ring_t* p = (ring_t*)((size_t)pFiles - offsetof(ring_t, f));
p->r.InsertTail(&m_cRing);
}
//===========================================================================
//
-// FCB処理
+// FCB processing
//
//===========================================================================
-//---------------------------------------------------------------------------
-//
-/// 初期化
-//
-//---------------------------------------------------------------------------
void CHostFcb::Init()
{
m_bUpdate = FALSE;
@@ -2423,7 +2340,7 @@ void CHostFcb::Init()
//---------------------------------------------------------------------------
//
-/// ファイルオープンモードを設定
+/// Set file open mode
//
//---------------------------------------------------------------------------
BOOL CHostFcb::SetMode(DWORD nHumanMode)
@@ -2447,11 +2364,6 @@ BOOL CHostFcb::SetMode(DWORD nHumanMode)
return TRUE;
}
-//---------------------------------------------------------------------------
-//
-/// ファイル名を設定
-//
-//---------------------------------------------------------------------------
void CHostFcb::SetFilename(const TCHAR* szFilename)
{
ASSERT(szFilename);
@@ -2460,11 +2372,6 @@ void CHostFcb::SetFilename(const TCHAR* szFilename)
strcpy(m_szFilename, szFilename);
}
-//---------------------------------------------------------------------------
-//
-/// Human68kパス名を設定
-//
-//---------------------------------------------------------------------------
void CHostFcb::SetHumanPath(const BYTE* szHumanPath)
{
ASSERT(szHumanPath);
@@ -2475,9 +2382,9 @@ void CHostFcb::SetHumanPath(const BYTE* szHumanPath)
//---------------------------------------------------------------------------
//
-/// ファイル作成
+/// Create file
///
-/// エラーの時はFALSEを返す。
+/// Return FALSE if error is thrown.
//
//---------------------------------------------------------------------------
BOOL CHostFcb::Create(Human68k::fcb_t* pFcb, DWORD nHumanAttribute, BOOL bForce)
@@ -2486,24 +2393,24 @@ BOOL CHostFcb::Create(Human68k::fcb_t* pFcb, DWORD nHumanAttribute, BOOL bForce)
ASSERT(strlen(m_szFilename) > 0);
ASSERT(m_pFile == NULL);
- // 重複チェック
+ // Duplication check
if (bForce == FALSE) {
struct stat sb;
if (stat(S2U(m_szFilename), &sb) == 0)
return FALSE;
}
- // ファイル作成
- m_pFile = fopen(S2U(m_szFilename), "w+b"); /// @warning 理想動作は属性ごと上書き
+ // Create file
+ m_pFile = fopen(S2U(m_szFilename), "w+b"); /// @warning The ideal operation is to overwrite each attribute
return m_pFile != NULL;
}
//---------------------------------------------------------------------------
//
-/// ファイルオープン
+/// File open
///
-/// エラーの時はFALSEを返す。
+/// Return FALSE if error is thrown.
//
//---------------------------------------------------------------------------
BOOL CHostFcb::Open()
@@ -2512,14 +2419,14 @@ BOOL CHostFcb::Open()
ASSERT(strlen(m_szFilename) > 0);
- // ディレクトリなら失敗
+ // Fail if directory
if (stat(S2U(m_szFilename), &st) == 0) {
if ((st.st_mode & S_IFMT) == S_IFDIR) {
return FALSE || m_bFlag;
}
}
- // ファイルオープン
+ // File open
if (m_pFile == NULL)
m_pFile = fopen(S2U(m_szFilename), m_pszMode);
@@ -2528,9 +2435,9 @@ BOOL CHostFcb::Open()
//---------------------------------------------------------------------------
//
-/// ファイルシーク
+/// File seek
///
-/// エラーの時はFALSEを返す。
+/// Return FALSE if error is thrown.
//
//---------------------------------------------------------------------------
BOOL CHostFcb::Rewind(DWORD nOffset)
@@ -2545,10 +2452,10 @@ BOOL CHostFcb::Rewind(DWORD nOffset)
//---------------------------------------------------------------------------
//
-/// ファイル読み込み
+/// Read file
///
-/// 0バイト読み込みでも正常動作とする。
-/// エラーの時は-1を返す。
+/// Handle a 0 byte read as normal operation too.
+/// Return -1 if error is thrown.
//
//---------------------------------------------------------------------------
DWORD CHostFcb::Read(BYTE* pBuffer, DWORD nSize)
@@ -2565,10 +2472,10 @@ DWORD CHostFcb::Read(BYTE* pBuffer, DWORD nSize)
//---------------------------------------------------------------------------
//
-/// ファイル書き込み
+/// Write file
///
-/// 0バイト書き込みでも正常動作とする。
-/// エラーの時は-1を返す。
+/// Handle a 0 byte read as normal operation too.
+/// Return -1 if error is thrown.
//
//---------------------------------------------------------------------------
DWORD CHostFcb::Write(const BYTE* pBuffer, DWORD nSize)
@@ -2585,9 +2492,9 @@ DWORD CHostFcb::Write(const BYTE* pBuffer, DWORD nSize)
//---------------------------------------------------------------------------
//
-/// ファイル切り詰め
+/// Truncate file
///
-/// エラーの時はFALSEを返す。
+/// Return FALSE if error is thrown.
//
//---------------------------------------------------------------------------
BOOL CHostFcb::Truncate()
@@ -2599,9 +2506,9 @@ BOOL CHostFcb::Truncate()
//---------------------------------------------------------------------------
//
-/// ファイルシーク
+/// File seek
///
-/// エラーの時は-1を返す。
+/// Return -1 if error is thrown.
//
//---------------------------------------------------------------------------
DWORD CHostFcb::Seek(DWORD nOffset, DWORD nHumanSeek)
@@ -2631,9 +2538,9 @@ DWORD CHostFcb::Seek(DWORD nOffset, DWORD nHumanSeek)
//---------------------------------------------------------------------------
//
-/// ファイル時刻設定
+/// Set file time stamp
///
-/// エラーの時はFALSEを返す。
+/// Return FALSE if error is thrown.
//
//---------------------------------------------------------------------------
BOOL CHostFcb::TimeStamp(DWORD nHumanTime)
@@ -2654,8 +2561,8 @@ BOOL CHostFcb::TimeStamp(DWORD nHumanTime)
ut.actime = ti;
ut.modtime = ti;
- // クローズ時に更新時刻が上書きされるのを防止するため
- // タイムスタンプの更新前にフラッシュして同期させる
+ // This is for preventing the last updated time stamp to be overwritten upon closing.
+ // Flush and synchronize before updating the time stamp.
fflush(m_pFile);
return utime(S2U(m_szFilename), &ut) == 0 || m_bFlag;
@@ -2663,17 +2570,17 @@ BOOL CHostFcb::TimeStamp(DWORD nHumanTime)
//---------------------------------------------------------------------------
//
-/// ファイルクローズ
+/// File close
///
-/// エラーの時はFALSEを返す。
+/// Return FALSE if error is thrown.
//
//---------------------------------------------------------------------------
BOOL CHostFcb::Close()
{
BOOL bResult = TRUE;
- // ファイルクローズ
- // Close→Free(内部で再度Close)という流れもあるので必ず初期化すること。
+ // File close
+ // Always initialize because of the Close→Free (internally one more Close) flow.
if (m_pFile) {
fclose(m_pFile);
m_pFile = NULL;
@@ -2689,11 +2596,6 @@ BOOL CHostFcb::Close()
//===========================================================================
#ifdef _DEBUG
-//---------------------------------------------------------------------------
-//
-// Final destructor
-//
-//---------------------------------------------------------------------------
CHostFcbManager::~CHostFcbManager()
{
// Confirm that the entity does not exist (just in case)
@@ -2737,11 +2639,6 @@ void CHostFcbManager::Clean()
}
}
-//---------------------------------------------------------------------------
-//
-// Alloc
-//
-//---------------------------------------------------------------------------
CHostFcb* CHostFcbManager::Alloc(DWORD nKey)
{
ASSERT(nKey);
@@ -2764,11 +2661,6 @@ CHostFcb* CHostFcbManager::Alloc(DWORD nKey)
return &p->f;
}
-//---------------------------------------------------------------------------
-//
-// Search
-//
-//---------------------------------------------------------------------------
CHostFcb* CHostFcbManager::Search(DWORD nKey)
{
ASSERT(nKey);
@@ -2787,11 +2679,6 @@ CHostFcb* CHostFcbManager::Search(DWORD nKey)
return NULL;
}
-//---------------------------------------------------------------------------
-//
-// Free
-//
-//---------------------------------------------------------------------------
void CHostFcbManager::Free(CHostFcb* pFcb)
{
ASSERT(pFcb);
@@ -2813,11 +2700,6 @@ void CHostFcbManager::Free(CHostFcb* pFcb)
DWORD CFileSys::g_nOption; // File name conversion flag
-//---------------------------------------------------------------------------
-//
-// Default constructor
-//
-//---------------------------------------------------------------------------
CFileSys::CFileSys()
{
m_nHostSectorCount = 0;
@@ -2830,108 +2712,107 @@ CFileSys::CFileSys()
m_szBase[n][0] = _T('\0');
}
- // TwentyOneオプション監視初期化
+ // Initialize TwentyOne option monitoring
m_nKernel = 0;
m_nKernelSearch = 0;
- // 動作フラグ初期化
+ // Initialize operational flags
m_nOptionDefault = 0;
m_nOption = 0;
ASSERT(g_nOption == 0);
- // 登録したドライブ数は0
+ // Number of registered drives are 0
m_nUnits = 0;
}
//---------------------------------------------------------------------------
//
-/// リセット (全クローズ)
+/// Reset (close all)
//
//---------------------------------------------------------------------------
void CFileSys::Reset()
{
- // 仮想セクタ領域初期化
+ // Initialize virtual sectors
m_nHostSectorCount = 0;
memset(m_nHostSectorBuffer, 0, sizeof(m_nHostSectorBuffer));
- // ファイル検索領域 解放 (起動・リセット時)
+ // File search memory - release (on startup and reset)
m_cFiles.Clean();
- // FCB操作領域 解放 (起動・リセット時)
+ // FCB operation memory (on startup and reset)
m_cFcb.Clean();
- // ディレクトリエントリ 解放 (起動・リセット時)
+ // Directory entry - release (on startup and reset)
m_cEntry.Clean();
- // TwentyOneオプション監視初期化
+ // Initialize TwentyOne option monitoring
m_nKernel = 0;
m_nKernelSearch = 0;
- // 動作フラグ初期化
+ // Initialize operational flags
SetOption(m_nOptionDefault);
}
//---------------------------------------------------------------------------
//
-/// 初期化 (デバイス起動とロード)
+/// Initialize (device startup and load)
//
//---------------------------------------------------------------------------
void CFileSys::Init()
{
- // ファイル検索領域 初期化 (デバイス起動・ロード時)
+ // Initialize file search memory (device startup and load)
m_cFiles.Init();
- // FCB操作領域 初期化 (デバイス起動・ロード時)
+ // Initialize FCB operation memory (device startup and load)
m_cFcb.Init();
- // ディレクトリエントリ 初期化 (デバイス起動・ロード時)
+ // Initialize directory entries (device startup and load)
m_cEntry.Init();
- // パス個別設定の有無を判定
+ // Evaluate per-path setting validity
DWORD nDrives = m_nDrives;
if (nDrives == 0) {
- // 個別設定を使わずにルートディレクトリを使用する
+ // Use root directory instead of per-path settings
strcpy(m_szBase[0], _T("/"));
m_nFlag[0] = 0;
nDrives++;
}
- // ファイルシステムを登録
+ // Register file system
DWORD nUnit = 0;
for (DWORD n = 0; n < nDrives; n++) {
- // ベースパスが存在しないエントリは登録しない
+ // Don't register is base path do not exist
if (m_szBase[n][0] == _T('\0'))
continue;
- // ファイルシステムを1ユニット生成
+ // Create 1 unit file system
CHostDrv* p = new CHostDrv; // std::nothrow
if (p) {
m_cEntry.SetDrv(nUnit, p);
p->Init(m_szBase[n], m_nFlag[n]);
- // 次のユニットへ
+ // To the next unit
nUnit++;
}
}
- // 登録したドライブ数を保存
+ // Store the registered number of drives
m_nUnits = nUnit;
}
//---------------------------------------------------------------------------
//
-/// $40 - デバイス起動
+/// $40 - Device startup
//
//---------------------------------------------------------------------------
DWORD CFileSys::InitDevice(const Human68k::argument_t* pArgument)
{
- // オプション初期化
InitOption(pArgument);
- // ファイルシステム初期化
+ // File system initialization
Init();
return m_nUnits;
@@ -2939,20 +2820,20 @@ DWORD CFileSys::InitDevice(const Human68k::argument_t* pArgument)
//---------------------------------------------------------------------------
//
-/// $41 - ディレクトリチェック
+/// $41 - Directory check
//
//---------------------------------------------------------------------------
int CFileSys::CheckDir(DWORD nUnit, const Human68k::namests_t* pNamests)
{
ASSERT(pNamests);
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
if (nUnit >= m_nUnits)
- return FS_INVALIDFUNC; // レジューム後に無効なドライブでmint操作時に白帯を出さないよう改良
+ return FS_INVALIDFUNC; // Avoid triggering a fatal error in mint when resuming with an invalid drive
- // パス名生成
+ // Generate path name
CHostFiles f;
f.SetPath(pNamests);
if (f.isRootPath())
@@ -2966,29 +2847,29 @@ int CFileSys::CheckDir(DWORD nUnit, const Human68k::namests_t* pNamests)
//---------------------------------------------------------------------------
//
-/// $42 - ディレクトリ作成
+/// $42 - Create directory
//
//---------------------------------------------------------------------------
int CFileSys::MakeDir(DWORD nUnit, const Human68k::namests_t* pNamests)
{
ASSERT(pNamests);
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
ASSERT(nUnit < m_nUnits);
if (nUnit >= m_nUnits)
- return FS_FATAL_MEDIAOFFLINE; // 念のため
+ return FS_FATAL_MEDIAOFFLINE; // Just in case
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
return FS_FATAL_MEDIAOFFLINE;
- // 書き込み禁止チェック
+ // Write-protect check
if (m_cEntry.isWriteProtect(nUnit))
return FS_FATAL_WRITEPROTECT;
- // パス名生成
+ // Generate path name
CHostFiles f;
f.SetPath(pNamests);
f.SetPathOnly();
@@ -2996,11 +2877,11 @@ int CFileSys::MakeDir(DWORD nUnit, const Human68k::namests_t* pNamests)
return FS_INVALIDPATH;
f.AddFilename();
- // ディレクトリ作成
+ // Create directory
if (mkdir(S2U(f.GetPath()), 0777))
return FS_INVALIDPATH;
- // キャッシュ更新
+ // Update cache
m_cEntry.CleanCache(nUnit, f.GetHumanPath());
return 0;
@@ -3008,36 +2889,36 @@ int CFileSys::MakeDir(DWORD nUnit, const Human68k::namests_t* pNamests)
//---------------------------------------------------------------------------
//
-/// $43 - ディレクトリ削除
+/// $43 - Delete directory
//
//---------------------------------------------------------------------------
int CFileSys::RemoveDir(DWORD nUnit, const Human68k::namests_t* pNamests)
{
ASSERT(pNamests);
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
ASSERT(nUnit < m_nUnits);
if (nUnit >= m_nUnits)
- return FS_FATAL_MEDIAOFFLINE; // 念のため
+ return FS_FATAL_MEDIAOFFLINE; // Just in case
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
return FS_FATAL_MEDIAOFFLINE;
- // 書き込み禁止チェック
+ // Write-protect check
if (m_cEntry.isWriteProtect(nUnit))
return FS_FATAL_WRITEPROTECT;
- // パス名生成
+ // Generate path name
CHostFiles f;
f.SetPath(pNamests);
f.SetAttribute(Human68k::AT_DIRECTORY);
if (f.Find(nUnit, &m_cEntry) == FALSE)
return FS_DIRNOTFND;
- // キャッシュ削除
+ // Delete cache
BYTE szHuman[HUMAN68K_PATH_MAX + 24];
ASSERT(strlen((const char*)f.GetHumanPath()) +
strlen((const char*)f.GetHumanFilename()) < HUMAN68K_PATH_MAX + 24);
@@ -3046,11 +2927,11 @@ int CFileSys::RemoveDir(DWORD nUnit, const Human68k::namests_t* pNamests)
strcat((char*)szHuman, "/");
m_cEntry.DeleteCache(nUnit, szHuman);
- // ディレクトリ削除
+ // Delete directory
if (rmdir(S2U(f.GetPath())))
return FS_CANTDELETE;
- // キャッシュ更新
+ // Update cache
m_cEntry.CleanCache(nUnit, f.GetHumanPath());
return 0;
@@ -3058,29 +2939,29 @@ int CFileSys::RemoveDir(DWORD nUnit, const Human68k::namests_t* pNamests)
//---------------------------------------------------------------------------
//
-/// $44 - ファイル名変更
+/// $44 - Change file name
//
//---------------------------------------------------------------------------
int CFileSys::Rename(DWORD nUnit, const Human68k::namests_t* pNamests, const Human68k::namests_t* pNamestsNew)
{
ASSERT(pNamests);
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
ASSERT(nUnit < m_nUnits);
if (nUnit >= m_nUnits)
- return FS_FATAL_MEDIAOFFLINE; // 念のため
+ return FS_FATAL_MEDIAOFFLINE; // Just in case
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
return FS_FATAL_MEDIAOFFLINE;
- // 書き込み禁止チェック
+ // Write-protect check
if (m_cEntry.isWriteProtect(nUnit))
return FS_FATAL_WRITEPROTECT;
- // パス名生成
+ // Generate path name
CHostFiles f;
f.SetPath(pNamests);
f.SetAttribute(Human68k::AT_ALL);
@@ -3094,11 +2975,11 @@ int CFileSys::Rename(DWORD nUnit, const Human68k::namests_t* pNamests, const Hum
return FS_INVALIDPATH;
fNew.AddFilename();
- // キャッシュ更新
+ // Update cache
if (f.GetAttribute() & Human68k::AT_DIRECTORY)
m_cEntry.CleanCacheChild(nUnit, f.GetHumanPath());
- // ファイル名変更
+ // Change file name
char szFrom[FILENAME_MAX];
char szTo[FILENAME_MAX];
SJIS2UTF8(f.GetPath(), szFrom, FILENAME_MAX);
@@ -3107,7 +2988,7 @@ int CFileSys::Rename(DWORD nUnit, const Human68k::namests_t* pNamests, const Hum
return FS_FILENOTFND;
}
- // キャッシュ更新
+ // Update cache
m_cEntry.CleanCache(nUnit, f.GetHumanPath());
m_cEntry.CleanCache(nUnit, fNew.GetHumanPath());
@@ -3116,39 +2997,39 @@ int CFileSys::Rename(DWORD nUnit, const Human68k::namests_t* pNamests, const Hum
//---------------------------------------------------------------------------
//
-/// $45 - ファイル削除
+/// $45 - Delete file
//
//---------------------------------------------------------------------------
int CFileSys::Delete(DWORD nUnit, const Human68k::namests_t* pNamests)
{
ASSERT(pNamests);
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
ASSERT(nUnit < m_nUnits);
if (nUnit >= m_nUnits)
- return FS_FATAL_MEDIAOFFLINE; // 念のため
+ return FS_FATAL_MEDIAOFFLINE; // Just in case
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
return FS_FATAL_MEDIAOFFLINE;
- // 書き込み禁止チェック
+ // Write-protect check
if (m_cEntry.isWriteProtect(nUnit))
return FS_FATAL_WRITEPROTECT;
- // パス名生成
+ // Generate path name
CHostFiles f;
f.SetPath(pNamests);
if (f.Find(nUnit, &m_cEntry) == FALSE)
return FS_FILENOTFND;
- // ファイル削除
+ // Delete file
if (unlink(S2U(f.GetPath())))
return FS_CANTDELETE;
- // キャッシュ更新
+ // Update cache
m_cEntry.CleanCache(nUnit, f.GetHumanPath());
return 0;
@@ -3156,43 +3037,43 @@ int CFileSys::Delete(DWORD nUnit, const Human68k::namests_t* pNamests)
//---------------------------------------------------------------------------
//
-/// $46 - ファイル属性取得/設定
+/// $46 - Get/set file attribute
//
//---------------------------------------------------------------------------
int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD nHumanAttribute)
{
ASSERT(pNamests);
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
if (nUnit >= m_nUnits)
- return FS_FATAL_MEDIAOFFLINE; // レジューム後に無効なドライブ上で発生
+ return FS_FATAL_MEDIAOFFLINE; // This occurs when resuming with an invalid drive
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
return FS_FATAL_MEDIAOFFLINE;
- // パス名生成
+ // Generate path name
CHostFiles f;
f.SetPath(pNamests);
f.SetAttribute(Human68k::AT_ALL);
if (f.Find(nUnit, &m_cEntry) == FALSE)
return FS_FILENOTFND;
- // 属性取得なら終了
+ // Exit if attribute is acquired
if (nHumanAttribute == 0xFF)
return f.GetAttribute();
- // 属性チェック
+ // Attribute check
if (nHumanAttribute & Human68k::AT_VOLUME)
return FS_CANTACCESS;
- // 書き込み禁止チェック
+ // Write-protect check
if (m_cEntry.isWriteProtect(nUnit))
return FS_FATAL_WRITEPROTECT;
- // 属性生成
+ // Generate attribute
DWORD nAttribute = (nHumanAttribute & Human68k::AT_READONLY) |
(f.GetAttribute() & ~Human68k::AT_READONLY);
if (f.GetAttribute() != nAttribute) {
@@ -3205,15 +3086,15 @@ int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD
else
m |= 0200; // u+w
- // 属性設定
+ // Set attribute
if (chmod(S2U(f.GetPath()), m))
return FS_FILENOTFND;
}
- // キャッシュ更新
+ // Update cache
m_cEntry.CleanCache(nUnit, f.GetHumanPath());
- // 変更後の属性取得
+ // Get attribute after changing
if (f.Find(nUnit, &m_cEntry) == FALSE)
return FS_FILENOTFND;
@@ -3222,7 +3103,7 @@ int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD
//---------------------------------------------------------------------------
//
-/// $47 - ファイル検索
+/// $47 - File search
//
//---------------------------------------------------------------------------
int CFileSys::Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::files_t* pFiles)
@@ -3231,49 +3112,48 @@ int CFileSys::Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests
ASSERT(nKey);
ASSERT(pFiles);
- // 既に同じキーを持つ領域があれば解放しておく
+ // Release if memory with the same key already exists
CHostFiles* pHostFiles = m_cFiles.Search(nKey);
if (pHostFiles != NULL) {
m_cFiles.Free(pHostFiles);
}
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
if (nUnit >= m_nUnits)
- return FS_FATAL_MEDIAOFFLINE; // レジューム後に無効なドライブ上で発生
+ return FS_FATAL_MEDIAOFFLINE; // This occurs when resuming with an invalid drive
- // ボリュームラベルの取得
+ // Get volume label
/** @note
- 直前のメディア交換チェックで正しくエラーを返しているにもかかわら
- ず、ボリュームラベルの取得を実行する行儀の悪いアプリでホスト側の
- リムーバブルメディア(CD-ROMドライブ等)が白帯を出すのを防ぐため、
- ボリュームラベルの取得はメディアチェックをせずに行なう仕様とした。
+ This skips the media check when getting the volume label to avoid triggering a fatal error
+ with host side removable media (CD-ROM, etc.) Some poorly coded applications will attempt to
+ get the volume label even though a proper error was thrown doing a media change check just before.
*/
if ((pFiles->fatr & (Human68k::AT_ARCHIVE | Human68k::AT_DIRECTORY | Human68k::AT_VOLUME))
== Human68k::AT_VOLUME) {
- // パスチェック
+ // Path check
CHostFiles f;
f.SetPath(pNamests);
if (f.isRootPath() == FALSE)
return FS_FILENOTFND;
- // バッファを確保せず、いきなり結果を返す
+ // Immediately return the results without allocating buffer
if (FilesVolume(nUnit, pFiles) == FALSE)
return FS_FILENOTFND;
return 0;
}
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
return FS_FATAL_MEDIAOFFLINE;
- // バッファ確保
+ // Allocate buffer
pHostFiles = m_cFiles.Alloc(nKey);
if (pHostFiles == NULL)
return FS_OUTOFMEM;
- // ディレクトリチェック
+ // Directory check
pHostFiles->SetPath(pNamests);
if (pHostFiles->isRootPath() == FALSE) {
pHostFiles->SetPathOnly();
@@ -3283,30 +3163,30 @@ int CFileSys::Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests
}
}
- // ワイルドカード使用可能に設定
+ // Enable wildcards
pHostFiles->SetPathWildcard();
pHostFiles->SetAttribute(pFiles->fatr);
- // ファイル検索
+ // Find file
if (pHostFiles->Find(nUnit, &m_cEntry) == FALSE) {
m_cFiles.Free(pHostFiles);
return FS_FILENOTFND;
}
- // 検索結果を格納
+ // Store search results
pFiles->attr = (BYTE)pHostFiles->GetAttribute();
pFiles->date = pHostFiles->GetDate();
pFiles->time = pHostFiles->GetTime();
pFiles->size = pHostFiles->GetSize();
strcpy((char*)pFiles->full, (const char*)pHostFiles->GetHumanResult());
- // 擬似ディレクトリエントリを指定
+ // Specify pseudo-directory entry
pFiles->sector = nKey;
pFiles->offset = 0;
- // ファイル名にワイルドカードがなければ、この時点でバッファを解放可能
+ // When the file name does not include wildcards, the buffer may be released
if (pNamests->wildcard == 0) {
- // しかし、仮想セクタのエミュレーションで使う可能性があるため、すぐには解放しない
+ // However, there is a chance the virtual selector may be used for emulation, so don't release immediately
// m_cFiles.Free(pHostFiles);
}
@@ -3315,7 +3195,7 @@ int CFileSys::Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests
//---------------------------------------------------------------------------
//
-/// $48 - ファイル次検索
+/// $48 - Search next file
//
//---------------------------------------------------------------------------
int CFileSys::NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles)
@@ -3323,22 +3203,22 @@ int CFileSys::NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles)
ASSERT(nKey);
ASSERT(pFiles);
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
if (nUnit >= m_nUnits)
- return FS_FATAL_MEDIAOFFLINE; // レジューム後に無効なドライブ上で発生
+ return FS_FATAL_MEDIAOFFLINE; // This occurs when resuming with an invalid drive
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
return FS_FATAL_MEDIAOFFLINE;
- // バッファ検索
+ // Find buffer
CHostFiles* pHostFiles = m_cFiles.Search(nKey);
if (pHostFiles == NULL)
return FS_INVALIDPTR;
- // ファイル検索
+ // Find file
if (pHostFiles->Find(nUnit, &m_cEntry) == FALSE) {
m_cFiles.Free(pHostFiles);
return FS_FILENOTFND;
@@ -3347,7 +3227,7 @@ int CFileSys::NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles)
ASSERT(pFiles->sector == nKey);
ASSERT(pFiles->offset == 0);
- // 検索結果を格納
+ // Store search results
pFiles->attr = (BYTE)pHostFiles->GetAttribute();
pFiles->date = pHostFiles->GetDate();
pFiles->time = pHostFiles->GetTime();
@@ -3359,7 +3239,7 @@ int CFileSys::NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles)
//---------------------------------------------------------------------------
//
-/// $49 - ファイル新規作成
+/// $49 - Create new file
//
//---------------------------------------------------------------------------
int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, DWORD nHumanAttribute, BOOL bForce)
@@ -3368,26 +3248,26 @@ int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamest
ASSERT(nKey);
ASSERT(pFcb);
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
ASSERT(nUnit < m_nUnits);
if (nUnit >= m_nUnits)
- return FS_FATAL_MEDIAOFFLINE; // 念のため
+ return FS_FATAL_MEDIAOFFLINE; // Just in case
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
return FS_FATAL_MEDIAOFFLINE;
- // 書き込み禁止チェック
+ // Write-protect check
if (m_cEntry.isWriteProtect(nUnit))
return FS_FATAL_WRITEPROTECT;
- // 既に同じキーを持つ領域があればエラーとする
+ // Release if memory with the same key already exists
if (m_cFcb.Search(nKey) != NULL)
return FS_INVALIDPTR;
- // パス名生成
+ // Generate path name
CHostFiles f;
f.SetPath(pNamests);
f.SetPathOnly();
@@ -3395,31 +3275,31 @@ int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamest
return FS_INVALIDPATH;
f.AddFilename();
- // 属性チェック
+ // Attribute check
if (nHumanAttribute & (Human68k::AT_DIRECTORY | Human68k::AT_VOLUME))
return FS_CANTACCESS;
- // パス名保存
+ // Store path name
CHostFcb* pHostFcb = m_cFcb.Alloc(nKey);
if (pHostFcb == NULL)
return FS_OUTOFMEM;
pHostFcb->SetFilename(f.GetPath());
pHostFcb->SetHumanPath(f.GetHumanPath());
- // オープンモード設定
+ // Set open mode
pFcb->mode = (WORD)((pFcb->mode & ~Human68k::OP_MASK) | Human68k::OP_FULL);
if (pHostFcb->SetMode(pFcb->mode) == FALSE) {
m_cFcb.Free(pHostFcb);
return FS_ILLEGALMOD;
}
- // ファイル作成
+ // Create file
if (pHostFcb->Create(pFcb, nHumanAttribute, bForce) == FALSE) {
m_cFcb.Free(pHostFcb);
return FS_FILEEXIST;
}
- // キャッシュ更新
+ // Update cache
m_cEntry.CleanCache(nUnit, f.GetHumanPath());
return 0;
@@ -3427,7 +3307,7 @@ int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamest
//---------------------------------------------------------------------------
//
-/// $4A - ファイルオープン
+/// $4A - File open
//
//---------------------------------------------------------------------------
int CFileSys::Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb)
@@ -3436,17 +3316,17 @@ int CFileSys::Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests,
ASSERT(nKey);
ASSERT(pFcb);
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
if (nUnit >= m_nUnits)
- return FS_FATAL_MEDIAOFFLINE; // レジューム後に無効なドライブ上で発生
+ return FS_FATAL_MEDIAOFFLINE; // This occurs when resuming with an invalid drive
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
return FS_FATAL_MEDIAOFFLINE;
- // 書き込み禁止チェック
+ // Write-protect check
switch (pFcb->mode & Human68k::OP_MASK) {
case Human68k::OP_WRITE:
case Human68k::OP_FULL:
@@ -3454,38 +3334,38 @@ int CFileSys::Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests,
return FS_FATAL_WRITEPROTECT;
}
- // 既に同じキーを持つ領域があればエラーとする
+ // Release if memory with the same key already exists
if (m_cFcb.Search(nKey) != NULL)
return FS_INVALIDPRM;
- // パス名生成
+ // Generate path name
CHostFiles f;
f.SetPath(pNamests);
f.SetAttribute(Human68k::AT_ALL);
if (f.Find(nUnit, &m_cEntry) == FALSE)
return FS_FILENOTFND;
- // タイムスタンプ
+ // Time stamp
pFcb->date = f.GetDate();
pFcb->time = f.GetTime();
- // ファイルサイズ
+ // File size
pFcb->size = f.GetSize();
- // パス名保存
+ // Store path name
CHostFcb* pHostFcb = m_cFcb.Alloc(nKey);
if (pHostFcb == NULL)
return FS_OUTOFMEM;
pHostFcb->SetFilename(f.GetPath());
pHostFcb->SetHumanPath(f.GetHumanPath());
- // オープンモード設定
+ // Set open mode
if (pHostFcb->SetMode(pFcb->mode) == FALSE) {
m_cFcb.Free(pHostFcb);
return FS_ILLEGALMOD;
}
- // ファイルオープン
+ // File open
if (pHostFcb->Open() == FALSE) {
m_cFcb.Free(pHostFcb);
return FS_INVALIDPATH;
@@ -3496,135 +3376,135 @@ int CFileSys::Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests,
//---------------------------------------------------------------------------
//
-/// $4B - ファイルクローズ
+/// $4B - File close
//
//---------------------------------------------------------------------------
int CFileSys::Close(DWORD nUnit, DWORD nKey, Human68k::fcb_t* /* pFcb */)
{
ASSERT(nKey);
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
if (nUnit >= m_nUnits)
- return FS_FATAL_MEDIAOFFLINE; // レジューム後に無効なドライブ上で発生
+ return FS_FATAL_MEDIAOFFLINE; // This occurs when resuming with an invalid drive
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
return FS_FATAL_MEDIAOFFLINE;
- // 既に同じキーを持つ領域がなければエラーとする
+ // Throw error if memory with the same key does not exist
CHostFcb* pHostFcb = m_cFcb.Search(nKey);
if (pHostFcb == NULL)
return FS_INVALIDPRM;
- // ファイルクローズと領域解放
+ // File close and release memory
m_cFcb.Free(pHostFcb);
- // キャッシュ更新
+ // Update cache
if (pHostFcb->isUpdate())
m_cEntry.CleanCache(nUnit, pHostFcb->GetHumanPath());
- /// @note クローズ時のFCBの状態を他のデバイスと合わせたい
+ /// TODO: Match the FCB status on close with other devices
return 0;
}
//---------------------------------------------------------------------------
//
-/// $4C - ファイル読み込み
+/// $4C - Read file
///
-/// 0バイト読み込みでも正常終了する。
+/// Clean exit when 0 bytes are read.
//
//---------------------------------------------------------------------------
int CFileSys::Read(DWORD nKey, Human68k::fcb_t* pFcb, BYTE* pBuffer, DWORD nSize)
{
ASSERT(nKey);
ASSERT(pFcb);
- // ASSERT(pBuffer); // 必要時のみ判定
- ASSERT(nSize <= 0xFFFFFF); // クリップ済
+ // ASSERT(pBuffer); // Evaluate only when needed
+ ASSERT(nSize <= 0xFFFFFF); // Clipped
- // 既に同じキーを持つ領域がなければエラーとする
+ // Throw error if memory with the same key does not exist
CHostFcb* pHostFcb = m_cFcb.Search(nKey);
if (pHostFcb == NULL)
return FS_NOTOPENED;
- // バッファ存在確認
+ // Confirm the existence of the buffer
if (pBuffer == NULL) {
m_cFcb.Free(pHostFcb);
return FS_INVALIDFUNC;
}
- // 読み込み
+ // Read
DWORD nResult;
nResult = pHostFcb->Read(pBuffer, nSize);
if (nResult == (DWORD)-1) {
m_cFcb.Free(pHostFcb);
- return FS_INVALIDFUNC; /// @note これに加えてエラーコード10(読み込みエラー)を返すべき
+ return FS_INVALIDFUNC; // TODO: Should return error code 10 (read error) as well here
}
ASSERT(nResult <= nSize);
- // ファイルポインタ更新
- pFcb->fileptr += nResult; /// @note オーバーフロー確認は必要じゃろうか?
+ // Update file pointer
+ pFcb->fileptr += nResult; /// TODO: Maybe an overflow check is needed here?
return nResult;
}
//---------------------------------------------------------------------------
//
-/// $4D - ファイル書き込み
+/// $4D - Write file
///
-/// 0バイト書き込みの場合はファイルを切り詰める。
+/// Truncate file if 0 bytes are written.
//
//---------------------------------------------------------------------------
int CFileSys::Write(DWORD nKey, Human68k::fcb_t* pFcb, const BYTE* pBuffer, DWORD nSize)
{
ASSERT(nKey);
ASSERT(pFcb);
- // ASSERT(pBuffer); // 必要時のみ判定
- ASSERT(nSize <= 0xFFFFFF); // クリップ済
+ // ASSERT(pBuffer); // Evaluate only when needed
+ ASSERT(nSize <= 0xFFFFFF); // Clipped
- // 既に同じキーを持つ領域がなければエラーとする
+ // Throw error if memory with the same key does not exist
CHostFcb* pHostFcb = m_cFcb.Search(nKey);
if (pHostFcb == NULL)
return FS_NOTOPENED;
DWORD nResult;
if (nSize == 0) {
- // 切り詰め
+ // Truncate
if (pHostFcb->Truncate() == FALSE) {
m_cFcb.Free(pHostFcb);
return FS_CANTSEEK;
}
- // ファイルサイズ更新
+ // Update file size
pFcb->size = pFcb->fileptr;
nResult = 0;
} else {
- // バッファ存在確認
+ // Confirm the existence of the buffer
if (pBuffer == NULL) {
m_cFcb.Free(pHostFcb);
return FS_INVALIDFUNC;
}
- // 書き込み
+ // Write
nResult = pHostFcb->Write(pBuffer, nSize);
if (nResult == (DWORD)-1) {
m_cFcb.Free(pHostFcb);
- return FS_CANTWRITE; /// @note これに加えてエラーコード11(書き込みエラー)を返すべき
+ return FS_CANTWRITE; /// TODO: Should return error code 11 (write error) as well here
}
ASSERT(nResult <= nSize);
- // ファイルポインタ更新
- pFcb->fileptr += nResult; /// @note オーバーフロー確認は必要じゃろうか?
+ // Update file pointer
+ pFcb->fileptr += nResult; /// TODO: Do we need an overflow check here?
- // ファイルサイズ更新
+ // Update file size
if (pFcb->size < pFcb->fileptr)
pFcb->size = pFcb->fileptr;
}
- // フラグ更新
+ // Update flag
pHostFcb->SetUpdate();
return nResult;
@@ -3632,32 +3512,32 @@ int CFileSys::Write(DWORD nKey, Human68k::fcb_t* pFcb, const BYTE* pBuffer, DWOR
//---------------------------------------------------------------------------
//
-/// $4E - ファイルシーク
+/// $4E - File seek
//
//---------------------------------------------------------------------------
int CFileSys::Seek(DWORD nKey, Human68k::fcb_t* pFcb, DWORD nSeek, int nOffset)
{
ASSERT(pFcb);
- // 既に同じキーを持つ領域がなければエラーとする
+ // Throw error if memory with the same key does not exist
CHostFcb* pHostFcb = m_cFcb.Search(nKey);
if (pHostFcb == NULL)
return FS_NOTOPENED;
- // パラメータチェック
+ // Parameter check
if (nSeek > Human68k::SK_END) {
m_cFcb.Free(pHostFcb);
return FS_INVALIDPRM;
}
- // ファイルシーク
+ // File seek
DWORD nResult = pHostFcb->Seek(nOffset, nSeek);
if (nResult == (DWORD)-1) {
m_cFcb.Free(pHostFcb);
return FS_CANTSEEK;
}
- // ファイルポインタ更新
+ // Update file pointer
pFcb->fileptr = nResult;
return nResult;
@@ -3665,9 +3545,9 @@ int CFileSys::Seek(DWORD nKey, Human68k::fcb_t* pFcb, DWORD nSeek, int nOffset)
//---------------------------------------------------------------------------
//
-/// $4F - ファイル時刻取得/設定
+/// $4F - Get/set file time stamp
///
-/// 結果の上位16Bitが$FFFFだとエラー。
+/// Throw error when the top 16 bits are $FFFF.
//
//---------------------------------------------------------------------------
DWORD CFileSys::TimeStamp(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb, DWORD nHumanTime)
@@ -3675,31 +3555,31 @@ DWORD CFileSys::TimeStamp(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb, DWORD
ASSERT(nKey);
ASSERT(pFcb);
- // 取得のみ
+ // Get only
if (nHumanTime == 0)
return ((DWORD)pFcb->date << 16) | pFcb->time;
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
ASSERT(nUnit < m_nUnits);
if (nUnit >= m_nUnits)
- return FS_FATAL_MEDIAOFFLINE; // 念のため
+ return FS_FATAL_MEDIAOFFLINE; // Just in case
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
return FS_FATAL_MEDIAOFFLINE;
- // 書き込み禁止チェック
+ // Write-protect check
if (m_cEntry.isWriteProtect(nUnit))
return FS_FATAL_WRITEPROTECT;
- // 既に同じキーを持つ領域がなければエラーとする
+ // Throw error if memory with the same key does not exist
CHostFcb* pHostFcb = m_cFcb.Search(nKey);
if (pHostFcb == NULL)
return FS_NOTOPENED;
- // 時刻設定
+ // Set time stamp
if (pHostFcb->TimeStamp(nHumanTime) == FALSE) {
m_cFcb.Free(pHostFcb);
return FS_INVALIDPRM;
@@ -3707,7 +3587,7 @@ DWORD CFileSys::TimeStamp(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb, DWORD
pFcb->date = (WORD)(nHumanTime >> 16);
pFcb->time = (WORD)nHumanTime;
- // キャッシュ更新
+ // Update cache
m_cEntry.CleanCache(nUnit, pHostFcb->GetHumanPath());
return 0;
@@ -3715,59 +3595,59 @@ DWORD CFileSys::TimeStamp(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb, DWORD
//---------------------------------------------------------------------------
//
-/// $50 - 容量取得
+/// $50 - Get capacity
//
//---------------------------------------------------------------------------
int CFileSys::GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity)
{
ASSERT(pCapacity);
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
ASSERT(nUnit < m_nUnits);
if (nUnit >= m_nUnits)
- return FS_FATAL_MEDIAOFFLINE; // 念のため
+ return FS_FATAL_MEDIAOFFLINE; // Just in case
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
return FS_FATAL_MEDIAOFFLINE;
- // 容量取得
+ // Get capacity
return m_cEntry.GetCapacity(nUnit, pCapacity);
}
//---------------------------------------------------------------------------
//
-/// $51 - ドライブ状態検査/制御
+/// $51 - Inspect/control drive status
//
//---------------------------------------------------------------------------
int CFileSys::CtrlDrive(DWORD nUnit, Human68k::ctrldrive_t* pCtrlDrive)
{
ASSERT(pCtrlDrive);
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
if (nUnit >= m_nUnits)
- return FS_INVALIDFUNC; // レジューム後に無効なドライブでmint操作時に白帯を出さないよう改良
+ return FS_INVALIDFUNC; // Avoid triggering a fatal error in mint when resuming with an invalid drive
switch (pCtrlDrive->status) {
- case 0: // 状態検査
- case 9: // 状態検査2
+ case 0: // Inspect status
+ case 9: // Inspect status 2
pCtrlDrive->status = (BYTE)m_cEntry.GetStatus(nUnit);
return pCtrlDrive->status;
- case 1: // イジェクト
- case 2: // イジェクト禁止1 (未実装)
- case 3: // イジェクト許可1 (未実装)
- case 4: // メディア未挿入時にLED点滅 (未実装)
- case 5: // メディア未挿入時にLED消灯 (未実装)
- case 6: // イジェクト禁止2 (未実装)
- case 7: // イジェクト許可2 (未実装)
+ case 1: // Eject
+ case 2: // Eject forbidden 1 (not implemented)
+ case 3: // Eject allowed 1 (not implemented)
+ case 4: // Flash LED when media is not inserted (not implemented)
+ case 5: // Turn off LED when media is not inserted (not implemented)
+ case 6: // Eject forbidden 2 (not implemented)
+ case 7: // Eject allowed 2 (not implemented)
return 0;
- case 8: // イジェクト検査
+ case 8: // Eject inspection
return 1;
}
@@ -3776,17 +3656,17 @@ int CFileSys::CtrlDrive(DWORD nUnit, Human68k::ctrldrive_t* pCtrlDrive)
//---------------------------------------------------------------------------
//
-/// $52 - DPB取得
+/// $52 - Get DPB
///
-/// レジューム後にDPBが取得できないとHuman68k内部でドライブが消滅するため、
-/// 範囲外のユニットでもとにかく正常系として処理する。
+/// If DPB cannot be acquired after resuming, the drive will be torn down internally in Human68k.
+/// Therefore, treat even a unit out of bounds as normal operation.
//
//---------------------------------------------------------------------------
int CFileSys::GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb)
{
ASSERT(pDpb);
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
@@ -3795,27 +3675,27 @@ int CFileSys::GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb)
if (nUnit < m_nUnits) {
media = m_cEntry.GetMediaByte(nUnit);
- // セクタ情報獲得
+ // Acquire sector data
if (m_cEntry.GetCapacityCache(nUnit, &cap) == FALSE) {
- // 手動イジェクトだとメディアチェックをすり抜けるためここで捕捉
+ // Carry out an extra media check here because it may be skipped when doing a manual eject
if (m_cEntry.isEnable(nUnit) == FALSE)
goto none;
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
goto none;
- // ドライブ状態取得
+ // Get drive status
m_cEntry.GetCapacity(nUnit, &cap);
}
} else {
none:
- cap.clusters = 4; // まっったく問題ないッスよ?
+ cap.clusters = 4; // This is totally fine, right?
cap.sectors = 64;
cap.bytes = 512;
}
- // シフト数計算
+ // Calculate number of shifts
DWORD nSize = 1;
DWORD nShift = 0;
for (;;) {
@@ -3825,102 +3705,102 @@ int CFileSys::GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb)
nShift++;
}
- // セクタ番号計算
+ // Sector number calculation
//
- // 以下の順に並べる。
- // クラスタ0: 未使用
- // クラスタ1: FAT
- // クラスタ2: ルートディレクトリ
- // クラスタ3: データ領域(擬似セクタ)
+ // In the following order:
+ // Cluster 0: Unused
+ // Cluster 1: FAT
+ // Cluster 2: Root directory
+ // Cluster 3: Data memory (pseudo-sector)
DWORD nFat = cap.sectors;
DWORD nRoot = cap.sectors * 2;
DWORD nData = cap.sectors * 3;
- // DPB設定
- pDpb->sector_size = (WORD)cap.bytes; // 1セクタ当りのバイト数
+ // Set DPB
+ pDpb->sector_size = (WORD)cap.bytes; // Bytes per sector
pDpb->cluster_size =
- (BYTE)(cap.sectors - 1); // 1クラスタ当りのセクタ数 - 1
- pDpb->shift = (BYTE)nShift; // クラスタ→セクタのシフト数
- pDpb->fat_sector = (WORD)nFat; // FAT の先頭セクタ番号
- pDpb->fat_max = 1; // FAT 領域の個数
- pDpb->fat_size = (BYTE)cap.sectors; // FAT の占めるセクタ数(複写分を除く)
+ (BYTE)(cap.sectors - 1); // Sectors per cluster - 1
+ pDpb->shift = (BYTE)nShift; // Number of cluster → sector shifts
+ pDpb->fat_sector = (WORD)nFat; // First FAT sector number
+ pDpb->fat_max = 1; // Number of FAT memory spaces
+ pDpb->fat_size = (BYTE)cap.sectors; // Number of sectors controlled by FAT (excluding copies)
pDpb->file_max =
- (WORD)(cap.sectors * cap.bytes / 0x20); // ルートディレクトリに入るファイルの個数
- pDpb->data_sector = (WORD)nData; // データ領域の先頭セクタ番号
- pDpb->cluster_max = (WORD)cap.clusters; // 総クラスタ数 + 1
- pDpb->root_sector = (WORD)nRoot; // ルートディレクトリの先頭セクタ番号
- pDpb->media = media; // メディアバイト
+ (WORD)(cap.sectors * cap.bytes / 0x20); // Number of files in the root directory
+ pDpb->data_sector = (WORD)nData; // First sector number of data memory
+ pDpb->cluster_max = (WORD)cap.clusters; // Total number of clusters + 1
+ pDpb->root_sector = (WORD)nRoot; // First sector number of the root directory
+ pDpb->media = media; // Media byte
return 0;
}
//---------------------------------------------------------------------------
//
-/// $53 - セクタ読み込み
+/// $53 - Read sector
///
-/// セクタは疑似的に構築したものを使用する。
-/// バッファサイズは$200バイト固定。
+/// We use pseudo-sectors.
+/// Buffer size is hard coded to $200 byte.
//
//---------------------------------------------------------------------------
int CFileSys::DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize)
{
ASSERT(pBuffer);
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
if (nUnit >= m_nUnits)
- return FS_FATAL_MEDIAOFFLINE; // レジューム後に無効なドライブ上で発生
+ return FS_FATAL_MEDIAOFFLINE; // This occurs when resuming with an invalid drive
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
return FS_FATAL_MEDIAOFFLINE;
- // セクタ数1以外の場合はエラー
+ // Throw error if number of sectors exceed 1
if (nSize != 1)
return FS_INVALIDPRM;
- // セクタ情報獲得
+ // Acquire sector data
Human68k::capacity_t cap;
if (m_cEntry.GetCapacityCache(nUnit, &cap) == FALSE) {
- // ドライブ状態取得
+ // Get drive status
m_cEntry.GetCapacity(nUnit, &cap);
}
- // 擬似ディレクトリエントリへのアクセス
+ // Access pseudo-directory entry
CHostFiles* pHostFiles = m_cFiles.Search(nSector);
if (pHostFiles) {
- // 擬似ディレクトリエントリを生成
+ // Generate pseudo-directory entry
Human68k::dirent_t* dir = (Human68k::dirent_t*)pBuffer;
memcpy(pBuffer, pHostFiles->GetEntry(), sizeof(*dir));
memset(pBuffer + sizeof(*dir), 0xE5, 0x200 - sizeof(*dir));
- // 擬似ディレクトリエントリ内にファイル実体を指す擬似セクタ番号を記録
- // なお、lzdsysでは以下の式で読み込みセクタ番号を算出している。
+ // Register the pseudo-sector number that points to the file entity inside the pseudo-directory.
+ // Note that in lzdsys the sector number to read is calculated by the following formula:
// (dirent.cluster - 2) * (dpb.cluster_size + 1) + dpb.data_sector
- /// @warning リトルエンディアン専用
- dir->cluster = (WORD)(m_nHostSectorCount + 2); // 擬似セクタ番号
- m_nHostSectorBuffer[m_nHostSectorCount] = nSector; // 擬似セクタの指す実体
+ /// @warning little endian only
+ dir->cluster = (WORD)(m_nHostSectorCount + 2); // Pseudo-sector number
+ m_nHostSectorBuffer[m_nHostSectorCount] = nSector; // Entity that points to the pseudo-sector
m_nHostSectorCount++;
m_nHostSectorCount %= XM6_HOST_PSEUDO_CLUSTER_MAX;
return 0;
}
- // クラスタ番号からセクタ番号を算出
+ // Calculate the sector number from the cluster number
DWORD n = nSector - (3 * cap.sectors);
DWORD nMod = 1;
if (cap.sectors) {
- // メディアが存在しない場合はcap.sectorsが0になるので注意
+ // Beware that cap.sectors becomes 0 when media does not exist
nMod = n % cap.sectors;
n /= cap.sectors;
}
- // ファイル実体へのアクセス
+ // Access the file entity
if (nMod == 0 && n < XM6_HOST_PSEUDO_CLUSTER_MAX) {
- pHostFiles = m_cFiles.Search(m_nHostSectorBuffer[n]); // 実体を検索
+ pHostFiles = m_cFiles.Search(m_nHostSectorBuffer[n]); // Find entity
if (pHostFiles) {
- // 擬似セクタを生成
+ // Generate pseudo-sector
CHostFcb f;
f.SetFilename(pHostFiles->GetPath());
f.SetMode(Human68k::OP_READ);
@@ -3941,28 +3821,28 @@ int CFileSys::DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize)
//---------------------------------------------------------------------------
//
-/// $54 - セクタ書き込み
+/// $54 - Write sector
//
//---------------------------------------------------------------------------
int CFileSys::DiskWrite(DWORD nUnit)
{
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
ASSERT(nUnit < m_nUnits);
if (nUnit >= m_nUnits)
- return FS_FATAL_MEDIAOFFLINE; // 念のため
+ return FS_FATAL_MEDIAOFFLINE; // Just in case
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
return FS_FATAL_MEDIAOFFLINE;
- // 書き込み禁止チェック
+ // Write-protect check
if (m_cEntry.isWriteProtect(nUnit))
return FS_FATAL_WRITEPROTECT;
- // 現実を突きつける
+ // Thrust at reality
return FS_INVALIDPRM;
}
@@ -3975,49 +3855,49 @@ int CFileSys::Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl)
{
ASSERT(pIoctrl);
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
if (nUnit >= m_nUnits)
- return FS_INVALIDFUNC; // レジューム後に無効なドライブでmint操作時に白帯を出さないよう改良
+ return FS_INVALIDFUNC; // Avoid triggering a fatal error in mint when resuming with an invalid drive
switch (nFunction) {
case 0:
- // メディアバイトの獲得
+ // Acquire media byte
pIoctrl->media = m_cEntry.GetMediaByte(nUnit);
return 0;
case 1:
- // Human68k互換のためのダミー
+ // Dummy for Human68k compatibility
pIoctrl->param = -1;
return 0;
case 2:
switch (pIoctrl->param) {
case (DWORD)-1:
- // メディア再認識
+ // Re-identify media
m_cEntry.isMediaOffline(nUnit);
return 0;
case 0:
case 1:
- // Human68k互換のためのダミー
+ // Dummy for Human68k compatibility
return 0;
}
break;
case (DWORD)-1:
- // 常駐判定
+ // Resident evaluation
memcpy(pIoctrl->buffer, "WindrvXM", 8);
return 0;
case (DWORD)-2:
- // オプション設定
+ // Set options
SetOption(pIoctrl->param);
return 0;
case (DWORD)-3:
- // オプション獲得
+ // Get options
pIoctrl->param = GetOption();
return 0;
}
@@ -4027,40 +3907,40 @@ int CFileSys::Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl)
//---------------------------------------------------------------------------
//
-/// $56 - フラッシュ
+/// $56 - Flush
//
//---------------------------------------------------------------------------
int CFileSys::Flush(DWORD nUnit)
{
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
if (nUnit >= m_nUnits)
- return FS_INVALIDFUNC; // レジューム後に無効なドライブでmintからコマンドを実行し戻る時に白帯を出さないよう改良
+ return FS_INVALIDFUNC; // Avoid triggering a fatal error returning from a mint command when resuming with an invalid drive
- // 常に成功
+ // Always succeed
return 0;
}
//---------------------------------------------------------------------------
//
-/// $57 - メディア交換チェック
+/// $57 - Media change check
//
//---------------------------------------------------------------------------
int CFileSys::CheckMedia(DWORD nUnit)
{
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
if (nUnit >= m_nUnits)
- return FS_INVALIDFUNC; // レジューム後に無効なドライブでmint操作時に白帯を出さないよう改良
+ return FS_INVALIDFUNC; // Avoid triggering a fatal error in mint when resuming with an invalid drive
- // メディア交換チェック
+ // Media change check
BOOL bResult = m_cEntry.CheckMedia(nUnit);
- // メディア未挿入ならエラーとする
+ // Throw error when media is not inserted
if (bResult == FALSE) {
return FS_INVALIDFUNC;
}
@@ -4070,36 +3950,36 @@ int CFileSys::CheckMedia(DWORD nUnit)
//---------------------------------------------------------------------------
//
-/// $58 - 排他制御
+/// $58 - Lock
//
//---------------------------------------------------------------------------
int CFileSys::Lock(DWORD nUnit)
{
- // ユニットチェック
+ // Unit check
if (nUnit >= DriveMax)
return FS_FATAL_INVALIDUNIT;
ASSERT(nUnit < m_nUnits);
if (nUnit >= m_nUnits)
- return FS_FATAL_MEDIAOFFLINE; // 念のため
+ return FS_FATAL_MEDIAOFFLINE; // Just in case
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
return FS_FATAL_MEDIAOFFLINE;
- // 常に成功
+ // Always succeed
return 0;
}
//---------------------------------------------------------------------------
//
-/// オプション設定
+/// Set options
//
//---------------------------------------------------------------------------
void CFileSys::SetOption(DWORD nOption)
{
- // オプション設定変更でキャッシュクリア
+ // Clear cache when option settings change
if (m_nOption ^ nOption)
m_cEntry.CleanCache();
@@ -4109,14 +3989,14 @@ void CFileSys::SetOption(DWORD nOption)
//---------------------------------------------------------------------------
//
-/// オプション初期化
+/// Initialize options
//
//---------------------------------------------------------------------------
void CFileSys::InitOption(const Human68k::argument_t* pArgument)
{
ASSERT(pArgument);
- // ドライブ数を初期化
+ // Initialize number of drives
m_nDrives = 0;
const BYTE* pp = pArgument->buf;
@@ -4136,7 +4016,7 @@ void CFileSys::InitOption(const Human68k::argument_t* pArgument)
} else if (c == '-') {
nMode = 0;
} else if (c == '/') {
- // デフォルトベースパスの指定
+ // Specify default base path
if (m_nDrives < DriveMax) {
p--;
strcpy(m_szBase[m_nDrives], (const char *)p);
@@ -4145,7 +4025,7 @@ void CFileSys::InitOption(const Human68k::argument_t* pArgument)
pp += strlen((const char*)pp) + 1;
continue;
} else {
- // オプション指定ではないので次へ
+ // Continue since no option is specified
pp += strlen((const char*)pp) + 1;
continue;
}
@@ -4185,7 +4065,7 @@ void CFileSys::InitOption(const Human68k::argument_t* pArgument)
pp = p;
}
- // オプション設定
+ // Set options
if (nOption != m_nOption) {
SetOption(nOption);
}
@@ -4193,26 +4073,26 @@ void CFileSys::InitOption(const Human68k::argument_t* pArgument)
//---------------------------------------------------------------------------
//
-/// ボリュームラベル取得
+/// Get volume label
//
//---------------------------------------------------------------------------
BOOL CFileSys::FilesVolume(DWORD nUnit, Human68k::files_t* pFiles)
{
ASSERT(pFiles);
- // ボリュームラベル取得
+ // Get volume label
TCHAR szVolume[32];
BOOL bResult = m_cEntry.GetVolumeCache(nUnit, szVolume);
if (bResult == FALSE) {
- // 手動イジェクトだとメディアチェックをすり抜けるためここで捕捉
+ // Carry out an extra media check here because it may be skipped when doing a manual eject
if (m_cEntry.isEnable(nUnit) == FALSE)
return FALSE;
- // メディアチェック
+ // Media check
if (m_cEntry.isMediaOffline(nUnit))
return FALSE;
- // ボリュームラベル取得
+ // Get volume label
m_cEntry.GetVolume(nUnit, szVolume);
}
if (szVolume[0] == _T('\0'))
diff --git a/src/raspberrypi/devices/cfilesystem.h b/src/raspberrypi/devices/cfilesystem.h
index ba66c088..21f9593a 100644
--- a/src/raspberrypi/devices/cfilesystem.h
+++ b/src/raspberrypi/devices/cfilesystem.h
@@ -127,7 +127,7 @@ namespace Human68k {
};
struct namests_t {
- BYTE wildcard; ///< Wildcard array
+ BYTE wildcard; ///< Wildcard character length
BYTE drive; ///< Drive number
BYTE path[65]; ///< Path (subdirectory +/)
BYTE name[8]; ///< File name (PADDING 0x20)
@@ -332,45 +332,44 @@ enum {
// Bit24~30 Duplicate file identification mark 0:Automatic 1~127:Chars
};
-/// ファイルシステム動作フラグ
+/// File system operational flag
/**
-通常は0にする。リードオンリーでマウントしたいドライブの場合は1にする。
-それ以外の値は将来のための予約とする。
-判定が困難なデバイス(自作USBストレージとか)のための保険用。
+Normal is 0. Becomes 1 if attempting to mount in read-only mode.
+Reserving the other values for future use.
+Insurance against hard-to-detect devices such as homemade USB storage.
*/
enum {
- FSFLAG_WRITE_PROTECT = 0x00000001, ///< Bit0: 強制書き込み禁止
- FSFLAG_REMOVABLE = 0x00000002, ///< Bit1: 強制リムーバブルメディア
- FSFLAG_MANUAL = 0x00000004, ///< Bit2: 強制手動イジェクト
+ FSFLAG_WRITE_PROTECT = 0x00000001, ///< Bit0: Force write protect
+ FSFLAG_REMOVABLE = 0x00000002, ///< Bit1: Force removable media
+ FSFLAG_MANUAL = 0x00000004, ///< Bit2: Force manual eject
};
//===========================================================================
//
-/// まるっとリングリスト
+/// Full ring list
///
-/// 先頭(root.next)が最も新しいオブジェクト。
-/// 末尾(root.prev)が最も古い/未使用オブジェクト。
-/// コード効率追求のため、delete時は必ずポインタをアップキャストすること。
+/// First (root.next) is the most recent object.
+/// Last (root.prev) is the oldest / unused object.
+/// For code optimization purposes, always upcast the pointer when deleting.
//
//===========================================================================
class CRing {
public:
- // 基本ファンクション
- CRing() { Init(); } ///< デフォルトコンストラクタ
- ~CRing() { Remove(); } ///< デストラクタ final
- void Init() { next = prev = this; } ///< 初期化
+ CRing() { Init(); }
+ ~CRing() { Remove(); }
+ void Init() { next = prev = this; }
- CRing* Next() const { return next; } ///< 次の要素を取得
- CRing* Prev() const { return prev; } ///< 前の要素を取得
+ CRing* Next() const { return next; } ///< Get the next element
+ CRing* Prev() const { return prev; } ///< Get the previous element
void Insert(CRing* pRoot)
{
- // 該当オブジェクトを切り離し
+ // Separate the relevant objects
ASSERT(next);
ASSERT(prev);
next->prev = prev;
prev->next = next;
- // リング先頭へ挿入
+ // Insert into the beginning of the ring
ASSERT(pRoot);
ASSERT(pRoot->next);
next = pRoot->next;
@@ -378,16 +377,16 @@ public:
pRoot->next->prev = this;
pRoot->next = this;
}
- ///< オブジェクト切り離し & リング先頭へ挿入
+ ///< Separate objects & insert into the beginning of the ring
void InsertTail(CRing* pRoot)
{
- // 該当オブジェクトを切り離し
+ // Separate the relevant objects
ASSERT(next);
ASSERT(prev);
next->prev = prev;
prev->next = next;
- // リング末尾へ挿入
+ // Insert into the end of the ring
ASSERT(pRoot);
ASSERT(pRoot->prev);
next = pRoot;
@@ -395,13 +394,13 @@ public:
pRoot->prev->next = this;
pRoot->prev = this;
}
- ///< オブジェクト切り離し & リング末尾へ挿入
+ ///< Separate objects & insert into the end of the ring
void InsertRing(CRing* pRoot)
{
if (next == prev) return;
- // リング先頭へ挿入
+ // Insert into the beginning of the ring
ASSERT(pRoot);
ASSERT(pRoot->next);
pRoot->next->prev = prev;
@@ -409,554 +408,537 @@ public:
pRoot->next = next;
next->prev = pRoot;
- // 自分自身を空にする
+ // Empty self
next = prev = this;
}
- ///< 自分以外のオブジェクト切り離し & リング先頭へ挿入
+ ///< Separate objects except self & insert into the beginning of the ring
void Remove()
{
- // 該当オブジェクトを切り離し
+ // Separate the relevant objects
ASSERT(next);
ASSERT(prev);
next->prev = prev;
prev->next = next;
- // 安全のため自分自身を指しておく (何度切り離しても問題ない)
+ // To be safe, assign self (nothing stops you from separating any number of times)
next = prev = this;
}
- ///< オブジェクト切り離し
+ ///< Separate objects
private:
- CRing* next; ///< 次の要素
- CRing* prev; ///< 前の要素
+ CRing* next; ///< Next element
+ CRing* prev; ///< Previous element
};
//===========================================================================
//
-/// ディレクトリエントリ ファイル名
+/// Directory Entry: File Name
//
//===========================================================================
class CHostFilename {
public:
- // 基本ファンクション
- CHostFilename(); ///< デフォルトコンストラクタ
- static size_t Offset() { return offsetof(CHostFilename, m_szHost); } ///< オフセット位置取得
+ CHostFilename();
+ static size_t Offset() { return offsetof(CHostFilename, m_szHost); } ///< Get offset location
- 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ファイル名を取得
+ void SetHost(const TCHAR* szHost); ///< Set the name of the host
+ const TCHAR* GetHost() const { return m_szHost; } ///< Get the name of the host
+ void ConvertHuman(int nCount = -1); ///< Convert the Human68k name
+ void CopyHuman(const BYTE* szHuman); ///< Copy the Human68k name
+ BOOL isReduce() const; ///< Inspect if the Human68k name is generated
+ BOOL isCorrect() const { return m_bCorrect; } ///< Inspect if the Human68k file name adhers to naming rules
+ const BYTE* GetHuman() const { return m_szHuman; } ///< Get Human68k file name
const BYTE* GetHumanLast() const
- { return m_pszHumanLast; } ///< Human68kファイル名を取得
- const BYTE* GetHumanExt() const { return m_pszHumanExt; }///< Human68kファイル名を取得
- void SetEntryName(); ///< Human68kディレクトリエントリを設定
+ { return m_pszHumanLast; } ///< Get Human68k file name
+ const BYTE* GetHumanExt() const { return m_pszHumanExt; }///< Get Human68k file name
+ void SetEntryName(); ///< Set Human68k directory entry
void SetEntryAttribute(BYTE nHumanAttribute)
- { m_dirHuman.attr = nHumanAttribute; } ///< Human68kディレクトリエントリを設定
+ { m_dirHuman.attr = nHumanAttribute; } ///< Set Human68k directory entry
void SetEntrySize(DWORD nHumanSize)
- { m_dirHuman.size = nHumanSize; } ///< Human68kディレクトリエントリを設定
+ { m_dirHuman.size = nHumanSize; } ///< Set Human68k directory entry
void SetEntryDate(WORD nHumanDate)
- { m_dirHuman.date = nHumanDate; } ///< Human68kディレクトリエントリを設定
+ { m_dirHuman.date = nHumanDate; } ///< Set Human68k directory entry
void SetEntryTime(WORD nHumanTime)
- { m_dirHuman.time = nHumanTime; } ///< Human68kディレクトリエントリを設定
+ { m_dirHuman.time = nHumanTime; } ///< Set Human68k directory entry
void SetEntryCluster(WORD nHumanCluster)
- { m_dirHuman.cluster = nHumanCluster; } ///< Human68kディレクトリエントリを設定
+ { m_dirHuman.cluster = nHumanCluster; } ///< Set Human68k directory entry
const Human68k::dirent_t* GetEntry() const
- { return &m_dirHuman; } ///< Human68kディレクトリエントリを取得
- BOOL CheckAttribute(DWORD nHumanAttribute) const; ///< Human68kディレクトリエントリの属性判定
+ { return &m_dirHuman; } ///< Get Human68k directory entry
+ BOOL CheckAttribute(DWORD nHumanAttribute) const; ///< Determine Human68k directory entry attributes
BOOL isSameEntry(const Human68k::dirent_t* pdirHuman) const
{ ASSERT(pdirHuman); return memcmp(&m_dirHuman, pdirHuman, sizeof(m_dirHuman)) == 0; }
- ///< Human68kディレクトリエントリの一致判定
+ ///< Determine Human68k directory entry match
- // パス名操作
- static const BYTE* SeparateExt(const BYTE* szHuman); ///< Human68kファイル名から拡張子を分離
+ // Path name operations
+ static const BYTE* SeparateExt(const BYTE* szHuman); ///< Extract extension from Human68k file name
private:
static BYTE* CopyName(BYTE* pWrite, const BYTE* pFirst, const BYTE* pLast);
- ///< Human68k側のファイル名要素をコピー
+ ///< Copy Human68k file name elements
- 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]; ///< 該当エントリのホスト側の名称 (可変長)
+ const BYTE* m_pszHumanLast; ///< Last position of the Human68k internal name of the relevant entry
+ const BYTE* m_pszHumanExt; ///< Position of the extension of the Human68k internal name of the relevant entry
+ BOOL m_bCorrect; ///< TRUE if the relevant entry of the Human68k internal name is correct
+ BYTE m_szHuman[24]; ///< Human68k internal name of the relevant entry
+ Human68k::dirent_t m_dirHuman; ///< All information for the Human68k relevant entry
+ TCHAR m_szHost[FILEPATH_MAX]; ///< The host name of the relevant entry (variable length)
};
//===========================================================================
//
-/// ディレクトリエントリ パス名
+/// Directory entry: path name
///
-/// Human68k側のパス名は、必ず先頭が/で始まり、末尾が/で終わる。
-/// ユニット番号は持たない。
-/// 高速化のため、ホスト側の名称にはベースパス部分も含む。
+/// A file path in Human68k always begings with / and ends with /
+/// They don't hold unit numbers.
+/// Include the base path part of the name on the host side for a performance boost.
//
//===========================================================================
/** @note
-ほとんどのHuman68kのアプリは、ファイルの更新等によってディレクトリエ
-ントリに変更が生じた際、親ディレクトリのタイムスタンプは変化しないも
-のと想定して作られている。
-ところがホスト側のファイルシステムでは親ディレクトリのタイムスタンプ
-も変化してしまうものが主流となってしまっている。
+Most Human68k applications are written in a way that expects time stamps not to
+get updated for new directories created as a result of file operations, which
+triggers updates to directory entires.
+However, on the host file system, new directories do typically get an updated time stamp.
-このため、ディレクトリのコピー等において、アプリ側は正確にタイムスタ
-ンプ情報などを設定しているにもかかわらず、実行結果では時刻情報が上書
-きされてしまうという惨劇が起きてしまう。
+The unfortunate outcome is that when copying a directory for instance, the time stamp
+will get overwritten even if the application did not intend for the time stamp to get updated.
-そこでディレクトリキャッシュ内にFATタイムスタンプのエミュレーション
-機能を実装した。ホスト側のファイルシステムの更新時にタイムスタンプ情
-報を復元することでHuman68k側の期待する結果と一致させる。
+Here follows an implementation of a directory cache FAT time stamp emulation feature.
+At the time of a file system update on the host side, time stamp information will be restored
+in order to achieve expected behavior on the Human68k side.
*/
class CHostPath: public CRing {
- /// メモリ管理用
+ /// For memory management
struct ring_t {
- CRing r; ///< 円環
- CHostFilename f; ///< 実体
+ CRing r;
+ CHostFilename f;
};
public:
- /// 検索用バッファ
+ /// Search buffer
struct find_t {
- DWORD count; ///< 検索実行回数 + 1 (0のときは以下の値は無効)
- DWORD id; ///< 次回検索を続行するパスのエントリ識別ID
- const ring_t* pos; ///< 次回検索を続行する位置 (識別ID一致時)
- Human68k::dirent_t entry; ///< 次回検索を続行するエントリ内容
+ DWORD count; ///< Search execution count + 1 (When 0 the below value is invalid)
+ DWORD id; ///< Entry unique ID for the path of the next search
+ const ring_t* pos; ///< Position of the next search (When identical to unique ID)
+ Human68k::dirent_t entry; ///< Contents of the next seach entry
- void Clear() { count = 0; } ///< 初期化
+ void Clear() { count = 0; } ///< Initialize
};
- // 基本ファンクション
- CHostPath(); ///< デフォルトコンストラクタ
- ~CHostPath(); ///< デストラクタ final
- void Clean(); ///< 再利用のための初期化
+ CHostPath();
+ ~CHostPath();
+ void Clean(); ///< Initialialize for reuse
- 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; } ///< ホスト側の名称の獲得
+ void SetHuman(const BYTE* szHuman); ///< Directly specify the name on the Human68k side
+ void SetHost(const TCHAR* szHost); ///< Directly specify the name on the host side
+ BOOL isSameHuman(const BYTE* szHuman) const; ///< Compare the name on the Human68k side
+ BOOL isSameChild(const BYTE* szHuman) const; ///< Compare the name on the Human68k side
+ const TCHAR* GetHost() const { return m_szHost; } ///< Obtain the name on the host side
const CHostFilename* FindFilename(const BYTE* szHuman, DWORD nHumanAttribute = Human68k::AT_ALL) const;
- ///< ファイル名を検索
+ ///< Find file name
const CHostFilename* FindFilenameWildcard(const BYTE* szHuman, DWORD nHumanAttribute, find_t* pFind) const;
- ///< ファイル名を検索 (ワイルドカード対応)
- BOOL isRefresh(); ///< ファイル変更が行なわれたか確認
- void Refresh(); ///< ファイル再構成
- void Backup(); /// ホスト側のタイムスタンプを保存
- void Restore() const; /// ホスト側のタイムスタンプを復元
- void Release(); ///< 更新
+ ///< Find file name (with support for wildcards)
+ BOOL isRefresh(); ///< Check that the file change has been done
+ void Refresh(); ///< Refresh file
+ void Backup(); /// Backup the time stamp on the host side
+ void Restore() const; /// Restore the time stamp on the host side
+ void Release(); ///< Update
- // CHostEntryが利用する外部API
- static void InitId() { g_nId = 0; } ///< 識別ID生成用カウンタ初期化
+ // CHostEntry is an external API that we use
+ static void InitId() { g_nId = 0; } ///< Initialize the counter for the unique ID generation
private:
- static ring_t* Alloc(size_t nLength); ///< ファイル名領域確保
- static void Free(ring_t* pRing); ///< ファイル名領域解放
+ static ring_t* Alloc(size_t nLength); ///< Allocate memory for the file name
+ static void Free(ring_t* pRing); ///< Release memory for the file name
static int Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFirst, const BYTE* pBufLast);
- ///< 文字列比較 (ワイルドカード対応)
+ ///< Compare string (with support for wildcards)
- 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]; ///< 該当エントリのホスト側の名称
+ CRing m_cRing; ///< For CHostFilename linking
+ time_t m_tBackup; ///< For time stamp restoration
+ BOOL m_bRefresh; ///< Refresh flag
+ DWORD m_nId; ///< Unique ID (When the value has changed, it means an update has been made)
+ BYTE m_szHuman[HUMAN68K_PATH_MAX]; ///< The internal Human68k name for the relevant entry
+ TCHAR m_szHost[FILEPATH_MAX]; ///< The host side name for the relevant entry
- static DWORD g_nId; ///< 識別ID生成用カウンタ
+ static DWORD g_nId; ///< Counter for the unique ID generation
};
//===========================================================================
//
-/// ファイル検索処理
+/// File search processing
///
-/// Human68k側のファイル名を内部Unicodeで処理するのは正直キツい。と
-/// いうわけで、全てBYTEに変換して処理する。変換処理はディレクトリエ
-/// ントリキャッシュが一手に担い、WINDRV側はすべてシフトJISのみで扱
-/// えるようにする。
-/// また、Human68k側名称は、完全にベースパス指定から独立させる。
+/// It's pretty much impossible to process Human68k file names as Unicode internally.
+/// So, we carry out binary conversion for processing. We leave it up to the
+/// directory entry cache to handle the conversion, which allows WINDRV to read
+/// everything as Shift-JIS. Additionally, it allows Human68k names to be
+/// fully independent of base path assignments.
///
-/// ファイルを扱う直前に、ディレクトリエントリのキャッシュを生成する。
-/// ディレクトリエントリの生成処理は高コストのため、一度生成したエントリは
-/// 可能な限り維持して使い回す。
+/// We create directory entry cache just before file handling.
+/// Since creating directory entires is very costly, we try to reuse created entries
+/// as much as humanly possible.
///
-/// ファイル検索は3方式。すべてCHostFiles::Find()で処理する。
-/// 1. パス名のみ検索 属性はディレクトリのみ _CHKDIR _CREATE
-/// 2. パス名+ファイル名+属性の検索 _OPEN
-/// 3. パス名+ワイルドカード+属性の検索 _FILES _NFILES
-/// 検索結果は、ディレクトリエントリ情報として保持しておく。
+/// There are three kinds of file search. They are all processed in CHostFiles::Find()
+/// 1. Search by path name only; the only attribute is 'directory'; _CHKDIR _CREATE
+/// 2. Path + file name + attribute search; _OPEN
+/// 3. Path + wildcard + attribute search; _FILES _NFILES
+/// The search results are kept as directory entry data.
//
//===========================================================================
class CHostFiles {
public:
- // 基本ファンクション
- CHostFiles() { SetKey(0); Init(); } ///< デフォルトコンストラクタ
- void Init(); ///< 初期化
+ 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 SetKey(DWORD nKey) { m_nKey = nKey; } ///< Set search key
+ BOOL isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< Compare search key
+ void SetPath(const Human68k::namests_t* pNamests); ///< Create path and file name internally
+ BOOL isRootPath() const { return m_szHumanPath[1] == '\0'; } ///< Check if root directory
+ void SetPathWildcard() { m_nHumanWildcard = 1; } ///< Enable file search using wildcards
+ void SetPathOnly() { m_nHumanWildcard = 0xFF; } ///< Enable only path names
+ BOOL isPathOnly() const { return m_nHumanWildcard == 0xFF; } ///< Check if set to only path names
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の新規ファイル名を追加
+ ///< Set search attribute
+ BOOL Find(DWORD nUnit, class CHostEntry* pEntry); ///< Find files on the Human68k side, generating data on the host side
+ const CHostFilename* Find(CHostPath* pPath); ///< Find file name
+ void SetEntry(const CHostFilename* pFilename); ///< Store search results on the Human68k side
+ void SetResult(const TCHAR* szPath); ///< Set names on the host side
+ void AddResult(const TCHAR* szPath); ///< Add file name to the name on the host side
+ void AddFilename(); ///< Add the new Human68k file name to the name on the host side
- const TCHAR* GetPath() const { return m_szHostResult; } ///< ホスト側の名称を取得
+ const TCHAR* GetPath() const { return m_szHostResult; } ///< Get the name on the host side
- const Human68k::dirent_t* GetEntry() const { return &m_dirHuman; }///< Human68kディレクトリエントリを取得
+ const Human68k::dirent_t* GetEntry() const { return &m_dirHuman; }///< Get Human68k directory entry
- 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パス名を取得
+ DWORD GetAttribute() const { return m_dirHuman.attr; } ///< Get Human68k attribute
+ WORD GetDate() const { return m_dirHuman.date; } ///< Get Human68k date
+ WORD GetTime() const { return m_dirHuman.time; } ///< Get Human68k time
+ DWORD GetSize() const { return m_dirHuman.size; } ///< Get Human68k file size
+ const BYTE* GetHumanFilename() const { return m_szHumanFilename; }///< Get Human68k file name
+ const BYTE* GetHumanResult() const { return m_szHumanResult; } ///< Get Human68k file name search results
+ const BYTE* GetHumanPath() const { return m_szHumanPath; } ///< Get Human68k path name
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ファイル名
+ DWORD m_nKey; ///< FILES buffer address for Human68k; 0 is unused
+ DWORD m_nHumanWildcard; ///< Human68k wildcard data
+ DWORD m_nHumanAttribute; ///< Human68k search attribute
+ CHostPath::find_t m_findNext; ///< Next search location data
+ Human68k::dirent_t m_dirHuman; ///< Search results: Human68k file data
+ BYTE m_szHumanFilename[24]; ///< Human68k file name
+ BYTE m_szHumanResult[24]; ///< Search results: Human68k file name
BYTE m_szHumanPath[HUMAN68K_PATH_MAX];
- ///< Human68kのパス名
- TCHAR m_szHostResult[FILEPATH_MAX]; ///< 検索結果 ホスト側のフルパス名
+ ///< Human68k path name
+ TCHAR m_szHostResult[FILEPATH_MAX]; ///< Search results: host's full path name
};
//===========================================================================
//
-/// ファイル検索領域 マネージャ
+/// File search memory manager
//
//===========================================================================
class CHostFilesManager {
public:
#ifdef _DEBUG
- // 基本ファンクション
- ~CHostFilesManager(); ///< デストラクタ final
+ ~CHostFilesManager();
#endif // _DEBUG
- void Init(); ///< 初期化 (ドライバ組込み時)
- void Clean(); ///< 解放 (起動・リセット時)
+ void Init(); ///< Initialization (when the driver is installed)
+ void Clean(); ///< Release (when starting up or resetting)
- CHostFiles* Alloc(DWORD nKey); ///< 確保
- CHostFiles* Search(DWORD nKey); ///< 検索
- void Free(CHostFiles* pFiles); ///< 解放
+ CHostFiles* Alloc(DWORD nKey);
+ CHostFiles* Search(DWORD nKey);
+ void Free(CHostFiles* pFiles);
private:
- /// メモリ管理用
+ /// For memory management
struct ring_t {
- CRing r; ///< 円環
- CHostFiles f; ///< 実体
+ CRing r;
+ CHostFiles f;
};
- CRing m_cRing; ///< CHostFiles連結用
+ CRing m_cRing; ///< For attaching to CHostFiles
};
//===========================================================================
//
-/// FCB処理
+/// FCB processing
//
//===========================================================================
class CHostFcb {
public:
- // 基本ファンクション
- CHostFcb() { SetKey(0); Init(); } ///< デフォルトコンストラクタ
- ~CHostFcb() { Close(); } ///< デストラクタ final
- void Init(); ///< 初期化
+ CHostFcb() { SetKey(0); Init(); }
+ ~CHostFcb() { Close(); }
+ 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パス名を取得
+ void SetKey(DWORD nKey) { m_nKey = nKey; } ///< Set search key
+ BOOL isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< Compare search key
+ void SetUpdate() { m_bUpdate = TRUE; } ///< Update
+ BOOL isUpdate() const { return m_bUpdate; } ///< Get update state
+ BOOL SetMode(DWORD nHumanMode); ///< Set file open mode
+ void SetFilename(const TCHAR* szFilename); ///< Set file name
+ void SetHumanPath(const BYTE* szHumanPath); ///< Set Human68k path name
+ const BYTE* GetHumanPath() const { return m_szHumanPath; } ///< Get Human68k path name
- 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(); ///< ファイルクローズ
+ BOOL Create(Human68k::fcb_t* pFcb, DWORD nHumanAttribute, BOOL bForce); ///< Create file
+ BOOL Open(); ///< Open file
+ BOOL Rewind(DWORD nOffset); ///< Seek file
+ DWORD Read(BYTE* pBuffer, DWORD nSize); ///< Read file
+ DWORD Write(const BYTE* pBuffer, DWORD nSize); ///< Write file
+ BOOL Truncate(); ///< Truncate file
+ DWORD Seek(DWORD nOffset, DWORD nHumanSeek); ///< Seek file
+ BOOL TimeStamp(DWORD nHumanTime); ///< Set file time stamp
+ BOOL Close(); ///< Close file
private:
- DWORD m_nKey; ///< Human68kのFCBバッファアドレス (0なら未使用)
- BOOL m_bUpdate; ///< 更新フラグ
- FILE* m_pFile; ///< ホスト側のファイルオブジェクト
- const char* m_pszMode; ///< ホスト側のファイルオープンモード
- bool m_bFlag; ///< ホスト側のファイルオープンフラグ
+ DWORD m_nKey; ///< Human68k FCB buffer address (0 if unused)
+ BOOL m_bUpdate; ///< Update flag
+ FILE* m_pFile; ///< Host side file object
+ const char* m_pszMode; ///< Host side file open mode
+ bool m_bFlag; ///< Host side file open flag
BYTE m_szHumanPath[HUMAN68K_PATH_MAX];
- ///< Human68kのパス名
- TCHAR m_szFilename[FILEPATH_MAX]; ///< ホスト側のファイル名
+ ///< Human68k path name
+ TCHAR m_szFilename[FILEPATH_MAX]; ///< Host side file name
};
//===========================================================================
//
-/// FCB処理 マネージャ
+/// FCB processing manager
//
//===========================================================================
class CHostFcbManager {
public:
#ifdef _DEBUG
- // 基本ファンクション
- ~CHostFcbManager(); ///< デストラクタ final
+ ~CHostFcbManager();
#endif // _DEBUG
- void Init(); ///< 初期化 (ドライバ組込み時)
- void Clean(); ///< 解放 (起動・リセット時)
+ void Init(); ///< Initialization (when the driver is installed)
+ void Clean(); ///< Release (when starting up or resetting)
- CHostFcb* Alloc(DWORD nKey); ///< 確保
- CHostFcb* Search(DWORD nKey); ///< 検索
- void Free(CHostFcb* p); ///< 解放
+ CHostFcb* Alloc(DWORD nKey);
+ CHostFcb* Search(DWORD nKey);
+ void Free(CHostFcb* p);
private:
- /// メモリ管理用
+ /// For memory management
struct ring_t {
- CRing r; ///< 円環
- CHostFcb f; ///< 実体
+ CRing r;
+ CHostFcb f;
};
- CRing m_cRing; ///< CHostFcb連結用
+ CRing m_cRing; ///< For attaching to CHostFcb
};
//===========================================================================
//
-/// ホスト側ドライブ
+/// Host side drive
///
-/// ドライブ毎に必要な情報の保持に専念し、管理はCHostEntryで行なう。
+/// Keeps the required data for each drive, managed in CHostEntry.
//
//===========================================================================
class CHostDrv
{
public:
- // 基本ファンクション
- CHostDrv(); ///< デフォルトコンストラクタ
- ~CHostDrv(); ///< デストラクタ final
- void Init(const TCHAR* szBase, DWORD nFlag); ///< 初期化 (デバイス起動とロード)
+ CHostDrv();
+ ~CHostDrv();
+ void Init(const TCHAR* szBase, DWORD nFlag); ///< Initialization (device startup and load)
- 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; ///< キャッシュから容量を取得
+ BOOL isWriteProtect() const { return m_bWriteProtect; }
+ BOOL isEnable() const { return m_bEnable; } ///< Is it accessible?
+ BOOL isMediaOffline();
+ BYTE GetMediaByte() const;
+ DWORD GetStatus() const;
+ void SetEnable(BOOL bEnable); ///< Set media status
+ BOOL CheckMedia(); ///< Check if media was changed
+ void Update(); ///< Update media status
+ void Eject();
+ void GetVolume(TCHAR* szLabel); ///< Get volume label
+ BOOL GetVolumeCache(TCHAR* szLabel) const; ///< Get volume label from cache
+ DWORD GetCapacity(Human68k::capacity_t* pCapacity);
+ BOOL GetCapacityCache(Human68k::capacity_t* pCapacity) const; ///< Get capacity from cache
- // キャッシュ操作
- 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); ///< ホスト側の名称を検索 (パス名+ファイル名(省略可)+属性)
+ // Cache operations
+ void CleanCache(); ///< Update all cache
+ void CleanCache(const BYTE* szHumanPath); ///< Update cache for the specified path
+ void CleanCacheChild(const BYTE* szHumanPath); ///< Update all cache below the specified path
+ void DeleteCache(const BYTE* szHumanPath); ///< Delete the cache for the specified path
+ CHostPath* FindCache(const BYTE* szHuman); ///< Inspect if the specified path is cached
+ CHostPath* CopyCache(CHostFiles* pFiles); ///< Acquire the host side name on the basis of cache information
+ CHostPath* MakeCache(CHostFiles* pFiles); ///< Get all required data to construct a host side name
+ BOOL Find(CHostFiles* pFiles); ///< Find host side name (path + file name (can be abbreviated) + attribute)
private:
- // パス名操作
+ // Path name operations
static const BYTE* SeparateCopyFilename(const BYTE* szHuman, BYTE* szBuffer);
- ///< Human68kフルパス名から先頭の要素を分離・コピー
+ ///< Split and copy the first element of the Human68k full path name
- // 排他制御
void Lock() {}
void Unlock() {}
- /// メモリ管理用
+ /// For memory management
struct ring_t {
- CRing r; ///< 円環
- CHostPath f; ///< 実体
+ 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]; ///< ベースパス
+ BOOL m_bWriteProtect; ///< TRUE if write-protected
+ BOOL m_bEnable; ///< TRUE if media is usable
+ DWORD m_nRing; ///< Number of stored path names
+ CRing m_cRing; ///< For attaching to CHostPath
+ Human68k::capacity_t m_capCache; ///< Sector data cache: if "sectors == 0" then not cached
+ BOOL m_bVolumeCache; ///< TRUE if the volume label has been read
+ TCHAR m_szVolumeCache[24]; ///< Volume label cache
+ TCHAR m_szBase[FILEPATH_MAX]; ///< Base path
};
//===========================================================================
//
-/// ディレクトリエントリ管理
+/// Directory entry management
//
//===========================================================================
class CHostEntry {
public:
- // 基本ファンクション
- CHostEntry(); ///< デフォルトコンストラクタ
- ~CHostEntry(); ///< デストラクタ final
- void Init(); ///< 初期化 (ドライバ組込み時)
- void Clean(); ///< 解放 (起動・リセット時)
+ CHostEntry();
+ ~CHostEntry();
+ void Init(); ///< Initialization (when the driver is installed)
+ void Clean(); ///< Release (when starting up or resetting)
- // キャッシュ操作
- 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); ///< ホスト側ファイルシステム状態変化通知
+ // Cache operations
+ void CleanCache(); ///< Update all cache
+ void CleanCache(DWORD nUnit); ///< Update cache for the specified unit
+ void CleanCache(DWORD nUnit, const BYTE* szHumanPath); ///< Update cache for the specified path
+ void CleanCacheChild(DWORD nUnit, const BYTE* szHumanPath); ///< Update cache below the specified path
+ void DeleteCache(DWORD nUnit, const BYTE* szHumanPath); ///< Delete cache for the specified path
+ BOOL Find(DWORD nUnit, CHostFiles* pFiles); ///< Find host side name (path + file name (can be abbreviated) + attribute)
+ void ShellNotify(DWORD nEvent, const TCHAR* szPath); ///< Notify status change in the host side file system
- // ドライブオブジェクト操作
- 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); ///< 容量の取得
+ // Drive object operations
+ void SetDrv(DWORD nUnit, CHostDrv* pDrv);
+ BOOL isWriteProtect(DWORD nUnit) const;
+ BOOL isEnable(DWORD nUnit) const; ///< Is it accessible?
+ BOOL isMediaOffline(DWORD nUnit);
+ BYTE GetMediaByte(DWORD nUnit) const;
+ DWORD GetStatus(DWORD nUnit) const; ///< Get drive status
+ BOOL CheckMedia(DWORD nUnit); ///< Media change check
+ void Eject(DWORD nUnit);
+ void GetVolume(DWORD nUnit, TCHAR* szLabel); ///< Get volume label
+ BOOL GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const; ///< Get volume label from cache
+ DWORD GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity);
BOOL GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity) const;
- ///< キャッシュからクラスタサイズを取得
+ ///< Get cluster size from cache
- /// 定数
enum {
- DriveMax = 10 ///< ドライブ最大候補数
+ DriveMax = 10 ///< Max number of drive candidates
};
private:
- CHostDrv* m_pDrv[DriveMax]; ///< ホスト側ドライブオブジェクト
- DWORD m_nTimeout; ///< 最後にタイムアウトチェックを行なった時刻
+ CHostDrv* m_pDrv[DriveMax]; ///< Host side drive object
+ DWORD m_nTimeout; ///< Last time a timeout check was carried out
};
//===========================================================================
//
-/// ホスト側ファイルシステム
+/// Host side file system
//
//===========================================================================
/** @note
-現在の見解。
+Current state of affairs:
-XM6の設計思想とは反するが、class Windrvまたはclass CWindrvに直接
-class CFileSysへのポインタを持たせる方法を模索するべきである。
-これにより、以下のメリットが得られる。
+While it violates the design philosophy of XM6, we should find a way for
+'class Windrv' and 'class CWindrv' to have a direct pointer to 'class CFileSys'.
+This way, we get the following benefits.
-メリットその1。
-コマンドハンドラの大量のメソッド群を一ヶ所で集中管理できる。
-コマンドハンドラはホスト側の仕様変更などの要因によって激しく変化する
-可能性が高いため、メソッドの追加削除や引数の変更などのメンテナンスが
-大幅に楽になる。
+Benefit no. 1
+Makes it possible to manage a large number of command handler methods in one place.
+There is a high chance the command handlers will change drastically because of
+host system architectural changes, so we will save a huge amount of maintenance work
+in the long run.
-メリットその2。
-仮想関数のテーブル生成・参照処理に関する処理コードを駆逐できる。
-XM6では複数のファイルシステムオブジェクトを同時に使うような実装は
-ありえない。つまりファイルシステムオブジェクトにポリモーフィズムは
-まったく必要ないどころか、ただクロックの無駄となっているだけである。
+Benefit no. 2
+We would get rid of virtual funcion code for processing table creation and lookup.
+It is not feasible to implement code in XM6 for simultaneous use of file system objects.
+Therefore file system object polymorphism is a waste of CPU cycles.
-試しに変えてみた。実際効率上がった。
-windrv.h内のFILESYS_FAST_STRUCTUREの値を変えてコンパイラの吐くソース
-を比較すれば一目瞭然。何故私がこんな長文を書こうと思ったのかを理解で
-きるはず。
+I made the change as an experiment. Performance did improve.
+The improvement was obvious from looking at the source the compiler spit out
+after changing the FILESYS_FAST_STRUCTURE value in windrv.h.
+You may understand now why I decided to rant here.
-一方ロシアはclass CWindrv内にclass CFileSysを直接設置した。
-(本当はclass CHostを廃止して直接置きたい……良い方法はないものか……)
+The easy solution is to put the content of 'class CFileSys' into 'class CWindrv'.
+(To be honest, I really want to deprecate 'class CHost'... I wonder if there's a good way...)
*/
class CFileSys
{
public:
- // 基本ファンクション
- CFileSys(); ///< デフォルトコンストラクタ
- virtual ~CFileSys() {}; ///< デストラクタ
+ CFileSys();
+ virtual ~CFileSys() {};
- // 初期化・終了
- void Reset(); ///< リセット (全クローズ)
- void Init(); ///< 初期化 (デバイス起動とロード)
+ void Reset(); ///< Reset (close all)
+ void Init(); ///< Initialization (device startup and load)
- // コマンドハンドラ
- 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 - ディレクトリ削除
+ // Command handlers
+ DWORD InitDevice(const Human68k::argument_t* pArgument); ///< $40 - Device startup
+ int CheckDir(DWORD nUnit, const Human68k::namests_t* pNamests); ///< $41 - Directory check
+ int MakeDir(DWORD nUnit, const Human68k::namests_t* pNamests); ///< $42 - Create directory
+ int RemoveDir(DWORD nUnit, const Human68k::namests_t* pNamests); ///< $43 - Delete directory
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 - ファイル削除
+ ///< $44 - Change file name
+ int Delete(DWORD nUnit, const Human68k::namests_t* pNamests); ///< $45 - Delete file
int Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD nHumanAttribute);
- ///< $46 - ファイル属性取得/設定
+ ///< $46 - Get / set file attribute
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 - ファイル次検索
+ ///< $47 - Find file
+ int NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles); ///< $48 - Find next file
int Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, DWORD nHumanAttribute, BOOL bForce);
- ///< $49 - ファイル作成
+ ///< $49 - Create file
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 - ファイルクローズ
+ ///< $4A - Open file
+ int Close(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb); ///< $4B - Close file
int Read(DWORD nKey, Human68k::fcb_t* pFcb, BYTE* pAddress, DWORD nSize);
- ///< $4C - ファイル読み込み
+ ///< $4C - Read file
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 - ファイルシーク
+ ///< $4D - Write file
+ int Seek(DWORD nKey, Human68k::fcb_t* pFcb, DWORD nSeek, int nOffset); ///< $4E - Seek file
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 - セクタ書き込み
+ ///< $4F - Get / set file timestamp
+ int GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity); ///< $50 - Get capacity
+ int CtrlDrive(DWORD nUnit, Human68k::ctrldrive_t* pCtrlDrive); ///< $51 - Inspect / control drive status
+ int GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb); ///< $52 - Get DPB
+ int DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize); ///< $53 - Read sectors
+ int DiskWrite(DWORD nUnit); ///< $54 - Write sectors
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 - 排他制御
+ int Flush(DWORD nUnit); ///< $56 - Flush
+ int CheckMedia(DWORD nUnit); ///< $57 - Media change check
+ int Lock(DWORD nUnit); ///< $58 - Lock
- void SetOption(DWORD nOption); ///< オプション設定
- DWORD GetOption() const { return m_nOption; } ///< オプション取得
- DWORD GetDefault() const { return m_nOptionDefault; } ///< デフォルトオプション取得
- static DWORD GetFileOption() { return g_nOption; } ///< ファイル名変換オプション取得
+ void SetOption(DWORD nOption); ///< Set option
+ DWORD GetOption() const { return m_nOption; } ///< Get option
+ DWORD GetDefault() const { return m_nOptionDefault; } ///< Get default options
+ static DWORD GetFileOption() { return g_nOption; } ///< Get file name change option
void ShellNotify(DWORD nEvent, const TCHAR* szPath)
- { m_cEntry.ShellNotify(nEvent, szPath); } ///< ホスト側ファイルシステム状態変化通知
+ { m_cEntry.ShellNotify(nEvent, szPath); } ///< Notify host side file system status change
- /// 定数
enum {
- DriveMax = CHostEntry::DriveMax ///< ドライブ最大候補数
+ DriveMax = CHostEntry::DriveMax ///< Max number of drive candidates
};
private:
- // 内部補助用
- void InitOption(const Human68k::argument_t* pArgument); ///< オプション初期化
- BOOL FilesVolume(DWORD nUnit, Human68k::files_t* pFiles); ///< ボリュームラベル取得
+ void InitOption(const Human68k::argument_t* pArgument);
+ BOOL FilesVolume(DWORD nUnit, Human68k::files_t* pFiles); ///< Get volume label
- DWORD m_nUnits; ///< 現在のドライブオブジェクト数 (レジューム毎に変化)
+ DWORD m_nUnits; ///< Number of current drive objects (Changes for every resume)
- DWORD m_nOption; ///< 現在の動作フラグ
- DWORD m_nOptionDefault; ///< リセット時の動作フラグ
+ DWORD m_nOption; ///< Current runtime flag
+ DWORD m_nOptionDefault; ///< Runtime flag at reset
- DWORD m_nDrives; ///< ベースパス状態復元用の候補数 (0なら毎回スキャン)
+ DWORD m_nDrives; ///< Number of candidates for base path status restoration (scan every time if 0)
- DWORD m_nKernel; ///< カーネルチェック用カウンタ
- DWORD m_nKernelSearch; ///< NULデバイスの先頭アドレス
+ DWORD m_nKernel; ///< Counter for kernel check
+ DWORD m_nKernelSearch; ///< Initial address for NUL device
- DWORD m_nHostSectorCount; ///< 擬似セクタ番号
+ DWORD m_nHostSectorCount; ///< Virtual sector identifier
- CHostFilesManager m_cFiles; ///< ファイル検索領域
- CHostFcbManager m_cFcb; ///< FCB操作領域
- CHostEntry m_cEntry; ///< ドライブオブジェクトとディレクトリエントリ
+ CHostFilesManager m_cFiles; ///< File search memory
+ CHostFcbManager m_cFcb; ///< FCB operation memory
+ CHostEntry m_cEntry; ///< Drive object and directory entry
DWORD m_nHostSectorBuffer[XM6_HOST_PSEUDO_CLUSTER_MAX];
- ///< 擬似セクタの指すファイル実体
+ ///< Entity that the virtual sector points to
- DWORD m_nFlag[DriveMax]; ///< ベースパス状態復元用の動作フラグ候補
- TCHAR m_szBase[DriveMax][FILEPATH_MAX]; ///< ベースパス状態復元用の候補
- static DWORD g_nOption; ///< ファイル名変換フラグ
+ DWORD m_nFlag[DriveMax]; ///< Candidate runtime flag for base path restoration
+ TCHAR m_szBase[DriveMax][FILEPATH_MAX]; ///< Candidate for base path restoration
+ static DWORD g_nOption; ///< File name change flag
};
diff --git a/src/raspberrypi/fileio.cpp b/src/raspberrypi/fileio.cpp
index fd795447..066abddd 100644
--- a/src/raspberrypi/fileio.cpp
+++ b/src/raspberrypi/fileio.cpp
@@ -99,7 +99,7 @@ BOOL Fileio::Open(const char *fname, OpenMode mode, BOOL directIO)
break;
case ReadWrite:
- // CD-ROMからの読み込みはRWが成功してしまう
+ // Make sure RW does not succeed when reading from CD-ROM
if (access(fname, 0x06) != 0) {
return FALSE;
}
diff --git a/src/web/file_cmds.py b/src/web/file_cmds.py
index 5adcbacb..62a9e64d 100644
--- a/src/web/file_cmds.py
+++ b/src/web/file_cmds.py
@@ -1,10 +1,7 @@
-import fnmatch
import os
import subprocess
import time
-import io
-import re
-import sys
+import logging
from ractl_cmds import (
attach_image,
@@ -14,6 +11,42 @@ from ractl_cmds import (
from settings import *
+def list_files():
+ from fnmatch import translate
+ valid_file_types = list(VALID_FILE_SUFFIX)
+ valid_file_types = ["*." + s for s in valid_file_types]
+ valid_file_types = r"|".join([translate(x) for x in valid_file_types])
+
+ from re import match, IGNORECASE
+
+ files_list = []
+ for path, dirs, files in os.walk(base_dir):
+ # Only list valid file types
+ files = [f for f in files if match(valid_file_types, f, IGNORECASE)]
+ files_list.extend(
+ [
+ (
+ os.path.join(path, file),
+ "{:,.1f}".format(
+ os.path.getsize(os.path.join(path, file)) / float(1 << 20),
+ ),
+ os.path.getsize(os.path.join(path, file)),
+ )
+ for file in files
+ ]
+ )
+ return files_list
+
+
+def list_config_files():
+ files_list = []
+ for root, dirs, files in os.walk(base_dir):
+ for file in files:
+ if file.endswith(".json"):
+ files_list.append(file)
+ return files_list
+
+
def create_new_image(file_name, type, size):
if file_name == "":
file_name = "new_image." + str(int(time.time())) + "." + type
@@ -42,14 +75,6 @@ def unzip_file(file_name):
return True
-def rascsi_service(action):
- # start/stop/restart
- return (
- subprocess.run(["sudo", "/bin/systemctl", action, "rascsi.service"]).returncode
- == 0
- )
-
-
def download_file_to_iso(scsi_id, url):
import urllib.request
@@ -60,14 +85,19 @@ def download_file_to_iso(scsi_id, url):
tmp_full_path = tmp_dir + file_name
iso_filename = base_dir + file_name + ".iso"
- urllib.request.urlretrieve(url, tmp_full_path)
+ try:
+ urllib.request.urlretrieve(url, tmp_full_path)
+ except:
+ # TODO: Capture a more descriptive error message
+ return {"status": False, "msg": "Error loading the URL"}
+
# iso_filename = make_cd(tmp_full_path, None, None) # not working yet
iso_proc = subprocess.run(
["genisoimage", "-hfs", "-o", iso_filename, tmp_full_path], capture_output=True
)
if iso_proc.returncode != 0:
- return iso_proc
- return attach_image(scsi_id, iso_filename, "SCCD")
+ return {"status": False, "msg": iso_proc}
+ return attach_image(scsi_id, type="SCCD", image=iso_filename)
def download_image(url):
@@ -76,50 +106,69 @@ def download_image(url):
file_name = url.split("/")[-1]
full_path = base_dir + file_name
- urllib.request.urlretrieve(url, full_path)
-
-def write_config_csv(file_name):
- import csv
-
- # This method takes the output of 'rasctl -l' and parses it into csv format:
- # 0: ID
- # 1: Unit Number (unused in rascsi-web)
- # 2: Device Type
- # 3: Device Status (includes the path to a loaded image file)
- # TODO: Remove the dependence on rasctl; e.g. when implementing protobuf for rascsi-web
try:
- with open(file_name, "w") as csv_file:
- writer = csv.writer(csv_file)
- for device in list_devices():
- if device["type"] != "-":
- device_info = list (device.values())
- # Match a *nix file path inside column 3, cutting out the last chunk that starts with a space
- filesearch = re.search("(^(/[^/ ]*)+)(\s.*)*$", device_info[3])
- if filesearch is None:
- device_info[3] = ""
- else:
- device_info[3] = filesearch.group(1)
- writer.writerow(device_info)
- return True
+ urllib.request.urlretrieve(url, full_path)
+ return {"status": True, "msg": "Downloaded the URL"}
except:
- print ("Could not open file for writing: ", file_name)
- return False
-
-def read_config_csv(file_name):
- import csv
+ # TODO: Capture a more descriptive error message
+ return {"status": False, "msg": "Error loading the URL"}
+
+def write_config(file_name):
+ from json import dump
try:
- with open(file_name) as csv_file:
+ with open(file_name, "w") as json_file:
+ devices = list_devices()[0]
+ for device in devices:
+ # Remove keys that we don't want to store in the file
+ del device["status"]
+ del device["file"]
+ # It's cleaner not to store an empty parameter for every device without media
+ if device["image"] == "":
+ device["image"] = None
+ # RaSCSI product names will be generated on the fly by RaSCSI
+ if device["vendor"] == "RaSCSI":
+ device["vendor"] = device["product"] = device["revision"] = None
+ # A block size of 0 is how RaSCSI indicates N/A for block size
+ if device["block_size"] == 0:
+ device["block_size"] = None
+ # Convert to a data type that can be serialized
+ device["params"] = list(device["params"])
+ dump(devices, json_file, indent=4)
+ return {"status": True, "msg": f"Successfully wrote to file: {file_name}"}
+ #TODO: more verbose error handling of file system errors
+ except:
+ logging.error(f"Could not write to file: {file_name}")
+ return {"status": False, "msg": f"Could not write to file: {file_name}"}
+
+
+def read_config(file_name):
+ from json import load
+ try:
+ with open(file_name) as json_file:
detach_all()
- config_reader = csv.reader(csv_file)
- #TODO: Remove hard-coded string sanitation (e.g. after implementing protobuf)
- exclude_list = ("X68000 HOST BRIDGE", "DaynaPort SCSI/Link", " (WRITEPROTECT)", "NO MEDIA")
- for row in config_reader:
- image_name = row[3]
- for e in exclude_list:
- image_name = image_name.replace(e, "")
- attach_image(row[0], image_name, row[2])
- return True
+ devices = load(json_file)
+ for row in devices:
+ process = attach_image(row["id"], device_type=row["device_type"], image=row["image"], unit=int(row["un"]), \
+ params=row["params"], vendor=row["vendor"], product=row["product"], \
+ revision=row["revision"], block_size=row["block_size"])
+ if process["status"] == True:
+ return {"status": process["status"], "msg": f"Successfully read from file: {file_name}"}
+ else:
+ return {"status": process["status"], "msg": process["msg"]}
+ #TODO: more verbose error handling of file system errors
except:
- print ("Could not access file: ", file_name)
- return False
+ logging.error(f"Could not read file: {file_name}")
+ return {"status": False, "msg": f"Could not read file: {file_name}"}
+
+
+def read_device_config(file_name):
+ from json import load
+ try:
+ with open(file_name) as json_file:
+ conf = load(json_file)
+ return {"status": True, "msg": f"Read data from file: {file_name}", "conf": conf}
+ #TODO: more verbose error handling of file system errors
+ except:
+ logging.error(f"Could not read file: {file_name}")
+ return {"status": False, "msg": f"Could not read file: {file_name}"}
diff --git a/src/web/pi_cmds.py b/src/web/pi_cmds.py
index 17f716cc..f5164091 100644
--- a/src/web/pi_cmds.py
+++ b/src/web/pi_cmds.py
@@ -29,3 +29,12 @@ def running_version():
.strip()
)
return ra_web_version + " " + pi_version
+
+
+def is_bridge_setup():
+ from subprocess import run
+ process = run(["brctl", "show"], capture_output=True)
+ output = process.stdout.decode("utf-8")
+ if "rascsi_bridge" in output:
+ return True
+ return False
\ No newline at end of file
diff --git a/src/web/ractl_cmds.py b/src/web/ractl_cmds.py
index 92d978aa..8284f13b 100644
--- a/src/web/ractl_cmds.py
+++ b/src/web/ractl_cmds.py
@@ -1,164 +1,328 @@
-import fnmatch
-import subprocess
-import re
import logging
from settings import *
+import rascsi_interface_pb2 as proto
-valid_file_suffix = ["*.hda", "*.hdn", "*.hdi", "*.nhd", "*.hdf", "*.hds", "*.hdr", "*.iso", "*.cdr", "*.toast", "*.img", "*.zip"]
-valid_file_types = r"|".join([fnmatch.translate(x) for x in valid_file_suffix])
+def get_server_info():
+ command = proto.PbCommand()
+ command.operation = proto.PbOperation.SERVER_INFO
+
+ data = send_pb_command(command.SerializeToString())
+ result = proto.PbResult()
+ result.ParseFromString(data)
+ version = str(result.server_info.major_version) + "." +\
+ str(result.server_info.minor_version) + "." +\
+ str(result.server_info.patch_version)
+ log_levels = result.server_info.log_levels
+ current_log_level = result.server_info.current_log_level
+ return {"status": result.status, "version": version, "log_levels": log_levels, "current_log_level": current_log_level}
+
+
+def validate_scsi_id(scsi_id):
+ from re import match
+ if match("[0-7]", str(scsi_id)) != None:
+ return {"status": True, "msg": "Valid SCSI ID."}
+ else:
+ return {"status": False, "msg": "Invalid SCSI ID. Should be a number between 0-7"}
-def is_active():
- process = subprocess.run(["systemctl", "is-active", "rascsi"], capture_output=True)
- return process.stdout.decode("utf-8").strip() == "active"
-
-
-def list_files():
- files_list = []
- for path, dirs, files in os.walk(base_dir):
- # Only list valid file types
- files = [f for f in files if re.match(valid_file_types, f)]
- files_list.extend(
- [
- (
- os.path.join(path, file),
- # TODO: move formatting to template
- "{:,.0f}".format(
- os.path.getsize(os.path.join(path, file)) / float(1 << 20)
- )
- + " MB",
- )
- for file in files
- ]
- )
- return files_list
-
-
-def list_config_files():
- files_list = []
- for root, dirs, files in os.walk(base_dir):
- for file in files:
- if file.endswith(".csv"):
- files_list.append(file)
- return files_list
-
-
-def get_valid_scsi_ids(devices, invalid_list):
+def get_valid_scsi_ids(devices, invalid_list, occupied_ids):
for device in devices:
- if device["file"] != "NO MEDIA" and device["file"] != "-":
- invalid_list.append(int(device["id"]))
+ # Make it possible to insert images on top of a
+ # removable media device currently without an image attached
+ if "No Media" in device["status"]:
+ occupied_ids.remove(device["id"])
- valid_list = list(range(8))
- for id in invalid_list:
- try:
- valid_list.remove(int(id))
- except:
- logging.warning("Invalid SCSI id " + str(id))
- valid_list.reverse()
- return valid_list
+ # Combine lists and remove duplicates
+ invalid_ids = list(set(invalid_list + occupied_ids))
+ valid_ids = list(range(8))
+ for id in invalid_ids:
+ valid_ids.remove(int(id))
+ valid_ids.reverse()
+ return valid_ids
def get_type(scsi_id):
- return list_devices()[int(scsi_id)]["type"]
+ device = proto.PbDeviceDefinition()
+ device.id = int(scsi_id)
+
+ command = proto.PbCommand()
+ command.operation = proto.PbOperation.DEVICE_INFO
+ command.devices.append(device)
+
+ data = send_pb_command(command.SerializeToString())
+ result = proto.PbResult()
+ result.ParseFromString(data)
+ # Assuming that only one PbDevice object is present in the response
+ try:
+ result_type = proto.PbDeviceType.Name(result.device_info.devices[0].type)
+ return {"status": result.status, "msg": result.msg, "device_type": result_type}
+ except:
+ return {"status": result.status, "msg": result.msg, "device_type": None}
-def attach_image(scsi_id, image, image_type):
- if image_type == "SCCD" and get_type(scsi_id) == "SCCD":
- return insert(scsi_id, image)
+def attach_image(scsi_id, **kwargs):
+
+ # Handling the inserting of media into an attached removable type device
+ currently_attached = get_type(scsi_id)["device_type"]
+ device_type = kwargs.get("device_type", None)
+
+ if device_type in REMOVABLE_DEVICE_TYPES and currently_attached in REMOVABLE_DEVICE_TYPES:
+ if currently_attached != device_type:
+ return {"status": False, "msg": f"Cannot insert an image for {device_type} into a {currently_attached} device."}
+ else:
+ return insert(scsi_id, kwargs.get("image", ""))
+ # Handling attaching a new device
else:
- return subprocess.run(
- ["rasctl", "-c", "attach", "-t", image_type, "-i", scsi_id, "-f", image],
- capture_output=True,
- )
+ devices = proto.PbDeviceDefinition()
+ devices.id = int(scsi_id)
+ if "device_type" in kwargs.keys():
+ logging.warning(kwargs["device_type"])
+ devices.type = proto.PbDeviceType.Value(str(kwargs["device_type"]))
+ if "unit" in kwargs.keys():
+ devices.unit = kwargs["unit"]
+ if "image" in kwargs.keys():
+ if kwargs["image"] not in [None, ""]:
+ devices.params.append(kwargs["image"])
+ if "params" in kwargs.keys():
+ for p in kwargs["params"]:
+ devices.params.append(p)
+ if "vendor" in kwargs.keys():
+ if kwargs["vendor"] not in [None, ""]:
+ devices.vendor = kwargs["vendor"]
+ if "product" in kwargs.keys():
+ if kwargs["product"] not in [None, ""]:
+ devices.product = kwargs["product"]
+ if "revision" in kwargs.keys():
+ if kwargs["revision"] not in [None, ""]:
+ devices.revision = kwargs["revision"]
+ if "block_size" in kwargs.keys():
+ if kwargs["block_size"] not in [None, ""]:
+ devices.block_size = int(kwargs["block_size"])
+
+ command = proto.PbCommand()
+ command.operation = proto.PbOperation.ATTACH
+ command.devices.append(devices)
+
+ data = send_pb_command(command.SerializeToString())
+ result = proto.PbResult()
+ result.ParseFromString(data)
+ return {"status": result.status, "msg": result.msg}
def detach_by_id(scsi_id):
- return subprocess.run(["rasctl", "-c" "detach", "-i", scsi_id], capture_output=True)
+ devices = proto.PbDeviceDefinition()
+ devices.id = int(scsi_id)
+
+ command = proto.PbCommand()
+ command.operation = proto.PbOperation.DETACH
+ command.devices.append(devices)
+
+ data = send_pb_command(command.SerializeToString())
+ result = proto.PbResult()
+ result.ParseFromString(data)
+ return {"status": result.status, "msg": result.msg}
def detach_all():
- for scsi_id in range(0, 8):
- subprocess.run(["rasctl", "-c" "detach", "-i", str(scsi_id)])
+ command = proto.PbCommand()
+ command.operation = proto.PbOperation.DETACH_ALL
-
-def disconnect_by_id(scsi_id):
- return subprocess.run(
- ["rasctl", "-c", "disconnect", "-i", scsi_id], capture_output=True
- )
+ data = send_pb_command(command.SerializeToString())
+ result = proto.PbResult()
+ result.ParseFromString(data)
+ return {"status": result.status, "msg": result.msg}
def eject_by_id(scsi_id):
- return subprocess.run(["rasctl", "-i", scsi_id, "-c", "eject"])
+ devices = proto.PbDeviceDefinition()
+ devices.id = int(scsi_id)
+
+ command = proto.PbCommand()
+ command.operation = proto.PbOperation.EJECT
+ command.devices.append(devices)
+
+ data = send_pb_command(command.SerializeToString())
+ result = proto.PbResult()
+ result.ParseFromString(data)
+ return {"status": result.status, "msg": result.msg}
def insert(scsi_id, image):
- return subprocess.run(
- ["rasctl", "-i", scsi_id, "-c", "insert", "-f", image], capture_output=True
- )
+ devices = proto.PbDeviceDefinition()
+ devices.id = int(scsi_id)
+ devices.params.append(image)
+
+ command = proto.PbCommand()
+ command.operation = proto.PbOperation.INSERT
+ command.devices.append(devices)
+
+ data = send_pb_command(command.SerializeToString())
+ result = proto.PbResult()
+ result.ParseFromString(data)
+ return {"status": result.status, "msg": result.msg}
def attach_daynaport(scsi_id):
- return subprocess.run(
- ["rasctl", "-i", scsi_id, "-c", "attach", "-t", "scdp"],
- capture_output=True,
- )
+ devices = proto.PbDeviceDefinition()
+ devices.id = int(scsi_id)
+ devices.type = proto.PbDeviceType.SCDP
+
+ command = proto.PbCommand()
+ command.operation = proto.PbOperation.ATTACH
+ command.devices.append(devices)
+
+ data = send_pb_command(command.SerializeToString())
+ result = proto.PbResult()
+ result.ParseFromString(data)
+ return {"status": result.status, "msg": result.msg}
-def is_bridge_setup(interface):
- process = subprocess.run(["brctl", "show"], capture_output=True)
- output = process.stdout.decode("utf-8")
- if "rascsi_bridge" in output and interface in output:
- return True
- return False
+def list_devices(scsi_id=None):
+ from os import path
+ command = proto.PbCommand()
+ command.operation = proto.PbOperation.DEVICE_INFO
+ # If method is called with scsi_id parameter, return the info on those devices
+ # Otherwise, return the info on all attached devices
+ if scsi_id != None:
+ device = proto.PbDeviceDefinition()
+ device.id = int(scsi_id)
+ command.devices.append(device)
-def daynaport_setup_bridge(interface):
- return subprocess.run(
- [f"{base_dir}../RASCSI/src/raspberrypi/setup_bridge.sh", interface],
- capture_output=True,
- )
+ data = send_pb_command(command.SerializeToString())
+ result = proto.PbResult()
+ result.ParseFromString(data)
-
-def rascsi_service(action):
- # start/stop/restart
- return (
- subprocess.run(["sudo", "/bin/systemctl", action, "rascsi.service"]).returncode
- == 0
- )
-
-
-def list_devices():
device_list = []
+ occupied_ids = []
+ n = 0
+ while n < len(result.device_info.devices):
+ did = result.device_info.devices[n].id
+ dun = result.device_info.devices[n].unit
+ dtype = proto.PbDeviceType.Name(result.device_info.devices[n].type)
+ dstat = result.device_info.devices[n].status
+ dprop = result.device_info.devices[n].properties
+
+ # Building the status string
+ # TODO: This formatting should probably be moved elsewhere
+ dstat_msg = []
+ if dprop.read_only == True:
+ dstat_msg.append("Read-Only")
+ if dstat.protected == True and dprop.protectable == True:
+ dstat_msg.append("Write-Protected")
+ if dstat.removed == True and dprop.removable == True:
+ dstat_msg.append("No Media")
+ if dstat.locked == True and dprop.lockable == True:
+ dstat_msg.append("Locked")
+
+ dpath = result.device_info.devices[n].file.name
+ dfile = path.basename(dpath)
+ dparam = result.device_info.devices[n].params
+ dven = result.device_info.devices[n].vendor
+ dprod = result.device_info.devices[n].product
+ drev = result.device_info.devices[n].revision
+ dblock = result.device_info.devices[n].block_size
+
+ device_list.append({"id": did, "un": dun, "device_type": dtype, \
+ "status": ", ".join(dstat_msg), "image": dpath, "file": dfile, "params": dparam,\
+ "vendor": dven, "product": dprod, "revision": drev, "block_size": dblock})
+ occupied_ids.append(did)
+ n += 1
+ return device_list, occupied_ids
+
+
+def sort_and_format_devices(device_list, occupied_ids):
+ # Add padding devices and sort the list
for id in range(8):
- device_list.append({"id": str(id), "un": "-", "type": "-", "file": "-"})
- output = subprocess.run(["rasctl", "-l"], capture_output=True).stdout.decode(
- "utf-8"
- )
- for line in output.splitlines():
- # Valid line to process, continue
- if (
- not line.startswith("+")
- and not line.startswith("| ID |")
- and (
- not line.startswith("No device is installed.")
- or line.startswith("No images currently attached.")
- )
- and len(line) > 0
- ):
- line.rstrip()
- device = {}
- segments = line.split("|")
- if len(segments) > 4:
- idx = int(segments[1].strip())
- device_list[idx]["id"] = str(idx)
- device_list[idx]["un"] = segments[2].strip()
- device_list[idx]["type"] = segments[3].strip()
- device_list[idx]["file"] = segments[4].strip()
+ if id not in occupied_ids:
+ device_list.append({"id": id, "type": "-", \
+ "status": "-", "file": "-", "product": "-"})
+ # Sort list of devices by id
+ device_list.sort(key=lambda dic: str(dic["id"]))
return device_list
+
def reserve_scsi_ids(reserved_scsi_ids):
- scsi_ids = ",".join(list(reserved_scsi_ids))
- return subprocess.run(["rasctl", "-r", scsi_ids])
+ command = proto.PbCommand()
+ command.operation = proto.PbOperation.RESERVE
+ command.params.append(reserved_scsi_ids)
+
+ data = send_pb_command(command.SerializeToString())
+ result = proto.PbResult()
+ result.ParseFromString(data)
+ return {"status": result.status, "msg": result.msg}
+
+
+def set_log_level(log_level):
+ '''Sends a command to the server to change the log level. Takes target log level as an argument'''
+ command = proto.PbCommand()
+ command.operation = proto.PbOperation.LOG_LEVEL
+ command.params.append(str(log_level))
+
+ data = send_pb_command(command.SerializeToString())
+ result = proto.PbResult()
+ result.ParseFromString(data)
+ return {"status": result.status, "msg": result.msg}
+
+
+def send_pb_command(payload):
+ # Host and port number where rascsi is listening for socket connections
+ HOST = 'localhost'
+ PORT = 6868
+
+ counter = 0
+ tries = 100
+ error_msg = ""
+
+ import socket
+ while counter < tries:
+ try:
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
+ s.connect((HOST, PORT))
+ return send_over_socket(s, payload)
+ except socket.error as error:
+ counter += 1
+ logging.warning("The RaSCSI service is not responding - attempt " + \
+ str(counter) + "/" + str(tries))
+ error_msg = str(error)
+
+ logging.error(error_msg)
+
+ # After failing all attempts, throw a 404 error
+ from flask import abort
+ abort(404, "Failed to connect to RaSCSI at " + str(HOST) + ":" + str(PORT) + \
+ " with error: " + error_msg + ". Is the RaSCSI service running?")
+
+
+def send_over_socket(s, payload):
+ from struct import pack, unpack
+
+ # Prepending a little endian 32bit header with the message size
+ s.send(pack("= 4:
+ # Extracting the response header to get the length of the response message
+ response_length = unpack("=3.17.3
diff --git a/src/web/settings.py b/src/web/settings.py
index 85036168..a91156e7 100644
--- a/src/web/settings.py
+++ b/src/web/settings.py
@@ -1,4 +1,14 @@
-import os
+from os import getenv
-base_dir = os.getenv("BASE_DIR", "/home/pi/images/")
-MAX_FILE_SIZE = os.getenv("MAX_FILE_SIZE", 1024 * 1024 * 1024 * 2) # 2gb
+base_dir = getenv("BASE_DIR", "/home/pi/images/")
+DEFAULT_CONFIG = base_dir + "default.json"
+MAX_FILE_SIZE = getenv("MAX_FILE_SIZE", 1024 * 1024 * 1024 * 2) # 2gb
+
+HARDDRIVE_FILE_SUFFIX = ("hda", "hdn", "hdi", "nhd", "hdf", "hds")
+CDROM_FILE_SUFFIX = ("iso", "cdr", "toast", "img")
+REMOVABLE_FILE_SUFFIX = ("hdr",)
+ARCHIVE_FILE_SUFFIX = ("zip",)
+VALID_FILE_SUFFIX = HARDDRIVE_FILE_SUFFIX + REMOVABLE_FILE_SUFFIX + \
+ CDROM_FILE_SUFFIX + ARCHIVE_FILE_SUFFIX
+
+REMOVABLE_DEVICE_TYPES = ("SCCD", "SCRM", "SCMO")
diff --git a/src/web/static/style.css b/src/web/static/style.css
index 9d5dd136..108a3063 100644
--- a/src/web/static/style.css
+++ b/src/web/static/style.css
@@ -41,4 +41,9 @@ table, tr, td {
color: white;
font-size:20px;
background-color:green;
-}
\ No newline at end of file
+}
+
+td.inactive {
+ text-align:center;
+ background-color:tan;
+}
diff --git a/src/web/templates/index.html b/src/web/templates/index.html
index fab180a2..e9c35aca 100644
--- a/src/web/templates/index.html
+++ b/src/web/templates/index.html
@@ -1,7 +1,7 @@
{% extends "base.html" %}
{% block header %}
-{% if active %}
+{% if server_info["status"] == True %}
Service Running
{% else %}
Service Stopped
@@ -21,12 +21,11 @@
{% block content %}
Current RaSCSI Configuration
- The default configuration will be loaded when the Web UI starts up.
+ The default configuration will be loaded when the Web UI starts up, if available.
ID |
Type |
+ Status |
File |
- Action |
+ Product |
+ Actions |
{% for device in devices %}
- {% if device.id not in reserved_scsi_ids %}
+ {% if device["id"]|string() not in reserved_scsi_ids %}
{{device.id}} |
- {{device.type}} |
- {{device.file}} |
-
- {% if device.type == "SCCD" and device.file != "NO MEDIA" %}
+ | {{device.device_type}} |
+ {{device.status}} |
+ {{device.file}} |
+ {% if device.vendor == "RaSCSI" %}
+ {{device.product}} |
+ {% else %}
+ {{device.vendor}} {{device.product}} |
+ {% endif %}
+
+ {% if device.device_type in removable_device_types and "No Media" not in device.status %}
+
+ {% elif device.device_type in ["-"] %}
+ -
{% else %}
+
{% endif %}
|
{% else %}
- {{device.id}} |
- - |
- Reserved ID |
- - |
+ {{device.id}} |
+ |
+ Reserved ID |
+ |
+ |
+ |
{% endif %}
{% endfor %}
@@ -96,24 +116,27 @@
|
- {% if file[0].endswith('.zip') or file[0].endswith('.ZIP') %}
+ {% if file[0].lower().endswith(archive_file_suffix) %}
|
+ Supported file types: {{valid_file_suffix|string()}}
Attach Ethernet Adapter
- Emulates a SCSI DaynaPORT Ethernet Adapter. Host drivers required.
+ Emulates a SCSI DaynaPORT Ethernet Adapter. Host drivers required.
+
+ Logging
+
+
+
+
+ Server Log Level
+
+
+
+
Raspberry Pi Operations
+
{% endblock %}
{% block footer %}
- {{version}}
- Logs
+RaSCSI version: {{server_info["version"]}}
+Server log level: {{server_info["current_log_level"]}}
+{{version}}
{% endblock %}
diff --git a/src/web/web.py b/src/web/web.py
index 23a4f2f0..3cc88fd2 100644
--- a/src/web/web.py
+++ b/src/web/web.py
@@ -1,35 +1,37 @@
-import io
-import re
-import sys
-
from flask import Flask, render_template, request, flash, url_for, redirect, send_file, send_from_directory
from file_cmds import (
+ list_files,
+ list_config_files,
create_new_image,
download_file_to_iso,
delete_file,
unzip_file,
download_image,
- write_config_csv,
- read_config_csv,
+ write_config,
+ read_config,
+ read_device_config,
+)
+from pi_cmds import (
+ shutdown_pi,
+ reboot_pi,
+ running_version,
+ rascsi_service,
+ is_bridge_setup,
)
-from pi_cmds import shutdown_pi, reboot_pi, running_version, rascsi_service
from ractl_cmds import (
attach_image,
list_devices,
- is_active,
- list_files,
+ sort_and_format_devices,
detach_by_id,
eject_by_id,
get_valid_scsi_ids,
attach_daynaport,
- is_bridge_setup,
- daynaport_setup_bridge,
- list_config_files,
detach_all,
- valid_file_suffix,
- valid_file_types,
reserve_scsi_ids,
+ get_server_info,
+ validate_scsi_id,
+ set_log_level,
)
from settings import *
@@ -38,21 +40,28 @@ app = Flask(__name__)
@app.route("/")
def index():
- devices = list_devices()
reserved_scsi_ids = app.config.get("RESERVED_SCSI_IDS")
- scsi_ids = get_valid_scsi_ids(devices, list(reserved_scsi_ids))
+ unsorted_devices, occupied_ids = list_devices()
+ devices = sort_and_format_devices(unsorted_devices, occupied_ids)
+ scsi_ids = get_valid_scsi_ids(devices, list(reserved_scsi_ids), occupied_ids)
return render_template(
"index.html",
- bridge_configured=is_bridge_setup("eth0"),
+ bridge_configured=is_bridge_setup(),
devices=devices,
- active=is_active(),
files=list_files(),
config_files=list_config_files(),
base_dir=base_dir,
scsi_ids=scsi_ids,
- reserved_scsi_ids=reserved_scsi_ids,
+ reserved_scsi_ids=[reserved_scsi_ids],
max_file_size=MAX_FILE_SIZE,
version=running_version(),
+ server_info=get_server_info(),
+ valid_file_suffix=VALID_FILE_SUFFIX,
+ removable_device_types=REMOVABLE_DEVICE_TYPES,
+ harddrive_file_suffix=HARDDRIVE_FILE_SUFFIX,
+ cdrom_file_suffix=CDROM_FILE_SUFFIX,
+ removable_file_suffix=REMOVABLE_FILE_SUFFIX,
+ archive_file_suffix=ARCHIVE_FILE_SUFFIX,
)
@app.route('/pwa/')
@@ -62,10 +71,15 @@ def send_pwa_files(path):
@app.route("/config/save", methods=["POST"])
def config_save():
file_name = request.form.get("name") or "default"
- file_name = f"{base_dir}{file_name}.csv"
+ file_name = f"{base_dir}{file_name}.json"
- write_config_csv(file_name)
- flash(f"Saved config to {file_name}!")
+ process = write_config(file_name)
+ if process["status"] == True:
+ flash(f"Saved config to {file_name}!")
+ return redirect(url_for("index"))
+ else:
+ flash(f"Failed to saved config to {file_name}!", "error")
+ flash(f"{process['msg']}", "error")
return redirect(url_for("index"))
@@ -75,10 +89,12 @@ def config_load():
file_name = f"{base_dir}{file_name}"
if "load" in request.form:
- if read_config_csv(file_name):
+ process = read_config(file_name)
+ if process["status"] == True:
flash(f"Loaded config from {file_name}!")
else:
flash(f"Failed to load {file_name}!", "error")
+ flash(f"{process['msg']}", "error")
elif "delete" in request.form:
if delete_file(file_name):
flash(f"Deleted config {file_name}!")
@@ -88,16 +104,20 @@ def config_load():
return redirect(url_for("index"))
-@app.route("/logs")
-def logs():
- import subprocess
+@app.route("/logs/show", methods=["POST"])
+def show_logs():
+ lines = request.form.get("lines") or "200"
+ scope = request.form.get("scope") or "default"
- lines = request.args.get("lines") or "100"
- process = subprocess.run(["journalctl", "-n", lines], capture_output=True)
+ from subprocess import run
+ if scope != "default":
+ process = run(["journalctl", "-n", lines, "-u", scope], capture_output=True)
+ else:
+ process = run(["journalctl", "-n", lines], capture_output=True)
if process.returncode == 0:
headers = {"content-type": "text/plain"}
- return process.stdout.decode("utf-8"), 200, headers
+ return process.stdout.decode("utf-8"), int(lines), headers
else:
flash("Failed to get logs")
flash(process.stdout.decode("utf-8"), "stdout")
@@ -105,86 +125,112 @@ def logs():
return redirect(url_for("index"))
+@app.route("/logs/level", methods=["POST"])
+def log_level():
+ level = request.form.get("level") or "info"
+
+ process = set_log_level(level)
+ if process["status"] == True:
+ flash(f"Log level set to {level}!")
+ return redirect(url_for("index"))
+ else:
+ flash(f"Failed to set log level to {level}!", "error")
+ flash(process["msg"], "error")
+ return redirect(url_for("index"))
+
+
@app.route("/daynaport/attach", methods=["POST"])
def daynaport_attach():
scsi_id = request.form.get("scsi_id")
+
+ validate = validate_scsi_id(scsi_id)
+ if validate["status"] == False:
+ flash(validate["msg"], "error")
+ return redirect(url_for("index"))
+
process = attach_daynaport(scsi_id)
- if process.returncode == 0:
+ if process["status"] == True:
flash(f"Attached DaynaPORT to SCSI id {scsi_id}!")
return redirect(url_for("index"))
else:
flash(f"Failed to attach DaynaPORT to SCSI id {scsi_id}!", "error")
- flash(process.stdout.decode("utf-8"), "stdout")
- flash(process.stderr.decode("utf-8"), "stderr")
- return redirect(url_for("index"))
-
-
-@app.route("/daynaport/setup", methods=["POST"])
-def daynaport_setup():
- # Future use for wifi
- interface = request.form.get("interface") or "eth0"
- process = daynaport_setup_bridge(interface)
- if process.returncode == 0:
- flash(f"Configured DaynaPORT bridge on {interface}!")
- return redirect(url_for("index"))
- else:
- flash(f"Failed to configure DaynaPORT bridge on {interface}!", "error")
- flash(process.stdout.decode("utf-8"), "stdout")
- flash(process.stderr.decode("utf-8"), "stderr")
+ flash(process["msg"], "error")
return redirect(url_for("index"))
@app.route("/scsi/attach", methods=["POST"])
def attach():
file_name = request.form.get("file_name")
+ file_size = request.form.get("file_size")
scsi_id = request.form.get("scsi_id")
- # Validate image type by suffix
- print("file_name", file_name)
- print("valid_file_types: ", valid_file_types)
- if re.match(valid_file_types, file_name):
- if file_name.lower().endswith((".iso", ".cdr", ".toast", ".img")):
- image_type = "SCCD"
- else:
- image_type = "SCHD"
- else:
- flash(f"Unknown file type. Valid files are: {', '.join(valid_file_suffix)}", "error")
+ validate = validate_scsi_id(scsi_id)
+ if validate["status"] == False:
+ flash(validate["msg"], "error")
return redirect(url_for("index"))
- # Validate the SCSI ID
- if re.match("[0-7]", str(scsi_id)) == None:
- flash(f"Invalid SCSI ID. Should be a number between 0-7", "error")
- return redirect(url_for("index"))
+ kwargs = {"image": file_name}
- process = attach_image(scsi_id, file_name, image_type)
- if process.returncode == 0:
+ # Attempt to load the device config sidecar file:
+ # same base path but .rascsi instead of the original suffix.
+ from pathlib import Path
+ device_config = Path(base_dir + str(Path(file_name).stem) + ".rascsi")
+ if device_config.is_file():
+ process = read_device_config(device_config)
+ if process["status"] == False:
+ flash(process["msg"], "error")
+ return redirect(url_for("index"))
+ conf = process["conf"]
+ conf_file_size = conf["blocks"] * conf["block_size"]
+ if conf_file_size != 0 and conf_file_size > int(file_size):
+ flash(f"Failed to attach {file_name} to SCSI id {scsi_id}!", "error")
+ flash(f"The file size {file_size} bytes needs to be at least {conf_file_size} bytes.", "error")
+ return redirect(url_for("index"))
+ kwargs["device_type"] = conf["device_type"]
+ kwargs["vendor"] = conf["vendor"]
+ kwargs["product"] = conf["product"]
+ kwargs["revision"] = conf["revision"]
+ kwargs["block_size"] = conf["block_size"]
+ # Validate image type by file name suffix as fallback
+ elif file_name.lower().endswith(CDROM_FILE_SUFFIX):
+ kwargs["device_type"] = "SCCD"
+ elif file_name.lower().endswith(REMOVABLE_FILE_SUFFIX):
+ kwargs["device_type"] = "SCRM"
+ elif file_name.lower().endswith(HARDDRIVE_FILE_SUFFIX):
+ kwargs["device_type"] = "SCHD"
+
+ process = attach_image(scsi_id, **kwargs)
+ if process["status"] == True:
flash(f"Attached {file_name} to SCSI id {scsi_id}!")
return redirect(url_for("index"))
else:
flash(f"Failed to attach {file_name} to SCSI id {scsi_id}!", "error")
- flash(process.stdout.decode("utf-8"), "stdout")
- flash(process.stderr.decode("utf-8"), "stderr")
+ flash(process["msg"], "error")
return redirect(url_for("index"))
@app.route("/scsi/detach_all", methods=["POST"])
def detach_all_devices():
- detach_all()
- flash("Detached all SCSI devices!")
- return redirect(url_for("index"))
+ process = detach_all()
+ if process["status"] == True:
+ flash("Detached all SCSI devices!")
+ return redirect(url_for("index"))
+ else:
+ flash("Failed to detach all SCSI devices!", "error")
+ flash(process["msg"], "error")
+ return redirect(url_for("index"))
@app.route("/scsi/detach", methods=["POST"])
def detach():
scsi_id = request.form.get("scsi_id")
process = detach_by_id(scsi_id)
- if process.returncode == 0:
- flash("Detached SCSI id " + scsi_id + "!")
+ if process["status"] == True:
+ flash(f"Detached SCSI id {scsi_id}!")
return redirect(url_for("index"))
else:
- flash("Failed to detach SCSI id " + scsi_id + "!", "error")
- flash(process.stdout, "stdout")
- flash(process.stderr, "stderr")
+ flash(f"Failed to detach SCSI id {scsi_id}!", "error")
+ flash(process["msg"], "error")
return redirect(url_for("index"))
@@ -192,15 +238,35 @@ def detach():
def eject():
scsi_id = request.form.get("scsi_id")
process = eject_by_id(scsi_id)
- if process.returncode == 0:
- flash("Ejected scsi id " + scsi_id + "!")
+ if process["status"] == True:
+ flash(f"Ejected scsi id {scsi_id}!")
return redirect(url_for("index"))
else:
- flash("Failed to eject SCSI id " + scsi_id + "!", "error")
- flash(process.stdout, "stdout")
- flash(process.stderr, "stderr")
+ flash(f"Failed to eject SCSI id {scsi_id}!", "error")
+ flash(process["msg"], "error")
return redirect(url_for("index"))
+@app.route("/scsi/info", methods=["POST"])
+def device_info():
+ scsi_id = request.form.get("scsi_id")
+ # Extracting the 0th dictionary in list index 0
+ device = list_devices(scsi_id)[0][0]
+ if str(device["id"]) == scsi_id:
+ flash("=== DEVICE INFO ===")
+ flash(f"SCSI ID: {device['id']}")
+ flash(f"Unit: {device['un']}")
+ flash(f"Type: {device['device_type']}")
+ flash(f"Status: {device['status']}")
+ flash(f"File: {device['image']}")
+ flash(f"Parameters: {device['params']}")
+ flash(f"Vendor: {device['vendor']}")
+ flash(f"Product: {device['product']}")
+ flash(f"Revision: {device['revision']}")
+ flash(f"Block Size: {device['block_size']}")
+ return redirect(url_for("index"))
+ else:
+ flash(f"Failed to get device info for SCSI id {scsi_id}!", "error")
+ return redirect(url_for("index"))
@app.route("/pi/reboot", methods=["POST"])
def restart():
@@ -231,23 +297,27 @@ def download_file():
scsi_id = request.form.get("scsi_id")
url = request.form.get("url")
process = download_file_to_iso(scsi_id, url)
- if process.returncode == 0:
- flash("File Downloaded")
+ if process["status"] == True:
+ flash(f"File Downloaded and Attached to SCSI id {scsi_id}")
+ flash(process["msg"])
return redirect(url_for("index"))
else:
- flash("Failed to download file", "error")
- flash(process.stdout, "stdout")
- flash(process.stderr, "stderr")
+ flash(f"Failed to download and attach file {url}", "error")
+ flash(process["msg"], "error")
return redirect(url_for("index"))
@app.route("/files/download_image", methods=["POST"])
def download_img():
url = request.form.get("url")
- # TODO: error handling
- download_image(url)
- flash("File Downloaded")
- return redirect(url_for("index"))
+ process = download_image(url)
+ if process["status"] == True:
+ flash(f"File Downloaded from {url}")
+ return redirect(url_for("index"))
+ else:
+ flash(f"Failed to download file {url}", "error")
+ flash(process["msg"], "error")
+ return redirect(url_for("index"))
@app.route("/files/upload/", methods=["POST"])
@@ -256,19 +326,22 @@ def upload_file(filename):
flash("No file provided.", "error")
return redirect(url_for("index"))
- file_path = os.path.join(app.config["UPLOAD_FOLDER"], filename)
- if os.path.isfile(file_path):
+ from os import path
+ file_path = path.join(app.config["UPLOAD_FOLDER"], filename)
+ if path.isfile(file_path):
flash(f"{filename} already exists.", "error")
return redirect(url_for("index"))
+ from io import DEFAULT_BUFFER_SIZE
binary_new_file = "bx"
- with open(file_path, binary_new_file, buffering=io.DEFAULT_BUFFER_SIZE) as f:
- chunk_size = io.DEFAULT_BUFFER_SIZE
+ with open(file_path, binary_new_file, buffering=DEFAULT_BUFFER_SIZE) as f:
+ chunk_size = DEFAULT_BUFFER_SIZE
while True:
chunk = request.stream.read(chunk_size)
if len(chunk) == 0:
break
f.write(chunk)
+ # TODO: display an informative success message
return redirect(url_for("index", filename=filename))
@@ -322,17 +395,25 @@ if __name__ == "__main__":
app.secret_key = "rascsi_is_awesome_insecure_secret_key"
app.config["SESSION_TYPE"] = "filesystem"
app.config["UPLOAD_FOLDER"] = base_dir
- os.makedirs(app.config["UPLOAD_FOLDER"], exist_ok=True)
+
+ from os import makedirs
+ makedirs(app.config["UPLOAD_FOLDER"], exist_ok=True)
app.config["MAX_CONTENT_LENGTH"] = MAX_FILE_SIZE
- if len(sys.argv) >= 2:
- app.config["RESERVED_SCSI_IDS"] = str(sys.argv[1])
+
+ from sys import argv
+ if len(argv) >= 2:
+ # Reserved ids format is a string of digits such as '017'
+ app.config["RESERVED_SCSI_IDS"] = str(argv[1])
# Reserve SCSI IDs on the backend side to prevent use
reserve_scsi_ids(app.config.get("RESERVED_SCSI_IDS"))
else:
app.config["RESERVED_SCSI_IDS"] = ""
- # Load the configuration in default.cvs, if it exists
- read_config_csv(f"{base_dir}default.csv")
+ # Load the default configuration file, if found
+ from pathlib import Path
+ default_config = Path(DEFAULT_CONFIG)
+ if default_config.is_file():
+ read_config(default_config)
import bjoern
print("Serving rascsi-web...")