Index: partition.h
===================================================================
--- partition.h	(.../sd-reader_release_20060319)	(Revision 106)
+++ partition.h	(.../sd-reader_release_20060808)	(Revision 106)
@@ -52,6 +52,10 @@
  * The partition is an extended partition with LBA.
  */
 #define PARTITION_TYPE_EXTENDED_LBA 0x0f
+/**
+ * The partition has an unknown type.
+ */
+#define PARTITION_TYPE_UNKNOWN 0xff
 
 /**
  * A function pointer used to read from the partition.
@@ -141,7 +145,7 @@
     uint32_t length;
 };
 
-struct partition_struct* partition_open(device_read_t device_read, device_read_interval_t device_read_interval, device_write_t device_write, uint8_t index);
+struct partition_struct* partition_open(device_read_t device_read, device_read_interval_t device_read_interval, device_write_t device_write, int8_t index);
 uint8_t partition_close(struct partition_struct* partition);
 
 /**
Index: sd_raw.c
===================================================================
--- sd_raw.c	(.../sd-reader_release_20060319)	(Revision 106)
+++ sd_raw.c	(.../sd-reader_release_20060808)	(Revision 106)
@@ -1,5 +1,6 @@
 
 #include <avr/io.h>
+
 #include "sd_raw.h"
 
 #if !SD_RAW_SAVE_RAM
@@ -132,6 +133,10 @@
 static uint8_t raw_block[512];
 /* offset where the data within raw_block lies on the card */
 static uint32_t raw_block_address;
+#if SD_RAW_WRITE_BUFFERING
+/* flag to remember if raw_block was written to the card */
+static uint8_t raw_block_written;
+#endif
 
 #endif
 
@@ -158,24 +163,27 @@
     configure_pin_sck();
     configure_pin_ss();
     configure_pin_miso();
+
     unselect_card();
 
-    SPCR |= (0 << SPIE) | /* SPI Interrupt Enable */
-            (1 << SPE)  | /* SPI Enable */
-            (0 << DORD) | /* Data Order: MSB first */
-            (1 << MSTR) | /* Master mode */
-            (0 << CPOL) | /* Clock Polarity: SCK low when idle */
-            (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
-            (1 << SPR1) | /* Clock Frequency: f_OSC / 64 */
-            (0 << SPR0);
+    /* initialize SPI with lowest frequency; max. 400kHz during identification mode of card */
+    SPCR = (0 << SPIE) | /* SPI Interrupt Enable */
+           (1 << SPE)  | /* SPI Enable */
+           (0 << DORD) | /* Data Order: MSB first */
+           (1 << MSTR) | /* Master mode */
+           (0 << CPOL) | /* Clock Polarity: SCK low when idle */
+           (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
+           (1 << SPR1) | /* Clock Frequency: f_OSC / 128 */
+           (1 << SPR0);
+    SPSR &= ~(1 << SPI2X); /* No doubled clock frequency */
 
     /* initialization procedure */
     
     if(!sd_raw_available())
         return 0;
 
-    /* the card needs 74 cycles minimum to start up */
-    for(int i = 0; i < 10; ++i)
+    /* card needs 74 cycles minimum to start up */
+    for(uint8_t i = 0; i < 10; ++i)
     {
         /* wait 8 clock cycles */
         sd_raw_rec_byte();
@@ -185,15 +193,32 @@
     select_card();
 
     /* reset card */
-    sd_raw_send_command_r1(CMD_GO_IDLE_STATE, 0);
+    uint8_t response;
+    for(uint16_t i = 0; ; ++i)
+    {
+        response = sd_raw_send_command_r1(CMD_GO_IDLE_STATE, 0);
+        if(response == (1 << R1_IDLE_STATE))
+            break;
+
+        if(i == 0x1ff)
+        {
+            unselect_card();
+            return 0;
+        }
+    }
     
     /* wait for card to get ready */
-    uint8_t response;
-    for(int i = 0; i < 10; ++i)
+    for(uint16_t i = 0; ; ++i)
     {
         response = sd_raw_send_command_r1(CMD_SEND_OP_COND, 0);
         if(!(response & (1 << R1_IDLE_STATE)))
             break;
+
+        if(i == 0x7fff)
+        {
+            unselect_card();
+            return 0;
+        }
     }
 
     /* set block size to 512 bytes */
@@ -206,9 +231,16 @@
     /* deaddress card */
     unselect_card();
 
+    /* switch to highest SPI frequency possible */
+    SPCR &= ~((1 << SPR1) | (1 << SPR0)); /* Clock Frequency: f_OSC / 4 */
+    SPSR |= (1 << SPI2X); /* Doubled Clock Frequency: f_OSC / 2 */
+
 #if !SD_RAW_SAVE_RAM
     /* the first block is likely to be accessed first, so precache it here */
     raw_block_address = 0xffffffff;
+#if SD_RAW_WRITE_BUFFERING
+    raw_block_written = 1;
+#endif
     if(!sd_raw_read(0, raw_block, sizeof(raw_block)))
         return 0;
 #endif
@@ -294,16 +326,13 @@
     sd_raw_send_byte(command == CMD_GO_IDLE_STATE ? 0x95 : 0xff);
     
     /* receive response */
-    for(int i = 0; i < 10; ++i)
+    for(uint8_t i = 0; i < 10; ++i)
     {
         response = sd_raw_rec_byte();
         if(response != 0xff)
             break;
     }
 
-    /* the card internally needs eight further clock cycles */
-    sd_raw_rec_byte();
-
     return response;
 }
 
@@ -331,7 +360,7 @@
     sd_raw_send_byte(command == CMD_GO_IDLE_STATE ? 0x95 : 0xff);
     
     /* receive response */
-    for(int i = 0; i < 10; ++i)
+    for(uint8_t i = 0; i < 10; ++i)
     {
         response = sd_raw_rec_byte();
         if(response != 0xff)
@@ -340,9 +369,6 @@
     response <<= 8;
     response |= sd_raw_rec_byte();
 
-    /* the card internally needs eight further clock cycles */
-    sd_raw_rec_byte();
-
     return response;
 }
 
@@ -358,9 +384,6 @@
  */
 uint8_t sd_raw_read(uint32_t offset, uint8_t* buffer, uint16_t length)
 {
-    /* address card */
-    select_card();
-
     uint32_t block_address;
     uint16_t block_offset;
     uint16_t read_length;
@@ -378,6 +401,17 @@
         if(block_address != raw_block_address)
 #endif
         {
+#if SD_RAW_WRITE_BUFFERING
+            if(!raw_block_written)
+            {
+                if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block)))
+                    return 0;
+            }
+#endif
+
+            /* address card */
+            select_card();
+
             /* send single block request */
             if(sd_raw_send_command_r1(CMD_READ_SINGLE_BLOCK, block_address))
             {
@@ -411,6 +445,12 @@
             /* read crc16 */
             sd_raw_rec_byte();
             sd_raw_rec_byte();
+            
+            /* deaddress card */
+            unselect_card();
+
+            /* let card some time to finish */
+            sd_raw_rec_byte();
         }
 #if !SD_RAW_SAVE_RAM
         else
@@ -423,13 +463,7 @@
         length -= read_length;
         offset += read_length;
     }
