Erreur `ls` lorsque le répertoire est supprimé

13

J'ai deux obus ouverts. Le premier se trouve dans le répertoire A. Dans le second, je supprime le répertoire A, puis le recrée. Quand je reviens au premier shell et que je tape ls, la sortie est:

ls: cannot open directory .: Stale file handle

Pourquoi? Je pensais que le premier shell (celui qui restait ouvert dans un répertoire inexistant) "se bloquerait" en attendant la prochaine commande, et n'aurait pas "réalisé" que le répertoire a été supprimé et recréé. Le shell contient-il une référence "plus profonde" à son répertoire de travail actuel autre que la chaîne $PWD?

fonini
la source
2
Une non-réponse, mais si vous souhaitez simplement que votre coquille retombe sur ses pieds, vous pouvez courir cd $PWD.
dhag
J'aimerais comprendre ce qui se passe, je sais qu'il est facile de récupérer la coque :)
fonini
Ce répertoire est-il sur un serveur NFS? Je pense que c'est la seule situation où vous obtenez des poignées de fichier périmées.
Barmar
Le répertoire est local. Lorsque vous faites cela dans votre système, le résultat est différent?
fonini

Réponses:

17

Un répertoire (comme tout fichier) n'est pas défini par son nom. Considérez le nom comme l' adresse du répertoire . Lorsque vous déplacez le répertoire, c'est toujours le même répertoire, tout comme si vous déménagez dans une autre maison, vous êtes toujours la même personne. Si vous supprimez un répertoire et en créez un nouveau du même nom, c'est un nouveau répertoire, tout comme quelqu'un qui s'installe dans la maison où vous habitiez n'est pas vous.

Chaque processus a un répertoire de travail . La cdcommande dans le shell modifie le répertoire de travail actuel du shell. La pwdcommande imprime le chemin¹ vers le répertoire de travail actuel.

Lorsque vous avez supprimé le répertoire A, cela a entraîné la suppression de l'entrée pour A dans son répertoire parent. Le répertoire A lui-même est resté dans le système de fichiers, mais dans un état détaché, sans nom. Il n'a pas encore été supprimé car il était utilisé par un processus, à savoir le premier shell. Lorsque vous avez modifié le répertoire dans le premier shell, le répertoire a finalement été supprimé. La même chose se produit lorsqu'un fichier est supprimé alors qu'un processus est toujours ouvert: l'entrée de répertoire du fichier est supprimée immédiatement et le fichier lui-même est supprimé lorsqu'il cesse d'être utilisé.

De même, observez ce qui se passe lorsque vous déplacez des répertoires.

mkdir one two
touch one/1 two/2
cd one
ls

Dans un autre shell:

mv one tmp
mv two one
mv tmp two

Dans le premier shell:

ls

Le fichier se 1trouve dans le répertoire qui était à l'origine appelé oneet s'appelle maintenant two. Le fichier se 2trouve dans le répertoire qui était à l'origine appelé twoet s'appelle maintenant one.

¹ Plus précisément, un chemin, qui peut ne pas être unique si des liens symboliques ou d'autres subtilités sont impliqués.

Gilles 'SO- arrête d'être méchant'
la source
Donc, le point clé ici est qu'un processus contient l'inode de son répertoire de travail, pas seulement le chemin?
Nacht - Rétablir Monica
1
@Nacht Le processus contient un descripteur, mais le noyau fait tout le mappage (descripteur / entrées des tables de fichiers / inode). Et en effet, en interne, le noyau ne stocke pas les chemins (car les choses intéressantes sont dans l'inode, pas dans le chemin). De plus, un "chemin" n'est qu'un lien vers un fichier ... il peut y en avoir plusieurs :)
John WH Smith
oh à droite, il contient un descripteur. alors bash contient constamment un fd du répertoire de travail? tous les processus n'ont sûrement pas les fds du répertoire de travail ... Je pensais que je me souvenais des fds commençant à la valeur 3 après stdin / out / err
Nacht - Reinstate Monica
2
@Nacht Le répertoire actuel n'est pas un descripteur de fichier, mais il fonctionne un peu comme un. Le noyau maintient cela pour chaque processus. Sous Linux, vous pouvez le voir dans /proc/<pid>/cwd, qui fonctionne comme /proc/<pid>/fd/<number>. C'est CWDdans la sortie de lsof.
Gilles 'SO- arrête d'être méchant'
il est possible de faire automatique cd - && cd -dans ce cas?
Vitaly Zdanevich
8

Le nouveau répertoire A n'est pas le même que le répertoire A. Il peut être vérifié avec la statcommande avant de supprimer l'ancien et après en avoir créé un nouveau et vous verrez différents numéros d'i-node.
Et je pense que cela est lié au fonctionnement du noyau. Il garde simplement une trace du numéro i du répertoire courant pour chaque processus. Donc, comme il existe différents nombres i, cela entraînera des collisions différentes.

taliezin
la source
Il convient de noter qu'un inode est une structure et non un numéro unique. Il peut être identifié de manière unique, mais il contient plus d'informations que son ID. C'est ce qui le rend plus important que les liens.
John WH Smith
1
@JohnWHSmith Je vais supprimer cette réponse car Gilles one is better.
taliezin
6
Ce n'est pas une raison pour supprimer le vôtre! Si vous pensez de cette façon, vous pouvez simplement ajouter un avertissement à votre réponse expliquant que vous considérez l'autre mieux.
terdon
7

Il s'agit d'un comportement attendu. Le nouveau répertoire A n'est pas le même que l'ancien répertoire A, il se trouve qu'il porte le même nom. Donc, le $ PWD du premier terminal est toujours parti, il n'a pas réapparu comme par magie quand vous avez fait le mkdir A.

John
la source
2
pourriez-vous élaborer sur «le nouveau répertoire A n'est pas le même que l'ancien répertoire A». Quels aspects du fichier / répertoire changent? Cela a-t-il à voir avec le numéro d'inode? Désolé de demander, mais j'apprends juste à ce sujet.
rahul
2
@rahul Philosophiquement, ce qui change, c'est son identité - un nouveau répertoire a été créé à partir de rien au même endroit. Au niveau de l'implémentation, oui, tous les fichiers ouverts sont identifiés par inode, et les anciens et nouveaux répertoires auront des inodes distincts avec des numéros d'inode différents.
Hobbs
0

Un répertoire, comme un fichier, est associé à un inode:

307% mkdir ABC

308% ls -i 11997708 A 11997709 B 11997710 C

Un inode est une structure de données qui contient des informations sur le répertoire ou le fichier. Chaque répertoire et fichier en a un. Considérez-le comme une adresse (un numéro d'index vraiment).

Si je suis dans A, numéro d'inode 11997708 et dans un autre shell (ou dans le même shell que je vais faire), supprimez le répertoire A puis recréez-le et ls l'inode:

309% cd A

310% rmdir ../A

311% mkdir ../A

312% ls -i ..

11997720 A 11997709 B 11997710 C

Le nœud i est différent, donc s'il essaie de créer un fichier dans le répertoire supprimé A:

313% le touchent

toucher: ne peut pas toucher «ceci»: aucun fichier ou répertoire de ce type

parce que le répertoire dans lequel je suis - n'est plus associé à l'inode 11997720 - donc là où je suis actuellement n'a plus d'adresse / d'index légitime - inode. D'où l'erreur.

user2592248
la source