// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2016 CTERA Networks. All Rights Reserved. * Author: Amir Goldstein */ /* * t_dir_type * * print directory entries and their file type, optionally filtered by d_type * or by inode number. * * ./t_dir_type [u|f|d|c|b|l|p|s|w|] */ #include #include #include #include #include #include #include #include struct linux_dirent64 { uint64_t d_ino; int64_t d_off; unsigned short d_reclen; unsigned char d_type; char d_name[0]; }; #define DT_MASK 15 #define DT_MAX 15 unsigned char type_to_char[DT_MAX] = { [DT_UNKNOWN] = 'u', [DT_DIR] = 'd', [DT_REG] = 'f', [DT_LNK] = 'l', [DT_CHR] = 'c', [DT_BLK] = 'b', [DT_FIFO] = 'p', [DT_SOCK] = 's', [DT_WHT] = 'w', }; #define DT_CHAR(t) type_to_char[(t)&DT_MASK] #define BUF_SIZE 4096 int main(int argc, char *argv[]) { int fd, nread; char buf[BUF_SIZE]; struct linux_dirent64 *d; int bpos; int type = -1; /* -1 means all types */ uint64_t ino = 0; int ret = 1; fd = open(argv[1], O_RDONLY | O_DIRECTORY); if (fd < 0) { perror("open"); exit(EXIT_FAILURE); } if (argc > 2 && argv[2][0]) { char t = argv[2][0]; for (type = DT_MAX-1; type >= 0; type--) if (DT_CHAR(type) == t) break; /* no match ends up with type = -1 */ if (type < 0) ino = strtoul(argv[2], NULL, 10); } for ( ; ; ) { nread = syscall(SYS_getdents64, fd, buf, BUF_SIZE); if (nread == -1) { perror("getdents"); exit(EXIT_FAILURE); } if (nread == 0) break; for (bpos = 0; bpos < nread;) { d = (struct linux_dirent64 *) (buf + bpos); if ((type < 0 || type == (int)d->d_type) && (!ino || ino == d->d_ino)) { ret = 0; printf("%s %c\n", d->d_name, DT_CHAR(d->d_type)); } bpos += d->d_reclen; } } return ret; }