Dowolny plik w systemie plikow jest opisywany przez nazwe sciezkowa zbudowana za pomoca nazw katalogow oddzielonych "/" i jego nazwy . Poniewaz jadro wewnetrznie posluguje sie iwezlami , konieczne jest przeksztalcanie nazwy sciezkowej w i-wezel . Poczatek przeszukiwania jest latwy do ustalenia , poniewaz rozpoczyna sie ono zawsze od korzenia systemu plikow (gdy sciezka zaczyna sie od znaku "/" )badz od biezacego katalogu procesu (dane na temat korzenia systemu plikowi biezacego katalogu procesu mozna znalezc w u-obszarze procesu .Nie mozna uzywac zmiennej globalnej zawierajacej korzen systemu plikow , gdyz proces funkcja systemowa chroot moze zmienic swoje pojecie korzenia systemu plikow ).
Przy kazdym dostepie do pliku nastepuje przeksztalcanie nazwy sciezkowej w i-wezel . Generalnie odpowiedzialny za to jest algorytm namei , z ktorego korzysta wiekszosc funkcji operujacych na plikach . Jednak niektore funkcje systemowe np. open i write maja wlasne algorytmy przeksztalcajace sciezke w i-wezel . Ja zajme sie ogolnym algorytmem .
Generalnie algorytm namei dziala poslugujac sie roboczymi i-wezlami (pierwszym jest korzen lub aktualny katalog ) wg nastepujacego schematu :
Szczegolnego traktowania wymagaja dowiazania symboliczne (pliki zawierajace nazwy sciezkowe innych plikow). Obsluga ich zajmuje sie funkcja followlink
Funkcja follow_link
DEFINCJA: int follow_link(struct inode * dir, struct inode * inode,
int flag, int mode ,struct inode ** result)
/* dir - i-wezel katalogu
/* inode,mode - i-wezel i typ pliku
WYNIK:0 i wskaznik do iwezla na result w przypadku sukcesu
kod bledu w przypadku porazki
ELOOP ( mozliwosc petli)
ENOENT ( nie istnieje taka pozycja katalogowa )
EIO ( nie mozna wczytac bloku do bufora )
{
if( i-wezel pliku lub katklogu jest rowny null)
{
zwolnij i-wezly pliku i katalogu (iput);
na resinode przypisz null;
return(-ENOENT);
}
if(w iwezlie pliku w strukturze i_op nie jest zdefiniowana funkcja followlink)
/* plik nie jest dowiazaniem symbolicznym */
{
zwolnij i-wezel katalogu ;
na resinode przypisz i-wezel pliku;
return( 0);
}
/* Tu wywolywana jest funkcja ext2_followlink wpisana wpisana w stukturze
i_op w iwezlie pliku , ktorej kod zrodlowy mozna znalezc w pliku
linux/fs/ext2/symlink.c. Dla czytelnosci opis jej umieszczam w opisie glownej funkcji followlink
*/
if(plik nie jest dowiazaniem symbolicznym )
{
zwolnij i-wezel katalogu ;
na resinode przpisz i-wezel pliku;
return(0);
}
if( licznik dowiazan symbolicznych (przechowywany w u-obszarze procesu
- current->link_count) jest wiekszy od 5)
/* Liczenie ilosci dowiazan symbolicznych zapobiega powstawaniu
petli*/
{
zwolnij i-wezel y katalogu i pliku (iput);
return(-ELOOP);
}
if(z plikiem zwiazany jest blok danych)
{
if( nie udalo sie wczytac bloku do bufora)
{
zwolnij i-wezly katalogu i pliku;
return( -EIO);
}
else
na zmienna pomocnicza link przypisz sciezke wczytana z pliku;
}
else
na zmienna link przypisz sciezke wpisana do bloku identyfikacyjnego;
zwieksz licznik dowiazan symbolicznych w u-obszarze;
znajdz i-wezel opisywany przez nazwe sciezkowa wpisana pod zmienna
link wywolujac funkcje open_namei( jedna z wersji funkcji namei);
zmniejsz licznik dowiazan symbolicznych w u_obszarze procesu;
zwolnij i-wezel pliku;
if( z iwezlem zwiazany blok danych )
zwolnij bufor do ktorego wczytano sciezke
}
Tak wiec obsluga dowiazan symbolicznych sprowadza sie do zapoczatkowania przeszukiwania nazwy sciezkowej utworzonej z zawartosci dowiazania symbolicznego. Aby zopobiec zapetleniu sie funkcji , liczy sie dowiazania symboliczne podczas przeszukiwania nazw sciezek i sygnalizuje blad wowczas ' gdy zostanie przekroczona ich gorna granica (5). Jezeli plik nie jest dowiazaniem symbolicznym to followlink zwraca ten plik.
Przed przystapieniem do szczegolowego pisu algorytmu namei zapoznajmy sie wczesniej z pomocnicza funkcja lookup , ktora majac i-wezel katalogu i nazwe pozycji katalogowej znajduje i-wezel tej pozycji.
Funkcja lookup
DEFINICJA: int lookup( struct inode * dir ,const char * name,
int len , struct inode **resinode)
/* dir - i-wezel katalogu
/* name,len - nazwa i dlugosc nazwy pozycji katalogowej
WYNIK:0 i szukany i-wezel na *resinode w przypadku sukcesu
kod bledu w przypadku porazki
ENOENT ( nie istnieje taka pozycja katalogowa )
EACCES ( brak koniecznych praw )
{
if(katalog roboczy jest rowny null)
return( -ENOENT);
sprawdz czy proces ma prawo wykonywac katalog;
if(skladowa jest "..")
{
if(katalog roboczy jest korzeniem systemu plikow
- jest rowny current->fs->root)
{
na result wpisz katalog wejsciowy;
return( 0);
}
if (katalog roboczy jest korzeniem podmontowanego systemu plikow
-jest rowny sb->s_mounted)
{
zwolnij i-wezel katalogu roboczego;
jako nowy katalog roboczy wez i-wezel katalogu ,
do ktorego podmontowano systm plikow (sb->s_coverd);
if(katalog roboczy jest nullem)
return( -ENOENT);
zwieksz licznik odwolan do katalogu roboczego (i_count w i-wezlie);
}
}
if(w i-wezlie katalogu roboczego w strukturze i_op nie jest zdefiniowana
funkcja lookup)
{
zwolnij i-wezel katalogu roboczego;
return(- ENOENT);
}
if(sprawdzanie praw wykonywania katalogu nie przebieglo pomyslnie)
{
zwolnij i-wezel katalogu roboczego;
return( -EACCES);
}
if(dlugosc nazwy jest rowna 0)
/*pozwala to na wystepowanie sciezek typu /pr1//pr2 i traktowanie
ich jak /pr1/./pr2 */
{
na result przypisz katalog roboczy;
return(0);
}
/* W tym miejscu wywolywana jest funkcja ext2_lookup wpisana do iwezla
w strukturze i_op ,ktorej kod zrodlowy mozna znalezc w pliku linux/fs/ext2/namei.
Dla czytelnosci opis jej umieszczam w opisie glownej funkcji lookup.*/
if(i-wezel katalogu roboczego nie jest iwezlem katalogu )
return( - ENOENT);
if(pozycja znajduje sie w tablicy haszujacej -funkcja dcache_lookup
nie zwrocila nulla)
{
if( numer i-wezla znaleziony przez dcache_lookup jest rowny 0)
/* Pozycja nie istnieje w katalogu */
{
zwolnij i-wezel katalogu(iput);
return( -ENOENT);
}
if(nie udalo sie przydzielic iwezla o numerze zwroconym
przez dcache_lookup - iget zwrocila blad)
{
zwolnij i-wezel katalogu (iput);
return( -EACCES);
}
zwlonij i-wezel katalogu (iput);
return( 0);
}
if(nie udalo sie znalezc pozycji katalogowej na dysku - ext2_find_entry
zwrocila null)
{
if(w miedzyczasie inny proces nie zmienil katalogu)
dodaj do tablicy haszujacej pozycje katalogowa z numerem i-wezla
rownym 0 (dcache_add);
zwolnij i-wezel katalogu(iput);
return( -ENOENT);
}
na ino przypisz znaleziony numer iwezla;
dodaj nowa pozycje do tablicy haszujacej (dcache_add) z ino jako
numer i-wezla;
zwolnij bufor do ktorego byla wczytana pozycja;
if(nie udalo sie przydzielic iwezla o numerze ino - iget zwrocila blad)
{
zwolnij i-wezel katalogu roboczego (iput);
return(-EACCES);
}
zwolnij i-wezel katalogu roboczego(iput);
return(0);
}
Funkcje dcashe_add i dcashe_lookup szczegolowo zostaly opisane w rozdziale poswieconym katalogom . Ext2_find _entry dziala analogicznie do funkcji czytajacej plik - uzywajac uzywajac funkcij ext2_bread i brelse czyta po kolei bloki danych zwiazane z katalogiem wejsciowym szukajac danej pozycji.
Podsumowujac lookup zwraca i-wezel szukanj pozycji katalogowej. Jezeli znajdowala sie ona juz w pamieci to ustawia ja na koniec kolejki level2_cache (w razie potrzeby przenoszac ja z level1_cache i usuwajac pierwszy element z level2_cache) Jezeli nie bylo jej w pamieci to wstawia ja na koniec kolejki level1_cache usuwajac jej pierwszy element (Jesli nie bylo jej i na dysku to numer i-wezla jest 0 ).
Teraz mozemy przejsc do funkcji namei ,ktorej kod mozemy znalezc w
Funkcja namei
DEFINICJA: int namei(const char *pathname, struct inode ** resinode)
WYNIK: 0 i szukany i-wezel na * resinode w przypadku sukcesu
kod bledu w przypadku porazki - bledy takie jak w funkcjach
followlink i lookup plus
ENAMETOOLONG ( sciezka nie miesci sie na jednej stronie )
ENOMEM ( brakuje pamieci , aby wczytac sciezke )
{
wczytaj nazwe sciezkowa do przestrzeni adresowj jadra ;
/* wielkosc nazwy nie moze przekraczac wielkosci strony */
/* W tym momencie wywolywana jest fukcja dir_namei zwracajaca
i-wezel katalogu maciezystego szukanego pliku .Kod jej znajduje
sie w pliku linux/fs/namei.c . Dla czytelnosci opis jej umieszcze
w opisie namei */
if(sciezka zaczyna sie od "/")
jako katalog roboczu wez korzen systemu plikow (current->fs->root)
else
jako katalog roboczy wez bierzacy katalog procesu(current->fs->pwd);
zwieksz licznik odwolan do katalogu roboczego (i_count);
while(1)
{
wczytaj kolejne skladowe nazwy sciezkowej;
if(skladowa pusta) /*koniec sciezki*/
break;
zwieksz licznik odwolan do katalogu roboczego(i_count);
znajdz pozycje katalogowa wywolujac lookup;
if(lookup zwrocila blad)
{
zwolnij i-wezel katalogu roboczego(iput);
wyjdz z bledem zwroconym przez lookup;
}
wywolaj followlink w celu obslugi ewentualnego dowiazania symbolicznego;
/* Jako wskaznik na ktory followlink wpisze wynik wez wskaznik do
katalogu roboczego , dzieki temu po followlink katalog roboczy bedzie
zmieniony na nastepny w nazwie sciezkowej */
if(followlink zwrocila blad )
wyjdz z bledem zwroconym przez followlink;
}
/* tu jest koniec funkcji dir_namei */
wywolaj lookup , aby znalezc koncowy plik;
if(lookup zwrocila blad )
wyjdz z bledem zwroconym przez lookup;
wywolaj followlink do obslugi ewentualnego dowiazania symbolicznego;
zwolnij strone w pamieci jadra ,gdzie wpisana jest sciezka;
zwroc 0;
}
Autor: Malgorzata Guziak