Linux
2019-03-06
Aliases: getdents64(2), getdents64(2), getdents64(2), getdents64(2), getdents64(2), getdents64(2), getdents64(2), getdents64(2), getdents64(2), getdents64(2)
man-pages-ru
Russian man pages from the Linux Documentation Project
manpages-dev
Manual pages about using GNU/Linux for development
man-pages
Linux kernel and C library user-space interface documentation
ИМЯ
getdents, getdents64 - возвращает записи каталога
ОБЗОР
int getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count); int getdents64(unsigned int fd, struct linux_dirent64 *dirp, unsigned int count);
Замечание: В glibc нет обёрточных функций для этих системных вызовов; смотрите ЗАМЕЧАНИЯ.
ОПИСАНИЕ
Это не те функции, которые должны представлять для вас интерес. Смотрите описание функции readdir(3), которая является интерфейсом библиотеки языка C, соответствующим стандарту POSIX. В этой странице описаны минимальные интерфейсы системных вызовов ядра.
getdents()
Системный вызов getdents() читает несколько структур linux_dirent из каталога, на который указывает открытый файловый дескриптор fd, в буфер, указанный в dirp. В аргументе count задаётся размер этого буфера.
Поле d_type появилось начиная с Linux 2.6.4. Оно занимает пространство, которое раньше в структуре linux_dirent было отведено для заполняющего байта с нулевым значением. Поэтому при работе с ядрами до версии 2.6.3 включительно при чтении значения этого поля всегда возвращается 0 (DT_UNKNOWN).
Структура linux_dirent определена следующим образом:
struct linux_dirent {
unsigned long d_ino; /* номер иноды */
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)
*/ }
unsigned long d_ino; /* номер иноды */
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>):
DT_BLK | Блочное устройство. |
DT_CHR | Символьное устройство. |
DT_DIR | Каталог. |
DT_FIFO | Именованный канал (FIFO). |
DT_LNK | Символическая ссылка. |
DT_REG | Обычный файл. |
DT_SOCK | Доменный сокет UNIX. |
DT_UNKNOWN | Неизвестный тип. |
В настоящее время, только файловые системы (среди которых: Btrfs, ext2, ext3 и ext4) поддерживают возврат типа файла в d_type. Все приложения должны правильно обрабатывать возвращаемое значение DT_UNKNOWN.
getdents64()
Первоначальный системный вызов Linux getdents() не работал с файловыми системами большого размера и большими смещениями файлов. В связи с этим, в Linux 2.4 была добавлен getdents64(), с более широкими типами полей d_ino и d_off. Также getdents64() поддерживает явно указанное поле d_type.
Системный вызов getdents64() подобен getdents(), за исключением того, что второй аргумент является указателем на буфер, содержащий структуры следующего типа:
struct linux_dirent64 {
ino64_t d_ino; /* 64-битный номер иноды */
off64_t d_off; /* 64-битное смещение следующей структуры */
unsigned short d_reclen; /* размер этой dirent */
unsigned char d_type; /* тип файла */
char d_name[]; /* имя файла (в конце null) */ };
ino64_t d_ino; /* 64-битный номер иноды */
off64_t d_off; /* 64-битное смещение следующей структуры */
unsigned short d_reclen; /* размер этой dirent */
unsigned char d_type; /* тип файла */
char d_name[]; /* имя файла (в конце null) */ };
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При нормальном завершении работы возвращается количество прочитанных байт. При достижении конца каталога возвращается 0. В случае ошибки возвращается -1 и значение errno устанавливается соответствующим образом.
ОШИБКИ
EBADF | Неверный файловый дескриптор fd. |
EFAULT | Аргумент указывает за пределы адресного пространства вызывающего процесса. |
EINVAL | Буфер результата слишком мал. |
ENOENT | Заданный каталог не существует. |
ENOTDIR | |
Файловый дескриптор указывает не на каталог. |
СООТВЕТСТВИЕ СТАНДАРТАМ
SVr4.
ЗАМЕЧАНИЯ
В glibc нет обёртки для данных системных вызовов; запускайте их с помощью syscall(2). Структуру linux_dirent или linux_dirent64 нужно определить самостоятельно. Однако лучше использовать readdir(3).
Данные системные вызовы заместил readdir(2).
ПРИМЕР
В программе, показанной далее, демонстрируется использование getdents(). В следующем выводе показан пример запуска этой программы с каталогом с ext2:
$ ./a.out /testfs/ --------------- nread=120 --------------- inode# 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
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)
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[]; };
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;
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");
if (fd == -1)
handle_error("open");
for ( ; ; ) {
nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
if (nread == -1)
handle_error("getdents");
nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
if (nread == -1)
handle_error("getdents");
if (nread == 0)
break;
break;
printf("--------------- nread=%d ---------------\n", nread);
printf("inode# 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, d->d_name);
bpos += d->d_reclen;
}
}
printf("inode# 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, d->d_name);
bpos += d->d_reclen;
}
}
exit(EXIT_SUCCESS); }