-    
-    /* deaddress card */
-    unselect_card();
 
-    /* let card some time to finish */
-    sd_raw_rec_byte();
-
     return 1;
 }
 
@@ -555,6 +589,10 @@
  * \ingroup sd_raw
  * Writes raw data to the card.
  *
+ * \note If write buffering is enabled, you might have to
+ *       call sd_raw_sync() before disconnecting the card
+ *       to ensure all remaining data has been written.
+ *
  * \param[in] offset The offset where to start writing.
  * \param[in] buffer The buffer containing the data to be written.
  * \param[in] length The number of bytes to write.
@@ -573,10 +611,10 @@
     uint16_t write_length;
     while(length > 0)
     {
-        /* determine byte count to read at once */
+        /* determine byte count to write at once */
         block_address = offset & 0xfffffe00;
         block_offset = offset & 0x01ff;
-        write_length = 512 - block_offset; /* read up to block border */
+        write_length = 512 - block_offset; /* write up to block border */
         if(write_length > length)
             write_length = length;
         
@@ -585,15 +623,34 @@
          */
         if(block_address != raw_block_address)
         {
+#if SD_RAW_WRITE_BUFFERING
+            if(!raw_block_written)
+            {
+                if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block)))
+                    return 0;
+            }
+#endif
+
             if(block_offset || write_length < 512)
             {
                 if(!sd_raw_read(block_address, raw_block, sizeof(raw_block)))
                     return 0;
             }
+            raw_block_address = block_address;
         }
-        raw_block_address = block_address;
-        
-        memcpy(raw_block + block_offset, buffer, write_length);
+
+        if(buffer != raw_block)
+        {
+            memcpy(raw_block + block_offset, buffer, write_length);
+
+#if SD_RAW_WRITE_BUFFERING
+            raw_block_written = 0;
+
+            if(length == write_length)
+                return 1;
+#endif
+        }
+
         buffer += write_length;
 
         /* address card */
@@ -627,6 +684,10 @@
 
         length -= write_length;
         offset += write_length;
+
+#if SD_RAW_WRITE_BUFFERING
+        raw_block_written = 1;
+#endif
     }
     
     return 1;
@@ -635,3 +696,30 @@
 #endif
 }
 
+/**
+ * \ingroup sd_raw
+ * Writes the write buffer's content to the card.
+ *
+ * \note When write buffering is enabled, you should
+ *       call this function before disconnecting the
+ *       card to ensure all remaining data has been
+ *       written.
+ *
+ * \returns 0 on failure, 1 on success.
+ * \see sd_raw_write
+ */
+uint8_t sd_raw_sync()
+{
+#if SD_RAW_WRITE_SUPPORT
+#if SD_RAW_WRITE_BUFFERING
+    if(raw_block_written)
+        return 1;
+    if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block)))
+        return 0;
+#endif
+    return 1;
+#else
+    return 0;
+#endif
+}
+
Index: fat16.c
===================================================================
--- fat16.c	(.../sd-reader_release_20060319)	(Revision 106)
+++ fat16.c	(.../sd-reader_release_20060808)	(Revision 106)
@@ -5,6 +5,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <avr/pgmspace.h>
 
 /**
  * \addtogroup fat16 FAT16 support
@@ -164,9 +165,9 @@
 static uint8_t fat16_dir_entry_read_callback(uint8_t* buffer, uint32_t offset, void* p);
 static uint8_t fat16_interpret_dir_entry(struct fat16_dir_entry_struct* dir_entry, const uint8_t* raw_entry);
 static uint16_t fat16_get_next_cluster(const struct fat16_fs_struct* fs, uint16_t cluster_num);
-static uint16_t fat16_append_cluster(const struct fat16_fs_struct* fs, uint16_t cluster_num);
-static uint8_t fat16_free_cluster(struct fat16_fs_struct* fs, uint16_t cluster_num);
-static uint8_t fat16_write_dir_entry(struct fat16_fs_struct* fs, const struct fat16_dir_entry_struct* dir_entry);
+static uint16_t fat16_append_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num, uint16_t count);
+static uint8_t fat16_free_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num);
+static uint8_t fat16_write_dir_entry(const struct fat16_fs_struct* fs, const struct fat16_dir_entry_struct* dir_entry);
 
 /**
  * \ingroup fat16_fs
@@ -239,11 +240,21 @@
     partition = fs->partition;
     header = &fs->header;
     
-    if(partition->type != PARTITION_TYPE_FAT16 &&
-       partition->type != PARTITION_TYPE_FAT16_LBA)
+    uint32_t partition_offset = partition->offset * 512;
+
+    /* ensure we really have a FAT16 fs here */
+    memset(buffer, 0, sizeof(buffer));
+
+    if(!partition->device_read(partition_offset + 0x36, buffer, 8) ||
+       !partition->device_read(partition_offset + 0x52, buffer + 9, 8))
         return 0;
+    if(strcmp_P((char*) buffer, PSTR("FAT16   ")) &&
+       strcmp_P((char*) buffer + 9, PSTR("FAT16   ")))
+        return 0;
 
-    uint32_t partition_offset = partition->offset * 512;
+    partition->type = PARTITION_TYPE_FAT16;
+
+    /* read fat parameters */
     if(!partition->device_read(partition_offset + 0x0b, buffer, sizeof(buffer)))
         return 0;
 
@@ -410,8 +421,8 @@
 {
     struct fat16_read_callback_arg* arg = p;
 
-    /* skip deleted entries */
-    if(buffer[0] == FAT16_DIRENTRY_DELETED)
+    /* skip deleted or empty entries */
+    if(buffer[0] == FAT16_DIRENTRY_DELETED || !buffer[0])
         return 1;
 
     if(arg->entry_cur == arg->entry_num)
@@ -438,8 +449,8 @@
 {
     struct fat16_dir_entry_struct* dir_entry = p;
 
-    /* there should not be any deleted entries */
-    if(buffer[0] == FAT16_DIRENTRY_DELETED)
+    /* there should not be any deleted or empty entries */
+    if(buffer[0] == FAT16_DIRENTRY_DELETED || !buffer[0])
         return 0;
 
     if(!dir_entry->entry_offset)
@@ -661,61 +672,85 @@
 
 /**
  * \ingroup fat16_fs
- * Appends a cluster to an existing cluster chain.
+ * Appends a new cluster chain to an existing one.
  *
- * Set cluster_num to zero to allocate the first cluster
- * within the chain.
+ * Set cluster_num to zero to create a completely new one.
  *
  * \param[in] fs The file system on which to operate.
- * \param[in] cluster_num The cluster to which to append a free one.
- * \returns 0 on failure, the number of the new cluster on success.
+ * \param[in] cluster_num The cluster to which to append the new chain.
+ * \param[in] count The number of clusters to allocate.
+ * \returns 0 on failure, the number of the first new cluster on success.
  */
-uint16_t fat16_append_cluster(const struct fat16_fs_struct* fs, uint16_t cluster_num)
+uint16_t fat16_append_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num, uint16_t count)
 {
 #if FAT16_WRITE_SUPPORT
     if(!fs)
         return 0;
-    
-    uint32_t fat_offset_from = fs->header.fat_offset;
-    uint32_t fat_offset_to = fat_offset_from + fs->header.fat_size;
-    uint32_t fat_offset = fat_offset_from;
+
     device_read_t device_read = fs->partition->device_read;
     device_write_t device_write = fs->partition->device_write;
-    uint16_t cluster_new = 0;
+    uint32_t fat_offset = fs->header.fat_offset;
+    uint16_t cluster_max = fs->header.fat_size / 2;
+    uint16_t cluster_next = 0;
+    uint16_t count_left = count;
     uint8_t buffer[2];
 
-    while(1)
+    for(uint16_t cluster_new = 0; cluster_new < cluster_max; ++cluster_new)
     {
-        if(!device_read(fat_offset, buffer, sizeof(buffer)))
+        if(!device_read(fat_offset + 2 * cluster_new, buffer, sizeof(buffer)))
             return 0;
 
         /* check if this is a free cluster */
         if(buffer[0] == (FAT16_CLUSTER_FREE & 0xff) &&
            buffer[1] == ((FAT16_CLUSTER_FREE >> 8) & 0xff))
-            break;
+        {
+            /* allocate cluster */
+            if(count_left == count)
+            {
+                buffer[0] = FAT16_CLUSTER_LAST_MAX & 0xff;
+                buffer[1] = (FAT16_CLUSTER_LAST_MAX >> 8) & 0xff;
+            }
+            else
+            {
+                buffer[0] = cluster_next & 0xff;
+                buffer[1] = (cluster_next >> 8) & 0xff;
+            }
 
-        ++cluster_new;
-        fat_offset += sizeof(buffer);
-        
-        /* abort if we reached the end of the fat */
-        if(fat_offset >= fat_offset_to)
-            return 0;
+            if(!device_write(fat_offset + 2 * cluster_new, buffer, sizeof(buffer)))
+                return 0;
+
+            cluster_next = cluster_new;
+            if(--count_left == 0)
+                break;
+        }
     }
 
-    buffer[0] = FAT16_CLUSTER_LAST_MAX & 0xff;
-    buffer[1] = (FAT16_CLUSTER_LAST_MAX >> 8) & 0xff;
-    if(!device_write(fat_offset_from + 2 * cluster_new, buffer, sizeof(buffer)))
-        return 0;
-    
-    if(cluster_num >= 2)
+    do
     {
-        buffer[0] = cluster_new & 0xff;
-        buffer[1] = (cluster_new >> 8) & 0xff;
-        device_write(fat_offset_from + 2 * cluster_num, buffer, sizeof(buffer));
-    }
+        if(count_left > 0)
+            break;
 
-    return cluster_new;
-    
+        /* We allocated a new cluster chain. Now join
+         * it with the existing one.
+         */
+        if(cluster_num >= 2)
+        {
+            buffer[0] = cluster_next & 0xff;
+            buffer[1] = (cluster_next >> 8) & 0xff;
+            if(!device_write(fat_offset + 2 * cluster_num, buffer, sizeof(buffer)))
+                break;
+        }
+
+        return cluster_next;
+
+    } while(0);
+
+    /* No space left on device or writing error.
+     * Free up all clusters already allocated.
+     */
+    fat16_free_clusters(fs, cluster_next);
+
+    return 0;
 #else
     return 0;
 #endif
@@ -723,16 +758,21 @@
 
 /**
  * \ingroup fat16_fs
- * Frees a cluster.
+ * Frees a cluster chain, or a part thereof.
  *
- * Marks the specified cluster as free. It may then again be
- * used for future file allocations.
+ * Marks the specified cluster and all clusters which are sequentially
+ * referenced by it as free. They may then be used again for future
+ * file allocations.
  *
+ * \note If this function is used for freeing just a part of a cluster
+ *       chain, the new end of the chain is not correctly terminated
+ *       within the FAT. This has to be done manually afterwards.
+ *
  * \param[in] fs The filesystem on which to operate.
- * \param[in] cluster_num The cluster which to free.
+ * \param[in] cluster_num The starting cluster of the chain which to free.
  * \returns 0 on failure, 1 on success.
  */
-uint8_t fat16_free_cluster(struct fat16_fs_struct* fs, uint16_t cluster_num)
+uint8_t fat16_free_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num)
 {
 #if FAT16_WRITE_SUPPORT
     if(!fs || cluster_num < 2)
@@ -740,12 +780,36 @@
 
     uint32_t fat_offset = fs->header.fat_offset;
     uint8_t buffer[2];
-    
-    buffer[0] = FAT16_CLUSTER_FREE & 0xff;
-    buffer[1] = (FAT16_CLUSTER_FREE >> 8) & 0xff;
+    while(cluster_num)
+    {
+        if(!fs->partition->device_read(fat_offset + 2 * cluster_num, buffer, 2))
+            return 0;
 
-    return fs->partition->device_write(fat_offset + 2 * cluster_num, buffer, 2);
+        /* get next cluster of current cluster before freeing current cluster */
+        uint16_t cluster_num_next = ((uint16_t) buffer[0]) |
+                                    ((uint16_t) buffer[1] << 8);
 
+        if(cluster_num_next == FAT16_CLUSTER_FREE)
+            return 1;
+        if(cluster_num_next == FAT16_CLUSTER_BAD ||
+           (cluster_num_next >= FAT16_CLUSTER_RESERVED_MIN &&
+            cluster_num_next <= FAT16_CLUSTER_RESERVED_MAX
+           )
+          )
+            return 0;
+        if(cluster_num_next >= FAT16_CLUSTER_LAST_MIN && cluster_num_next <= FAT16_CLUSTER_LAST_MAX)
+            cluster_num_next = 0;
+
+        /* free cluster */
+        buffer[0] = FAT16_CLUSTER_FREE & 0xff;
+        buffer[1] = (FAT16_CLUSTER_FREE >> 8) & 0xff;
+        if(!fs->partition->device_write(fat_offset + 2 * cluster_num, buffer, 2))
+            return 0;
+
+        cluster_num = cluster_num_next;
+    }
+
+    return 1;
 #else
     return 0;
 #endif
@@ -921,7 +985,7 @@
             if(!fd->pos)
             {
                 /* empty file */
-                fd->dir_entry.cluster = cluster_num = fat16_append_cluster(fd->fs, 0);
+                fd->dir_entry.cluster = cluster_num = fat16_append_clusters(fd->fs, 0, 1);
                 if(!cluster_num)
                     return -1;
             }
@@ -941,7 +1005,7 @@
                 cluster_num_next = fat16_get_next_cluster(fd->fs, cluster_num);
                 if(!cluster_num_next && pos == 0)
                     /* the file exactly ends on a cluster boundary, and we append to it */
-                    cluster_num_next = fat16_append_cluster(fd->fs, cluster_num);
+                    cluster_num_next = fat16_append_clusters(fd->fs, cluster_num, 1);
                 if(!cluster_num_next)
                     return -1;
 
@@ -975,7 +1039,7 @@
             uint16_t cluster_num_next = fat16_get_next_cluster(fd->fs, cluster_num);
             if(!cluster_num_next && buffer_left > 0)
                 /* we reached the last cluster, append a new one */
-                cluster_num_next = fat16_append_cluster(fd->fs, cluster_num);
+                cluster_num_next = fat16_append_clusters(fd->fs, cluster_num, 1);
             if(!cluster_num_next)
             {
                 fd->pos_cluster = 0;
@@ -1082,8 +1146,12 @@
  *
  * If the file is truncated, all bytes having an equal or larger offset
  * than the given size are lost. If the file is expanded, the additional
- * bytes are allocated, but they keep their values.
+ * bytes are allocated.
  *
+ * \note Please be aware that this function just allocates or deallocates disk
+ * space, it does not explicitely clear it. To avoid data leakage, this
+ * must be done manually.
+ *
  * \param[in] fd The file decriptor of the file which to resize.
  * \param[in] size The new size of the file.
  * \returns 0 on failure, 1 on success.
@@ -1097,88 +1165,77 @@
     uint16_t cluster_size = fd->fs->header.cluster_size;
     uint32_t size_new = size;
 
-    if(fd->dir_entry.file_size < size)
+    do
     {
-        /* check if the file owns a cluster */
-        if(cluster_num == 0)
+        if(cluster_num == 0 && size_new == 0)
+            /* the file stays empty */
+            break;
+
+        /* seek to the next cluster as long as we need the space */
+        while(size_new > 0)
         {
-            /* allocate first cluster */
-            if(!(cluster_num = fat16_append_cluster(fd->fs, cluster_num)))
-                return 0;
-            fd->dir_entry.cluster = cluster_num;
-        }
-        else
-        {
-            /* get last cluster of file */
-            uint16_t cluster_num_next;
-            while((cluster_num_next = fat16_get_next_cluster(fd->fs, cluster_num)))
+            /* get next cluster of file */
+            uint16_t cluster_num_next = fat16_get_next_cluster(fd->fs, cluster_num);
+            if(cluster_num_next)
             {
                 cluster_num = cluster_num_next;
-                size_new -= cluster_size;
-            }
-        }
 
-        /* append new clusters as needed */
-        if(size_new > cluster_size)
-        {
-            while(1)
-            {
-                if(!(cluster_num = fat16_append_cluster(fd->fs, cluster_num)))
-                    return 0;
-
                 if(size_new <= cluster_size)
+                {
+                    /* file will shrink; get the first cluster to deallocate */
+                    cluster_num = fat16_get_next_cluster(fd->fs, cluster_num);
+                    size_new = 0;
                     break;
+                }
 
                 size_new -= cluster_size;
             }
+            else
+            {
+                break;
+            }
         }
 
-        /* write new directory entry */
-        fd->dir_entry.file_size = size;
-        if(!fat16_write_dir_entry(fd->fs, &fd->dir_entry))
-            return 0;
-    }
-    else if(fd->dir_entry.file_size > size)
-    {
-        /* write new directory entry */
-        fd->dir_entry.file_size = size;
-        if(size == 0)
-            fd->dir_entry.cluster = 0;
-        if(!fat16_write_dir_entry(fd->fs, &fd->dir_entry))
-            return 0;
-        
-        /* get cluster where the file is cut off */
-        while(size_new > cluster_size)
+        if(size_new == 0)
         {
-            if(!(cluster_num = fat16_get_next_cluster(fd->fs, cluster_num)))
+            /* free all clusters no longer needed */
+            fat16_free_clusters(fd->fs, cluster_num);
+        }
+        else
+        {
+            /* Allocate new cluster chain and append
+             * it to the existing one, if available.
+             */
+            uint16_t cluster_count = size_new / cluster_size;
+            if((uint32_t) cluster_count * cluster_size < size_new)
+                ++cluster_count;
+            uint16_t cluster_new_chain = fat16_append_clusters(fd->fs, cluster_num, cluster_count);
+            if(!cluster_new_chain)
                 return 0;
 
-            size_new -= cluster_size;
-        }
-
-        /* free all clusters no longer needed */
-        if(size == 0 || (cluster_num = fat16_get_next_cluster(fd->fs, cluster_num)))
-        { 
-            while(cluster_num)
+            if(!cluster_num)
             {
-                /* get next cluster before freeing the previous one */
-                uint16_t cluster_num_next = fat16_get_next_cluster(fd->fs, cluster_num);
-                
-                /* delete cluster */
-                fat16_free_cluster(fd->fs, cluster_num);
-
-                cluster_num = cluster_num_next;
+                cluster_num = cluster_new_chain;
+                fd->dir_entry.cluster = cluster_num;
             }
         }
 
-        /* correct file position */
-        if(size < fd->pos)
-        {
-            fd->pos = size;
-            fd->pos_cluster = 0;
-        }
+    } while(0);
+
+    /* correct file position */
+    if(size < fd->pos)
+    {
+        fd->pos = size;
+        fd->pos_cluster = 0;
     }
-    
+
+    /* write new directory entry */
+    fd->dir_entry.file_size = size;
+    if(size == 0)
+        fd->dir_entry.cluster = 0;
+    if(!fat16_write_dir_entry(fd->fs, &fd->dir_entry))
+        return 0;
+
     return 1;
 }
 
@@ -1302,7 +1359,7 @@
  * \param[in] dir_entry The directory entry to write.
  * \returns 0 on failure, 1 on success.
  */
-uint8_t fat16_write_dir_entry(struct fat16_fs_struct* fs, const struct fat16_dir_entry_struct* dir_entry)
+uint8_t fat16_write_dir_entry(const struct fat16_fs_struct* fs, const struct fat16_dir_entry_struct* dir_entry)
 {
 #if FAT16_WRITE_SUPPORT
     if(!fs || !dir_entry)
@@ -1468,9 +1525,7 @@
     }
 
     memset(dir_entry, 0, sizeof(*dir_entry));
-    
-    strncpy(dir_entry->long_name, file, sizeof(dir_entry->long_name));
-    dir_entry->long_name[sizeof(dir_entry->long_name)] = '\0';
+    strncpy(dir_entry->long_name, file, sizeof(dir_entry->long_name) - 1);
 
     /* search for a place where to write the directory entry to disk */
     uint8_t free_dir_entries_needed = strlen(file) / 13 + 1 + 1;
@@ -1508,13 +1563,17 @@
                 uint16_t cluster_next = fat16_get_next_cluster(fs, cluster_num);
                 if(!cluster_next)
                 {
-                    cluster_next = fat16_append_cluster(fs, cluster_num);
+                    cluster_next = fat16_append_clusters(fs, cluster_num, 1);
                     if(!cluster_next)
                         return 0;
 
                     /* we appended a new cluster and know it is free */
                     dir_entry_offset = fs->header.cluster_zero_offset +
                                        (uint32_t) (cluster_next - 2) * fs->header.cluster_size;
+
+                    /* TODO: This cluster has to be zeroed in an efficient way, or at least
+                     *       every 32th byte should be set to FAT16_DIRENTRY_DELETED.
+                     */
                     break;
                 }
                 cluster_num = cluster_next;
@@ -1535,17 +1594,6 @@
         /* check if we found a free directory entry */
         if(first_char == FAT16_DIRENTRY_DELETED || !first_char)
         {
-            if(!first_char)
-            {
-                /* Mark the directory entries as deleted.
-                 * This is needed if our new directory entry is
-                 * too large to fit into the current cluster.
-                 */
-                first_char = FAT16_DIRENTRY_DELETED;
-                if(!fs->partition->device_write(offset, &first_char, sizeof(first_char)))
-                    return 0;
-            }
-
             /* check if we have the needed number of available entries */
             ++free_dir_entries_found;
             if(free_dir_entries_found >= free_dir_entries_needed)
@@ -1623,18 +1671,7 @@
     /* We deleted the directory entry. The next thing to do is
      * marking all occupied clusters as free.
      */
-    uint16_t cluster_num = dir_entry->cluster;
-    uint16_t cluster_num_next;
-    while(cluster_num)
-    {
-        /* get next cluster before freeing the previous one */
-        cluster_num_next = fat16_get_next_cluster(fs, cluster_num);
-
-        /* free cluster */
-        fat16_free_cluster(fs, cluster_num);
-        
-        cluster_num = cluster_num_next;
-    }
+    fat16_free_clusters(fs, dir_entry->cluster);
     
     return 1;
 #else
Index: main.c
===================================================================
--- main.c	(.../sd-reader_release_20060319)	(Revision 106)
+++ main.c	(.../sd-reader_release_20060808)	(Revision 106)
@@ -7,8 +7,11 @@
 #include "fat16_config.h"
 #include "partition.h"
 #include "sd_raw.h"
+#include "sd_raw_config.h"
 #include "uart.h"
 
+#define DEBUG 1
+
 /**
  * \mainpage MMC/SD card example application
  *
@@ -59,27 +62,27 @@
  *     </tr>
  *     <tr>
  *         <td>MMC/SD (read-only)</td>
- *         <td align="right">1002</td>
+ *         <td align="right">1034</td>
  *         <td align="right">0</td>
  *     </tr>
  *     <tr>
  *         <td>MMC/SD (read-write)</td>
- *         <td align="right">1178</td>
- *         <td align="right">516</td>
+ *         <td align="right">1486</td>
+ *         <td align="right">517</td>
  *     </tr>
  *     <tr>
  *         <td>Partition</td>
- *         <td align="right">382</td>
+ *         <td align="right">408</td>
  *         <td align="right">0</td>
  *     </tr>
  *     <tr>
  *         <td>FAT16 (read-only)</td>
- *         <td align="right">3414</td>
+ *         <td align="right">3596</td>
  *         <td align="right">0</td>
  *     </tr>
  *     <tr>
  *         <td>FAT16 (read-write)</td>
- *         <td align="right">6412</td>
+ *         <td align="right">6628</td>
  *         <td align="right">0</td>
  *     </tr>
  * </table>
@@ -165,20 +168,47 @@
 
     /* setup sd card slot */
     if(!sd_raw_init())
+    {
+#if DEBUG
+        printf_P(PSTR("MMC/SD initialization failed\n"));
+#endif
         return 1;
+    }
 
     /* open first partition */
     struct partition_struct* partition = partition_open(sd_raw_read,
                                                         sd_raw_read_interval,
                                                         sd_raw_write,
                                                         0);
+
     if(!partition)
-        return 1;
+    {
+        /* If the partition did not open, assume the storage device
+         * is a "superfloppy", i.e. has no MBR.
+         */
+        partition = partition_open(sd_raw_read,
+                                   sd_raw_read_interval,
+                                   sd_raw_write,
+                                   -1
+                                  );
+        if(!partition)
+        {
+#if DEBUG
+            printf_P(PSTR("opening partition failed\n"));
+#endif
+            return 1;
+        }
+    }
 
     /* open file system */
     struct fat16_fs_struct* fs = fat16_open(partition);
     if(!fs)
+    {
+#if DEBUG
+        printf_P(PSTR("opening filesystem failed\n"));
+#endif
         return 1;
+    }
 
     /* open root directory */
     struct fat16_dir_entry_struct directory;
@@ -186,10 +216,15 @@
 
     struct fat16_dir_struct* dd = fat16_open_dir(fs, &directory);
     if(!dd)
+    {
+#if DEBUG
+        printf_P(PSTR("opening root directory failed\n"));
+#endif
         return 1;
+    }
     
     /* provide a simple shell */
-    char buffer[32];
+    char buffer[24];
     while(1)
     {
         /* print prompt */
@@ -198,12 +233,11 @@
 
         /* read command */
         char* command = buffer;
-        uint8_t command_len = read_line(command, sizeof(buffer));
-        if(command_len < 1)
+        if(read_line(command, sizeof(buffer)) < 1)
             continue;
 
         /* execute command */
-        if(strncmp("cd ", command, 3) == 0)
+        if(strncmp_P(command, PSTR("cd "), 3) == 0)
         {
             command += 3;
             if(command[0] == '\0')
@@ -224,7 +258,7 @@
 
             printf_P(PSTR("directory not found: %s\n"), command);
         }
-        else if(strcmp("ls", command) == 0)
+        else if(strcmp_P(command, PSTR("ls")) == 0)
         {
             /* print directory listing */
             struct fat16_dir_entry_struct dir_entry;
@@ -237,7 +271,7 @@
                         );
             }
         }
-        else if(strncmp("cat ", command, 4) == 0)
+        else if(strncmp_P(command, PSTR("cat "), 4) == 0)
         {
             command += 4;
             if(command[0] == '\0')
@@ -273,7 +307,7 @@
             fat16_close_file(fd);
         }
 #if FAT16_WRITE_SUPPORT
-        else if(strncmp("rm ", command, 3) == 0)
+        else if(strncmp_P(command, PSTR("rm "), 3) == 0)
         {
             command += 3;
             if(command[0] == '\0')
@@ -288,7 +322,7 @@
 
             printf_P(PSTR("error deleting file: %s\n"), command);
         }
-        else if(strncmp("touch ", command, 6) == 0)
+        else if(strncmp_P(command, PSTR("touch "), 6) == 0)
         {
             command += 6;
             if(command[0] == '\0')
@@ -298,7 +332,7 @@
             if(!fat16_create_file(dd, command, &file_entry))
                 printf_P(PSTR("error creating file: %s\n"), command);
         }
-        else if(strncmp("write ", command, 6) == 0)
+        else if(strncmp_P(command, PSTR("write "), 6) == 0)
         {
             command += 6;
             if(command[0] == '\0')
@@ -331,8 +365,18 @@
 
             /* read text from the shell and write it to the file */
             uint8_t data_len;
-            while((data_len = read_line(buffer, sizeof(buffer))))
+            while(1)
             {
+                /* give a different prompt */
+                uart_putc('<');
+                uart_putc(' ');
+
+                /* read one line of text */
+                data_len = read_line(buffer, sizeof(buffer));
+                if(!data_len)
+                    break;
+
+                /* write text to file */
                 if(fat16_write_file(fd, (uint8_t*) buffer, data_len) != data_len)
                 {
                     printf_P(PSTR("error writing to file\n"));
@@ -343,6 +387,13 @@
             fat16_close_file(fd);
         }
 #endif
+#if SD_RAW_WRITE_BUFFERING
+        else if(strcmp_P(command, PSTR("sync")) == 0)
+        {
+            if(!sd_raw_sync())
+                printf_P(PSTR("error syncing disk\n"));
+        }
+#endif
         else
         {
             printf_P(PSTR("unknown command: %s\n"), command);
Index: sd_raw.h
===================================================================
--- sd_raw.h	(.../sd-reader_release_20060319)	(Revision 106)
+++ sd_raw.h	(.../sd-reader_release_20060808)	(Revision 106)
@@ -26,6 +26,7 @@
 uint8_t sd_raw_read(uint32_t offset, uint8_t* buffer, uint16_t length);
 uint8_t sd_raw_read_interval(uint32_t offset, uint8_t* buffer, uint16_t interval, uint16_t length, sd_raw_interval_handler callback, void* p);
 uint8_t sd_raw_write(uint32_t offset, const uint8_t* buffer, uint16_t length);
+uint8_t sd_raw_sync();
 
 /**
  * @}
Index: ChangeLog
===================================================================
--- ChangeLog	(.../sd-reader_release_20060319)	(Revision 0)
+++ ChangeLog	(.../sd-reader_release_20060808)	(Revision 106)
@@ -0,0 +1,24 @@
+
+2006-08-08 sd-reader
+	* Thanks go to Torsten Seeboth for his ongoing efforts
+	  to test changes, fix regressions and give suggestions.
+	  Many of the changes below were initiated by him.
+	* Much more reliable card initialization.
+	* Highly improved performance
+	  - optional write buffering
+	  - better cluster handling
+	  - remove unneeded SPI access when reading from buffered block
+	  - use highest spi frequency after card initialization
+	* Add superfloppy support.
+	* Better checks when opening a FAT16 filesystem.
+	* Provide SPI pin mappings for commonly used ATmegas.
+	* Fix resizing files, hangs could occur.
+	* Fix overflow when creating files with names longer than 31 characters.
+	* Fix numerous other small things.
+
+2006-03-19 sd-reader
+	* Fix speed regressions.
+
+2006-03-16 sd-reader
+	* Initial releaseA.
+
Index: partition.c
===================================================================
--- partition.c	(.../sd-reader_release_20060319)	(Revision 106)
+++ partition.c	(.../sd-reader_release_20060808)	(Revision 106)
@@ -30,10 +30,13 @@
  * \param[in] device_read_interval A function pointer which is used to read in constant intervals from the disk.
  * \param[in] device_write A function pointer which is used to write to the disk.
  * \param[in] index The index of the partition which should be opened, range 0 to 3.
+ *                  A negative value is allowed as well. In this case, the partition opened is
+ *                  not checked for existance, begins at offset zero, has a length of zero
+ *                  and is of an unknown type.
  * \returns 0 on failure, a partition descriptor on success.
  * \see partition_close
  */
-struct partition_struct* partition_open(device_read_t device_read, device_read_interval_t device_read_interval, device_write_t device_write, uint8_t index)
+struct partition_struct* partition_open(device_read_t device_read, device_read_interval_t device_read_interval, device_write_t device_write, int8_t index)
 {
     struct partition_struct* new_partition = 0;
     uint8_t buffer[0x10];
@@ -41,13 +44,16 @@
     if(!device_read || !device_read_interval || index >= 4)
         return 0;
 
-    /* read specified partition table index */
-    if(!device_read(0x01be + index * 0x10, buffer, sizeof(buffer)))
-        return 0;
+    if(index >= 0)
+    {
+        /* read specified partition table index */
+        if(!device_read(0x01be + index * 0x10, buffer, sizeof(buffer)))
+            return 0;
 
-    /* abort on empty partition entry */
-    if(buffer[4] == 0x00)
-        return 0;
+        /* abort on empty partition entry */
+        if(buffer[4] == 0x00)
+            return 0;
+    }
 
     /* allocate partition descriptor */
     new_partition = malloc(sizeof(*new_partition));
@@ -59,16 +65,24 @@
     new_partition->device_read = device_read;
     new_partition->device_read_interval = device_read_interval;
     new_partition->device_write = device_write;
-    new_partition->type = buffer[4];
-    new_partition->offset = ((uint32_t) buffer[8]) |
-                            ((uint32_t) buffer[9] << 8) |
-                            ((uint32_t) buffer[10] << 16) |
-                            ((uint32_t) buffer[11] << 24);
-    new_partition->length = ((uint32_t) buffer[12]) |
-                            ((uint32_t) buffer[13] << 8) |
-                            ((uint32_t) buffer[14] << 16) |
-                            ((uint32_t) buffer[15] << 24);
 
+    if(index >= 0)
+    {
+        new_partition->type = buffer[4];
+        new_partition->offset = ((uint32_t) buffer[8]) |
+                                ((uint32_t) buffer[9] << 8) |
+                                ((uint32_t) buffer[10] << 16) |
+                                ((uint32_t) buffer[11] << 24);
+        new_partition->length = ((uint32_t) buffer[12]) |
+                                ((uint32_t) buffer[13] << 8) |
+                                ((uint32_t) buffer[14] << 16) |
+                                ((uint32_t) buffer[15] << 24);
+    }
+    else
+    {
+        new_partition->type = 0xff;
+    }
+
     return new_partition;
 }
 
Index: sd_raw_config.h
===================================================================
--- sd_raw_config.h	(.../sd-reader_release_20060319)	(Revision 106)
+++ sd_raw_config.h	(.../sd-reader_release_20060808)	(Revision 106)
@@ -22,6 +22,16 @@
 
 /**
  * \ingroup sd_raw_config
+ * Controls MMC/SD write buffering.
+ *
+ * Set to 1 to buffer write accesses, set to 0 to disable it.
+ *
+ * \note This option has no effect when SD_RAW_WRITE_SUPPORT is 0.
+ */
+#define SD_RAW_WRITE_BUFFERING 1
+
+/**
+ * \ingroup sd_raw_config
  * Controls MMC/SD access buffering.
  * 
  * Set to 1 to save static RAM, but be aware that you will
@@ -35,16 +45,35 @@
 /* defines for customisation of sd/mmc port access */
 #define configure_pin_available() DDRC &= ~(1 << DDC4)
 #define configure_pin_locked() DDRC &= ~(1 << DDC5)
-#define configure_pin_mosi() DDRB |= (1 << DDB3)
-#define configure_pin_sck() DDRB |= (1 << DDB5)
-#define configure_pin_ss() DDRB |= (1 << DDB2)
-#define configure_pin_miso() DDRB &= ~(1 << DDB4)
+#if defined(__AVR_ATmega8__) || \
+    defined(__AVR_ATmega48__) || \
+    defined(__AVR_ATmega88__) || \
+    defined(__AVR_ATmega168__)
+    #define configure_pin_mosi() DDRB |= (1 << DDB3)
+    #define configure_pin_sck() DDRB |= (1 << DDB5)
+    #define configure_pin_ss() DDRB |= (1 << DDB2)
+    #define configure_pin_miso() DDRB &= ~(1 << DDB4)
+#elif defined(__AVR_ATmega16__) || \
+      defined(__AVR_ATmega32__)
+    #define configure_pin_mosi() DDRB |= (1 << DDB5)
+    #define configure_pin_sck() DDRB |= (1 << DDB7)
+    #define configure_pin_ss() DDRB |= (1 << DDB4)
+    #define configure_pin_miso() DDRB &= ~(1 << DDB6)
+#elif defined(__AVR_ATmega64__) || \
+      defined(__AVR_ATmega128__)
+    #define configure_pin_mosi() DDRB |= (1 << DDB2)
+    #define configure_pin_sck() DDRB |= (1 << DDB1)
+    #define configure_pin_ss() DDRB |= (1 << DDB0)
+    #define configure_pin_miso() DDRB &= ~(1 << DDB3)
+#else
+    #error "no sd/mmc pin mapping available!"
+#endif
 
 #define get_pin_available() ((PINC >> PC4) & 0x01)
 #define get_pin_locked() ((PINC >> PC5) & 0x01)
 
-#define select_card() PORTC &= ~(1 << PB2)
-#define unselect_card() PORTC |= (1 << PB2)
+#define select_card() PORTB &= ~(1 << PB2)
+#define unselect_card() PORTB |= (1 << PB2)
 
 /**
  * @}
@@ -54,6 +83,9 @@
 #if SD_RAW_WRITE_SUPPORT
 #undef SD_RAW_SAVE_RAM
 #define SD_RAW_SAVE_RAM 0
+#else
+#undef SD_RAW_WRITE_BUFFERING
+#define SD_RAW_WRITE_BUFFERING 0
 #endif
 
 #endif
