Index: uspace/srv/fs/fat/fat_fat.c
===================================================================
--- uspace/srv/fs/fat/fat_fat.c	(revision fc35e985a99af215aebc39389e5bfeeedc65fcfe)
+++ uspace/srv/fs/fat/fat_fat.c	(revision 97bc3ee99b9182a255fcba5caf3fc118a0f767c1)
@@ -29,5 +29,5 @@
 /** @addtogroup fs
  * @{
- */ 
+ */
 
 /**
@@ -53,8 +53,4 @@
  * primitive boot sector members.
  */
-#define RDS(bs)		((sizeof(fat_dentry_t) * RDE((bs))) / BPS((bs))) + \
-			(((sizeof(fat_dentry_t) * RDE((bs))) % BPS((bs))) != 0)
-#define SSA(bs)		(RSCNT((bs)) + FATCNT((bs)) * SF((bs)) + RDS(bs))
-
 #define CLBN2PBN(bs, cl, bn) \
 	(SSA((bs)) + ((cl) - FAT_CLST_FIRST) * SPC((bs)) + (bn) % SPC((bs)))
@@ -64,5 +60,5 @@
  * during allocation of clusters. The lock does not have to be held durring
  * deallocation of clusters.
- */  
+ */
 static FIBRIL_MUTEX_INITIALIZE(fat_alloc_lock);
 
@@ -76,9 +72,9 @@
  * @param numc		If non-NULL, output argument holding the number of
  *			clusters seen during the walk.
- * @param max_clusters	Maximum number of clusters to visit.	
+ * @param max_clusters	Maximum number of clusters to visit.
  *
  * @return		EOK on success or a negative error code.
  */
-int 
+int
 fat_cluster_walk(fat_bs_t *bs, devmap_handle_t devmap_handle, fat_cluster_t firstc,
     fat_cluster_t *lastc, uint16_t *numc, uint16_t max_clusters)
@@ -105,5 +101,4 @@
 
                 /* read FAT1 */
-                /* We should use fat_get_cluster instead */
                 rc = fat_get_cluster(bs, devmap_handle, FAT1, clst, &clst);
                 if (rc != EOK)
@@ -145,5 +140,5 @@
 		return ELIMIT;
 
-	if (nodep->firstc == FAT_CLST_ROOT) 
+	if (nodep->firstc == FAT_CLST_ROOT)
 		goto fall_through;
 
@@ -172,5 +167,5 @@
 	if (rc != EOK)
 		return rc;
