-/* readdir & getdents */
-
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
-
-struct old_linux_dirent32 {
- u32 d_ino;
- u32 d_offset;
- unsigned short d_namlen;
- char d_name[1];
-};
-
-struct readdir_callback32 {
- struct old_linux_dirent32 * dirent;
- int count;
-};
-
-static int fillonedir(void * __buf, const char * name, int namlen,
- loff_t offset, ino_t ino, unsigned int d_type)
-{
- struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf;
- struct old_linux_dirent32 * dirent;
-
- if (buf->count)
- return -EINVAL;
- buf->count++;
- dirent = buf->dirent;
- 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;
-}
-
-asmlinkage long old32_readdir(unsigned int fd, struct old_linux_dirent32 *dirent, unsigned int count)
-{
- int error = -EBADF;
- struct file * file;
- struct readdir_callback32 buf;
-
- file = fget(fd);
- if (!file)
- goto out;
-
- buf.count = 0;
- buf.dirent = dirent;
-
- error = vfs_readdir(file, fillonedir, &buf);
- if (error < 0)
- goto out_putf;
- error = buf.count;
-
-out_putf:
- fput(file);
-out:
- return error;
-}
-
-struct linux_dirent32 {
- u32 d_ino;
- u32 d_off;
- unsigned short d_reclen;
- char d_name[1];
-};
-
-struct getdents_callback32 {
- struct linux_dirent32 * current_dir;
- struct linux_dirent32 * previous;
- int count;
- int error;
-};
-
-static int filldir(void * __buf, const char * name, int namlen, loff_t offset, ino_t ino,
- unsigned int d_type)
-{
- struct linux_dirent32 * dirent;
- struct getdents_callback32 * buf = (struct getdents_callback32 *) __buf;
- int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
-
- buf->error = -EINVAL; /* only used if we fail.. */
- if (reclen > buf->count)
- return -EINVAL;
- dirent = buf->previous;
- if (dirent)
- put_user(offset, &dirent->d_off);
- dirent = buf->current_dir;
- buf->previous = dirent;
- put_user(ino, &dirent->d_ino);
- put_user(reclen, &dirent->d_reclen);
- copy_to_user(dirent->d_name, name, namlen);
- put_user(0, dirent->d_name + namlen);
- buf->current_dir = ((void *)dirent) + reclen;
- buf->count -= reclen;
- return 0;
-}
-
-asmlinkage long sys32_getdents(unsigned int fd, struct linux_dirent32 *dirent, unsigned int count)
-{
- struct file * file;
- struct linux_dirent32 * lastdirent;
- struct getdents_callback32 buf;
- int error = -EBADF;
-
- file = fget(fd);
- if (!file)
- goto out;
-
- buf.current_dir = dirent;
- buf.previous = NULL;
- buf.count = count;
- buf.error = 0;
-
- error = vfs_readdir(file, filldir, &buf);
- if (error < 0)
- goto out_putf;
- lastdirent = buf.previous;
- error = buf.error;
- if(lastdirent) {
- put_user(file->f_pos, &lastdirent->d_off);
- error = count - buf.count;
- }
-out_putf:
- fput(file);
-out:
- return error;
-}
-
-/* end of readdir & getdents */
-