3. týždeň

Práca so súbormi II, práca s adresármi a prístupové práva

Ciele

  1. Spoznať možnosti presmerovania vstupu a výstupu
  2. Získanie informácii o súbore
  3. Spoznať typy súborov a ich možnosti
  4. Prístupové práva súborov

Postup

Krok 1: Duplikovanie, priradenie deskriptora súboru

Príprava

Stiahnite si archív k cvičeniu .

Obsah archívu.

.
└── 03
    ├── Makefile
    ├── o6-4.c
    ├── prepare-03.sh
    ├── pr1-1.c
    ├── pr1-2.c
    ├── pr1-3.c
    ├── pr2-2.c
    ├── pr4-1.c
    ├── remove-03.sh
    ├── tests
    │   ├── u1-1-test.sh
    │   ├── u1-2-test.sh
    │   ├── u2-2-test.sh
    │   ├── u3-2-test.sh
    │   ├── u6-3-test.sh
    │   └── u6-4-test.sh
    ├── u1-1.c
    ├── u1-2.c
    ├── u1-2R.c
    ├── u2-2.c
    ├── u3-2.c
    ├── u3-3.c
    ├── u5-4.c
    ├── u6-3.c
    └── u6-4.c

Pracujte v adresári pomenovanom podľa cvičenia napr. ak pri rozbalení 03.zip vznikne 03, pracujte v adresári 03.

Spustite skript prepare-03.sh, ktorý vytvorí potrebné súbory k cvičeniu: ./prepare-03.sh .

Poznámka

Ak súbor, s ktorým pracuje úloha nechtiac zmeníte, môžete ho nanovo vytvoriť podľa pokynov v časti //príprava uvedenej pri úlohe alebo zmazaním celej štruktúry súborov, s ktorými cvičenie pracuje skriptom remove-02.sh a následne spustením prepare-02.sh

Poznámka

Ak je úloha testovaná, test je možné spustiť nasledovne:
príklad: otestovanie riešenia úlohy 1.1, váš program má názov v tvare u1-1

./tests/u1-1-test.sh 

Príklad - vstup programu - pr1-1

Príklad 1.1
Nasledujúci program, ktorý načítava riadok zo vstupu a vypíše ho s číslom, kým nenarazí na EOF funguje podobne ako:
echo -e "prvý riadok\ndruhý riadok\ntretí riadok" | cat -n

//pr1-1.c
#include <stdio.h>

int main(int argc, char const *argv[])
{
    //maximálny počet znakov v riadku
    int len = 20;                               
    char line[len];
    int number_of_line = 1;
    //načíta riadok zo štandardného vstupu
    while (fgets(line,len,stdin))               
    {
        //očísluje a vypíše riadok
        printf("%d %s",number_of_line, line);   
        number_of_line++;   
    }
    return 0;
}

//výstup 
1 prvý riadok
2 druhý riadok
3 tretí riadok

Vstup je možné zadať ručne alebo ho odniekiaľ presmerovať:

  • vstupom je výstup príkazu:
    echo -e "prvý riadok\ndruhý riadok\ntretí riadok" | ./pr1-1
  • vstupom je súbor:
    ./pr1-1 < input01.txt

Poznámka

Ak je vstup zadávaný ručne, je možné ho ukončiť s CTRL + D.

Upozornenie

Ak ste nechtiac upravili súbory, potrebnú štruktúru môžete vytvoriť nasledujúcim postupom.

//príprava
echo -e "prvý riadok\ndruhý riadok\ntretí riadok" > input01.txt

Teória - dup

Aký by bol postup, ak má byť nastavený súbor ako štandardný vstup priamo v programe? Riešením môže byť nasledujúca služba.

Služba jadra dup()

Základný princíp činnosti dup() je, že zduplikuje deskriptor, ktorý dostane ako argument a duplikát uloží na prvú voľnú pozíciu v tabuľke deskriptorov. Hodnota deskriptora bude preto najnižšie nepoužité číslo.

#include <unistd.h>

int dup (int oldfd);
int dup2 (int oldfd, int newfd);
Parametre Popis
oldfd deskriptor otvoreného súboru
newfd Pri dup2() je hodnota nového deskriptora vopred určená. Ak sa deskriptor s hodnotou newfd používa pre nejaký súbor, ten bude najprv zatvorený.
Ukončenie Návratová hodnota
úspešné nový deskriptor
chyba - 1

Príklad - dup - pr1-2 pr1-3

Všimnite si rozdiel.

Príklad 1.2
Zápis do súboru, ktorý je otvorený dvakrát.

//pr1-2.c
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char const *argv[])
{   
    int fd1;
    int fd2;

    //vytvorenie / otvorenie súboru
    fd1 = open("file02.txt" , O_CREAT | O_WRONLY , S_IRUSR | S_IWUSR); 
    //druhykrat ho netreba vytvorit
    fd2 = open("file02.txt" , O_WRONLY);

    char text[] = "Tento text je zapisany ako prvy.";
    int len = strlen(text);
    write(fd1, text, len);
    write(fd2,"0123456789",10);

    //zatvorenie súboru
    close(fd1);
    close(fd2);

    return 0;
}

//obsah súboru file02.txt po spustení
$ xxd file02.txt 
00000000: 3031 3233 3435 3637 3839 206a 6520 7a61  0123456789 je za
00000010: 7069 7361 6e79 2061 6b6f 2070 7276 792e  pisany ako prvy.

Príklad 1.3
Zápis do súboru, zduplikovanie deskriptora.

//pr1-3.c
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char const *argv[])
{   
    int fd1;
    int fd2;

    //vytvorenie / otvorenie súboru
    fd1 = open("file03.txt" , O_CREAT | O_WRONLY , S_IRUSR | S_IWUSR); 
    //zduplikovanie deskriptora
    fd2=dup(fd1);

    char text[] = "Tento text je zapisany ako prvy.";
    int len = strlen(text);
    write(fd1, text, len);
    write(fd2,"0123456789",10);

    //zatvorený prvý deskriptor
    close(fd1);
    //zatvorený druhý deskriptor    
    close(fd2);

    return 0;
}

//obsah súboru file03.txt po spustení
$ xxd file03.txt 
00000000: 5465 6e74 6f20 7465 7874 206a 6520 7a61  Tento text je za
00000010: 7069 7361 6e79 2061 6b6f 2070 7276 792e  pisany ako prvy.
00000020: 3031 3233 3435 3637 3839                 0123456789

Zduplikovanie deskriptora neznamená, že sa znova otvorí ten istý súbor. Súbor ostane otvorený iba raz. Zostane teda iba jediný ukazovateľ na aktuálnu pozíciu v súbore.

Aktivita - dup - o1-1 o1-2 o1-3

Otázka 1.1

Aká je prípustná hodnota parametra pre dup(oldfd)?

Odoslať odpoveď
Správna odpoveď:
oldfd = 1;
int a = 4;
oldfd = a;

Vysvetlenie: prameter je typu int

Nesprávna odpoveď

Otázka 1.2

Aká bude hodnota premennej newFd po vykonaní časti programu, keď program neskončil s chybou? Aký výstup by ste uvideli v konzole, ak fd = 3?

    int fd = open("file04.txt", O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
    perror("after open");
    close(2);
    int newFd = dup(fd);

    perror("after dup");
    printf("newFd = %d\n", newFd);
Odoslať odpoveď
Správna odpoveď:
after open: Success
newFd = 2

Vysvetlenie: Deskriptor stderr má hodnotu 2. Po zavolaní close(2) bude pozícia 2 v tabuľke deskriptorov prvou voľnou.

Nesprávna odpoveď

Poznámka

Uvažujte kam sa "stratil" výpis funkcie perror()?

Otázka 1.3

Aký je názov súboru, do ktorého je presmerovaný chybový výstup v predchádzajúcej otázke? (Odpoveď uveďte v tvare: "nazov.txt" bez úvodzoviek.)

Správna odpoveď: file04.txt

Vysvetlenie: Funkcia perror() vykonáva výpis na stderr, ktorého hodnota je 2. V programe z otázky je deskriptor s hodnotou 2 priradený súboru file04.txt.

//obsah súboru file04.txt po spustení
$ more file04.txt 
after dup: Success
Nesprávna odpoveď

Aktivita - dup - u1-1

Úloha 1.1

Zduplikujte deskriptor tak, aby hodnota nového deskriptora bola 5. Pracujte so súborom u1-1.c.

//u1-1.c
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char const *argv[])
{
    int fd1;
    int fd2;

    fd1=open("file05.txt" , O_CREAT | O_WRONLY , S_IRUSR | S_IWUSR);
    //zduplikovanie deskriptora
    // DOPLNTE
    fd2=

    printf("fd1 = %d\n", fd1);
    printf("fd2 = %d\n", fd2);

    write(fd1,"abc",3);
    write(fd2, "123", 3);
    //zatvorenie prvy deskriptor
    close(fd1);
    //zatvorenie druhy deskriptor   
    close(fd2);

    return 0;
}
//očakávaný výstup
fd1 = 3
fd2 = 5
//obsah súboru file05.txt po spustení programu  
abc123

//otestovanie riešenia
./tests/u1-1-test.sh

Aktivita - dup - u1-2

Úloha 1.2

Upravte program a vyriešte problém predstavený na začiatku. Aký bude postup, ak chcete nastaviť súbor input_output.txt ako štandardný vstup a výstup priamo v programe? Pracujte so súborom u1-2. Upraviť potrebujete len funkciu redirect_input_output().

//u1-2.c
#include <stdio.h>

void redirect_input_output(){
  
    int fd1=open("input_output.txt" , O_RDWR);
    //DOPLNTE
}

int main(int argc, char const *argv[])
{
    redirect_input_output();
    //maximálny počet znakov v riadku
    int len = 20;                               
    char line[len];
    int number_of_line = 1;
    //načíta riadok zo štandardného vstupu
    while (fgets(line,len,stdin))               
    {
        //očísluje a vypíše riadok
        printf("%d %s",number_of_line, line);   
        number_of_line++;   
    }
    return 0;
}
//obsah input_output.txt na začiatku
$ more input_output.txt 
jedno
slovo
jeden
riadok
//očakávaný obsah input_output.txt  na konci
$ more input_output.txt 
jedno
slovo
jeden
riadok
1 jedno
2 slovo
3 jeden
4 riadok

//otestovanie riešenia
./tests/u1-2-test.sh

Upozornenie

Ak ste nechtiac upravili súbory, potrebnú štruktúru môžete vytvoriť nasledujúcim postupom.

//príprava
echo -e "jedno\nslovo\njeden\nriadok" > input_output.txt

Krok 2: Informácie o súbore - všeobecne

Príklad - ls - pr2-1

Doterajšie kroky boli zamerané na manipuláciu s obsahom súboru. Tento krok je venovaný získaniu informácii o súbore a spoznaniu spôsobu, ako vytvoriť program, ktorého výstup bude podobný ako pri ls -l.

Príklad 2.1
Časť z výstupu ls -l /usr/include/

    drwxr-xr-x  2 root root   4096 feb  3 01:44 sound
    -rw-r--r--  1 root root   6690 apr 16  2018 spawn.h
    -rw-r--r--  1 root root    264 apr 16  2018 stab.h
    -rw-r--r--  1 root root   2363 apr 16  2018 stdc-predef.h
    -rw-r--r--  1 root root   8626 apr 16  2018 stdint.h
    -rw-r--r--  1 root root   2799 apr 16  2018 stdio_ext.h
    -rw-r--r--  1 root root  29665 apr 16  2018 stdio.h
    -rw-r--r--  1 root root  35784 apr 16  2018 stdlib.h
    -rw-r--r--  1 root root  17545 apr 16  2018 string.h

Poznámka

Pozrite si niekoľko príkladov použitia príkazu ls.

Teória - stat

Základné pojmy

Adresár je zvláštny súbor, ktorý obsahuje zoznam s menami súborov a číslami i-uzlov. Jednoznačne tak každému súboru priraďuje i-uzol (cez i-number).

Jednotlivé i-uzly sú v systéme rozlíšené číslom. Číslo i-uzla je jednoznačné iba v rámci jedného zväzku, preto nestačí k jednoznačnej identifikácii súboru (podrobnejšie: Sofia - Adresáre).

štruktúru štandardného UNIX súborového systému
Obr. 1: štruktúru štandardného UNIX súborového systému

Význam i-uzla je, že obsahuje metaúdaje o súbore napr. čas poslednej zmeny, prístupové práva a pod. Získať ich je možné napr. službou jadra stat alebo jej podobnými.

Služba jadra stat()

Služba jadra stat() získa informácie o súbore a vloží ich do dátovej štruktúry.

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

int stat (const char *pathname, struct stat *buf);
int fstat (int filedes, struct stat *buf);
int lstat (const char *pathname, struct stat *buf);
 Parametre Popis
pathname špecifikácia súboru - meno, cesta k súboru
filedes deskriptor otvoreného súboru
 buf ukazovateľ na dátovú štruktúru, ktorú služba vyplní
Ukončenie  Návratová hodnota
úspešné 0
chyba - 1

Príklad - stat - pr2-2 u2-1

Príklad 2.2 Získanie informácií o súbore.

struct stat {
    dev_t     st_dev;         /* číslo zariadenia */
    ino_t     st_ino;         /* číslo i-uzla*/
    mode_t    st_mode;        /* typs súboru a prístupové práva */
    nlink_t   st_nlink;       /* počet linkov (hard links) */
    uid_t     st_uid;         /* user ID vlastník*/
    gid_t     st_gid;         /* group ID skupina */
    dev_t     st_rdev;        /* device ID (pre špeciálne súbory) */
    off_t     st_size;        /* veľkosť v bajtoch */
    blksize_t st_blksize;     /* najlepšia veľkosť bloku pre efektívne I/O operácie */
    blkcnt_t  st_blocks;      /* počet alokovaných blokov s veľkosťou 512B */
              
    struct timespec st_atime;  /* čas posledného prístupu */
    struct timespec st_mtime;  /* čas poslednej modifikácie */
    struct timespec st_ctime;  /* čas polednej zmeny stavu */
}

//pr2-2.c
#include <time.h> //ctime
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>

int main(int argc, char const *argv[])
{
    struct stat buf;

    stat("file06.txt", &buf);
    printf("Access time  = %s\n", ctime(&buf.st_atime));
    printf("Modification time  = %s\n", ctime(&buf.st_mtime));
    printf("Change time  = %s\n", ctime(&buf.st_ctime));
    return 0;
}

Upozornenie

Ak ste nechtiac upravili súbory, potrebnú štruktúru môžete vytvoriť nasledujúcim postupom.

//príprava
echo "informacie o subore" > file06.txt

Úloha 2.1

Všimnite si, ako sa menia hodnoty, ked vyskúšate zmeniť.

  • obsah súboru
  • otvoriť súbor a nemeniť obsah
  • premenovať súbor alebo zmeniť práva. Môžete to vyskúšať na súbore file06.txt.

Aktivita - stat - o2-1 o2-2 o2-3

Otázka 2.1

Ktorá z hodnôt bude zmenená, ak otvoríte súbor, zmeníte jeho obsah a uložíte zmeny?

Odoslať odpoveď
Správna odpoveď: st_atime, st_mtime, st_ctime
Nesprávna odpoveď

Otázka 2.2

Ktoré informácie sa nachádzajú v štruktúre stat.

Odoslať odpoveď
Správna odpoveď: číslo i-nodu, typ súboru, prístupvé práva
Nesprávna odpoveď

Otázka 2.3

Ktorú z trojice služieb stat, fstat, lstat použijete, ak je súbor špecifikovaný návratovou hodnotou služby open(), ktorá skončila úspešne? (Odpoveď uveďte v tvare: "open" bez úvodzoviek.)

Správna odpoveď: fstat
Nesprávna odpoveď

Aktivita - stat - u2-2

Úloha 2.2

Program má vypísať číslo i-uzla súboru, ktorý bol zadaný z príkazového riadka. Kostra riešenia je v u2-2.c.

//u2-2.c
#include <sys/stat.h>
#include <stdio.h>

int main(int argc, char const *argv[])
{
    struct stat buf;

    //DOPLNTE
    if( /*volanie služby a zistenie, či nastala chyba*/){
        perror("stat");
    }
    else {
        //DOPLNTE
        int inode = ;
        printf("%s inode = %d\n", argv[1], inode);
    }
    return 0;
}
//spustenie
./u2-2 file06.txt
//otestovanie riešenia
./tests/u2-2-test.sh

Poznámka

Vysvetlenie typov napr. mode_t, ino_t si môžete pozrieť na tejto stránke

Krok 3: Adresáre

Aktivita - adresáre - u3-1 o3-1

Koncept adresárov je spôsob ako organizovať súbory (tvoria stromovú štruktúru). V skutočnosti adresár neobsahuje súbory a podadresáre, je iba postupnosťou bajtov, ktorá obsahuje informáciu o pároch i-uzol a názov súboru.

Úloha 3.1

Overte si tvrdenie "adresár je tiež len súbor". Pokúste sa otvoriť adresár u3-1-dir v rôznych režimoch (O_RDONLY, O_WRONLY, O_RDWR).

Otázka 3.1

