7 votes

Comment fonctionne la commande mv avec les disques externes?

Sur le même disque, je suppose que cela changerait quelque chose comme une table FAT pour pointer vers l'emplacement des fichiers.

Question

Lorsque vous vous déplacez vers un autre lecteur (peut-être même une autre partition), est-ce que la commande mv d'abord copie, puis supprime les anciens fichiers - afin de prévenir toute perte de données en cas d'exception ?

2 votes

Notez que mv lui-même ne sait rien des détails internes du système de fichiers comme la table FAT sur un système de fichiers FAT. Comme le soulignent les réponses, il se contente de faire un appel système rename() et laisse le noyau renvoyer le succès ou l'échec. L'API de fichiers Unix/POSIX laisse tous les détails du système de fichiers virtuel au noyau; le noyau lui-même est la seule chose avec des pilotes pour HFS+, VFAT, NTFS, etc. Voir la page de manuel POSIX rename(2) pour voir à quel point c'est simple.

10voto

ParanoidGeek Points 366

La commande mv de macOS est basée sur le code source BSD. Vous pouvez trouver le code source de la commande mv en ligne. En utilisant https://github.com/freebsd/freebsd/blob/master/bin/mv/mv.c comme référence, vous pouvez voir qu'ils tentent effectivement d'renommer le fichier d'abord, puis s'il traverse des systèmes de fichiers, ils font une cp suivie d'un rm.

    /*
     * Si le renommage échoue car nous essayons de traverser des périphériques, et
     * c'est un fichier régulier, faire la copie en interne ; sinon, utiliser
     * cp et rm.
     */
    if (lstat(from, &sb)) {
        warn("%s", from);
        return (1);
    }
    return (S_ISREG(sb.st_mode) ?
        fastcopy(from, to, &sb) : copy(from, to));
}

1 votes

Le extrait de code source auquel vous faites référence n'a en réalité rien à voir avec la détection d'un déplacement inter-système de fichiers ou avec l'exécution d'une commande cp suivie d'une commande rm. Ce n'est qu'un commentaire qui décrit ce comportement - le code réel pour cela se trouve en réalité avant le commentaire. Le code après le commentaire suppose déjà qu'il s'agit d'un déplacement entre appareils, et détermine si la source est un fichier régulier à copier en interne, ou quelque chose d'autre à déplacer en utilisant les appels aux programmes externes cp et mv.

2 votes

@jksoegaard - Correct. Je mettais en évidence la section de code du code source lié qui répond directement à la question posée.

2 votes

Eh bien, le commentaire aborde la question. Le code ne le fait pas, car le code pertinent se trouve avant le commentaire :-)

6voto

Jose Chavez Points 645

Oui, vous avez raison de penser que le déplacement d'un seul fichier sur le même système de fichiers est en fait implémenté comme une opération de renommage qui modifie la structure du système de fichiers pour mettre à jour le nouveau nom/emplacement du fichier, mais le contenu du fichier n'est pas lu/écrit sur le disque à nouveau.

Lorsque le déplacement se fait entre deux systèmes de fichiers différents (lecteurs ou partitions), alors la commande mv supprime d'abord la destination (s'il y avait déjà un ancien fichier là-bas), copie le contenu du fichier vers la destination et enfin supprime le fichier source.

Le comportement est expliqué dans le manuel de mv sur macOS:

Comme l'appel à rename(2) ne fonctionne pas entre les systèmes de fichiers, mv utilise cp(1) et rm(1) pour réaliser le déplacement. L'effet est équivalent à :

rm -f chemin_destination && \
cp -pRP fichier_source destination && \
rm -rf fichier_source

En ce qui concerne l'autre réponse qui compare ce comportement avec le code source FreeBSD - la commande mv sur macOS est en réalité un peu différente de celle sur FreeBSD. En particulier, elle veille à ce que les attributs étendus et les fourches de ressources soient déplacés correctement et ne disparaissent pas lors des déplacements entre les limites des systèmes de fichiers.

Vous pouvez lire le véritable code source macOS pour mv. Vous verrez qu'il est similaire en structure à la version FreeBSD, mais contient diverses améliorations spécifiques à Apple. En plus de la fonctionnalité concernant les attributs étendus et les fourches de ressources telles que décrites ci-dessus, il comporte également des améliorations de performance pour une utilisation avec Xsan (système de fichiers distribués).

Vous verrez dans le code qu'au départ un renommage est tenté :

if (!rename(from, to)) {
    if (vflg)
        printf("%s -> %s\n", from, to);
    return (0);
}

Si ce rename() échoue, le code vérifie pourquoi il a échoué. Surtout, il vérifie le numéro d'erreur EXDEV, qui signifie que le renommage aurait traversé les systèmes de fichiers, et donc ne peut être effectué:

if (errno == EXDEV) {
    struct statfs sfs;
    char path[PATH_MAX];

    /* Impossible de mv(1) un point de montage. */
    if (realpath(from, path) == NULL) {
        warnx("ne peut pas résoudre %s: %s", from, path);
        return (1);
    }
    if (!statfs(path, &sfs) && !strcmp(path, sfs.f_mntonname)) {
        warnx("impossible de renommer un point de montage");
        return (1);
    }
} else {
    warn("renommage %s en %s", from, to);
    return (1);
}

Remarquez ici que ce code interrompt le déplacement si la source contient des liens symboliques non résolus, ou si c'est en fait un point de montage - et également généralement si le rename() échoue pour d'autres raisons que EXDEV.

Seulement dans le cas où rename() échoue avec le numéro d'erreur EXDEV, et non pour les raisons mentionnées ci-dessus, le code suivant est exécuté:

/*
 * Si le renommage échoue parce que nous tentons de traverser des périphériques, et
 * qu'il s'agit d'un fichier régulier, effectuez la copie en interne ; sinon, utilisez
 * cp et rm.
 */
if (lstat(from, &sb)) {
    warn("%s", from);
    return (1);
}
return (S_ISREG(sb.st_mode) ?
    fastcopy(from, to, &sb) : copy(from, to));

Ce code se ramifie pour effectuer le déplacement entre les systèmes de fichiers de deux manières différentes selon que la source à déplacer est effectivement un fichier régulier - ou autre chose. "Autre chose" est généralement un répertoire, un lien symbolique, un nœud de périphérique ou similaire.

Dans le cas d'un fichier régulier, il utilise fastcopy() qui ouvre simplement les fichiers source et destination, lit les données du source grâce à read() et les écrit à la destination grâce à write(). Contrairement à la version FreeBSD, la fonction fastcopy() utilise fcopyfile() pour copier les ACL et les attributs étendus du source à la destination.

Dans le cas de quelque chose qui n'est pas un fichier régulier, il invoque simplement des commandes externes pour effectuer le déplacement: cp pour copier et rm pour supprimer.

0 votes

Voici une réponse plus verbeuse mais beaucoup plus descriptive que la réponse actuellement la mieux notée. D'après ta description, il semble que la réponse simple à la question de OP est oui, lorsque vous travaillez avec des déplacements entre appareils mv copie d'abord le fichier source puis le supprime.

LesApples.com

LesApples est une communauté de Apple où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres utilisateurs d'appareils Apple, poser vos propres questions ou résoudre celles des autres.

Powered by:

X