GNU/Linux >> Tutoriels Linux >  >> Linux

Comment Unix garde-t-il une trace du répertoire de travail d'un utilisateur lors de la navigation dans le système de fichiers ?

Supposons que je me connecte à un shell sur un système Unix et que je commence à taper sur les commandes. Je commence initialement dans le répertoire personnel de mon utilisateur ~ . Je pourrais partir de là cd jusqu'au répertoire Documents .

La commande pour changer de répertoire de travail ici est très simple à comprendre intuitivement :le nœud parent a une liste de nœuds enfants auxquels il peut accéder, et il utilise probablement une variante (optimisée) d'une recherche pour localiser l'existence d'un nœud enfant avec le nom de l'utilisateur entré, et le répertoire de travail est ensuite "modifié" pour correspondre à cela - corrigez-moi si je me trompe. Il peut même être plus simple que le shell essaie simplement "naïvement" d'essayer d'accéder au répertoire exactement selon les souhaits de l'utilisateur et lorsque le système de fichiers renvoie un type d'erreur, le shell affiche une réponse en conséquence.

Ce qui m'intéresse cependant, c'est comment le même processus fonctionne lorsque je navigue dans un répertoire, c'est-à-dire vers un parent ou le parent d'un parent.

Compte tenu de mon emplacement inconnu, probablement "aveugle" de Documents , l'un des nombreux répertoires de l'arborescence complète du système de fichiers portant ce nom, comment Unix détermine-t-il où je dois être placé ensuite ? Fait-il référence à pwd et examiner cela? Si oui, comment pwd suivre l'état de navigation actuel ?

Réponse acceptée :

Les autres réponses sont des simplifications excessives, chacune ne présentant que des parties de l'histoire, et sont erronées sur quelques points.

Il y en a deux manières dont le répertoire de travail est suivi :

  • Pour chaque processus, dans la structure de données de l'espace noyau qui représente ce processus, le noyau stocke deux références vnode aux vnodes du répertoire de travail et au répertoire racine de ce processus. L'ancienne référence est définie par le chdir() et fchdir() appels système, ces derniers par chroot() . On peut les voir indirectement dans /proc sur les systèmes d'exploitation Linux ou via le fstat commande sur FreeBSD et autres :

    % fstat -p $$|head -n 5
    USER     CMD          PID   FD MOUNT      INUM MODE         SZ|DV R/W
    JdeBP    zsh        92648 text /         24958 -r-xr-xr-x  702360  r
    JdeBP    zsh        92648 ctty /dev        148 crw--w----   pts/4 rw
    JdeBP    zsh        92648   wd /usr/home/JdeBP      4 drwxr-xr-x     124  r
    JdeBP    zsh        92648 root /             4 drwxr-xr-x      35  r
    % 

    Lorsque la résolution de chemin s'opère, elle commence à l'un ou l'autre de ces vnodes référencés, selon que le chemin est relatif ou absolu. (Il existe une famille de …at() appels système qui permettent à la résolution des noms de chemin de commencer au vnode référencé par un descripteur de fichier ouvert (répertoire) comme troisième option.)

    Dans les micro-noyaux Unices, la structure des données se trouve dans l'espace d'application, mais le principe de maintien des références ouvertes à ces répertoires reste le même.

  • En interne, dans des coques telles que les coques Z, Korn, Bourne Again, C et Almquist, la coque en plus assure le suivi du répertoire de travail à l'aide de la manipulation de chaîne d'une variable de chaîne interne. Il le fait chaque fois qu'il doit appeler chdir() .

    Si l'on change pour un chemin d'accès relatif, il manipule la chaîne pour ajouter ce nom. Si l'on change pour un chemin d'accès absolu, il remplace la chaîne par le nouveau nom. Dans les deux cas, il ajuste la chaîne pour supprimer . et .. composants et pour chasser les liens symboliques en les remplaçant par leurs noms liés. (Voici le code du shell Z pour cela, par exemple.)

    Le nom dans la variable de chaîne interne est suivi par une variable shell nommé PWD (ou cwd dans les coques C). Celle-ci est classiquement exportée sous forme de variable d'environnement (nommée PWD ) aux programmes générés par le shell.

Ces deux méthodes de suivi des choses sont révélées par le -P et -L options au cd et pwd commandes intégrées du shell, et par les différences entre les pwd intégrés des shells commandes et les deux /bin/pwd commande et le pwd intégré commandes de choses comme (entre autres) VIM et NeoVIM.

% mkdir a ; ln -s a b
% (cd b; pwd; /bin/pwd; printenv PWD)
/usr/home/JdeBP/b
/usr/home/JdeBP/a
/usr/home/JdeBP/b
% (cd b; pwd -P; /bin/pwd -P)
/usr/home/JdeBP/a
/usr/home/JdeBP/a
% (cd b; pwd -L; /bin/pwd -L)
/usr/home/JdeBP/b
/usr/home/JdeBP/b
% (cd -P b; pwd; /bin/pwd; printenv PWD)
/usr/home/JdeBP/a
/usr/home/JdeBP/a
/usr/home/JdeBP/a
% (cd b; PWD=/hello/there /bin/pwd -L)
/usr/home/JdeBP/a
% 

En relation :Vous recherchez un éditeur de fichiers GUI alternatif avec prise en charge de fichiers volumineux ?

Comme vous pouvez le voir :pour obtenir le répertoire de travail "logique", il suffit de regarder le PWD variable shell (ou variable d'environnement si l'on n'est pas le programme shell); alors que l'obtention du répertoire de travail "physique" revient à appeler le getcwd() fonction de bibliothèque.

Le fonctionnement de /bin/pwd programme lorsque le -L option est utilisée est quelque peu subtile. Il ne peut pas faire confiance la valeur du PWD variable d'environnement dont il a hérité. Après tout, il n'est pas nécessaire qu'il ait été invoqué par un shell et les programmes intermédiaires n'ont peut-être pas implémenté le mécanisme du shell pour créer le PWD La variable d'environnement suit toujours le nom du répertoire de travail. Ou quelqu'un peut faire ce que j'ai fait juste là.

Donc, ce qu'il fait est (comme le dit la norme POSIX) de vérifier que le nom donné dans PWD donne la même chose que le nom . , comme on peut le voir avec une trace d'appel système :

% ln -s a c
% (cd b;  truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd')
stat("/usr/home/JdeBP/b",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0)
stat(".",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0)
/usr/home/JdeBP/b
% (cd b; PWD=/usr/local/etc truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd')
stat("/usr/local/etc",{ mode=drwxr-xr-x ,inode=14835,size=158,blksize=10240 }) = 0 (0x0)
stat(".",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0)
__getcwd("/usr/home/JdeBP/a",1024)       = 0 (0x0)
/usr/home/JdeBP/a
% (cd b; PWD=/hello/there truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd')
stat("/hello/there",0x7fffffffe730)      ERR#2 'No such file or directory'
__getcwd("/usr/home/JdeBP/a",1024)       = 0 (0x0)
/usr/home/JdeBP/a
% (cd b; PWD=/usr/home/JdeBP/c truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd')
stat("/usr/home/JdeBP/c",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0)
stat(".",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0)
/usr/home/JdeBP/c
%

Comme vous pouvez le voir :il n'appelle que getcwd() s'il détecte une non-concordance ; et il peut être trompé en définissant PWD à une chaîne qui nomme bien le même répertoire, mais par une route différente.

Le getcwd() la fonction bibliothèque est un sujet à part entière. Mais pour préciser :

  • À l'origine, il s'agissait purement d'une fonction de bibliothèque, qui construisait un chemin d'accès depuis le répertoire de travail jusqu'à la racine en essayant à plusieurs reprises de rechercher le répertoire de travail dans le .. annuaire. Il s'est arrêté lorsqu'il a atteint une boucle où .. était le même que son répertoire de travail ou lorsqu'il y avait une erreur en essayant d'ouvrir le prochain .. en haut. Ce serait beaucoup d'appels système cachés.
  • Aujourd'hui, la situation est légèrement plus complexe. Sur FreeBSD, par exemple (ceci étant également vrai pour d'autres systèmes d'exploitation), il est un véritable appel système, comme vous pouvez le voir dans la trace des appels système donnée précédemment. Toute la traversée du répertoire de travail vnode jusqu'à la racine est effectuée en un seul appel système, qui tire parti de choses comme l'accès direct du code en mode noyau au cache d'entrée de répertoire pour effectuer les recherches de composants de nom de chemin beaucoup plus efficacement.

    Cependant, notez que même sur FreeBSD et ces autres systèmes d'exploitation, le noyau ne le fait pas garder une trace du répertoire de travail avec une chaîne.

Navigation vers .. redevient un sujet à part entière. Un autre précis :Bien que les annuaires soient conventionnels (bien que, comme nous l'avons déjà mentionné, ce n'est pas obligatoire) contiennent un .. réel dans la structure de données du répertoire sur le disque, le noyau suit lui-même le répertoire parent de chaque vnode de répertoire et peut ainsi naviguer vers le .. vnode de n'importe quel répertoire de travail. Ceci est quelque peu compliqué par le point de montage et les mécanismes racine modifiés, qui sortent du cadre de cette réponse.

À part

Windows NT fait en fait une chose similaire. Il y a un seul répertoire de travail par processus, défini par le SetCurrentDirectory() Appel d'API et suivi par processus par le noyau via un descripteur de fichier ouvert (interne) dans ce répertoire ; et il existe un ensemble de variables d'environnement que les programmes Win32 (pas seulement les interpréteurs de commandes, mais tous programmes Win32) utilisent pour suivre les noms de plusieurs répertoires de travail (un par lecteur), en les ajoutant ou en les écrasant chaque fois qu'ils changent de répertoire.

Connexe :Comment utiliser $ ? et tester pour vérifier la fonction?

Classiquement, contrairement au cas des systèmes d'exploitation Unix et Linux, les programmes Win32 n'affichent pas ces variables d'environnement aux utilisateurs. On peut parfois les voir dans des sous-systèmes de type Unix exécutés sur Windows NT, ainsi qu'en utilisant les interpréteurs de commandes SET commandes d'une manière particulière.

Autres lectures

  • "pwd “. Les spécifications de base du groupe ouvert Numéro 7. IEEE 1003.1:2008. Le groupe ouvert. 2016.
  • "Résolution de nom de chemin". Les spécifications de base du groupe ouvert Numéro 7. IEEE 1003.1:2008. Le groupe ouvert. 2016.
  • https://askubuntu.com/a/636001/43344
  • Comment les fichiers sont-ils ouverts sous Unix ?
  • à quoi sert inode, dans FreeBSD ou Solaris
  • Variable d'environnement étrange !::=::dans Cygwin
  • Pourquoi CDPATH ne fonctionne-t-il pas comme indiqué dans les manuels ?
  • Comment puis-je configurer zsh pour qu'il utilise des chemins physiques ?
  • Aller dans un répertoire lié par un lien

Linux
  1. Comment conserver la propriété et les autorisations de fichiers intactes lors de la copie de fichiers ou de répertoires

  2. Comment trouver le fichier le plus ancien dans une arborescence de répertoires sous Linux

  3. Linux - Comment inspecter les informations de structure de répertoire d'un fichier Unix/linux ?

  4. Comment fonctionne la commande Exit sur un terminal Unix ?

  5. Comment activer l'indexation de fichiers et de répertoires apache sous Linux ou UNIX ?

Comment imprimer le répertoire de travail à l'aide de la commande Linux pwd ?

Comment fonctionne la commande 'ls' sous Linux/Unix ?

comment trouver le propriétaire d'un fichier ou d'un répertoire en python

Comment définir le répertoire de travail du processus parent ?

Comment rediriger la sortie de system() vers un fichier ?

Comment obtenir le répertoire absolu d'un fichier dans bash ?