ext4: Correct block number handling, empty block vs. error code

read_allocated block may return block number 0, which is just an indicator
a chunk of the file is not backed by a block, i.e. it is sparse.

During file deletions, just continue with the next logical block, for other
operations treat blocknumber <= 0 as an error.

For writes, blocknumber 0 should never happen, as U-Boot always allocates
blocks for the whole file.  Reading already handles this correctly, i.e. the
read buffer is 0-fillled.

Not treating block 0 as sparse block leads to FS corruption, e.g.
	./sandbox/u-boot -c 'host bind 0 ./sandbox/test/fs/3GB.ext4.img ;
		ext4write host 0 0 /2.5GB.file 1 '
The 2.5GB.file from the fs test is actually a sparse file.

Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c
index 5e874af..5f21dc7 100644
--- a/fs/ext4/ext4_common.c
+++ b/fs/ext4/ext4_common.c
@@ -534,7 +534,7 @@
 	/* get the block no allocated to a file */
 	for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) {
 		blknr = read_allocated_block(parent_inode, blk_idx);
-		if (blknr == 0)
+		if (blknr <= 0)
 			goto fail;
 
 		/* read the directory block */
@@ -828,7 +828,7 @@
 	/* read the block no allocated to a file */
 	for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) {
 		blknr = read_allocated_block(g_parent_inode, blk_idx);
-		if (blknr == 0)
+		if (blknr <= 0)
 			break;
 		inodeno = unlink_filename(filename, blknr);
 		if (inodeno != -1)
@@ -1590,7 +1590,7 @@
 			if (status == 0) {
 				printf("** SI ext2fs read block (indir 1)"
 					"failed. **\n");
-				return 0;
+				return -1;
 			}
 			ext4fs_indir1_blkno =
 				le32_to_cpu(inode->b.blocks.
diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c
index 913c46e..e4f0905 100644
--- a/fs/ext4/ext4_write.c
+++ b/fs/ext4/ext4_write.c
@@ -461,6 +461,10 @@
 	/* release data blocks */
 	for (i = 0; i < no_blocks; i++) {
 		blknr = read_allocated_block(&inode, i);
+		if (blknr == 0)
+			continue;
+		if (blknr < 0)
+			goto fail;
 		bg_idx = blknr / blk_per_grp;
 		if (fs->blksz == 1024) {
 			remainder = blknr % blk_per_grp;
@@ -718,6 +722,10 @@
 	fs->curr_blkno = 0;
 }
 
+/*
+ * Write data to filesystem blocks. Uses same optimization for
+ * contigous sectors as ext4fs_read_file
+ */
 static int ext4fs_write_file(struct ext2_inode *file_inode,
 			     int pos, unsigned int len, char *buf)
 {
@@ -744,7 +752,7 @@
 		int blockend = fs->blksz;
 		int skipfirst = 0;
 		blknr = read_allocated_block(file_inode, i);
-		if (blknr < 0)
+		if (blknr <= 0)
 			return -1;
 
 		blknr = blknr << log2_fs_blocksize;
@@ -910,6 +918,7 @@
 	/* copy the file content into data blocks */
 	if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
 		printf("Error in copying content\n");
+		/* FIXME: Deallocate data blocks */
 		goto fail;
 	}
 	ibmap_idx = parent_inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group);