Index: uspace/srv/fs/fat/fat_fat.c
===================================================================
--- uspace/srv/fs/fat/fat_fat.c	(revision 6c8d267f6f936c9ea1e6b6c21a5dcb0e47cb7c6e)
+++ uspace/srv/fs/fat/fat_fat.c	(revision 913a821c75618e2080c191022d635c81d2a7052e)
@@ -130,5 +130,5 @@
 	unsigned ssa;		/* size of the system area */
 	unsigned clusters, max_clusters;
-	fat_cluster_t lastc, clst = firstc;
+	fat_cluster_t lastc;
 
 	bps = uint16_t_le2host(bs->bps);
@@ -158,5 +158,4 @@
 	return b;
 }
-
 
 /** Fill the gap between EOF and a new file position.
@@ -204,14 +203,41 @@
 }
 
-/** Mark cluster in one instance of FAT.
+/** Get cluster from the first FAT.
+ *
+ * @param bs		Buffer holding the boot sector for the file system.
+ * @param dev_handle	Device handle for the file system.
+ * @param clst		Cluster which to get.
+ *
+ * @return		Value found in the cluster.
+ */
+fat_cluster_t
+fat_get_cluster(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t clst)
+{
+	block_t *b;
+	uint16_t bps;
+	uint16_t rscnt;
+	fat_cluster_t *cp, value;
+
+	bps = uint16_t_le2host(bs->bps);
+	rscnt = uint16_t_le2host(bs->rscnt);
+
+	b = block_get(dev_handle, rscnt + (clst * sizeof(fat_cluster_t)) / bps);
+	cp = (fat_cluster_t *)b->data + clst % (bps / sizeof(fat_cluster_t));
+	value = uint16_t_le2host(*cp);
+	block_put(b);
+	
+	return value;
+}
+
+/** Set cluster in one instance of FAT.
  *
  * @param bs		Buffer holding the boot sector for the file system.
  * @param dev_handle	Device handle for the file system.
  * @param fatno		Number of the FAT instance where to make the change.
- * @param clst		Cluster which is to be marked.
- * @param value		Value mark the cluster with.
+ * @param clst		Cluster which is to be set.
+ * @param value		Value to set the cluster with.
  */
 void
-fat_mark_cluster(fat_bs_t *bs, dev_handle_t dev_handle, unsigned fatno,
+fat_set_cluster(fat_bs_t *bs, dev_handle_t dev_handle, unsigned fatno,
     fat_cluster_t clst, fat_cluster_t value)
 {
@@ -250,5 +276,5 @@
 	for (fatno = FAT1 + 1; fatno < bs->fatcnt; fatno++) {
 		for (c = 0; c < nclsts; c++) {
-			fat_mark_cluster(bs, dev_handle, fatno, lifo[c],
+			fat_set_cluster(bs, dev_handle, fatno, lifo[c],
 			    c == 0 ? FAT_CLST_LAST1 : lifo[c - 1]);
 		}
@@ -334,5 +360,5 @@
 	 */
 	while (found--) {
-		fat_mark_cluster(bs, dev_handle, FAT1, lifo[found],
+		fat_set_cluster(bs, dev_handle, FAT1, lifo[found],
 		    FAT_CLST_RES0);
 	}
@@ -342,7 +368,30 @@
 }
 
+/** Free clusters forming a cluster chain in all copies of FAT.
+ *
+ * @param bs		Buffer hodling the boot sector of the file system.
+ * @param dev_handle	Device handle of the file system.
+ * @param firstc	First cluster in the chain which is to be freed.
+ */
+void
+fat_free_clusters(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t firstc)
+{
+	unsigned fatno;
+	fat_cluster_t nextc;
+
+	/* Mark all clusters in the chain as free in all copies of FAT. */
+	while (firstc < FAT_CLST_LAST1) {
+		nextc = fat_get_cluster(bs, dev_handle, firstc);
+		assert(nextc >= FAT_CLST_FIRST && nextc < FAT_CLST_BAD);
+		for (fatno = FAT1; fatno < bs->fatcnt; fatno++)
+			fat_set_cluster(bs, dev_handle, fatno, firstc,
+			    FAT_CLST_RES0);
+		firstc = nextc;
+	}
+}
+
 /** Append a cluster chain to the last file cluster in all FATs.
  *
- * @param bs		Buffer holding boot sector of the file system.
+ * @param bs		Buffer holding the boot sector of the file system.
  * @param nodep		Node representing the file.
  * @param mcl		First cluster of the cluster chain to append.
@@ -354,5 +403,5 @@
 	uint8_t fatno;
 
-	if (fat_cluster_walk(bs, nodep->idx->dev_handle, nodep->firstc, &lcl,
+	if (fat_cluster_walk(bs, dev_handle, nodep->firstc, &lcl,
 	    (uint16_t) -1) == 0) {
 		/* No clusters allocated to the node yet. */
@@ -363,5 +412,36 @@
 
 	for (fatno = FAT1; fatno < bs->fatcnt; fatno++)
-		fat_mark_cluster(bs, nodep->idx->dev_handle, fatno, lcl, mcl);
+		fat_set_cluster(bs, nodep->idx->dev_handle, fatno, lcl, mcl);
+}
+
+/** Chop off node clusters in all copies of FAT.
+ *
+ * @param bs		Buffer holding the boot sector of the file system.
+ * @param nodep		FAT node where the chopping will take place.
+ * @param lastc		Last cluster which will remain in the node. If this
+ *			argument is FAT_CLST_RES0, then all clusters will
+ *			be choped off.
+ */
+void fat_chop_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t lastc)
+{
+	dev_handle_t dev_handle = nodep->idx->dev_handle;
+	if (lastc == FAT_CLST_RES0) {
+		/* The node will have zero size and no clusters allocated. */
+		fat_free_clusters(bs, dev_handle, nodep->firstc);
+		nodep->firstc = FAT_CLST_RES0;
+		nodep->dirty = true;		/* need to sync node */
+	} else {
+		fat_cluster_t nextc;
+		unsigned fatno;
+
+		nextc = fat_get_cluster(bs, dev_handle, lastc);
+
+		/* Terminate the cluster chain in all copies of FAT. */
+		for (fatno = FAT1; fatno < bs->fatcnt; fatno++)
+			fat_set_cluster(bs, dev_handle, fatno, lastc, FAT_CLST_LAST1);
+
+		/* Free all following clusters. */
+		fat_free_clusters(bs, dev_handle, nextc);
+	}
 }
 
Index: uspace/srv/fs/fat/fat_fat.h
===================================================================
--- uspace/srv/fs/fat/fat_fat.h	(revision 6c8d267f6f936c9ea1e6b6c21a5dcb0e47cb7c6e)
+++ uspace/srv/fs/fat/fat_fat.h	(revision 913a821c75618e2080c191022d635c81d2a7052e)
@@ -72,9 +72,13 @@
 extern void fat_append_clusters(struct fat_bs *, struct fat_node *,
     fat_cluster_t);
+extern void fat_chop_clusters(struct fat_bs *, struct fat_node *,
+    fat_cluster_t);
 extern int fat_alloc_clusters(struct fat_bs *, dev_handle_t, unsigned,
     fat_cluster_t *, fat_cluster_t *);
+extern void fat_free_clusters(struct fat_bs *, dev_handle_t, fat_cluster_t);
 extern void fat_alloc_shadow_clusters(struct fat_bs *, dev_handle_t,
     fat_cluster_t *, unsigned);
-extern void fat_mark_cluster(struct fat_bs *, dev_handle_t, unsigned,
+extern fat_cluster_t fat_get_cluster(struct fat_bs *, dev_handle_t, fat_cluster_t);
+extern void fat_set_cluster(struct fat_bs *, dev_handle_t, unsigned,
     fat_cluster_t, fat_cluster_t);
 extern void fat_fill_gap(struct fat_bs *, struct fat_node *, fat_cluster_t,
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision 6c8d267f6f936c9ea1e6b6c21a5dcb0e47cb7c6e)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 913a821c75618e2080c191022d635c81d2a7052e)
@@ -635,4 +635,5 @@
 	uint16_t bps;
 	unsigned spc;
+	unsigned bpc;		/* bytes per cluster */
 	off_t boundary;
 	
@@ -650,4 +651,9 @@
 		return;
 	}
+
+	bs = block_bb_get(dev_handle);
+	bps = uint16_t_le2host(bs->bps);
+	spc = bs->spc;
+	bpc = bps * spc;
 
 	/*
@@ -659,10 +665,6 @@
 	 */ 
 	bytes = min(len, bps - pos % bps);
-
-	bs = block_bb_get(dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	spc = bs->spc;
-	
-	boundary = ROUND_UP(nodep->size, bps * spc);
+	
+	boundary = ROUND_UP(nodep->size, bpc);
 	if (pos < boundary) {
 		/*
@@ -694,9 +696,7 @@
 		fat_cluster_t mcl, lcl; 
  
-		nclsts = (ROUND_UP(pos + bytes, bps * spc) - boundary) /
-		    bps * spc;
+		nclsts = (ROUND_UP(pos + bytes, bpc) - boundary) / bpc;
 		/* create an independent chain of nclsts clusters in all FATs */
-		status = fat_alloc_clusters(bs, dev_handle, nclsts, &mcl,
-		    &lcl);
+		status = fat_alloc_clusters(bs, dev_handle, nclsts, &mcl, &lcl);
 		if (status != EOK) {
 			/* could not allocate a chain of nclsts clusters */
@@ -732,4 +732,8 @@
 	size_t size = (off_t)IPC_GET_ARG3(*request);
 	fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
+	fat_bs_t *bs;
+	uint16_t bps;
+	uint8_t spc;
+	unsigned bpc;	/* bytes per cluster */
 	int rc;
 
@@ -738,4 +742,9 @@
 		return;
 	}
+
+	bs = block_bb_get(dev_handle);
+	bps = uint16_t_le2host(bs->bps);
+	spc = bs->spc;
+	bpc = bps * spc;
 
 	if (nodep->size == size) {
@@ -743,18 +752,34 @@
 	} else if (nodep->size < size) {
 		/*
-		 * TODO: the standard says we have the freedom to grow the file.
+		 * The standard says we have the freedom to grow the node.
 		 * For now, we simply return an error.
 		 */
 		rc = EINVAL;
+	} else if (ROUND_UP(nodep->size, bpc) == ROUND_UP(size, bpc)) {
+		/*
+		 * The node will be shrunk, but no clusters will be deallocated.
+		 */
+		nodep->size = size;
+		nodep->dirty = true;		/* need to sync node */
+		rc = EOK;	
 	} else {
 		/*
-		 * The file is to be shrunk.
-		 */
-		rc = ENOTSUP;	/* XXX */
+		 * The node will be shrunk, clusters will be deallocated.
+		 */
+		if (size == 0) {
+			fat_chop_clusters(bs, nodep, FAT_CLST_RES0);
+		} else {
+			fat_cluster_t lastc;
+			(void) fat_cluster_walk(bs, dev_handle, nodep->firstc,
+			    &lastc, (size - 1) / bpc);
+			fat_chop_clusters(bs, nodep, lastc);
+		}
+		nodep->size = size;
+		nodep->dirty = true;		/* need to sync node */
+		rc = EOK;	
 	}
 	fat_node_put(nodep);
 	ipc_answer_0(rid, rc);
 	return;
-
 }
 
