1 /* 2 * linux/fs/readdir.c 3 * 4 * Copyright (C) 1995 Linus Torvalds 5 */ 6 7 #include <linux/stddef.h> 8 #include <linux/kernel.h> 9 #include <linux/export.h> 10 #include <linux/time.h> 11 #include <linux/mm.h> 12 #include <linux/errno.h> 13 #include <linux/stat.h> 14 #include <linux/file.h> 15 #include <linux/fs.h> 16 #include <linux/fsnotify.h> 17 #include <linux/dirent.h> 18 #include <linux/security.h> 19 #include <linux/syscalls.h> 20 #include <linux/unistd.h> 21 22 #include <asm/uaccess.h> 23 24 int iterate_dir(struct file *file, struct dir_context *ctx) 25 { 26 struct inode *inode = file_inode(file); 27 int res = -ENOTDIR; 28 if (!file->f_op->iterate) 29 goto out; 30 31 res = security_file_permission(file, MAY_READ); 32 if (res) 33 goto out; 34 35 res = mutex_lock_killable(&inode->i_mutex); 36 if (res) 37 goto out; 38 39 res = -ENOENT; 40 if (!IS_DEADDIR(inode)) { 41 ctx->pos = file->f_pos; 42 res = file->f_op->iterate(file, ctx); 43 file->f_pos = ctx->pos; 44 fsnotify_access(file); 45 file_accessed(file); 46 } 47 mutex_unlock(&inode->i_mutex); 48 out: 49 return res; 50 } 51 EXPORT_SYMBOL(iterate_dir); 52 53 /* 54 * Traditional linux readdir() handling.. 55 * 56 * "count=1" is a special case, meaning that the buffer is one 57 * dirent-structure in size and that the code can't handle more 58 * anyway. Thus the special "fillonedir()" function for that 59 * case (the low-level handlers don't need to care about this). 60 */ 61 62 #ifdef __ARCH_WANT_OLD_READDIR 63 64 struct old_linux_dirent { 65 unsigned long d_ino; 66 unsigned long d_offset; 67 unsigned short d_namlen; 68 char d_name[1]; 69 }; 70 71 struct readdir_callback { 72 struct dir_context ctx; 73 struct old_linux_dirent __user * dirent; 74 int result; 75 }; 76 77 static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset, 78 u64 ino, unsigned int d_type) 79 { 80 struct readdir_callback *buf = (struct readdir_callback *) __buf; 81 struct old_linux_dirent __user * dirent; 82 unsigned long d_ino; 83 84 if (buf->result) 85 return -EINVAL; 86 d_ino = ino; 87 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { 88 buf->result = -EOVERFLOW; 89 return -EOVERFLOW; 90 } 91 buf->result++; 92 dirent = buf->dirent; 93 if (!access_ok(VERIFY_WRITE, dirent, 94 (unsigned long)(dirent->d_name + namlen + 1) - 95 (unsigned long)dirent)) 96 goto efault; 97 if ( __put_user(d_ino, &dirent->d_ino) || 98 __put_user(offset, &dirent->d_offset) || 99 __put_user(namlen, &dirent->d_namlen) || 100 __copy_to_user(dirent->d_name, name, namlen) || 101 __put_user(0, dirent->d_name + namlen)) 102 goto efault; 103 return 0; 104 efault: 105 buf->result = -EFAULT; 106 return -EFAULT; 107 } 108 109 SYSCALL_DEFINE3(old_readdir, unsigned int, fd, 110 struct old_linux_dirent __user *, dirent, unsigned int, count) 111 { 112 int error; 113 struct fd f = fdget(fd); 114 struct readdir_callback buf = { 115 .ctx.actor = fillonedir, 116 .dirent = dirent 117 }; 118 119 if (!f.file) 120 return -EBADF; 121 122 error = iterate_dir(f.file, &buf.ctx); 123 if (buf.result) 124 error = buf.result; 125 126 fdput(f); 127 return error; 128 } 129 130 #endif /* __ARCH_WANT_OLD_READDIR */ 131 132 /* 133 * New, all-improved, singing, dancing, iBCS2-compliant getdents() 134 * interface. 135 */ 136 struct linux_dirent { 137 unsigned long d_ino; 138 unsigned long d_off; 139 unsigned short d_reclen; 140 char d_name[1]; 141 }; 142 143 struct getdents_callback { 144 struct dir_context ctx; 145 struct linux_dirent __user * current_dir; 146 struct linux_dirent __user * previous; 147 int count; 148 int error; 149 }; 150 151 static int filldir(void * __buf, const char * name, int namlen, loff_t offset, 152 u64 ino, unsigned int d_type) 153 { 154 struct linux_dirent __user * dirent; 155 struct getdents_callback * buf = (struct getdents_callback *) __buf; 156 unsigned long d_ino; 157 int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2, 158 sizeof(long)); 159 160 buf->error = -EINVAL; /* only used if we fail.. */ 161 if (reclen > buf->count) 162 return -EINVAL; 163 d_ino = ino; 164 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { 165 buf->error = -EOVERFLOW; 166 return -EOVERFLOW; 167 } 168 dirent = buf->previous; 169 if (dirent) { 170 if (__put_user(offset, &dirent->d_off)) 171 goto efault; 172 } 173 dirent = buf->current_dir; 174 if (__put_user(d_ino, &dirent->d_ino)) 175 goto efault; 176 if (__put_user(reclen, &dirent->d_reclen)) 177 goto efault; 178 if (copy_to_user(dirent->d_name, name, namlen)) 179 goto efault; 180 if (__put_user(0, dirent->d_name + namlen)) 181 goto efault; 182 if (__put_user(d_type, (char __user *) dirent + reclen - 1)) 183 goto efault; 184 buf->previous = dirent; 185 dirent = (void __user *)dirent + reclen; 186 buf->current_dir = dirent; 187 buf->count -= reclen; 188 return 0; 189 efault: 190 buf->error = -EFAULT; 191 return -EFAULT; 192 } 193 194 SYSCALL_DEFINE3(getdents, unsigned int, fd, 195 struct linux_dirent __user *, dirent, unsigned int, count) 196 { 197 struct fd f; 198 struct linux_dirent __user * lastdirent; 199 struct getdents_callback buf = { 200 .ctx.actor = filldir, 201 .count = count, 202 .current_dir = dirent 203 }; 204 int error; 205 206 if (!access_ok(VERIFY_WRITE, dirent, count)) 207 return -EFAULT; 208 209 f = fdget(fd); 210 if (!f.file) 211 return -EBADF; 212 213 error = iterate_dir(f.file, &buf.ctx); 214 if (error >= 0) 215 error = buf.error; 216 lastdirent = buf.previous; 217 if (lastdirent) { 218 if (put_user(buf.ctx.pos, &lastdirent->d_off)) 219 error = -EFAULT; 220 else 221 error = count - buf.count; 222 } 223 fdput(f); 224 return error; 225 } 226 227 struct getdents_callback64 { 228 struct dir_context ctx; 229 struct linux_dirent64 __user * current_dir; 230 struct linux_dirent64 __user * previous; 231 int count; 232 int error; 233 }; 234 235 static int filldir64(void * __buf, const char * name, int namlen, loff_t offset, 236 u64 ino, unsigned int d_type) 237 { 238 struct linux_dirent64 __user *dirent; 239 struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf; 240 int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1, 241 sizeof(u64)); 242 243 buf->error = -EINVAL; /* only used if we fail.. */ 244 if (reclen > buf->count) 245 return -EINVAL; 246 dirent = buf->previous; 247 if (dirent) { 248 if (__put_user(offset, &dirent->d_off)) 249 goto efault; 250 } 251 dirent = buf->current_dir; 252 if (__put_user(ino, &dirent->d_ino)) 253 goto efault; 254 if (__put_user(0, &dirent->d_off)) 255 goto efault; 256 if (__put_user(reclen, &dirent->d_reclen)) 257 goto efault; 258 if (__put_user(d_type, &dirent->d_type)) 259 goto efault; 260 if (copy_to_user(dirent->d_name, name, namlen)) 261 goto efault; 262 if (__put_user(0, dirent->d_name + namlen)) 263 goto efault; 264 buf->previous = dirent; 265 dirent = (void __user *)dirent + reclen; 266 buf->current_dir = dirent; 267 buf->count -= reclen; 268 return 0; 269 efault: 270 buf->error = -EFAULT; 271 return -EFAULT; 272 } 273 274 SYSCALL_DEFINE3(getdents64, unsigned int, fd, 275 struct linux_dirent64 __user *, dirent, unsigned int, count) 276 { 277 struct fd f; 278 struct linux_dirent64 __user * lastdirent; 279 struct getdents_callback64 buf = { 280 .ctx.actor = filldir64, 281 .count = count, 282 .current_dir = dirent 283 }; 284 int error; 285 286 if (!access_ok(VERIFY_WRITE, dirent, count)) 287 return -EFAULT; 288 289 f = fdget(fd); 290 if (!f.file) 291 return -EBADF; 292 293 error = iterate_dir(f.file, &buf.ctx); 294 if (error >= 0) 295 error = buf.error; 296 lastdirent = buf.previous; 297 if (lastdirent) { 298 typeof(lastdirent->d_off) d_off = buf.ctx.pos; 299 if (__put_user(d_off, &lastdirent->d_off)) 300 error = -EFAULT; 301 else 302 error = count - buf.count; 303 } 304 fdput(f); 305 return error; 306 } 307