patch-2.1.1 linux/fs/read_write.c

Next file: linux/fs/stat.c
Previous file: linux/fs/ncpfs/file.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.0/linux/fs/read_write.c linux/fs/read_write.c
@@ -16,84 +16,95 @@
 
 #include <asm/segment.h>
 
-asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
+static long long default_llseek(struct inode *inode,
+	struct file *file,
+	long long offset,
+	int origin)
 {
-	struct file * file;
-	long tmp = -1;
-
-	if (fd >= NR_OPEN || !(file=current->files->fd[fd]) || !(file->f_inode))
-		return -EBADF;
-	if (origin > 2)
-		return -EINVAL;
-	if (file->f_op && file->f_op->llseek)
-		return file->f_op->llseek(file->f_inode,file,offset,origin);
+	long long retval;
 
-/* this is the default handler if no lseek handler is present */
 	switch (origin) {
-		case 0:
-			tmp = offset;
-			break;
-		case 1:
-			tmp = file->f_pos + offset;
-			break;
 		case 2:
-			if (!file->f_inode)
-				return -EINVAL;
-			tmp = file->f_inode->i_size + offset;
+			offset += inode->i_size;
 			break;
+		case 1:
+			offset += file->f_pos;
 	}
-	if (tmp < 0)
-		return -EINVAL;
-	if (tmp != file->f_pos) {
-		file->f_pos = tmp;
-		file->f_reada = 0;
-		file->f_version = ++event;
+	retval = -EINVAL;
+	if (offset >= 0) {
+		if (offset != file->f_pos) {
+			file->f_pos = offset;
+			file->f_reada = 0;
+			file->f_version = ++event;
+		}
+		retval = offset;
 	}
-	return file->f_pos;
+	return retval;
+}
+
+static inline long long llseek(struct inode * inode, struct file *file,
+	long long offset, unsigned int origin)
+{
+	long long (*fn)(struct inode *, struct file *, long long, int);
+
+	fn = default_llseek;
+	if (file->f_op && file->f_op->llseek)
+		fn = file->f_op->llseek;
+	return fn(inode, file, offset, origin);
+}
+
+asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
+{
+	long retval;
+	struct file * file;
+	struct inode * inode;
+
+	retval = -EBADF;
+	if (fd >= NR_OPEN ||
+	    !(file = current->files->fd[fd]) ||
+	    !(inode = file->f_inode))
+		goto bad;
+	retval = -EINVAL;
+	if (origin > 2)
+		goto bad;
+	retval = llseek(inode, file, offset, origin);
+bad:
+	return retval;
 }
 
 asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
 			  unsigned long offset_low, loff_t * result,
 			  unsigned int origin)
 {
+	long retval;
 	struct file * file;
-	loff_t tmp = -1;
-	loff_t offset;
-	int err;
+	struct inode * inode;
+	long long offset;
 
-	if (fd >= NR_OPEN || !(file=current->files->fd[fd]) || !(file->f_inode))
-		return -EBADF;
+	retval = -EBADF;
+	if (fd >= NR_OPEN ||
+	    !(file = current->files->fd[fd]) ||
+	    !(inode = file->f_inode))
+		goto bad;
+	retval = -EINVAL;
 	if (origin > 2)
-		return -EINVAL;
-	if ((err = verify_area(VERIFY_WRITE, result, sizeof(loff_t))))
-		return err;
-	offset = (loff_t) (((unsigned long long) offset_high << 32) | offset_low);
-
-	if (file->f_op && file->f_op->llseek)
-		return file->f_op->llseek(file->f_inode,file,offset,origin);
+		goto bad;
 
-	switch (origin) {
-		case 0:
-			tmp = offset;
-			break;
-		case 1:
-			tmp = file->f_pos + offset;
-			break;
-		case 2:
-			if (!file->f_inode)
-				return -EINVAL;
-			tmp = file->f_inode->i_size + offset;
-			break;
-	}
-	if (tmp < 0)
-		return -EINVAL;
-	if (tmp != file->f_pos) {
-		file->f_pos = tmp;
-		file->f_reada = 0;
-		file->f_version = ++event;
+	retval = verify_area(VERIFY_WRITE, result, sizeof(offset));
+	if (retval)
+		goto bad;
+
+	offset = llseek(inode, file,
+		(((unsigned long long) offset_high << 32) | offset_low),
+		origin);
+
+	retval = offset;
+	if (offset >= 0) {
+		put_user(offset, result);
+		retval = 0;
 	}
-	memcpy_tofs(result, &file->f_pos, sizeof(loff_t));
-	return 0;
+bad:
+	return retval;
 }
 
 asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov