Co to są katalogi, jeśli wszystko w systemie Linux jest plikiem?

17

Bardzo często początkujący słyszą zwrot „Wszystko w systemie Linux / Unix”. Jakie są zatem katalogi? Czym różnią się od plików?

Sergiy Kolodyazhnyy
źródło

Odpowiedzi:

22

Uwaga: pierwotnie zostało to napisane na poparcie mojej odpowiedzi na pytanie: Dlaczego bieżący katalog w lspoleceniu jest zidentyfikowany jako powiązany z samym sobą? ale czułem, że jest to temat, który zasługuje na samodzielne podejście, i stąd te pytania i odpowiedzi .

Zrozumienie systemu plików i systemów Unix / Linux: Wszystko jest i-węzłem

Zasadniczo katalog to tylko specjalny plik, który zawiera listę wpisów i ich identyfikatory.

Przed rozpoczęciem dyskusji ważne jest, aby wprowadzić rozróżnienie między kilkoma terminami i zrozumieć, co tak naprawdę reprezentują katalogi i pliki. Być może słyszałeś wyrażenie „Wszystko jest plikiem” dla Unix / Linux. Cóż, użytkownicy często rozumieją jako plik: /etc/passwd- Obiekt ze ścieżką i nazwą. W rzeczywistości nazwa (czy to katalog, plik, czy cokolwiek innego) to tylko ciąg tekstowy - właściwość rzeczywistego obiektu. Ten obiekt nazywa się i- węzłem lub numerem I i jest przechowywany na dysku w tabeli i-węzłów. Otwarte programy również mają tabele i-węzłów, ale na razie nie jest to naszym celem.

Uniksowe pojęcie katalogu jest takie, jak ujął to Ken Thompson w wywiadzie z 1989 roku :

... A potem niektóre z tych plików były katalogami, które właśnie zawierały nazwę i numer I.

Interesująca obserwacja może być wykonana z talk Dennisa Ritchiego w 1972 roku , że

„... katalog jest w rzeczywistości niczym więcej niż plikiem, ale jego zawartość jest kontrolowana przez system, a zawartość to nazwy innych plików. (W innych systemach katalog jest czasem nazywany katalogiem).”

... ale w rozmowie nie ma wzmianki o i-węzłach. Jednak instrukcja 1971 o format of directoriesstanach:

O tym, że plik jest katalogiem, wskazuje nieco słowo flagowe wpisu i-węzła.

Wpisy w katalogu mają długość 10 bajtów. Pierwsze słowo to i-węzeł pliku reprezentowany przez wpis, jeśli niezerowy; jeśli zero, wpis jest pusty.

Tak było od początku.

Parowanie katalogów i i-węzłów wyjaśniono również w rozdziale Jak przechowywane są struktury katalogów w systemie plików UNIX? . sam katalog jest strukturą danych, a dokładniej: listą obiektów (plików i numerów i-węzłów) wskazujących na listy o tych obiektach (uprawnienia, typ, właściciel, rozmiar itp.). Tak więc każdy katalog zawiera swój własny numer i-węzła, a następnie nazwy plików i ich numery i-węzłów. Najbardziej znana jest i- węzeł nr 2, który jest /katalogiem . (Uwaga, chociaż /devi /runto wirtualne systemy plików, ponieważ są one tak korzeń ich foldery plików, mają też 2-węzeł; tzn. i-węzeł jest unikalny w swoim własnym systemie plików, ale z dołączonymi wieloma systemami plików masz nie-unikalne i-węzły). schemat zapożyczony z połączonego pytania prawdopodobnie wyjaśnia go bardziej zwięźle:

Directory-iNode-Block

Wszystkie te informacje przechowywane w i-węźle są dostępne za pośrednictwem stat()wywołań systemowych, zgodnie z Linuksem man 7 inode:

Każdy plik ma i-węzeł zawierający metadane dotyczące pliku. Aplikacja może odzyskać te metadane przy użyciu stat (2) (lub powiązanych wywołań), które zwraca strukturę stat, lub statx (2), która zwraca strukturę statx.

Czy to możliwe, aby uzyskać dostęp do pliku tylko znając jego numer i-węzła ( REF1 , REF2 )? W niektórych implementacjach Uniksa jest to możliwe, ale omija sprawdzanie uprawnień i dostępu, więc w Linuksie nie jest zaimplementowane i musisz przejść przez drzewo systemu plików ( find <DIR> -inum 1234na przykład), aby uzyskać nazwę pliku i odpowiadający mu i-węzeł.

Na poziomie kodu źródłowego jest on zdefiniowany w źródle jądra Linux i jest również adoptowany przez wiele systemów plików, które działają w systemach operacyjnych Unix / Linux, w tym systemy plików ext3 i ext4 (domyślnie Ubuntu). Ciekawe: ponieważ dane są tylko blokami informacji, Linux faktycznie ma funkcję inode_init_always, która może określić, czy i-węzeł jest potokiem ( inode->i_pipe). Tak, gniazda i potoki są technicznie także plikami - plikami anonimowymi, które mogą nie mieć nazwy pliku na dysku. FIFO i gniazda domeny Unix mają nazwy plików w systemie plików.

Same dane mogą być unikalne, ale numery i-węzłów nie są unikalne. Jeśli mamy twardy link do foo o nazwie foobar, będzie to wskazywać również na i-węzeł 123. Sam ten i-węzeł zawiera informacje o tym, jakie rzeczywiste bloki miejsca na dysku są zajęte przez ten i-węzeł. I technicznie jest to sposób na .połączenie z nazwą pliku katalogu. Cóż, prawie: nie można samodzielnie tworzyć twardych dowiązań do katalogów w systemie Linux , ale systemy plików mogą zezwalać na dowiązania twarde do katalogów w bardzo zdyscyplinowany sposób, co stanowi ograniczenie posiadania tylko .i ..jako twardych dowiązań.

Drzewo katalogów

Systemy plików implementują drzewo katalogów jako jedną z drzewiastych struktur danych. W szczególności,

  • ext3 i ext4 używają HTree
  • xfs używa drzewa B +
  • ZFS używa drzewa skrótu

Kluczową kwestią jest to, że same katalogi są węzłami w drzewie, a podkatalogi są węzłami potomnymi, przy czym każde dziecko ma łącze z powrotem do węzła nadrzędnego. Zatem dla łącza do katalogu liczba i-węzłów wynosi co najmniej 2 dla /home/example/samego katalogu (link do nazwy katalogu i link do siebie /home/example/.), a każdy dodatkowy podkatalog jest dodatkowym łączem / węzłem:

# new directory has link count of 2
$ stat --format=%h .
2
# Adding subdirectories increases link count
$ mkdir subdir1
$ stat --format=%h .
3
$ mkdir subdir2
$ stat --format=%h .
4
# Count of links for root
$ stat --format=%h /
25
# Count of subdirectories, minus .
$ find / -maxdepth 1 -type d | wc -l
24

Schemat znajdujący się na stronie kursu Iana D. Allena pokazuje uproszczony bardzo jasny schemat:

WRONG - names on things      RIGHT - names above things
=======================      ==========================

    R O O T            --->         [etc,bin,home]   <-- ROOT directory
   /   |   \                         /    |      \
etc   bin   home       --->  [passwd]  [ls,rm]  [abcd0001]
 |   /   \    \                 |      /    \       |
 |  ls   rm  abcd0001  --->     |  <data>  <data>  [.bashrc]
 |               |              |                   |
passwd       .bashrc   --->  <data>                <data>

Jedyne, co na diagramie PRAWY jest niepoprawne, to fakt, że technicznie nie uważa się, że pliki znajdują się w samym drzewie katalogów: dodanie pliku nie ma wpływu na liczbę łączy:

$ mkdir subdir2
$ stat --format=%h .
4
# Adding files doesn't make difference
$ cp /etc/passwd passwd.copy
$ stat --format=%h .
4

Dostęp do katalogów tak, jakby były plikami

Cytując Linusa Torvaldsa :

Chodzi o to, że „wszystko jest plikiem” nie polega na tym, że masz jakąś losową nazwę pliku (w rzeczywistości gniazda i potoki pokazują, że „plik” i „nazwa pliku” nie mają ze sobą nic wspólnego), ale fakt, że możesz używać wspólnego narzędzia do obsługi różnych rzeczy.

Biorąc pod uwagę, że katalog jest tylko specjalnym przypadkiem pliku, oczywiście muszą istnieć interfejsy API, które pozwalają nam otwierać / odczytywać / zapisywać / zamykać je w podobny sposób jak zwykłe pliki.

Tam właśnie dirent.hpojawia się biblioteka C, która określa direntstrukturę, którą można znaleźć w readdir man 3 :

   struct dirent {
       ino_t          d_ino;       /* Inode number */
       off_t          d_off;       /* Not an offset; see below */
       unsigned short d_reclen;    /* Length of this record */
       unsigned char  d_type;      /* Type of file; not supported
                                      by all filesystem types */
       char           d_name[256]; /* Null-terminated filename */
   };

Dlatego w kodzie C musisz zdefiniować struct dirent *entry_p, a kiedy otworzymy katalog opendir()i zaczniemy go czytać readdir(), będziemy przechowywać każdy element w tej entry_pstrukturze. Oczywiście każdy element będzie zawierał pola zdefiniowane w szablonie dla direntpokazanego powyżej.

Praktyczny przykład tego, jak to działa, można znaleźć w mojej odpowiedzi na temat wyświetlania plików i ich numerów i-węzłów w bieżącym katalogu roboczym .

Zauważ, że instrukcja POSIX na fdopen stwierdza, że ​​„wpisy katalogu dla kropki i kropki są opcjonalne”, a stany instrukcji readdir struct dirent są wymagane tylko d_namei d_inopola.

Uwaga na temat „zapisywania” do katalogów: zapisywanie do katalogu modyfikuje jego „listę” wpisów. Dlatego tworzenie lub usuwanie pliku jest bezpośrednio związane z uprawnieniami do zapisu w katalogu , a dodawanie / usuwanie plików jest operacją zapisu w tym katalogu.

Sergiy Kolodyazhnyy
źródło
2
Odmawiam akceptowania gniazd to pliki;) Czy „wszystko jest dostępne jako plik” byłoby bardziej dokładne?
Rinzwind,
@Rinzwind Cóż, wyrażenie „wszystko jest dostępne jako plik” jest dokładne. Zwykłe pliki mają open()i read()gniazda mają connect()i read()też. Bardziej dokładne byłoby to, że „plik” to tak naprawdę zorganizowane „dane” przechowywane na dysku lub w pamięci, a niektóre pliki są anonimowe - nie mają nazwy pliku. Zwykle użytkownicy myślą o plikach w kategoriach tej ikony na pulpicie, ale to nie jedyna rzecz, która istnieje. Zobacz także unix.stackexchange.com/a/116616/85039
Sergiy Kolodyazhnyy
Pytanie dotyczyło raczej tego, czy katalog jest plikiem. I to jest. Gniazda mogą być prawie osobnym pytaniem wraz z nazwanymi rurami FIFO.
WinEunuuchs2Unix,
Cóż, do tej pory otrzymałem odpowiedź na temat rur: askubuntu.com/a/1074550/295286 Może FIFO będą następne
Sergiy Kolodyazhnyy