changeset 588:59c264b5fef0

cp/fs: don't read past end of file & deal with blocks spanning block boundary Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Sat, 26 Nov 2011 16:34:43 -0500
parents 643aebd957cb
children f74b95352a4e
files cp/fs/edf.c
diffstat 1 files changed, 40 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/cp/fs/edf.c	Sat Nov 26 15:13:45 2011 -0500
+++ b/cp/fs/edf.c	Sat Nov 26 16:34:43 2011 -0500
@@ -205,25 +205,57 @@
 
 	mutex_lock(&file->lock);
 
+	/* check for unsupported geometry */
 	if (file->FST.NLVL != 0 ||
 	    file->FST.PTRSZ != 4 ||
 	    file->FST.LRECL > fs->ADT.DBSIZ ||
 	    file->FST.RECFM != FSTDFIX)
 		goto out;
 
+	/* reading past the end of file? */
+	if (recno >= file->FST.AIC)
+		goto out;
+
 	blk = (recno * file->FST.LRECL) / fs->ADT.DBSIZ;
 	off = (recno * file->FST.LRECL) % fs->ADT.DBSIZ;
 
-	dbuf = bcache_read(file, 0, blk);
-	if (IS_ERR(dbuf)) {
-		ret = PTR_ERR(dbuf);
-		goto out;
+	if ((off + file->FST.LRECL) > fs->ADT.DBSIZ) {
+		int flen = fs->ADT.DBSIZ - off;
+		int slen = file->FST.LRECL - flen;
+
+		assert(flen < file->FST.LRECL);
+		assert(slen < file->FST.LRECL);
+
+		/* the first part of the record */
+		dbuf = bcache_read(file, 0, blk);
+		if (IS_ERR(dbuf)) {
+			ret = PTR_ERR(dbuf);
+			goto out;
+		}
+
+		memcpy(buf, dbuf + off, flen);
+
+		/* the second part of the record */
+		blk++;
+
+		dbuf = bcache_read(file, 0, blk);
+		if (IS_ERR(dbuf)) {
+			ret = PTR_ERR(dbuf);
+			goto out;
+		}
+
+		memcpy(buf + flen, dbuf, slen);
+	} else {
+		/* the whole record */
+		dbuf = bcache_read(file, 0, blk);
+		if (IS_ERR(dbuf)) {
+			ret = PTR_ERR(dbuf);
+			goto out;
+		}
+
+		memcpy(buf, dbuf + off, file->FST.LRECL);
 	}
 
-	BUG_ON((off + file->FST.LRECL) > fs->ADT.DBSIZ);
-
-	memcpy(buf, dbuf + off, file->FST.LRECL);
-
 	ret = 0;
 
 out: