Mgr inż. Marcin Borkowski Pliki i Katalogi UNIX. mgr inż. Marcin Borkowski Wejście/Wyjście – Pliki, pipe'y, FIFO i gniazda sieciowe (sockets) – Dostęp.

1 mgr inż. Marcin Borkowski Pliki i Katalogi UNIX ...
Author: Roman Jóźwiak
0 downloads 0 Views

1 mgr inż. Marcin Borkowski Pliki i Katalogi UNIX

2 mgr inż. Marcin Borkowski Wejście/Wyjście – Pliki, pipe'y, FIFO i gniazda sieciowe (sockets) – Dostęp poprzez deskryptor (niskopoziomowy) lub poprzez strumień (wysokopoziomowy) – Strumienie są najlepiej przenośne ( standard ISO C) – Pozycja odczytu/zapisu w pliku: ● dostęp swobodny (random access) ● dostęp limitowany (np. dla pipe), próba pozycjonowania generuje błąd ESPIPE ● jest współdzielona pomiędzy procesem potomnym i dzieckiem o ile deskryptor został otwarty przed wywołaniem fork ● tryb dopisywania (append) ma wpływ tylko na zapis, odczyt nadal jest swobodny – W dalszej części omówiony zostanie dostęp niskopoziomowy

3 mgr inż. Marcin Borkowski Wejście/Wyjście – deskryptory związane (Linked channels) ● pojedyncze otwarcie deskryptora wraz z funkcją: – fork, dup, dup2, fileno, fdopen ● współdzielona pozycja w pliku ● współdzielone flagi statusu pliku (ale osobne flagi deskryptora) ● jeśli pracuje się na związanych strumieniach, ich bufory powinny być puste przed otwarciem następnego związanego strumienia ● bufor strumienia jest pusty gdy: – wywołamy fflush – strumień jest niebuforowany – po znaku nowej linii gdy strumień jest buforowany liniami (line buffered)

4 mgr inż. Marcin Borkowski Wejście/Wyjście – Deskryptory niezwiązane (independent channels) ● każdy powstał w wyniku niezależnego wywołania funkcji open ● niezależna pozycja w pliku i wszystkie flagi ● niezależne bufory strumieni nadal mogą zakłócić porządek wypisywania danych ● zawsze dobrze jest opróżnić bufor jednego strumienia przed użyciem następnego ● do dopisywania na koniec pliku przez współbieżne procesy niezbędne jest użycie trybu append, inne rozwiązania nie są poprawne ● wiele sytuacji wielodostępu do tego samego pliku wymaga blokowania (patrz następne slajdy)

5 mgr inż. Marcin Borkowski Strumienie – Typ danych: FILE * – Standardowe strumienie ● automatycznie otwarte podczas uruchomienia procesu ● stdin, stdout, stderr – Typowe funkcje (proszę przeczytać strony man): ● fopen, fclose, ● fseek, ftell, fflush ● (f)printf, (f)scanf, fgets ● ungetc, fread, fwrite ● feof, ferror, clearerr

6 mgr inż. Marcin Borkowski Strumienie – Posix definiuje operacje na strumieniach jako atomowe – bezpieczne dla wątków (ale to nie oznacza, że nie mogą być przerwane przez obsługę sygnału) – Proste automatyczne blokowanie działa tylko dla pojedynczego wywołania funkcji. Jeśli kilka różnych operacji na strumieniu musi być wykonanych atomowo konieczne staje się użycie specjalnych funkcji blokujących strumień : ● flockfile, ftrylockfile, funlockfile – Jeden wątek może zablokować ten sam strumień więcej niż jeden raz, musi też potem tyle samo razy go odblokowąć

7 mgr inż. Marcin Borkowski Strumienie – Buforowanie ● niebuforowany _IONBF ● buforowanie liniami _IOLBF (domyślne dla strumieni związanych z konsolą) ● pełne buforowanie _IOFBF (domyślne dla pozostałych strumieni) ● stdin, stdout oraz stderr są buforowane liniowo ● buforowanie można zmienić tylko przed wykonaniem pierwszej operacji na strumieniu - setvbuf ● UWAGA: dane do stdin (oraz STDIN_FILENO) przechodzą przez niezależny bufor terminala, którego zachowanie można zmienić funkcjami kontroli terminala

8 mgr inż. Marcin Borkowski Strumienie ● Funkcje nie zgodne z POSIX (nie używać) ● fcloseall ● __fpurge ● POSIX nie rozróżnia plików (strumieni, deskryptorów) binarnych i tekstowych ● Aby zachować zgodność z systemami rozróżniającymi te dwa typy używamy: – funkcji fgetpos i fsetpos – binarnej flagi “b” podczas otwierania strumienia

9 mgr inż. Marcin Borkowski Niskopoziomowe We/Wy – Typ danych: int – Standardowe deskryptory ● otwierane podczas uruchomienia procesu ● zadeklarowane w unistd.h ● STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO – Typowe funkcje (proszę poczytać strony man): ● open, close, fdopen, fileno ● lseek,read, write (patrz przykłady) – Proces może pisać także na dowolnej pozycji poza końcem pliku, ewentualne przerwy wypełniane są zerami – Nigdy nie należy używać niebezpiecznej funkcji : gets

10 mgr inż. Marcin Borkowski Niskopoziomowe We/Wy – Funkcje: mmap/munmap ● łatwy dostęp do pliku ● może redukować dostępną przestrzeń adresową procesu ● użycie mieszane z normalnymi funkcjami read/write wymaga odpowiedniej synchronizacji (f. sync ) ● ochrona pamięci: – PROT_READDane mogą być czytane – PROT_WRITEDane mogą być zapisywane – PROT_EXECDane mogą być wykonane jako kod (biblioteki so) – PROT_NONEDane są niedostępne ● nie wszystkie kombinacje powyższych flag muszą być zaimplementowane

11 mgr inż. Marcin Borkowski Niskopoziomowe We/Wy – Funkcja: mmap ● flagi: – MAP_SHAREDZmiany są współdzielone pomiędzy procesami – MAP_PRIVATEZmiany są prywatne dla procesu – MAP_FIXEDMapowanie na podany adres ● dokumentacja POSIX nie zaleca używania MAP_FIXED, funkcja ta nie musi być zaimplementowana w niektórych systemach ● tej funkcji można używać tylko na plikach (nie na fifo, pipe etc) ● adres i rozmiar bloku mogą być zmienione aby pasowały do rozmiaru strony pamięci, który można sprawdzić np. tak: size_t page_size = (size_t) sysconf(_SC_PAGESIZE);

12 mgr inż. Marcin Borkowski Niskopoziomowe We/Wy – System może buforować wszystkie operacje na dysku (oddzielnie dla każdego procesu), aby upewnić się, że dane istotnie zostały zapisane na dysku należy wywołać: ● funkcję sync aby zlecić synchronizację bez czekania na jej zakończenie ● funkcję fsync aby przeprowadzić synchronizację do końca – może zgłaszać błędy We/Wy !!! – może być przerwana obsługą sygnału(EINTR) – jeśli zmodyfikowane dane w pliku mają być udostępnione innemu procesowi należy przed zwolnieniem blokady wykonać synchronizację (oddzilene bufory procesów)

13 mgr inż. Marcin Borkowski Niskopoziomowe We/Wy – Duplikowanie deskryptorów ● tworzy powiązane deskryptory ● zazwyczaj jest używane w celu przekierowania danych między deskryptorami – funkcja dup tworzy kopię deskryptora, nowy deskryptor ma najniższy dostępny numer – ten sam efekt da: fcntl (old, F_DUPFD, 0); – funkcja dup2 tworzy kopię na deskryptor o podanym numerze, jeśli podany numer jest otwartym deskryptorem, zostanie on zamknięty przed wykonaniem kopii – ten sam efekt osiągamy: close (new);fcntl (old, F_DUPFD, new); – tyle że, dup2 jest operacją atomową (wątki, nie sygnały)

14 mgr inż. Marcin Borkowski Niskopoziomowe We/Wy – Flagi statusu dzielimy na: ● tryby dostępu ● flagi typu otwarcia pliku ● flagi trybu pracy – Ustawiane podczas otwarcia pliku open lub (poza typem otwarcia) później za pomocą fcntl – Zawsze należy najpierw odczytać istniejące i na nich dokonywać zmian (ze względu na nowe flagi jakie mogą powstać w przyszłości): new-flags = fcntl(filedes, F_GETFL) | O_APPEND; fcntl(filedes, F_SETFL, new-flags);

15 mgr inż. Marcin Borkowski Niskopoziomowe We/Wy – Tryby dostępu ● O_RDONLY,O_WRONLY, O_RDWR + uprawnienia – Typy otwarcia ● O_CREAT ● O_EXCL tylko z O_CREAT ● O_TRUNC – wycofane należy użyć f. ftruncate – Tryby pracy ● O_APPEND – pewne dodawanie na koniec pliku ● O_DSYNC,O_SYNC,O_RSYNC – wyłączenie buforowania ● O_NONBLOCK – wyłączenie oczekiwania na dane gdy bufor jest pusty

16 mgr inż. Marcin Borkowski Niskopoziomowe We/Wy – Blokady danych w pliku (tylko pliki) ● dobrowolny (advisory) i wymuszony (mandatory) ● blokowanie wymuszone – nie jest standaryzowane przez POSIX ! – specjalna opcja mount oraz ustawienie uprawnień dla pliku g+s g-x (Linux) ● wyłączna blokada zapisu (write lock) ● współdzielona między wiele procesów blokada odczytu (read lock) ● funkcje read/write nie blokują domyślnie żadnych danych w pliku ● dane poza końcem pliku też mogą być zablokowane

17 mgr inż. Marcin Borkowski Niskopoziomowe We/Wy ● blokady są związane z procesem, każdy bajt danych można blokować oddzielnie ● blokady nie są dziedziczone ● funkcja close zwalnia wszystkie blokady w danym pliku nawet jeśli w tym samym procesie mamy inne deskryptory tego samego pliku !!!! ● funkcja exit zwalnia wszystkie blokady ● proces może zwalniać blokady na innych częściach pliku niż je zajmował (zwolnienie kilku blokad za jednym razem, rozbicie blokady na 2 części itp.) ● do obsługi blokad służy funkcja fcntl – F_GETLK, F_SETLK – F_SETLKW (czeka na możliwość zajęcia blokady)

18 mgr inż. Marcin Borkowski Katalog – Nazwy plików, hierarchia katalogów (FHS) – Separator nazw katalogów (/) – Wielokrotne wystąpienie znaku separatora (//) jest traktowane jako pojedynczy znak (/) w systemach GNU – Wyszukiwanie plików na podstawie ścieżki (rezolucja) ● ścieżki bezwzględne ● ścieżki względne ● wyszukiwanie plików wykonywalnych w katalogach PATH ● lokalne wykonywalne pliki (./binary ) – Specjalne katalogi (.) oraz (..)

19 mgr inż. Marcin Borkowski Katalog – Katalog roboczy (CWD): getcwd – Nie należy używać – getwd ze względu na możliwość przepełnienia bufora – CWD można zmieniać (funkcja chdir) ● zmiana obowiązuje tylko dla danego procesu (nie rodzica) – Katalogi dla wielu FS są implementowane na specjalnych plikach – Odczyt zawartości katalogu jest zorganizowany podobnie do strumienia: ● struct dirent – jedyne pole opisane przez standard POSIX to d_name !!! ● pozostałe atrybuty można odczytać funkcjami stat i lstat

20 mgr inż. Marcin Borkowski Katalog – opendir otwiera strumień katalogu (directory stream) ● implementacja może być oparta na zwykłych plikach ● proces może wyczerpać limit deskryptorów ● nie wolno współdzielić otwartych strumieni katalogów z procesami potomnymi – readdir odczytuje następny wpis w katalogu ● zwracana struktura dirent jest statycznie alokowana i podczas następnego wywołania będzie nadpisana !!! ● błąd i koniec katalogu są tak samo sygnalizowane !!! ● przed wywołaniem należy wyzerować errno aby odróżnić błąd od końca katalogu (patrz przykłady) ● nie można bezpieczna używać tej funkcji w wątkach, bezpieczny odpowiednik to readdir_r

21 mgr inż. Marcin Borkowski Katalog – readdir cd. ● pliki skasowane lub dodane po opendir nie muszą być poprawnie uwzględniane w wynikach – closedir zamyka strumień katalogu – rewinddir rozpoczyna ponowny odczyt katalogu z uwzględnieniem zmian (nowe i skasowane pliki) – telldir zwraca pozycje w katalogu ● pozycja taka staje się niepoprawna na skutek wywołania rewinddir lub pary closedir i opendir – seekdir zmienia pozycję w katalogu atrybut position musi pochodzić od wywołania telldir

22 mgr inż. Marcin Borkowski Katalog – Funkca scandir wraz z alphasort nie są częścią standardu POSIX i choć są przydatne należy ich unikać – Zamiast tego POSIX definiuje ftw oraz nftw ● funkcja callback wywołana dla każdego znalezionego obiektu ● możliwość limitowania ilości użytych deskryptorów ● funkcja callback nie może zmieniać CWD ● dodatkowo nftw posiada flagi: – FTW_CHDIR -zmienia CWD zgodnie z obiektem dla którego następuje wyołanie callback, CWD jest później przywracane – FTW_DEPTH – użyj algorytmu wgłąb, wpp. algorytm w szerz – FTW_PHYS – nie podążaj za linkami symbolicznymi ● zarówno ftw jak i nftw z natury rzeczy nie mogą być współbieżnie użyte w wątkach

23 mgr inż. Marcin Borkowski Katalog – Ścieżki do plików w formie kanonicznej ● bez dowiązań symbolicznych, ● bez (.) oraz (..) w ścieżce ● bez powtarzających się separatorów (//) ● funkcja canonicalize_file_name – dodatek GNU (nie POSIX) – alokuje pamięć, którą trzeba później ręcznie zwolić free ● funkcja realpath – zgodna z POSIX – wymaga podania bufora, brak kontroli rozmiaru (b.niebezpieczna) – może samodzielnie alokować bufor ale ta opcja nie jest obowiązkowa i może nie być obecna w niektórych implementacjach !

24 mgr inż. Marcin Borkowski Katalog – Pliki tymczasowe ● funkcja tmpfile tworzy tymczasowy plik (strumień) – nie daje kontroli co do lokalizacji pliku i jego nazwy – plik jest kasowany na skutek wywołania close lub exit – w razie nagłego zakończenia programu (np. SIGKILL) plik taki może pozostać nieskasowany – funkcja może być bezpiecznie użyta w wątkach ● funkcje tmpnam, tmpnam_r oraz tempnam generują nazwę dla pliku tymczasowego – proces samodzielnie musi plik otworzyć i zamknąć – nazwa może okazać się zajęta (zawsze otwieramy z O_EXCL | O_CREAT ) – tmpnam nie może być używana współbieżnie w wątkach

25 mgr inż. Marcin Borkowski Katalog – Atrybuty plików ● wszystkie poza nazwą są przechowywane w inode ● standard POSIX opisuje jedynie następujące pola struktury stat : – st_mode – uprawnienia i typ – st_ino – st_dev – st_uid,st_gid – st_atime,st_ctime, i st_mtime – st_nlink ● typ st_mode można sprawdzac następującymi makrami: – S_ISDIR(mode_t m), S_ISREG(mode_t m) – S_ISLNK (mode_t m)

26 mgr inż. Marcin Borkowski Katalog – Atrybuty plików cd. ● funkcje stat oraz fstat odczytują atrybuty pojedynczego pliku – jeśli podana plik jest łączem symbolicznym, stat sprawdza dokąd prowadzi łącze i sprawdza wskazywany obiekt (rekursywnie) – nie jest możliwe aby makro S_ISLNK (mode_t m) zwróciło niezerowy status dla parametru otrzymanego z funkcji stat ● funkcja lstat nie podąża za linkami symbolicznymi – pozwala odczytać atrybuty linku symbolicznego

27 mgr inż. Marcin Borkowski Katalog – „umask” procesu ● za każdym razem gdy nowy obiekt jest tworzony, wybrane przez uprawnienia są modyfikowane przez maskę umask ● bity ustawione w masce są odbierane z uprawnień ● wartość umask jest ustawiana dla sesji użytkownika i dziedziczona przez procesy ● można zmieniać umask z linii poleceń (komenda umask ) ● sam proces może ją również kontrolować (funkcja umask ) ● nie należy bez powodu zmieniać tej wartości, z założenia ma to być mechanizm limitowania praw dostępu bez dobrego powodu go nie wyłączamy ! ● funkcja getumask jest dodatkiem GNU i jako traka nie przenośna

28 mgr inż. Marcin Borkowski Katalog – Kilka pozostałych użytecznych funkcji, które nie powinny sprawiać trudności (proszę poczytać dokumentację man pages) ● link, unlink ● rmdir, remove ● symlink, readlink ● rename ● mkdir ● chmod, fchmod

29 mgr inż. Marcin Borkowski Pliki i Katalogi w Przykładach ● Jak czytać dane : ssize_t bulk_read(int fd, char *buf, size_t count) { int c; size_t len=0; do { c = TEMP_FAILURE_RETRY(read(fd, buf, count)); if (c < 0) return c; if (0 == c) return len; buf += c; len += c; count -= c; } while(count > 0); return len ; }

30 mgr inż. Marcin Borkowski Pliki i Katalogi w Przykładach ● Jak zapisywać dane : ssize_t bulk_write(int fd, char *buf, size_t count) { int c; size_t len = 0; do { c = TEMP_FAILURE_RETRY(write(fd, buf, count)); if (c < 0) return c; buf += c; len += c; count -= c; } while(count > 0); return len ; }

31 mgr inż. Marcin Borkowski Pliki i Katalogi w Przykładach ● Jak przekierować stdout do pliku int pfd;... if (-1 == TEMP_FAILURE_RETRY(close(STDOUT_FILENO))) ERR(); if (-1 == dup(pfd)) ERR(); if (-1 == TEMP_FAILURE_RETRY(close(pfd))) ERR();... ● Jak przekierować stderr na stdout if (-1 == TEMP_FAILURE_RETRY(dup2(STDOUT_FILENO, STDERR_FILENO))) ERR();

32 mgr inż. Marcin Borkowski Pliki i Katalogi w Przykładach ● Jak ustawić blokadę pliku : void SetWrLock(int fd, int start, int len) { struct flock l; l.l_whence = SEEK_SET; l.l_start = start; l.l_len = len; l.l_type = F_WRLCK; if (-1 == TEMP_FAILURE_RETRY(fcntl(fd, F_SETLKW, &l))) ERR("fcntl"); }

33 mgr inż. Marcin Borkowski Pliki i Katalogi w Przykładach ● Jak odczytać katalog roboczy wpis po wpisie: if (NULL == (dirp = opendir("."))) ERR(); do { errno = 0; if ((dp = readdir(dirp)) != NULL) printf("found %s\n", dp->d_name); } while (dp != NULL); if (errno != 0) ERR(); TEMP_FAILURE_RETRY(closedir(dirp));

34 mgr inż. Marcin Borkowski Pliki i Katalogi w Przykładach ● Jak analizować strukturę dirent: if (lstat(filenamepath, &filestat) == -1) error("Cannot read file"); if (S_ISDIR(filestat.st_mode)) dirs++; else if (S_ISREG(filestat.st_mode)) files++; else if (S_ISLNK(filestat.st_mode)) links++; else other++;