4. Sisteme de fisiere. Apeluri sistem si functii de biblioteca pentru
lucrul cu fisiere si directoare

1. Sisteme de fisiere

Fiecare sistem de operare are un mod propriu de organizare si exploatare a informatiei stocate pe suporturile de memorare fizice. Principiile, regulile si structurile care realizeaza acest lucru compun sistemul de fisiere caracteristic sistemului de operare respectiv.

In general, din punctul de vedere al utilizatorului, sistemele de fisiere prezinta o organizare bazata pe conceptele de fisier si director (catalog). Fisierele sunt entitati care incapsuleaza informatia de un anumit tip, iar directoarele grupeaza in interiorul lor fisiere si alte directoare. Orice fisier sau director poate fi identificat prin numele sau, indicat in mod absolut, ca nume de cale sau relativ, fata de directorul curent.

In cazul discurilor fixe (hard-disk-uri) si in cel al dischetelor, informatia se memoreaza folosind proprietatile magnetice ale acestora. Hard-disk-ul contine in interior mai multe platane ce pot memora informatie, iar discheta este formata dintr-un singur disc flexibil (cu ambele fete magnetizate). O fata a unui disc este impartita in piste, care sunt cercuri concentrice in care poate fi memorata informatia. Pistele sunt impartite la randul lor in sectoare, un sector memorand o cantitate fixa de informatie (de obicei 512 octeti). Citirea si scrierea informatiei pe un disc se face la nivel de  blocuri de date. Un bloc (cluster)  poate fi format dintr-un singur sector (cum se intampla la dischete) sau din mai multe (ca la hard-disk-uri).

Un hard-disk poate fi impartit de utilizator in partitii, fiecare partitie comportandu-se, la nivel utilizator, ca un disc de sine statator. Partitia memoreaza sistemul de fisiere, de unde rezulta ca pe acelasi disc fizic pot fi intalnite mai multe sisteme de fisiere. Pentru calculatoarele personale obisnuite (PC), informatiile referitoare la partitii se memoreaza la inceputul discului, in asa-numita tabela de partitii. Aceasta contine 4 intrari in care memoreaza pozitiile, dimensiunile si tipurile partitiilor de pe disc. Partitiile memorate tabela de la inceputul discului se numesc partitii primare, care pot fi, evident, cel mult 4 la numar. Este posibil, insa, ca in interiorul oricarei partitii primare sa se creeze cate o noua tabela de partitii, referind partitii care fizic se afla in interiorul partitiei curente si care se numesc partitii extinse.

In cele ce urmeaza, vom trece in revista principalele caracteristici ale sistemelor de fisiere caracteristice pentru doua sisteme de operare: MS-DOS (Windows) si Unix.  

1.1 Sistemul de fisiere in MS-DOS

1.1.1 Organizarea discurilor in MS-DOS

Primul sector al partitiei sau discului care contine sistemul se numeste sectorul de boot. Acesta contine urmatoarele informatii:
 
 
Offset Dimensiune (octeti) Continut
+00h 3 JMP adresa. Salt la rutina de incarcare a sistemului de operare
+03h 8 Numele producatorului si versiunii
+0Bh 2 Numarul de octeti pe sector
+0Dh 1 Numarul de sectoare pe cluster
+0Eh 2 Numarul de sectoare rezervate (inaintea FAT)
+10h 1 Numarul de FAT-uri
+11h 2 Numarul maxim de intrari in directorul radacina
+13h 2 Numarul total de sectoare
+15h 1 Media descriptor
+16h 2 Numarul de sectoare dintr-un FAT
+18h 2 Numarul de sectoare pe pista
+1Ah 2 Numarul de capete de citire/scriere
+1Bh 2 Numarul de sectoare ascunse
+1Dh ... Codul de bootare

Directoarele sunt memorate ca structuri speciale, ca tabele in care fiecare intrare reprezinta un fisier. De fapt, un director este memorat ca un fisier obisnuit, dar care contine informatii despre alte fisiere. Exista un director radacina, memorat dupa tabela de alocare a fisierelor (FAT), care are o dimensiune limitata.

Structura unei intrari in director este:
 
Offset Dimensiune Continut
+00h 8 Numele fisierului
+08h 3 Extensia numelui de fisier
+0Bh 1 Atribute
+0Ch 0Ah Rezervat
+16H 2 Ora ultimei modificari a fisierului
+18h 2 Data ultimei modificari a fisierului
+1Ah 2 Numarul primului cluster ocupat de fisier
+1Ch 4 Dimensiunea fisierului (in octeti)

Tabela de alocare a fisierelor (File Allocation Table - FAT)

FAT este o structura care este folosita pentru localizarea datelor care apartin unui fisier. Ea este, de fapt, o structura de tip tablou care memoreaza in interiorul ei liste inlantuite care indica clustererele ce compun fisierele. Fiecare locatie din FAT are 12 biti la dischete, 16 biti la partitiile MS-DOS obisnuite (FAT16) si 32 biti la partitiile FAT32 recunoscute de catre Windows 95 OSR2 si Windows 98. Primul octet din FAT contine un octet de identificare numit media descriptor. Urmatorii 5 octeti (FAT12) sau 7 octeti (FAT16) sau 15 octeti (FAT32) contin valoarea 0FFh.

Celelalte intrari din FAT corespund fiecare unui cluster de pe disc (clusterele se numara de la spatiul imediat urmator FAT-ului). Astfel, intrarea 1 din FAT corespunde clusterului 1, intrarea 2 clusterului 2, s.a.m.d.

Fiecare intrare in FAT memoreaza numarul urmatorului cluster din fisierul din care face parte clusterul care corespunde intrarii. Numarul primului cluster al unui fisier este memorat, dupa cum s-a vazut deja, in intrerea in director corespunzatoare fisierului respectiv. Se vede ca numarul de biti pe care este reprezentata o intrare in FAT limiteaza, astfel, numarul maxim de clustere pe disc.

Exemplu: Fie fisierul abc.txt care incepe in clusterul 5 si fisierul xyz.exe care incepe in clusterul 4. O posibila organizare a spatiului ocupat de aceste fisiere este prezentata mai jos:


.
 

1.2 Sistemul de fisiere in UNIX

1.2.1 Organizarea discurilor in Unix

Spatiul fiecarei partitii Unix contine urmatoarele zone:
 
Bloc
Incarcare
Super-bloc Zona noduri
index
Swapping Continut

  • Blocul de incarcare (boot block)contine programele care realizeaza incarcarea partii rezidente a sistemului de operare Unix.
  • Superblocul contine informatii generale despre sistemul de fisiere de pe disc: inceputul zonelor urmatoare, inceputul zonelor libere de pe disc.
  • Zona de noduri index are o dimensiune fixata la creareea sistemului de fisiere si contine cate o intrare pentru fiecare fisier ce poate fi creat pe acest suport
  • Zona pentru swapping (daca exista) este rezervata pentru pastrarea imaginilor proceselor atunci cand sunt eliminate temporar din memorie pentru a face loc altor procese. De obicei, insa, pentru zona de swap se folosesc partitii distincte.
  • Ultima zona contine blocurile care memoreaza fisierele propriu-zise.
Intrarile in director au o structura foarte simpla, continand doar doua campuri:
  • numele fisierului
  • numarul nodului index asociat fisierului
1.2.1.1 Structura nodurilor index

Un nod index (i-node) contine informatiile esentiale despre fisierul caruia ii corespunde. Exista cate un singur nod index pentru fiecare fisier. Este posibil sa intalnim mai multe intrari in director indicand acelasi nod index (sistemul de fisiere din Unix accepta crearea de legaturi multiple).