-	
+
 	/*
 	 * Update the "current" cluster cache.
@@ -192,5 +187,5 @@
  * @param clp		If not NULL, address where the cluster containing bn
  *			will be stored.
- *			stored 
+ *			stored
  * @param bn		Block number.
  * @param flags		Flags passed to libblock.
@@ -269,8 +264,8 @@
 			return rc;
 	}
-	
+
 	if (o >= pos)
 		return EOK;
-	
+
 	/* zero out the initial part of the new cluster chain */
 	for (o = boundary; o < pos; o += BPS(bs)) {
@@ -302,38 +297,53 @@
     fat_cluster_t clst, fat_cluster_t *value)
 {
-	block_t *b;
-	fat_cluster_t *cp;
-        aoff64_t fsec;  /* sector offset relative to FAT */
-        unsigned fidx;  /* entry index */
+	block_t *b, *b1;
+        aoff64_t offset;
 	int rc;
 
         assert(fatno < FATCNT(bs));
 
-
         if (FATTYPE(bs) == 16)
-        {
-            fsec = (clst * sizeof(fat_cluster_t)) / BPS(bs);
-            fidx = clst % (BPS(bs) / sizeof(fat_cluster_t));
+            offset = (clst * 2);
+        else
+            offset = (clst + clst/2);
+
+        rc = block_get(&b, devmap_handle, RSCNT(bs) + SF(bs) * fatno +
+                       offset / BPS(bs), BLOCK_FLAGS_NONE);
+        if (rc != EOK)
+                return rc;
+
+        /* This cluster access spans a sector boundary. Check only for FAT12 */
+        if (FATTYPE(bs) == 12 && (offset % BPS(bs)+1 == BPS(bs))) {
+            /* Is it last sector of FAT? */
+            if (offset / BPS(bs) < SF(bs)) { /* NO */
+                /* Reading next sector */
+                rc = block_get(&b1, devmap_handle, 1+RSCNT(bs)+SF(bs)*fatno +
+                               offset / BPS(bs), BLOCK_FLAGS_NONE);
+                if (rc != EOK) {
+                    block_put(b);
+                    return rc;
+                }
+                /*
+                 * Combining value with last byte of current sector and
+                 * first byte of next sector
+                 */
+                *value  = *(uint8_t *)(b->data + BPS(bs) - 1);
+                *value |= *(uint8_t *)(b1->data);
+
+                rc = block_put(b1);
+                if (rc != EOK) {
+                    block_put(b);
+                    return rc;
+                }
+            }
+            else {      /* YES */
+                block_put(b);
+                return ERANGE;
+            }
         }
         else
-        {
-            fsec = (clst + clst/2) / BPS(bs);
-            fidx = clst % (2 * BPS(bs) / 3 );
-        }
-
-        rc = block_get(&b, devmap_handle, RSCNT(bs) + SF(bs) * fatno +
-                       fsec, BLOCK_FLAGS_NONE);
-        if (rc != EOK)
-                return rc;
-
-        if (FATTYPE(bs) == 16)
-            cp = &((fat_cluster_t *)b->data)[fidx];
-        else
-            cp = (fat_cluster_t *)(b->data + fidx);
-
-        *value = *cp;
-
-        if (FATTYPE(bs) == 12)
-        {
+            *value = *(fat_cluster_t *)(b->data + offset % BPS(bs));
+
+        if (FATTYPE(bs) == 12) {
             if (clst & 0x0001)
                 *value = (*value) >> 4;
@@ -344,5 +354,5 @@
         *value = uint16_t_le2host(*value);
 	rc = block_put(b);
-	
+
 	return rc;
 }
@@ -362,47 +372,76 @@
     fat_cluster_t clst, fat_cluster_t value)
 {
-	block_t *b;
-	fat_cluster_t *cp;
-	int rc;
-        aoff64_t fsec;  /* sector offset relative to FAT */
-        unsigned fidx;  /* entry index */
+	block_t *b, *b1;
+        aoff64_t offset;
+        fat_cluster_t *cp, temp;
+	int rc;
+        int spans = 0;
 
         assert(fatno < FATCNT(bs));
 
         if (FATTYPE(bs) == 16)
-        {
-            fsec = (clst * sizeof(fat_cluster_t)) / BPS(bs);
-            fidx = clst % (BPS(bs) / sizeof(fat_cluster_t));
+            offset = (clst * sizeof(fat_cluster_t));
+        else
+            offset = (clst + clst/2);
+
+        rc = block_get(&b, devmap_handle, RSCNT(bs) + SF(bs) * fatno +
+                       offset / BPS(bs), BLOCK_FLAGS_NONE);
+	if (rc != EOK)
+		return rc;
+
+        /* This cluster access spans a sector boundary. Check only for FAT12 */
+        if (FATTYPE(bs) == 12 && (offset % BPS(bs)+1 == BPS(bs))) {
+            /* Is it last sector of FAT? */
+            if (offset / BPS(bs) < SF(bs)) { /* NO */
+                /* Reading next sector */
+                rc = block_get(&b1, devmap_handle, 1+RSCNT(bs)+SF(bs)*fatno +
+                               offset / BPS(bs), BLOCK_FLAGS_NONE);
+                if (rc != EOK) {
+                    block_put(b);
+                    return rc;
+                }
+                /*
+                 * Combining value with last byte of current sector and
+                 * first byte of next sector
+                 */
+                spans=1;
+                cp = &temp;
+                *cp  = *(uint8_t *)(b->data + BPS(bs) - 1);
+                *cp |= *(uint8_t *)(b1->data);
+            }
+            else {      /* YES */
+                block_put(b);
+                return ERANGE;
+            }
         }
         else
-        {
-            fsec = (clst + clst/2) / BPS(bs);
-            fidx = clst % (2 * BPS(bs) / 3 );
-        }
-
-        rc = block_get(&b, devmap_handle, RSCNT(bs) + SF(bs) * fatno +
-                       fsec, BLOCK_FLAGS_NONE);
-	if (rc != EOK)
-		return rc;
-
-        if (FATTYPE(bs) == 12)
-        {
-            cp = (fat_cluster_t *)(b->data + fidx);
-            if (clst & 0x0001)
+            cp = (fat_cluster_t *)(b->data + offset % BPS(bs));
+
+        value = host2uint16_t_le(value);
+        if (FATTYPE(bs) == 12) {
+            if (clst & 0x0001) {
+                *cp &= 0x000f;
+                *cp |= value << 4;
+            }
+            else {
+                *cp &= 0xf000;
+                *cp |= value & 0x0fff;
+            }
+
+            if (spans)
             {
-                *cp &= 0x000f;
-                *cp |= host2uint16_t_le(value) << 4;
-            }
-            else
-            {
-                *cp &= 0xf000;
-                *cp |= host2uint16_t_le(value) & 0x0fff;
+                *(uint8_t *)(b->data + BPS(bs) - 1) = cp[0];
+                *(uint8_t *)(b1->data) = cp[1];
+
+                b1->dirty = true;
+                rc = block_put(b1);
+                if (rc != EOK) {
+                    block_put(b);
+                    return rc;
+                }
             }
         }
         else
-        {
-            cp = &((fat_cluster_t *)b->data)[fidx];
-            *cp = host2uint16_t_le(value);
-        }
+            *cp = value;
 
         b->dirty = true;		/* need to sync block */
@@ -464,42 +503,21 @@
         fat_cluster_t *lifo;    /* stack for storing free cluster numbers */
         unsigned found = 0;     /* top of the free cluster number stack */
-        fat_cluster_t clst, max_clst, value;
+        fat_cluster_t clst, value;
         int rc = EOK;
         uint16_t clst_last1 = FATTYPE(bs) == 16 ? FAT16_CLST_LAST1 :
                                                   FAT12_CLST_LAST1;
 
-
         lifo = (fat_cluster_t *) malloc(nclsts * sizeof(fat_cluster_t));
         if (!lifo)
                 return ENOMEM;
-
         /*
          * Search FAT1 for unused clusters.
          */
-
-        if (FATTYPE(bs) == 16)
-            max_clst = SF(bs) * BPS(bs) / sizeof(fat_cluster_t);
-        else
-            max_clst = 2 *SF(bs) * BPS(bs) / 3;
-
         fibril_mutex_lock(&fat_alloc_lock);
-        for (clst=0; clst < max_clst && found < nclsts; clst++)
-        {
+        for (clst=FAT_CLST_FIRST; clst < CC(bs)+2 && found < nclsts; clst++) {
             rc = fat_get_cluster(bs, devmap_handle, FAT1, clst, &value);
             if (rc != EOK)
                 break;
-            /*
-            * Check if the entire cluster is physically there.
-            * This check becomes necessary when the file system is
-            * created with fewer total sectors than how many is
-            * inferred from the size of the file allocation table
-            * or when the last cluster ends beyond the end of the
-            * device.
-            */
-            if ((clst >= FAT_CLST_FIRST) &&
-                CLBN2PBN(bs, clst, SPC(bs) - 1) >= TS(bs)) {
-                    rc = EIO;
-                    break;
-            }
+
             if (value == FAT_CLST_RES0) {
                 /*
@@ -518,9 +536,7 @@
         }
 
-        if (rc == EOK && found == nclsts)
-        {
+        if (rc == EOK && found == nclsts) {
             rc = fat_alloc_shadow_clusters(bs, devmap_handle, lifo, nclsts);
-            if (rc == EOK)
-            {
+            if (rc == EOK) {
                 *mcl = lifo[found - 1];
                 *lcl = lifo[0];
@@ -532,6 +548,5 @@
 
         /* If something wrong - free the clusters */
-        if (found > 0)
-        {
+        if (found > 0) {
             while (found--) {
                 rc = fat_set_cluster(bs, devmap_handle, FAT1, lifo[found],
@@ -735,5 +750,5 @@
 
 	if (bs->totsec16 != 0 && bs->totsec32 != 0 &&
-	    bs->totsec16 != bs->totsec32) 
+	    bs->totsec16 != bs->totsec32)
 		return ENOTSUP;
 
@@ -775,8 +790,6 @@
 		 * set to one.
 		 */
-		/* Disabled for testing FAT12
-                if ((e0 >> 8) != 0xff || e1 != 0xffff)
+                if (FATTYPE(bs)!=12 && ((e0 >> 8) != 0xff || e1 != 0xffff))
 			return ENOTSUP;
-		*/
 	}
 
@@ -786,3 +799,3 @@
 /**
  * @}
- */ 
+ */
Index: uspace/srv/fs/fat/fat_fat.h
===================================================================
--- uspace/srv/fs/fat/fat_fat.h	(revision fc35e985a99af215aebc39389e5bfeeedc65fcfe)
+++ uspace/srv/fs/fat/fat_fat.h	(revision 97bc3ee99b9182a255fcba5caf3fc118a0f767c1)
@@ -29,5 +29,5 @@
 /** @addtogroup fs
  * @{
- */ 
+ */
 
 #ifndef FAT_FAT_FAT_H_
@@ -56,5 +56,14 @@
 #define FAT_CLST_ROOT		FAT_CLST_RES1
 
-#define FATTYPE(bs)      (bs)->reserved
+/*
+ * Convenience macros for computing some frequently used values from the
+ * primitive boot sector members.
+ */
+#define RDS(bs)         ((sizeof(fat_dentry_t) * RDE((bs))) / BPS((bs))) + \
+                        (((sizeof(fat_dentry_t) * RDE((bs))) % BPS((bs))) != 0)
+#define SSA(bs)         (RSCNT((bs)) + FATCNT((bs)) * SF((bs)) + RDS(bs))
+#define DS(bs)          (TS(bs) - SSA(bs))
+#define CC(bs)          (DS(bs) / SPC(bs))
+#define FATTYPE(bs)     (bs)->reserved
 
 /* forward declarations */
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision fc35e985a99af215aebc39389e5bfeeedc65fcfe)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 97bc3ee99b9182a255fcba5caf3fc118a0f767c1)
@@ -29,5 +29,5 @@
 /** @addtogroup fs
  * @{
- */ 
+ */
 
 /**
@@ -116,9 +116,9 @@
 	fat_dentry_t *d;
 	int rc;
-	
+
 	assert(node->dirty);
 
 	bs = block_bb_get(node->idx->devmap_handle);
-	
+
 	/* Read the block that contains the dentry of interest. */
 	rc = _fat_block_get(&b, bs, node->idx->devmap_handle, node->idx->pfc,
@@ -136,7 +136,7 @@
 		d->attr = FAT_ATTR_SUBDIR;
 	}
-	
+
 	/* TODO: update other fields? (e.g time fields) */
-	
+
 	b->dirty = true;		/* need to sync block */
 	rc = block_put(b);
@@ -255,5 +255,5 @@
 	fn->data = nodep;
 	nodep->bp = fn;
-	
+
 	*nodepp = nodep;
 	return EOK;
@@ -291,5 +291,5 @@
 	 * We must instantiate the node from the file system.
 	 */
-	
+
 	assert(idxp->pfc);
 
@@ -310,5 +310,5 @@
 	d = ((fat_dentry_t *)b->data) + (idxp->pdi % DPS(bs));
 	if (d->attr & FAT_ATTR_SUBDIR) {
-		/* 
+		/*
 		 * The only directory which does not have this bit set is the
 		 * root directory itself. The root directory node is handled
@@ -316,5 +316,6 @@
 		 */
 		nodep->type = FAT_DIRECTORY;
-		/*
+
+                /*
 		 * Unfortunately, the 'size' field of the FAT dentry is not
 		 * defined for the directory entry type. We must determine the
@@ -334,5 +335,6 @@
 		nodep->size = uint32_t_le2host(d->size);
 	}
-	nodep->firstc = uint16_t_le2host(d->firstc);
+
+        nodep->firstc = uint16_t_le2host(d->firstc);
 	nodep->lnkcnt = 1;
 	nodep->refcnt = 1;
@@ -383,5 +385,5 @@
 		if (rc != EOK)
 			return rc;
-		for (j = 0; j < DPS(bs); j++) { 
+		for (j = 0; j < DPS(bs); j++) {
 			d = ((fat_dentry_t *)b->data) + j;
 			switch (fat_classify_dentry(d)) {
@@ -521,5 +523,5 @@
 	rc = fat_idx_get_new(&idxp, devmap_handle);
 	if (rc != EOK) {
-		(void) fat_free_clusters(bs, devmap_handle, mcl);	
+		(void) fat_free_clusters(bs, devmap_handle, mcl);
 		(void) fat_node_put(FS_NODE(nodep));
 		return rc;
@@ -618,5 +620,5 @@
 	 * a new one.
 	 */
-	
+
 	fibril_mutex_lock(&parentp->idx->lock);
 	bs = block_bb_get(parentp->idx->devmap_handle);
@@ -650,5 +652,5 @@
 	}
 	j = 0;
-	
+
 	/*
 	 * We need to grow the parent in order to create a new unused dentry.
@@ -697,9 +699,9 @@
 	rc = block_put(b);
 	fibril_mutex_unlock(&parentp->idx->lock);
-	if (rc != EOK) 
+	if (rc != EOK)
 		return rc;
 
 	fibril_mutex_lock(&childp->idx->lock);
-	
+
 	if (childp->type == FAT_DIRECTORY) {
 		/*
@@ -778,5 +780,5 @@
 	if (!parentp)
 		return EBUSY;
-	
+
 	rc = fat_has_children(&has_children, cfn);
 	if (rc != EOK)
@@ -794,5 +796,5 @@
 	    NULL, (childp->idx->pdi * sizeof(fat_dentry_t)) / BPS(bs),
 	    BLOCK_FLAGS_NONE);
-	if (rc != EOK) 
+	if (rc != EOK)
 		goto error;
 	d = (fat_dentry_t *)b->data +
@@ -839,5 +841,5 @@
 		return EOK;
 	}
-	
+
 	fibril_mutex_lock(&nodep->idx->lock);
 	bs = block_bb_get(nodep->idx->devmap_handle);
@@ -847,5 +849,5 @@
 	for (i = 0; i < blocks; i++) {
 		fat_dentry_t *d;
-	
+
 		rc = fat_block_get(&b, bs, nodep, i, BLOCK_FLAGS_NONE);
 		if (rc != EOK) {
@@ -875,5 +877,5 @@
 		if (rc != EOK) {
 			fibril_mutex_unlock(&nodep->idx->lock);
-			return rc;	
+			return rc;
 		}
 	}
@@ -945,10 +947,4 @@
  */
 
-
-#define RootDirSectors(bs)      (((RDE(bs)*32) + (BPS(bs)-1)) / BPS(bs))
-#define FATSz(bs)               SF(bs) != 0 ? SF(bs) : uint32_t_le2host((bs)->fat32.sectors_per_fat)
-#define DataSec(bs)             (TS(bs) - (RSCNT(bs) + (FATCNT(bs) * FATSz(bs)) + RootDirSectors(bs)))
-#define CountOfClusters(bs)     (DataSec(bs) / SPC(bs))
-
 void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
 {
@@ -956,9 +952,9 @@
 	enum cache_mode cmode;
 	fat_bs_t *bs;
-	
+
 	/* Accept the mount options */
 	char *opts;
 	int rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
-	
+
 	if (rc != EOK) {
 		async_answer_0(rid, rc);
@@ -991,5 +987,5 @@
 	/* get the buffer with the boot sector */
 	bs = block_bb_get(devmap_handle);
-	
+
 	if (BPS(bs) != BS_SIZE) {
 		block_fini(devmap_handle);
@@ -1007,9 +1003,9 @@
 
         /* Storing FAT type (12, 16, 32) in reserved field (bs->reserved) */
-        if (CountOfClusters(bs) < 4085) {
+        if (CC(bs) < 4085) {
         /* Volume is FAT12 */
             printf("Found FAT12 filesystem\n");
             (bs)->reserved = 12;
-        } else if (CountOfClusters(bs) < 65525) {
+        } else if (CC(bs) < 65525) {
         /* Volume is FAT16 */
             printf("Found FAT16 filesystem\n");
@@ -1017,5 +1013,5 @@
         } else {
         /* Volume is FAT32 */
-            printf("FAT32 is not supported by FAT driver. Sorry\n");
+            printf("FAT32 filesystem is not supported by FAT server. Sorry.\n");
             block_fini(devmap_handle);
             async_answer_0(rid, ENOTSUP);
@@ -1085,5 +1081,5 @@
 	rootp->bp = rfn;
 	rfn->data = rootp;
-	
+
 	fibril_mutex_unlock(&ridxp->lock);
 
@@ -1119,5 +1115,5 @@
 		return;
 	}
-	
+
 	/*
 	 * Put the root node and force it to the FAT free node list.
@@ -1300,5 +1296,5 @@
 	int flags = BLOCK_FLAGS_NONE;
 	int rc;
-	
+
 	rc = fat_node_get(&fn, devmap_handle, index);
 	if (rc != EOK) {
@@ -1311,5 +1307,5 @@
 	}
 	nodep = FAT_NODE(fn);
-	
+
 	ipc_callid_t callid;
 	size_t len;
@@ -1328,10 +1324,10 @@
 	 * but this one greatly simplifies fat_write(). Note that we can afford
 	 * to do this because the client must be ready to handle the return
-	 * value signalizing a smaller number of bytes written. 
-	 */ 
+	 * value signalizing a smaller number of bytes written.
+	 */
 	bytes = min(len, BPS(bs) - pos % BPS(bs));
 	if (bytes == BPS(bs))
 		flags |= BLOCK_FLAGS_NOREAD;
-	
+
 	boundary = ROUND_UP(nodep->size, BPC(bs));
 	if (pos < boundary) {
@@ -1379,6 +1375,6 @@
 		 */
 		unsigned nclsts;
-		fat_cluster_t mcl, lcl; 
- 
+		fat_cluster_t mcl, lcl;
+
 		nclsts = (ROUND_UP(pos + bytes, BPC(bs)) - boundary) / BPC(bs);
 		/* create an independent chain of nclsts clusters in all FATs */
@@ -1476,5 +1472,5 @@
 		nodep->size = size;
 		nodep->dirty = true;		/* need to sync node */
-		rc = EOK;	
+		rc = EOK;
 	} else {
 		/*
@@ -1497,5 +1493,5 @@
 		nodep->size = size;
 		nodep->dirty = true;		/* need to sync node */
-		rc = EOK;	
+		rc = EOK;
 	}
 out:
@@ -1553,5 +1549,5 @@
 	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
 	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	
+
 	fs_node_t *fn;
 	int rc = fat_node_get(&fn, devmap_handle, index);
@@ -1564,10 +1560,10 @@
 		return;
 	}
-	
+
 	fat_node_t *nodep = FAT_NODE(fn);
-	
+
 	nodep->dirty = true;
 	rc = fat_node_sync(nodep);
-	
+
 	fat_node_put(fn);
 	async_answer_0(rid, rc);
