Scroll to navigation

GETDENTS(2) Руководство программиста Linux GETDENTS(2)

ИМЯ

getdents - получить записи каталога

ОБЗОР

int getdents(unsigned int fd, struct linux_dirent *dirp,
             unsigned int count);

ОПИСАНИЕ

Эта не та функция, которая должна представлять для вас интерес. Смотрите описание функции readdir(3), которая является интерфейсом библиотеки языка C, соответствующим стандарту POSIX. В этой странице описан минимальный интерфейс системного вызова ядра.

Системный вызов getdents() читает несколько структур linux_dirent из каталога, на который указывает открытый файловый дескриптор fd, в буфер, указанный в dirp. В аргументе count задаётся размер этого буфера.

Структура linux_dirent определена следующим образом:


struct linux_dirent {

unsigned long d_ino; /* номер inode */
unsigned long d_off; /* смещение до следующей linux_dirent */
unsigned short d_reclen; /* длина данной linux_dirent */
char d_name[]; /* имя файла (завершается null) */
/* реальная длина (d_reclen - 2 -
offsetof(struct linux_dirent, d_name) */
/*
char pad; // нулевой байт заполнения
char d_type; // тип файла (начиная с Linux 2.6.4;
// смещение (d_reclen - 1))
*/ }

В d_ino указан номер inode. В d_off задаётся расстояние от начала каталога до начала следующей linux_dirent. В d_reclen указывается размер данного linux_dirent целиком. В d_name задаётся имя файла, завершающееся null.

d_type — байт в конце структуры, которым определяется тип файла. В нём содержится одно из следующих значений (определённых в <dirent.h>):

Блочное устройство.
Символьное устройство.
Каталог.
Именованный канал (FIFO).
Символическая ссылка.
Обычный файл.
Доменный сокет UNIX.
Неизвестный тип.

Поле d_type появилось начиная с Linux 2.6.4. Оно занимает пространство, которое раньше в структуре linux_dirent было отведено для заполняющего байта с нулевым значением. Поэтому при работе с ядрами до версии 2.6.3, при чтении значения этого поля всегда возвращается 0 (DT_UNKNOWN).

В настоящее время, только файловые системы (среди которых: Btrfs, ext2, ext3 и ext4) поддерживают возврат типа файла в d_type. Все приложения должны правильно обрабатывать возвращаемое значение DT_UNKNOWN.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При нормальном завершении работы возвращается количество прочитанных байт. При достижении конца каталога возвращается 0. В случае ошибки возвращается -1 и значение errno устанавливается соответствующим образом.

ОШИБКИ

Неверный файловый дескриптор fd.
Аргумент указывает за пределы адресного пространства вызывающего процесса.
Буфер результата слишком мал.
Заданный каталог не существует.
Файловый дескриптор указывает не на каталог.

СООТВЕТСТВИЕ СТАНДАРТАМ

SVr4.

ЗАМЕЧАНИЯ

В glibc нет обёртки для данного системного вызова; запускайте его с помощью syscall(2). Структуру linux_dirent нужно определить самостоятельно.

Этот вызов заменяет readdir(2).

Первоначальный системный вызов getdents() в Linux не умел работать с большими файловыми системами и файловыми смещениями. Позднее, в Linux 2.4 был добавлен вызов getdents64() с расширенными типами для полей d_ino и d_off структуры linux_dirent.

ПРИМЕР

В программе, показанной далее, демонстрируется использование getdents(). В следующем выводе показан пример запуска этой программы с каталогом с ext2:


$ ./a.out /testfs/
--------------- nread=120 ---------------
i-node#  file type  d_reclen  d_off   d_name

2 directory 16 12 .
2 directory 16 24 ..
11 directory 24 44 lost+found
12 regular 16 56 a
228929 directory 16 68 sub
16353 directory 16 80 sub2
130817 directory 16 4096 sub3

Исходный код программы

#define _GNU_SOURCE
#include <dirent.h>     /* Определяет константы DT_* */
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#define handle_error(msg) \

do { perror(msg); exit(EXIT_FAILURE); } while (0) struct linux_dirent {
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, nread;
char buf[BUF_SIZE];
struct linux_dirent *d;
int bpos;
char d_type;
fd = open(argc > 1 ? argv[1] : ".", O_RDONLY | O_DIRECTORY);
if (fd == -1)
handle_error("open");
for ( ; ; ) {
nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
if (nread == -1)
handle_error("getdents");
if (nread == 0)
break;
printf("--------------- nread=%d ---------------\n", nread);
printf("i-node# file type d_reclen d_off d_name\n");
for (bpos = 0; bpos < nread;) {
d = (struct linux_dirent *) (buf + bpos);
printf("%8ld ", d->d_ino);
d_type = *(buf + bpos + d->d_reclen - 1);
printf("%-10s ", (d_type == DT_REG) ? "regular" :
(d_type == DT_DIR) ? "directory" :
(d_type == DT_FIFO) ? "FIFO" :
(d_type == DT_SOCK) ? "socket" :
(d_type == DT_LNK) ? "symlink" :
(d_type == DT_BLK) ? "block dev" :
(d_type == DT_CHR) ? "char dev" : "???");
printf("%4d %10lld %s\n", d->d_reclen,
(long long) d->d_off, (char *) d->d_name);
bpos += d->d_reclen;
}
}
exit(EXIT_SUCCESS); }

СМОТРИТЕ ТАКЖЕ

readdir(2), readdir(3)

2010-11-21 Linux