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