fs/readdir.c
Source file repositories/reference/linux-study-clean/fs/readdir.c
File Facts
- System
- Linux kernel
- Corpus path
fs/readdir.c- Extension
.c- Size
- 15484 bytes
- Lines
- 574
- Domain
- Core OS
- Bucket
- VFS And Filesystem Core
- Inferred role
- Core OS: syscall or user/kernel boundary
- Status
- core implementation candidate
Why This File Exists
Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.
- Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.
- Defines or participates in a user/kernel boundary; inspect argument validation, copy_from_user/copy_to_user, credentials, and dispatch target.
- Touches user memory; correctness depends on fault-safe copying and privilege boundary handling.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/stddef.hlinux/kernel.hlinux/export.hlinux/time.hlinux/mm.hlinux/errno.hlinux/stat.hlinux/file.hlinux/fs.hlinux/fsnotify.hlinux/dirent.hlinux/security.hlinux/syscalls.hlinux/unistd.hlinux/compat.hlinux/uaccess.h
Detected Declarations
syscall old_readdirsyscall getdentssyscall getdents64struct old_linux_direntstruct readdir_callbackstruct linux_direntstruct getdents_callbackstruct getdents_callback64struct compat_old_linux_direntstruct compat_readdir_callbackstruct compat_linux_direntstruct compat_getdents_callbackfunction Copyrightfunction iterate_dirfunction strlenfunction fillonedirfunction filldirfunction filldir64function compat_fillonedirfunction compat_filldirexport wrap_directory_iteratorexport iterate_dir
Annotated Snippet
SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
struct old_linux_dirent __user *, dirent, unsigned int, count)
{
int error;
CLASS(fd_pos, f)(fd);
struct readdir_callback buf = {
.ctx.actor = fillonedir,
.ctx.count = 1, /* Hint to fs: just one entry. */
.dirent = dirent
};
if (fd_empty(f))
return -EBADF;
error = iterate_dir(fd_file(f), &buf.ctx);
if (buf.result)
error = buf.result;
return error;
}
#endif /* __ARCH_WANT_OLD_READDIR */
/*
* New, all-improved, singing, dancing, iBCS2-compliant getdents()
* interface.
*/
struct linux_dirent {
unsigned long d_ino;
unsigned long d_off;
unsigned short d_reclen;
char d_name[];
};
struct getdents_callback {
struct dir_context ctx;
struct linux_dirent __user * current_dir;
int prev_reclen;
int error;
};
static bool filldir(struct dir_context *ctx, const char *name, int namlen,
loff_t offset, u64 ino, unsigned int d_type)
{
struct linux_dirent __user *dirent, *prev;
struct getdents_callback *buf =
container_of(ctx, struct getdents_callback, ctx);
unsigned long d_ino;
int reclen = ALIGN(dirent_size(dirent, namlen + 2), sizeof(long));
int prev_reclen;
unsigned int flags = d_type;
BUILD_BUG_ON(FILLDIR_FLAG_NOINTR & S_DT_MASK);
d_type &= S_DT_MASK;
buf->error = verify_dirent_name(name, namlen);
if (unlikely(buf->error))
return false;
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > ctx->count)
return false;
d_ino = ino;
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
buf->error = -EOVERFLOW;
return false;
}
prev_reclen = buf->prev_reclen;
if (!(flags & FILLDIR_FLAG_NOINTR) && prev_reclen && signal_pending(current))
return false;
dirent = buf->current_dir;
prev = (void __user *) dirent - prev_reclen;
scoped_user_write_access_size(prev, reclen + prev_reclen, efault) {
/* This might be 'dirent->d_off', but if so it will get overwritten */
unsafe_put_user(offset, &prev->d_off, efault);
unsafe_put_user(d_ino, &dirent->d_ino, efault);
unsafe_put_user(reclen, &dirent->d_reclen, efault);
unsafe_put_user(d_type, (char __user *)dirent + reclen - 1, efault);
unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault);
}
buf->current_dir = (void __user *)dirent + reclen;
buf->prev_reclen = reclen;
ctx->count -= reclen;
return true;
efault:
buf->error = -EFAULT;
return false;
}
SYSCALL_DEFINE3(getdents, unsigned int, fd,
Annotation
- Immediate include surface: `linux/stddef.h`, `linux/kernel.h`, `linux/export.h`, `linux/time.h`, `linux/mm.h`, `linux/errno.h`, `linux/stat.h`, `linux/file.h`.
- Detected declarations: `syscall old_readdir`, `syscall getdents`, `syscall getdents64`, `struct old_linux_dirent`, `struct readdir_callback`, `struct linux_dirent`, `struct getdents_callback`, `struct getdents_callback64`, `struct compat_old_linux_dirent`, `struct compat_readdir_callback`.
- Atlas domain: Core OS / VFS And Filesystem Core.
- Implementation status: core implementation candidate.
- This snippet crosses the user/kernel memory boundary; validate fault handling and access checks before translating the pattern.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.