mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-27 11:07:44 +00:00
Merge pull request #8191 from sylvestre/l10n-dd
l10n: port dd for translation + add french
This commit is contained in:
commit
ba447eb869
6 changed files with 435 additions and 95 deletions
|
@ -113,3 +113,48 @@ dd-after-help = ### Operands
|
||||||
- nocache : request that OS drop cache.
|
- nocache : request that OS drop cache.
|
||||||
- noctty : do not assign a controlling tty.
|
- noctty : do not assign a controlling tty.
|
||||||
- nofollow : do not follow system links.
|
- nofollow : do not follow system links.
|
||||||
|
|
||||||
|
# Error messages
|
||||||
|
dd-error-failed-to-open = failed to open { $path }
|
||||||
|
dd-error-write-error = write error
|
||||||
|
dd-error-failed-to-seek = failed to seek in output file
|
||||||
|
dd-error-io-error = IO error
|
||||||
|
dd-error-cannot-skip-offset = '{ $file }': cannot skip to specified offset
|
||||||
|
dd-error-cannot-skip-invalid = '{ $file }': cannot skip: Invalid argument
|
||||||
|
dd-error-cannot-seek-invalid = '{ $output }': cannot seek: Invalid argument
|
||||||
|
dd-error-not-directory = setting flags for '{ $file }': Not a directory
|
||||||
|
dd-error-failed-discard-cache-input = failed to discard cache for: 'standard input'
|
||||||
|
dd-error-failed-discard-cache-output = failed to discard cache for: 'standard output'
|
||||||
|
|
||||||
|
# Parse errors
|
||||||
|
dd-error-unrecognized-operand = Unrecognized operand '{ $operand }'
|
||||||
|
dd-error-multiple-format-table = Only one of conv=ascii conv=ebcdic or conv=ibm may be specified
|
||||||
|
dd-error-multiple-case = Only one of conv=lcase or conv=ucase may be specified
|
||||||
|
dd-error-multiple-block = Only one of conv=block or conv=unblock may be specified
|
||||||
|
dd-error-multiple-excl = Only one ov conv=excl or conv=nocreat may be specified
|
||||||
|
dd-error-invalid-flag = invalid input flag: ‘{ $flag }’
|
||||||
|
Try '{ $cmd } --help' for more information.
|
||||||
|
dd-error-conv-flag-no-match = Unrecognized conv=CONV -> { $flag }
|
||||||
|
dd-error-multiplier-parse-failure = invalid number: '{ $input }'
|
||||||
|
dd-error-multiplier-overflow = Multiplier string would overflow on current system -> { $input }
|
||||||
|
dd-error-block-without-cbs = conv=block or conv=unblock specified without cbs=N
|
||||||
|
dd-error-status-not-recognized = status=LEVEL not recognized -> { $level }
|
||||||
|
dd-error-unimplemented = feature not implemented on this system -> { $feature }
|
||||||
|
dd-error-bs-out-of-range = { $param }=N cannot fit into memory
|
||||||
|
dd-error-invalid-number = invalid number: ‘{ $input }’
|
||||||
|
|
||||||
|
# Progress messages
|
||||||
|
dd-progress-records-in = { $complete }+{ $partial } records in
|
||||||
|
dd-progress-records-out = { $complete }+{ $partial } records out
|
||||||
|
dd-progress-truncated-record = { $count ->
|
||||||
|
[one] { $count } truncated record
|
||||||
|
*[other] { $count } truncated records
|
||||||
|
}
|
||||||
|
dd-progress-byte-copied = { $bytes } byte copied, { $duration } s, { $rate }/s
|
||||||
|
dd-progress-bytes-copied = { $bytes } bytes copied, { $duration } s, { $rate }/s
|
||||||
|
dd-progress-bytes-copied-si = { $bytes } bytes ({ $si }) copied, { $duration } s, { $rate }/s
|
||||||
|
dd-progress-bytes-copied-si-iec = { $bytes } bytes ({ $si }, { $iec }) copied, { $duration } s, { $rate }/s
|
||||||
|
|
||||||
|
# Warnings
|
||||||
|
dd-warning-zero-multiplier = { $zero } is a zero multiplier; use { $alternative } if that is intended
|
||||||
|
dd-warning-signal-handler = Internal dd Warning: Unable to register signal handler
|
||||||
|
|
160
src/uu/dd/locales/fr-FR.ftl
Normal file
160
src/uu/dd/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
dd-about = Copier, et optionnellement convertir, une ressource du système de fichiers
|
||||||
|
dd-usage = dd [OPÉRANDE]...
|
||||||
|
dd OPTION
|
||||||
|
dd-after-help = ### Opérandes
|
||||||
|
|
||||||
|
- bs=OCTETS : lire et écrire jusqu'à OCTETS octets à la fois (par défaut : 512) ;
|
||||||
|
remplace ibs et obs.
|
||||||
|
- cbs=OCTETS : la 'taille de bloc de conversion' en octets. S'applique aux
|
||||||
|
opérations conv=block et conv=unblock.
|
||||||
|
- conv=CONVS : une liste séparée par des virgules d'options de conversion ou (pour des
|
||||||
|
raisons historiques) d'indicateurs de fichier.
|
||||||
|
- count=N : arrêter la lecture de l'entrée après N opérations de lecture de taille ibs
|
||||||
|
plutôt que de continuer jusqu'à EOF. Voir iflag=count_bytes si l'arrêt après N octets
|
||||||
|
est préféré
|
||||||
|
- ibs=N : la taille du tampon utilisé pour les lectures (par défaut : 512)
|
||||||
|
- if=FICHIER : le fichier utilisé pour l'entrée. Quand non spécifié, stdin est utilisé à la place
|
||||||
|
- iflag=INDICATEURS : une liste séparée par des virgules d'indicateurs d'entrée qui spécifient comment
|
||||||
|
la source d'entrée est traitée. INDICATEURS peut être n'importe lequel des indicateurs d'entrée ou
|
||||||
|
indicateurs généraux spécifiés ci-dessous.
|
||||||
|
- skip=N (ou iseek=N) : ignorer N enregistrements de taille ibs dans l'entrée avant de commencer
|
||||||
|
les opérations de copie/conversion. Voir iflag=seek_bytes si la recherche de N octets est préférée.
|
||||||
|
- obs=N : la taille du tampon utilisé pour les écritures (par défaut : 512)
|
||||||
|
- of=FICHIER : le fichier utilisé pour la sortie. Quand non spécifié, stdout est utilisé
|
||||||
|
à la place
|
||||||
|
- oflag=INDICATEURS : liste séparée par des virgules d'indicateurs de sortie qui spécifient comment la
|
||||||
|
source de sortie est traitée. INDICATEURS peut être n'importe lequel des indicateurs de sortie ou
|
||||||
|
indicateurs généraux spécifiés ci-dessous
|
||||||
|
- seek=N (ou oseek=N) : recherche N enregistrements de taille obs dans la sortie avant de
|
||||||
|
commencer les opérations de copie/conversion. Voir oflag=seek_bytes si la recherche de N octets est
|
||||||
|
préférée
|
||||||
|
- status=NIVEAU : contrôle si les statistiques de volume et de performance sont écrites sur
|
||||||
|
stderr.
|
||||||
|
|
||||||
|
Quand non spécifié, dd affichera les statistiques à la fin. Un exemple est ci-dessous.
|
||||||
|
|
||||||
|
```plain
|
||||||
|
6+0 enregistrements en entrée
|
||||||
|
16+0 enregistrements en sortie
|
||||||
|
8192 octets (8.2 kB, 8.0 KiB) copiés, 0.00057009 s,
|
||||||
|
14.4 MB/s
|
||||||
|
|
||||||
|
Les deux premières lignes sont les statistiques de 'volume' et la dernière ligne est les
|
||||||
|
statistiques de 'performance'.
|
||||||
|
Les statistiques de volume indiquent le nombre de lectures complètes et partielles de taille ibs,
|
||||||
|
ou d'écritures de taille obs qui ont eu lieu pendant la copie. Le format des statistiques de
|
||||||
|
volume est <complètes>+<partielles>. Si des enregistrements ont été tronqués (voir
|
||||||
|
conv=block), les statistiques de volume contiendront le nombre d'enregistrements tronqués.
|
||||||
|
|
||||||
|
Les valeurs possibles de NIVEAU sont :
|
||||||
|
- progress : Afficher les statistiques de performance périodiques pendant la copie.
|
||||||
|
- noxfer : Afficher les statistiques de volume finales, mais pas les statistiques de performance.
|
||||||
|
- none : N'afficher aucune statistique.
|
||||||
|
|
||||||
|
L'affichage des statistiques de performance est aussi déclenché par le signal INFO (quand supporté),
|
||||||
|
ou le signal USR1. Définir la variable d'environnement POSIXLY_CORRECT à n'importe quelle valeur
|
||||||
|
(y compris une valeur vide) fera ignorer le signal USR1.
|
||||||
|
|
||||||
|
### Options de conversion
|
||||||
|
|
||||||
|
- ascii : convertir d'EBCDIC vers ASCII. C'est l'inverse de l'option ebcdic.
|
||||||
|
Implique conv=unblock.
|
||||||
|
- ebcdic : convertir d'ASCII vers EBCDIC. C'est l'inverse de l'option ascii.
|
||||||
|
Implique conv=block.
|
||||||
|
- ibm : convertir d'ASCII vers EBCDIC, en appliquant les conventions pour [, ]
|
||||||
|
et ~ spécifiées dans POSIX. Implique conv=block.
|
||||||
|
|
||||||
|
- ucase : convertir de minuscules vers majuscules.
|
||||||
|
- lcase : convertir de majuscules vers minuscules.
|
||||||
|
|
||||||
|
- block : pour chaque nouvelle ligne inférieure à la taille indiquée par cbs=OCTETS, supprimer
|
||||||
|
la nouvelle ligne et remplir avec des espaces jusqu'à cbs. Les lignes plus longues que cbs sont tronquées.
|
||||||
|
- unblock : pour chaque bloc d'entrée de la taille indiquée par cbs=OCTETS, supprimer
|
||||||
|
les espaces de fin à droite et remplacer par un caractère de nouvelle ligne.
|
||||||
|
|
||||||
|
- sparse : tente de rechercher la sortie quand un bloc de taille obs ne contient que
|
||||||
|
des zéros.
|
||||||
|
- swab : échange chaque paire d'octets adjacents. Si un nombre impair d'octets est
|
||||||
|
présent, l'octet final est omis.
|
||||||
|
- sync : remplit chaque bloc de taille ibs avec des zéros. Si block ou unblock est
|
||||||
|
spécifié, remplit avec des espaces à la place.
|
||||||
|
- excl : le fichier de sortie doit être créé. Échoue si le fichier de sortie est déjà
|
||||||
|
présent.
|
||||||
|
- nocreat : le fichier de sortie ne sera pas créé. Échoue si le fichier de sortie n'est
|
||||||
|
pas déjà présent.
|
||||||
|
- notrunc : le fichier de sortie ne sera pas tronqué. Si cette option n'est pas
|
||||||
|
présente, la sortie sera tronquée à l'ouverture.
|
||||||
|
- noerror : toutes les erreurs de lecture seront ignorées. Si cette option n'est pas présente,
|
||||||
|
dd n'ignorera que Error::Interrupted.
|
||||||
|
- fdatasync : les données seront écrites avant la fin.
|
||||||
|
- fsync : les données et les métadonnées seront écrites avant la fin.
|
||||||
|
|
||||||
|
### Indicateurs d'entrée
|
||||||
|
|
||||||
|
- count_bytes : une valeur pour count=N sera interprétée comme des octets.
|
||||||
|
- skip_bytes : une valeur pour skip=N sera interprétée comme des octets.
|
||||||
|
- fullblock : attendre ibs octets de chaque lecture. les lectures de longueur zéro sont toujours
|
||||||
|
considérées comme EOF.
|
||||||
|
|
||||||
|
### Indicateurs de sortie
|
||||||
|
|
||||||
|
- append : ouvrir le fichier en mode ajout. Considérez définir conv=notrunc aussi.
|
||||||
|
- seek_bytes : une valeur pour seek=N sera interprétée comme des octets.
|
||||||
|
|
||||||
|
### Indicateurs généraux
|
||||||
|
|
||||||
|
- direct : utiliser les E/S directes pour les données.
|
||||||
|
- directory : échouer sauf si l'entrée donnée (si utilisée comme iflag) ou
|
||||||
|
la sortie (si utilisée comme oflag) est un répertoire.
|
||||||
|
- dsync : utiliser les E/S synchronisées pour les données.
|
||||||
|
- sync : utiliser les E/S synchronisées pour les données et les métadonnées.
|
||||||
|
- nonblock : utiliser les E/S non-bloquantes.
|
||||||
|
- noatime : ne pas mettre à jour l'heure d'accès.
|
||||||
|
- nocache : demander au système d'exploitation de supprimer le cache.
|
||||||
|
- noctty : ne pas assigner un tty de contrôle.
|
||||||
|
- nofollow : ne pas suivre les liens système.
|
||||||
|
|
||||||
|
# Error messages
|
||||||
|
dd-error-failed-to-open = échec de l'ouverture de { $path }
|
||||||
|
dd-error-write-error = erreur d'écriture
|
||||||
|
dd-error-failed-to-seek = échec de la recherche dans le fichier de sortie
|
||||||
|
dd-error-io-error = erreur E/S
|
||||||
|
dd-error-cannot-skip-offset = '{ $file }' : impossible d'ignorer jusqu'au décalage spécifié
|
||||||
|
dd-error-cannot-skip-invalid = '{ $file }' : impossible d'ignorer : Argument invalide
|
||||||
|
dd-error-cannot-seek-invalid = '{ $output }' : impossible de rechercher : Argument invalide
|
||||||
|
dd-error-not-directory = définir les indicateurs pour '{ $file }' : N'est pas un répertoire
|
||||||
|
dd-error-failed-discard-cache-input = échec de la suppression du cache pour : 'entrée standard'
|
||||||
|
dd-error-failed-discard-cache-output = échec de la suppression du cache pour : 'sortie standard'
|
||||||
|
|
||||||
|
# Parse errors
|
||||||
|
dd-error-unrecognized-operand = Opérande non reconnue '{ $operand }'
|
||||||
|
dd-error-multiple-format-table = Seul un seul de conv=ascii conv=ebcdic ou conv=ibm peut être spécifié
|
||||||
|
dd-error-multiple-case = Seul un seul de conv=lcase ou conv=ucase peut être spécifié
|
||||||
|
dd-error-multiple-block = Seul un seul de conv=block ou conv=unblock peut être spécifié
|
||||||
|
dd-error-multiple-excl = Seul un seul de conv=excl ou conv=nocreat peut être spécifié
|
||||||
|
dd-error-invalid-flag = indicateur d'entrée invalide : '{ $flag }'
|
||||||
|
Essayez '{ $cmd } --help' pour plus d'informations.
|
||||||
|
dd-error-conv-flag-no-match = conv=CONV non reconnu -> { $flag }
|
||||||
|
dd-error-multiplier-parse-failure = nombre invalide : ‘{ $input }‘
|
||||||
|
dd-error-multiplier-overflow = La chaîne de multiplicateur déborderait sur le système actuel -> { $input }
|
||||||
|
dd-error-block-without-cbs = conv=block ou conv=unblock spécifié sans cbs=N
|
||||||
|
dd-error-status-not-recognized = status=NIVEAU non reconnu -> { $level }
|
||||||
|
dd-error-unimplemented = fonctionnalité non implémentée sur ce système -> { $feature }
|
||||||
|
dd-error-bs-out-of-range = { $param }=N ne peut pas tenir en mémoire
|
||||||
|
dd-error-invalid-number = nombre invalide : ‘{ $input }‘
|
||||||
|
|
||||||
|
# Progress messages
|
||||||
|
dd-progress-records-in = { $complete }+{ $partial } enregistrements en entrée
|
||||||
|
dd-progress-records-out = { $complete }+{ $partial } enregistrements en sortie
|
||||||
|
dd-progress-truncated-record = { $count ->
|
||||||
|
[one] { $count } enregistrement tronqué
|
||||||
|
*[other] { $count } enregistrements tronqués
|
||||||
|
}
|
||||||
|
dd-progress-byte-copied = { $bytes } octet copié, { $duration } s, { $rate }/s
|
||||||
|
dd-progress-bytes-copied = { $bytes } octets copiés, { $duration } s, { $rate }/s
|
||||||
|
dd-progress-bytes-copied-si = { $bytes } octets ({ $si }) copiés, { $duration } s, { $rate }/s
|
||||||
|
dd-progress-bytes-copied-si-iec = { $bytes } octets ({ $si }, { $iec }) copiés, { $duration } s, { $rate }/s
|
||||||
|
|
||||||
|
# Warnings
|
||||||
|
dd-warning-zero-multiplier = { $zero } est un multiplicateur zéro ; utilisez { $alternative } si c'est voulu
|
||||||
|
dd-warning-signal-handler = Avertissement dd interne : Impossible d'enregistrer le gestionnaire de signal
|
|
@ -26,6 +26,7 @@ use progress::{ProgUpdate, ReadStat, StatusLevel, WriteStat, gen_prog_updater};
|
||||||
use uucore::io::OwnedFileDescriptorOrHandle;
|
use uucore::io::OwnedFileDescriptorOrHandle;
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
|
@ -62,7 +63,7 @@ use uucore::error::{USimpleError, set_exit_code};
|
||||||
use uucore::show_if_err;
|
use uucore::show_if_err;
|
||||||
use uucore::{format_usage, show_error};
|
use uucore::{format_usage, show_error};
|
||||||
|
|
||||||
use uucore::locale::get_message;
|
use uucore::locale::{get_message, get_message_with_args};
|
||||||
const BUF_INIT_BYTE: u8 = 0xDD;
|
const BUF_INIT_BYTE: u8 = 0xDD;
|
||||||
|
|
||||||
/// Final settings after parsing
|
/// Final settings after parsing
|
||||||
|
@ -235,7 +236,13 @@ impl Source {
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
Self::Stdin(stdin) => match io::copy(&mut stdin.take(n), &mut io::sink()) {
|
Self::Stdin(stdin) => match io::copy(&mut stdin.take(n), &mut io::sink()) {
|
||||||
Ok(m) if m < n => {
|
Ok(m) if m < n => {
|
||||||
show_error!("'standard input': cannot skip to specified offset");
|
show_error!(
|
||||||
|
"{}",
|
||||||
|
get_message_with_args(
|
||||||
|
"dd-error-cannot-skip-offset",
|
||||||
|
HashMap::from([("file".to_string(), "standard input".to_string())])
|
||||||
|
)
|
||||||
|
);
|
||||||
Ok(m)
|
Ok(m)
|
||||||
}
|
}
|
||||||
Ok(m) => Ok(m),
|
Ok(m) => Ok(m),
|
||||||
|
@ -247,14 +254,26 @@ impl Source {
|
||||||
if len < n {
|
if len < n {
|
||||||
// GNU compatibility:
|
// GNU compatibility:
|
||||||
// this case prints the stats but sets the exit code to 1
|
// this case prints the stats but sets the exit code to 1
|
||||||
show_error!("'standard input': cannot skip: Invalid argument");
|
show_error!(
|
||||||
|
"{}",
|
||||||
|
get_message_with_args(
|
||||||
|
"dd-error-cannot-skip-invalid",
|
||||||
|
HashMap::from([("file".to_string(), "standard input".to_string())])
|
||||||
|
)
|
||||||
|
);
|
||||||
set_exit_code(1);
|
set_exit_code(1);
|
||||||
return Ok(len);
|
return Ok(len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match io::copy(&mut f.take(n), &mut io::sink()) {
|
match io::copy(&mut f.take(n), &mut io::sink()) {
|
||||||
Ok(m) if m < n => {
|
Ok(m) if m < n => {
|
||||||
show_error!("'standard input': cannot skip to specified offset");
|
show_error!(
|
||||||
|
"{}",
|
||||||
|
get_message_with_args(
|
||||||
|
"dd-error-cannot-skip-offset",
|
||||||
|
HashMap::from([("file".to_string(), "standard input".to_string())])
|
||||||
|
)
|
||||||
|
);
|
||||||
Ok(m)
|
Ok(m)
|
||||||
}
|
}
|
||||||
Ok(m) => Ok(m),
|
Ok(m) => Ok(m),
|
||||||
|
@ -343,7 +362,10 @@ impl<'a> Input<'a> {
|
||||||
if settings.iflags.directory && !f.metadata()?.is_dir() {
|
if settings.iflags.directory && !f.metadata()?.is_dir() {
|
||||||
return Err(USimpleError::new(
|
return Err(USimpleError::new(
|
||||||
1,
|
1,
|
||||||
"setting flags for 'standard input': Not a directory",
|
get_message_with_args(
|
||||||
|
"dd-error-not-directory",
|
||||||
|
HashMap::from([("file".to_string(), "standard input".to_string())]),
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -364,8 +386,12 @@ impl<'a> Input<'a> {
|
||||||
opts.custom_flags(libc_flags);
|
opts.custom_flags(libc_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
opts.open(filename)
|
opts.open(filename).map_err_context(|| {
|
||||||
.map_err_context(|| format!("failed to open {}", filename.quote()))?
|
get_message_with_args(
|
||||||
|
"dd-error-failed-to-open",
|
||||||
|
HashMap::from([("path".to_string(), filename.quote().to_string())]),
|
||||||
|
)
|
||||||
|
})?
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut src = Source::File(src);
|
let mut src = Source::File(src);
|
||||||
|
@ -457,10 +483,11 @@ impl Input<'_> {
|
||||||
fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) {
|
fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
show_if_err!(self
|
show_if_err!(
|
||||||
.src
|
self.src
|
||||||
.discard_cache(offset, len)
|
.discard_cache(offset, len)
|
||||||
.map_err_context(|| "failed to discard cache for: 'standard input'".to_string()));
|
.map_err_context(|| get_message("dd-error-failed-discard-cache-input"))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
{
|
{
|
||||||
|
@ -609,7 +636,16 @@ impl Dest {
|
||||||
if len < n {
|
if len < n {
|
||||||
// GNU compatibility:
|
// GNU compatibility:
|
||||||
// this case prints the stats but sets the exit code to 1
|
// this case prints the stats but sets the exit code to 1
|
||||||
show_error!("'standard output': cannot seek: Invalid argument");
|
show_error!(
|
||||||
|
"{}",
|
||||||
|
get_message_with_args(
|
||||||
|
"dd-error-cannot-seek-invalid",
|
||||||
|
HashMap::from([(
|
||||||
|
"output".to_string(),
|
||||||
|
"standard output".to_string()
|
||||||
|
)])
|
||||||
|
)
|
||||||
|
);
|
||||||
set_exit_code(1);
|
set_exit_code(1);
|
||||||
return Ok(len);
|
return Ok(len);
|
||||||
}
|
}
|
||||||
|
@ -723,7 +759,7 @@ impl<'a> Output<'a> {
|
||||||
fn new_stdout(settings: &'a Settings) -> UResult<Self> {
|
fn new_stdout(settings: &'a Settings) -> UResult<Self> {
|
||||||
let mut dst = Dest::Stdout(io::stdout());
|
let mut dst = Dest::Stdout(io::stdout());
|
||||||
dst.seek(settings.seek)
|
dst.seek(settings.seek)
|
||||||
.map_err_context(|| "write error".to_string())?;
|
.map_err_context(|| get_message("dd-error-write-error"))?;
|
||||||
Ok(Self { dst, settings })
|
Ok(Self { dst, settings })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -744,8 +780,12 @@ impl<'a> Output<'a> {
|
||||||
opts.open(path)
|
opts.open(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
let dst = open_dst(filename, &settings.oconv, &settings.oflags)
|
let dst = open_dst(filename, &settings.oconv, &settings.oflags).map_err_context(|| {
|
||||||
.map_err_context(|| format!("failed to open {}", filename.quote()))?;
|
get_message_with_args(
|
||||||
|
"dd-error-failed-to-open",
|
||||||
|
HashMap::from([("path".to_string(), filename.quote().to_string())]),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
// Seek to the index in the output file, truncating if requested.
|
// Seek to the index in the output file, truncating if requested.
|
||||||
//
|
//
|
||||||
|
@ -770,7 +810,7 @@ impl<'a> Output<'a> {
|
||||||
};
|
};
|
||||||
let mut dst = Dest::File(dst, density);
|
let mut dst = Dest::File(dst, density);
|
||||||
dst.seek(settings.seek)
|
dst.seek(settings.seek)
|
||||||
.map_err_context(|| "failed to seek in output file".to_string())?;
|
.map_err_context(|| get_message("dd-error-failed-to-seek"))?;
|
||||||
Ok(Self { dst, settings })
|
Ok(Self { dst, settings })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -832,9 +872,11 @@ impl<'a> Output<'a> {
|
||||||
fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) {
|
fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
show_if_err!(self.dst.discard_cache(offset, len).map_err_context(|| {
|
show_if_err!(
|
||||||
"failed to discard cache for: 'standard output'".to_string()
|
self.dst
|
||||||
}));
|
.discard_cache(offset, len)
|
||||||
|
.map_err_context(|| { get_message("dd-error-failed-discard-cache-output") })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
{
|
{
|
||||||
|
@ -1083,7 +1125,7 @@ fn dd_copy(mut i: Input, o: Output) -> io::Result<()> {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
if let Err(e) = &signal_handler {
|
if let Err(e) = &signal_handler {
|
||||||
if Some(StatusLevel::None) != i.settings.status {
|
if Some(StatusLevel::None) != i.settings.status {
|
||||||
eprintln!("Internal dd Warning: Unable to register signal handler \n\t{e}");
|
eprintln!("{}\n\t{e}", get_message("dd-warning-signal-handler"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1419,7 +1461,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
None if is_stdout_redirected_to_seekable_file() => Output::new_file_from_stdout(&settings)?,
|
None if is_stdout_redirected_to_seekable_file() => Output::new_file_from_stdout(&settings)?,
|
||||||
None => Output::new_stdout(&settings)?,
|
None => Output::new_stdout(&settings)?,
|
||||||
};
|
};
|
||||||
dd_copy(i, o).map_err_context(|| "IO error".to_string())
|
dd_copy(i, o).map_err_context(|| get_message("dd-error-io-error"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uu_app() -> Command {
|
pub fn uu_app() -> Command {
|
||||||
|
|
|
@ -9,42 +9,53 @@ mod unit_tests;
|
||||||
|
|
||||||
use super::{ConversionMode, IConvFlags, IFlags, Num, OConvFlags, OFlags, Settings, StatusLevel};
|
use super::{ConversionMode, IConvFlags, IFlags, Num, OConvFlags, OFlags, Settings, StatusLevel};
|
||||||
use crate::conversion_tables::ConversionTable;
|
use crate::conversion_tables::ConversionTable;
|
||||||
|
use std::collections::HashMap;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::UError;
|
use uucore::error::UError;
|
||||||
|
use uucore::locale::{get_message, get_message_with_args};
|
||||||
use uucore::parser::parse_size::{ParseSizeError, Parser as SizeParser};
|
use uucore::parser::parse_size::{ParseSizeError, Parser as SizeParser};
|
||||||
use uucore::show_warning;
|
use uucore::show_warning;
|
||||||
|
|
||||||
/// Parser Errors describe errors with parser input
|
/// Parser Errors describe errors with parser input
|
||||||
#[derive(Debug, PartialEq, Eq, Error)]
|
#[derive(Debug, PartialEq, Eq, Error)]
|
||||||
pub enum ParseError {
|
pub enum ParseError {
|
||||||
#[error("Unrecognized operand '{0}'")]
|
#[error("{}", get_message_with_args("dd-error-unrecognized-operand",
|
||||||
|
HashMap::from([("operand".to_string(), .0.clone())])))]
|
||||||
UnrecognizedOperand(String),
|
UnrecognizedOperand(String),
|
||||||
#[error("Only one of conv=ascii conv=ebcdic or conv=ibm may be specified")]
|
#[error("{}", get_message("dd-error-multiple-format-table"))]
|
||||||
MultipleFmtTable,
|
MultipleFmtTable,
|
||||||
#[error("Only one of conv=lcase or conv=ucase may be specified")]
|
#[error("{}", get_message("dd-error-multiple-case"))]
|
||||||
MultipleUCaseLCase,
|
MultipleUCaseLCase,
|
||||||
#[error("Only one of conv=block or conv=unblock may be specified")]
|
#[error("{}", get_message("dd-error-multiple-block"))]
|
||||||
MultipleBlockUnblock,
|
MultipleBlockUnblock,
|
||||||
#[error("Only one ov conv=excl or conv=nocreat may be specified")]
|
#[error("{}", get_message("dd-error-multiple-excl"))]
|
||||||
MultipleExclNoCreate,
|
MultipleExclNoCreate,
|
||||||
#[error("invalid input flag: ‘{}’\nTry '{} --help' for more information.", .0, uucore::execution_phrase())]
|
#[error("{}", get_message_with_args("dd-error-invalid-flag",
|
||||||
|
HashMap::from([("flag".to_string(), .0.clone()),("cmd".to_string(), uucore::execution_phrase().to_string())])))]
|
||||||
FlagNoMatch(String),
|
FlagNoMatch(String),
|
||||||
#[error("Unrecognized conv=CONV -> {0}")]
|
#[error("{}", get_message_with_args("dd-error-conv-flag-no-match",
|
||||||
|
HashMap::from([("flag".to_string(), .0.clone())])))]
|
||||||
ConvFlagNoMatch(String),
|
ConvFlagNoMatch(String),
|
||||||
#[error("invalid number: ‘{0}’")]
|
#[error("{}", get_message_with_args("dd-error-multiplier-parse-failure",
|
||||||
|
HashMap::from([("input".to_string(), .0.clone())])))]
|
||||||
MultiplierStringParseFailure(String),
|
MultiplierStringParseFailure(String),
|
||||||
#[error("Multiplier string would overflow on current system -> {0}")]
|
#[error("{}", get_message_with_args("dd-error-multiplier-overflow",
|
||||||
|
HashMap::from([("input".to_string(), .0.clone())])))]
|
||||||
MultiplierStringOverflow(String),
|
MultiplierStringOverflow(String),
|
||||||
#[error("conv=block or conv=unblock specified without cbs=N")]
|
#[error("{}", get_message("dd-error-block-without-cbs"))]
|
||||||
BlockUnblockWithoutCBS,
|
BlockUnblockWithoutCBS,
|
||||||
#[error("status=LEVEL not recognized -> {0}")]
|
#[error("{}", get_message_with_args("dd-error-status-not-recognized",
|
||||||
|
HashMap::from([("level".to_string(), .0.clone())])))]
|
||||||
StatusLevelNotRecognized(String),
|
StatusLevelNotRecognized(String),
|
||||||
#[error("feature not implemented on this system -> {0}")]
|
#[error("{}", get_message_with_args("dd-error-unimplemented",
|
||||||
|
HashMap::from([("feature".to_string(), .0.clone())])))]
|
||||||
Unimplemented(String),
|
Unimplemented(String),
|
||||||
#[error("{0}=N cannot fit into memory")]
|
#[error("{}", get_message_with_args("dd-error-bs-out-of-range",
|
||||||
|
HashMap::from([("param".to_string(), .0.clone())])))]
|
||||||
BsOutOfRange(String),
|
BsOutOfRange(String),
|
||||||
#[error("invalid number: ‘{0}’")]
|
#[error("{}", get_message_with_args("dd-error-invalid-number",
|
||||||
|
HashMap::from([("input".to_string(), .0.clone())])))]
|
||||||
InvalidNumber(String),
|
InvalidNumber(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,9 +435,14 @@ impl UError for ParseError {
|
||||||
|
|
||||||
fn show_zero_multiplier_warning() {
|
fn show_zero_multiplier_warning() {
|
||||||
show_warning!(
|
show_warning!(
|
||||||
"{} is a zero multiplier; use {} if that is intended",
|
"{}",
|
||||||
"0x".quote(),
|
get_message_with_args(
|
||||||
"00x".quote()
|
"dd-warning-zero-multiplier",
|
||||||
|
HashMap::from([
|
||||||
|
("zero".to_string(), "0x".quote().to_string()),
|
||||||
|
("alternative".to_string(), "00x".quote().to_string())
|
||||||
|
])
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
//! read and write progress of a running `dd` process. The
|
//! read and write progress of a running `dd` process. The
|
||||||
//! [`gen_prog_updater`] function can be used to implement a progress
|
//! [`gen_prog_updater`] function can be used to implement a progress
|
||||||
//! updater that runs in its own thread.
|
//! updater that runs in its own thread.
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
|
@ -20,6 +21,8 @@ use signal_hook::iterator::Handle;
|
||||||
use uucore::{
|
use uucore::{
|
||||||
error::UResult,
|
error::UResult,
|
||||||
format::num_format::{FloatVariant, Formatter},
|
format::num_format::{FloatVariant, Formatter},
|
||||||
|
locale::get_message_with_args,
|
||||||
|
locale::setup_localization,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::numbers::{SuffixType, to_magnitude_and_suffix};
|
use crate::numbers::{SuffixType, to_magnitude_and_suffix};
|
||||||
|
@ -102,8 +105,13 @@ impl ProgUpdate {
|
||||||
self.write_stat.report(w)?;
|
self.write_stat.report(w)?;
|
||||||
match self.read_stat.records_truncated {
|
match self.read_stat.records_truncated {
|
||||||
0 => {}
|
0 => {}
|
||||||
1 => writeln!(w, "1 truncated record")?,
|
count => {
|
||||||
n => writeln!(w, "{n} truncated records")?,
|
let message = get_message_with_args(
|
||||||
|
"dd-progress-truncated-record",
|
||||||
|
HashMap::from([("count".to_string(), count.to_string())]),
|
||||||
|
);
|
||||||
|
writeln!(w, "{}", message)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -164,24 +172,45 @@ impl ProgUpdate {
|
||||||
// If the number of bytes written is sufficiently large, then
|
// If the number of bytes written is sufficiently large, then
|
||||||
// print a more concise representation of the number, like
|
// print a more concise representation of the number, like
|
||||||
// "1.2 kB" and "1.0 KiB".
|
// "1.2 kB" and "1.0 KiB".
|
||||||
match btotal {
|
let message = match btotal {
|
||||||
1 => write!(
|
1 => get_message_with_args(
|
||||||
w,
|
"dd-progress-byte-copied",
|
||||||
"{carriage_return}{btotal} byte copied, {duration_str} s, {transfer_rate}/s{newline}",
|
HashMap::from([
|
||||||
)?,
|
("bytes".to_string(), btotal.to_string()),
|
||||||
0..=999 => write!(
|
("duration".to_string(), duration_str.to_string()),
|
||||||
w,
|
("rate".to_string(), transfer_rate.to_string()),
|
||||||
"{carriage_return}{btotal} bytes copied, {duration_str} s, {transfer_rate}/s{newline}",
|
]),
|
||||||
)?,
|
),
|
||||||
1000..=1023 => write!(
|
0..=999 => get_message_with_args(
|
||||||
w,
|
"dd-progress-bytes-copied",
|
||||||
"{carriage_return}{btotal} bytes ({btotal_metric}) copied, {duration_str} s, {transfer_rate}/s{newline}",
|
HashMap::from([
|
||||||
)?,
|
("bytes".to_string(), btotal.to_string()),
|
||||||
_ => write!(
|
("duration".to_string(), duration_str.to_string()),
|
||||||
w,
|
("rate".to_string(), transfer_rate.to_string()),
|
||||||
"{carriage_return}{btotal} bytes ({btotal_metric}, {btotal_bin}) copied, {duration_str} s, {transfer_rate}/s{newline}",
|
]),
|
||||||
)?,
|
),
|
||||||
|
1000..=1023 => get_message_with_args(
|
||||||
|
"dd-progress-bytes-copied-si",
|
||||||
|
HashMap::from([
|
||||||
|
("bytes".to_string(), btotal.to_string()),
|
||||||
|
("si".to_string(), btotal_metric.to_string()),
|
||||||
|
("duration".to_string(), duration_str.to_string()),
|
||||||
|
("rate".to_string(), transfer_rate.to_string()),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
_ => get_message_with_args(
|
||||||
|
"dd-progress-bytes-copied-si-iec",
|
||||||
|
HashMap::from([
|
||||||
|
("bytes".to_string(), btotal.to_string()),
|
||||||
|
("si".to_string(), btotal_metric.to_string()),
|
||||||
|
("iec".to_string(), btotal_bin.to_string()),
|
||||||
|
("duration".to_string(), duration_str.to_string()),
|
||||||
|
("rate".to_string(), transfer_rate.to_string()),
|
||||||
|
]),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
write!(w, "{carriage_return}{message}{newline}")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,11 +340,14 @@ impl ReadStat {
|
||||||
///
|
///
|
||||||
/// If there is a problem writing to `w`.
|
/// If there is a problem writing to `w`.
|
||||||
fn report(&self, w: &mut impl Write) -> std::io::Result<()> {
|
fn report(&self, w: &mut impl Write) -> std::io::Result<()> {
|
||||||
writeln!(
|
let message = get_message_with_args(
|
||||||
w,
|
"dd-progress-records-in",
|
||||||
"{}+{} records in",
|
HashMap::from([
|
||||||
self.reads_complete, self.reads_partial
|
("complete".to_string(), self.reads_complete.to_string()),
|
||||||
)?;
|
("partial".to_string(), self.reads_partial.to_string()),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
writeln!(w, "{}", message)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,11 +400,14 @@ impl WriteStat {
|
||||||
///
|
///
|
||||||
/// If there is a problem writing to `w`.
|
/// If there is a problem writing to `w`.
|
||||||
fn report(&self, w: &mut impl Write) -> std::io::Result<()> {
|
fn report(&self, w: &mut impl Write) -> std::io::Result<()> {
|
||||||
writeln!(
|
let message = get_message_with_args(
|
||||||
w,
|
"dd-progress-records-out",
|
||||||
"{}+{} records out",
|
HashMap::from([
|
||||||
self.writes_complete, self.writes_partial
|
("complete".to_string(), self.writes_complete.to_string()),
|
||||||
)
|
("partial".to_string(), self.writes_partial.to_string()),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
writeln!(w, "{}", message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,6 +463,9 @@ pub(crate) fn gen_prog_updater(
|
||||||
print_level: Option<StatusLevel>,
|
print_level: Option<StatusLevel>,
|
||||||
) -> impl Fn() {
|
) -> impl Fn() {
|
||||||
move || {
|
move || {
|
||||||
|
// As we are in a thread, we need to set up localization independently.
|
||||||
|
let _ = setup_localization("dd");
|
||||||
|
|
||||||
let mut progress_printed = false;
|
let mut progress_printed = false;
|
||||||
while let Ok(update) = rx.recv() {
|
while let Ok(update) = rx.recv() {
|
||||||
// Print the final read/write statistics.
|
// Print the final read/write statistics.
|
||||||
|
@ -502,6 +540,9 @@ pub(crate) fn gen_prog_updater(
|
||||||
) -> impl Fn() {
|
) -> impl Fn() {
|
||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
move || {
|
move || {
|
||||||
|
// As we are in a thread, we need to set up localization independently.
|
||||||
|
let _ = setup_localization("dd");
|
||||||
|
|
||||||
// Holds the state of whether we have printed the current progress.
|
// Holds the state of whether we have printed the current progress.
|
||||||
// This is needed so that we know whether or not to print a newline
|
// This is needed so that we know whether or not to print a newline
|
||||||
// character before outputting non-progress data.
|
// character before outputting non-progress data.
|
||||||
|
@ -532,11 +573,18 @@ pub(crate) fn gen_prog_updater(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::env;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use uucore::locale::setup_localization;
|
||||||
|
|
||||||
use super::{ProgUpdate, ReadStat, WriteStat};
|
use super::{ProgUpdate, ReadStat, WriteStat};
|
||||||
|
fn init() {
|
||||||
|
unsafe {
|
||||||
|
env::set_var("LANG", "C");
|
||||||
|
}
|
||||||
|
let _ = setup_localization("dd");
|
||||||
|
}
|
||||||
|
|
||||||
fn prog_update_write(n: u128) -> ProgUpdate {
|
fn prog_update_write(n: u128) -> ProgUpdate {
|
||||||
ProgUpdate {
|
ProgUpdate {
|
||||||
|
@ -561,22 +609,31 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_read_stat_report() {
|
fn test_read_stat_report() {
|
||||||
|
init();
|
||||||
let read_stat = ReadStat::new(1, 2, 3, 4);
|
let read_stat = ReadStat::new(1, 2, 3, 4);
|
||||||
let mut cursor = Cursor::new(vec![]);
|
let mut cursor = Cursor::new(vec![]);
|
||||||
read_stat.report(&mut cursor).unwrap();
|
read_stat.report(&mut cursor).unwrap();
|
||||||
assert_eq!(cursor.get_ref(), b"1+2 records in\n");
|
assert_eq!(
|
||||||
|
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||||
|
"1+2 records in\n"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_write_stat_report() {
|
fn test_write_stat_report() {
|
||||||
|
init();
|
||||||
let write_stat = WriteStat::new(1, 2, 3);
|
let write_stat = WriteStat::new(1, 2, 3);
|
||||||
let mut cursor = Cursor::new(vec![]);
|
let mut cursor = Cursor::new(vec![]);
|
||||||
write_stat.report(&mut cursor).unwrap();
|
write_stat.report(&mut cursor).unwrap();
|
||||||
assert_eq!(cursor.get_ref(), b"1+2 records out\n");
|
assert_eq!(
|
||||||
|
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||||
|
"1+2 records out\n"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_prog_update_write_io_lines() {
|
fn test_prog_update_write_io_lines() {
|
||||||
|
init();
|
||||||
let read_stat = ReadStat::new(1, 2, 3, 4);
|
let read_stat = ReadStat::new(1, 2, 3, 4);
|
||||||
let write_stat = WriteStat::new(4, 5, 6);
|
let write_stat = WriteStat::new(4, 5, 6);
|
||||||
let duration = Duration::new(789, 0);
|
let duration = Duration::new(789, 0);
|
||||||
|
@ -591,13 +648,14 @@ mod tests {
|
||||||
let mut cursor = Cursor::new(vec![]);
|
let mut cursor = Cursor::new(vec![]);
|
||||||
prog_update.write_io_lines(&mut cursor).unwrap();
|
prog_update.write_io_lines(&mut cursor).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cursor.get_ref(),
|
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||||
b"1+2 records in\n4+5 records out\n3 truncated records\n"
|
"1+2 records in\n4+5 records out\n3 truncated records\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_prog_update_write_prog_line() {
|
fn test_prog_update_write_prog_line() {
|
||||||
|
init();
|
||||||
let prog_update = ProgUpdate {
|
let prog_update = ProgUpdate {
|
||||||
read_stat: ReadStat::default(),
|
read_stat: ReadStat::default(),
|
||||||
write_stat: WriteStat::default(),
|
write_stat: WriteStat::default(),
|
||||||
|
@ -615,45 +673,55 @@ mod tests {
|
||||||
// 0 bytes copied, 7.9151e-05 s, 0.0 kB/s
|
// 0 bytes copied, 7.9151e-05 s, 0.0 kB/s
|
||||||
//
|
//
|
||||||
// The throughput still does not match GNU dd.
|
// The throughput still does not match GNU dd.
|
||||||
assert_eq!(cursor.get_ref(), b"0 bytes copied, 1 s, 0.0 B/s\n");
|
assert_eq!(
|
||||||
|
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||||
|
"0 bytes copied, 1 s, 0.0 B/s\n"
|
||||||
|
);
|
||||||
|
|
||||||
let prog_update = prog_update_write(1);
|
let prog_update = prog_update_write(1);
|
||||||
let mut cursor = Cursor::new(vec![]);
|
let mut cursor = Cursor::new(vec![]);
|
||||||
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
||||||
assert_eq!(cursor.get_ref(), b"1 byte copied, 1 s, 0.0 B/s\n");
|
assert_eq!(
|
||||||
|
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||||
|
"1 byte copied, 1 s, 0.0 B/s\n"
|
||||||
|
);
|
||||||
|
|
||||||
let prog_update = prog_update_write(999);
|
let prog_update = prog_update_write(999);
|
||||||
let mut cursor = Cursor::new(vec![]);
|
let mut cursor = Cursor::new(vec![]);
|
||||||
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
||||||
assert_eq!(cursor.get_ref(), b"999 bytes copied, 1 s, 0.0 B/s\n");
|
assert_eq!(
|
||||||
|
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||||
|
"999 bytes copied, 1 s, 0.0 B/s\n"
|
||||||
|
);
|
||||||
|
|
||||||
let prog_update = prog_update_write(1000);
|
let prog_update = prog_update_write(1000);
|
||||||
let mut cursor = Cursor::new(vec![]);
|
let mut cursor = Cursor::new(vec![]);
|
||||||
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cursor.get_ref(),
|
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||||
b"1000 bytes (1.0 kB) copied, 1 s, 1.0 kB/s\n"
|
"1000 bytes (1.0 kB) copied, 1 s, 1.0 kB/s\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
let prog_update = prog_update_write(1023);
|
let prog_update = prog_update_write(1023);
|
||||||
let mut cursor = Cursor::new(vec![]);
|
let mut cursor = Cursor::new(vec![]);
|
||||||
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cursor.get_ref(),
|
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||||
b"1023 bytes (1.0 kB) copied, 1 s, 1.0 kB/s\n"
|
"1023 bytes (1.0 kB) copied, 1 s, 1.0 kB/s\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
let prog_update = prog_update_write(1024);
|
let prog_update = prog_update_write(1024);
|
||||||
let mut cursor = Cursor::new(vec![]);
|
let mut cursor = Cursor::new(vec![]);
|
||||||
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cursor.get_ref(),
|
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||||
b"1024 bytes (1.0 kB, 1.0 KiB) copied, 1 s, 1.0 kB/s\n"
|
"1024 bytes (1.0 kB, 1.0 KiB) copied, 1 s, 1.0 kB/s\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn write_transfer_stats() {
|
fn write_transfer_stats() {
|
||||||
|
init();
|
||||||
let prog_update = ProgUpdate {
|
let prog_update = ProgUpdate {
|
||||||
read_stat: ReadStat::default(),
|
read_stat: ReadStat::default(),
|
||||||
write_stat: WriteStat::default(),
|
write_stat: WriteStat::default(),
|
||||||
|
@ -664,16 +732,18 @@ mod tests {
|
||||||
prog_update
|
prog_update
|
||||||
.write_transfer_stats(&mut cursor, false)
|
.write_transfer_stats(&mut cursor, false)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut iter = cursor.get_ref().split(|v| *v == b'\n');
|
let output_str = std::str::from_utf8(cursor.get_ref()).unwrap();
|
||||||
assert_eq!(iter.next().unwrap(), b"0+0 records in");
|
let mut iter = output_str.split('\n');
|
||||||
assert_eq!(iter.next().unwrap(), b"0+0 records out");
|
assert_eq!(iter.next().unwrap(), "0+0 records in");
|
||||||
assert_eq!(iter.next().unwrap(), b"0 bytes copied, 1 s, 0.0 B/s");
|
assert_eq!(iter.next().unwrap(), "0+0 records out");
|
||||||
assert_eq!(iter.next().unwrap(), b"");
|
assert_eq!(iter.next().unwrap(), "0 bytes copied, 1 s, 0.0 B/s");
|
||||||
|
assert_eq!(iter.next().unwrap(), "");
|
||||||
assert!(iter.next().is_none());
|
assert!(iter.next().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn write_final_transfer_stats() {
|
fn write_final_transfer_stats() {
|
||||||
|
init();
|
||||||
// Tests the formatting of the final statistics written after a progress line.
|
// Tests the formatting of the final statistics written after a progress line.
|
||||||
let prog_update = ProgUpdate {
|
let prog_update = ProgUpdate {
|
||||||
read_stat: ReadStat::default(),
|
read_stat: ReadStat::default(),
|
||||||
|
@ -685,21 +755,26 @@ mod tests {
|
||||||
let rewrite = true;
|
let rewrite = true;
|
||||||
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
||||||
prog_update.write_transfer_stats(&mut cursor, true).unwrap();
|
prog_update.write_transfer_stats(&mut cursor, true).unwrap();
|
||||||
let mut iter = cursor.get_ref().split(|v| *v == b'\n');
|
let output_str = std::str::from_utf8(cursor.get_ref()).unwrap();
|
||||||
assert_eq!(iter.next().unwrap(), b"\r0 bytes copied, 1 s, 0.0 B/s");
|
let mut iter = output_str.split('\n');
|
||||||
assert_eq!(iter.next().unwrap(), b"0+0 records in");
|
assert_eq!(iter.next().unwrap(), "\r0 bytes copied, 1 s, 0.0 B/s");
|
||||||
assert_eq!(iter.next().unwrap(), b"0+0 records out");
|
assert_eq!(iter.next().unwrap(), "0+0 records in");
|
||||||
assert_eq!(iter.next().unwrap(), b"0 bytes copied, 1 s, 0.0 B/s");
|
assert_eq!(iter.next().unwrap(), "0+0 records out");
|
||||||
assert_eq!(iter.next().unwrap(), b"");
|
assert_eq!(iter.next().unwrap(), "0 bytes copied, 1 s, 0.0 B/s");
|
||||||
|
assert_eq!(iter.next().unwrap(), "");
|
||||||
assert!(iter.next().is_none());
|
assert!(iter.next().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_duration_precision() {
|
fn test_duration_precision() {
|
||||||
|
init();
|
||||||
let prog_update = prog_update_duration(Duration::from_nanos(123));
|
let prog_update = prog_update_duration(Duration::from_nanos(123));
|
||||||
let mut cursor = Cursor::new(vec![]);
|
let mut cursor = Cursor::new(vec![]);
|
||||||
let rewrite = false;
|
let rewrite = false;
|
||||||
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
||||||
assert_eq!(cursor.get_ref(), b"0 bytes copied, 1.23e-07 s, 0.0 B/s\n");
|
assert_eq!(
|
||||||
|
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||||
|
"0 bytes copied, 0.000000123 s, 0.0 B/s\n"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1617,6 +1617,7 @@ fn test_reading_partial_blocks_from_fifo() {
|
||||||
.args(["dd", "ibs=3", "obs=3", &format!("if={fifoname}")])
|
.args(["dd", "ibs=3", "obs=3", &format!("if={fifoname}")])
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
|
.env("LANG", "C")
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -1661,6 +1662,7 @@ fn test_reading_partial_blocks_from_fifo_unbuffered() {
|
||||||
.args(["dd", "bs=3", "ibs=1", "obs=1", &format!("if={fifoname}")])
|
.args(["dd", "bs=3", "ibs=1", "obs=1", &format!("if={fifoname}")])
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
|
.env("LANG", "C")
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -1767,10 +1769,10 @@ fn test_wrong_number_err_msg() {
|
||||||
new_ucmd!()
|
new_ucmd!()
|
||||||
.args(&["count=kBb"])
|
.args(&["count=kBb"])
|
||||||
.fails()
|
.fails()
|
||||||
.stderr_contains("dd: invalid number: ‘kBb’\n");
|
.stderr_contains("dd: invalid number: 'kBb'\n");
|
||||||
|
|
||||||
new_ucmd!()
|
new_ucmd!()
|
||||||
.args(&["count=1kBb555"])
|
.args(&["count=1kBb555"])
|
||||||
.fails()
|
.fails()
|
||||||
.stderr_contains("dd: invalid number: ‘1kBb555’\n");
|
.stderr_contains("dd: invalid number: '1kBb555'\n");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue