pread() called with negative offset behaves differently on different
filesystems.

It sets errno to EFBIG on ext2fs and ffs, and EINVAL on msdosfs, nfs,
cd9660 and udf.

Here's what POSIX says:

 The pread() function shall fail, and the file pointer shall remain
 unchanged, if:

 [EINVAL]
    The offset argument is invalid. The value is negative. 

Here's the test.code:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char **argv) {
        int fd;
        char buf[100];

        if((fd = open(argv[1], O_RDONLY, 0777)) == -1) {
                perror("open() failed");
                return 1;
        }
        if(lseek(fd, -1024, SEEK_SET) == -1) {
                perror("lseek() failed");
        }
        if(pread(fd, &buf, 100, -1024) < 0) {
                perror("pread() failed");
                return 3;
        }
        printf("ok\n");
}

I am not sure if this should be fixed on filesystem level or on higher
(like lseek()), but here's a diff for filesystems.

Index: sys/ufs/ext2fs/ext2fs_readwrite.c
===================================================================
RCS file: /cvs/src/sys/ufs/ext2fs/ext2fs_readwrite.c,v
retrieving revision 1.22
diff -u -r1.22 ext2fs_readwrite.c
--- sys/ufs/ext2fs/ext2fs_readwrite.c   17 Jun 2007 20:15:25 -0000      1.22
+++ sys/ufs/ext2fs/ext2fs_readwrite.c   22 Mar 2011 16:52:41 -0000
@@ -92,6 +92,8 @@
                panic("%s: type %d", "ext2fs_read", vp->v_type);
 #endif
        fs = ip->i_e2fs;
+       if (uio->uio_offset < 0)
+               return (EINVAL);
        if ((u_int64_t)uio->uio_offset >
                ((u_int64_t)0x80000000 * fs->e2fs_bsize - 1))
                return (EFBIG);
Index: sys/ufs/ffs/ffs_vnops.c
===================================================================
RCS file: /cvs/src/sys/ufs/ffs/ffs_vnops.c,v
retrieving revision 1.60
diff -u -r1.60 ffs_vnops.c
--- sys/ufs/ffs/ffs_vnops.c     29 Dec 2010 21:28:45 -0000      1.60
+++ sys/ufs/ffs/ffs_vnops.c     22 Mar 2011 16:52:41 -0000
@@ -228,6 +228,8 @@
                panic("ffs_read: type %d", vp->v_type);
 #endif
        fs = ip->i_fs;
+       if (uio->uio_offset < 0)
+               return (EINVAL);
        if ((u_int64_t)uio->uio_offset > fs->fs_maxfilesize)
                return (EFBIG);
 
Index: sys/ntfs/ntfs_vnops.c
===================================================================
RCS file: /cvs/src/sys/ntfs/ntfs_vnops.c,v
retrieving revision 1.22
diff -u -r1.22 ntfs_vnops.c
--- sys/ntfs/ntfs_vnops.c       21 Dec 2010 20:14:43 -0000      1.22
+++ sys/ntfs/ntfs_vnops.c       22 Mar 2011 16:52:57 -0000
@@ -108,6 +108,8 @@
 
        dprintf(("ntfs_read: filesize: %d",(u_int32_t)fp->f_size));
 
+       if (uio->uio_offset < 0)
+               return (EINVAL);
        /* don't allow reading after end of file */
        if (uio->uio_offset > fp->f_size)
                toread = 0;

-- 
Alexander Polakov | plhk.ru

Reply via email to