GNU/Linux >> Tutoriels Linux >  >> Linux

Sous Linux, que se passe-t-il si 1000 fichiers d'un répertoire sont déplacés vers un autre emplacement alors que 300 autres fichiers ont été ajoutés au répertoire source ?

Cela dépend des outils que vous utilisez :vérifions quelques cas :

Si vous exécutez quelque chose dans le sens de mv /path/to/source/* /path/to/dest/ Dans un shell, vous vous retrouverez avec les 1000 fichiers originaux déplacés, les 300 nouveaux étant intacts. Cela vient du fait que le shell étendra le * avant de commencer l'opération de déplacement, donc lorsque le déplacement est en cours, la liste est déjà fixée.

Si vous utilisez Nautilus (et d'autres amis de l'interface graphique), vous vous retrouverez de la même manière :il exécutera l'opération de déplacement en fonction des fichiers sélectionnés - cela ne change pas lorsque de nouveaux fichiers apparaissent.

Si vous utilisez votre propre programme en utilisant des appels système le long de la ligne de boucle sur glob et seulement un mv jusqu'au glob reste vide, vous vous retrouverez avec les 1300 fichiers dans le nouveau répertoire. C'est parce que chaque nouveau glob récupérera les nouveaux fichiers qui sont apparus entre-temps.


Lorsque vous dites au système de déplacer tous les fichiers d'un répertoire, il répertorie tous les fichiers, puis commence à les déplacer. Si de nouveaux fichiers apparaissent dans le répertoire, ils ne sont pas ajoutés à la liste des fichiers à déplacer, ils resteront donc à l'emplacement d'origine.

Vous pouvez, bien sûr, programmer une manière de déplacer les fichiers différente de mv qui vérifiera périodiquement les nouveaux fichiers dans le répertoire source.


Le noyau lui-même ne peut pas être "au milieu" d'une opération "déplacer 1000 fichiers". Vous devez être beaucoup plus précis sur l'opération que vous proposez.

Un thread ne peut déplacer qu'un seul fichier à la fois avec le rename(*oldpath, const char *newpath) ou renameat appels système (et uniquement dans le même système de fichiers). Ou Linux renameat2 qui a des drapeaux comme RENAME_EXCHANGE pour échanger atomiquement deux chemins, ou RENAME_NOREPLACE à pas remplacer la destination si elle existe. (par exemple, autoriser un mv -i implémentation qui évite la condition de concurrence de stat puis rename , qui écraserait toujours un fichier créé après stat .link + unlink pourrait également résoudre ce problème, car link échoue si le nouveau nom existe.)

Mais chacun de ces appels système ne renomme qu'une seule entrée de répertoire par appel système . Utilisation de POSIX renameat avec olddirfd et newdirfd (ouvert avec open(O_DIRECTORY) ) vous permettrait de continuer à parcourir les fichiers d'un répertoire même si le répertoire source ou de destination lui-même avait été renommé. (L'utilisation de chemins relatifs pourrait également permettre cela avec le rename() normal .)

Quoi qu'il en soit, comme le disent les autres réponses, la plupart des programmes qui utilisent l'appel système rename trouveront une liste de noms de fichiers avant de faire le premier rename . (Généralement en utilisant le readdir(3) La bibliothèque POSIX fonctionne comme un wrapper pour les appels système spécifiques à la plate-forme comme Linux getdents ).

Mais si vous parlez de find -exec ... {} \; pour exécuter une commande par fichier, ou le plus efficace -exec {} + avec tant de fichiers qu'ils ne tiennent pas sur une seule ligne de commande, vous pouvez certainement renommer tout en scannant. ex.

find . -name '*.txt' -exec mv -t ../txtfiles {} \;   # Intentionally inefficient

Si vous avez créé un nouveau .txt fichiers pendant que cela fonctionnait, vous pourriez voir certains d'entre eux en ../txtfiles . Mais en interne find(1) aura utilisé open(O_DIRECTORY) et getdents sur . .

Si un seul appel système suffisait à renvoyer tous les entrées du répertoire en . (qui find bouclera sur un à la fois, ne faisant d'autres appels système que si nécessaire pour -type ou pour récurser, ou fork+exec sur une correspondance), alors la liste est un instantané des entrées du répertoire à un moment donné. D'autres modifications apportées au répertoire ne peuvent pas affecter ce que find fait, car il a déjà une copie du répertoire listant ce qu'il va boucler. (Il utilise probablement en interne readdir(3) , qui renvoie une entrée à la fois, mais à l'intérieur de la glibc, nous savons en utilisant strace find . qu'il fait un getdents64 appel système avec une taille de tampon de count=32768 entrées.)

Mais si le répertoire est énorme et/ou le noyau ne remplit pas find 's buffer, il devra faire un deuxième appel système getdents après avoir bouclé sur ce qu'il a obtenu la première fois. Donc, il pourrait peut-être voir de nouvelles entrées après avoir fait quelques changements de nom.

Mais voir la discussion dans les commentaires sous d'autres réponses :le noyau a peut-être pris un instantané pour nous, car (je pense) que getdents n'est pas autorisé à renvoyer deux fois le même nom de fichier. Différents systèmes de fichiers utilisent différents mécanismes de tri / indexation pour rendre l'accès à une entrée dans un énorme répertoire plus efficace qu'une recherche linéaire. Ainsi, l'ajout ou la suppression d'un répertoire peut éventuellement avoir d'autres effets sur l'ordre des entrées restantes. Hmm, il est probablement plus probable que les systèmes de fichiers conservent un ordre stable et mettent simplement à jour un index réel (comme le EXT4 dir_index fonctionnalité), donc la position d'un répertoire FD peut simplement être une entrée de répertoire à partir de laquelle reprendre ? Je ne sais vraiment pas comment le telldir(3) l'interface de la bibliothèque correspond à lseek , ou si c'est purement une chose de l'espace utilisateur pour boucler sur le tampon obtenu par l'espace utilisateur. Mais plusieurs getdents peut être nécessaire pour obtenir toutes les entrées d'un énorme répertoire, donc même si la recherche n'est pas prise en charge, le noyau doit être capable d'enregistrer une position actuelle.

Note de bas de page 1 :

Pour "se déplacer" entre les systèmes de fichiers, c'est à l'espace utilisateur de copier et de dissocier. (par exemple avec open et soit read+write , mmap+write ou sendfile(2) ou copy_file_range(2) , les deux derniers évitant totalement de faire rebondir les données du fichier dans l'espace utilisateur.)


Linux
  1. Quels sont les différents types de shells sous Linux ?

  2. Que sont les fichiers fragmentés sous Linux

  3. Quelles devraient être les autorisations idéales pour le répertoire personnel sous Linux

  4. Quelles sont les différentes façons de définir les autorisations de fichiers, etc. sur gnu/linux

  5. Hiérarchie des fichiers Linux - quel est le meilleur emplacement pour stocker les fichiers de verrouillage ?

Chemin absolu ou relatif sous Linux :quelle est la différence ?

Quelles sont les différences entre les fichiers Linux et Windows .txt (encodage Unicode)

Où est le répertoire temporaire sous Linux ?

Quel est le moyen le plus rapide de déplacer un million d'images d'un répertoire à un autre sous Linux ?

Quel est l'équivalent d'Active Directory sous Linux

Que sont exactement les en-têtes du noyau Linux ?