X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Freaddir.c;h=f39f5b3132527243a5eb08979d7bf5aebaaa9f15;hb=02e5785fcf5b86c05a42b6c4ff67343be8493766;hp=f02cae6b6067f9043f4f52d33ae5b9c8171b27b2;hpb=daddc0d38b3571bed170afa273a49a0eba090c1e;p=linux-2.6.git diff --git a/fs/readdir.c b/fs/readdir.c index f02cae6b6..f39f5b313 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -14,12 +14,14 @@ #include #include #include +#include +#include #include int vfs_readdir(struct file *file, filldir_t filler, void *buf) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; int res = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) goto out; @@ -28,13 +30,13 @@ int vfs_readdir(struct file *file, filldir_t filler, void *buf) if (res) goto out; - down(&inode->i_sem); + mutex_lock(&inode->i_mutex); res = -ENOENT; if (!IS_DEADDIR(inode)) { res = file->f_op->readdir(file, buf, filler); file_accessed(file); } - up(&inode->i_sem); + mutex_unlock(&inode->i_mutex); out: return res; } @@ -49,10 +51,10 @@ EXPORT_SYMBOL(vfs_readdir); * anyway. Thus the special "fillonedir()" function for that * case (the low-level handlers don't need to care about this). */ -#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de))) #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1)) -#ifndef __ia64__ +#ifdef __ARCH_WANT_OLD_READDIR struct old_linux_dirent { unsigned long d_ino; @@ -67,20 +69,24 @@ struct readdir_callback { }; static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset, - ino_t ino, unsigned int d_type) + u64 ino, unsigned int d_type) { struct readdir_callback * buf = (struct readdir_callback *) __buf; struct old_linux_dirent __user * dirent; + unsigned long d_ino; if (buf->result) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; buf->result++; dirent = buf->dirent; - if (!access_ok(VERIFY_WRITE, (unsigned long)dirent, + if (!access_ok(VERIFY_WRITE, dirent, (unsigned long)(dirent->d_name + namlen + 1) - (unsigned long)dirent)) goto efault; - if ( __put_user(ino, &dirent->d_ino) || + if ( __put_user(d_ino, &dirent->d_ino) || __put_user(offset, &dirent->d_offset) || __put_user(namlen, &dirent->d_namlen) || __copy_to_user(dirent->d_name, name, namlen) || @@ -115,7 +121,7 @@ out: return error; } -#endif /* !__ia64__ */ +#endif /* __ARCH_WANT_OLD_READDIR */ /* * New, all-improved, singing, dancing, iBCS2-compliant getdents() @@ -136,22 +142,26 @@ struct getdents_callback { }; static int filldir(void * __buf, const char * name, int namlen, loff_t offset, - ino_t ino, unsigned int d_type) + u64 ino, unsigned int d_type) { struct linux_dirent __user * dirent; struct getdents_callback * buf = (struct getdents_callback *) __buf; + unsigned long d_ino; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; dirent = buf->previous; if (dirent) { if (__put_user(offset, &dirent->d_off)) goto efault; } dirent = buf->current_dir; - if (__put_user(ino, &dirent->d_ino)) + if (__put_user(d_ino, &dirent->d_ino)) goto efault; if (__put_user(reclen, &dirent->d_reclen)) goto efault; @@ -159,7 +169,7 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset, goto efault; if (__put_user(0, dirent->d_name + namlen)) goto efault; - if (__put_user(d_type, (char *) dirent + reclen - 1)) + if (__put_user(d_type, (char __user *) dirent + reclen - 1)) goto efault; buf->previous = dirent; dirent = (void __user *)dirent + reclen; @@ -220,7 +230,7 @@ struct getdents_callback64 { }; static int filldir64(void * __buf, const char * name, int namlen, loff_t offset, - ino_t ino, unsigned int d_type) + u64 ino, unsigned int d_type) { struct linux_dirent64 __user *dirent; struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf; @@ -285,7 +295,9 @@ asmlinkage long sys_getdents64(unsigned int fd, struct linux_dirent64 __user * d lastdirent = buf.previous; if (lastdirent) { typeof(lastdirent->d_off) d_off = file->f_pos; - __put_user(d_off, &lastdirent->d_off); + error = -EFAULT; + if (__put_user(d_off, &lastdirent->d_off)) + goto out_putf; error = count - buf.count; }