root/fs/readdir.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fillonedir
  2. old_readdir
  3. filldir
  4. sys_getdents

   1 /*
   2  *  linux/fs/readdir.c
   3  *
   4  *  Copyright (C) 1995  Linus Torvalds
   5  */
   6 
   7 #include <linux/types.h>
   8 #include <linux/errno.h>
   9 #include <linux/stat.h>
  10 #include <linux/kernel.h>
  11 #include <linux/sched.h>
  12 #include <linux/mm.h>
  13 
  14 #include <asm/segment.h>
  15 
  16 /*
  17  * Traditional linux readdir() handling..
  18  *
  19  * "count=1" is a special case, meaning that the buffer is one
  20  * dirent-structure in size and that the code can't handle more
  21  * anyway. Thus the special "fillonedir()" function for that
  22  * case (the low-level handlers don't need to care about this).
  23  */
  24 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
  25 #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
  26 
  27 struct old_linux_dirent {
  28         unsigned long   d_ino;
  29         unsigned long   d_offset;
  30         unsigned short  d_namlen;
  31         char            d_name[1];
  32 };
  33 
  34 struct readdir_callback {
  35         struct old_linux_dirent * dirent;
  36         int count;
  37 };
  38 
  39 static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
     /* [previous][next][first][last][top][bottom][index][help] */
  40 {
  41         struct readdir_callback * buf = (struct readdir_callback *) __buf;
  42         struct old_linux_dirent * dirent;
  43 
  44         if (buf->count)
  45                 return -EINVAL;
  46         buf->count++;
  47         dirent = buf->dirent;
  48         put_user(ino, &dirent->d_ino);
  49         put_user(offset, &dirent->d_offset);
  50         put_user(namlen, &dirent->d_namlen);
  51         memcpy_tofs(dirent->d_name, name, namlen);
  52         put_user(0, dirent->d_name + namlen);
  53         return 0;
  54 }
  55 
  56 asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  57 {
  58         int error;
  59         struct file * file;
  60         struct readdir_callback buf;
  61 
  62         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
  63                 return -EBADF;
  64         if (!file->f_op || !file->f_op->readdir)
  65                 return -ENOTDIR;
  66         error = verify_area(VERIFY_WRITE, dirent, sizeof(struct old_linux_dirent));
  67         if (error)
  68                 return error;
  69         buf.count = 0;
  70         buf.dirent = dirent;
  71         error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir);
  72         if (error < 0)
  73                 return error;
  74         return buf.count;
  75 }
  76 
  77 /*
  78  * New, all-improved, singing, dancing, iBCS2-compliant getdents()
  79  * interface. 
  80  */
  81 struct linux_dirent {
  82         unsigned long   d_ino;
  83         unsigned long   d_off;
  84         unsigned short  d_reclen;
  85         char            d_name[1];
  86 };
  87 
  88 struct getdents_callback {
  89         struct linux_dirent * current;
  90         struct linux_dirent * previous;
  91         int count;
  92         int error;
  93 };
  94 
  95 static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 {
  97         struct linux_dirent * dirent;
  98         struct getdents_callback * buf = (struct getdents_callback *) __buf;
  99         int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
 100 
 101         buf->error = -EINVAL;   /* only used if we fail.. */
 102         if (reclen > buf->count)
 103                 return -EINVAL;
 104         dirent = buf->previous;
 105         if (dirent)
 106                 put_user(offset, &dirent->d_off);
 107         dirent = buf->current;
 108         buf->previous = dirent;
 109         put_user(ino, &dirent->d_ino);
 110         put_user(reclen, &dirent->d_reclen);
 111         memcpy_tofs(dirent->d_name, name, namlen);
 112         put_user(0, dirent->d_name + namlen);
 113         ((char *) dirent) += reclen;
 114         buf->current = dirent;
 115         buf->count -= reclen;
 116         return 0;
 117 }
 118 
 119 asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 120 {
 121         struct file * file;
 122         struct linux_dirent * lastdirent;
 123         struct getdents_callback buf;
 124         int error;
 125 
 126         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 127                 return -EBADF;
 128         if (!file->f_op || !file->f_op->readdir)
 129                 return -ENOTDIR;
 130         error = verify_area(VERIFY_WRITE, dirent, count);
 131         if (error)
 132                 return error;
 133         buf.current = (struct linux_dirent *) dirent;
 134         buf.previous = NULL;
 135         buf.count = count;
 136         buf.error = 0;
 137         error = file->f_op->readdir(file->f_inode, file, &buf, filldir);
 138         if (error < 0)
 139                 return error;
 140         lastdirent = buf.previous;
 141         if (!lastdirent)
 142                 return buf.error;
 143         put_user(file->f_pos, &lastdirent->d_off);
 144         return count - buf.count;
 145 }

/* [previous][next][first][last][top][bottom][index][help] */