Pri ktorom režime nenastala chyba?

Odoslať odpoveď
Správna odpoveď: O_RDONLY
Nesprávna odpoveď

Aj keď je adresár typ súboru, pre jeho otvorenie a prácu s ním sú určené osobitné funkcie.

Aktivita - stat - o3-2

Zatiaľ bol predstavený spôsob, ako je možné vytvoriť program, ktorý vypíše informácie pre jeden súbor. Podobne ako: ls -li /usr/include/stdio.h.

Otázka 3.2

Čo z výpisu (ráta sa aj iný tvar) nie je uvednéné v štruktúre stat?

69418 -rw-r--r-- 1 root root 29665 apr 16  2018 /usr/include/stdio.h
Odoslať odpoveď
Správna odpoveď: /usr/include/stdio.h8
Nesprávna odpoveď

Teória - opendir, readdir

V prípade ak má byť vytvorený výpis s informáciami o všetkých súboroch adresára, môžu byť užitočné nasledujúce funkcie, ktoré nie sú priamo služby jadra, ale využívajú ich vo svojom tele.

Funkcie opendir() a readdir()

Funkcia opendir() otvorí adresár a vráti deskriptor adresára. Funkcia readdir() vráti ukazovateľ na štruktúru dirent nasledujúcej položky adresára.

#include <sys/types.h>
#include <dirent.h>

DIR *opendir(const char *pathname);
Parameter Popis
pathname názov, cesta k súboru
Ukončenie Návratová hodnota
úspešné adresárový prúd, deskriptor adresára
chyba NULL, zmenená hodnota errno
#include <dirent.h>

struct dirent *readdir(DIR *dirp);
Parameter Popis
dirp adresárový prúd, deskriptor adresára získaný pri otvorení adresára funkciou opendir
Ukončenie Návratová hodnota
úspešné ukazovateľ na štruktúru dirent alebo NULL ak dosiahne koniec adresára
chyba NULL, zmenená hodnota errno

Štruktúra dirent obsahuje adresárové záznamy pre jednotlivé súbory.

struct dirent
{
    ino_t          d_ino;       /* číslo i-uzla */
    off_t          d_off;       /* offset na nasledujúci dirent */
    unsigned short d_reclen;    /* veľkosť záznamu v bajtoch */
    unsigned char  d_type;      /* typ súboru */
    char           d_name[];    /* názov súboru */
}; 

Aktivita - opendir, readdir - o3-3

Otázka 3.3

V ukážke programu, ktorý vypisuje mená súborov pracovného adresára nhraďte čísla 1 - 5. V akom poradí budú použité premenné? (Odpoveď uveďte v tvare: 'a' ako 'adresar', 's' ako 'subor' napr. 'sssss' bez úvodzoviek a medzier.)

//a
DIR *adresar;
//s
struct dirent *subor;

1 = opendir(".");
//čítanie položiek, kým nedôjde na koniec súboru
while((2 = readdir(3) != NULL)){
    printf("%s\n", 4->d_name);
}
//zatvorenie adresára
closedir(5);
Správna odpoveď: asasa
Nesprávna odpoveď

Aktivita - adresáre - u3-2

Úloha 3.2

Program má vykonať nasledujúce kroky:

  • nastavýiť adresár u3-2-dir ako pracovný,
  • vypísať názvy položiek v pracovnom adresári,
  • vytvoriť v pracovnom adresári nový adresár dir2,
  • opäť vypísať obsah adresára u3-2-dir.

Užitočné môžu byť funkcie: mkdir, chdir, rewinddir.
Pracujte so súborom u3-2.c.

//u3-2.c
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <sys/stat.h>//mkdir
#include <unistd.h>//chdir

int main(int argc, char const *argv[])
{

    //nastavenie pracovného adresára
    //DOPLNTE
    ("u3-2-dir");

    //výpis názvov súborov v pracovnom adresári
    DIR *pracovny_adresar;
    struct dirent *subor;

    pracovny_adresar = //DOPLNTE
    printf("Výpis položiek adresára.\n");
    while(/*DOPLNTE*/){
        printf("%s\n", subor->d_name);
    }

    //vytvorenie adresára dir2
    //DOPLNTE
    ("dir2", 0700);

    //výpis názvov súborov v pracovnom adresári
    printf("\nVýpis položiek adresára po vytvorení nového adresára.\n");
    while(/*DOPLNTE*/){
        printf("%s\n", subor->d_name);
    }

    return 0;
}
//možný výstup
$ ./u3-2R
Výpis položiek adresára.
..
file1.txt
.

Výpis položiek adresára po vytvorení nového adresára.
..
dir2
file1.txt
.

//otestovanie riešenia
./tests/u3-2-test.sh

Upozornenie

Ak ste nechtiac upravili súbory, potrebnú štruktúru môžete vytvoriť nasledujúcim postupom.

//príprava
mkdir u3-2-dir
touch u3-2-dir/file1.txt

Teória - telldir, seekdir

Po vypísani položiek adresára je možné sa vrátiť ku konkrétnej položke. Slúži na to dvojica funkcií: telldir určuje aktuálnu pozíciu v adresárovom prúde a seekdir nastavý smerník na adresárovú položku adresárového prúdu.

#include <dirent.h>

long telldir(DIR *dirp);
void seekdir(DIR *dirp, long loc);
Parameter Popis
dirp adresárový prúd, deskriptor adresára
loc aktuálna pozícia v adresárovom prúde
Ukončenie Návratová hodnota
úspešné aktuálna pozícia v adresárovom prúde
chyba -1

Aktivita - telldir, seekdir - u3-3

Úloha 3.3

Program má vykonať nasledujúce kroky:

  • vypísať informácie o súboroch v adresári u3-2-dir,
  • vrátiť sa ku položke s názvom hladany.txt,
  • vypísať informácie o nasledujúcej položke.

Pracujte so súborom u3-3.c.

