patch-2.1.44 linux/fs/readdir.c
Next file: linux/fs/romfs/inode.c
Previous file: linux/fs/proc/scsi.c
Back to the patch index
Back to the overall index
- Lines: 267
- Date:
Sun Jul 6 20:13:54 1997
- Orig file:
v2.1.43/linux/fs/readdir.c
- Orig date:
Mon Jun 16 16:35:59 1997
diff -u --recursive --new-file v2.1.43/linux/fs/readdir.c linux/fs/readdir.c
@@ -1,35 +1,20 @@
/*
- * fs/readdir.c
+ * linux/fs/readdir.c
*
* Copyright (C) 1995 Linus Torvalds
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
-#ifdef CONFIG_TRANS_NAMES
-#include <linux/nametrans.h>
-#endif
-#include <linux/dalloc.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
-/* [T.Schoebel-Theuer] I am assuming that directories never get too large.
- * The problem is that getdents() delivers d_offset's that can be used
- * for lseek() by the user, so I must encode the status information for
- * name translation and dcache baskets in the offset.
- * Note that the linux man page getdents(2) does not mention that
- * the d_offset is fs-specific and can be used for lseek().
- */
-#define BASKET_BIT (1<<30) /* 31 is already used by affs */
-#define TRANS_BIT (1<<29)
-
/*
* Traditional linux readdir() handling..
*
@@ -50,9 +35,6 @@
struct readdir_callback {
struct old_linux_dirent * dirent;
- struct file * file;
- int translate;
- off_t oldoffset;
int count;
};
@@ -65,26 +47,11 @@
return -EINVAL;
buf->count++;
dirent = buf->dirent;
- copy_to_user(dirent->d_name, name, namlen);
- put_user(0, dirent->d_name + namlen);
-#ifdef CONFIG_TRANS_NAMES
- if(!buf->translate) {
- char * cut;
-#ifdef CONFIG_TRANS_RESTRICT
- struct inode * inode = buf->file->f_inode;
- cut = testname(inode && inode->i_gid != CONFIG_TRANS_GID, dirent->d_name);
-#else
- cut = testname(1, dirent->d_name);
-#endif
- if(cut) {
- put_user(0, cut);
- buf->translate = 1;
- }
- }
-#endif
put_user(ino, &dirent->d_ino);
put_user(offset, &dirent->d_offset);
put_user(namlen, &dirent->d_namlen);
+ copy_to_user(dirent->d_name, name, namlen);
+ put_user(0, dirent->d_name + namlen);
return 0;
}
@@ -93,7 +60,6 @@
int error = -EBADF;
struct file * file;
struct readdir_callback buf;
- off_t oldpos;
lock_kernel();
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
@@ -104,21 +70,11 @@
error = verify_area(VERIFY_WRITE, dirent, sizeof(struct old_linux_dirent));
if (error)
goto out;
- oldpos = file->f_pos;
- buf.file = file;
- buf.dirent = dirent;
buf.count = 0;
- buf.translate = 0;
- if(file->f_pos & TRANS_BIT) {
- file->f_pos &= ~TRANS_BIT;
- buf.translate = 1;
- }
+ buf.dirent = dirent;
error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir);
if (error < 0)
goto out;
- if(buf.translate) {
- file->f_pos = oldpos | TRANS_BIT;
- }
error = buf.count;
out:
unlock_kernel();
@@ -139,11 +95,8 @@
struct getdents_callback {
struct linux_dirent * current_dir;
struct linux_dirent * previous;
- struct file * file;
int count;
- int error;
- int restricted;
- int do_preload;
+ int error;
};
static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
@@ -152,51 +105,18 @@
struct getdents_callback * buf = (struct getdents_callback *) __buf;
int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
- /* Do not touch buf->error any more if everything is ok! */
+ buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
- return (buf->error = -EINVAL);
-#ifdef CONFIG_DCACHE_PRELOAD
- if(buf->do_preload && (name[0] != '.' || namlen > 2)) {
- struct qstr qname = { name, namlen };
- struct inode * dir = buf->file->f_inode;
- d_entry_preliminary(dir->i_dentry, &qname, ino);
- }
-#endif
+ return -EINVAL;
+ dirent = buf->previous;
+ if (dirent)
+ put_user(offset, &dirent->d_off);
dirent = buf->current_dir;
- copy_to_user(dirent->d_name, name, namlen);
- put_user(0, dirent->d_name + namlen);
-#ifdef CONFIG_TRANS_NAMES
- {
- char * cut;
-#ifdef CONFIG_TRANS_RESTRICT
- cut = testname(buf->restricted, dirent->d_name);
-#else
- cut = testname(1, dirent->d_name);
-#endif
- if(cut) {
- int newlen = (int)cut - (int)dirent->d_name;
- int newreclen = ROUND_UP(NAME_OFFSET(dirent) + newlen + 1);
- /* Either both must fit or none. This way we need
- * no status information in f_pos */
- if (reclen+newlen > buf->count)
- return -EINVAL;
- put_user(0, cut);
- put_user(ino, &dirent->d_ino);
- put_user(newreclen, &dirent->d_reclen);
- put_user(offset, &dirent->d_off);
- ((char *) dirent) += newreclen;
- buf->count -= newreclen;
- put_user(offset, &dirent->d_off);
- copy_to_user(dirent->d_name, name, namlen);
- put_user(0, dirent->d_name + namlen);
- }
- }
-#endif
+ buf->previous = dirent;
put_user(ino, &dirent->d_ino);
put_user(reclen, &dirent->d_reclen);
- if (buf->previous)
- put_user(buf->file->f_pos, &buf->previous->d_off);
- buf->previous = dirent;
+ copy_to_user(dirent->d_name, name, namlen);
+ put_user(0, dirent->d_name + namlen);
((char *) dirent) += reclen;
buf->current_dir = dirent;
buf->count -= reclen;
@@ -206,6 +126,7 @@
asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count)
{
struct file * file;
+ struct linux_dirent * lastdirent;
struct getdents_callback buf;
int error = -EBADF;
@@ -218,72 +139,18 @@
error = verify_area(VERIFY_WRITE, dirent, count);
if (error)
goto out;
- buf.file = file;
buf.current_dir = (struct linux_dirent *) dirent;
buf.previous = NULL;
buf.count = count;
buf.error = 0;
- buf.restricted = 0;
-#ifdef CONFIG_TRANS_RESTRICT
- buf.restricted = file->f_inode && file->f_inode->i_gid != CONFIG_TRANS_GID;
-#endif
- buf.do_preload = 0;
-#ifdef CONFIG_DCACHE_PRELOAD
- if(file->f_inode && file->f_inode->i_dentry &&
- !(file->f_inode->i_sb->s_type->fs_flags & (FS_NO_DCACHE|FS_NO_PRELIM)) &&
- !(file->f_inode->i_dentry->d_flag & D_PRELOADED))
- buf.do_preload = 1;
-#endif
-
- if(!(file->f_pos & BASKET_BIT)) {
- int oldcount;
- do {
- oldcount = buf.count;
- error = file->f_op->readdir(file->f_inode, file, &buf, filldir);
- if (error < 0)
- goto out;
- } while(!buf.error && buf.count != oldcount);
- }
- if(!buf.error) {
- int nr = 0;
- struct dentry * list = file->f_inode ?
- d_basket(file->f_inode->i_dentry) : NULL;
- struct dentry * ptr = list;
-#ifdef CONFIG_DCACHE_PRELOAD
- if(buf.do_preload) {
- buf.do_preload = 0;
- file->f_inode->i_dentry->d_flag |= D_PRELOADED;
- }
-#endif
- if(ptr) {
- if(!(file->f_pos & BASKET_BIT))
- file->f_pos = BASKET_BIT;
- do {
- struct dentry * next = ptr->d_basket_next;
- struct inode * inode;
- /* vfs_locks() are missing here */
- inode = d_inode(&ptr);
- if(inode) {
- nr++;
- if(nr > (file->f_pos & ~BASKET_BIT)) {
- int err = filldir(&buf, ptr->d_name,
- ptr->d_len,
- file->f_pos,
- inode->i_ino);
- if(err)
- break;
- file->f_pos++;
- }
- iput(inode);
- }
- ptr = next;
- } while(ptr != list);
- }
- }
- if (!buf.previous) {
+ error = file->f_op->readdir(file->f_inode, file, &buf, filldir);
+ if (error < 0)
+ goto out;
+ lastdirent = buf.previous;
+ if (!lastdirent) {
error = buf.error;
} else {
- put_user(file->f_pos, &buf.previous->d_off);
+ put_user(file->f_pos, &lastdirent->d_off);
error = count - buf.count;
}
out:
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov