Allez, encore une méthode pour recoller vos XTM favoris.
L'idée m'est venue à la lecture des efforts de zedtux pour réaliser un programme natif Linux permettant ce recollage.
Voir le fil ici :
http://forum.ubuntu-fr.org/viewtopic.php?id=34185
En ce qui me concerne, j'aime bien les trucs faits à base de scripts, car c'est facile à modifier par soi-même si on veut un peu personnaliser.
Il faut dire aussi que je ne vois pas non plus très clair dans le post de zedtux... 28 pages... et on n'est pas complètement sûr que le post de la page 1 soit bien à jour. En effet, j'ai récupéré un utilitaire qui a fonctionné (en ligne de commande), mais m'a craché une erreur inquiétante !
J'ai donc décidé de me lancer par moi-même et d'écrire un script pour le recollage des fichier XTM.
Voyant la documentation sur le site de référence (
http://xtremsplit.fr/xtremsplit-developpeurs-format-extension-xtm.html), cela paraissait assez abordable car le format est relativement simple.
Bien sûr il s'agit de recoller. Pour découper, je ne prendrais jamais la peine de faire un tel script car j'estime que c'est un format un peu bidon et passablement spécifique. Il est bien mieux d'utiliser des formats tels que RAR + PAR2 qui sont bien plus commun, répandus et efficaces (puisque avec le PAR2, non seulement on détecte les erreurs, mais on les répare).
Donc voici le script.
Vous êtes bienvenus à améliorer (si vous le souhaitez), ou faire toute suggestion utile.
Il présente peu limitations connues. Elles sont indiquées par /TODO en commentaire.
Il présente aussi un
GROS avantage par rapport à la version wine : c'est à peu près
deux fois plus rapide !
Chrono sur un fichier d'environ 8Gio :
- Wine/XtremSplit =
6m08
- tuXtremSplit =
3m07 !
Evolutions possibles : voir post #13
Cette première page contiendra toujours la dernière version du script !
(mes améliorations, ou vos contributions)
History
Version 0.9.0 du 16 juillet 2010
Version 1.0.0 du 19 juillet 2010
Version 1.0.1 du 19 juillet 2010
Version 1.1.0 du 26 juillet 2010
Version 1.2.0 du 26 juillet 2010
Version 1.5.0 du 30 décembre 2010
Version 1.5.1 du 30 décembre 2010
Version 1.5.2 du 10 janvier 2011
Version 1.5.3 du 10 avril 2011
Version 1.5.4 du 25 avril 2011
Version 1.5.5 du 25 avril 2011
Version 1.6.0 du 21 mai 2011
Version 1.6.1 du 25 mai 2011
Version 1.6.2 du 21 juin 2011
Version 1.7.0 du 24 septembre 2011
Version 1.7.1 du 21 janvier 2012 (le présent script)
FONCTIONS UNIQUES !
A partir de la version 1.2.0, le script dispose de 2 fonctions uniques qui n'existent pas sur l'original XtremSplit.
A partir de la version 1.6.0, le script dispose d'une 3ème fonction unique (NAS) qui n'existe pas sur l'original.
-1) Le mode TURBO ... profitez de la toute puissance de Linux !
Ce mode est automatique depuis la 1.5, il ne nécessite plus d'option.
Le principe est que la vérification MD5 et la concaténation se font en une seule étape. La lecture du fichier source ne se fait qu'une fois, et est
"pipé" à la fois sur le fichier de résultat et sur md5sum.
Avantage : on gagne un temps considérable (si tous les MD5 sont corrects). En mode "Turbo", le script est deux fois plus rapide que Wine XtremSplit, et on gagne 50% sur le mode "normal" (vérification puis concaténation)
-2) Le mode Progressif ... commencez à recoller pendant le téléchargement !
Ce mode est également automatique depuis la 1.5 et ne nécessite plus d'option.
C'est particulièrement utile lorsque les fichiers constituant l'ensemble des xtm sont récupérés depuis une source "lente", comme un téléchargement.
L'option permet alors de commencer le recollage sans attendre d'avoir tout récupéré.
Conditions : il faut néanmoins avoir récupéré au moins le premier et le dernier fichier (pour les MD5 ou la vérification de cohérence des tailles).
L'ordre de récupération idéal des fichiers doit donc être : dernier, 1er, 2ème, 3ème, ...., avant-dernier.
L'option va alors concaténer les fichiers qui sont entiers et dont le MD5 est correct.
On peut la relancer autant de fois que nécessaire, à chaque fois les nouveaux fichiers entiers sont ajoutés au résultat.
Avantages : si c'est le film des vacances du cousin, on peut visionner le début sans attendre... un peu comme une "bande annonce"... et éventuellement ne pas poursuivre le téléchargement si ça ne plaît pas (en général, les films perso des vacances du cousin sont pas terribles !).
Cela permet aussi de commencer à regrouper les fichiers pendant le téléchargement, et ainsi une fois que le téléchargement se termine, il ne reste que quelques fichiers à regrouper, et l'opération est plus rapide.
-3) Fonctionne directement sur votre NAS (Synology, QNAP...) ... sans perdre de temps en transferts réseau
Désormais, pour alléger ce post, les instructions détaillées pour les NAS sont sur le deuxième post.
Votre NAS est doté de fonctions lui permettant de télécharger sans qu'un PC ait besoin d'être allumé. C'est très pratique (un peu comme la Freebox V6, mais en mieux !).
Le problème, si les fichiers que vous récupérez sont des xtm, est qu'avec tous les autres programmes classiques, il vous faudra transférer les .xtm vers votre PC, procéder à leur "recollage", et retransférer à nouveau sur le NAS. Selon la vitesse de votre réseau, plusieurs précieuses minutes de perdues !..
Mais pas de problème, comme la méthode que j'ai développée est basée sur du script et n'utilise que des utilitaires GNU communs et présents à peu près partout,
le script fonctionne directement sur votre NAS !
A titre d'estimation, un fichier de 3G rassemblé sur Synology DS1010+
- Script = 1min 30
- XtremSplit = 4min 15
(Soit presque
trois fois plus rapide que la version Windows pour ce cas d'usage !)
Tous les détails pour le fonctionnement sur NAS ainsi que sur les NAS où cela a été testé sont sur le post suivant (#2).
N'hésitez pas à témoigner :
- si ça fonctionne sur votre NAS, indiquez la référence du NAS : marque, modèle (et si possible O.S.)
- si ça ne fonctionne pas et que vous voulez debuger : soit directement dans le code, soit sur ce forum, auquel cas, laissez un message.
AUTRES FONCTIONS
- Préciser un nom de fichier destination ou un répertoire de destination
- Ne vérifier que les MD5 (pas d'écriture de fichier)
- Ignorez les MD5 (à vos risques et périls !)
- etc...
Pour le détail de ces fonctions vous pouvez consulter l'aire en lançant le script avec l'option
-h
Télécharger le script (Faites un clic droit pour sauvegarder)
ou copier/coller le source (GPL V2)
#!/bin/bash
# Copyright (C) 2010,2011,2012 Zakhar for ubuntu-fr
# 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 2 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.
# The text of the GNU General Public License is available at
# http://www.gnu.org/licenses/gpl-2.0.html; if you cannot access it,
# write to the Free Software Foundation, Inc., 51 Franklin Street,
# Fifth Floor, Boston, MA 02110-1301 USA.
#===========================================================
# Fonction :
# ----------
# - Rassemble des fichiers découpés par XtremSplit
# - Vérifie le MD5 s'il est inclus dans les fichiers source
#
# Usage :
# -------
# tuXtremMerge Nom_Du_Fichier_NNN.xtm
# (N'importe lequel des fichiers fonctionne : 001 ou autre)
#
# Tested : Ubuntu Lucid,Karmic, Busybox (Synology DS211j, DS1010+, DS411+, DS209, DS211+)
# ------
#
# Version : 1.7.1
# -------
#
# Date : 2012-01-21
# -----
#
# Author : Zakhar (ubuntu-fr)
# ------
#
# Contributor : // Ajouter votre nom si vous contribuez et redistribuez //
# -----------
# Hypnose @ ubuntu.fr : amélioration des spécifications
# Totor @ ubuntu.fr : amélioration et optimisation du code
# Moonface @ ubuntu.fr : témoignage, test et debug de fonctionnement sur Synology DS211j
# stadros83 @ ubuntu.fr : debug sur Synology DS1010+ (merci pour la patience !)
# A partir de là, certaines spécificités Synology (Busybox) sont
# dans le script "compagnon" busyXtremMerge
# zootroopa @ ubuntu.fr : debug et test sur Synology DS411+
# Gajo22 @ ubuntu.fr : témoignage sur Synology DS209 = OK (après installation coreutils)
# NiKo88 @ ubuntu.fr : témoignage sur Synology DS211+
# Respawner @ ubuntu.fr : aide pour le format des .exe
# Hizoka @ ubuntu.fr : signalement de bug pour noms de fichiers bizarres !
# Josh63 @ ubuntu.fr : témoignage sur Synology DS211
# McMyst @ ubuntu.fr : témoignage sur Dlink DNS 325
#
# History :
# ---------
# 1.7.1
# - Correction du calcul du nom de la destination lorsque le nom du fichier source
# contient des caractères tels que {}
# 1.7.0
# - Prise en compte des fichiers au format .exe
# Le différence réside seulement dans le premier fichier dont il faut retirer
# 305664 octets au début et 24 octets à la fin, pour avoir l'équivalent du xtm.
# 1.6.2
# - Retrait du "process substitution" a profit d'une fonction avec un simple "pipe"
# davantage compatible avec d'autres Linux (comme busybox)
# 1.6.1
# - Simplification de la substitution du md5sum pour busybox (nécessite 1.0.1 busyXtremMerge)
# 1.6.0
# - Modification de l'algorithme pour le premier fichier afin de le rendre compatible Busybox
# (pas de ibs/obs sur le dd). Ainsi modifié, c'est également plus rapide sur Linux standard !
# - Simplification algo sur le dernier fichier (idem ci-dessus).
# - Rajout de l'option pipefail pour ne pas "masquer" les éventuelles erreurs lors des "pipes"
# du processus de recollage.
# 1.5.6
# - Remplacement de od par dd lorsqu'on doit lire des chaines.
# - Remplacement de basemane par interne ${var##*/}
# 1.5.5
# - Retour au code 1.5.3. (plus amélioration: suppression de 'du + cut' remplacé par 'stat -c%s')
# et séparation du code non fini pour Synology 1010+
# 1.5.4
# - Tentative du mise au point pour Synology 1010+ qui utilise une Busybox 1.16.1
# 1.5.2
# - Suppression useless cat ! (Totor @ ubuntu.fr)
# - Remplacement du fichier temporaire par un process substitution (Totor @ ubuntu.fr)
# - Isolation des libellés et codes erreur.
# - Nouveaux paramètre : V (Version), t (temps) [et donc désormais n'affiche plus par défaut les temps]
# 1.5.1
# - Sécurité : création du fichier temporaire avec mktemp
# - Amélioration de libellés
# - Ordonnancement plus logique des tests de cohérence initiaux.
# - Optimisations mineures.
# 1.5.0
# - Suppression et fusion des options -o et -a !..
# Le script utilise désormais toujours l'option -o (ce qui est sa plus-value)
# Si un traitement partiel est détecté, il reprend là où ça en était (deuxième plus-value)
# Ces deux options sont donc désormais inutiles car implicites... et cela simplifie le code !
# - Le script fonctionne désormais "à la mode Firefox", c'est à dire que le fichier résultat
# est d'abord écrit dans resultat.part, et celui-ci est renommé à la fin du traitement.
# La fonction de reprise tient compte de ce nouveau fonctionnement, de même que l'option -f
# - Le premier fichier bénéficie aussi de l'optimisation (parallelisme copie/md5)
# 1.2.0
# - Suppression de l'option -s devenue inutile. Le fichier est maintenant mis par défaut (suggestion Hypnose @ ubuntu-fr)
# dans le même répertoire que les fichiers source (xtm). Le mode par défaut précédent s'obtient en spécifiant "."
# (c'est à dire le répertoire courant) comme destination.
# - Rajout des options d'optimisation -a et -o
# -a permet de lancer le script en cours de téléchargement et d'obtenir un résultat partiel
# -o optimise les MD5/concaténation via un tee (tout est fait en une seule commande, une seule lecture).
# - Diverses corrections de bugs
# 1.1.0
# - Rajout de l'exploration des arguments
# - Rajout des options : voir description dans la fonction usage
# - Un peu de couleurs pour égayer l'affichage !
# 1.0.1
# - Correction du chemin si le script est lancé depuis via PATH (exemple script placé dans /usr/local/bin)
# - Affichage des fichiers tels que passés en paramètres avec leurs éventuels chemins relatifs/absolus
# 1.0.0
# - Supporte d'être lancé avec des noms de fichiers contenant des chemins
# - Deuxième paramètre optionnel pour spécifier le fichier destination
# - Support des noms de fichiers contenant des espaces (source et destination)
# - Vérification au préalable de l'existence du fichier destination pour éviter les écrasement intempestifs
# - Vérification avant de calculer les MD5 qu'on va bien pouvoir écrire sur le fichier destination
#==========================================================
# Messages and Error codes.
#+ This way it is easyier, if somebody would like to localise
readonly MSG_ERROR="\E[1;31mErreur\E[0m\n"
readonly MSG_OK="\E[1;32mOK\E[0m"
readonly MSG_ATTENTION="\E[1;33mAttention !\E[0m"
readonly MSG_BAD_OPTION='Option - incorrecte'
readonly MSG_TOO_MANY_PARAMS='Trop de paramètre :'
readonly MSG_UNKNOWN_OPTION='Option inconnue :'
readonly MSG_UNSPECIFIED_SOURCE_FILE='Fichier source non spécifié'
readonly MSG_VERSION='tuXtremMerge (turbo XTM), version 1.7.1'
readonly MSG_OPTION_M_AND_N="Vous ne pouvez spécifier les options \E[1;32m-m\E[0m et \E[1;32m-n\E[0m simultanément."
readonly MSG_IGNORING_OPTION_F="L'option \E[1;32m-f\E[0m sera ignorée puisque l'option -\E[1;32m-m\E[0m est spécifiée."
readonly MSG_IGNORING_DEST="Le nom du fichier résultat sera ignoré puisque l'option \E[1;32m-m\E[0m est spécifiée."
readonly MSG_CHECKING='Vérifications ... '
readonly MSG_CHECKING_FIRST_SOURCE_FILE="Vérification d'existence du premier fichier source..."
readonly MSG_TIP="\E[1;34mAstuce :\E[0;34m il faut le premier et le dernier fichier, corrects et complets, pour que le script puisse fonctionner.\nVous pouvez optimiser le résultat en récupérant ces deux fichiers en priorité.\E[0m"
readonly MSG_SUCCESS="==================================================\n\E[1;32mToutes les opérations sont terminées avec succès !\E[0m"
readonly MSG_FIRST_FILE_ERROR=' non trouvé, vide ou erreur'
readonly MSG_FIRST_FILE_FOUND='Premier fichier source trouvé :'
readonly MSG_OPTION_M_AND_NO_MD5="\E[1;33mRien à faire !\E[0m\nL'option \E[1;32m-m\E[0m est spécifiée, or il n'y a pas MD5 à vérifier dans ces fichiers xtm."
readonly MSG_CHECKING_LAST_SOURCE_FILE="Vérification d'existence du dernier fichier source..."
readonly MSG_LAST_FILE_ERROR="Fichier %s%3.3u.xtm non trouvé ou vide\n"
readonly MSG_LAST_FILE_FOUND="Dernier fichier source trouvé: %s%3.3u.xtm\n"
readonly MSG_FILE_SIZES_OK='Tailles premier et dernier fichier cohérentes.'
readonly MSG_FILE_SIZES_ERROR='Premier ou dernier fichier de taille incohérente.'
readonly MSG_NO_FILE_WRITTEN="Aucun fichier résultat ne sera écrit car l'option \E[1;32m-m\E[0m est spécifiée."
readonly MSG_COMPUTING_DEST="Détermination de l'emplacement du résultat..."
readonly MSG_DISPLAY_DEST='Emplacement du résultat :'
readonly MSG_CHECK_DEST_WRITABLE="Vérification de la possibilité d'écrire le résultat : existence, autorisation d'écriture, espace disponible, etc..."
readonly MSG_WARN_FORCED_OVERWRITE="\nEcrasement forcé par l'option \E[1;32m-f\E[0m, le fichier résultat existe déjà."
readonly MSG_WARN_OVERWRITE="\nLe fichier : %s existe déjà.\n"
readonly MSG_FILE_SIZE_MATCHES='La taille du fichier correspond au résultat prévu dans le xtm.'
readonly MSG_FILE_SIZE_DOES_NOT_MATCH='La taille du fichier ne correspond pas au résultat prévu dans le xtm.'
readonly MSG_OVERWRITE_HINT="Si vous désirez ré-écrire ce fichier effacez/renommez-le au préalable ou spécifiez l'option \E[1;32m-f\E[0m pour forcer l'écrasement"
readonly MSG_WRITE_ERROR="Ecriture de : %s impossible.\nVeuillez vérifier que vous avez l'autorisation d'écrire ce fichier et que son nom est correct.\n"
readonly MSG_INSUFFICIENT_SPACE="Espace insuffisant sur %s pour créer le fichier %s.\nEspace nécessaire : %'u\nEspace disponible : %'u\n"
readonly MSG_CHUNKS_AVAIL='fichiers déjà traités.'
readonly MSG_INFO_DELETED_OLD_FILE="Fichier partiel incohérent supprimé par option \E[1;32m-f\E[0m"
readonly MSG_INCOHERENT_PARTIAL_FILE="La taille du fichier partiel n'est pas un multiple de la taille de découpage des fichiers xtm.\nSupprimez ce fichier (%s.part) ou utilisez l'option \E[1;32m-f\E[0m\n"
readonly MSG_ALL_CHECKED_OK='Vérifications pour le fichier résultat terminées.'
readonly MSG_PROCESSING_START="\E[1mTraitement optimisé des %u fichiers\E[0m\n"
readonly MSG_PROCESSING_RESTART="\E[1mReprise du traitement à partir du fichier %u\E[0m\nReste à traiter %u fichier(s)\n"
readonly MSG_SEPARATOR='=================================='
readonly MSG_PROCESSING_FILE='Traitement de %s%3.3u.%s ... '
readonly MSG_FILE_MISSING='*** Le fichier est manquant ou de taille incorrecte.'
readonly MSG_FILE_MISSING_TIP='*** Relancez le programme lorsque le fichier sera complet.'
readonly E_BAD_OPTION=65
readonly E_UNKNOWN_OPTION=66
readonly E_TOO_MANY_PARAMS=67
readonly E_UNSPECIFIED_SOURCE_FILE=68
readonly E_MSG_OPTION_M_AND_N=69
readonly E_FIRST_FILE_ERROR=80
readonly E_LAST_FILE_ERROR=81
readonly E_FILE_SIZES_ERROR=82
readonly E_WRITE_ERROR=83
readonly E_INSUFFICIENT_SPACE=83
readonly E_INCOHERENT_PARTIAL_FILE=84
readonly E_WARN_OVERWRITE=96
readonly E_CRITICAL_ERROR=127
#==========================================================
# Utility functions
# usage : affiche l'usage/aide du script
# v_echo : affichage pour l'option verbeux
usage()
{
if [ -n "$1" ]; then echo "$1"; fi
cat <<EOF
Usage : tuXtremMerge [Options] Source [Destination]
Source : le fichier source, généralement de la forme [chemin/]fichier.001.xtm
On peut cependant indiquer n'importe lequel des xtm de la série, par
exemple fichier.007.xtm
Destination : nom du fichier destination souhaité.
Si la destination est un répertoire existant, le fichier résultat sera
stocké dans ce répertoire, avec le nom indiqué au découpage en xtm.
Par défaut, le fichier résultat est stocké dans le répertoire du
fichier source et porte le nom indiqué lors du découpage en xtm.
Options :
-h Affiche le présent message d'aide.
-n Ne vérifie pas les md5 (concaténation sans vérifier).
-m Vérifie seulement les md5 (pas de concaténation)
-f Force l'écriture du fichier résultat.
Si un fichier existe déjà il est écrasé.
-v Verbeux. Permet aussi de diagnostiquer les incohérences entre options.
-t Temps. Affiche les heures de début et fin de traitement.
Doublé (tt) affiche davantage de temps intermédiaires.
-V Affiche la version du script.
ASTUCE :
Dans tous les cas, le premier et le dernier fichier sont nécessaires pour
que le script puisse au moins commencer à assembler. S'il s'agit de fichiers
téléchargés, veillez donc à récupérer ces deux fichiers en priorité.
EOF
}
v_echo()
{
if [ $OPTION_v ]; then echo -e "*** $1"; fi
}
#______________________________
# Function that scan parameters
# It works with style: -a -v
# but also BSD style : -av
scan_parameters()
{
for param in "$@"
do
case "$param" in
-* )
if [ "$param" == "-" ]; then
usage "$MSG_BAD_OPTION"
exit $E_BAD_OPTION
fi
i=1
while [ $i -lt ${#param} ]
do
case ${param:$i:1} in
h )
usage
exit 0
;;
m )
OPTION_m='1'
;;
n )
OPTION_n='1'
;;
f )
OPTION_f='1'
;;
t )
if [ ${param:$i:2} = 'tt' ]; then
OPTION_t='2'
i=$(( $i + 1 ))
else
OPTION_t='1'
fi
;;
v )
OPTION_v='1'
;;
V )
if [ -n "$MSG_BUSY_VERSION" ]; then
echo "$MSG_BUSY_VERSION"
fi
echo "$MSG_VERSION"
exit 0
;;
* )
usage "$MSG_UNKNOWN_OPTION -${param:$i:1}"
exit $E_UNKNOWN_OPTION
;;
esac
i=$(( $i + 1 ))
done
;;
*)
if [ -z "$DISPLAY_SOURCE_FILE_NAME" ]; then
DISPLAY_SOURCE_FILE_NAME="$param"
elif [ -z "$DISPLAY_DEST_FILE_NAME" ]; then
DISPLAY_DEST_FILE_NAME="$param"
else
usage "$MSG_TOO_MANY_PARAMS $param"
exit $E_TOO_MANY_PARAMS
fi
;;
esac
done
if [ -z "$DISPLAY_SOURCE_FILE_NAME" ]; then
usage "$MSG_UNSPECIFIED_SOURCE_FILE"
exit $E_UNSPECIFIED_SOURCE_FILE
else
SOURCE_FILE_NAME=$( readlink -f "$DISPLAY_SOURCE_FILE_NAME" )
fi
}
#_________________________________
# Functions that check parameters
# and give some warnings or errors
# if things are not correct
check_parameters()
{
if [ $OPTION_m ]; then
if [ $OPTION_n ]; then
echo -e "$MSG_ERROR$MSG_OPTION_M_AND_N"
exit $E_MSG_OPTION_M_AND_N
fi
if [ $OPTION_f ]; then
v_echo "$MSG_IGNORING_OPTION_F"
fi
if [ -n "$DISPLAY_DEST_FILE_NAME" ]; then
v_echo "$MSG_IGNORING_DEST"
fi
fi
}
success()
{
if [ ! $OPTION_m ]; then
# If we mv directly it appears that system syncs, and so the script appears to run longer
#+ When we rm the file first, the async write continues after the script ends.
rm "$DEST_FILE_NAME"
mv "$DEST_FILE_NAME_PART" "$DEST_FILE_NAME"
fi
echo -e "$MSG_SUCCESS"
timing 1
exit 0
}
tip()
{
echo -e "$MSG_TIP"
exit $1
}
nop()
{
cat - >/dev/null
}
md5check()
{
md5sum | cut -b 1-32 | grep -iq "$( echo ${1} )"
}
timing()
{
if [ $OPTION_t -ge $1 ]; then date +%T.%N; fi
}
#==========================================================
# START OF THE MAIN PROGRAM HERE !
# /TODO
# -> Traiter les interruptions (Ctrl-C) et erreurs par un truncate (au lieu de supprimer)
#_________________________________________
# Variables declaration and initialisation
declare -i i size SOURCE_FILE_NB DEST_FILE_NAME_LENGTH SPACE_AVAIL DISK_SPACE_NEEDED DEST_FILE_SIZE CHUNK_SIZE CHUNKS_AVAIL fMD5 LAST_SOURCE_FILE_SIZE
OPTION_m=''
OPTION_n=''
OPTION_f=''
OPTION_v=''
declare -i OPTION_t=0
DISPLAY_SOURCE_FILE_NAME=''
DISPLAY_DEST_FILE_NAME=''
declare -i CHUNKS_AVAIL=0
set -o pipefail
scan_parameters "$@"
timing 1
if [ ! $OPTION_v ]; then
echo -n "$MSG_CHECKING"
fi
check_parameters
#==========================================================
# Checking file existence
# - On commence par vérifier le 001 qui contient le header
v_echo "$MSG_CHECKING_FIRST_SOURCE_FILE"
declare -i fEXE EXE_OFFSET
if echo "$SOURCE_FILE_NAME" | grep -q '.exe$'; then
fEXE=1
EXE_OFFSET=305664
FIRST_SUFFIX='exe'
else
fEXE=0
EXE_OFFSET=0
FIRST_SUFFIX='xtm'
fi
RADIX=$( echo "$SOURCE_FILE_NAME" | sed "s/...\.${FIRST_SUFFIX}\$//" )
DISPLAY_RADIX=$( echo "$DISPLAY_SOURCE_FILE_NAME" | sed "s/...\.${FIRST_SUFFIX}\$//" )
FIRST_SOURCE_FILE_NAME="${RADIX}001.${FIRST_SUFFIX}"
if [ ! -f "$FIRST_SOURCE_FILE_NAME" ] || [ ! -s "$FIRST_SOURCE_FILE_NAME" ]; then
echo -e "${MSG_ERROR}${DISPLAY_RADIX}001.${FIRST_SUFFIX}${MSG_FIRST_FILE_ERROR}"
tip $E_FIRST_FILE_ERROR
else
v_echo "$MSG_FIRST_FILE_FOUND ${DISPLAY_RADIX}001.${FIRST_SUFFIX}"
fi
fMD5=$( od -An -vtu1 -j$(( ${EXE_OFFSET} + 91 )) -N1 "$FIRST_SOURCE_FILE_NAME" )
#==========================================================
# Checking if MD5 is included in that xtm
# If not and only a MD5 check is asked (option -m) exit with message
if [ $fMD5 -eq 0 ] && [ $OPTION_m ]; then
echo -e "$MSG_OPTION_M_AND_NO_MD5"
exit 0
fi
CHUNK_SIZE=$(( $( stat -c%s "$FIRST_SOURCE_FILE_NAME" ) - 104 - ${fEXE} * 305688 ))
SOURCE_FILE_NB=$( od -An -vtu4 -j$(( ${EXE_OFFSET} + 92 )) -N4 "$FIRST_SOURCE_FILE_NAME" )
DEST_FILE_SIZE=$( od -An -vtu8 -j$(( ${EXE_OFFSET} + 96 )) -N8 "$FIRST_SOURCE_FILE_NAME" )
#---------------------------------
# - On vérifie le dernier fichier
# => Dans le cas de MD5, celui-ci contient les MD5
# => Dans le cas non-MD5, cela sert à vérifier au moins la cohérence de taille des fichiers
v_echo "$MSG_CHECKING_LAST_SOURCE_FILE"
LAST_SOURCE_FILE_NAME=$( printf "${RADIX}%3.3u.xtm" $SOURCE_FILE_NB )
if [ ! -f "$LAST_SOURCE_FILE_NAME" ] || [ ! -s "$LAST_SOURCE_FILE_NAME" ]; then
printf "$MSG_ERROR$MSG_LAST_FILE_ERROR" "$DISPLAY_RADIX" $SOURCE_FILE_NB
tip $E_LAST_FILE_ERROR
else
v_echo "$( printf "$MSG_LAST_FILE_FOUND" "$DISPLAY_RADIX" $SOURCE_FILE_NB )"
fi
LAST_SOURCE_FILE_SIZE=$(( $( stat -c%s "$LAST_SOURCE_FILE_NAME" ) - $fMD5 * $SOURCE_FILE_NB * 32 ))
if [ $(( $CHUNK_SIZE * ($SOURCE_FILE_NB - 1) + $LAST_SOURCE_FILE_SIZE )) -eq $DEST_FILE_SIZE ]; then
v_echo "$MSG_FILE_SIZES_OK"
else
echo -e "$MSG_ERROR$MSG_FILE_SIZES_ERROR"
tip $E_FILE_SIZES_ERROR
fi
#==========================================================
# From here we have first and last file, we can do something!
# Checking output file
# - Vérifie qu'on ne va pas écraser un fichier (si option -f, juste message verbeux)
# - Vérifie qu'on peut bien écrire le fichier (autorisation, nom/chemin correct)
# - Vérifie qu'on a la place d'écrire le fichier
#
# Mais on commence par déterminer le nom du fichier résultat
# Ca dépend de plusieurs choses :
# - si un fichier destination a été spécifié en paramètre
# + et si c'est le cas, si c'est un répertoire existant ou pas
if [ $OPTION_m ]; then
v_echo "$MSG_NO_FILE_WRITTEN"
else
v_echo "$MSG_COMPUTING_DEST"
if [ -z "$DISPLAY_DEST_FILE_NAME" ] || [ -d "$DISPLAY_DEST_FILE_NAME" ]; then
DEST_FILE_NAME_LENGTH=$( od -An -vtu1 -j$(( ${EXE_OFFSET} + 40 )) -N1 "$FIRST_SOURCE_FILE_NAME" )
DEFAULT_DEST_FILE_NAME=$( dd if="$FIRST_SOURCE_FILE_NAME" bs=1 skip=$(( ${EXE_OFFSET} + 41 )) count=$DEST_FILE_NAME_LENGTH 2>/dev/null)
if [ -z "$DISPLAY_DEST_FILE_NAME" ]; then
this_file_radix=${DISPLAY_SOURCE_FILE_NAME%"${DISPLAY_SOURCE_FILE_NAME##*/}"}
else # Ici DISPLAY_DEST_FILE_NAME est forcément un répertoire
# on rajoute le / final si nécessaire
if [ ${DISPLAY_DEST_FILE_NAME:(-1)} == '/' ]; then
this_file_radix="$DISPLAY_DEST_FILE_NAME"
else
this_file_radix="$DISPLAY_DEST_FILE_NAME/"
fi
fi
DISPLAY_DEST_FILE_NAME="$this_file_radix$DEFAULT_DEST_FILE_NAME"
fi
v_echo "$MSG_DISPLAY_DEST $DISPLAY_DEST_FILE_NAME"
DEST_FILE_NAME=$( readlink -fn "$DISPLAY_DEST_FILE_NAME" )
DEST_FILE_NAME_PART="${DEST_FILE_NAME}.part"
#---------------------------------
# Vérifications de la possibilité d'écrire le fichier résultat
v_echo "$MSG_CHECK_DEST_WRITABLE"
if [ -f "$DEST_FILE_NAME" ] && [ -s "$DEST_FILE_NAME" ]; then
if [ $OPTION_f ]; then
v_echo "$MSG_ATTENTION$MSG_WARN_FORCED_OVERWRITE"
else
size=$( stat -c%s "$DEST_FILE_NAME" )
if [ $size -eq $DEST_FILE_SIZE ]; then
printf "$MSG_ATTENTION$MSG_WARN_OVERWRITE" $DISPLAY_DEST_FILE_NAME
echo "$MSG_FILE_SIZE_MATCHES"
else
printf "$MSG_ERROR$MSG_WARN_OVERWRITE" $DISPLAY_DEST_FILE_NAME
echo "$MSG_FILE_SIZE_DOES_NOT_MATCH"
fi
echo -e "$MSG_OVERWRITE_HINT"
exit $E_WARN_OVERWRITE
fi
fi
touch "$DEST_FILE_NAME" "$DEST_FILE_NAME_PART" 2>/dev/null
if [ $? -ne 0 ]; then
printf "$MSG_ERROR$MSG_WRITE_ERROR" $DISPLAY_DEST_FILE_NAME
exit $E_WRITE_ERROR
fi
TMP=$( df "$DEST_FILE_NAME" | sed -n '2p' )
SPACE_AVAIL=$(( $( echo $TMP | cut -d' ' -f 4 ) * 1024 - 1024))
size=$( stat -c%s "$DEST_FILE_NAME_PART" )
DISK_SPACE_NEEDED=$(( $DEST_FILE_SIZE - $size ))
if [ $DISK_SPACE_NEEDED == 0 ]; then
success
fi
if [ $SPACE_AVAIL -lt $DISK_SPACE_NEEDED ]; then
printf "$MSG_ERROR$MSG_INSUFFICIENT_SPACE" $( echo $TMP | cut -d' ' -f 6 ) "$DISPLAY_DEST_FILE_NAME" $DISK_SPACE_NEEDED $SPACE_AVAIL
exit $E_INSUFFICIENT_SPACE
fi
CHUNKS_AVAIL=$(( $size / $CHUNK_SIZE ))
if [ $(( $size % $CHUNK_SIZE )) -eq 0 ]; then
v_echo "$CHUNKS_AVAIL $MSG_CHUNKS_AVAIL"
else
if [ $OPTION_f ]; then
v_echo "$MSG_INFO_DELETED_OLD_FILE"
rm "$DEST_FILE_NAME_PART" 2>/dev/null
CHUNKS_AVAIL=0
else
printf "$MSG_ERROR$MSG_INCOHERENT_PARTIAL_FILE" $DISPLAY_DEST_FILE_NAME
exit $E_INCOHERENT_PARTIAL_FILE
fi
fi
v_echo "$MSG_ALL_CHECKED_OK"
fi
#==========================================================
# The Real work starts here!
# - Toutes les vérifications et préparations étant finies on commence
# la concaténation/checksum à proprement parler
if [ $OPTION_m ]; then
DEST_FILE_NAME_PART="/dev/null"
fi
if [ $fMD5 -eq 0 ] || [ $OPTION_n ]; then
MD5_PROG="nop"
else
MD5_PROG="md5check"
fi
if [ ! $OPTION_v ]; then
echo -e "$MSG_OK"
fi
timing 1
if [ $CHUNKS_AVAIL -eq 0 ]; then
printf "$MSG_PROCESSING_START" $SOURCE_FILE_NB
else
printf "$MSG_PROCESSING_RESTART" $(( $CHUNKS_AVAIL + 1 )) $(( $SOURCE_FILE_NB - $CHUNKS_AVAIL ))
fi
echo "$MSG_SEPARATOR"
i=$CHUNKS_AVAIL
while (( $i < $SOURCE_FILE_NB )) ; do
if [ $fMD5 -eq 1 ]; then
this_file_MD5=$( dd if="$LAST_SOURCE_FILE_NAME" bs=1 skip=$(( $LAST_SOURCE_FILE_SIZE + $i * 32)) count=32 2>/dev/null )
fi
i=$(( $i + 1 ))
this_file_radix=$( printf "%s%3.3u" "$RADIX" $i )
if [ ${i} -eq 1 ]; then
printf "$MSG_PROCESSING_FILE" "$DISPLAY_RADIX" $i ${FIRST_SUFFIX}
else
printf "$MSG_PROCESSING_FILE" "$DISPLAY_RADIX" $i 'xtm'
fi
case $i in
1 )
if [ ${fEXE} -eq 0 ]; then
# Pour le premier fichier on ne 'tee' pas les 104 premiers octets, mais ils rentrent dans le md5
{ dd if="$this_file_radix.xtm" bs=104 count=1 2>/dev/null &&
# On fait un deuxième dd pour "aligner" à un bloc de 4096, et ensuite par 4096
# C'est 7% plus rapide que de ne faire que des dd par 104.
# Si le fichier est plus petit que 4096 (peu probable) ça fonctionne tout de même
# car dans ce cas le deuxième s'arrête à la fin du fichier et le dernier dd
# ne retourne rien.
{ dd if="$this_file_radix.xtm" bs=8 skip=13 count=499 2>/dev/null
dd if="$this_file_radix.xtm" bs=4096 skip=1 2>/dev/null
} | tee "$DEST_FILE_NAME_PART";
} | $MD5_PROG "${this_file_MD5}"
else
FIRST_FILE_BLOCKS=$(( ( ${CHUNK_SIZE} - 1432 ) / 4096 ))
FIRST_FILE_PAD=$(( ${CHUNK_SIZE} - 1432 - ${FIRST_FILE_BLOCKS} * 4096 ))
{ dd if="$this_file_radix.exe" bs=8 skip=38208 count=13 2>/dev/null &&
# Idem que ci-dessus pour les optimisations avec des PGCD recalculés
# C'est juste un peu plus compliqué car on doit aussi sauter 24
# octets à la fin, donc il faut savoir combien de blocs de 4096 on a.
{ dd if="$this_file_radix.exe" bs=8 skip=38221 count=179 2>/dev/null
dd if="$this_file_radix.exe" bs=4096 skip=75 count=${FIRST_FILE_BLOCKS} 2>/dev/null
dd if="$this_file_radix.exe" bs=1 skip=$(( (${FIRST_FILE_BLOCKS} + 75) * 4096 )) count=${FIRST_FILE_PAD} 2>/dev/null
} | tee "$DEST_FILE_NAME_PART";
} | $MD5_PROG "${this_file_MD5}"
fi
;;
$SOURCE_FILE_NB )
# Pour le dernier fichier on enlève les octets de MD5 (ou pas... s'il n'y en a pas !)
dd if="$this_file_radix.xtm" bs=$LAST_SOURCE_FILE_SIZE count=1 2>/dev/null | \
tee -a "$DEST_FILE_NAME_PART" | \
$MD5_PROG "${this_file_MD5}"
;;
*)
# On vérifie la cohérence de taille du fichier seulement si ce n'est ni le premier
# ni le dernier, car pour c'est deux fichiers, c'est déjà vérifié avant !
size=$( stat -c%s "$this_file_radix.xtm" 2>/dev/null )
if [ $? -ne 0 ] || [ $size -ne $CHUNK_SIZE ]; then
echo -e "$MSG_ATTENTION"
echo "$MSG_FILE_MISSING"
if [ $OPTION_m ]; then
continue
else
echo "$MSG_FILE_MISSING_TIP"
exit $E_WARN_FILE_MISSING
fi
fi
tee -a "$DEST_FILE_NAME_PART" <"$this_file_radix.xtm" | $MD5_PROG "${this_file_MD5}"
esac
if [ $? -eq 0 ]; then # No error: all is OK
echo -e "$MSG_OK"
else # Error: it means we get an incorrect MD5, a write error, or other bad things, so here we cancel and abort
echo -e "$MSG_ERROR"
if [ ! $OPTION_m ]; then # But we stop only if no option -m.
# If option -m we continue so that we check ALL the files and not stop on the first error
rm "$DEST_FILE_NAME_PART" "$DEST_FILE_NAME" 2>/dev/null
exit $E_CRITICAL_ERROR
fi
fi
timing 2
done
#==========================================================
# Success!
success
Mode d'emploi :
Installation :
- coller ce source dans un fichier de votre choix (par exemple : /usr/local/bin/tuXtremMerge).
- rendez le exécutable
Usage :
- lancez dans un terminal
Désinstallation :
- supprimez le script