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. sys_readv
  6. 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/mm.h>
  13 #include <linux/uio.h>
  14 
  15 #include <asm/segment.h>
  16 
  17 asmlinkage int sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
     /* [previous][next][first][last][top][bottom][index][help] */
  18 {
  19         struct file * file;
  20         int tmp = -1;
  21 
  22         if (fd >= NR_OPEN || !(file=current->files->fd[fd]) || !(file->f_inode))
  23                 return -EBADF;
  24         if (origin > 2)
  25                 return -EINVAL;
  26         if (file->f_op && file->f_op->lseek)
  27                 return file->f_op->lseek(file->f_inode,file,offset,origin);
  28 
  29 /* this is the default handler if no lseek handler is present */
  30         switch (origin) {
  31                 case 0:
  32                         tmp = offset;
  33                         break;
  34                 case 1:
  35                         tmp = file->f_pos + offset;
  36                         break;
  37                 case 2:
  38                         if (!file->f_inode)
  39                                 return -EINVAL;
  40                         tmp = file->f_inode->i_size + offset;
  41                         break;
  42         }
  43         if (tmp < 0)
  44                 return -EINVAL;
  45         if (tmp != file->f_pos) {
  46                 file->f_pos = tmp;
  47                 file->f_reada = 0;
  48                 file->f_version = ++event;
  49         }
  50         return file->f_pos;
  51 }
  52 
  53 asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
     /* [previous][next][first][last][top][bottom][index][help] */
  54                           unsigned long offset_low, loff_t * result,
  55                           unsigned int origin)
  56 {
  57         struct file * file;
  58         loff_t tmp = -1;
  59         loff_t offset;
  60         int err;
  61 
  62         if (fd >= NR_OPEN || !(file=current->files->fd[fd]) || !(file->f_inode))
  63                 return -EBADF;
  64         if (origin > 2)
  65                 return -EINVAL;
  66         if ((err = verify_area(VERIFY_WRITE, result, sizeof(loff_t))))
  67                 return err;
  68         offset = (loff_t) (((unsigned long long) offset_high << 32) | offset_low);
  69 
  70         /* if there is a fs-specific handler, we can't just ignore it.. */
  71         /* accept llseek() only for the signed long subset of long long */
  72         if (file->f_op && file->f_op->lseek) {
  73                 if (offset != (long) offset)
  74                         return -EINVAL;
  75                 return file->f_op->lseek(file->f_inode,file,offset,origin);
  76         }
  77 
  78         switch (origin) {
  79                 case 0:
  80                         tmp = offset;
  81                         break;
  82                 case 1:
  83                         tmp = file->f_pos + offset;
  84                         break;
  85                 case 2:
  86                         if (!file->f_inode)
  87                                 return -EINVAL;
  88                         tmp = file->f_inode->i_size + offset;
  89                         break;
  90         }
  91         if (tmp < 0)
  92                 return -EINVAL;
  93         if (tmp != file->f_pos) {
  94                 file->f_pos = tmp;
  95                 file->f_reada = 0;
  96                 file->f_version = ++event;
  97         }
  98         memcpy_tofs(result, &file->f_pos, sizeof(loff_t));
  99         return 0;
 100 }
 101 
 102 asmlinkage int sys_read(unsigned int fd,char * buf,unsigned int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104         int error;
 105         struct file * file;
 106         struct inode * inode;
 107 
 108         if (fd>=NR_OPEN || !(file=current->files->fd[fd]) || !(inode=file->f_inode))
 109                 return -EBADF;
 110         if (!(file->f_mode & 1))
 111                 return -EBADF;
 112         if (!file->f_op || !file->f_op->read)
 113                 return -EINVAL;
 114         if (!count)
 115                 return 0;
 116         error = verify_area(VERIFY_WRITE,buf,count);
 117         if (error)
 118                 return error;
 119         return file->f_op->read(inode,file,buf,count);
 120 }
 121 
 122 asmlinkage int sys_write(unsigned int fd,char * buf,unsigned int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 123 {
 124         int error;
 125         struct file * file;
 126         struct inode * inode;
 127         int written;
 128         
 129         if (fd>=NR_OPEN || !(file=current->files->fd[fd]) || !(inode=file->f_inode))
 130                 return -EBADF;
 131         if (!(file->f_mode & 2))
 132                 return -EBADF;
 133         if (!file->f_op || !file->f_op->write)
 134                 return -EINVAL;
 135         if (!count)
 136                 return 0;
 137         error = verify_area(VERIFY_READ,buf,count);
 138         if (error)
 139                 return error;
 140         written = file->f_op->write(inode,file,buf,count);
 141         /*
 142          * If data has been written to the file, remove the setuid and
 143          * the setgid bits
 144          */
 145         if (written > 0 && !suser() && (inode->i_mode & (S_ISUID | S_ISGID))) {
 146                 struct iattr newattrs;
 147                 newattrs.ia_mode = inode->i_mode & ~(S_ISUID | S_ISGID);
 148                 newattrs.ia_valid = ATTR_MODE;
 149                 notify_change(inode, &newattrs);
 150         }
 151         return written;
 152 }
 153 
 154 /*
 155  * OSF/1 (and SunOS) readv/writev emulation.
 156  *
 157  * NOTE! This is not really the way it should be done,
 158  * but it should be good enough for TCP connections,
 159  * notably X11 ;-)
 160  */
 161 asmlinkage int sys_readv(unsigned long fd, const struct iovec * vector, long count)
     /* [previous][next][first][last][top][bottom][index][help] */
 162 {
 163         int retval;
 164         struct file * file;
 165         struct inode * inode;
 166 
 167         if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode = file->f_inode))
 168                 return -EBADF;
 169         if (!(file->f_mode & 1))
 170                 return -EBADF;
 171         if (!file->f_op || !file->f_op->read)
 172                 return -EINVAL;
 173         if (!count)
 174                 return 0;
 175         retval = verify_area(VERIFY_READ, vector, count*sizeof(*vector));
 176         if (retval)
 177                 return retval;
 178 
 179         while (count > 0) {
 180                 void * base;
 181                 int len, nr;
 182 
 183                 base = get_user(&vector->iov_base);
 184                 len = get_user(&vector->iov_len);
 185                 vector++;
 186                 count--;
 187                 nr = verify_area(VERIFY_WRITE, base, len);
 188                 if (!nr)
 189                         nr = file->f_op->read(inode, file, base, len);
 190                 if (nr < 0) {
 191                         if (retval)
 192                                 return retval;
 193                         return nr;
 194                 }
 195                 retval += nr;
 196                 if (nr != len)
 197                         break;
 198         }
 199         return retval;
 200 }
 201 
 202 asmlinkage int sys_writev(unsigned long fd, const struct iovec * vector, long count)
     /* [previous][next][first][last][top][bottom][index][help] */
 203 {
 204         int retval;
 205         struct file * file;
 206         struct inode * inode;
 207 
 208         if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode = file->f_inode))
 209                 return -EBADF;
 210         if (!(file->f_mode & 2))
 211                 return -EBADF;
 212         if (!file->f_op || !file->f_op->write)
 213                 return -EINVAL;
 214         if (!count)
 215                 return 0;
 216         retval = verify_area(VERIFY_READ, vector, count*sizeof(*vector));
 217         if (retval)
 218                 return retval;
 219 
 220         while (count > 0) {
 221                 void * base;
 222                 int len, nr;
 223 
 224                 base = get_user(&vector->iov_base);
 225                 len = get_user(&vector->iov_len);
 226                 vector++;
 227                 count--;
 228                 nr = verify_area(VERIFY_READ, base, len);
 229                 if (!nr)
 230                         nr = file->f_op->write(inode, file, base, len);
 231                 if (nr < 0) {
 232                         if (retval)
 233                                 return retval;
 234                         return nr;
 235                 }
 236                 retval += nr;
 237                 if (nr != len)
 238                         break;
 239         }
 240         return retval;
 241 }

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