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.

Slides:



Advertisements
Podobne prezentacje
Tablice 1. Deklaracja tablicy
Advertisements

Wstęp do strumieni danych
C++ wykład 4 ( ) Przeciążanie operatorów.
Język C/C++ Funkcje.
Mechanizmy pracy równoległej
Dzisiejszy wykład Wyjątki.
Wzorce.
SYSTEMY OPERACYJNE SYSTEMY PLIKÓW
Systemy rozproszone W. Bartkiewicz
Kamil Smitkiewicz Bezpieczeństwo w PHP.
Zabezpieczenia w programie MS Access
ELEMENTY SKŁADOWE JEDNOSTKI CENTRALNEJ
Zakres i zasięg deklaracji Zakres : obszar programu, w którym identyfikator może być użyty zakres globalny : cały program zakres lokalny : definicja pojedynczej.
Inżynieria oprogramowania Lecture XXX JavaTM – część IV: IO
Systemy plików UNIX Krzysztof Ratkowski Mateusz Wosiński.
Systemy operacyjne Wykład nr 5: Wątki Piotr Bilski.
Biblioteki i przestrzenie nazw
Podstawowe komendy UNIXA
Programowanie w C Wykład 3
Język ANSI C Operacje we/wy
Muteksy Muteksy (mutex – MUTual EXclusion) są prostymi obiektami synchronizacyjnymi pełniącymi rolę semaforów binarnych dla wątków (chroniącymi sekcje.
Semafory według normy POSIX
10. PROSTE MECHANIZMY KOORDYNACJI DOSTĘPNE W JĘZYKU C W systemie Unix użytkownikowi (nie będącemu administratorem) nie wolno wykonywać bezpośrednio żadnych.
9. KOORDYNACJA PROCESÓW WSPÓŁBIEŻNYCH PRZY UŻYCIU INTERPRETATORA
1 Podstawy informatyki H. P. Janecki- 2006_ Systemy Operacyjne W6.
Procesy odrębne –Unikatowy PID ( ) –Zmienne –Zbiory deskryptorów plików –Przestrzeń stosu (lokalne zmienne, wywołania funkcji) –Środowisko –Licznik.
Wątki.
Konfiguracja polcenie SUDO
Pamięć wspólna Opis własnego rozwiązania Marcin Kamiński, Michał Kotra Wydział EAIiE Katedra Automatyki Kraków, 2008.
Pamięć wspólna Przegląd stosowanych rozwiązań Marcin Kamiński, Michał Kotra Wydział EAIiE Katedra Automatyki Kraków, 2008.
SIEĆ P2P 1. Definicja sieci równouprawnionej. To taka sieć, która składa się z komputerów o takim samym priorytecie ważności, a każdy z nich może pełnić.
Podstawy programowania
Pakiety w Javie Łukasz Smyczyński (132834). Czym są pakiety? Klasy w Javie są grupowane w pewne zbiory zwane pakietami. Pakiety są więc pewnym podzbiorem.
Podstawy programowania II
Podstawy programowania II Wykład 2: Biblioteka stdio.h Zachodniopomorska Szkoła Biznesu.
Pliki tekstowe. Operacje na plikach. mgr inż. Agata Pacek.
Tworzenie nowych kont lokalnych i domenowych, oraz zarządzanie nimi
Linux - polecenia.
Wielodostępność systemu operacyjnego Linux
W większości języków programowania biblioteki wejścia/wyjścia ukrywają szczegóły obsługi poszczególnych mediów pod abstrakcją strumienia (ang. stream).
Instrukcja USOS Rejestracja na zajęcia obieralne wersja by Marek Opacki.
Pliki tekstowe – A. Jędryczkowski © 2007 Turbo Pascal umożliwia wykorzystanie w programach plików tekstowych. Pliki takie zawierają informację niezakodowaną
Prezentacja i szkolenie
Systemy wejścia i wyjścia Michał Wrona. Co to jest system wejścia i wyjścia? Pobierania informacji ze źródeł danych, zdolnych przesyłać sekwencje bajtów,
Programowanie obiektowe Wykład 3 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21 Dariusz Wardowski.
Problem sekcji krytycznej
Przerwanie ang. interrupt.
Buforowanie D e f i n i c j a.
Koncepcja procesu Zadanie i proces. Definicja procesu Process – to program w trakcie wykonywania; wykonanie procesu musi przebiegać w sposób sekwencyjny.
MICROSOFT Access TWORZENIE MAKR
1 Strumienie Hierarchie klas strumieniowych, strumienie bajtowe - klasy InputStream i OutputStream i ich metody, klasa File, strumienie plikowe, strumienie.
Wykład 7 Synchronizacja procesów i wątków
Systemy operacyjne (wiosna 2014)
Wzorce slajdów programu microsoft powerpoint
Bariery synchronizacyjne Bariery są obiektami synchronizacyjnymi pakietu pthread służącymi do wyrównywania czasów pracy wątków wykonujących wspólne zadanie.
Podstawy programowania II Wykład 3: Obsługa plików w stdio.h.
System plików.
Kurs języka C++ – wykład 4 ( )
Paweł Starzyk Obiektowe metody projektowania systemów
Dowiązania (linki) twarde i symboliczne
Seminarium Dyplomowe: Metodyka i Techniki Programowania Autor: Bartłomiej Fornal.
1 Architektury Komputerów i Systemy Operacyjne Prowadzący przedmiot: dr inż. Rafał Stankiewicz Data:
Strumienie w języku Java Bartosz Walter InMoST Wielkopolska sieć współpracy w zakresie innowacyjnych metod wytwarzania oprogramowania Termin realizacji:
Temat: Tworzenie bazy danych
C++ mgr inż. Tomasz Turba Politechnika Opolska 2016.
Piotr Kawałek , Mateusz Śliwowski
Strumienie, Wczytywanie, Zapisywanie, Operacje na plikach
PROGRAMY DO KONTROLI RODZICIELSKIEJ
PROGRAMY DO KONTROLI RODZICIELSKIEJ
Zapis prezentacji:

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 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

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)

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)

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

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ąć

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

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

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

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

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);

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)

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)

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);

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

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

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)

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 (..)

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

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

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

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

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 !

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

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)

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

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

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

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 ; }

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 ; }

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();

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"); }

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));

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++;