Scroll to navigation

getdents(2) System Calls Manual getdents(2)

NAZWA

getdents, getdents64 - pobiera wpisy z katalogu

BIBLIOTEKA

Standardowa biblioteka C (libc, -lc)

SKŁADNIA

#include <sys/syscall.h>           /* Definicja stałych SYS_* */
#include <unistd.h>
long syscall(SYS_getdents, unsigned int fd, struct linux_dirent *dirp,
             unsigned int count);
#define _GNU_SOURCE           /* Zob. feature_test_macros(7) */
#include <dirent.h>
ssize_t getdents64(int fd, void dirp[.count], size_t count);

Uwaga: glibc nie udostępnia opakowania dla getdents(), co wymusza użycie syscall(2).

Note: W glibc brak definicji struct linux_dirent; zob. UWAGI.

OPIS

Nie są to interfejsy, które cię interesują. Opis implementacji interfejsu zgodnego z POSIX w bibliotece C znajduje się w readdir(3). Niniejsza strona opisuje nagi interfejs wywołania systemowego.

getdents()

Wywołanie systemowe getdents() odczytuje kolejne struktury linux_dirent z katalogu wskazywanego przez przez deskryptor otwartego pliku fd do bufora wskazywanego przez dirp. Argument count określa rozmiar tego bufora.

Struktura linux_dirent jest zadeklarowana następująco:


struct linux_dirent {

unsigned long d_ino; /* Numer i-węzła */
unsigned long d_off; /* Nie jest przesunięciem; zob. niżej */
unsigned short d_reclen; /* Długość tego linux_dirent */
char d_name[]; /* Nazwa pliku (zakończ. znakiem null) */
/* długość to faktycznie (d_reclen - 2 -
offsetof(struct linux_dirent, d_name)) */
/*
char pad; // Zerowy bajt wyrównania
char d_type; // Typ pliku (tylko od Linuksa
// 2.6.4); przesunięciem jest (d_reclen - 1)
*/ }

d_ino jest numerem i-węzła. d_off jest wartością zależną od systemu plików, która nie ma znaczenia dla przestrzeni użytkownika, choć w starszych systemach plików była odległością od początku katalogu do początku następnej struktury linux_dirent; zob. readdir(3). d_reclen jest wielkością tej całej struktury linux_dirent. d_name jest nazwą pliku zakończoną znakiem NUL.

d_type jest bajtem na końcu struktury wskazującym typ pliku. Zawiera jedną z następujących wartości (zdefiniowanym w <dirent.h>):

Jest to urządzenie blokowe
Jest to urządzenie znakowe.
Jest to katalog.
Jest to potok nazwany (FIFO).
Jest to dowiązanie symboliczne.
Jest to zwykły plik.
Jest to gniazdo dziedziny Uniksa.
Typ pliku jest nieznany.

Pole d_type zaimplementowano od Linuksa 2.6.4. Zajmuje miejsce, które wcześniej zajmował zerowy bajt wypełnienia w strukturze linux_dirent. Z tego względu jądra do Linuksa 2.6.3, próbujące uzyskać dostęp do tego pola zawsze zwracają wartość 0 (DT_UNKNOWN).

Obecnie jedynie niektóre systemy plików (m.in Btrfs, ext2, ext3 i ext4) obsługują w pełni zwracanie typu pliku w d_type. Wszystkie programy muszą poprawnie obsługiwać zwrócenie wartości DT_UNKNOWN.

getdents64()

Pierwotne, linuksowe wywołanie getdents() nie obsługiwało dużych systemów plików i dużych przesunięć pliku. Z tego powodu, Linux 2.4 dodał getdents64(), z szerszymi typami pól d_ino i d_off. Dodatkowo, getdents64() obsługuje wprost pole d_type.

Wywołanie systemowe getdents64() zachowuje się jak getdents(), tyle że jego drugi argument jest wskaźnikiem do bufora zawierającego strukturę następującego typu:


struct linux_dirent64 {

ino64_t d_ino; /* 64-bitowy numer i-węzła */
off64_t d_off; /* Nie jest przesunięciem, zob. getdents() */
unsigned short d_reclen; /* Rozmiar tego dirent */
unsigned char d_type; /* Typ pliku */
char d_name[]; /* Nazwa pliku (zakończona null) */ };

