3. Tiedostojärjestelmä
Sisältö:
- 3 Tiedostojärjestelmä
- 3.1 Tiedoston avaus
- 3.2 Tiedoston luonti
- 3.3 Tiedoston sulkeminen
- 3.4 Tiedostosta lukeminen
- 3.5 Tiedostoon kirjoittaminen
- 3.6 Luku/Kirjoitusposition asettaminen
- 3.7 Tiedostojärjestelmän tietorakenteet
- 3.8 Kuvaajien duplikointi ja uudelleenjärjestely
- 3.9 Lipukkeiden kysely ja asettaminen
- 3.10 Tiedostojen ominaisuudet
- 3.11 Tiedostojen käyttöoikeudet
- 3.12 Tiedoston uudelleennimeäminen ja poisto
- 3.13 Tiedoston aikaleimat
- 3.14 Hakemiston käsittely
3 Tiedostojärjestelmä
Tiedostoon viitataan nimellä lähinnä vain avattaessa, muissa kutsuissa käytetään avattaessa saatua tiedostokuvaajaa. Tiedostokuvaaja voi osoittaa:
- "bittisankoa", "mustaa aukkoa" (/dev/null)
- laitetta (/dev/nrst0)
- putkea tai nimettyä putkea (ns. fifot)
- verkkoliittymää (pistokkeet)
Kaikille samat read(), write() ja close(), luomisessa ja avaamisessa eroja. Valmiiksi avatut tiedostokuvaajat:
- 0 STDIN_FILENO
- 1 STDOUT_FILENO
- 2 STDERR_FILENO
Seuraavaksi avattavat tiedostot saavat kuvaajat 3 ... OPEN_MAX. Avatut tiedostokuvaajat periytyvät lapsiprosessille. Tiedosto on avattava ennen käyttöä, jotta
- KJ saa mahdollisuuden tarkistaa käyttöoikeudet
- KJ voi luoda tiedostojärjestelmän tietorakenteet
3.1 Tiedoston avaus
Tiedosto avataan funktiolla int open(const char *pathname, int oflag, . . . /* , mode_t mode */); , joka palauttaa tiedostokuvaajan numeron. Käyttötapalipukkeet (oflag):
- O_RDONLY vain lukemista varten
- O_WRONLY vain kirjoittamista varten
- O_RDWR sekä lukemista että kirjoittamista varten
- O_APPEND kirjoita tiedoston loppuun
- O_CREAT luo, ellei olemassa. Annettava myös luotavan tiedoston rwx-bitit (mode)
- O_EXCL käytetään ed. kanssa, open palauttaa virheen, jos tiedosto on jo olemassa
- O_TRUNC jos tiedosto olemassa ja avataan kirjoittamista varten, aseta aluksi kooksi 0
- O_NONBLOCK älä odota I/O -kutsun valmistumista
- O_SYNC odota writessä, kunnes tieto todella kirjoitettu levylle
Uutta tiedostoa luotaessa pitää määritellä käyttöoikeudet (mode). Oikeudet eivät kuitenkaan jää sellaisenaan voimaan, sillä myös prosessin umask-arvo huomioidaan. Esimerkiksi, jos
mode = S_IRWXU | S_IRWXG | S_IRWX0 umask = 007 niin luotavalle tiedostolle tulee oikeudet -rwxrwx---
sys/stat.h /* MODE MASKS */ /* the following macros are for POSIX conformance */ #define S_IRWXU 00700 read, write, execute: owner #define S_IRUSR 00400 read permission: owner #define S_IWUSR 00200 write permission: owner #define S_IXUSR 00100 execute permission: owner #define S_IRWXG 00070 read, write, execute: group #define S_IRGRP 00040 read permission: group #define S_IWGRP 00020 write permission: group #define S_IXGRP 00010 execute permission: group #define S_IRWXO 00007 read, write, execute: other #define S_IROTH 00004 read permission: other #define S_IWOTH 00002 write permission: other #define S_IXOTH 00001 execute permission: other
Esimerkki:
fd = open("Unso/puppua.txt", O_CREAT | O_WRONLY, S_IRUSR | SIWUSR | S_IRGRP); if (fd = -1){ perror("Eipä auennut"); ... }
3.2 Tiedoston luonti
Tiedoston voi luoda funktiolla int creat(const char *pathname, mode_t mode);, joka palauttaa tiedostokuvaajan. Tämä vastaa kutsua:
fd=open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode);
3.3 Tiedoston sulkeminen
Tiedosto suljetaan funktiolla int close(int fildes); Unix sulkee kaikki avoimet tiedostot, kun ohjelma päättyy. Sääntö on silti: Sulje tiedosto heti, kun et sitä enää tarvitse.
3.4 Tiedostosta lukeminen
Avatusta tiedostosta luetaan merkkejä funktiolla ssize_t read(int fildes, void *buff, size_t nbytes);, joka Palauttaa luettujen merkkien lukumäärän tai 0 kun EOF. Muista: read() ei aina palauta arvonaan samaa arvoa kuin on pyydettyjen merkkien lukumäärä (nbytes): tiedoston viimeinen lukupyyntö jää yleensä vajaaksi!
3.5 Tiedostoon kirjoittaminen
Avattuun tiedostoon kirjoitetaan funktiolla ssize_t write(int fildes, const void *buff, size_t nbytes);, joka palauttaa kirjoitettujen merkkien lukumäärän. Yleensä paluuarvo on aina sama kuin kirjoitettavaksi pyydettyjen merkkien lukumäärä (nbytes).
#include < unisdt.h > #define BUFFSIZE 8192 int main(void) { int n; char buf[BUFFSIZE]; while ((n=read(STDIN_FILENO,buf,BUFFSIZE))>0) if (write(STDOUT_FILENO, buf, n) != n) perror("write error"); if (n < 0) perror("read error"); exit(0); }
3.6 Luku/ Kirjoitusposition asettaminen
Luku/ kirjoitusposition voi asettaa funktiolla off_t lseek(int fildes, off_t offset, int whence); , joka palauttaa uuden position. Uusi positio määräytyy parametrin whence arvon perusteella seuraavasti:
- SEEK_SET positio = offset
- SEEK_CUR positio = positio + offset
- SEEK_END positio = tiedoston koko + offset
Nykyposition saa selville kutsulla:
currpos = lseek(fd, 0, SEEK_CUR);Tiedoston koon saa selville kutsulla
size = lseek(fd, 0, SEEK_END);Esimerkki käytöstä:
#include < unistd.h > #include < stdio.h > #include < fcntl.h > void main(int argc, char *argv[]) { int fd; off_t size; char * buf; if (argc != 3) perror("Usage: gulp infile outfile "); if ((fd = open(argv[1],O_RDONLY)) < 0) perror("open"); size = lseek(fd,0,SEEK_END); if ((buf = (char *)malloc(size)) == NULL) perror("malloc"); lseek(fd,0,SEEK_SET); if (read(fd,buf,size) != size) perror("read"); close(fd); if ((fd = open(argv[2], O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR)) < 0) perror("open"); if (write(fd,buf,size) != size) perror("write"); close(fd); exit(0); }
3.7 Tiedostojärjestelmän tietorakenteet
Tiedostojärjestelmän toteutukseen liittyy kolme tietorakennetta, joiden avulla voidaan järjestää mm. tiedostojen yhteiskäyttö:
- Tiedostokuvaajataulu: jokaisella prosessilla omansa eli on osa PCB:tä. Tästä käy ilmi avoimet tiedostot. Tiedostokuvaajaa (se pieni kok.luku) vastaavassa lokerossa linkki avoimet tiedostot tauluun sekä lipukkeita (FD_CLOEXEC).
- Avoimet tiedostot taulu: globaali, ts. sisältää kaikkien prosessien tietoja eli tiedoston luku- ja kirjoitusposition, viitelaskurin (monestako paikasta tulee viite), linkin indeksisolmutauluun ja lipukkeita.
- Indeksisolmutaulu: globaali, ts. yksi 'alkio' kutakin avattua tiedostoa kohden. Levyltä muistiin tuotu indeksisolmu ja lisätietoa: viitelaskuri, lipukkeita.
Sama tiedosto voi olla auki usealla prosessilla, koska vain yksi alkio indeksisolmutaulussa per tiedosto. Erilliset alkiot tai yhteinen alkio avoimet tiedostot taulussa:
- erilliset luku/kirjoituspositiot tai
- yhteinen luku/kirjoituspositio
Kahdella prosessilla voi olla yhteinen alkio avoimet tiedostot taulussa vain, kun lapsi on perinyt avoimet tiedostot äidiltään fork() -kutsussa. Saman prosessin kaksi tiedostokuvaajaa voi osoittaa samaan avoimet tiedostot taulun alkioon, jos kuvaajia on duplikoitu systeemikutsulla dup() tai dup2().
read() kasvattaa lukupositiota luettujen tavujen lkm:llä. Jos positio = tiedoston koko, palauttaa arvon 0 (= eof).
write() kasvattaa positiota kirjoitettujen tavujen lkm:llä. Jos tiedoston koko kasvaa, arvo kopioidaan i- solmutauluun. Jos lipuke O_APPEND on asetettu, kopioidaan positiolle arvo ennen kirjoittamista i- solmutaulusta eli jokainen kirjoitus menee tiedoston loppuun.
lseek() muuttaa vain positiota avoimet tiedostot taulussa. Se ei aiheuta koskaan siirräntää.
3.8 Kuvaajien duplikointi ja uudelleenjärjestely
Avatun tiedostokuvaajan voi kopioida toisen tiedostokuvaajan arvoksi funktiolla int dup(int filedes); tai int dup2(int filedes1, filedes2), jotka palauttavat uuden tiedostokuvaajan. dup() kopioi parametrina annetun kuvaajan numeroltaan pienimpään vapaaseen tiedostokuvaajaan.
if ((fd = open("puppu.dat",O_WRONLY)) < 0) perror("can't open"); close(STDOUT_FILENO); dup(fd); close(fd); n = write(STDOUT_FILENO,buf, BUFLEN);
dup2() sulkee kuvaajan filedes2 ja kopioi sen paikalle kuvaajan filedes1. Atominen toiminto. Edelläolevat rivit close() ja dup() voi korvata rivillä:
dup2(fd,STDOUT_FILENO);
3.9 Lipukkeiden kysely ja asettaminen
Avatun tiedoston lipukkeita voi kysellä ja asettaa funktiolla int fcntl(int filedes, int cmd, . . . /* int arg */); , missä paluuarvo riippuu parametrista cmd, jonka mahdollisia arvoja ovat:
- F_DUPFD - tee duplikaatti tiedostokuvaajasta
- F_GETFD, F_SETFD - kysy / aseta tdostokuvaajan lipuke FD_CLOEXEC (ts. suljetaanko tiedosto exec:ssä)
- F_GETFL, F_SETFL
- kysy / aseta käyttötapalipukkeita
- O_RDONLY, O_RDWR, O_WRONLY (näille vain get)
- O_APPEND kirjoitus aina loppuun
- O_NONBLOCK estymätön I/O
- O_SYNC kirjoitus aina levylle
- O_ASYNC asynkroninen I/O + signaali
- F_GETOWN, F_SETOWN - kysy / aseta estymättömän I/O:n omistaja, ts. prosessi, joka saa SIGIO- ja SIGURG-signaalit
- F_GETLK, F_SETLK, F_SETLKW - kysy / aseta tiedostolukko
- F_FREESP - vapauta tiedostolle varattua tilaa
#include < stdio.h> #include < unistd.h> #include < sys/types.h> #include < fcntl.h> int main(int argc, char *argv[]) { int accmode, val; if (argc != 2) perror("usage: a.out"); if ((val=fcntl(atoi(argv[1]),F_GETFL,0))< 0) perror("fcntl error for fd %d",atoi(argv[1])); accmode = val & O_ACCMODE; if (accmode==O_RDONLY) printf("read only"); else if (accmode==O_WRONLY) printf("write only"); else if (accmode == O_RDWR) printf("read write"); else perror("unknown access mode"); if (val & O_APPEND) printf(", append"); if (val & O_NONBLOCK) printf(", nonblocking"); putchar('\n'); exit(0); } void set_fl(int fd, int flags) /* file status flags to turn on */ { int val; if ((val = fcntl(fd, F_GETFL, 0)) < 0) perrro("fcntl F_GETFL error"); val |= flags; /* turn on flags */ if (fcntl(fd, F_SETFL, val) < 0) perror("fcntl F_SETFL error"); }
3.10 Tiedostojen ominaisuudet
Tiedosto on jono tavuja. Siihen liittyy nimi, attribuutit ja datalohkot. Unix tallettaa nämä erilleen toisistaan. Hakemisto on tiedosto, jossa on peräkkäin pareja: tiedostonimi ja i-solmunumero. Hakemisto voi edelleen sisältää hakemistotiedostojen nimiä, jolloin muodostuu puurakenne. Attribuutit on talletettu indeksisolmuun. Ja indeksisolmusta käy ilmi missä tiedoston lohkot sijaitsevat. SysV:ssä tiedostonimelle on varattu 14 tavua ja i- solmunumerolle 2 tavua. BSD:ssä tiedostonimelle on varattu 255 merkkiä.Tiedostojen ominaisuuksia voi kysellä funktioilla stat(), fstat() ja lstat(). Sekä stat() että fstat() osaavat kulkea symbolista linkkiä pitkin todelliseen kohdetiedostoon. lstat() on muuten kuin stat(), mutta jos nimi on symbolinen linkki, se antaa linkkitiedoston ominaisuudet.
#include < sys/types.h> #include < sys/stat.h> struct stat { mode_t st_mode; tyyppi, käyttöoikeudet ino_t st_ino; i-solmun numero dev_t st_dev; laitenumero dev_t st_rdev; laitenumero (special) nlink_t st_nlink; tulevien linkkien lkm uid_t st_uid; omistaja gid_t st_gid; ryhmä off_t st_size; koko tavuina time_t st_atime; milloin viim. käytetty time_t st_mtime; milloin viim. muutettu time_t st_ctime; milloin viim. muutettu oikeuksia i-solmuun long st_blksize; suositeltu I/O:n lohkokoko long st_blocks; allokoitujen lohkojen lkm } int stat(const char *pathname, struct stat *buf); int fstat(int filedes, struct stat *buf); int lstat(const char *pathname, struct stat *buf);POSIX ei vaadi kenttiä st_rdev, st_blksize, st_blocks. Koska Unix sallii kokonaisten tiedostojärjestelmien mounttaamisen yhtenäiseksi tiedostopuuksi, tarvitaan tiedoston yksilöintiin sekä i-solmunumero että laitenumero. Tiedostotyypit (kentässä st_mode):
- - tavallinen (teksti- tai binääri-)tiedosto
- d hakemisto(tiedosto)
- l symbolinen linkki(tiedosto)
- c erikoistiedosto, merkkilaite
- b erikoistiedosto, lohkolaite
- p putki(tiedosto), FIFO
- s pistoke(tiedosto)
#define S_ISFIFO(mode) (((mode)&0xF000)==0x1000) #define S_ISCHR(mode) (((mode)&0xF000)==0x2000) #define S_ISDIR(mode) (((mode)&0xF000)==0x4000) #define S_ISBLK(mode) (((mode)&0xF000)==0x6000) #define S_ISREG(mode) (((mode)&0xF000)==0x8000) #define S_ISLNK(mode) (((mode)&0xF000)==0xa000) #define S_ISSOCK(mode) (((mode)&0xF000)==0xc000) #define S_ISDOOR(mode) (((mode)&0xF000)==0xd000) #define S_TYPEISMQ(buf) (0) #define S_TYPEISSEM(buf) (0) #define S_TYPEISSHM(buf) (0)
#include < sys/types.h> #include < sys/stat.h> #include < unistd.h> int main(int argc, char *argv[]) { int i; struct stat buf; char *ptr; for (i = 1; i < argc; i++) { printf("%s: ", argv[i]); if (lstat(argv[i], &buf) < 0) { perror("lstat error"); continue; } if(S_ISREG(buf.st_mode)) ptr = "regular"; else if (S_ISDIR(buf.st_mode)) ptr = "directory"; else if (S_ISCHR(buf.st_mode)) ptr = "character special"; else if (S_ISBLK(buf.st_mode)) ptr = "block special"; else if (S_ISFIFO(buf.st_mode)) ptr = "fifo"; #ifdef S_ISLNK else if (S_ISLNK(buf.st_mode)) ptr = "symbolic link"; #endif #ifdef S_ISSOCK else if (S_ISSOCK(buf.st_mode)) ptr = "socket"; #endif else ptr = "** unknown mode **"; printf("%s\n", ptr); } exit(0); }
3.11 Tiedostojen käyttöoikeudet
Suoritettavaan prosessiin liittyy aina: real user id (uid) ja real group id (gid), effective user id (euid), effective group id (egid) ja supplementary group list. Lisäksi voi olla: saved user id ja saved group id.
- uid ja gid: Todellinen prosessin omistaja ja hänen ensisijainen ryhmänsä. Saatu istunnon alussa salasanatiedostosta.
- euid ja egid: Käytetään tiedostojen käyttöoikeuksien tarkistuksessa. Aluksi euid = uid ja egid = gid euid muuttuu koodin suoritusajaksi, jos kooditiedostolla on omistajan x-oikeuden tilalla s-oikeus (set-user-id). egid muuttuu koodin suoritusajaksi, jos kooditiedostolla on ryhmän x-oikeuden tilalla S-oikeus (set-group-id).
- supplementary group list: Muodostetaan ryhmätiedoston /etc/group perusteella prosessia käynnistettäessä. Käytetään tiedostojen käyttöoikeuksien tarkistamisessa.
- saved uid ja saved gid: Näihin kopioidaan euid ja egid, kun prosessi on käynnistymässä. Käyttöä set-uid ja set-gid ohjelmien yhteydessä.
Unix tarkistaa tiedoston käyttöoikeudet seuraavasti:
jos euid = root niin saa kaikki oikeudet muuten jos euid = st_uid niin tarkista kohdasta 'user' muuten jos egid = st_gid | egid IN grouplist tarkista kohdasta 'group' muuten tarkista kohdasta 'other'
Huomaa: jos käyttäjä kuuluu samaan ryhmään kuin omistaja, ei oikeuksia tarkisteta kohdasta 'other' !!! Jos sovellus haluaa tarkistaa omat oikeutensa tiedostoon todellisen uid:in ja todellisen gid:in perusteella, se voi käyttää funktiota int access(const char *pathname, int mode);, joka palauttaa 0, jos oikeus olemassa. mode:
- R_OK onko lukuoikeus
- W_OK onko kirjoitusoikeus
- X_OK onko suoritus / läpikulkuoikeus
- F_OK onko tiedosto olemassa
#include < sys/types.h> #include < fcntl.h> #include < unistd.h> int main(int argc, char *argv[]) { if (argc != 2) perror("usage: a.out"); if (access(argv[1], R_OK) < 0) perror("access error for %s", argv[1]); else printf("read access OK\n"); if (open(argv[1], O_RDONLY) < 0) perror("open error for %s", argv[1]); else printf("open for reading OK\n"); exit(0); }
Uusi tiedosto saa omistajan ja ryhmän tiedot prosessin kuvaajasta. st_uid = euid ja st_gid = egid tai st_gid = isähakemiston st_gid. Uudelle tiedostolle on annettava käyttöoikeudet luonnin yhteydessä (eli open() / creat() kutsussa). Ne eivät tule kuitenkaan sellaisenaan voimaan, vaan prosessin umask-arvo vaikuttaa i-solmuun tallettuviin arvoihin. umask-arvo periytyy äitiprosessilta. umask-arvoa voi muuttaa funktiolla mode_t umask(mode_t cmask);, joka palauttaa edellisen umask-arvon.
#include < sys/types.h> #include < sys/stat.h> #include < fcntl.h> #include < unistd.h> int main(void) { umask(0); if (creat("foo",S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) < 0) perror("creat error for foo"); umask(S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); if (creat("bar",S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) < 0) perror("creat error for bar"); exit(0); }
Prosessi voi muuttaa omistamansa tiedoston käyttöoikeuksia funktioilla int chmod(const char *pathname, mode_t mode); ja int fchmod(int filedes, mode_t mode);, jotka palauttaa 0, jos funktion suoritus onnistuu. Vain super-user voi:
- muuttaa muiden omistamien tiedostojen käyttöoikeuksia
- asettaa sticky-bitin, ts. määrätä, että koodi pidetään heittovaihtoalueella, vaikka mikään prosessi ei sitä tarvitsisikaan. [On jo katoavaa kansanperinnettä]
#include < sys/types.h> #include < sys/stat.h> #include < unistd.h> int main(void) { struct stat statbuf; /* turn on set-group-ID and turn off group-execute */ if (stat("foo", &statbuf) < 0) perror("stat error for foo"); if (chmod("foo", statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0) perror("chmod error for foo"); /* set absolute mode to "rw-r--r--" */ if (chmod("bar", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) perror("chmod error for bar"); exit(0); }Prosessi voi muuttaa eräin edellytyksin omistamansa tiedoston omistajaa ja ryhmää funktioilla int chown(const char *pathname, uid_t owner, gid_t group);, int fchown(int filedes, uid_t owner, gid_t group); ja int lchown(const char *pathname, uid_t owner, gid_t group);, jotka palauttavat 0 jos funktion suoritus onnistuu.
Jos viitattu tiedosto on symbolinen linkki, muuttavat chown() ja fchown() todellisen kohteen omistajaa tai ryhmää, mutta lchown() linkkitiedoston.
Ryhmän muutoksessa perussääntö kuten omistajan muutoksessa. Jos sallittua, ryhmäksi voi muuttaa vain sellaisen ryhmän johon itsekin kuuluu. Jos muutoksen tekee joku muu kuin super-user, nollataan set-uid ja set-gid bitit.
3.12 Tiedoston uudelleennimeäminen ja poisto
Tiedoston nimeä voi vaihtaa funktiolla int rename(const char *oldname, const char *newname);. Toiminta ja perusvaatimukset vaihtelevat sen mukaan onko oldname ja/tai newname tiedosto vai hakemisto.Jotta tiedoston voisi poistaa, on tiedostoon itseensä oltava w-oikeus ja hakemistoon sekä w-oikeus että x- oikeus. Tiedosto poistuu, kun viimeinenkin siihen osoittava linkki katkaistaan funktiolla int unlink(const char *pathname); tai int remove(const char *pathname);
unlink() poistaa aina hakemistoalkion ja vähentää indeksisolmussa olevaa linkkien lukumäärää yhdellä. Jos lukumääräksi tulee 0, vapauttaa se myös tiedostoon kuuluneet lohkot sekä indeksisolmun. Jos parametrina annettu tiedosto on (symbolinen) linkkitiedosto, unlink() poistaa sen, ei linkin päässä olevaa tiedostoa. unlink() poistaa hakemistoalkion heti, mutta muut vapautukset tehdään vasta ohjelman päättyessä. Aputiedostolle voi tehdä unlink() heti, kun se on luotu, jolloin aputilan siivoaminen ei pääse unohtumaan:
#include < sys/types.h> #include < sys/stat.h> #include < fcntl.h> #include < unistd.h> int main(void) { if (open("tempfile", O_RDWR) < 0) perror("open error"); if (unlink("tempfile") < 0) perror("unlink error"); printf("file unlinked\n"); sleep(15); printf("done\n"); exit(0); }
3.13 Tiedoston aikaleimat
Indeksisolmussa on kolme aikaleimaa:
- st_atime milloin tdstoa viimeeksi käytetty
- st_mtime milloin tdstoa viimeeksi muutettu
- st_ctime milloin i-solmua viimeeksi muutettu
Komento ls näyttää oletusarvoisesti milloin tiedostoa on viimeeksi muutettu eli kentän st_mtime. Ko. kenttää hyödynnetään esim. varmuuskopioinnissa (täydennyskopiot). Indeksisolmun tietojen kysely funktiolla stat() tms. ei muuta aikaleimoja. Omistamansa tiedoston aikaleimoja st_atime ja st_mtime voi muuttaa funktiolla utime():
#include < sys/types.h> #include < utime.h> struct utimbuf { time_t actime; time_t modtime; } int utime(const char *pathname, const struct utimbuf *times); Jos times = NULL && w-oikeus st_atime <- current time st_mtime <- current time muuten st_atime <- times.actime st_mtime <- times.modtime
utime() aiheuttaa myös kentän st_ctime päivittymisen. Komentotulkin tasolla aikaleimoja voi muuttaa komennolla:
$ touch
#include < sys/types.h> #include < sys/stat.h> #include < fcntl.h> #include < utime.h> #include < unistd.h> int main(int argc, char *argv[]) { int i; struct stat statbuf; struct utimbuf timebuf; for (i = 1; i < argc; i++) { if (stat(argv[i], &statbuf) < 0) { perror("%s: stat error", argv[i]); continue; } if (open(argv[i], O_RDWR | O_TRUNC) < 0) { perror("%s: open error", argv[i]); continue; } timebuf.actime = statbuf.st_atime; timebuf.modtime = statbuf.st_mtime; if (utime(argv[i], &timebuf) < 0) { perror("%s: utime error", argv[i]); continue; } } exit(0); }
3.14 Hakemiston käsittely
Hakemisto luodaan funktiolla int mkdir(const char *pathname, mode_t mode); ja tyhjä hakemisto poistetaan funktiolla int rmdir(const char *pathname);Prosessi saa työhakemistonsa nimen funktiolla char *getcwd(char *buf, size_t bufsize); ja se voi vaihtaa työhakemistoa funktioilla int chdir(const char *pathname); ja int fchdir(int fildes);.
int main(void) { char *ptr; int size=256; if (chdir("/usr/spool/uucppublic") < 0) perror("chdir failed"); ptr = malloc(size); if (getcwd(ptr, size) == NULL) perror("getcwd failed"); printf("cwd = %s\n", ptr); exit(0); }
Hakemistotiedoston käsittelyyn on funktiot:
#include < sys/types.h> #include < dirent.h> struct dirent { ino_t d_ino; char d_name[NAME_MAX + 1]; } DIR *opendir(const char *pathname) struct dirent *readdir(DIR *dp); void rewinddir(DIR *dp); int closedir(DIR *dp);Funktioita opendir(), readdir() ja closedir() käytetään kuten vastaavia salasanatiedoston tai ryhmätiedoston funktioita. Vain KJ voi kirjoittaa hakemistotiedostoon. DIR on järjestelmän sisäinen rakenne, jota ei tarvitse tuntea tarkemmin (vrt. FILE *).
Jan Lindström (Jan.Lindstrom@cs.Helsinki.FI)