Index: uspace/srv/fs/fat/fat_fat.c
===================================================================
--- uspace/srv/fs/fat/fat_fat.c	(revision 8334a4273bf63ded76f0b722c7073266018a773c)
+++ uspace/srv/fs/fat/fat_fat.c	(revision 4f1c0b4508cc407558c39daef8cd8eaf155276f0)
@@ -55,110 +55,48 @@
 static futex_t fat_alloc_lock = FUTEX_INITIALIZER;
 
-/** Read block from file located on a FAT file system.
- *
- * @param bs		Buffer holding the boot sector of the file system.
- * @param dev_handle	Device handle of the file system.
- * @param firstc	First cluster used by the file. Can be zero if the file
- *			is empty.
- * @param offset	Offset in blocks.
- *
- * @return		Block structure holding the requested block.
- */
-block_t *
-_fat_block_get(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t firstc,
-    off_t offset)
+/** Walk the cluster chain.
+ *
+ * @param bs		Buffer holding the boot sector for the file.
+ * @param dev_handle	Device handle of the device with the file.
+ * @param firstc	First cluster to start the walk with.
+ * @param penult	If non-NULL, output argument hodling the
+ * 			the penultimate cluster visited.
+ * @param ult		If non-NULL, output argument holding the
+ *			ultimate cluster visited.
+ * @param max_clusters	Maximum number of clusters to visit.	
+ *
+ * @return		Number of clusters seen during the walk.
+ */
+uint16_t 
+fat_cluster_walk(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t firstc,
+    fat_cluster_t *penult, fat_cluster_t *ult, uint16_t max_clusters)
 {
 	block_t *b;
 	unsigned bps;
-	unsigned spc;
 	unsigned rscnt;		/* block address of the first FAT */
-	unsigned fatcnt;
-	unsigned rde;
-	unsigned rds;		/* root directory size */
-	unsigned sf;
-	unsigned ssa;		/* size of the system area */
-	unsigned clusters;
+	uint16_t clusters = 0;
 	fat_cluster_t clst = firstc;
-	unsigned i;
-
-	bps = uint16_t_le2host(bs->bps);
-	spc = bs->spc;
+
+	bps = uint16_t_le2host(bs->bps);
 	rscnt = uint16_t_le2host(bs->rscnt);
-	fatcnt = bs->fatcnt;
-	rde = uint16_t_le2host(bs->root_ent_max);
-	sf = uint16_t_le2host(bs->sec_per_fat);
-
-	rds = (sizeof(fat_dentry_t) * rde) / bps;
-	rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
-	ssa = rscnt + fatcnt * sf + rds;
-
-	if (firstc == FAT_CLST_ROOT) {
-		/* root directory special case */
-		assert(offset < rds);
-		b = block_get(dev_handle, rscnt + fatcnt * sf + offset);
-		return b;
-	}
-
-	clusters = offset / spc; 
-	for (i = 0; i < clusters; i++) {
+
+	if (firstc == FAT_CLST_RES0) {
+		/* No space allocated to the file. */
+		if (ult)
+			*ult = firstc;
+		return 0;
+	}
+
+	/* At this point, the meaning of penult is not well-defined. */
+	if (penult)
+		*penult = FAT_CLST_RES0;
+
+	while (clst < FAT_CLST_LAST1 && clusters < max_clusters) {
 		unsigned fsec;	/* sector offset relative to FAT1 */
 		unsigned fidx;	/* FAT1 entry index */
 
-		assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD);
-		fsec = (clst * sizeof(fat_cluster_t)) / bps;
-		fidx = clst % (bps / sizeof(fat_cluster_t));
-		/* read FAT1 */
-		b = block_get(dev_handle, rscnt + fsec);
-		clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
-		assert(clst != FAT_CLST_BAD);
-		assert(clst < FAT_CLST_LAST1);
-		block_put(b);
-	}
-
-	b = block_get(dev_handle, ssa + (clst - FAT_CLST_FIRST) * spc +
-	    offset % spc);
-
-	return b;
-}
-
-/** Return number of blocks allocated to a file.
- *
- * @param bs		Buffer holding the boot sector for the file.
- * @param dev_handle	Device handle of the device with the file.
- * @param firstc	First cluster of the file.
- * @param lastc		If non-NULL, output argument holding the
- *			last cluster.
- *
- * @return		Number of blocks allocated to the file.
- */
-uint16_t 
-_fat_blcks_get(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t firstc,
-    fat_cluster_t *lastc)
-{
-	block_t *b;
-	unsigned bps;
-	unsigned spc;
-	unsigned rscnt;		/* block address of the first FAT */
-	unsigned clusters = 0;
-	fat_cluster_t clst = firstc;
-
-	bps = uint16_t_le2host(bs->bps);
-	spc = bs->spc;
-	rscnt = uint16_t_le2host(bs->rscnt);
-
-	if (firstc == FAT_CLST_RES0) {
-		/* No space allocated to the file. */
-		if (lastc)
-			*lastc = firstc;
-		return 0;
-	}
-
-	while (clst < FAT_CLST_LAST1) {
-		unsigned fsec;	/* sector offset relative to FAT1 */
-		unsigned fidx;	/* FAT1 entry index */
-
 		assert(clst >= FAT_CLST_FIRST);
-		if (lastc)
-			*lastc = clst;		/* remember the last cluster */
+		if (penult)
+			*penult = clst;	/* remember the penultimate cluster */
 		fsec = (clst * sizeof(fat_cluster_t)) / bps;
 		fidx = clst % (bps / sizeof(fat_cluster_t));
@@ -171,8 +109,61 @@
 	}
 
-	if (lastc)
-		*lastc = clst;
-	return clusters * spc;
-}
+	if (ult)
+		*ult = clst;
+
+	return clusters;
+}
+
+/** Read block from file located on a FAT file system.
+ *
+ * @param bs		Buffer holding the boot sector of the file system.
+ * @param dev_handle	Device handle of the file system.
+ * @param firstc	First cluster used by the file. Can be zero if the file
+ *			is empty.
+ * @param offset	Offset in blocks.
+ *
+ * @return		Block structure holding the requested block.
+ */
+block_t *
+_fat_block_get(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t firstc,
+    off_t offset)
+{
+	block_t *b;
+	unsigned bps;
+	unsigned rscnt;		/* block address of the first FAT */
+	unsigned rde;
+	unsigned rds;		/* root directory size */
+	unsigned sf;
+	unsigned ssa;		/* size of the system area */
+	unsigned clusters, max_clusters;
+	fat_cluster_t lastc, clst = firstc;
+
+	bps = uint16_t_le2host(bs->bps);
+	rscnt = uint16_t_le2host(bs->rscnt);
+	rde = uint16_t_le2host(bs->root_ent_max);
+	sf = uint16_t_le2host(bs->sec_per_fat);
+
+	rds = (sizeof(fat_dentry_t) * rde) / bps;
+	rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
+	ssa = rscnt + bs->fatcnt * sf + rds;
+
+	if (firstc == FAT_CLST_ROOT) {
+		/* root directory special case */
+		assert(offset < rds);
+		b = block_get(dev_handle, rscnt + bs->fatcnt * sf + offset);
+		return b;
+	}
+
+	max_clusters = offset / bs->spc;
+	clusters = fat_cluster_walk(bs, dev_handle, firstc, NULL, &lastc,
+	    max_clusters);
+	assert(clusters == max_clusters);
+
+	b = block_get(dev_handle, ssa + (lastc - FAT_CLST_FIRST) * bs->spc +
+	    offset % bs->spc);
+
+	return b;
+}
+
 
 /** Fill the gap between EOF and a new file position.
@@ -370,5 +361,6 @@
 	uint8_t fatno;
 
-	if (_fat_blcks_get(bs, dev_handle, nodep->firstc, &lcl) == 0) {
+	if (fat_clusters_get(bs, nodep->idx->dev_handle, nodep->firstc) == 0) {
+		/* No clusters allocated to the node yet. */
 		nodep->firstc = host2uint16_t_le(mcl);
 		nodep->dirty = true;		/* need to sync node */