WARTOŚĆ ZWRACANA

Po pomyślnym zakończeniu zwracana jest ilość odczytanych bajtów. Na końcu katalogu zwracane jest 0. Przy błędzie zwracane jest -1 i ustawiane errno wskazując błąd.

BŁĘDY

Nieprawidłowy deskryptor fd.
Argument wskazuje poza przestrzeń adresową wywołującego procesu.
Bufor na wynik jest za mały.
Nie ma takiego katalogu.
Deskryptor pliku nie odnosi się do katalogu.

STANDARDY

Brak.

HISTORIA

SVr4.

glibc 2.30.

UWAGI

glibc nie udostępnia opakowania dla getdents(); należy je wywołać za pomocą syscall(2). W takim przypadku konieczne będzie samodzielne zdefiniowanie struktury linux_dirent lub linux_dirent64.

Zamiast opisywanych wywołań systemowych, prawdopodobnie lepszym pomysłem będzie użycie readdir(3).

Te wywołania zastępują readdir(2).

PRZYKŁADY

Program poniżej demonstruje użycie getdents(). Poniższe wyjście pokazuje przykład, w którym można zaobserwować działanie tego programu w katalogu ext2:


$ ./a.out /testfs/
--------------- nread=120 ---------------
i-węzeł#  typ pliku  d_reclen  d_off   d_name

2 katalog 16 12 .
2 katalog 16 24 ..
11 katalog 24 44 lost+found
12 zwykły 16 56 a
228929 katalog 16 68 sub
16353 katalog 16 80 sub2
130817 katalog 16 4096 sub3

Kod źródłowy programu

#define _GNU_SOURCE
#include <dirent.h>     /* Definiuje stałe DT_* */
#include <err.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
struct linux_dirent {

unsigned long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[]; }; #define BUF_SIZE 1024 int main(int argc, char *argv[]) {
int fd;
char d_type;
char buf[BUF_SIZE];
long nread;
struct linux_dirent *d;
fd = open(argc > 1 ? argv[1] : ".", O_RDONLY | O_DIRECTORY);
if (fd == -1)
err(EXIT_FAILURE, "open");
for (;;) {
nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
if (nread == -1)
err(EXIT_FAILURE, "getdents");
if (nread == 0)
break;
printf("--------------- nread=%ld ---------------\n", nread);
printf("i-węzeł# typ pliku d_reclen d_off d_name\n");
for (size_t bpos = 0; bpos < nread;) {
d = (struct linux_dirent *) (buf + bpos);
printf("%8lu ", d->d_ino);
d_type = *(buf + bpos + d->d_reclen - 1);
printf("%-10s ", (d_type == DT_REG) ? "zwykły" :
(d_type == DT_DIR) ? "katalog" :
(d_type == DT_FIFO) ? "FIFO" :
(d_type == DT_SOCK) ? "gniazdo" :
(d_type == DT_LNK) ? "dow. symbol." :
(d_type == DT_BLK) ? "urz. blok." :
(d_type == DT_CHR) ? "urz. znak." : "???");
printf("%4d %10jd %s\n", d->d_reclen,
(intmax_t) d->d_off, d->d_name);
bpos += d->d_reclen;
}
}
exit(EXIT_SUCCESS); }

ZOBACZ TAKŻE

readdir(2), readdir(3), inode(7)

TŁUMACZENIE

Autorami polskiego tłumaczenia niniejszej strony podręcznika są: Przemek Borys <pborys@dione.ids.pl>, Andrzej Krzysztofowicz <ankry@green.mf.pg.gda.pl> i Michał Kułach <michal.kulach@gmail.com>

Niniejsze tłumaczenie jest wolną dokumentacją. Bliższe informacje o warunkach licencji można uzyskać zapoznając się z GNU General Public License w wersji 3 lub nowszej. Nie przyjmuje się ŻADNEJ ODPOWIEDZIALNOŚCI.

Błędy w tłumaczeniu strony podręcznika prosimy zgłaszać na adres listy dyskusyjnej manpages-pl-list@lists.sourceforge.net.

2 maja 2024 r. Linux man-pages 6.8