Linux - súbory a adresáre

Tomáš Plch  /  11. 05. 2007, 00:00

Funkcie na narábanie s adresármi a súbormi sú neodmysliteľnou súčasťou výbavy každého programátora. V tomto článku si zhrnieme niektoré zaujímavé funkcie.

Okrem štandardných funkcií ako fopen() fclose() fseek() a ftell(), prípadne read(), write(), fprintf() by mal programátor v prostredí operačného systému Linux poznať sadu užitočných funkcií, ktorú sa posnažíme zosumarizovať v tomto článku. V článku predpokladáme znalosť pojmu dekritor a určitá dávka programátorského pochopenia.

Funkcia fstat() a príbuzné lstat() a stat() nájdeme v hlavičkových súboroch

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

ich deklarácie sú nasledovné
int fstat(int filedes, struct stat *buf);

int stat(const char *path, struct stat *buf);

int lstat(const char *path, struct stat *buf);


Budeme sa zaoberať funkciou fstat(), avšak vysvetlíme si rozdiel medzi lstat() a stat(). Ich chovanie je rozdielne pokiaľ parameter path ukazuje na symbolický odkaz (symlink). Funkcia stat() vráti informácie o súbore na ktorý odkaz odkazuje a fstat() vracia informácie o samotnom súbore ktorý obsahuje symlink. Simlink je na rozdiel od hardlinku odkaz pomocou "cesty" k súboru na ktorý odkazuje, a môže byť na neexistujúce súbory, prípadne sa rozprestierať cez partície a filesystémy. Naopak hardlink je priamo odkaz na súbor a nesmie prekračovať partície alebo filesystémy. Jedná sa o ďalší ukazovateľ na reálny obsah alebo štruktúru, ktorá obsahuje dáta súboru. Počet hardlinkov sa drží ako informácia vo filesystéme a súbor je reálne zmazaný(jeho obsah na médiu) až keď prestane existovať posledný hardlink. Symlink takúto výsadu nemá a môže teda odkazovať na zmazaný alebo neexistujúci súbor.

U mazania súborov je ešte jedna dôležitá skutočnosť a tou je, že okrem hardlinkov sa zohľadňujú aj otvorené desktriptory. Pokiaľ existuje otvorený deskriptor, súbor ostáva rezidentný.

int filedes je deskriptor na súbor (získať sa dá zavolaním open() alebo vytvorením z FILE* pomocou fileno(), prípadne použitím dup() alebo dup2() )

Čo sa skrýva za štruktúrov struct stat
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
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 ID (if special file) */
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 status change */
};
Pre nás najzaujímavejšie položky sú mode_t st_mode, uid_t st_uid, gid_t st_gid, off_t st_size. nlink_t st_nlink a položky time_t st_atime, st_mtime, st_ctime.

mode_t st_mode - je to bitmask rôznych príznakov, pričom spodných 9 bitov patrí prístupovým právam, podľa klasického schématu RWXRWXRWX (R - read, W - write, X - execute) pričom prvá trojica je vlastník, potom je skupina a končí to zvyškom sveta.

Makrá pre tieto položky sú nasledovné:
  • S_IRWXU - nastaví všetky práva vlastníka
  • S_IRWXG - nastaví všetky práva skupiny
  • S_IRWXO - nastaví všetky práva zvyšku sveta
  • S_IRUSR S_IWUSR S_IXUSR - nastaví práva čítania zápisu spustenia pre vlastníka
  • S_IRGRP S_IWGRP S_IXGRP - nastaví práva čítania zápisu spustenia pre skupinu
  • S_IRGRP S_IWGRP S_IXGRP - nastaví práva čítania zápisu spustenia pre skupinu
  • S_IROTH S_IWOTH S_IXOTH - nastaví práva čítania zápisu spustenia pre zvyšok sveta
Iné zaujímavé flagy sú:
S_IFLNK(je to symbolický link),S_IFREG(normálny súbor),S_IFDIR(adresár)

A použiteľné makrá sú (parameter je mode_t st_mode)
  • S_ISREG(x)  - zistí či je nastavný príznak toho, źe sa jedná o súbor
  • S_ISDIR(x) - zistí či je nastavný príznak toho, źe sa jedná o adresár
  • S_ISLNK(x) - zistí či je nastavný príznak toho, źe sa jedná o symbolický odkaz
  • S_ISCHR(x), S_ISBLK(x), S_ISFIFO(x), S_ISSOCK(x) sú zaujímavé z pohľadu typu zariadenia alebo špecifického druhu súboru
  • uid_t st_uid - user ID vlastníka
  • gid_t st_gid - group ID vlastníka
  • off_t st_size - veľkosť súboru v bajtoch
  • nlink_t st_nlink - počet hardlinkov
time_t st_atime, st_mtime, st_ctime - časy posledného prístupu, poslednej zmeny práv, vlastníka skupiny alebo obsahu a čas poslednej zmeny obsahu

Vytvorenie súboru sa dá tradičnou cestou pomocou open() prípadne fopen() alebo použitím funkcie mknod().

Na jej použitie potrebujeme hlavičkové súbory
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

Deklarácia funkcie je:
int mknod(const char *pathname, mode_t mode, dev_t dev);

Vytvorí súbor s menom pathname pričom ak súbor existuje, vráti chybu. Vytvára vlastne hardlink (prvý), ak sa jedná o súbor. V reále vytvára uzol(node) vo filesystéme. Keďže v *nixe je súbor základný koncept, ktorý predstavuje obecne ľubovolnú vec (súbor, socket, zariadenie, pipu...), pomocou tejto funkcie sa realizuje práve toto.

Parameter const char *pathname je cesta k súboru
Parameter mode_t mode sa použije pri nastavení prístupových práv a aký druh uzlu aký sa má vytvoriť (súbor, adresár, zariadenie).
Medzi ne patria S_IFREG(normálny súbor), S_IFCHR(znakové zariadenie), S_IFBLK(blokové zariadenie), S_IFIFO(pomenovaná pipa), S_IFSOCK(socket). Skutočné prístupové práva sa nastavia tak, že bity v premennej prostredia umask sa v parametre mode odmaskujú ( čize mask & (~umask) sú je reálne aplikovaný).

Hodnotu premennej umask môžete nastaviť pomocou funkcie

mode_t umask(mode_t mask);


V prípade vytvorenia zariadenia sa zohľadňuje parameter dev_t dev ktorý určuje minor a major číslo zariadenia. Inak sa ignoruje.

V prípade chyby vráti hodnotu -1 a v prípade úspechu 0. V prípade chyby sa errno naplní jednou z nasledujúcich hodnôt.

EACCES - jeden z adresárov v ceste nedovolil procesu zápis
EEXIST - súbor už existuje
EFAULT -
chyba v parametre path
EINVAL -
chyba v parametroch
ELOOP -
príliž veľa symbolických linkov v pathname
ENAMETOOLONG -
príliš dlhý pathname
ENOENT -
položka v pathname neexistuje alebo je nefunkčný symlink
ENOMEM - nedostatok pamäte v kerneli (fakt prúser)
ENOSPC -
nedá sa vytvoriť uzol na danom zariadení, z dôvodu nedostatku miesta
ENOTDIR - položka v pathname ktorá by mala byť adresárom nieje adresár
EPERM - ak nieje v danom filesysteme podpora pre vytvorenie daného uzlu, prípadne vlastník procesu nieje privilegovaný daný druh uzlu vytvoriť
EROFS - zápis do read-only filesystemu

Funkcia
int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);

má rovnaké použitie, s tým rozdielom, že sa súbor vytvára relatívne k adresáru uvedenom pomocou parametru int dirfd.

Keď už sme as tak rozrozprávali o prístupových právach, nejde nespomenúť funkcie chmod() a chown().

int chmod(const char *path, mode_t mode);

int fchmod(int fildes, mode_t mode);


Funkcia chmod() zmení prístupové práva k súboru.
Chyby v errno
EACCES, EFAULT, ELOOP, ENAMETOOLONG, ENOENT, ENOMEM, ENOTDIR, EPERM, EROFS sú rovnaké ako vyššie spomenuté chyby
Naviac sa vyskytuje chyba EIO(nejaká I/O chyba) a EBADF(zle zadaný parameter int filedes)

Pre použitie funckie chown()
treba hlavičkové súbory
#include <sys/types.h>
#include <unistd.h>
Deklarácia funkcie je nasledovná:

int chown(const char *path, uid_t owner, gid_t group);

int fchown(int fd, uid_t owner, gid_t group);

int lchown(const char *path, uid_t owner, gid_t group);

Pričom funkcia lchown() pracuje so symlinkami a funkcia chown() so súbormi na ktoré ukazujú.


Funkcia vracia rovnkú množinu chýb ako v prípade chmod() a zmení aktuálneho vlastníka a skupinu ktorej je vlastník členom.

Ďalej si povieme o tom ako vytvoriť adresár, pomenovnú pipu, nový hardlink, a symlink. Funkcie na vytvorenie pomenovnej pipy(mkfifo()) a adresáru(mkdir())sú viacmenej rovnaké, takže ich preberieme jedným dychom.

Na ich použitie treba hlavičkové súbory
#include <sys/stat.h>
#include <sys/types.h>

a deklarácie týchto funkcií su nasledovné
int mkdir(const char *pathname, mode_t mode);
int mkfifo(const char *pathname, mode_t mode);

ich použitie i návratové chybové hodnoty v errno sú rovnaké ako v prípade funkcie mknod(), s tým rozdielom, že parameter mode obsahuje len prístupové práva v už spomenutom schémate.

Vytvorenie hardlinku(link()) a symlinku(symlink()) je tiež viacmenej identické.

Treba použit hlavičkový súbor
#include <unistd.h>
A deklarácie funkcií vyzerajú nasledovne:

int symlink(const char *oldpath, const char *newpath);

int link(const char *oldpath, const char *newpath);

Funkcie vytvoria hard/sym link zo súboru reprezentovaného parametrom oldpath v súbore reprezentovanom parametrom newpath.

Chyby sú zas rovnakého charakteru ako v prípade mknod().


Väčšina z vás si uź určite všimla, že vyššie spomenuté funkcie sú viacmenej len zjednodušením volania funkcie mknod(). No čo by programátor pre uľahčenie a sprehľadnenie práce neurobil. ^_^

V nasledujúcom článku si povieme o funkciách pomocou ktorých sa súborov prípadne adresárov môžme zbaviť a ako sa v adresárovej štruktúre pohybovať. Povieme si aj niečo o zámkoch a o mapovaní súborov do pamäte, ale to až nabudúce.

Neprehliadnite: