salut la liste,

j'ai vibe coder un script de récupération, mais j'ai peur que sans r é-écriture du firmware il n'y ai pas grand chose a faire.

je n'ai malheureusement pas d'ordinateur windows pour réparer ce firrmware déféctueux, peut-être qu'un firmware libre pour les clé usb serai un bonne chose.

ne serai-ce pour lui redonner une seconde vie, mais comme dis Basile toute puces sicilium, si elle est de mauvaise qualité s'use, ne serai-ce par les échange micro éléctrique.

je poste ici mon script zsh, s'il peut servir a la communauté, il est sous GPLv3 :

=======================================================
#!/usr/bin/zsh
# ============================================================================= # rescue_transcend.zsh - Script de recuperation pour cle USB Transcend JetFlash
# Copyright (C) 2026 Jean-Christophe Enee
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# =============================================================================

setopt NO_GLOB_SUBST

export PATH="/usr/bin:/bin:/usr/sbin:/sbin"
HOME_DIR="/home/jean-christophe"
DEFAULT_IMG="$HOME_DIR/transcend_rescue.img"
DEFAULT_LOG="$HOME_DIR/transcend_rescue.log"
MOUNT_POINT="$HOME_DIR/rescue_mount"
USB_VID="8564"
USB_PID="1000"
DEVICE=""
TARGET_IMG=""
TARGET_LOG=""
DRY_RUN=false
FORCE=false

if [[ -t 1 ]]; then
    RED=$'\033[0;31m'
    GREEN=$'\033[0;32m'
    YELLOW=$'\033[1;33m'
    BLUE=$'\033[0;34m'
    NC=$'\033[0m'
else
    RED=""
    GREEN=""
    YELLOW=""
    BLUE=""
    NC=""
fi

log_info() { builtin echo "${GREEN}[INFO]${NC} $1"; }
log_warn() { builtin echo "${YELLOW}[WARNING]${NC} $1"; }
log_error() { builtin echo "${RED}[ERROR]${NC} $1"; }
log_step() { builtin echo "${BLUE}[STEP]${NC} $1"; }

check_root() {
[[ $EUID -ne 0 ]] && { log_error "Root requis. Utilisez sudo."; exit 1; }
}

install_dependencies() {
    log_step "Verification des dependances..."
local packages=("usbutils" "gawk" "coreutils" "gddrescue" "util-linux")
    local missing=()
    for pkg in "${packages[@]}"; do
/usr/bin/dpkg -l "$pkg" 2>/dev/null | /usr/bin/grep -q "^ii" || missing+=("$pkg")
    done
    if (( ${#missing} > 0 )); then
        log_info "Installation: ${missing}"
        /usr/bin/apt-get update -qq >/dev/null 2>&1
        /usr/bin/apt-get install -y -qq "${missing[@]}" >/dev/null 2>&1
        for pkg in "${missing[@]}"; do
/usr/bin/dpkg -l "$pkg" 2>/dev/null | /usr/bin/grep -q "^ii" || { log_error "Echec: $pkg"; exit 1; }
        done
        log_info "Dependances installees."
    else
        log_info "Toutes les dependances sont presentes."
    fi
}

check_commands() {
    local required=(
        "/usr/bin/lsusb"
        "/usr/bin/awk"
        "/usr/bin/cut"
        "/usr/bin/ddrescue"
        "/usr/bin/lsblk"
        "/usr/sbin/blockdev"
        "/usr/bin/mount"
        "/usr/bin/umount"
        "/usr/bin/mountpoint"
        "/usr/bin/grep"
    )
    for cmd in "${required[@]}"; do
[[ ! -x "$cmd" ]] && { log_error "Commande manquante: ${cmd##*/}"; exit 1; }
    done
}

setup_mount_point() {
[[ ! -d "$MOUNT_POINT" ]] && /usr/bin/mkdir -p "$MOUNT_POINT" || { log_error "Impossible de creer $MOUNT_POINT"; exit 1; }
}

force_unmount_usb() {
    log_step "Demontage force des peripheriques USB..."
    local devs
devs=$(/usr/bin/lsblk -d -n -o NAME,TRAN 2>/dev/null | /usr/bin/grep -i usb | /usr/bin/awk '{print "/dev/"$1}')
    for dev in $devs; do
/usr/bin/mountpoint -q "$dev" 2>/dev/null && /usr/bin/umount -f "$dev" 2>/dev/null || log_warn "Echec demontage $dev"
    done
    local parts
parts=$(/usr/bin/lsblk -l -n -o NAME,TRAN 2>/dev/null | /usr/bin/grep -i usb | /usr/bin/awk '{print "/dev/"$1}')
    for part in $parts; do
/usr/bin/mountpoint -q "$part" 2>/dev/null && /usr/bin/umount -f "$part" 2>/dev/null || log_warn "Echec demontage $part"
    done
    /usr/bin/sleep 1
}

force_unbind_usb_drivers() {
    log_step "Detachement force des pilotes USB..."
    if [[ -d "/sys/bus/usb/drivers/usb-storage" ]]; then
        for usb_dev in /sys/bus/usb/drivers/usb-storage/*:1.0(N); do
[[ -e "$usb_dev" ]] && builtin echo "${usb_dev##*/}" > /sys/bus/usb/drivers/usb-storage/unbind 2>/dev/null && log_info "Detache: ${usb_dev##*/}"
        done
    fi
    if [[ -d "/sys/class/scsi_host" ]]; then
        for scsi_host in /sys/class/scsi_host/host*(N); do
[[ -e "$scsi_host/scan" ]] && builtin echo "- - -" > "$scsi_host/scan" 2>/dev/null && log_info "SCSI reset: ${scsi_host##*/}"
        done
        for scsi_dev in /sys/bus/scsi/devices/*(N); do
[[ -e "$scsi_dev/delete" ]] && builtin echo 1 > "$scsi_dev/delete" 2>/dev/null && log_info "SCSI deconnecte: ${scsi_dev##*/}"
        done
    else
        log_info "Aucun controleur SCSI (normal)."
    fi
    /usr/bin/sleep 2
}

find_usb_device() {
    local path
path=$(/usr/bin/lsusb -d "$USB_VID:$USB_PID" 2>/dev/null | /usr/bin/awk '{print $2}' | /usr/bin/cut -d: -f1) [[ -z "$path" ]] && { log_error "Cle Transcend (VID:PID=$USB_VID:$USB_PID) introuvable. Branchez-la."; exit 1; }
    log_info "Cle trouvee en: ${path}:1.0"
}

wait_for_device() {
    local max=20 attempt=1
    while [[ $attempt -le $max ]]; do
DEVICE=$(/usr/bin/lsblk -d -n -o NAME,TRAN 2>/dev/null | /usr/bin/grep -i usb | /usr/bin/head -n1 | /usr/bin/awk '{print "/dev/"$1}') [[ -n "$DEVICE" && -e "$DEVICE" ]] && { log_info "Peripherique detecte: $DEVICE"; return 0; }
        log_step "Attente peripherique ($attempt/$max)..."
        /usr/bin/sleep 2
        ((attempt++))
    done
    log_error "Peripherique USB non detecte."
    return 1
}

bind_usb_storage() {
    local usb_bus
    usb_bus=${DEVICE#/dev/}
if [[ -n "$usb_bus" && -e "/sys/bus/usb/drivers/usb-storage/${usb_bus}:1.0" ]]; then builtin echo "${usb_bus}:1.0" > /sys/bus/usb/drivers/usb-storage/bind 2>/dev/null && log_info "Pilote reattache: ${usb_bus}:1.0" || log_warn "Reattachement impossible pour ${usb_bus}:1.0"
    else
        log_warn "Reattachement impossible"
    fi
}

check_disk_space() {
    local size_bytes
size_bytes=$(/usr/sbin/blockdev --getsize64 "$DEVICE" 2>/dev/null || builtin echo 0)
    local required_gb=$(( size_bytes / 1073741824 + 1 ))
    local available_gb
available_gb=$(/usr/bin/df -BG "$HOME_DIR" | /usr/bin/awk 'NR==2 {print $4}' | /usr/bin/tr -d 'G') (( required_gb > available_gb )) && { log_error "Espace insuffisant: ${required_gb}GB > ${available_gb}GB"; return 1; } log_info "Espace OK: ${available_gb}GB (necessaire: ${required_gb}GB)"
    return 0
}

run_ddrescue() {
    local pass=$1 device=$2 image=$3 mapfile=$4
    local cmd=("/usr/bin/ddrescue")
    case $pass in
1) cmd+=("-f" "-n"); log_info "Passe 1/3: Lecture rapide des secteurs sains" ;; 2) cmd+=("-f" "-r3"); log_info "Passe 2/3: Relire les secteurs defectueux (3 tentatives)" ;; 3) cmd+=("-f" "-R" "-r3"); log_info "Passe 3/3: Passe inverse pour les secteurs problematiques" ;;
        *) { log_error "Passe invalide: $pass"; return 1; }
    esac
    cmd+=("$device" "$image" "$mapfile")
    log_step "Execution ddrescue passe $pass"
    log_step "Commande: ${cmd[*]}"
    if [[ "$DRY_RUN" = false ]]; then
        "${cmd[@]}"
        local rc=$?
        case $rc in
            0) log_info "Passe $pass: succes"; return 0 ;;
            1) log_warn "Passe $pass: erreurs (normal)"; return 0 ;;
