DEV Community

Wouter Van Rossem
Wouter Van Rossem

Posted on

Fixing Linux Backup Sync Issues for exFAT Compatibility

A recent issue with synchronizing my home directory to my exFAT-formatted external SSD surfaced while using KDE’s Kup Backup application. Errors occurred because some filenames contained characters not supported by the exFAT file system.

Understanding exFAT's Filename Restrictions

Many external drives use exFAT for cross-platform compatibility. However, exFAT prohibits certain characters in filenames, which can cause issues when backing up files from Linux filesystems.

Filenames can include all Unicode characters except:

  • " (double quote)
  • * (asterisk)
  • : (colon)
  • < (less than)
  • > (greater than)
  • ? (question mark)
  • \ (backslash)
  • / (forward slash)
  • | (pipe)

Filenames also cannot end with a space or a period, but these cases are not currently handled by the script below.

Identifying Problematic Files

Kup Backup logs errors related to such files in ~/.cache/kup/kup_plan1.log. Reviewing this log allowed me to isolate the problematic files. If only a few files are affected, the simple solution is to manually rename them, removing or replacing any unsupported characters.

Automating the Renaming Process with a Bash Script

For a large number of files, the renaming process can be automated. The following Bash script (corrected from an initial version created with ChatGPT) identifies and renames files in given directories that contain invalid characters, replacing each with an underscore.

#!/bin/bash

# Directories to scan
directories=(
    "/path/to/your/directory1"
    "/path/to/your/directory2"
)

# Array of characters to replace
declare -A char_map=(
    ['"']='_'
    ['*']='_'
    [':']='_'
    ['<']='_'
    ['>']='_'
    ['?']='_'
    ['\\']='_'
    ['/']='_'
    ['|']='_'
)

# Function to rename files
rename_files() {
    local dir="$1"
    # Use find to search for files in "$dir" with names containing restricted characters, 
    # then pass each result to the while loop for processing.
    find "$dir" -depth -name '*["*:<>?\\|]*' | while IFS= read -r file; do
        # Get the directory and base name of the file
        dir_path=$(dirname "$file")
        base_name=$(basename "$file")

        # Rename the file
        new_name="$base_name"
        for char in "${!char_map[@]}"; do
            new_name="${new_name//"$char"/${char_map[$char]}}"
        done

        # If the filename has changed, rename it
        if [[ "$base_name" != "$new_name" ]]; then
            mv -v -n "$file" "$dir_path/$new_name"
        fi
    done
}

# Iterate over directories and rename files
for dir in "${directories[@]}"; do
    if [[ -d "$dir" ]]; then
        rename_files "$dir"
    else
        echo "Directory $dir does not exist."
    fi
done
Enter fullscreen mode Exit fullscreen mode

How the Script Works

The script iterates over each specified directory, checks if it exists, and calls the rename_files function.

The rename_files function uses find to locate files with restricted characters in their names. It then iteratively replaces each restricted character with an underscore and renames the file using mv, with verbose flag to explain what is being done. The -n flag makes sure it will not overwrite an existing file.

Usage Instructions

I’ve tested the script, but remember to take precautions to prevent data loss when running it.

After running the process, verify that the files were renamed correctly. Manual post-processing is needed for files that would have caused duplicate names (these files are skipped).

If you encounter any issues or have suggestions for improvements, feel free to reach out and let me know.

Top comments (0)