VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / fs / read_write.c
index f765a22..d85431d 100644 (file)
@@ -76,14 +76,12 @@ loff_t remote_llseek(struct file *file, loff_t offset, int origin)
        unlock_kernel();
        return retval;
 }
-
 EXPORT_SYMBOL(remote_llseek);
 
 loff_t no_llseek(struct file *file, loff_t offset, int origin)
 {
        return -ESPIPE;
 }
-
 EXPORT_SYMBOL(no_llseek);
 
 loff_t default_llseek(struct file *file, loff_t offset, int origin)
@@ -109,18 +107,21 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin)
        unlock_kernel();
        return retval;
 }
-
 EXPORT_SYMBOL(default_llseek);
 
-static inline loff_t llseek(struct file *file, loff_t offset, int origin)
+loff_t vfs_llseek(struct file *file, loff_t offset, int origin)
 {
        loff_t (*fn)(struct file *, loff_t, int);
 
-       fn = default_llseek;
-       if (file->f_op && file->f_op->llseek)
-               fn = file->f_op->llseek;
+       fn = no_llseek;
+       if (file->f_mode & FMODE_LSEEK) {
+               fn = default_llseek;
+               if (file->f_op && file->f_op->llseek)
+                       fn = file->f_op->llseek;
+       }
        return fn(file, offset, origin);
 }
+EXPORT_SYMBOL(vfs_llseek);
 
 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
 {
@@ -135,7 +136,7 @@ asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
 
        retval = -EINVAL;
        if (origin <= 2) {
-               loff_t res = llseek(file, offset, origin);
+               loff_t res = vfs_llseek(file, offset, origin);
                retval = res;
                if (res != (loff_t)retval)
                        retval = -EOVERFLOW;    /* LFS: should only happen on 32 bit platforms */
@@ -165,7 +166,7 @@ asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
        if (origin > 2)
                goto out_putf;
 
-       offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
+       offset = vfs_llseek(file, ((loff_t) offset_high << 32) | offset_low,
                        origin);
 
        retval = (int)offset;
@@ -269,6 +270,16 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
 
 EXPORT_SYMBOL(vfs_write);
 
+static inline loff_t file_pos_read(struct file *file)
+{
+       return file->f_pos;
+}
+
+static inline void file_pos_write(struct file *file, loff_t pos)
+{
+       file->f_pos = pos;
+}
+
 asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count)
 {
        struct file *file;
@@ -277,7 +288,9 @@ asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count)
 
        file = fget_light(fd, &fput_needed);
        if (file) {
-               ret = vfs_read(file, buf, count, &file->f_pos);
+               loff_t pos = file_pos_read(file);
+               ret = vfs_read(file, buf, count, &pos);
+               file_pos_write(file, pos);
                fput_light(file, fput_needed);
        }
 
@@ -293,7 +306,9 @@ asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t co
 
        file = fget_light(fd, &fput_needed);
        if (file) {
-               ret = vfs_write(file, buf, count, &file->f_pos);
+               loff_t pos = file_pos_read(file);
+               ret = vfs_write(file, buf, count, &pos);
+               file_pos_write(file, pos);
                fput_light(file, fput_needed);
        }
 
@@ -312,7 +327,9 @@ asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf,
 
        file = fget_light(fd, &fput_needed);
        if (file) {
-               ret = vfs_read(file, buf, count, &pos);
+               ret = -ESPIPE;
+               if (file->f_mode & FMODE_PREAD)
+                       ret = vfs_read(file, buf, count, &pos);
                fput_light(file, fput_needed);
        }
 
@@ -331,7 +348,9 @@ asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf,
 
        file = fget_light(fd, &fput_needed);
        if (file) {
-               ret = vfs_write(file, buf, count, &pos);
+               ret = -ESPIPE;
+               if (file->f_mode & FMODE_PWRITE)  
+                       ret = vfs_write(file, buf, count, &pos);
                fput_light(file, fput_needed);
        }
 
@@ -515,7 +534,9 @@ sys_readv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
 
        file = fget_light(fd, &fput_needed);
        if (file) {
-               ret = vfs_readv(file, vec, vlen, &file->f_pos);
+               loff_t pos = file_pos_read(file);
+               ret = vfs_readv(file, vec, vlen, &pos);
+               file_pos_write(file, pos);
                fput_light(file, fput_needed);
        }
 
@@ -531,7 +552,9 @@ sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
 
        file = fget_light(fd, &fput_needed);
        if (file) {
-               ret = vfs_writev(file, vec, vlen, &file->f_pos);
+               loff_t pos = file_pos_read(file);
+               ret = vfs_writev(file, vec, vlen, &pos);
+               file_pos_write(file, pos);
                fput_light(file, fput_needed);
        }
 
@@ -562,8 +585,12 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
                goto fput_in;
        if (!in_file->f_op || !in_file->f_op->sendfile)
                goto fput_in;
+       retval = -ESPIPE;
        if (!ppos)
                ppos = &in_file->f_pos;
+       else
+               if (!(in_file->f_mode & FMODE_PREAD))
+                       goto fput_in;
        retval = locks_verify_area(FLOCK_VERIFY_READ, in_inode, in_file, *ppos, count);
        if (retval)
                goto fput_in;