Pourquoi est-ce '.' un lien dur sous Unix?

51

J'ai vu de nombreuses explications pour expliquer pourquoi le nombre de liens pour un répertoire vide dans les systèmes d'exploitation Unix est égal à 2 au lieu de 1. Ils disent tous que c'est à cause du '.' répertoire, que chaque répertoire a pointant sur lui-même. Je comprends pourquoi avoir un concept de '.' est utile pour spécifier des chemins relatifs, mais que gagne-t-il en l'implémentant au niveau du système de fichiers? Pourquoi ne pas simplement faire en sorte que les shells ou les appels système prenant des chemins sachent l’interpréter?

Le fait que '..' soit un lien réel est beaucoup plus logique pour moi - le système de fichiers doit stocker un pointeur dans le répertoire parent pour pouvoir y accéder. Mais je ne vois pas pourquoi. être un vrai lien est nécessaire. Il semble également que cela conduise à un cas particulier déplorable dans la mise en œuvre - vous pourriez penser que vous ne pouvez libérer que l'espace utilisé par les inodes dont le nombre de liens est inférieur à 1, mais si ce sont des répertoires, vous devez vérifier un lien compte moins de 2. Pourquoi cette incohérence?

Joseph Garvin
la source
1
Une fois que vous avez les ..liens durs, votre logiciel de navigation dans l'arborescence doit déjà comporter une exception "ne suit pas les cycles sur le lien de répertoire parent" , ce qui en fait une complexité supplémentaire, à l'exception du .lien également.
dmckee

Réponses:

37

Une question intéressante, en effet. À première vue, je vois les avantages suivants:

Tout d’abord, vous indiquez que l’interprétation " ." comme répertoire actuel peut être effectuée par le shell ou par des appels système. Cependant, le fait d'avoir une entrée de points dans le répertoire supprime réellement cette nécessité et force la cohérence à un niveau même inférieur.

Mais je ne pense pas que ce soit l’idée de base de cette décision de conception.

Lorsqu'un fichier est créé ou supprimé d'un répertoire, l'horodatage de modification du répertoire doit également être mis à jour. Cet horodatage est stocké dans son inode. Le numéro d'inode est stocké dans l'entrée de répertoire correspondante.

SI l'entrée de point ne serait pas là, les routines devraient rechercher le numéro d'inode à l'entrée de ce répertoire dans le répertoire parent, ce qui provoquerait une nouvelle recherche dans le répertoire.

MAIS heureusement, il y a une entrée de points dans le répertoire actuel. La routine qui ajoute ou supprime un fichier dans le répertoire en cours doit simplement retourner à la première entrée (où réside habituellement l'entrée de point) et a immédiatement trouvé le numéro d'inode du répertoire en cours.

Il y a une troisième bonne chose à propos de l'entrée de point:

Lorsque fsckvérifie un système de fichiers pourri et doit traiter des blocs non connectés qui ne figurent pas non plus sur la liste libre, il est facile pour lui de vérifier si un bloc de données (lorsqu'il est interprété comme une liste de répertoires) a une entrée point qui pointe vers un inode qui pointe à son tour vers ce bloc de données. Si tel est le cas, ce bloc de données peut être considéré comme un répertoire perdu devant être reconnecté.

ktf
la source
Réponse très utile.
Navaneeth KN
6
Le commentaire sur les routines recherchant l'inode du répertoire est faux. Les routines du noyau n'ont pas besoin de chercher .dans le répertoire en cours. À moins que vous ne trouviez un noyau où cela fonctionne réellement (j'en doute ...)
Dietrich Epp
1
Je suis d'accord avec @DietrichEpp; pour le système à la recherche sur les entrées du répertoire en premier lieu , il faut déjà savoir sur le inode - parce que c'est la façon dont il obtient des blocs de données contenant les entrées du répertoire.
Lqueryvg
10

(Hmm: ce qui suit est maintenant un peu une épopée ...)

La conception du répertoire sur les systèmes de fichiers Unix (qui, pour être pédant, sont généralement, mais pas nécessairement, rattachés à des systèmes d’exploitation Unix) représente un excellent aperçu, qui réduit en réalité le nombre de cas spéciaux requis.

Un "répertoire" n'est en réalité qu'un fichier du système de fichiers. Tout le contenu réel des fichiers du système de fichiers est en inodes (d'après votre question, je constate que vous connaissez déjà certains de ces éléments). Les inodes sur le disque ne sont pas structurés - ils ne sont que de nombreux blocs d'octets numérotés, répartis comme du beurre d'arachide sur le disque. Ce n'est pas utile, et en effet est répugnant pour toute personne avec un soupçon d'esprit rangé.

Le seul inode spécial est l'inode numéro 2 (et non 0 ou 1, pour des raisons de tradition); inode 2 est un fichier de répertoire: le répertoire racine . Lorsque le système monte le système de fichiers, il "sait" qu'il doit lire l'inode 2 pour se lancer.

Un fichier de répertoire est juste un fichier, avec une structure interne destinée à être lue par opendir (3) et ses amis. Vous pouvez voir sa structure interne documentée dans dir (5) (selon votre système d'exploitation); Si vous regardez cela, vous verrez que l'entrée du fichier de répertoire ne contient presque aucune information sur le fichier - c'est tout dans l'inode du fichier. Une des rares particularités de ce fichier est que la fonction open (2) génère une erreur si vous essayez d'ouvrir un fichier de répertoire avec un mode permettant l'écriture. Diverses autres commandes (pour ne citer qu'un exemple hexdump) refuseront d'agir normalement avec les fichiers de répertoires, simplement parce que ce n'est probablement pas ce que vous voulez faire (mais c'est leur cas particulier, pas le système de fichiers).

Un lien physique n'est ni plus ni moins qu'une entrée dans la carte d'un fichier de répertoire. Vous pouvez avoir deux entrées (ou plus) dans une telle carte qui correspondent toutes deux au même numéro d'inode: cet inode a donc deux (ou plus) liens physiques. Cela explique également pourquoi chaque fichier contient au moins un "lien dur". L'inode a un nombre de références, qui enregistre le nombre de fois où il est mentionné dans un fichier de répertoire quelque part dans le système de fichiers (il s'agit du nombre que vous voyez lorsque vous le faites ls -l).

OK: nous arrivons au point maintenant.

Le fichier de répertoire est une carte de chaînes ("noms de fichiers") en nombres (numéros d'inode). Ces numéros d'inodes sont les numéros des inodes des fichiers qui sont 'dans' ce répertoire. Les fichiers qui sont 'dans' ce répertoire peuvent inclure d'autres fichiers de répertoire, ainsi leurs numéros d'inode figureront parmi ceux répertoriés dans le répertoire. Ainsi, si vous avez un fichier /tmp/foo/bar, le fichier de répertoire fooinclut une entrée pour barmapper cette chaîne sur l'inode de ce fichier. Il y a aussi une entrée dans le fichier de répertoire /tmp, pour le fichier de répertoire fooqui est 'dans' le répertoire /tmp.

Lorsque vous créez un répertoire avec mkdir (2), cette fonction

  1. crée un fichier de répertoire (avec un certain numéro d'inode) avec la structure interne correcte,
  2. ajoute une entrée dans le répertoire parent, mappant le nom du nouveau répertoire sur ce nouvel inode (qui représente l'un des liens),
  3. ajoute une entrée au nouveau répertoire en mappant la chaîne '.' au même inode (cela représente l'autre lien), et
  4. ajoute une autre entrée dans le nouveau répertoire, en mappant la chaîne '..' avec l'inode du fichier de répertoire modifié à l'étape (2) (cela représente le plus grand nombre de liens physiques que vous verrez sur les fichiers de répertoires contenant des sous-répertoires )

Le résultat final est que (presque) les seuls cas spéciaux sont:

  • La fonction open (2) essaie de rendre plus difficile de se tirer dans le pied en vous empêchant d'ouvrir des fichiers de répertoire pour l'écriture.
  • La fonction mkdir (2) facilite les choses en ajoutant quelques entrées supplémentaires ('.' Et '..') au nouveau fichier de répertoire, uniquement pour faciliter le déplacement dans le système de fichiers. Je soupçonne que le système de fichiers fonctionnerait parfaitement bien sans '.' et '..', mais serait une douleur à utiliser.
  • Le fichier de répertoire est l’un des rares types de fichiers marqués «spécial» - c’est vraiment ce qui dit que open (2) se comporte légèrement différemment. Voir st_modedans stat (2).

(copie de la question d'origine de stackoverflow, 2011-10-20)

Norman Gray
la source
1
Vous confondez des blocs avec des inodes. Dans des cas particuliers, pour les fichiers courts, le contenu du fichier peut être à l'intérieur de l'inode, mais il est faux d'affirmer que les inodes sont non structurés. Ils sont très structurés et contiennent presque toutes les métadonnées du fichier, à l'exception des noms de fichiers sous lesquels le fichier peut être trouvé. L'inode contient des pointeurs (directs, indirects, doublement indirects, etc.) vers les blocs sur le disque, où se trouve le contenu du fichier.
Phil P
1
Non, je ne confonds pas les blocs avec les inodes. Les inodes sont une abstraction située au-dessus de blocs, et le but de cette publication était de décrire la relation entre les fichiers et les répertoires et leur contenu: toute la structure du système de fichiers provient des fichiers de répertoires. C'était déjà assez long sans s'embourber dans les implémentations d'inode! (Cela dit, je pourrais éventuellement écrire les deux premiers paragraphes plus clairement). En outre, comme vous le voyez, je déclare explicitement que toutes les informations sur le fichier (à l'exception de son nom) se trouvent dans l'inode et non dans le fichier de répertoire.
Norman Gray
@ NormanGray: Même si vous vous défendez, vous vous tirez une balle dans le pied. Vous avez dit: "Tout le contenu réel des fichiers du système de fichiers est en inodes ...". C'est faux.  Les propriétés / attributs d'un fichier (propriétaire, autorisations, date de modification, etc.) sont stockés dans l'inode. Le contenu d'un fichier ordinaire est stocké dans des blocs de données. Si vous ne voulez pas vous perdre dans les implémentations d'inodes, ne le faites pas, mais s'il vous plait, évitez les simplifications excessives.
G-Man dit 'Réintégrez Monica' le