root/fs/read_write.c

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

DEFINITIONS

This source file includes following definitions.
  1. sys_lseek
  2. sys_llseek
  3. sys_read
  4. sys_write
  5. sock_readv_writev
  6. do_readv_writev
  7. sys_readv
  8. sys_writev

   1 /*
   2  *  linux/fs/read_write.c
   3  *
   4  *  Copyright (C) 1991, 1992  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/fcntl.h>
  13 #include <linux/mm.h>
  14 #include <linux/uio.h>
  15 
  16 #include <asm/segment.h>
  17 
  18 asmlinkage int sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
     /* [previous][next][first][last][top][bottom][index][help] */
  19 {
  20         struct file * file;
  21         long tmp = -1;
  22 
  23         if (fd >= NR_OPEN || !(file=current->files->fd[fd]) || !(file->f_inode))
  24                 return -EBADF;
  25         if (origin > 2)
  26                 return -EINVAL;
  27         if (file->f_op && file->f_op->lseek)
  28                 return file->f_op->lseek(file->f_inode,file,offset,origin);
  29 
  30 /* this is the default handler if no lseek handler is present */
  31         switch (origin) {
  32                 case 0:
  33                         tmp = offset;
  34                         break;
  35                 case 1:
  36                         tmp = file->f_pos + offset;
  37                         break;
  38                 case 2:
  39                         if (!file->f_inode)
  40                                 return -EINVAL;
  41                         tmp = file->f_inode->i_size + offset;
  42                         break;
  43         }
  44         if (tmp < 0)
  45                 return -EINVAL;
  46         if (tmp != file->f_pos) {
  47                 file->f_pos = tmp;
  48                 file->f_reada = 0;
  49                 file->f_version = ++event;
  50         }
  51         return file->f_pos;
  52 }
  53 
  54 asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
     /* [previous][next][first][last][top][bottom][index][help] */
  55                           unsigned long offset_low, loff_t * result,
  56                           unsigned int origin)
  57 {
  58         struct file * file;
  59         loff_t tmp = -1;
  60         loff_t offset;
  61         int err;
  62 
  63         if (fd >= NR_OPEN || !(file=current->files->fd[fd]) || !(file->f_inode))
  64                 return -EBADF;
  65         if (origin > 2)
  66                 return -EINVAL;
  67         if ((err = verify_area(VERIFY_WRITE, result, sizeof(loff_t))))
  68                 return err;
  69         offset = (loff_t) (((unsigned long long) offset_high << 32) | offset_low);
  70 
  71         /* if there is a fs-specific handler, we can't just ignore it.. */
  72         /* accept llseek() only for the signed long subset of long long */
  73         if (file->f_op && file->f_op->lseek) {
  74                 if (offset != (long) offset)
  75                         return -EINVAL;
  76                 return file->f_op->lseek(file->f_inode,file,offset,origin);
  77         }
  78 
  79         switch (origin) {
  80                 case 0:
  81                         tmp = offset;
  82                         break;
  83                 case 1:
  84                         tmp = file->f_pos + offset;
  85                         break;
  86                 case 2:
  87                         if (!file->f_inode)
  88                                 return -EINVAL;
  89                         tmp = file->f_inode->i_size + offset;
  90                         break;
  91         }
  92         if (tmp < 0)
  93                 return -EINVAL;
  94         if (tmp != file->f_pos) {
  95                 file->f_pos = tmp;
  96                 file->f_reada = 0;
  97                 file->f_version = ++event;
  98         }
  99         memcpy_tofs(result, &file->f_pos, sizeof(loff_t));
 100         return 0;
 101 }
 102 
 103 asmlinkage int sys_read(unsigned int fd,char * buf,unsigned int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 104 {
 105         int error;
 106         struct file * file;
 107         struct inode * inode;
 108 
 109         if (fd>=NR_OPEN || !(file=current->files->fd[fd]) || !(inode=file->f_inode))
 110                 return -EBADF;
 111         if (!(file->f_mode & 1))
 112                 return -EBADF;
 113         if (!file->f_op || !file->f_op->read)
 114                 return -EINVAL;
 115         if (!count)
 116                 return 0;
 117         error = locks_verify_area(FLOCK_VERIFY_READ,inode,file,file->f_pos,count);
 118         if (error)
 119                 return error;
 120         error = verify_area(VERIFY_WRITE,buf,count);
 121         if (error)
 122                 return error;
 123         return file->f_op->read(inode,file,buf,count);
 124 }
 125 
 126 asmlinkage int sys_write(unsigned int fd,char * buf,unsigned int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 127 {
 128         int error;
 129         struct file * file;
 130         struct inode * inode;
 131         int written;
 132         
 133         if (fd>=NR_OPEN || !(file=current->files->fd[fd]) || !(inode=file->f_inode))
 134                 return -EBADF;
 135         if (!(file->f_mode & 2))
 136                 return -EBADF;
 137         if (!file->f_op || !file->f_op->write)
 138                 return -EINVAL;
 139         if (!count)
 140                 return 0;
 141         error = locks_verify_area(FLOCK_VERIFY_WRITE,inode,file,file->f_pos,count);
 142         if (error)
 143                 return error;
 144         error = verify_area(VERIFY_READ,buf,count);
 145         if (error)
 146                 return error;
 147         /*
 148          * If data has been written to the file, remove the setuid and
 149          * the setgid bits. We do it anyway otherwise there is an
 150          * extremely exploitable race - does your OS get it right |->
 151          *
 152          * Set ATTR_FORCE so it will always be changed.
 153          */
 154         if (!suser() && (inode->i_mode & (S_ISUID | S_ISGID))) {
 155                 struct iattr newattrs;
 156                 /*
 157                  * Don't turn off setgid if no group execute. This special
 158                  * case marks candidates for mandatory locking.
 159                  */
 160                 newattrs.ia_mode = inode->i_mode &
 161                         ~(S_ISUID | ((inode->i_mode & S_IXGRP) ? S_ISGID : 0));
 162                 newattrs.ia_valid = ATTR_CTIME | ATTR_MODE | ATTR_FORCE;
 163                 notify_change(inode, &newattrs);
 164         }
 165 
 166         down(&inode->i_sem);
 167         written = file->f_op->write(inode,file,buf,count);
 168         up(&inode->i_sem);
 169         return written;
 170 }
 171 
 172 static int sock_readv_writev(int type, struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 173         const struct iovec * iov, long count, long size)
 174 {
 175         struct msghdr msg;
 176         struct socket *sock;
 177 
 178         sock = &inode->u.socket_i;
 179         if (!sock->ops)
 180                 return -EOPNOTSUPP;
 181         msg.msg_name = NULL;
 182         msg.msg_namelen = 0;
 183         msg.msg_accrights = NULL;
 184         msg.msg_iov = (struct iovec *) iov;
 185         msg.msg_iovlen = count;
 186 
 187         /* read() does a VERIFY_WRITE */
 188         if (type == VERIFY_WRITE) {
 189                 if (!sock->ops->recvmsg)
 190                         return -EOPNOTSUPP;
 191                 return sock->ops->recvmsg(sock, &msg, size,
 192                         (file->f_flags & O_NONBLOCK), 0, NULL);
 193         }
 194         if (!sock->ops->sendmsg)
 195                 return -EOPNOTSUPP;
 196         return sock->ops->sendmsg(sock, &msg, size,
 197                 (file->f_flags & O_NONBLOCK), 0);
 198 }
 199 
 200 typedef int (*IO_fn_t)(struct inode *, struct file *, char *, int);
 201 
 202 static int do_readv_writev(int type, struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 203         const struct iovec * vector, unsigned long count)
 204 {
 205         size_t tot_len;
 206         struct iovec iov[MAX_IOVEC];
 207         int retval, i;
 208         IO_fn_t fn;
 209 
 210         /*
 211          * First get the "struct iovec" from user memory and
 212          * verify all the pointers
 213          */
 214         if (!count)
 215                 return 0;
 216         if (count > MAX_IOVEC)
 217                 return -EINVAL;
 218         retval = verify_area(VERIFY_READ, vector, count*sizeof(*vector));
 219         if (retval)
 220                 return retval;
 221         memcpy_fromfs(iov, vector, count*sizeof(*vector));
 222         tot_len = 0;
 223         for (i = 0 ; i < count ; i++) {
 224                 tot_len += iov[i].iov_len;
 225                 retval = verify_area(type, iov[i].iov_base, iov[i].iov_len);
 226                 if (retval)
 227                         return retval;
 228         }
 229 
 230         retval = locks_verify_area(type == VERIFY_READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
 231                                    inode, file, file->f_pos, tot_len);
 232         if (retval)
 233                 return retval;
 234 
 235         /*
 236          * Then do the actual IO.  Note that sockets need to be handled
 237          * specially as they have atomicity guarantees and can handle
 238          * iovec's natively
 239          */
 240         if (inode->i_sock)
 241                 return sock_readv_writev(type, inode, file, iov, count, tot_len);
 242 
 243         if (!file->f_op)
 244                 return -EINVAL;
 245         /* VERIFY_WRITE actually means a read, as we write to user space */
 246         fn = file->f_op->read;
 247         if (type == VERIFY_READ)
 248                 fn = (IO_fn_t) file->f_op->write;               
 249         vector = iov;
 250         while (count > 0) {
 251                 void * base;
 252                 int len, nr;
 253 
 254                 base = vector->iov_base;
 255                 len = vector->iov_len;
 256                 vector++;
 257                 count--;
 258                 nr = fn(inode, file, base, len);
 259                 if (nr < 0) {
 260                         if (retval)
 261                                 break;
 262                         retval = nr;
 263                         break;
 264                 }
 265                 retval += nr;
 266                 if (nr != len)
 267                         break;
 268         }
 269         return retval;
 270 }
 271 
 272 asmlinkage int sys_readv(unsigned long fd, const struct iovec * vector, long count)
     /* [previous][next][first][last][top][bottom][index][help] */
 273 {
 274         struct file * file;
 275         struct inode * inode;
 276 
 277         if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode = file->f_inode))
 278                 return -EBADF;
 279         if (!(file->f_mode & 1))
 280                 return -EBADF;
 281         return do_readv_writev(VERIFY_WRITE, inode, file, vector, count);
 282 }
 283 
 284 asmlinkage int sys_writev(unsigned long fd, const struct iovec * vector, long count)
     /* [previous][next][first][last][top][bottom][index][help] */
 285 {
 286         int error;
 287         struct file * file;
 288         struct inode * inode;
 289 
 290         if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode = file->f_inode))
 291                 return -EBADF;
 292         if (!(file->f_mode & 2))
 293                 return -EBADF;
 294         down(&inode->i_sem);
 295         error = do_readv_writev(VERIFY_READ, inode, file, vector, count);
 296         up(&inode->i_sem);
 297         return error;
 298 }

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