Informatia din nodul index cuprinde:

  • identificatorul utilizatorului: uid (user-id.). Identifica proprietarul fisierului
  • identificatorul de grup al utilizatorului
  • drepturile de acces la fisier. Drepturile sunt de trei tipuri (r-read, w-write, x-execute)  si sunt grupate pe trei categorii:
    • user - drepturile proprietarului fisierului
    • group - drepturile utilizatorilor din grupul proprietarului
    • others - drepturile tuturor celorlalti utilizatori
  • timpul ultimului acces la fisier
  • timpul ultimei actualizari a fisierului
  • timpul ultimului acces pentru actualizarea nodului index
  • codul fisierului (tipul fisierului). Fisierele pot fi: fisiere obisnuite (-), directoare (d), periferice (c) etc.
  • lungimea fisierului (in octeti)
  • contorul de legaturi al fisierului. Reprezinta numarul de legaturi existente spre acest nod index. Este utilizat la operatia de stergere a nodului index.
  • lista de blocuri care contin fisierul
Lista de blocuri de pe disc care contin fisierul se realizeaza printr-un tablou cu 13 intrari. Primele 10 intrari contin direct adresele de bloc (cluster) pentru primele 10 blocuri ale fisierului. A unsprezecea intrare din aceasta lista este adresa unui bloc, rezervat fisierului, al carui continut este, insa, interpretat ca lista de adrese de blocuri. Se spune ca aceste blocuri sunt adresate prin indirectare simpla. Intrarea a 12-a contine un bloc al carui continut consta in adrese de blocuri, care acestea contin adrese de blocuri de date (indirectare dubla). In mod analog, intrarea cu numarul 13 determina o indirectare tripla.


 

1.2.2 Legaturi si fisiere speciale

Sistemul de fisiere din UNIX permite crearea asa-numitelor legaturi la fisiere. O asemenea legatura (link) este vazuta de catre utilizator ca un fisier cu un nume propriu, dar care in realitate refera un alt fisier de pe disc. Orice operatie care se executa asupra fisierului legatura (mai putin stergerea) isi va avea efectul de fapt asupra fisierului indicat de legatura. Daca este solicitata stergerea, efectul depinde de tipul legaturii respective.

Legaturile sunt de doua tipuri:

  • fizice (hard links)
  • simbolice (symbolic links)
Legaturile din prima categorie se realizeaza prin introducerea de intrari in director care pointeaza spre acelasi nod index, si anume cel al fisierului indicat. Cand spre fisier este stearsa si ultima intrare in director care il indica, fisierul in sine va fi sters si el. Legaturile de acest tip au dezavantajul ca nu pot indica nume de directoare si nici fisiere din alte partitii decat cea pe care se afla.

Legaturile simbolice sunt de fapt fisiere distincte, marcate cu un cod special, care au ca si continut numele complet al fisierului indicat. Stergerea lor nu afecteaza fisierul. Pot referi directoare, precum si fisiere si directoare din alta partitie sau alt disc, dar au dezavantajul ca pentru ele (fiind fisiere) trebuie creat un nod index separat si, in plus, ocupa spatiu pe disc prin continutul lor.

Crearea legaturilor spre fisiere sau directoare se face cu ajutorul comenzii ln.

  • ln fisier_indicat nume_legatura - creeaza o legatura "fizica"
  • ln -s fisier_indicat nume_legatura - creeaza o legatura simbolica
  • Pe langa legaturi, in Unix exista si alte fisiere speciale. Tipul acestora poate fi observat citind primul caracter afisat de comanda ls -l

    Astfel, avem:

    1. Fisiere obisnuite
    2. Directoare. Dupa cum am vazut, sunt fisiere care, avand un format special, grupeaza fisiere
    3. Fisiere speciale care corespund unor dispozitive orientate pe caractere
    4. Fisiere speciale care corespund unor dispozitive orientate pe blocuri
    5. Fisiere FIFO
    6. Legaturi simbolice
    Fisierele speciale evidentiate la punctele 3 si 4 reprezinta metoda prin care sistemul Unix abstractizeaza dispozitivele de intrare-iesire si alte dipozitive din sistemul de calcul. Toate aceste fisiere se gasesc in directorul /dev.

    Spre exemplu, fiecarei unitati de disc ii corespunde cate un fisier in directorul /dev. In Linux, primei unitati de dischete ii corespunde fisierul /dev/fd0, celei de-a doua /dev/fd1, s.a.m.d. Primului hard-disk cu interfata IDE din sistem ii corespunde fisierul special /dev/hda, iar primei sale partitii fisierul /dev/hda1. A doua partitie de pe primul disc are ca si corespondent fisierul /dev/hda2, al doilea hard-disk IDE se refera cu /dev/hdb, s.a.m.d.
     

    1.2.3 Montarea sistemelor de fisiere

    Fisierele speciale care indica unitati de disc sau partitii sunt folosite in operatia numita montare a sistemelor de fisiere. Sistemul de operare Unix permite montarea intr-un director a unui sistem de fisiere aflat pe un disc sau o partitie. Aceasta inseamna ca, dupa montare, in directorul respectiv se va afla intreaga structura de fisiere si directoare de pe sistemul de fisiere respectiv. Mecanismul este deosebit de puternic, deoarece ofera posibilitatea de a avea o structura de directoare unitara, care grupeaza fisiere de pe mai multe partitii sau discuri. Daca se adauga si sistemul de fisiere NFS (Network File System), aceasta structura de directoare va putea contine si sisteme de fisiere montate de la distanta (de pe alta masina)

    Montarea unui sistem de fisiere se face cu comanda mount. Data fara nici un parametru, ea afiseaza sistemele de fisiere montate in momentul respectiv in sistem. O alta forma a ei este urmatoarea:
     

    mount fisier-special director
    care monteaza un disc sau o partitie intr-un director dat; sau
    mount -t tip fisier-special director
    cu acelasi efect, doar ca se specifica in clar tipul sistemului de fisiere care se monteaza. Diferitele variante de Unix cunosc mai multe sau mai putine tipuri de sisteme de fisiere. Spre exemplu, Linux cunoaste, printre altele, urmatoarele:
    • minix - sistemul de fisiere al sistemului de operare MINIX
    • ext2 - Second-Extended File System - sistemul caracteristic Linux
    • msdos - sistemul de fisiere DOS FAT16 sau FAT12
    • vfat - sistemul de fisiere DOS cu extensia pentru nume lungi introdusa de Windows 95
    • iso9660 - sistem de fisiere pentru CD-ROM (cel mai raspandit) cu o serie de extensii ale sale
    • proc - un sistem de fisiere virtual ale carui componente furnizeaza informatii despre starea sistemului
    De obicei, montarea de sisteme de fisiere poate fi facuta numai de catre utilizatorul root (cel mai privilegiat utilizator, administratorul sistemului), dar se poate permite si utilizatorilor obisnuiti sa monteze anumite partitii sau unitati de disc.

    Exemplu:

    Montarea unei dischete introdusa in prima unitate de dischete, care contine si fisiere cu nume lungi create in Windows se face astfel
     

    mount /dev/fd0 diskA
    unde diskA este numele directorului in care se va monta discheta, aflat in directorul curent.

    Important: Orice sistem de fisiere montat de pe o unitate de disc care permite inlaturarea discului respectiv trebuie demontat inainte de a scoate discul. De asemenea, inainte de inchiderea sau repornirea calculatorului, trebuie de-montate si sistemele de fisiere de pe discurile fixe (in Linux, aceasta din urma operatie se efectueaza automat la restartarea sistemului prin apasarea simultana a tastelor Ctrl+Alt+Del). De-montarea fisierelor se face cu comanda
     

    umount fisier-special
    sau
    umount director
    (unde director este numele directorului in care a fost montat sistemul de fisiere).

    2. Apeluri sistem si functii de biblioteca pentru lucrul cu fisiere

    Orice sistem de operare pune la dispozitia programatorilor o serie de servicii prin intermediul carora acestora li se ofera acces la resursele hardware si software gestionate de sistem: lucrul cu tastatura, cu discurile, cu dispozitivul de afisare, gestionarea fisierelor si directoarelor etc. Aceste servicii se numesc apeluri sistem. De cele mai multe ori, operatiile pe care ele le pot face asupra resurselor gestionate sunt operatii simple, cu destul de putine facilitati. De aceea, frecvent, se pot intalni in bibliotecile specifice limbajelor de programare colectii de functii mai complicate care gestioneaza resursele respective, dar oferind programatorului niveluri suplimentare de abstractizare a operatiilor efectuate, precum si importante facilitati in plus. Acestea sunt functiile de biblioteca. Trebuie subliniat faptul ca functiile de biblioteca cu ajutorul carora se poate gestiona o anumita resursa sunt implementate folosind chiar functiile sistem corespunzatoare, specifice sistemului de operare.

    In acest document vor fi prezentate functiile sistem pe care le pun la dispozitie sistemele de operare MS-DOS si UNIX pentru lucrul cu fisiere. Se va presupune in continuare ca limbajul de programare utilizat este C si ca sunt cunoscute toate caracteristicile si facilitatile acestui limbaj. Vor fi trecute in revista, de asemenea, cateva functii de biblioteca C care servesc aceluiasi scop.  

    2.1 Apeluri sistem pentru lucrul cu fisiere

    Apelurile sistem care vor fi discutate aici sunt caracteristice atat sistemului de operare UNIX cat si MS-DOS. Operatiile care pot fi aplicate fisierelor folosind aceste functii se refera la deschiderea fisierelor, scrierea si citirea de blocuri de date in si din fisiere, mutarea si copierea fisierelor etc.

    Pentru a putea actiona asupra unui fisier, este nevoie inainte de toate de o metoda de a identifica in mod unic fisierul. In cazul functiilor discutate, identificarea fisierului se face printr-un asa-numit descriptor de fisier (file descriptor). Acesta este un numar intreg care este asociat fisierului in momentul deschiderii acestuia.

    2.1.1 Functiile open si close

    Deschiderea unui fisier este operatia prin care fisierul este pregatit pentru a putea fi prelucrat in continuare. Aceasta operatie se realizeaza prin intermediul functiei open:

    int open(const char *pathname, int oflag, [, mode_t mode]);
    Functia returneaza -1 in caz de eroare. In caz contrar, ea returneaza descriptorul de fisier asociat fisierului deschis.
    Parametri:
    • pathname - contine numele fisierului
    • oflag - optiunile de deschidere a fisierului. Este, in realitate un sir de biti, in care fiecare bit sau grupa de biti are o anumita semnificatie. Pentru fiecare astfel de semnificatie exista definite in fisierul header C fcntl.h cate o constanta. Constantele se pot combina folosind operatorul '|' (sau logic pe biti) din C, pentru a seta mai multi biti (deci a alege mai multe optiuni) in parametrul intreg oflag. Iata cateva din aceste constante:
      • O_RDONLY - deschidere numai pentru citire
      • O_WRONLY - deschidere numai pentru scriere
      • O_RDWR - deschidere pentru citire si scriere
      • O_APPEND - deschidere pentru adaugare la sfarsitul fisierului
      • O_CREAT - crearea fisierului, daca el nu exista deja; daca e folosita cu aceasta optiune, functia open trebuie sa primeasca si parametrul mode.
      • O_EXCL - creare "exclusiva" a fisierului: daca s-a folosit O_CREAT si fisierul exista deja, functia open va  returna eroare
      • O_TRUNC - daca fisierul exista, continutul lui este sters
    • mode - se foloseste numai in cazul in care fisierul este creat si specifica drepturile de acces asociate fisierului. Acestea se obtin prin combinarea unor constante folosind operatorul sau ('|'), la fel ca si la optiunea precedenta. Constantele pot fi:
      • S_IRUSR - drept de citire pentru proprietarul fisierului (user)
      • S_IWUSR - drept de scriere pentru proprietarul fisierului (user)
      • S_IXUSR - drept de executie pentru proprietarul fisierului (user)
      • S_IRGRP - drept de citire pentru grupul proprietar al fisierului
      • S_IWGRP - drept de scriere pentru grupul proprietar al fisierului
      • S_IXGRP - drept de executie pentru grupul proprietar al fisierului
      • S_IROTH - drept de citire pentru ceilalti utilizatori
      • S_IWOTH - drept de scriere pentru ceilalti utilizatori
      • S_IROTH - drept de executie pentru ceilalti utilizatori
    Pentru crearea fisierelor poate fi folosita si functia
    creat (const char *pathname, mode_t mode)
    echivalenta cu specificarea optiunilor O_WRONLY | O_CREAT | O_TRUNC la functia open.

    Dupa utilizarea fisierului, acesta trebuie inchis, folosind functia

    int close (int filedes)
    in care filedes este descriptorul de fisier obtinut la open.  

    2.1.2 Functiile read si write

    Citirea datelor dintr-un fisier deschis se face cu functia

    ssize_t read(int fd, void *buff, size_t nbytes)
    Functia citeste un numar de exact nbytes octeti de la pozitia curenta in fisierul al carui descriptor este fd si ii pune in zona de memorie indicata de pointerul buff.
    Este posibil ca in fisier sa fie de citit la un moment dat mai putin de nbytes octeti (de exemplu daca s-a ajuns spre sfarsitul fisierului), astfel ca functia read va pune in buffer doar atatia octeti cati poate citi. In orice caz, functia returneaza numarul de octeti cititi din fisier, deci acest lucru poate fi usor observat.

    Daca s-a ajuns exact la sfarsitul fisierului, functia returneaza zero, iar in caz de eroare, -1.

    Scrierea datelor se face cu
     

    ssize_t write(int fd, void *buff, size_t nbytes)
    Functia scrie in fisier primii nbytes octeti din bufferul indicat de buff. Returneaza -1 in caz de eroare.  

    2.1.3 Functia lseek

    Operatiile de scriere si citire in si din fisier se fac la o anumita pozitie in fisier, considerata pozitia curenta. Fiecare operatie de citire, de exemplu, va actualiza indicatorul pozitiei curente incrementand-o cu numarul de octeti cititi. Indicatorul pozitiei curente poate fi setat si in mod explicit, cu ajutorul functiei lseek:

    off_t lseek(int fd, off_t offset, int pos)
    Functia pozitioneaza indicatorul la deplasamentul offset in fisier, astfel:
    • daca parametrul pos ia valoarea SEEK_SET, pozitionarea se face relativ la inceputul fisierului
    • daca parametrul pos ia valoarea SEEK_CUR, pozitionarea se face relativ la pozitia curenta
    • daca parametrul pos ia valoarea SEEK_END, pozitionarea se face relativ la sfarsitul fisierului
    Parametrul offset poate lua si valori negative si reprezinta deplasamentul, calculat in octeti.

    In caz de eroare, functia returneaza -1.  

    2.1.4 Alte functii

    • int mkdir(const char *pathname, mode_t mode) - creeaza un director
    • int rmdir(const char *pathname) - sterge un director
    Observatie: La orice folosire a unei functii sistem este foarte important sa se testeze valoarea returnata de aceasta. Daca apelul functiei s-a incheiat cu eroare, programul trebuie sa recunoasca acest caz si sa actioneze in consecinta, de exemplu prin tiparirea unui mesaj de eroare si eventual terminarea executiei.

    2.2 Functii de biblioteca

    In biblioteca standard C exista cateva functii pentru gestionarea fisierelor. Acestea folosesc pentru identificarea fisierelor un descriptor reprezentat de o structura de date, FILE.  

    2.2.1 Deschiderea si inchiderea unui fisier

    FILE *fopen(const char *filename, const char *mode)
    Functia deschide fisierul indicat prin filename, creeaza o structura FILE continand informatii despre fisier si returneaza un pointer catre aceasta. Acest pointer va fi elementul care va putea fi folosit in continuare pentru accesarea fisierului. Parametrul mode este un sir de caractere care indica modul de deschidere a fisierului. "r" semnifica deschidere pentru citire, "w" deschidere pentru scriere. Poate fi specificat si tipul fisierului: "t" pentru fisier text, "b" pentru fisier binar. Optiunile pot fi combinate, de exemplu sub forma "r+t".

    Inchiderea fisierului se face cu

    fclose(FILE *stream)
    unde stream este pointerul spre structura FILE obtinut la deschiderea fisierului.  

    2.2.2 Operatii asupra fisierelor

    • int fprintf(FILE *stream, const char *format, ...); - scriere in fisier cu formatare; sirul de caractere care specifica formatul este similar celui de la instructiunea printf.
    • int fscanf(FILE *stream, const char *format, ...); - citire din fisier, asemanator cu functia scanf.
    • size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); - citeste din fisierul indicat de stream un numar de nmemb elemente, fiecare de dimensiunea size, si le pune in zona de memorie indicata de ptr.
    • size_t fwrite( void *ptr, size_t size, size_t nmemb,  FILE *stream); - scrie in fisierul indicat de stream un numar de nmemb elemente, fiecare de dimensiunea size, pe care le ia din zona de memorie indicata de ptr.
    Consultati paginile de manual corespunzatoare apelurilor sistem si functiilor de biblioteca discutate, precum si functiilor inrudite cu acestea. Apelurile sistem sunt tratate in sectiunea 2 a manualului Unix (man 2 nume_functie), iar functiile de biblioteca in sectiunea 3.  

    3. Gestionarea directoarelor

    Accesul la informatiile memorate in directoare se face cu ajutorul unor functii speciale, cu ajutorul carora se pot afla numele fisierelor continute si informatii despre acestea (dimensiune, data crearii, drepturile aferente etc).

    Daca in ceea ce priveste gestionarea fisierelor puteau fi intalnite aspecte comune in cazurile sistemelor de operare DOS si UNIX, modul in care se exploateaza directoarele (din perspectiva programatorului) difera substantial.  

    3.1 Gestionarea directoarelor in MS-DOS

    3.1.1 Functiile findfirst si findnext

    Aceste functii utilizeaza ca intermediar o structura de date numita struct ffblk, care contine informatii despre un anumit fisier:

      struct ffblk {
          char ff_reserved[21];
          char ff_attrib; /*atributele fisierului*/
          int ff_ftime; /*timpul crearii fisierului*/
          int ff_fdate; /*data crearii fisierului*/
          long ff_fsize; /*dimensiunea fisierului (in octeti)*/
          char ff_fname[13]; /*numele si extensia fisierului (cu punct)*/
      }

    • int findfirst(const char *pathname, struct ffblk *ffblk, int attrib)
      • Gaseste primul fisier care se potriveste tiparului dat in pathname (tipar care poate contine caracterele * si ?) si initializeaza structurile de date    folosite intern de catre functiile de cautare de fisiere. Functia  va completa o structura ffblk cu  informatii despre primul fisier gasit.  Adresa acestei structuri trebuie data de catre utilizator in parametrul ffblk.  Parametrul attrib specifica atributele de cautare. (Pentru mai multe detalii, consultati help-urile compilatoarelor de C pentru MS-DOS).
    • int findnext(struct ffblk *ffblk)
      • Primul fisier care corespunde unui anumit tipar poate fi gasit cu findfirst. Urmatoarele fisiere care corespund aceluiasi tipar pot fi gasite apeland succesiv functia findnext. Aceasta primeste ca parametru structura ffblk folosita la findfirst, va gasi fisierul cautat si va completa structura ffblk cu informatiile specifice fisierului gasit.

    3.2. Gestionarea directoarelor in UNIX

    3.2.1. Aflarea atributelor fisierelor

     int stat(const char *file_name, struct stat *buf);
     int fstat(int filedes, struct stat *buf);
     int lstat(const char *file_name, struct stat *buf);
    Functia stat primeste ca parametru un nume de fisier (cale) si scrie o structura stat la adresa buf, care contine informatii despre fisierul respectiv. Structura stat are urmatoarea forma:
                 struct stat
                  {
                      dev_t         st_dev;      /* device */
                      ino_t         st_ino;      /* inode */
                      umode_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 */
                      unsigned long st_blksize;  /* blocksize for filesystem I/O */
                      unsigned long 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 */
                  };

    Pointerul care indica zona de memorie in care functia stat va returna aceste informatii trebuie dat ca al doilea parametru al functiei. Zona de memorie trebuie in prealabil rezervata (prin malloc) pentru a putea memora structura stat.

    Functia fstat are acelasi efect, cu deosebirea ca ea primeste ca argument un descriptor de fisier, si nu numele acestuia, deci se poate aplica doar fisierelor in prealabil deschise.

    Functia lstat este asemanatoare cu stat, cu diferenta ca, daca este aplicata unei legaturi simbolice, informatiile returnate se vor referi la legatura, si nu la fisierul indicat.  

    3.2.2 Functii de biblioteca pentru citirea directoarelor

    Directoarele sunt, in esenta, fisiere cu un format special. Sistemul de operare UNIX pune la dispozitia programatorului un set de apeluri sistem care ofera posibilitatea de a citi continutul directoarelor, accesand astfel informatii despre fisierele si directoarele continute. Folosind aceste apeluri sistem, biblioteca standard C defineste un set de functii care se conformeaza standardului POSIX si care ofera aceleasi facilitati. Fiind recomandabil sa se utilizeze, in locul apelarii directe a functiilor sistem, functiile de biblioteca , in continuare vor fi prezentate numai acestea din urma.
     

    DIR *opendir(const char *name);
    struct dirent *readdir(DIR *dir);
    void rewinddir(DIR *dir);
    int closedir(DIR *dir);
    Conform specificatiilor POSIX, structura dirent contine un camp
    char d_name[];
    de dimensiune nespecificata, cu cel mult  NAME_MAX charactere exclusiv caracterul de terminare (NULL).  Folosirea altor campuri existente in aceasta structura dauneaza portabilitatii programului. Campul d_name contine numele unei intrari in director (nume de fisier, director etc.).

    Structura DIR este o structura utilizata intern de cele patru functii. Structura va fi returnata (initializata) de opendir si trebuie transmisa ca parametru celorlalte functii.

    Inspectarea fisierelor dintr-un director se face astfel:

    • se "deschide" directorul dorit cu functia opendir.
    • se citeste, pe rand, cate o intrare in director, apeland succesiv functia readdir. Fiecare apel al aceste functii va returna un pointer la o structura dirent, in care se vor gasi informatii despre intrarea in director citita. Intrarile in director vor fi parcurse, astfel, una dupa alta, pana cand se ajunge la ultima intrare. In momentul in care nu mai exista intrari in director de citit, functia readdir va returna NULL. De asemenea, in caz de eroare, functia va returna tot NULL, dar atunci va si pozitiona valoarea lui errno in mod corespunzator.

      Dupa cum a fost aratat mai sus, singura informatie care poate fi extrasa (conform POSIX) din structura dirent este numele intrarii in director. Toate celelalte informatii despre intrarea citita se pot afla apeland in continuare functiile stat, fstat sau lstat.

    • in final. directorul este inchis, folosind closedir.
    Consultati paginile de manual corespunzatoare acestor functii.

    Anexa: Alte functii pentru lucrul cu directoare si fisiere

    Consultati paginile de manual corespunzatoare urmatoarelor functii, precum si cele ale functiilor inrudite:
    • int link(const char *oldpath, const char *newpath); - creeaza legaturi fixe spre fisiere
    • int symlink(const char *oldpath, const char *newpath); -  creeaza legaturi simbolice spre fisiere sau directoare
    • int unlink(const char *pathname); -  sterge o intrare in director (legatura, fisier sau director)
    • int rename(const char *oldpath, const char *newpath); - redenumire / mutare de fisiere
    • int rmdir(const char *pathname); -  stergere de directoare
    • int chdir(const char *path); - schimbarea directorului curent
    • char *getcwd(char *buf, size_t size); - determinarea directorului curent

    Tema pentru acasa:

    Sa se scrie un program C pentru Unix, apelabil din linia de comanda astfel:

    copytree cale1 cale2
    care copiaza directorul cale1, cu tot subarborele sau de directoare in destinatia cale2. Daca exista deja cale2, se va genera un mesaj de eroare. Daca in sursa sunt intalnite legaturi simbolice, la destinatie se vor crea legaturi simbolice care refera acelasi fisier ca originalul (nu se copiaza fisierul indicat!).

      


    Autor: Dan Cosma