*) log_error "Passe $pass: echouee (code $rc)"; return $rc ;;
        esac
    else
        log_info "[DRY RUN] ${cmd[*]}"
    fi
}

analyze_log() {
    local logfile="$1"
[[ ! -f "$logfile" ]] && { log_error "Log introuvable: $logfile"; return 1; }
    log_step "Analyse des resultats..."
    local total
total=$(/usr/sbin/blockdev --getsize64 "$DEVICE" 2>/dev/null || builtin echo 0)
    local rescued
rescued=$(/usr/bin/grep -Eo '[0-9]+ bytes rescued' "$logfile" 2>/dev/null | /usr/bin/tail -n1 | /usr/bin/grep -Eo '[0-9]+' || builtin echo 0)
    local errsize
errsize=$(/usr/bin/grep -Eo '[0-9]+ bytes errsize' "$logfile" 2>/dev/null | /usr/bin/tail -n1 | /usr/bin/grep -Eo '[0-9]+' || builtin echo 0)
    local err_count
err_count=$(/usr/bin/grep -c "Error" "$logfile" 2>/dev/null || builtin echo 0)
    local pct_rescued=0 pct_failed=0
    (( total > 0 )) && pct_rescued=$(( rescued * 100 / total ))
    (( total > 0 )) && pct_failed=$(( errsize * 100 / total ))
    builtin echo ""
    builtin echo "======================================="
    builtin echo "         RAPPORT DE RECUPERATION"
    builtin echo "======================================="
    builtin echo "Peripherique:     $DEVICE"
    builtin echo "Taille:           $((total / 1073741824)) GB"
builtin echo "Recuperes: $((rescued / 1073741824)) GB (${pct_rescued}%)" builtin echo "Erreurs: $((errsize / 1073741824)) GB (${pct_failed}%)"
    builtin echo "Count erreurs:   $err_count"
    builtin echo "Image:            $TARGET_IMG"
    builtin echo "Log:              $TARGET_LOG"
    builtin echo "======================================="
    builtin echo ""
    if (( pct_rescued >= 90 )); then
        log_info "Succes: ${pct_rescued}%!"
    elif (( pct_rescued >= 50 )); then
        log_warn "Partiel: ${pct_rescued}%."
    else
        log_error "Faible: ${pct_rescued}%."
    fi
}

mount_rescue_image() {
    local img_file="$1" mnt_dir="$MOUNT_POINT/image"
[[ ! -d "$mnt_dir" ]] && /usr/bin/mkdir -p "$mnt_dir" || { log_error "Impossible de creer $mnt_dir"; return 1; } if /usr/bin/mount -o ro,loop "$img_file" "$mnt_dir" 2>/dev/null; then
        log_info "Image montee: $mnt_dir"
        log_info "Contenu:"
/usr/bin/ls -la "$mnt_dir" 2>/dev/null | /usr/bin/head -n 10 || builtin echo "(Aucun fichier)"
        return 0
    else
        log_warn "Montage impossible (FS corrompu?)."
log_info "Essayez: sudo apt install testdisk && sudo photorec $img_file"
        return 1
    fi
}

main() {
    while [[ $# -gt 0 ]]; do
        case "$1" in
            -h|--help)
builtin echo "Usage: sudo $0 [OPTIONS] [image.img] [mapfile.log]" builtin echo "OPTIONS: -d (dry-run), -f (force), -h (help)"
                exit 0 ;;
            -d|--dry-run) DRY_RUN=true; shift ;;
            -f|--force) FORCE=true; shift ;;
            *)
                if [[ -z "$TARGET_IMG" ]]; then
                    TARGET_IMG="$1"
                elif [[ -z "$TARGET_LOG" ]]; then
                    TARGET_LOG="$1"
                else
                    log_error "Trop d'arguments."; exit 1
                fi
                shift ;;
        esac
    done
    [[ -z "$TARGET_IMG" ]] && TARGET_IMG="$DEFAULT_IMG"
    [[ -z "$TARGET_LOG" ]] && TARGET_LOG="$DEFAULT_LOG"
    check_root
    install_dependencies
    check_commands
    setup_mount_point
log_info "Debut recuperation Transcend JetFlash (VID:PID=$USB_VID:$USB_PID)"
    log_info "Image: $TARGET_IMG"
    log_info "Log: $TARGET_LOG"
    [[ "$DRY_RUN" = true ]] && log_warn "MODE SIMULATION"
    log_step "Demontage USB..."
    force_unmount_usb
    log_step "Detachement pilotes..."
    force_unbind_usb_drivers
    log_step "Recherche cle..."
    find_usb_device
    log_step "Attente peripherique..."
    wait_for_device || { bind_usb_storage; exit 1; }
    log_step "Verification espace..."
check_disk_space || { [[ "$FORCE" = false ]] && { bind_usb_storage; exit 1; }; }
    log_step "Lancement ddrescue..."
run_ddrescue 1 "$DEVICE" "$TARGET_IMG" "$TARGET_LOG" || { bind_usb_storage; log_error "Passe 1 echouee."; exit 1; } run_ddrescue 2 "$DEVICE" "$TARGET_IMG" "$TARGET_LOG" || { bind_usb_storage; log_error "Passe 2 echouee."; exit 1; } run_ddrescue 3 "$DEVICE" "$TARGET_IMG" "$TARGET_LOG" || log_warn "Passe 3 echouee (normal si cle endommagee)"
    log_step "Reattachement..."
    bind_usb_storage
    analyze_log "$TARGET_LOG"
[[ "$DRY_RUN" = false ]] && { log_step "Verification image..."; mount_rescue_image "$TARGET_IMG" || true; }
    log_info "Termine. Verifiez $TARGET_IMG et $TARGET_LOG."
}

main "$@"
=======================================================

toute suggestion ou patch sur ce code sont les bienvenue, ainsi que pour récuperer les données (des photos) sur la clé

ainsi que réécrire le firmware qui est certainement le font du problem.
---
tout problème à ses faille et un homme comme vous est à même de les résoudre ;-)
---
Jean-Christophe

Le 2026-07-27 11:13, jean-christophe a écrit :
Récupérer les données n'est pas la priorité,
Récupérer le matériel oui.

On me dit qu'il y a une commande Linux pour flashé la clé

Il me faut juste le firmware, et c'est plus pour le défi et la
stupidité de mise en obsolescence.

Surtout que je sais que cette clé est récupérable.

Juste pour le défi et la connaissance, j'ai beaucoup de support de
stockage a récupérer de la même manière, quitte à ce qu'elle soit
définitivement inutilisable

https://flashboot.ru/iflash/
https://usbdev.ru/firmware/
https://www.eevblog.com/forum/

Sur 27 juill. 2026 à 08 h 50, Basile STARYNKEVITCH
<[email protected]> a écrit :

On Mon, 2026-07-27 at 02:09 +0200, jean-christophe wrote:

Début du message transféré :

De : jean-christophe <[email protected]>
Date : 27 juill. 2026 à 02 h 05
To: SmartList <[email protected]>
Sujet : Flash firmware clé USB sous debian Trixie

Bonjour,
J'ai un clé USB [ID 8564:1000]
Elle a était mise en lecture seule, impossible de lire le contenu
(secteurs défectueux)

Et impossible de :
# dd if=/dev/zero of=/dev/sdX bs=4M status=progress

Les clefs USB sont un matériel qui s'use très vite. A mon avis il y
a peu de choses à faire, sauf à être équipé de matériel
extrêmement onéreux.

Il est possible que certaines entreprrises vendent à prix d'or
(plusieurs milliers d'euros) un tel service de récupération
partielle

Cordia&lement

--

Basile STARYNKEVITCH
<[email protected]>
8 rue de la Faïencerie
http://starynkevitch.net/Basile/
92340 Bourg-la-Reine
https://github.com/bstarynk
France
https://github.com/RefPerSys/RefPerSys
                  https://orcid.org/0000-0003-0908-5250

Répondre à