Skip to content
Permalink
1139b72d5e
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
555 lines (522 sloc) 17.7 KB
diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/i386/kernel/syscall_table.S vanilla-new/arch/i386/kernel/syscall_table.S
--- vanilla/arch/i386/kernel/syscall_table.S 2006-05-09 18:53:48.000000000 -0500
+++ vanilla-new/arch/i386/kernel/syscall_table.S 2006-05-11 14:03:04.000000000 -0500
@@ -314,7 +314,9 @@
.long sys_openfh
.long sys_newstatlite
.long sys_newlstatlite
- .long sys_newfstatlite
+ .long sys_newfstatlite /* 315 */
.long sys_statlite64
.long sys_lstatlite64
.long sys_fstatlite64
+ .long sys_getdents_plus
+ .long sys_getdents64_plus /* 320 */
diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/ia64/kernel/entry.S vanilla-new/arch/ia64/kernel/entry.S
--- vanilla/arch/ia64/kernel/entry.S 2006-05-09 18:53:48.000000000 -0500
+++ vanilla-new/arch/ia64/kernel/entry.S 2006-05-11 14:10:30.000000000 -0500
@@ -1624,5 +1624,7 @@
data8 sys_newstatlite
data8 sys_newlstatlite
data8 sys_newfstatlite
+ data8 sys_getdents_plus
+ data8 sys_getdents64_plus
.org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/powerpc/kernel/systbl.S vanilla-new/arch/powerpc/kernel/systbl.S
--- vanilla/arch/powerpc/kernel/systbl.S 2006-05-09 18:53:48.000000000 -0500
+++ vanilla-new/arch/powerpc/kernel/systbl.S 2006-05-11 14:12:20.000000000 -0500
@@ -327,3 +327,5 @@
SYSCALL(newstatlite)
SYSCALL(newlstatlite)
SYSCALL(newfstatlite)
+SYSCALL(sys_getdents_plus)
+SYSCALL(sys_getdents64_plus)
diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/x86_64/ia32/ia32entry.S vanilla-new/arch/x86_64/ia32/ia32entry.S
--- vanilla/arch/x86_64/ia32/ia32entry.S 2006-05-09 18:53:48.000000000 -0500
+++ vanilla-new/arch/x86_64/ia32/ia32entry.S 2006-05-11 14:09:30.000000000 -0500
@@ -696,6 +696,8 @@
.quad sys32_statlite64
.quad sys32_lstatlite64
.quad sys32_fstatlite64
+ .quad sys_ni_syscall /* getdents_plus */
+ .quad sys_ni_syscall /* getdents64_plus */
ia32_syscall_end:
.rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
.quad ni_syscall
diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/fs/readdir.c vanilla-new/fs/readdir.c
--- vanilla/fs/readdir.c 2006-03-19 23:53:29.000000000 -0600
+++ vanilla-new/fs/readdir.c 2006-05-18 19:25:06.000000000 -0500
@@ -43,6 +43,32 @@
EXPORT_SYMBOL(vfs_readdir);
+int vfs_readdirplus(struct file *file, filldirplus_t fillerplus, void *buf)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ int res = -ENOTDIR;
+ if (!file->f_op || !file->f_op->readdirplus)
+ goto out;
+
+ res = security_file_permission(file, MAY_READ);
+ if (res)
+ goto out;
+
+ mutex_lock(&inode->i_mutex);
+ res = -ENOENT;
+ if (!IS_DEADDIR(inode)) {
+ res = file->f_op->readdirplus(file, buf, fillerplus);
+ file_accessed(file);
+ }
+ mutex_unlock(&inode->i_mutex);
+out:
+ if (file->f_op && file->f_op->readdir && !file->f_op->readdirplus)
+ res = -EOPNOTSUPP;
+ return res;
+}
+
+EXPORT_SYMBOL_GPL(vfs_readdirplus);
+
/*
* Traditional linux readdir() handling..
*
@@ -212,6 +238,111 @@
return error;
}
+/* getdents_plus implementation */
+#define DIRENT_OFFSET(de) ((unsigned long) &((de)->dp_dirent) - (unsigned long) (char __user *) (de))
+
+struct linux_dirent_plus {
+ struct stat dp_stat;
+ int dp_stat_err;
+ struct linux_dirent dp_dirent;
+};
+
+struct getdentsplus_callback {
+ struct linux_dirent_plus __user * current_dir;
+ struct linux_dirent_plus __user * previous;
+ int count;
+ int error;
+};
+
+static int filldirplus(void * __buf, const char * name, int namlen, loff_t offset,
+ ino_t ino, unsigned int d_type, struct kstat *statp)
+{
+ struct linux_dirent __user *de;
+ struct linux_dirent_plus __user * dirent;
+ struct getdentsplus_callback * buf = (struct getdentsplus_callback *) __buf;
+ int err, reclen = ROUND_UP(NAME_OFFSET(de) + namlen + DIRENT_OFFSET(dirent) + 2);
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
+ dirent = buf->previous;
+ if (dirent) {
+ if (__put_user(offset, &dirent->dp_dirent.d_off))
+ goto efault;
+ }
+ dirent = buf->current_dir;
+ err = 0;
+ if (IS_ERR(statp)) {
+ err = PTR_ERR(statp);
+ if (__put_user(err, &dirent->dp_stat_err))
+ goto efault;
+ }
+ else {
+ if (__put_user(err, &dirent->dp_stat_err))
+ goto efault;
+ if (cp_new_stat(statp, &dirent->dp_stat))
+ goto efault;
+ }
+ if (__put_user(ino, &dirent->dp_dirent.d_ino))
+ goto efault;
+ if (__put_user(reclen, &dirent->dp_dirent.d_reclen))
+ goto efault;
+ if (copy_to_user(dirent->dp_dirent.d_name, name, namlen))
+ goto efault;
+ if (__put_user(0, dirent->dp_dirent.d_name + namlen))
+ goto efault;
+ if (__put_user(d_type, (char __user *) dirent + reclen - 1))
+ goto efault;
+ buf->previous = dirent;
+ dirent = (void __user *)dirent + reclen;
+ buf->current_dir = dirent;
+ buf->count -= reclen;
+ return 0;
+efault:
+ buf->error = -EFAULT;
+ return -EFAULT;
+}
+
+asmlinkage long sys_getdents_plus(unsigned int fd, struct linux_dirent_plus __user * dirent, unsigned int count)
+{
+ struct file * file;
+ struct linux_dirent_plus __user * lastdirent;
+ struct getdentsplus_callback buf;
+ int error;
+
+ error = -EFAULT;
+ if (!access_ok(VERIFY_WRITE, dirent, count))
+ goto out;
+
+ error = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto out;
+
+ buf.current_dir = dirent;
+ buf.previous = NULL;
+ buf.count = count;
+ buf.error = 0;
+
+ error = vfs_readdirplus(file, filldirplus, &buf);
+ if (error < 0)
+ goto out_putf;
+ error = buf.error;
+ lastdirent = buf.previous;
+ if (lastdirent) {
+ typeof(lastdirent->dp_dirent.d_off) d_off = file->f_pos;
+ error = -EFAULT;
+ if (__put_user(d_off, &lastdirent->dp_dirent.d_off))
+ goto out_putf;
+ error = count - buf.count;
+ }
+
+out_putf:
+ fput(file);
+out:
+ return error;
+}
+
#define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
struct getdents_callback64 {
@@ -298,3 +429,105 @@
out:
return error;
}
+
+struct getdentsplus_callback64 {
+ struct linux_dirent64_plus __user * current_dir;
+ struct linux_dirent64_plus __user * previous;
+ int count;
+ int error;
+};
+
+static int filldir64_plus(void * __buf, const char * name, int namlen, loff_t offset,
+ ino_t ino, unsigned int d_type, struct kstat *statp)
+{
+ struct linux_dirent64 __user *de;
+ struct linux_dirent64_plus __user *dirent;
+ struct getdentsplus_callback64 * buf = (struct getdentsplus_callback64 *) __buf;
+ int err, reclen = ROUND_UP64(NAME_OFFSET(de) + namlen + 1 + DIRENT_OFFSET(dirent));
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
+ dirent = buf->previous;
+ if (dirent) {
+ if (__put_user(offset, &dirent->dp_dirent.d_off))
+ goto efault;
+ }
+ dirent = buf->current_dir;
+ err = 0;
+ if (IS_ERR(statp)) {
+ err = PTR_ERR(statp);
+ if (__put_user(err, &dirent->dp_stat_err))
+ goto efault;
+ }
+ else {
+ if (__put_user(err, &dirent->dp_stat_err))
+ goto efault;
+#ifdef __ARCH_WANT_STAT64
+ if (cp_new_stat64(statp, &dirent->dp_stat))
+#else
+ if (cp_new_stat(statp, &dirent->dp_stat))
+#endif
+ goto efault;
+ }
+ if (__put_user(ino, &dirent->dp_dirent.d_ino))
+ goto efault;
+ if (__put_user(0, &dirent->dp_dirent.d_off))
+ goto efault;
+ if (__put_user(reclen, &dirent->dp_dirent.d_reclen))
+ goto efault;
+ if (__put_user(d_type, &dirent->dp_dirent.d_type))
+ goto efault;
+ if (copy_to_user(dirent->dp_dirent.d_name, name, namlen))
+ goto efault;
+ if (__put_user(0, dirent->dp_dirent.d_name + namlen))
+ goto efault;
+ buf->previous = dirent;
+ dirent = (void __user *)dirent + reclen;
+ buf->current_dir = dirent;
+ buf->count -= reclen;
+ return 0;
+efault:
+ buf->error = -EFAULT;
+ return -EFAULT;
+}
+
+asmlinkage long sys_getdents64_plus(unsigned int fd, struct linux_dirent64_plus __user * dirent, unsigned int count)
+{
+ struct file * file;
+ struct linux_dirent64_plus __user * lastdirent;
+ struct getdentsplus_callback64 buf;
+ int error;
+
+ error = -EFAULT;
+ if (!access_ok(VERIFY_WRITE, dirent, count))
+ goto out;
+
+ error = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto out;
+
+ buf.current_dir = dirent;
+ buf.previous = NULL;
+ buf.count = count;
+ buf.error = 0;
+
+ error = vfs_readdirplus(file, filldir64_plus, &buf);
+ if (error < 0)
+ goto out_putf;
+ error = buf.error;
+ lastdirent = buf.previous;
+ if (lastdirent) {
+ typeof(lastdirent->dp_dirent.d_off) d_off = file->f_pos;
+ error = -EFAULT;
+ if (__put_user(d_off, &lastdirent->dp_dirent.d_off))
+ goto out_putf;
+ error = count - buf.count;
+ }
+
+out_putf:
+ fput(file);
+out:
+ return error;
+}
diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/fs/stat.c vanilla-new/fs/stat.c
--- vanilla/fs/stat.c 2006-05-09 18:53:48.000000000 -0500
+++ vanilla-new/fs/stat.c 2006-05-11 13:35:08.000000000 -0500
@@ -297,7 +297,7 @@
#endif /* __ARCH_WANT_OLD_STAT */
-static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
+int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
{
struct stat tmp;
@@ -345,7 +345,7 @@
return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
}
-static int cp_new_statlite(struct kstat_lite *stat_lite, struct stat_lite __user *statlitebuf)
+int cp_new_statlite(struct kstat_lite *stat_lite, struct stat_lite __user *statlitebuf)
{
struct stat_lite tmp;
@@ -545,7 +545,7 @@
/* ---------- LFS-64 ----------- */
#ifdef __ARCH_WANT_STAT64
-static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf)
+long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf)
{
struct stat64 tmp;
@@ -580,7 +580,7 @@
return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
}
-static long cp_new_stat64_lite(struct kstat_lite *stat_lite, struct stat64_lite __user *statlitebuf)
+long cp_new_stat64_lite(struct kstat_lite *stat_lite, struct stat64_lite __user *statlitebuf)
{
struct stat64_lite tmp;
diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-i386/dirent.h vanilla-new/include/asm-i386/dirent.h
--- vanilla/include/asm-i386/dirent.h 1969-12-31 18:00:00.000000000 -0600
+++ vanilla-new/include/asm-i386/dirent.h 2006-05-18 19:25:26.000000000 -0500
@@ -0,0 +1,28 @@
+#ifndef _I386_DIRENT_H
+#define _I386_DIRENT_H
+
+#include <asm/stat.h>
+
+struct dirent_plus {
+ struct stat dp_stat;
+ int dp_stat_err;
+ struct dirent dp_dirent;
+};
+
+struct dirent64_plus {
+ struct stat64 dp_stat;
+ int dp_stat_err;
+ struct dirent64 dp_dirent;
+};
+
+#ifdef __KERNEL__
+
+struct linux_dirent64_plus {
+ struct stat64 dp_stat;
+ int dp_stat_err;
+ struct linux_dirent64 dp_dirent;
+};
+
+#endif
+
+#endif
diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-i386/unistd.h vanilla-new/include/asm-i386/unistd.h
--- vanilla/include/asm-i386/unistd.h 2006-05-09 18:53:48.000000000 -0500
+++ vanilla-new/include/asm-i386/unistd.h 2006-05-11 14:00:29.000000000 -0500
@@ -324,8 +324,10 @@
#define __NR_statlite64 316
#define __NR_lstatlite64 317
#define __NR_fstatlite64 318
+#define __NR_getdents_plus 319
+#define __NR_getdents64_plus 320
-#define NR_syscalls 319
+#define NR_syscalls 321
/*
* user-visible error numbers are in the range -1 - -128: see
diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-ia64/unistd.h vanilla-new/include/asm-ia64/unistd.h
--- vanilla/include/asm-ia64/unistd.h 2006-05-09 18:53:48.000000000 -0500
+++ vanilla-new/include/asm-ia64/unistd.h 2006-05-11 14:05:50.000000000 -0500
@@ -290,12 +290,14 @@
#define __NR_statlite 1299
#define __NR_lstatlite 1300
#define __NR_fstatlite 1301
+#define __NR_getdents_plus 1302
+#define __NR_getdents64_plus 1303
#ifdef __KERNEL__
#include <linux/config.h>
-#define NR_syscalls 278 /* length of syscall table */
+#define NR_syscalls 280 /* length of syscall table */
#define __ARCH_WANT_SYS_RT_SIGACTION
diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-powerpc/unistd.h vanilla-new/include/asm-powerpc/unistd.h
--- vanilla/include/asm-powerpc/unistd.h 2006-05-05 13:59:14.000000000 -0500
+++ vanilla-new/include/asm-powerpc/unistd.h 2006-05-11 14:14:28.000000000 -0500
@@ -303,8 +303,13 @@
#define __NR_unshare 282
#define __NR_openg 283
#define __NR_openfh 284
+#define __NR_statlite 285
+#define __NR_lstatlite 286
+#define __NR_fstatlite 287
+#define __NR_getdents_plus 288
+#define __NR_getdents64_plus 289
-#define __NR_syscalls 285
+#define __NR_syscalls 290
#ifdef __KERNEL__
#define __NR__exit __NR_exit
diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-x86_64/dirent.h vanilla-new/include/asm-x86_64/dirent.h
--- vanilla/include/asm-x86_64/dirent.h 1969-12-31 18:00:00.000000000 -0600
+++ vanilla-new/include/asm-x86_64/dirent.h 2006-05-18 19:25:47.000000000 -0500
@@ -0,0 +1,28 @@
+#ifndef _ASM_X86_64_DIRENT_H
+#define _ASM_X86_64_DIRENT_H
+
+#include <asm/stat.h>
+
+struct dirent_plus {
+ struct stat dp_stat;
+ int dp_stat_err;
+ struct dirent dp_dirent;
+};
+
+struct dirent64_plus {
+ struct stat dp_stat;
+ int dp_stat_err;
+ struct dirent64 dp_dirent;
+};
+
+#ifdef __KERNEL__
+
+struct linux_dirent64_plus {
+ struct stat dp_stat;
+ int dp_stat_err;
+ struct linux_dirent64 dp_dirent;
+};
+
+#endif
+
+#endif
diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-x86_64/unistd.h vanilla-new/include/asm-x86_64/unistd.h
--- vanilla/include/asm-x86_64/unistd.h 2006-05-09 18:53:48.000000000 -0500
+++ vanilla-new/include/asm-x86_64/unistd.h 2006-05-11 14:04:27.000000000 -0500
@@ -615,8 +615,12 @@
__SYSCALL(__NR_newlstatlite, sys_newlstatlite)
#define __NR_newfstatlite 277
__SYSCALL(__NR_newfstatlite, sys_newfstatlite)
+#define __NR_getdents_plus 278
+__SYSCALL(__NR_getdents_plus, sys_getdents_plus)
+#define __NR_getdents64_plus 279
+__SYSCALL(__NR_getdents64_plus, sys_getdents64_plus)
-#define __NR_syscall_max __NR_newfstatlite
+#define __NR_syscall_max __NR_getdents64_plus
#ifndef __NO_STUBS
diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/dirent.h vanilla-new/include/linux/dirent.h
--- vanilla/include/linux/dirent.h 2006-03-19 23:53:29.000000000 -0600
+++ vanilla-new/include/linux/dirent.h 2006-05-18 19:29:03.000000000 -0500
@@ -28,5 +28,6 @@
#endif /* __KERNEL__ */
+#include <asm/dirent.h>
#endif
diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/fs.h vanilla-new/include/linux/fs.h
--- vanilla/include/linux/fs.h 2006-05-09 18:53:48.000000000 -0500
+++ vanilla-new/include/linux/fs.h 2006-05-18 19:28:16.000000000 -0500
@@ -9,6 +9,7 @@
#include <linux/config.h>
#include <linux/limits.h>
#include <linux/ioctl.h>
+#include <linux/unistd.h>
/*
* It's silly to have NR_OPEN bigger than NR_FILE, but you can change
@@ -951,6 +952,13 @@
*/
typedef int (*filldir_t)(void *, const char *, int, loff_t, ino_t, unsigned);
+/*
+ * This is the "filldirplus" function type, used by readdirplus() to let
+ * the kernel specify the kind of dirent layout and the stat information
+ * all in one shot
+ */
+typedef int (*filldirplus_t)(void *, const char *, int, loff_t, ino_t, unsigned, struct kstat *);
+
struct block_device_operations {
int (*open) (struct inode *, struct file *);
int (*release) (struct inode *, struct file *);
@@ -1025,6 +1033,7 @@
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
+ int (*readdirplus) (struct file *, void *, filldirplus_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
@@ -1712,7 +1721,13 @@
void inode_set_bytes(struct inode *inode, loff_t bytes);
extern int vfs_readdir(struct file *, filldir_t, void *);
-
+extern int vfs_readdirplus(struct file *, filldirplus_t, void *);
+extern int cp_new_stat(struct kstat *stat, struct stat __user *statbuf);
+extern int cp_new_statlite(struct kstat_lite *stat_lite, struct stat_lite __user *statlitebuf);
+#ifdef __ARCH_WANT_STAT64
+extern long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf);
+extern long cp_new_stat64_lite(struct kstat_lite *stat_lite, struct stat64_lite __user *statlitebuf);
+#endif
extern int vfs_stat(char __user *, struct kstat *);
extern int vfs_statlite(char __user *, struct kstat_lite *);
extern int vfs_lstat(char __user *, struct kstat *);
diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/syscalls.h vanilla-new/include/linux/syscalls.h
--- vanilla/include/linux/syscalls.h 2006-05-09 18:53:48.000000000 -0500
+++ vanilla-new/include/linux/syscalls.h 2006-05-11 14:01:51.000000000 -0500
@@ -22,6 +22,8 @@
struct kexec_segment;
struct linux_dirent;
struct linux_dirent64;
+struct linux_dirent_plus;
+struct linux_dirent64_plus;
struct list_head;
struct msgbuf;
struct msghdr;
@@ -418,6 +420,12 @@
asmlinkage long sys_getdents64(unsigned int fd,
struct linux_dirent64 __user *dirent,
unsigned int count);
+asmlinkage long sys_getdents_plus(unsigned int fd,
+ struct linux_dirent_plus __user *dirent,
+ unsigned int count);
+asmlinkage long sys_getdents64_plus(unsigned int fd,
+ struct linux_dirent64_plus __user *dirent,
+ unsigned int count);
asmlinkage long sys_setsockopt(int fd, int level, int optname,
char __user *optval, int optlen);