Back to home page

LXR

 
 

    


0001 /*
0002  *  linux/fs/readdir.c
0003  *
0004  *  Copyright (C) 1995  Linus Torvalds
0005  */
0006 
0007 #include <linux/stddef.h>
0008 #include <linux/kernel.h>
0009 #include <linux/export.h>
0010 #include <linux/time.h>
0011 #include <linux/mm.h>
0012 #include <linux/errno.h>
0013 #include <linux/stat.h>
0014 #include <linux/file.h>
0015 #include <linux/fs.h>
0016 #include <linux/fsnotify.h>
0017 #include <linux/dirent.h>
0018 #include <linux/security.h>
0019 #include <linux/syscalls.h>
0020 #include <linux/unistd.h>
0021 
0022 #include <linux/uaccess.h>
0023 
0024 int iterate_dir(struct file *file, struct dir_context *ctx)
0025 {
0026     struct inode *inode = file_inode(file);
0027     bool shared = false;
0028     int res = -ENOTDIR;
0029     if (file->f_op->iterate_shared)
0030         shared = true;
0031     else if (!file->f_op->iterate)
0032         goto out;
0033 
0034     res = security_file_permission(file, MAY_READ);
0035     if (res)
0036         goto out;
0037 
0038     if (shared) {
0039         inode_lock_shared(inode);
0040     } else {
0041         res = down_write_killable(&inode->i_rwsem);
0042         if (res)
0043             goto out;
0044     }
0045 
0046     res = -ENOENT;
0047     if (!IS_DEADDIR(inode)) {
0048         ctx->pos = file->f_pos;
0049         if (shared)
0050             res = file->f_op->iterate_shared(file, ctx);
0051         else
0052             res = file->f_op->iterate(file, ctx);
0053         file->f_pos = ctx->pos;
0054         fsnotify_access(file);
0055         file_accessed(file);
0056     }
0057     if (shared)
0058         inode_unlock_shared(inode);
0059     else
0060         inode_unlock(inode);
0061 out:
0062     return res;
0063 }
0064 EXPORT_SYMBOL(iterate_dir);
0065 
0066 /*
0067  * Traditional linux readdir() handling..
0068  *
0069  * "count=1" is a special case, meaning that the buffer is one
0070  * dirent-structure in size and that the code can't handle more
0071  * anyway. Thus the special "fillonedir()" function for that
0072  * case (the low-level handlers don't need to care about this).
0073  */
0074 
0075 #ifdef __ARCH_WANT_OLD_READDIR
0076 
0077 struct old_linux_dirent {
0078     unsigned long   d_ino;
0079     unsigned long   d_offset;
0080     unsigned short  d_namlen;
0081     char        d_name[1];
0082 };
0083 
0084 struct readdir_callback {
0085     struct dir_context ctx;
0086     struct old_linux_dirent __user * dirent;
0087     int result;
0088 };
0089 
0090 static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
0091               loff_t offset, u64 ino, unsigned int d_type)
0092 {
0093     struct readdir_callback *buf =
0094         container_of(ctx, struct readdir_callback, ctx);
0095     struct old_linux_dirent __user * dirent;
0096     unsigned long d_ino;
0097 
0098     if (buf->result)
0099         return -EINVAL;
0100     d_ino = ino;
0101     if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
0102         buf->result = -EOVERFLOW;
0103         return -EOVERFLOW;
0104     }
0105     buf->result++;
0106     dirent = buf->dirent;
0107     if (!access_ok(VERIFY_WRITE, dirent,
0108             (unsigned long)(dirent->d_name + namlen + 1) -
0109                 (unsigned long)dirent))
0110         goto efault;
0111     if (    __put_user(d_ino, &dirent->d_ino) ||
0112         __put_user(offset, &dirent->d_offset) ||
0113         __put_user(namlen, &dirent->d_namlen) ||
0114         __copy_to_user(dirent->d_name, name, namlen) ||
0115         __put_user(0, dirent->d_name + namlen))
0116         goto efault;
0117     return 0;
0118 efault:
0119     buf->result = -EFAULT;
0120     return -EFAULT;
0121 }
0122 
0123 SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
0124         struct old_linux_dirent __user *, dirent, unsigned int, count)
0125 {
0126     int error;
0127     struct fd f = fdget_pos(fd);
0128     struct readdir_callback buf = {
0129         .ctx.actor = fillonedir,
0130         .dirent = dirent
0131     };
0132 
0133     if (!f.file)
0134         return -EBADF;
0135 
0136     error = iterate_dir(f.file, &buf.ctx);
0137     if (buf.result)
0138         error = buf.result;
0139 
0140     fdput_pos(f);
0141     return error;
0142 }
0143 
0144 #endif /* __ARCH_WANT_OLD_READDIR */
0145 
0146 /*
0147  * New, all-improved, singing, dancing, iBCS2-compliant getdents()
0148  * interface. 
0149  */
0150 struct linux_dirent {
0151     unsigned long   d_ino;
0152     unsigned long   d_off;
0153     unsigned short  d_reclen;
0154     char        d_name[1];
0155 };
0156 
0157 struct getdents_callback {
0158     struct dir_context ctx;
0159     struct linux_dirent __user * current_dir;
0160     struct linux_dirent __user * previous;
0161     int count;
0162     int error;
0163 };
0164 
0165 static int filldir(struct dir_context *ctx, const char *name, int namlen,
0166            loff_t offset, u64 ino, unsigned int d_type)
0167 {
0168     struct linux_dirent __user * dirent;
0169     struct getdents_callback *buf =
0170         container_of(ctx, struct getdents_callback, ctx);
0171     unsigned long d_ino;
0172     int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
0173         sizeof(long));
0174 
0175     buf->error = -EINVAL;   /* only used if we fail.. */
0176     if (reclen > buf->count)
0177         return -EINVAL;
0178     d_ino = ino;
0179     if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
0180         buf->error = -EOVERFLOW;
0181         return -EOVERFLOW;
0182     }
0183     dirent = buf->previous;
0184     if (dirent) {
0185         if (signal_pending(current))
0186             return -EINTR;
0187         if (__put_user(offset, &dirent->d_off))
0188             goto efault;
0189     }
0190     dirent = buf->current_dir;
0191     if (__put_user(d_ino, &dirent->d_ino))
0192         goto efault;
0193     if (__put_user(reclen, &dirent->d_reclen))
0194         goto efault;
0195     if (copy_to_user(dirent->d_name, name, namlen))
0196         goto efault;
0197     if (__put_user(0, dirent->d_name + namlen))
0198         goto efault;
0199     if (__put_user(d_type, (char __user *) dirent + reclen - 1))
0200         goto efault;
0201     buf->previous = dirent;
0202     dirent = (void __user *)dirent + reclen;
0203     buf->current_dir = dirent;
0204     buf->count -= reclen;
0205     return 0;
0206 efault:
0207     buf->error = -EFAULT;
0208     return -EFAULT;
0209 }
0210 
0211 SYSCALL_DEFINE3(getdents, unsigned int, fd,
0212         struct linux_dirent __user *, dirent, unsigned int, count)
0213 {
0214     struct fd f;
0215     struct linux_dirent __user * lastdirent;
0216     struct getdents_callback buf = {
0217         .ctx.actor = filldir,
0218         .count = count,
0219         .current_dir = dirent
0220     };
0221     int error;
0222 
0223     if (!access_ok(VERIFY_WRITE, dirent, count))
0224         return -EFAULT;
0225 
0226     f = fdget_pos(fd);
0227     if (!f.file)
0228         return -EBADF;
0229 
0230     error = iterate_dir(f.file, &buf.ctx);
0231     if (error >= 0)
0232         error = buf.error;
0233     lastdirent = buf.previous;
0234     if (lastdirent) {
0235         if (put_user(buf.ctx.pos, &lastdirent->d_off))
0236             error = -EFAULT;
0237         else
0238             error = count - buf.count;
0239     }
0240     fdput_pos(f);
0241     return error;
0242 }
0243 
0244 struct getdents_callback64 {
0245     struct dir_context ctx;
0246     struct linux_dirent64 __user * current_dir;
0247     struct linux_dirent64 __user * previous;
0248     int count;
0249     int error;
0250 };
0251 
0252 static int filldir64(struct dir_context *ctx, const char *name, int namlen,
0253              loff_t offset, u64 ino, unsigned int d_type)
0254 {
0255     struct linux_dirent64 __user *dirent;
0256     struct getdents_callback64 *buf =
0257         container_of(ctx, struct getdents_callback64, ctx);
0258     int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
0259         sizeof(u64));
0260 
0261     buf->error = -EINVAL;   /* only used if we fail.. */
0262     if (reclen > buf->count)
0263         return -EINVAL;
0264     dirent = buf->previous;
0265     if (dirent) {
0266         if (signal_pending(current))
0267             return -EINTR;
0268         if (__put_user(offset, &dirent->d_off))
0269             goto efault;
0270     }
0271     dirent = buf->current_dir;
0272     if (__put_user(ino, &dirent->d_ino))
0273         goto efault;
0274     if (__put_user(0, &dirent->d_off))
0275         goto efault;
0276     if (__put_user(reclen, &dirent->d_reclen))
0277         goto efault;
0278     if (__put_user(d_type, &dirent->d_type))
0279         goto efault;
0280     if (copy_to_user(dirent->d_name, name, namlen))
0281         goto efault;
0282     if (__put_user(0, dirent->d_name + namlen))
0283         goto efault;
0284     buf->previous = dirent;
0285     dirent = (void __user *)dirent + reclen;
0286     buf->current_dir = dirent;
0287     buf->count -= reclen;
0288     return 0;
0289 efault:
0290     buf->error = -EFAULT;
0291     return -EFAULT;
0292 }
0293 
0294 SYSCALL_DEFINE3(getdents64, unsigned int, fd,
0295         struct linux_dirent64 __user *, dirent, unsigned int, count)
0296 {
0297     struct fd f;
0298     struct linux_dirent64 __user * lastdirent;
0299     struct getdents_callback64 buf = {
0300         .ctx.actor = filldir64,
0301         .count = count,
0302         .current_dir = dirent
0303     };
0304     int error;
0305 
0306     if (!access_ok(VERIFY_WRITE, dirent, count))
0307         return -EFAULT;
0308 
0309     f = fdget_pos(fd);
0310     if (!f.file)
0311         return -EBADF;
0312 
0313     error = iterate_dir(f.file, &buf.ctx);
0314     if (error >= 0)
0315         error = buf.error;
0316     lastdirent = buf.previous;
0317     if (lastdirent) {
0318         typeof(lastdirent->d_off) d_off = buf.ctx.pos;
0319         if (__put_user(d_off, &lastdirent->d_off))
0320             error = -EFAULT;
0321         else
0322             error = count - buf.count;
0323     }
0324     fdput_pos(f);
0325     return error;
0326 }