//u3-3.c
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char const *argv[])
{
  
    DIR *adresar;
    struct dirent *subor;
    long int position;

    adresar = opendir("u3-3-dir");

    if(adresar != NULL){
        printf("Výpis položiek adresára.\n%-20s  %-7s pozícia\n", "názov", "i-uzol");
        while((subor = readdir(adresar)) != NULL){
            printf("%-20s %ld %ld\n", /*DOPLNTE názov*/, /*DOPLNTE i-uzol*/, /*DOPLNTE pozícia*/);
            if(strcmp("hladany.txt",subor->d_name)== 0){
                position=/*DOPLNTE získanie pozície*/;
            }
        }

        //DOPLNTE vrátenie na položku
      
        //DOPLNTE načítanie položky
      

        printf("\n%-20s  %-7s pozícia\n", "názov", "i-uzol");
        printf("%-20s %ld %ld\n", /*DOPLNTE názov*/, /*DOPLNTE i-uzol*/, /*DOPLNTE pozícia*/);
    }

    return 0;
}

//možný výstup
$ ./u3-3R
Výpis položiek adresára.
názov                i-uzol  pozícia
..                   1123270 3517075659704677360
file1.txt            1356007 4786282983948090838
file2.txt            1356009 5602542653180332055
hladany.txt          1356008 7301517832763653560
.                    1356006 9223372036854775807

názov                i-uzol  pozícia
.                    1356006 9223372036854775807

Upozornenie

Ak narazíte na problém s prekladom pri spúšťaní programu, skúste použiť nasledovný postup.
gcc -std=gnu11 -Wall -Werror u3-3.c -o u3-3

Upozornenie

Ak ste nechtiac upravili súbory, potrebnú štruktúru môžete vytvoriť nasledujúcim postupom.

//príprava
mkdir u3-3-dir
touch u3-3-dir/file1.txt
touch u3-3-dir/hladany.txt
touch u3-3-dir/file2.txt

Krok 4: Typy súborov - všeobecne

Teória - typy súborov

Ak si všimnete výpis, ls -l prvý stĺpec tvoria informácie o type súboru a používateľských právach.

-rw-r--r--  1 root root  29665 apr 16  2018 stdio.h
Prvý stĺpec zdroj
Obr. 2: Prvý stĺpec zdroj

Používatelia zvyčajne prichádzajú do kontaktu s:

  • - obyčajnými súbormi
  • d adresármi
  • l symbolickými linkami (odkazmi na iný súbor)

Poznámka

Viac sa môžete dozvedieť o typoch súborov na tejto stránke

V položke st_mode sú uložené informácie o type súboru a prístupových právach vo forme bitového súčtu rôznych príznakov (OR, operátor | ).

Príznaky pre typy súborov:

Popis Príznak
obyčajný súbor S_IFREG
adresár S_IFDIR
symbolický link S_IFLNK
maska pre súbor S_IFMT

Upozornenie

Ak by ste chceli overiť typ súboru napr. postupom:
if((statbuf.st_mode & S_IFMT) == S_IFCHR)
narazíte na problém, že S_IFMT a S_IFCHR nie sú definované.
Ak vás zaujímajú konkrétne hodnoty, viac sa môžete dozvedieť na tejto stránke

Jednoduchý spôsob ako určiť typ súboru, môže byť použitie makra, ktoré otestuje či je súbor konkrétneho typu. Ak súbor nie je daného typu vráti 0.

Typ súboru Macro
obyčajný súbor S_ISREG(m)
adresár S_ISDIR(m)
symbolický link S_ISLNK(m)

Podrobnejšie sys/stat.h

Príklad - typy súborov - pr4-1

Príklad 4.1
Program overí, či je súbor obyčajný.

//pr4-1.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    struct stat statbuf;
    stat("pr4-1-dir/file07.txt", &statbuf);
  
    if(S_ISREG(statbuf.st_mode)){
        printf("Is regular\n");
    }
    else printf("Other type\n");

    stat("pr4-1-dir", &statbuf);

    if(S_ISREG(statbuf.st_mode)){
        printf("Is regular\n");
    }
    else printf("Other type\n");

    return 0;
}

//výstup
$ ./pr4-1 
Is regular
Other type

Upozornenie

Ak ste nechtiac upravili súbory, potrebnú štruktúru môžete vytvoriť nasledujúcim postupom.

//príprava
mkdir pr4-1-dir
touch pr4-1-dir/file07.txt

Aktivita - typy súborov - o4-1 o4-2

Otázka 4.1

Aké sú správne dvojice: typ súboru a makro? (Odpoveď uveďte v tvare: "a0b0c0" bez úvodzoviek a medzier.)

a. -
b. d
c. l

1. S_ISDIR(m)
2. S_ISBLK(m)
3. S_ISLNK(m)
4. S_ISREG(m)
5. S_ISCHR(m)
6. S_ISSOCK(m)

Správna odpoveď: a4b1c3
Nesprávna odpoveď

Otázka 4.2

Aký bude typ súboru prvých dvoch položiek? Nahraďte znak '?'. (Odpoveď uveďte v tvare: "c" bez úvodzoviek a medzier.)

?rwxrwxr-x 3 sofia sofia 4096 apr 15 01:50 .
?rwxrwxr-x 7 sofia sofia 4096 apr 15 00:23 ..
-rw------- 1 sofia sofia   32 apr 14 15:44 file02.txt
-rw------- 1 sofia sofia   42 apr 14 15:52 file03.txt
-rw------- 1 sofia sofia   19 apr 14 16:38 file04
Správna odpoveď: d
Nesprávna odpoveď

Krok 5: Linky

Aktivita - linky - o5-1

Otázka 5.1

