Myös inodet säilytetään levyllä, eli jos halutaan lukea tietyn tiedoston sisältö, on tiedostojärjestelmän ensin etsittävä levyltä tiedostoa vastaava inode ja katsottava inoden sisältä missä päin levyä tiedoston data on talletettuna.
Tiedostojen nimi ei ole talletettu inodeen. Tiedoston nimi löytyy ainoastaan hakemistosta. Hakemistot ovat tiedostoja, jotka sisältävät tiedostojen nimiä ja viitteitä nimiä vastaaviin inodeihin.
Seuraava kuva havainnollistaa hakemiston ja inoden suhdetta.
Hakemisto siis sisältää sen sisältämien tiedostojen (ja hakemistojen) nimet sekä linkin niitä vastaaviin inodeihin. Tiedostojen attribuutit löytyvät inodesta, samoin kun linkit niihin levylohkoihin jotka tallettavat tiedoston datan.
SYNOPSIS #include < sys/types.h> #include < sys/stat.h> #include < unistd.h> int stat(const char *file_name, struct stat *buf); int fstat(int filedes, struct stat *buf); DESCRIPTION These functions return information about the specified file. You do not need any access rights to the file to get this information but you need search rights to all directories named in the path leading to the file. stat stats the file pointed to by file_name and fills in buf. fstat is identical to stat, only the open file pointed to by filedes (as returned by open(2)) is stat-ed in place of file_name. They all return a stat structure, which contains the following fields: struct stat { dev_t st_dev; /* device */ ino_t st_ino; /* inode */ mode_t st_mode; /* protection */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ dev_t st_rdev; /* device type (if inode device) */ off_t st_size; /* total size, in bytes */ blksize_t st_blksize; /* blocksize for filesystem I/O */ blkcnt_t st_blocks; /* number of blocks allocated */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of last change */ };stat ja fstat -operaatioiden avulla siis saadaan struct stat -tyyppinen tietue, jonka kenttinä löytyy tietoa tiedoston ominaisuuksista. Komennot eroavat toisistaan sen suhteen, että statin ensimmäisenä parametrina on tiedoston nimi ja fstatissa avoimen (openilla avatun) tiedoston tiedostokuvaaja.
Tiedoston nimi Unixeissa on joko absoluuttinen tai suhteellinen. Absoluuttinen polkunimi alkaa /-merkillä. Esim. tämän html-tiedoston absoluuttinen polkunimi on /home/luuma/public_html/kj/vko10/index.html. Suhteellinen polkunimi taas kertoo tiedoston nimen suhteessa työhakemistoon. Jos työhakemistona olisi /home/luuma/public_html/kj, viitataan tähän html-tiedostoon suhteellisella nimellä vko10/index.html.
Eli jos käytetään tiedstoista suhteellisia nimiä, on työhakemiston oltava oikea. Kun ohjelma käynnistetään komentotulkista, tulee ohjelman työhakemistoksi se hakemisto missä komentotulkki oli ohjelman käynnistyshetkellä. Ohjelma voi vaihtaa työhakemistoa komennolla chdir, man-sivulta:
#include < unistd.h> int chdir(const char *path); DESCRIPTION chdir changes the current directory to that specified in path. RETURN VALUE On success, zero is returned. On error, -1 is returned, and errno is set appropriately.Työhakemiston saa selville komennolla getcwd, man-sivulta:
#include < unistd.h> char *getcwd(char *buf, size_t size); DESCRIPTION The getcwd() function copies an absolute pathname of the current work- ing directory to the array pointed to by buf, which is of length size. If the current absolute path name would require a buffer longer than size elements, NULL is returned, and errno is set to ERANGE; an appli- cation should check for this error, and allocate a larger buffer if necessary. If buf is NULL, the behaviour of getcwd() is undefined. RETURN VALUE NULL on failure with errno set accordingly, and buf on success. The contents of the array pointed to by buf is undefined on error.Esimerkkinä ohjelma 10-1.c, joka ensin tulostaa ohjelmatiedostonsa koon tavuina. Tämän jälkeen ohjelma tulostaa työhakemistonsa, siirtyy hakemistotasolla yhden tason alaspäin (eli sama kuin cd ..) ja tulostaa jälleen oman työhakemistonsa. Koodi seuraavassa:
#define SIZE 1024 int main(int argc, char *argv[]){ struct stat attrib; char buf[SIZE]; // pyydetään ohjelmatiedoston attribuutit stat(argv[0], &attrib); // tulostetaan koko printf("tiedoston %s koko %d tavua\n", argv[0], attrib.st_size); // tulostetaan työhakemisto getcwd(buf, SIZE); printf("työhakemisto: %s\n", buf); // mennään yksi taso alaspäin chdir(".."); getcwd(buf, SIZE); printf("ja nyt: %s\n", buf); return 0; }
#include < sys/types.h> #include < dirent.h> DIR *opendir(const char *name); DESCRIPTION The opendir() function opens a directory stream corresponding to the directory name, and returns a pointer to the directory stream. The stream is positioned at the first entry in the directory. RETURN VALUE The opendir() function returns a pointer to the directory stream or NULL if an error occurred.opendir siis palauttaa osoittimen DIR-tyyppiseen muuttujaan.
Avoinna olevan hakemiston sisältö luetaan komennolla readdir. readdir palauttaa hakemistosta yhden hakemistomerkinnän (directory entry) kerrallaan.
readdirin man-sivulla (huom: sektiossa 3) sanotaan seuraavasti:
#include < sys/types.h> #include < dirent.h> struct dirent *readdir(DIR *dir); DESCRIPTION The readdir() function returns a pointer to a dirent structure repre- senting the next directory entry in the directory stream pointed to by dir. It returns NULL on reaching the end-of-file or if an error occurred. According to POSIX, the dirent structure contains a field char d_name[] of unspecified size, with at most NAME_MAX characters preceding the terminating null character. Use of other fields will harm the porta- bility of your programs. POSIX 1003.1-2001 also documents the field ino_t d_ino as an XSI extension. The data returned by readdir() may be overwritten by subsequent calls to readdir() for the same directory stream. RETURN VALUE The readdir() function returns a pointer to a dirent structure, or NULL if an error occurs or end-of-file is reached.readdir siis palauttaa osoittimen struct dirent -tyyppiseen tietueeseen. Tietueella on kenttinä tiedoston nimi d_name, ja tiedoston inoden numero d_ino.
readdirillä luetaan hakemiston sisältöä yksi merkintä kerrallaan. Hakemiston koko sisältö saadaan luetuksi kutsumalla readdiriä toistuvasti kunnes koko sisältö on luettu ja readdir palauttaa NULL:in.
Avoinna olevan hakemiston sulkeminen tapahtuu komennolla closedir, joka saa parametrikeen opendirin palauttaman DIR-osoittimen. Ohjelma 10-2.c toteuttaa suunnilleen saman kun komento ls ilman komentoriviparametreja.
int main(void){ DIR *hakemisto; // hakemistokahva struct dirent *entry; // osoitin hakemistomerkintään // avataan nykyhakemisto eli ".", operaatio palauttaa hakemistokahvan hakemisto = opendir("."); while( 1 ){ entry = readdir(hakemisto); if ( entry == NULL ) break; // ollaan lopussa // tulostetaan hakemistomerkinnän nimi ruudulle printf("%s\n",entry->d_name); } // suljetaan hakemisto closedir(hakemisto); return 0; }Ojelma 10-3.c on hieman kehittyneempi versio edellisestä. Ohjelma tulostaa joko parametrina annetun hakemiston sisällön tai jos parametria ei ole, tulostetaan sen hakemiston sisältö missä ohjelma käynnistetään.
int main(int argc, char *argv[]){ DIR *hakemisto; // hakemistokahva struct dirent *entry; // osoitin hakemistomerkintään struct stat attrib; // muuttuja tiedoston/hakemiston attribuuteille char *hnimi = "."; // avattavan hakemiston nimi // jos komentoriviparametri, sijoitetaan tämä luettavan hakemiston nimeksi if ( argc>1 ) hnimi = argv[1]; // avataan hakemisto, operaatio palauttaa hakemistokahvan hakemisto = opendir(hnimi); // testataan epäonnistuiko operaatio if ( hakemisto == NULL ) { printf("hakemistoa %s ei olemassa\n",hnimi); return 0; } // laitetaan ohjelman hakemistoksi tutkittava hakemisto chdir(hnimi);Nyt hakemisto on avattuna ja muuttujassa hakemisto on DIR-osoitin, jonka kautta hakemiston sisältöä luetaan. Viimeisenä komentona edellä oli chdir, jolla siirrytään siihen hakemistoon, minkä sisältö tulostetaan. Tämä ei ole hakemiston selaamisen kannalta oleellista, mutta koska jatkossa käytetään stat-komentoa ja suhteellisia polkunimiä, niin ohjelman työhakemiston on oltava sama kun selattava hakemisto.
Perusratkaisuna jälleen while-silmukka, jossa hakemiston sisältö luetaan entry kerrallaan. Tällä kertaa toimitaan siten, että jos entry on hakemisto, tulostetaan hakemiston nimen perään /-merkki. Jos entry on normaali tiedosto, tulostetaan tiedoston koko tavuina.
Tiedoston tyyppi selviää stat-funktion avulla. Funktion palauttaman structin st_mode-kenttä sisältää pakattuna paljon tietoa, mm. tiedon siitä minkä tyyppinen tiedosto on, eli onko kyseessä hakemisto vai normaali tiedosto. stat-komennon man-sivulta selviää, että kentän arvon tutkimiseen on olemassa valmiita makroja, esim. S_ISDIR(attrib.st_mode) on tosi (eli lausekkeella arvo 1) jos kyseessä on hakemisto ja S_ISREG(attrib.st_mode) on tosi jos kyseessä normaali tiedosto.
Ohjelma tutkii tiedoston attribuuttien st_mode-kenttää ja muotoilee tämän perusteella tulostuksen oikeanlaiseksi.
while( 1 ){ entry = readdir(hakemisto); if ( entry == NULL ) break; // luetaan hakemistomerkinnän attribuutut muuttujaan attrib stat(entry->d_name, &attrib); // testataan, onko kyseessä hakemisto if ( S_ISDIR(attrib.st_mode) ) { // tulostetaan hakemistonimen perään kenoviiva eli /-merkki printf("%s/\n",entry->d_name); } else if ( S_ISREG(attrib.st_mode) ) { // tulostetaan tiedoston nimen lisäksi koko tavuina printf("%-30s %10d B\n",entry->d_name, attrib.st_size); } } // suljetaan hakemisto closedir(hakemisto); return 0; }
inodessa on kenttä, joka kertoo kuinka monessa hakemistossa tiedosto on linkitettynä. Kenttän arvo on stat-komennon palauttaman tietueen kentässä st_nlink. Tiedosto ja inode eivät tiedä mistä hakemistoista tiedostoon viitataan.
Kova linkki luodaan komennolla link, man-sivulta:
#include < unistd.h> int link(const char *oldpath, const char *newpath); DESCRIPTION link creates a new link (also known as a hard link) to an existing file. If newpath exists it will not be overwritten. This new name may be used exactly as the old one for any operation; both names refer to the same file (and so have the same permissions and ownership) and it is impossible to tell which name was the `original'. RETURN VALUE On success, zero is returned. On error, -1 is returned, and errno is set appropriately.Kuten man-sivu kuvaa, linkityksen jälkeen ei enää mistään erota mikä oli tiedoston aluperäinen nimi.
Kovan linkin (kuten myös ns. symbolisen linkin josta kohta enemmän) saa poistettua komennolla unlink, man-sivulta:
#include < unistd.h> int unlink(const char *pathname); DESCRIPTION unlink deletes a name from the filesystem. If that name was the last link to a file and no processes have the file open the file is deleted and the space it was using is made available for reuse. If the name was the last link to a file but any processes still have the file open the file will remain in existence until the last file descriptor referring to it is closed. If the name referred to a symbolic link the link is removed.Eli komento poistaa tiedoston jos se suoritetaan tiedostolle johon on enää yksi linkki jäljellä. Unixeissa ei ole mitään erillistä tiedoston poistamiseen tarkoitettua käskyä, poistaminen hoidetaan aina unlink-komennolla ja KJ pitää huolen siitä, että jos tiedosto ei ole enää missään hakemistossa, se poistetaan.
Toinen linkkityyppi on symbolinen linkki (symbolic link tai soft link), joka luodaan komennolla symlink. Erona kovaan linkkiin on se, että symbolinen linkki ei osoita suoraan inodeen vaan sisältää jonkun polkunimen. Jos on luotu symbolinen linkki, missä nimi x.c on linkitetty tiedostoon /home/luuma/koe.c, niin tiedoston x.c avaaminen saakin aikaan sen, että avataan tiedosto /home/luuma/koe.c. Symbolinen linkki on siis vain viite johonkin toiseen kohtaan hakemistohierarkiassa. Symbolisen linkin luominen ei kasvata inoden linkkikenttää.
Jaettu muistialue luotiin shm_open-komennolla, joka palautti tiedostokuvaajan luotuun muistialueeseen. Komennolle mmap annettiin sitten muistialuetta edustanut tiedostokuvaaja, ja mmap palautti osoittimen jaetulle muistialueelle.
mmap-komentoa voidaan käyttää myös tiedoston sisällön mappaamiseksi keskusmuistiin. Tämä seikka selviää myös mmap-komennon man-sivulta:
#include < sys/mman.h> void *mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset); DESCRIPTION The mmap function asks to map length bytes starting at offset offset from the file (or other object) specified by the file descriptor fd into memory, preferably at address start. This latter address is a hint only, and is usually specified as 0. The actual place where the object is mapped is returned by mmap, and is never 0.Tarkastellaan ohjelmaa 10-4.c, joka mappaa tiedoston muistiinsa ja tulostaa muistiin mapatun tiedoston sisällön lukien tiedostoa osoittimen avulla aivan kuin kyseessä olisi keskusmuistin sisällön lukeminen.
int main(int argc, char *argv[]){ int fd; if ( argc<2 ) return 0; // avataan komentoriviparametrina annettu tiedosto fd = open( argv[1], O_RDONLY ); if ( fd == -1 ){ perror("ongelma openissa"); return -1; } // selvitetään tiedoston koko fstat-funktiolla struct stat st; fstat( fd, &st ); int koko = st.st_size; // mapataan tiedosto muistiin, osoitteeksi p char *p; p = (char *) mmap( 0, koko, PROT_READ, MAP_SHARED, fd, 0 ); if ( p == MAP_FAILED ){ perror("ongelma jaetun muistialueen luomisessa"); return -1; } // tulostetaan mapatun muistialueen sisältö int i; for ( i=0; i < koko; i++ ){ printf("%c", p[i] ); } // poistetaan mappays ja suljetaan tiedosto munmap( p, koko ); close( fd ); return 0; }Jos tiedosto olisi avattu ja mapattu luku- ja kirjoitusoikeuksilla, menisivät kaikki mapatulle muistialueelle tehdyt muutokset tiedostoon.