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