Pri použítí príkazu ls -la nie je zobrazená hodnota pre i-uzol. Ako bude vyzerať príkaz, keď doplníte prepínač, ktorý umožní aj zobrazenie i-uzla? Môžete si pomôcť manuálovými stránkami. (Odpoveď uveďte v tvare: "ls -lab" bez úvodzoviek.)

//príklad výstupu
11420219 drwxrwxr-x 2 sofia sofia 4096 apr 15 02:55 .
11409366 drwxrwxr-x 3 sofia sofia 4096 apr 15 02:53 ..
11413898 -rw-rw-r-- 3 sofia sofia    5 apr 15 02:55 file08.txt
11413900 lrwxrwxrwx 1 sofia sofia   10 apr 15 02:55 file08.txt-soft -> file08.txt
11413898 -rw-rw-r-- 3 sofia sofia    5 apr 15 02:55 file08.txt-hard

Správna odpoveď: ls -lai
Nesprávna odpoveď

Vo výstupe je ukázané, že na jeden fyzický súbor (t.j. na rovnaký i-node) môže odkazovať viac adresárových položiek.

Aktivita - Pevný a symbolický odkaz

Upozornenie

Ak ste nechtiac upravili súbory, potrebnú štruktúru môžete vytvoriť nasledujúcim postupom.

//príprava
mkdir u5-1-dir
echo "obsah suboru file08.txt" > u5-1-dir/file08.txt
ln u5-1-dir/file08.txt u5-1-dir/file08.txt-hard
ln -s u5-1-dir/file08.txt u5-1-dir/file08.txt-soft

Poznámka

Pracujte v adresári u5-1-dir.

Úloha 5.1

V termináli zobrazte obsah súborov file08.txt, file08.txt-sotf a file08.txt-hard. Pomôcť vám môže príkaz more.

Úloha 5.2

Premenujte názov súboru file08.txt na renamed. Môžete použiť príkaz mv
napr. mv stary_nazov novy_nazov.

Otázka 5.2

Pri ktorom odkaze nastane chyba, ak budete opäť vypisovať obsah súborov file08.txt-hard a file08.txt-soft ?

Odoslať odpoveď
Správna odpoveď: symbolický odkaz
Nesprávna odpoveď

Teória - symbolický a pevný odkaz

Symbolický odkaz (symbolic link, soft link) odkazuje na iný súbor podľa názvu. Je v ňom uložená len informácia, na aký súbor odkazuje. Vo výpise ls -l je označený inak ako obyčajný súbor.

Úloha 5.3

Zobrazte názov súboru, na ktorý odkazuje symbolický link file08.txt-soft. Skúste použiť príkaz readlink.

Pevný odkaz (hard link) odkazuje na i-uzol, rovnako ako pôvoddný názov.

11413898 4 -rw-rw-r-- 3 sofia sofia 24 apr 17 01:02 file08.txt-hard
11413900 0 lrwxrwxrwx 1 sofia sofia 10 apr 15 02:55 file08.txt-soft -> file08.txt
11413898 4 -rw-rw-r-- 3 sofia sofia 24 apr 17 01:02 renamed
zdroj
Obr. 3: zdroj

Teória - link, unlink

Pre prácu s odkazmi je možné použiť nasledujúce služby.

Služby jadra link() a unlink()

Služba jadra link() vytvorí novú položku adresára newpath, ktorá odkazuje na existujúcu položku existingpath.

#include <unistd.h>
int link (const char *existingpath, const char newpath);
int unlink (const char *pathname);
Parametre Popis
existingpath existujúca položka adresára
newpath nová položka adresára
pathname položka adrasára
Ukončenie Návaratová hodnota
úspešné 0
chyba - 1

Aktivita - symbolický a pevný odkaz - u5-4

Úloha 5.4

Pokúste sa vytvoriť odkaz file09.txt-link a u5-4-dir-link na súbor file09.txt a adresár u5-4-dir. Doplnte program v súbore u5-4.c a všimnite si výstup.

//u5-4.c
#include <unistd.h>
#include <stdio.h>

int main(int argc, char const *argv[])
{
    //DOPLNTE VYTVORENIE ODKAZU NA SÚBOR
    if( ==  -1)
        perror("link file");

    //DOPLNTE VYTVORENIE ODKAZU NA ADRESÁR
    if( == -1)
        perror("link dir");
  
    return 0;
}

Upozornenie

Ak ste nechtiac upravili súbory, potrebnú štruktúru môžete vytvoriť nasledujúcim postupom.

//príprava
echo "obsah suboru file09.txt" > file09.txt
mkdir u5-4-dir

Aktivita - symbolický a pevný odkaz - o5-3 o5-4

Otázka 5.3

Aký typ odkazu vytvára služba link()c?

Odoslať odpoveď
Správna odpoveď: pevný odkaz
Nesprávna odpoveď

Služba jadra unlink () odstráni položku adresára. Ak existujú na súbor aj iné odkazy, ostanú cez ne dáta daného súboru prístupné.

Otázka 5.4

Ak je aktuálny stav:

11413965 -rw-rw-r-- 2 sofia sofia   24 apr 18 23:34 file10.txt
11413965 -rw-rw-r-- 2 sofia sofia   24 apr 18 23:34 file10.txt-hard

Aká hodnota bude v buf.st_nlink? (Odpoveď uveďte v tvare: "2" bez úvodzoviek.)

...

struct stat buf;

unlink("file10.txt");
stat("file10.txt-hard". &buf);

...
Správna odpoveď: 1
Nesprávna odpoveď

Krok 6: Prístupové práva

Teória - práva

Každý súbor má definované prístupové práva. Vo výpise ls -l sú uvedené po informácii o type súboru. Pre jednotivé typy používateľov špecifikujú, ako môžu so súborom pracovať. Rozlišované sú tri typy používateľov:

  • u (user) - vlastník súboru
  • g (group) - pracovná skupina
  • o (others) - ostatní

Súbory majú definovaného svojho vlastníka a skupinu.

Prístupové práva sú zaznamenané v i-uzle v bitovom tvare. Ak na danej pozícii má bit hodnotu 1, znamená to, že právo je pridelené.

Obr. 4:
práva súbor adresár
r čítanie vypísať zoznam súborov
w zápis vytvárať / mazať súbory
x spustenie nastaviť adresár ako pracovný, vôjsť do aresára

Aktivita - práva - o6-1 u6-1 u6-2

Otázka 6.1

Aký je symbolický tvar, ak osmičková hodnota je 751. (Odpoveď uveďte v tvare: "rwxrwxrw-" bez úvodzoviek.)

Správna odpoveď: rwxr-x--x
Nesprávna odpoveď

Poznámka

Pracujte v adresári u6-1-dir.

Úloha 6.1

Vytvorte súbor myFile a adresár myDir. Použiť môžete príkazy touch a mkdir.

Všimnite si prístupové práva vytvorených súborov.

drwxrwxr-x 2 sofia sofia 4096 apr 19 20:35 myDir
-rw-rw-r-- 1 sofia sofia    0 apr 19 20:36 myFile.txt

Zvyčajne je hodnota práv pri nových súboroch 664 a pri adresároch 775.

Táto hodnota vznikne odobraním práv od prednastavenej hodnoty podľa tzv. masky práv.

Úloha 6.2

Zistite aktuálnu hodnotu masky práv. Použiť môžete príkaz umask .

Teória - umask

Prednastavená hodnota práv je pri súboroch 0666 a pri adresároch 0777. Maska práv definuje, ktoré práva majú byť odobrané. Zvyčajne je nastavená na 0002.

Obr. 5:

Služba jadra umask()

Zmenu masky je možné vykonať už spomenutým príkazom umask alebo pomocou služby jadra.

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

mode_t umask(mode_t mask);
Parametre Popis
mask práva, ktoré majú byť odobrané

Príklad hodnôt pre nastavenie masky práv:

mask - prístupové práva osmičková hodnota popis
S_IRUSR 0400 čítanie pre majiteľa
S_IWGRP 0020 zápis pre skupinu
S_IXOTH 0001 vykonávanie pre ostatných
S_IRWXG 0070 čítanie, zápis a vykonávanie pre skupinu
S_IRWXO 0007 čítanie, zápis a vykonávanie pre ostatných
Ukončenie Návratová hodnota
úspešné predošlá maska

Aktivita - umask - o6-2 u6-3

Otázka 6.2

Aká je hodnota masky práv, ak mali byť nastavené práva:
rwxrwxrwx
ale v skutočnosti boli nastavené:
rw-r-----
Tvar odpovede: 0002 (Odpoveď uveďte v tvare: "0002" bez úvodzoviek.)

Správna odpoveď: 0137
Nesprávna odpoveď

Úloha 6.3

V súbore u6-3.c je kostra programu, ktorý má zmeniť masku práv tak, aby ponechala práva iba pre vlastníka. Novú hodnotu masky vypíšte v osmičkovom tvare. Po vytvorení súboru file11.txt nastavte pôvodnú masku.

//u6-3.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>

int main(int argc, char const *argv[])
{
    mode_t oldmask;

    oldmask = //DOPLNTE;

    printf("stará maska: //DOPLNTE \n", oldmask);
    creat("file11.txt", 0777);
    printf("maska použitá pri vytvorení súboru: /*DOPLNTE*/\n", /*DOPLNTE*/);
    printf("nastavená pôvodná maska\n");
    return 0;
}

//otestovanie riešenia
./tests/u6-3-test.sh

Príklad - chmod - pr6-1

Prístupové práva môžu byť po vytvorení zmenené. Príkaz chmod alebo rovnomenná služba môžu byť užitočné ak je cieľom napr. rozšíriť prístupové práva pre skupinu používateľov.

Príklad 6.1
Použitie príkazu chmod.

Všimnite si aktuálne práva súboru file12.txt.

$ ls -l file12.txt
-rw-rw-r-- 1 sofia sofia 33 apr 23 15:17 file12.txt

Príkazom chmod je možné určiť, aká bude nová hodntoa prístupových práv.

$ chmod 777 file12.txt
$ ls -l file12.txt 
-rwxrwxrwx 1 sofia sofia 33 apr 23 15:17 file12.txt

Možné je aj určiť, len ako májú byť zmenené využitím označení používateľov v tvare u, g, o.

Upozornenie

Ak ste nechtiac upravili súbory, potrebnú štruktúru môžete vytvoriť nasledujúcim postupom.

//príprava
echo "subor, ktoreho prava budu zmenene" > file12.txt

Aktivita - chmod - o6-3

Otázka 6.3

Ak je aktuálny stav súboru:

$ ls -l file12.txt 
-rwxrwxrwx 1 sofia sofia 33 apr 23 15:17 file12.txt

Aká bude hodnota prístupových práv po zadaní nasledujúceho príkazu? (Odpoveď uveďte v tvare: "777" bez úvodzoviek.)

$ chmod u-x,g-wx,o-rwx file12.txt
Správna odpoveď: 640
Nesprávna odpoveď

Teória - chmod

Služba jadra chmod()

Služba jadra chmod() zmení prístupové práva súboru.

#include <sys/types.h>
#include <sys/stat.h>
int chmod (const char *pathname, mode_t mode);
Parametere Popis
pathname názov alebo cesta k súboru
mode prístupové práva - číselné hodnoty (777) alebo pomocou príznakov
Ukočenie Návratová hodnota
úspešné 0
chyba - 1

Aktivita - chmod - o6-4

Otázka 6.4

Súbor má mať nastavené práva rwxr-x---. Ktoré z možností sa dajú použiť?

//o6-4.c
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char const *argv[])
{
    chmod("file14.txt", /*DOPLNTE*/);
    return 0;
}

Pre určenie odpovede, môžete použiť program v súbore o6-4.c.

Odoslať odpoveď
Správna odpoveď: 0700 | 0050, S_IRWXU | S_IRGRP | S_IXGRP, 0750
Nesprávna odpoveď

Upozornenie

Ak ste nechtiac upravili súbory, potrebnú štruktúru môžete vytvoriť nasledujúcim postupom.

//príprava
echo "na zaciatku prava 664" > file14.txt

Aktivita - chmod - u6-4

Úloha 6.4

Vytvorte jednoduchý program, ktorého argument bude názov súboru. Ak je zadaný súbor adresár, zabezpečte nech doň môže vstupovať len vlastník. V prípade, že je to obyčajný súbor, zabezpečte, aby len vlastník mohol meniť jeho obsah. Ostatné práva nech sú zachované. Jeho fungovanie môžete testovať na dir05 a file13.txt. Pracujte so súborom u6-4.c.

//u6-4R.c
#include <sys/stat.h>
#include <sys/types.h>

int main(int argc, char const *argv[])
{

    struct stat buf;
  
    stat(/*DOPLNTE - získanie informácii o súbore*/);

    mode_t current_mode = buf.st_mode;

    if(/*DOPLNTE - zitit ci je adresár*/){
        mode_t new_mode = current_mode  & ~(/*DOPLNTE*/);
        new_mode = new_mode | /*DOPLNTE*/;

        chmod(/*DOPLNTE*/);
    }
    if(/*DOPLNTE - zistit ci je obycajny subor*/){
        /*DOPLNTE - zmena práv*/
    }

    return 0;
}

Príklad fungovania programu:

//pred spustením
drw-rwxrw- 2 sofia sofia 4096 apr 23 19:30 dir05
-r-xrwxrwx 1 sofia sofia   22 apr 23 19:30 file13.txt
$ ./u6-4R file13.txt
$ ./u6-4R dir05
drwxrw-rw- 2 sofia sofia 4096 apr 23 19:30 dir05
-rwxr-xr-x 1 sofia sofia   22 apr 23 19:30 file13.txt
//otestovanie riešenia
./tests/u6-4-test.sh

Upozornenie

Ak ste nechtiac upravili súbory, potrebnú štruktúru môžete vytvoriť nasledujúcim postupom.

//príprava
echo "na zaciatku prava 577" > file13.txt;
chmod 577 file13.txt;
mkdir dir05;
chmod 676 dir05

Poznámka

Príklady bitových operácií:

//pridanie práv na čítanie pre skupinu
current_mode | S_IRGRP

//odobranie práv na čítanie pre skupinu
current_mode & ~S_IRGRP

//odobranie práv na čítanie a vykonávanie pre skupinu
current_mode & ~(S_IRGRP | S_IXGRP)
Bitové operácie
Obr. 6: Bitové operácie

Krok 7: Špeciálne bity

Teória

sticky bit

Ak je súbor v adresári, ku ktorému má viacero používateľov právo na zápis (napr. sú členmi pracovnej skupiny), môže sa stať, že súbor jedného používateľa bude zmazaný niektorým iným používateľom.

Ak je potrebné to obmedziť, vlastník adresára môže adresáru nastaviť sticky bit, čím zabezpečí, že iba root a vlastník súboru môžu zmazať súbor v adresári.

Môžné je to vidieť pri adresári /tmp

drwxrwxrwt  15 root root      4096 máj  2 07:52 tmp

Príklad:
Nastavenie sticky bit

//stav na začiatku
drwxrwxrwx 2 sofia sofia 4096 máj  2 08:38 pr6-2-dir

$ ls -l pr6-2-dir/
celkom 0
-rw-rw-r-- 1 sofia sofia 0 máj  2 08:38 file16.txt

//nastavenie možné viacerými spôsobmi
$ chmod +t pr6-2-dir
$ chmod 1777 pr6-2-dir

//stav na konci
drwxrwxrwt 2 sofia sofia 4096 máj  2 08:38 pr6-2-dir

$ ls -l pr6-2-dir/
celkom 0
-rw-rw-r-- 1 sofia sofia 0 máj  2 08:38 file16.txt

Pri obyčajných súboroch môže nastavenie sticky bitu ovplyvniť rýchlosť práce so súborom. Viac informácii na stránke alebo v man.

Teória

setuid a setgid bit

Keď používateľ spustí program, program má rovnaké práva ako používateľ. Môže upravovať iba súbory, ku ktorým má daný používateľ právo na zápis. Môže nastať situácia, keď je potrebné dočasne rozšíriť prístupové práva.

Napríklad príkaz passwd, ktorý potrebuje upravovať súbor s heslami, ku ktorému nemajú prístup všetci používatelia. Viac informácii na stránke alebo v man.

-rwsr-xr-x 1 root root 59640 mar 22 20:05 /usr/bin/passwd

Príklad 7.2:
Nastavenie setuid

//stav na začiatku
-rwxr-xr-x 1 root  root     0 máj  2 10:14 program

//nastavenie možné viacerými spôsobmi
chmod u+s program
chmod 4755 program

//stav na konci
-rwsr-xr-x 1 root  root     0 máj  2 10:14 program

Pri spustení iným používateľom ako root program bude mať práva ako root.

Na podobnom princípe funguje aj setgid. Pri spustení programu iným používateľom program bude mať práva, ako má jeho skupina. Viac informácii na stránke alebo v man.

Príklad 7.3: Nastavenie setgid

//stav na začiatku
-rwxr-xr-x 1 root  root     0 máj  2 10:19 program2

//nastavenie možné viacerými spôsobmi
chmod g+s program2
chmod 2755 program2

//stav na konci
-rwxr-sr-x 1 root  root     0 máj  2 10:19 program2

Zdroje

  1. Sofia - Súbory
  2. Sofia - Adresáre
  3. Sofia - Prístupové práva