Archived
1
Fork 0
Python-script for batch copying floppy disks. No active development is being done publicly on this repository, which is why it has been archived. Relates to this blog post: https://uuksu.fi/blog/korppujen-sailonta/
This repository has been archived on 2026-02-11. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
Find a file
2026-02-11 15:16:25 +02:00
floppy-batch.py Add initial files 2026-02-11 15:16:25 +02:00
LICENSE.md Add initial files 2026-02-11 15:16:25 +02:00
README.md Add initial files 2026-02-11 15:16:25 +02:00

floppy-batch.py

Batch process floppy disks by mounting, checking for files, and creating disk images with dd.

Features

  • Interactive batch processing workflow for multiple floppy disks
  • Automatic disk detection - monitors device and detects when disk is inserted and ready
  • Duplicate prevention - tracks processed IDs and warns about duplicates
  • Prompts for floppy ID before each disk
  • Attempts to mount floppy with multiple filesystem types (msdos, vfat, ext2, auto)
  • Checks if disk contains any files before proceeding
  • Preserves volume label - reads original disk name and sets it on the image
  • Creates disk images using dd or ddrescue (optional flag)
  • ddrescue support - superior error recovery with detailed progress monitoring
  • Intelligent fallback for damaged disks - if raw copy fails, automatically creates image and copies files one-by-one
  • Partial data recovery from broken disks (copies what it can, skips unreadable files)
  • Skips empty disks automatically
  • Per-floppy logging - each disk gets its own detailed log file
  • Comprehensive logging with timestamps and status tracking
  • Handles filenames with invalid/corrupted characters gracefully
  • Robust error handling with graceful degradation
  • Automatic cleanup (unmounts) even on errors
  • Progress display during disk imaging
  • Automatic disk removal detection before proceeding to next disk

Usage

Important: This script must be run as root to access the floppy drive device.

sudo ./scripts/floppy-batch.py
sudo ./scripts/floppy-batch.py --device /dev/sde --output ./my_floppies
sudo ./scripts/floppy-batch.py --mount-point /mnt/floppy --output ./archive
sudo ./scripts/floppy-batch.py --ddrescue  # Use ddrescue for better error recovery

Options

  • --device PATH - Floppy drive device path (default: /dev/sde)
  • --output DIR - Output directory for disk images and log files (default: ./floppy_images)
  • --mount-point PATH - Temporary mount point for floppy disk (default: /mnt/floppy_temp)
  • --ddrescue - Use ddrescue instead of dd for disk imaging (recommended for damaged/old disks)

Workflow

For each floppy disk:

  1. User Input - Script prompts for floppy ID
  2. Duplicate Check - Warns if ID was already processed (can override)
  3. Automatic Detection - Monitors device and waits for disk insertion
    • Detects capacity change in /sys/block/sde/size
    • Waits for drive to stabilize (3 stable readings)
    • No manual confirmation needed!
  4. Mount - Script attempts to mount with multiple filesystem types
    • If mount fails: Skip file check, proceed directly to raw imaging
    • If mount succeeds: Continue to file check
  5. Check Files (if mounted) - Scans mounted disk for any files
  6. Decision Point (if mounted):
    • If no files: Log status, unmount, mark as processed, skip imaging
    • If files found: Continue to imaging
  7. Read Volume Label (if mounted) - Captures original disk name (if present)
  8. Unmount - Unmount before creating image (if was mounted)
  9. Create Image - Use dd to create .img file named with the floppy ID
    • Volume label is preserved automatically in raw copy
    • If dd fails: Automatic fallback to manual copy method
      1. Create empty 1.44MB FAT12 image with original volume label
      2. Mount as loop device
      3. Copy files one-by-one from source
      4. Log success/failure for each file
      5. Succeeds if at least one file copied
  10. Log Result - Write final status to log file and mark ID as processed
  11. Wait for Removal - Automatically detects when disk is removed
  12. Repeat - Return to step 1 for next disk

Exit anytime by typing q or pressing Ctrl+C.

Output Format

Directory Structure

floppy_images/
├── session.log         # Session-level log (overall progress)
├── processed_ids.txt   # List of already-processed IDs (prevents duplicates)
├── disk001.img         # Disk image for ID: disk001 (raw dd/ddrescue copy)
├── disk001.log         # Detailed log for disk001
├── disk001.map         # ddrescue map file (if using --ddrescue)
├── disk002.img         # Partial raw image for disk002
├── disk002_files.img   # Fallback file-by-file recovery image for disk002
├── disk002.log         # Detailed log for disk002
└── archive_1995.img    # Disk image for ID: archive_1995
└── archive_1995.log    # Detailed log for archive_1995

Log File Format

[2026-02-08 14:30:15] === Batch processing session started ===
[2026-02-08 14:30:25] [disk001] Starting processing
[2026-02-08 14:30:26] [disk001] Successfully mounted
[2026-02-08 14:30:26] [disk001] Found 5 file(s)
[2026-02-08 14:30:26] [disk001]   - README.TXT
[2026-02-08 14:30:26] [disk001]   - DATA.DAT
[2026-02-08 14:30:26] [disk001]   - CONFIG.SYS
[2026-02-08 14:30:26] [disk001]   - AUTOEXEC.BAT
[2026-02-08 14:30:26] [disk001]   - DOCS/MANUAL.TXT
[2026-02-08 14:30:26] [disk001] Original volume label: BACKUP95
[2026-02-08 14:30:26] [disk001] dd image created successfully (1.41 MB)
[2026-02-08 14:30:26] [disk001] Volume label: BACKUP95
[2026-02-08 14:30:45] [disk001] SUCCESS: Disk image created
[2026-02-08 14:31:02] [disk002] Starting processing
[2026-02-08 14:31:02] [disk002] WARNING: Could not mount floppy disk
[2026-02-08 14:31:02] [disk002] Will attempt raw disk imaging without file listing
[2026-02-08 14:31:05] [disk002] ddrescue image created successfully (1.41 MB)
[2026-02-08 14:31:05] [disk002] SUCCESS: Disk image created
[2026-02-08 14:31:15] [disk003] Starting processing
[2026-02-08 14:31:15] [disk003] Successfully mounted
[2026-02-08 14:31:15] [disk003] No files found on disk - skipping
[2026-02-08 14:32:00] [damaged_disk] Starting processing
[2026-02-08 14:32:01] [damaged_disk] Successfully mounted
[2026-02-08 14:32:01] [damaged_disk] Found 3 file(s)
[2026-02-08 14:32:01] [damaged_disk]   - FILE1.TXT
[2026-02-08 14:32:01] [damaged_disk]   - FILE2.DAT
[2026-02-08 14:32:01] [damaged_disk]   - CORRUPT.BIN
[2026-02-08 14:32:01] [damaged_disk] Original volume label: OLDDISK
[2026-02-08 14:32:05] [damaged_disk] dd failed, attempting manual file-by-file copy
[2026-02-08 14:32:05] [damaged_disk] Creating fallback image: damaged_disk_files.img
[2026-02-08 14:32:05] [damaged_disk] Creating empty 1.44MB image file
[2026-02-08 14:32:06] [damaged_disk] Formatting image as FAT12
[2026-02-08 14:32:06] [damaged_disk] Volume label set: OLDDISK
[2026-02-08 14:32:06] [damaged_disk] Setting up loop device
[2026-02-08 14:32:06] [damaged_disk] Loop device: /dev/loop0
[2026-02-08 14:32:07] [damaged_disk] Copying 3 files individually
[2026-02-08 14:32:07] [damaged_disk]   ✓ FILE1.TXT
[2026-02-08 14:32:07] [damaged_disk]   ✓ FILE2.DAT
[2026-02-08 14:32:08] [damaged_disk]   ✗ CORRUPT.BIN - Input/output error
[2026-02-08 14:32:08] [damaged_disk] Copy complete: 2 succeeded, 1 failed
[2026-02-08 14:32:09] [damaged_disk] SUCCESS: Disk image created
[2026-02-08 14:33:00] === Batch processing session ended ===

