4 * Copyright (C) 1995 Linus Torvalds
7 #include <linux/sched.h>
9 #include <linux/errno.h>
10 #include <linux/stat.h>
11 #include <linux/file.h>
12 #include <linux/smp_lock.h>
14 #include <asm/uaccess.h>
16 int vfs_readdir(struct file *file, filldir_t filler, void *buf)
18 struct inode *inode = file->f_dentry->d_inode;
20 if (!file->f_op || !file->f_op->readdir)
23 down(&inode->i_zombie);
25 if (!IS_DEADDIR(inode)) {
27 res = file->f_op->readdir(file, buf, filler);
36 int dcache_dir_open(struct inode *inode, struct file *file)
38 static struct qstr cursor_name = {len:1, name:"."};
40 file->private_data = d_alloc(file->f_dentry, &cursor_name);
42 return file->private_data ? 0 : -ENOMEM;
45 int dcache_dir_close(struct inode *inode, struct file *file)
47 dput(file->private_data);
51 loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin)
53 down(&file->f_dentry->d_inode->i_sem);
56 offset += file->f_pos;
61 up(&file->f_dentry->d_inode->i_sem);
64 if (offset != file->f_pos) {
66 if (file->f_pos >= 2) {
68 struct dentry *cursor = file->private_data;
69 loff_t n = file->f_pos - 2;
71 spin_lock(&dcache_lock);
72 p = file->f_dentry->d_subdirs.next;
73 while (n && p != &file->f_dentry->d_subdirs) {
75 next = list_entry(p, struct dentry, d_child);
76 if (!list_empty(&next->d_hash) && next->d_inode)
80 list_del(&cursor->d_child);
81 list_add_tail(&cursor->d_child, p);
82 spin_unlock(&dcache_lock);
85 up(&file->f_dentry->d_inode->i_sem);
89 int dcache_dir_fsync(struct file * file, struct dentry *dentry, int datasync)
95 * Directory is locked and all positive dentries in it are safe, since
96 * for ramfs-type trees they can't go away without unlink() or rmdir(),
97 * both impossible due to the lock on directory.
100 int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
102 struct dentry *dentry = filp->f_dentry;
103 struct dentry *cursor = filp->private_data;
104 struct list_head *p, *q = &cursor->d_child;
110 ino = dentry->d_inode->i_ino;
111 if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
117 spin_lock(&dcache_lock);
118 ino = dentry->d_parent->d_inode->i_ino;
119 spin_unlock(&dcache_lock);
120 if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
126 spin_lock(&dcache_lock);
127 if (filp->f_pos == 2) {
129 list_add(q, &dentry->d_subdirs);
131 for (p=q->next; p != &dentry->d_subdirs; p=p->next) {
133 next = list_entry(p, struct dentry, d_child);
134 if (list_empty(&next->d_hash) || !next->d_inode)
137 spin_unlock(&dcache_lock);
138 if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos, next->d_inode->i_ino, DT_UNKNOWN) < 0)
140 spin_lock(&dcache_lock);
141 /* next is still alive */
147 spin_unlock(&dcache_lock);
152 struct file_operations dcache_dir_ops = {
153 open: dcache_dir_open,
154 release: dcache_dir_close,
155 llseek: dcache_dir_lseek,
156 read: generic_read_dir,
157 readdir: dcache_readdir,
158 fsync: dcache_dir_fsync,
162 * Traditional linux readdir() handling..
164 * "count=1" is a special case, meaning that the buffer is one
165 * dirent-structure in size and that the code can't handle more
166 * anyway. Thus the special "fillonedir()" function for that
167 * case (the low-level handlers don't need to care about this).
169 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
170 #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
174 struct old_linux_dirent {
176 unsigned long d_offset;
177 unsigned short d_namlen;
181 struct readdir_callback {
182 struct old_linux_dirent * dirent;
186 static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset,
187 ino_t ino, unsigned int d_type)
189 struct readdir_callback * buf = (struct readdir_callback *) __buf;
190 struct old_linux_dirent * dirent;
195 dirent = buf->dirent;
196 put_user(ino, &dirent->d_ino);
197 put_user(offset, &dirent->d_offset);
198 put_user(namlen, &dirent->d_namlen);
199 copy_to_user(dirent->d_name, name, namlen);
200 put_user(0, dirent->d_name + namlen);
204 asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count)
208 struct readdir_callback buf;
218 error = vfs_readdir(file, fillonedir, &buf);
227 #endif /* !__ia64__ */
230 * New, all-improved, singing, dancing, iBCS2-compliant getdents()
233 struct linux_dirent {
236 unsigned short d_reclen;
240 struct getdents_callback {
241 struct linux_dirent * current_dir;
242 struct linux_dirent * previous;
247 static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
248 ino_t ino, unsigned int d_type)
250 struct linux_dirent * dirent;
251 struct getdents_callback * buf = (struct getdents_callback *) __buf;
252 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
254 buf->error = -EINVAL; /* only used if we fail.. */
255 if (reclen > buf->count)
257 dirent = buf->previous;
259 put_user(offset, &dirent->d_off);
260 dirent = buf->current_dir;
261 buf->previous = dirent;
262 put_user(ino, &dirent->d_ino);
263 put_user(reclen, &dirent->d_reclen);
264 copy_to_user(dirent->d_name, name, namlen);
265 put_user(0, dirent->d_name + namlen);
266 ((char *) dirent) += reclen;
267 buf->current_dir = dirent;
268 buf->count -= reclen;
272 asmlinkage long sys_getdents(unsigned int fd, void * dirent, unsigned int count)
275 struct linux_dirent * lastdirent;
276 struct getdents_callback buf;
284 buf.current_dir = (struct linux_dirent *) dirent;
289 error = vfs_readdir(file, filldir, &buf);
293 lastdirent = buf.previous;
295 put_user(file->f_pos, &lastdirent->d_off);
296 error = count - buf.count;
306 * And even better one including d_type field and 64bit d_ino and d_off.
308 struct linux_dirent64 {
311 unsigned short d_reclen;
312 unsigned char d_type;
316 #define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
318 struct getdents_callback64 {
319 struct linux_dirent64 * current_dir;
320 struct linux_dirent64 * previous;
325 static int filldir64(void * __buf, const char * name, int namlen, loff_t offset,
326 ino_t ino, unsigned int d_type)
328 struct linux_dirent64 * dirent, d;
329 struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf;
330 int reclen = ROUND_UP64(NAME_OFFSET(dirent) + namlen + 1);
332 buf->error = -EINVAL; /* only used if we fail.. */
333 if (reclen > buf->count)
335 dirent = buf->previous;
338 copy_to_user(&dirent->d_off, &d.d_off, sizeof(d.d_off));
340 dirent = buf->current_dir;
341 buf->previous = dirent;
342 memset(&d, 0, NAME_OFFSET(&d));
346 copy_to_user(dirent, &d, NAME_OFFSET(&d));
347 copy_to_user(dirent->d_name, name, namlen);
348 put_user(0, dirent->d_name + namlen);
349 ((char *) dirent) += reclen;
350 buf->current_dir = dirent;
351 buf->count -= reclen;
355 asmlinkage long sys_getdents64(unsigned int fd, void * dirent, unsigned int count)
358 struct linux_dirent64 * lastdirent;
359 struct getdents_callback64 buf;
367 buf.current_dir = (struct linux_dirent64 *) dirent;
372 error = vfs_readdir(file, filldir64, &buf);
376 lastdirent = buf.previous;
378 struct linux_dirent64 d;
379 d.d_off = file->f_pos;
380 copy_to_user(&lastdirent->d_off, &d.d_off, sizeof(d.d_off));
381 error = count - buf.count;