Index: uspace/srv/fs/fat/fat_fat.h
===================================================================
--- uspace/srv/fs/fat/fat_fat.h	(revision 8334a4273bf63ded76f0b722c7073266018a773c)
+++ uspace/srv/fs/fat/fat_fat.h	(revision 4f1c0b4508cc407558c39daef8cd8eaf155276f0)
@@ -58,11 +58,13 @@
 typedef uint16_t fat_cluster_t;
 
+#define fat_clusters_get(bs, dh, fc) \
+    fat_cluster_walk((bs), (dh), (fc), NULL, NULL, (uint16_t) -1)
 #define fat_block_get(bs, np, off) \
     _fat_block_get((bs), (np)->idx->dev_handle, (np)->firstc, (off))
-    
+
 extern struct block *_fat_block_get(struct fat_bs *, dev_handle_t,
     fat_cluster_t, off_t);
-extern uint16_t _fat_blcks_get(struct fat_bs *, dev_handle_t, fat_cluster_t,
-    fat_cluster_t *);
+extern uint16_t fat_cluster_walk(struct fat_bs *, dev_handle_t, fat_cluster_t,
+    fat_cluster_t *, fat_cluster_t *, uint16_t);
   
 extern void fat_append_clusters(struct fat_bs *, struct fat_node *,
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision 8334a4273bf63ded76f0b722c7073266018a773c)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 4f1c0b4508cc407558c39daef8cd8eaf155276f0)
@@ -114,4 +114,5 @@
 	fat_node_t *nodep = NULL;
 	unsigned bps;
+	unsigned spc;
 	unsigned dps;
 
@@ -165,4 +166,5 @@
 	bs = block_bb_get(idxp->dev_handle);
 	bps = uint16_t_le2host(bs->bps);
+	spc = bs->spc;
 	dps = bps / sizeof(fat_dentry_t);
 
@@ -185,6 +187,6 @@
 		 * size of the directory by walking the FAT.
 		 */
-		nodep->size = bps * _fat_blcks_get(bs, idxp->dev_handle,
-		    uint16_t_le2host(d->firstc), NULL);
+		nodep->size = bps * spc * fat_clusters_get(bs, idxp->dev_handle,
+		    uint16_t_le2host(d->firstc));
 	} else {
 		nodep->type = FAT_FILE;