Example Session

Standard Mode (dd)

$ sudo ./scripts/floppy-batch.py
============================================================
Floppy Disk Batch Processor
============================================================
Device: /dev/sde
Output directory: ./floppy_images
Session log: ./floppy_images/session.log
Mount point: /mnt/floppy_temp
Imaging tool: dd
============================================================

Press Ctrl+C to exit at any time

Enter floppy ID (or 'q' to quit): backup_1995

Waiting for floppy disk insertion...
(Insert disk now, detection is automatic)
Disk stabilizing... (2880 blocks)
✓ Disk detected (2880 blocks)

Mounting floppy from /dev/sde...
[2026-02-08 14:30:26] [backup_1995] Successfully mounted
[2026-02-08 14:30:26] [backup_1995] Found 12 file(s)
[2026-02-08 14:30:26] [backup_1995]   - README.TXT
[2026-02-08 14:30:26] [backup_1995]   - LETTER.DOC
...
Unmounting before creating image...
Creating disk image: ./floppy_images/backup_1995.img
[2026-02-08 14:30:45] [backup_1995] SUCCESS: Disk image created

Waiting for disk removal...
(Remove disk to continue with next one)
✓ Disk removed

Enter floppy ID (or 'q' to quit): backup_1995

⚠️  WARNING: Floppy ID 'backup_1995' has already been processed!
Process anyway? (y/N): n
Skipping duplicate ID

Enter floppy ID (or 'q' to quit): q

Session complete. Check logs for details:
  Session log: ./floppy_images/session.log
  Individual logs: ./floppy_images/<floppy_id>.log
Total processed: 1 disk(s)

ddrescue Mode (--ddrescue flag)

$ sudo ./scripts/floppy-batch.py --ddrescue
============================================================
Floppy Disk Batch Processor
============================================================
Device: /dev/sde
Output directory: ./floppy_images
Session log: ./floppy_images/session.log
Mount point: /mnt/floppy_temp
Imaging tool: ddrescue
============================================================

Enter floppy ID (or 'q' to quit): damaged_disk

Waiting for floppy disk insertion...
(Insert disk now, detection is automatic)
✓ Disk detected (2880 blocks)

Mounting floppy from /dev/sde...
[2026-02-08 14:30:26] [damaged_disk] Successfully mounted
[2026-02-08 14:30:26] [damaged_disk] Found 5 file(s)
[2026-02-08 14:30:26] [damaged_disk] Original volume label: OLDDISK
Unmounting before creating image...
Creating disk image with ddrescue: ./floppy_images/damaged_disk.img

GNU ddrescue 1.27
Press Ctrl-C to interrupt
     ipos:    1474 kB, non-trimmed:        0 B,  current rate:  49152 B/s
     opos:    1474 kB, non-scraped:        0 B,  average rate:  47104 B/s
non-tried:        0 B,  bad-sector:        0 B,    error rate:       0 B/s
  rescued:    1474 kB,   bad areas:        0,        run time:         31s
pct rescued:  100.00%, read errors:        0,  remaining time:         n/a
                              time since last successful read:         n/a
Finished

[2026-02-08 14:31:01] [damaged_disk] ddrescue image created successfully (1.41 MB)
[2026-02-08 14:31:01] [damaged_disk] SUCCESS: Disk image created

Waiting for disk removal...
✓ Disk removed

Technical Details

Automatic Disk Detection

The script monitors /sys/block/sde/size to detect disk insertion:

  • Polls every 0.5 seconds for size changes
  • Waits for size to become non-zero (disk inserted)
  • Requires 3 consecutive stable readings before proceeding
  • Adds 1 second final delay for drive stabilization
  • Detects the capacity change events you see in dmesg

This eliminates the need for manual confirmation and ensures the drive is ready before mounting.

Per-Floppy Logging

Each floppy disk gets its own detailed log file:

  • Log file naming: <floppy_id>.log (e.g., disk001.log)
  • Contains: All operations for that specific disk
  • Includes: Mount attempts, file listings, imaging output, errors
  • ddrescue output: Full verbose output captured when using --ddrescue
  • Session log: session.log tracks overall session progress
  • Benefits: Easy to review individual disk processing, troubleshoot specific issues

Duplicate Prevention

Processed floppy IDs are tracked in processed_ids.txt:

  • Each processed ID is recorded (success or failure)
  • On startup, previously processed IDs are loaded
  • Warns when attempting to reprocess an ID
  • Allows override if intentional (e.g., retry after fixing disk)
  • Prevents accidental reprocessing of same disk

Volume Label Preservation

The script preserves the original disk name/label:

Reading the label:

  • Uses dosfslabel to read from the device
  • Falls back to blkid if needed
  • Reads while disk is mounted for reliability

Setting the label:

  • dd method: Label automatically preserved in raw copy
  • Fallback method: Sets label during mkfs.msdos -n LABEL formatting
  • FAT12 supports up to 11 characters
  • Logged for reference

This preserves the original disk identity in the archived image.

Mounting Strategy

The script tries multiple filesystem types in order:

  1. msdos - MS-DOS FAT filesystem
  2. vfat - VFAT (Windows 95+ FAT)
  3. ext2 - Linux ext2 filesystem
  4. auto - Let kernel auto-detect

This ensures compatibility with various floppy disk formats.

Disk Imaging with dd

Command used: dd if=/dev/sde of=<id>.img bs=512 conv=noerror,sync status=progress

  • bs=512 - 512-byte blocks (standard floppy sector size)
  • conv=noerror - Continue on read errors
  • conv=sync - Pad failed blocks with zeros
  • status=progress - Show progress during copy

The image will capture the raw disk structure, including:

  • Boot sector
  • File allocation table
  • Directory entries
  • All file data
  • Empty space

Disk Imaging with ddrescue (--ddrescue flag)

Command used: ddrescue -v -d -R -r 3 -b 512 /dev/sde <id>.img <id>.map

Flags explained:

  • -v - Verbose mode (shows detailed progress)
  • -d - Use direct disc access (bypasses OS cache for better hardware error detection)
  • -R - Reverse direction of copying (reads from end to start, useful for damaged media)
  • -r 3 - Retry bad sectors up to 3 times
  • -b 512 - Block size 512 bytes (standard floppy sector size)
  • Creates a map file (.map) tracking which sectors succeeded/failed

Advantages over dd:

  • Better error recovery - Multiple retry strategies
  • Progress monitoring - Real-time status with detailed statistics
  • Rescue maps - Tracks good/bad sectors, can resume interrupted operations
  • Optimized for damaged media - Skips bad sectors initially, retries later
  • Live output - See exactly what's happening during the copy

Output displayed:

  • Current position
  • Rescued data size
  • Error count
  • Average read rate
  • Time elapsed/remaining

All output is shown in terminal AND logged to the floppy's log file.

Fallback Method for Damaged Disks

When dd/ddrescue fails (disk too damaged for raw copy), the script automatically creates a separate fallback image to preserve both copies:

Filenames:

  • Original raw copy attempt: <id>.img (may be partial/corrupted)
  • Fallback file recovery: <id>_files.img (clean FAT12 with recovered files)

Process:

  1. Creates empty image: dd if=/dev/zero of=<id>_files.img bs=1024 count=1440
  2. Formats as FAT12: mkfs.msdos -F 12 <id>_files.img (standard floppy format)
  3. Mounts as loop: losetup -f --show <id>_files.img to get writable image
  4. Copies files individually: Uses cp -p to preserve metadata
  5. Logs each file: Shows ✓ for success, ✗ for failures
  6. Partial success: Succeeds if at least one file copied
  7. Cleanup: Unmounts loop device and detaches

Benefits:

  • Preserves both images: Original raw attempt + clean file recovery
  • Recovers readable data from partially damaged disks
  • Shows exactly which files failed to copy
  • Creates valid FAT12 image with recovered files
  • Can analyze the raw image separately for forensics/data recovery

Limitations:

  • _files.img doesn't capture raw disk structure (boot sector, bad sectors, etc.)
  • Only gets files that can be read through filesystem
  • Lost files won't appear in recovered image

Disk Removal Detection

After processing each disk, the script automatically waits for removal:

  • Monitors /sys/block/sde/size until it returns to 0
  • Polls every 0.5 seconds
  • Prevents starting next disk while previous one is still in drive
  • Ensures clean state between disks

Error Handling

  • Mount failures: Logged as WARNING, continues to raw imaging (dd/ddrescue can read without mounting)
  • No files (when successfully mounted): Logged and skipped (no image created), ID marked as processed
  • Unmount failures: Warning logged, continues to imaging
  • Image creation failures: Logged with FAIL status, ID marked as processed
  • Unexpected errors: Caught and logged, allows continuation, ID marked as processed
  • Always unmounts: Even on error, cleanup is attempted
  • Failed IDs tracked: Prevents infinite retry loops on bad disks

File ID Sanitization

Floppy IDs are sanitized to safe filenames by keeping only:

  • Alphanumeric characters (a-z, A-Z, 0-9)
  • Hyphens (-)
  • Underscores (_)
  • Periods (.)

Requirements

  • Must run as root (sudo)
  • USB floppy drive connected and recognized by Linux
  • Sufficient disk space for images (~1.44MB per floppy)
  • Write permissions in output directory

Dependencies

No external Python dependencies required (uses only standard library).

System requirements:

  • mount command
  • umount command
  • dd command
  • ddrescue command (optional, for --ddrescue flag - highly recommended for old/damaged disks)
  • losetup command (for loop device mounting in fallback mode)
  • mkfs.msdos command (for creating FAT filesystems in fallback mode, usually in dosfstools package)
  • dosfslabel command (for reading/writing volume labels, usually in dosfstools package)
  • blkid command (for reading volume labels as fallback, usually in util-linux package)
  • cp command
  • Linux kernel with floppy drive support

Install ddrescue:

# Debian/Ubuntu
sudo apt install gddrescue

# The command is 'ddrescue' (GNU ddrescue), not 'dd_rescue'

Troubleshooting

"Error: This script must be run as root"

  • Run with sudo

"Error: Device /dev/sde does not exist"

  • Check USB floppy is connected: ls -l /dev/sd*
  • Verify correct device path with dmesg | tail after plugging in

"WARNING: Could not mount floppy disk"

  • Script will continue with raw disk imaging (dd/ddrescue doesn't need mounting)
  • Disk may be corrupted, unformatted, or have unknown filesystem
  • Raw image may still contain recoverable data
  • If imaging succeeds, you can analyze the .img file with data recovery tools

"No files found on disk - skipping"

  • Disk is empty or contains only hidden system files
  • This is expected behavior for blank disks

"dd failed, attempting manual file-by-file copy"

  • Normal for damaged/worn disks that can't be read as raw device
  • Fallback method will recover readable files
  • Check log to see which files succeeded (✓) and failed (✗)
  • Creates two images: <id>.img (partial raw) + <id>_files.img (recovered files)
  • Both images preserved for different recovery approaches

Some files marked with ✗ during manual copy

  • Those specific files have read errors (bad sectors)
  • Other files on same disk may be fine
  • Recovered files are in the .img file
  • Consider the disk worn out, don't reuse it

Disk keeps unmounting during image creation

  • Normal - script unmounts before dd to ensure consistency
  • dd reads from raw device, not mounted filesystem

Automatic detection not working

  • Verify /sys/block/sde/size exists (adjust device name if needed)
  • Check with: cat /sys/block/sde/size before and after inserting disk
  • Should show 0 when empty, 2880 when disk inserted
  • If not working, check dmesg for device name

Script stuck on "Waiting for floppy disk insertion"

  • Make sure you insert the disk AFTER seeing this message
  • If disk already inserted, remove and reinsert it
  • Drive needs to detect the insertion event