linux-old/fs/read_write.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/read_write.c
   3 *
   4 *  Copyright (C) 1991, 1992  Linus Torvalds
   5 */
   6
   7#include <linux/malloc.h> 
   8#include <linux/stat.h>
   9#include <linux/fcntl.h>
  10#include <linux/file.h>
  11#include <linux/uio.h>
  12#include <linux/smp_lock.h>
  13
  14#include <asm/uaccess.h>
  15
  16static loff_t default_llseek(struct file *file, loff_t offset, int origin)
  17{
  18        long long retval;
  19
  20        switch (origin) {
  21                case 2:
  22                        offset += file->f_dentry->d_inode->i_size;
  23                        break;
  24                case 1:
  25                        offset += file->f_pos;
  26        }
  27        retval = -EINVAL;
  28        if (offset >= 0) {
  29                if (offset != file->f_pos) {
  30                        file->f_pos = offset;
  31                        file->f_reada = 0;
  32                        file->f_version = ++global_event;
  33                }
  34                retval = offset;
  35        }
  36        return retval;
  37}
  38
  39static inline loff_t llseek(struct file *file, loff_t offset, int origin)
  40{
  41        loff_t (*fn)(struct file *, loff_t, int);
  42
  43        fn = default_llseek;
  44        if (file->f_op && file->f_op->llseek)
  45                fn = file->f_op->llseek;
  46        return fn(file, offset, origin);
  47}
  48
  49asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
  50{
  51        off_t retval;
  52        struct file * file;
  53        struct dentry * dentry;
  54        struct inode * inode;
  55
  56        lock_kernel();
  57        retval = -EBADF;
  58        file = fget(fd);
  59        if (!file)
  60                goto bad;
  61        /* N.B. Shouldn't this be ENOENT?? */
  62        if (!(dentry = file->f_dentry) ||
  63            !(inode = dentry->d_inode))
  64                goto out_putf;
  65        retval = -EINVAL;
  66        if (origin <= 2)
  67                retval = llseek(file, offset, origin);
  68out_putf:
  69        fput(file);
  70bad:
  71        unlock_kernel();
  72        return retval;
  73}
  74
  75#if !defined(__alpha__)
  76asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
  77                          unsigned long offset_low, loff_t * result,
  78                          unsigned int origin)
  79{
  80        int retval;
  81        struct file * file;
  82        struct dentry * dentry;
  83        struct inode * inode;
  84        loff_t offset;
  85
  86        lock_kernel();
  87        retval = -EBADF;
  88        file = fget(fd);
  89        if (!file)
  90                goto bad;
  91        /* N.B. Shouldn't this be ENOENT?? */
  92        if (!(dentry = file->f_dentry) ||
  93            !(inode = dentry->d_inode))
  94                goto out_putf;
  95        retval = -EINVAL;
  96        if (origin > 2)
  97                goto out_putf;
  98
  99        offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
 100                        origin);
 101
 102        retval = (int)offset;
 103        if (offset >= 0) {
 104                retval = -EFAULT;
 105                if (!copy_to_user(result, &offset, sizeof(offset)))
 106                        retval = 0;
 107        }
 108out_putf:
 109        fput(file);
 110bad:
 111        unlock_kernel();
 112        return retval;
 113}
 114#endif
 115
 116asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
 117{
 118        ssize_t ret;
 119        struct file * file;
 120        ssize_t (*read)(struct file *, char *, size_t, loff_t *);
 121
 122        lock_kernel();
 123
 124        ret = -EBADF;
 125        file = fget(fd);
 126        if (!file)
 127                goto bad_file;
 128        if (!(file->f_mode & FMODE_READ))
 129                goto out;
 130        ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
 131                                file, file->f_pos, count);
 132        if (ret)
 133                goto out;
 134        ret = -EINVAL;
 135        if (!file->f_op || !(read = file->f_op->read))
 136                goto out;
 137        ret = read(file, buf, count, &file->f_pos);
 138out:
 139        fput(file);
 140bad_file:
 141        unlock_kernel();
 142        return ret;
 143}
 144
 145asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
 146{
 147        ssize_t ret;
 148        struct file * file;
 149        struct inode * inode;
 150        ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
 151
 152        lock_kernel();
 153
 154        ret = -EBADF;
 155        file = fget(fd);
 156        if (!file)
 157                goto bad_file;
 158        if (!(file->f_mode & FMODE_WRITE))
 159                goto out;
 160        inode = file->f_dentry->d_inode;
 161        ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
 162                                file->f_pos, count);
 163        if (ret)
 164                goto out;
 165        ret = -EINVAL;
 166        if (!file->f_op || !(write = file->f_op->write))
 167                goto out;
 168
 169        fs_down(&inode->i_sem);
 170        ret = write(file, buf, count, &file->f_pos);
 171        fs_up(&inode->i_sem);
 172out:
 173        fput(file);
 174bad_file:
 175        unlock_kernel();
 176        return ret;
 177}
 178
 179
 180static ssize_t do_readv_writev(int type, struct file *file,
 181                               const struct iovec * vector,
 182                               unsigned long count)
 183{
 184        typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
 185
 186        size_t tot_len;
 187        struct iovec iovstack[UIO_FASTIOV];
 188        struct iovec *iov=iovstack;
 189        ssize_t ret, i;
 190        io_fn_t fn;
 191        struct inode *inode;
 192
 193        /*
 194         * First get the "struct iovec" from user memory and
 195         * verify all the pointers
 196         */
 197        ret = 0;
 198        if (!count)
 199                goto out_nofree;
 200        ret = -EINVAL;
 201        if (count > UIO_MAXIOV)
 202                goto out_nofree;
 203        if (count > UIO_FASTIOV) {
 204                ret = -ENOMEM;
 205                iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
 206                if (!iov)
 207                        goto out_nofree;
 208        }
 209        ret = -EFAULT;
 210        if (copy_from_user(iov, vector, count*sizeof(*vector)))
 211                goto out;
 212
 213        /* BSD readv/writev returns EINVAL if one of the iov_len
 214           values < 0 or tot_len overflowed a 32-bit integer. -ink */
 215        tot_len = 0;
 216        ret = -EINVAL;
 217        for (i = 0 ; i < count ; i++) {
 218                size_t tmp = tot_len;
 219                int len = iov[i].iov_len;
 220                if (len < 0)
 221                        goto out;
 222                (u32)tot_len += len;
 223                if (tot_len < tmp || tot_len < (u32)len)
 224                        goto out;
 225        }
 226
 227        inode = file->f_dentry->d_inode;
 228        /* VERIFY_WRITE actually means a read, as we write to user space */
 229        ret = locks_verify_area((type == VERIFY_WRITE
 230                                 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
 231                                inode, file, file->f_pos, tot_len);
 232        if (ret) goto out;
 233
 234        /*
 235         * Then do the actual IO.  Note that sockets need to be handled
 236         * specially as they have atomicity guarantees and can handle
 237         * iovec's natively
 238         */
 239        if (inode->i_sock) {
 240                ret = sock_readv_writev(type,inode,file,iov,count,tot_len);
 241                goto out;
 242        }
 243
 244        ret = -EINVAL;
 245        if (!file->f_op)
 246                goto out;
 247
 248        /* VERIFY_WRITE actually means a read, as we write to user space */
 249        fn = file->f_op->read;
 250        if (type == VERIFY_READ)
 251                fn = (io_fn_t) file->f_op->write;               
 252
 253        ret = 0;
 254        vector = iov;
 255        while (count > 0) {
 256                void * base;
 257                size_t len;
 258                ssize_t nr;
 259
 260                base = vector->iov_base;
 261                len = vector->iov_len;
 262                vector++;
 263                count--;
 264
 265                nr = fn(file, base, len, &file->f_pos);
 266
 267                if (nr < 0) {
 268                        if (!ret) ret = nr;
 269                        break;
 270                }
 271                ret += nr;
 272                if (nr != len)
 273                        break;
 274        }
 275
 276out:
 277        if (iov != iovstack)
 278                kfree(iov);
 279out_nofree:
 280        return ret;
 281}
 282
 283asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
 284                             unsigned long count)
 285{
 286        struct file * file;
 287        ssize_t ret;
 288
 289        lock_kernel();
 290
 291        ret = -EBADF;
 292        file = fget(fd);
 293        if (!file)
 294                goto bad_file;
 295        if (file->f_op && file->f_op->read && (file->f_mode & FMODE_READ))
 296                ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
 297        fput(file);
 298
 299bad_file:
 300        unlock_kernel();
 301        return ret;
 302}
 303
 304asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
 305                              unsigned long count)
 306{
 307        struct file * file;
 308        ssize_t ret;
 309
 310        lock_kernel();
 311
 312        ret = -EBADF;
 313        file = fget(fd);
 314        if (!file)
 315                goto bad_file;
 316        if (file->f_op && file->f_op->write && (file->f_mode & FMODE_WRITE)) {
 317                fs_down(&file->f_dentry->d_inode->i_sem);
 318                ret = do_readv_writev(VERIFY_READ, file, vector, count);
 319                fs_up(&file->f_dentry->d_inode->i_sem);
 320        }
 321        fput(file);
 322
 323bad_file:
 324        unlock_kernel();
 325        return ret;
 326}
 327
 328/* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
 329   lseek back to original location.  They fail just like lseek does on
 330   non-seekable files.  */
 331
 332asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
 333                             size_t count, loff_t pos)
 334{
 335        ssize_t ret;
 336        struct file * file;
 337        ssize_t (*read)(struct file *, char *, size_t, loff_t *);
 338
 339        lock_kernel();
 340
 341        ret = -EBADF;
 342        file = fget(fd);
 343        if (!file)
 344                goto bad_file;
 345        if (!(file->f_mode & FMODE_READ))
 346                goto out;
 347        ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
 348                                file, pos, count);
 349        if (ret)
 350                goto out;
 351        ret = -EINVAL;
 352        if (!file->f_op || !(read = file->f_op->read))
 353                goto out;
 354        if (pos < 0)
 355                goto out;
 356        ret = read(file, buf, count, &pos);
 357out:
 358        fput(file);
 359bad_file:
 360        unlock_kernel();
 361        return ret;
 362}
 363
 364asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
 365                              size_t count, loff_t pos)
 366{
 367        ssize_t ret;
 368        struct file * file;
 369        ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
 370
 371        lock_kernel();
 372
 373        ret = -EBADF;
 374        file = fget(fd);
 375        if (!file)
 376                goto bad_file;
 377        if (!(file->f_mode & FMODE_WRITE))
 378                goto out;
 379        ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
 380                                file, pos, count);
 381        if (ret)
 382                goto out;
 383        ret = -EINVAL;
 384        if (!file->f_op || !(write = file->f_op->write))
 385                goto out;
 386        if (pos < 0)
 387                goto out;
 388
 389        fs_down(&file->f_dentry->d_inode->i_sem);
 390        ret = write(file, buf, count, &pos);
 391        fs_up(&file->f_dentry->d_inode->i_sem);
 392
 393out:
 394        fput(file);
 395bad_file:
 396        unlock_kernel();
 397        return ret;
 398}
 399
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.