summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2007-05-20 23:22:56 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2007-05-20 23:22:56 +0000
commit4815a2fb0e87d0b64a61f57f287de92be5027e90 (patch)
tree0c7e51da8deec2627958437c76f329219dfa84f8
parent87d2e8e9ebb04306b09e647833fac0a4f71acceb (diff)
downloadnuttx-4815a2fb0e87d0b64a61f57f287de92be5027e90.tar.gz
nuttx-4815a2fb0e87d0b64a61f57f287de92be5027e90.tar.bz2
nuttx-4815a2fb0e87d0b64a61f57f287de92be5027e90.zip
Implemented FAT write
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@244 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/examples/mount/mount_main.c41
-rw-r--r--nuttx/fs/fs_fat32.c229
-rw-r--r--nuttx/fs/fs_fat32.h10
-rw-r--r--nuttx/fs/fs_fat32util.c819
4 files changed, 881 insertions, 218 deletions
diff --git a/nuttx/examples/mount/mount_main.c b/nuttx/examples/mount/mount_main.c
index 274a35010..09dc8e189 100644
--- a/nuttx/examples/mount/mount_main.c
+++ b/nuttx/examples/mount/mount_main.c
@@ -64,7 +64,7 @@ static const char g_target[] = "/mnt/fs";
static const char g_filesystemtype[] = "vfat";
static const char g_testfile1[] = "/mnt/fs/TestDir/TestFile.txt";
-static const char g_testfile2[] = "/mnt/fs/TestDir/WriteTest.txt";
+static const char g_testfile2[] = "/mnt/fs/TestDir/WritTest.txt";
static const char g_testmsg[] = "This is a write test";
/****************************************************************************
@@ -89,7 +89,9 @@ void user_initialize(void)
int user_start(int argc, char *argv[])
{
- int ret;
+ char buffer[128];
+ int nbytes;
+ int ret;
printf("main: mounting %s filesystem at target=%s with source=%s\n",
g_filesystemtype, g_target, g_source);
@@ -104,12 +106,12 @@ int user_start(int argc, char *argv[])
int fd = open(g_testfile1, O_RDONLY);
if (fd < 0)
{
- printf("main: failed open %s, errno=%d\n", g_testfile1, *get_errno_ptr());
+ printf("main: failed to open %s, errno=%d\n", g_testfile1, *get_errno_ptr());
}
else
{
- char buffer[128];
- int nbytes = read(fd, buffer, 128);
+ memset(buffer, 0, 128);
+ nbytes = read(fd, buffer, 128);
if (nbytes < 0)
{
printf("main: failed to read from %s, errno=%d\n", g_testfile1, *get_errno_ptr());
@@ -127,7 +129,7 @@ int user_start(int argc, char *argv[])
fd = open(g_testfile2, O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (fd < 0)
{
- printf("main: failed open %s, errno=%d\n", g_testfile2, *get_errno_ptr());
+ printf("main: failed to open %s for writing, errno=%d\n", g_testfile2, *get_errno_ptr());
}
else
{
@@ -136,6 +138,33 @@ int user_start(int argc, char *argv[])
{
printf("main: failed to write to %s, errno=%d\n", g_testfile2, *get_errno_ptr());
}
+ else
+ {
+ printf("main: wrote %d bytes to %s\n", nbytes, g_testfile2);
+ }
+ close(fd);
+ }
+
+ printf("main: opening %s for reading\n", g_testfile2);
+
+ fd = open(g_testfile2, O_RDONLY);
+ if (fd < 0)
+ {
+ printf("main: failed to open %s for reading, errno=%d\n", g_testfile2, *get_errno_ptr());
+ }
+ else
+ {
+ memset(buffer, 0, 128);
+ nbytes = read(fd, buffer, 128);
+ if (nbytes < 0)
+ {
+ printf("main: failed to read from %s, errno=%d\n", g_testfile2, *get_errno_ptr());
+ }
+ else
+ {
+ buffer[127]='\0';
+ printf("main: Read \"%s\" from %s\n", buffer, g_testfile2);
+ }
close(fd);
}
diff --git a/nuttx/fs/fs_fat32.c b/nuttx/fs/fs_fat32.c
index 51441bacf..a5b68831f 100644
--- a/nuttx/fs/fs_fat32.c
+++ b/nuttx/fs/fs_fat32.c
@@ -4,6 +4,11 @@
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
+ * References:
+ * Microsoft FAT documentation
+ * FAT implementation 'Copyright (C) 2007, ChaN, all right reserved.'
+ * which has an unrestricted license.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -377,7 +382,7 @@ static ssize_t fat_read(FAR struct file *filp, char *buffer, size_t buflen)
struct inode *inode;
struct fat_mountpt_s *fs;
struct fat_file_s *ff;
- unsigned int cluster;
+ uint32 cluster;
unsigned int bytesread;
unsigned int readsize;
unsigned int nsectors;
@@ -461,10 +466,12 @@ static ssize_t fat_read(FAR struct file *filp, char *buffer, size_t buflen)
}
else
{
- /* No.. Handle a special case of the first sector */
+ /* No.. Handle the case of the first sector of the file */
if (ff->ff_position == 0)
{
+ /* Get the first cluster of the file */
+
cluster = ff->ff_startcluster;
}
@@ -499,8 +506,8 @@ static ssize_t fat_read(FAR struct file *filp, char *buffer, size_t buflen)
nsectors = buflen / fs->fs_hwsectorsize;
if (nsectors > 0)
{
- /* Read maximum contiguous sectors directly without using
- * our tiny read buffer.
+ /* Read maximum contiguous sectors directly to the user's
+ * buffer without using our tiny read buffer.
*
* Limit the number of sectors that we read on this time
* through the loop to the remaining contiguous sectors
@@ -580,6 +587,12 @@ static ssize_t fat_write(FAR struct file *filp, const char *buffer,
struct inode *inode;
struct fat_mountpt_s *fs;
struct fat_file_s *ff;
+ sint32 cluster;
+ size_t writesector;
+ unsigned int byteswritten;
+ unsigned int writesize;
+ unsigned int nsectors;
+ ubyte *userbuffer = (ubyte*)buffer;
int ret;
/* Sanity checks */
@@ -600,12 +613,211 @@ static ssize_t fat_write(FAR struct file *filp, const char *buffer,
ret = fat_checkmount(fs);
if (ret != OK)
{
- fat_semgive(fs);
- return ret;
+ goto errout_with_semaphore;
+ }
+
+ /* Check if the file was opened for write access */
+
+ if ((ff->ff_oflags & O_WROK) == 0)
+ {
+ ret= -EACCES;
+ goto errout_with_semaphore;
+ }
+
+ /* Check if the file size would exceed the range of size_t */
+
+ if (ff->ff_size + buflen < ff->ff_size)
+ {
+ ret = -EFBIG;
+ goto errout_with_semaphore;
+ }
+
+ /* Loop until either (1) all data has been transferred, or (2) an
+ * error occurs.
+ */
+
+ byteswritten = 0;
+ while (buflen > 0)
+ {
+ /* Get offset into the sector where we begin the read */
+
+ int sectorindex = ff->ff_position & SEC_NDXMASK(fs);
+
+ /* Check if the current read stream happens to lie on a
+ * sector boundary.
+ */
+
+ if (sectorindex == 0)
+ {
+ /* Decrement the number of sectors left in this cluster */
+
+ ff->ff_sectorsincluster--;
+
+ /* Are there unwritten sectors remaining in this cluster */
+
+ if (ff->ff_sectorsincluster > 0)
+ {
+ /* Yes.. There are more sectors in this cluster to be written.
+ * just increment the current sector number and write.
+ */
+
+ writesector = ff->ff_currentsector + 1;
+ }
+ else
+ {
+ /* No.. Handle the case of the first sector of the file */
+
+ if (ff->ff_position == 0)
+ {
+ /* Check the first cluster of the file. Zero means that
+ * the file is empty -- perhaps the file was truncated or
+ * created when it was opened
+ */
+
+ if (ff->ff_startcluster == 0)
+ {
+ /* In this case, we have to create a new cluster chain */
+
+ ff->ff_startcluster = fat_createchain(fs);
+ }
+
+ /* Start writing at the first cluster of the file */
+
+ cluster = ff->ff_startcluster;
+ }
+
+ /* But in the general case, we have to extend the current
+ * cluster by one (unless lseek was used to move the file
+ * position back from the end of the file)
+ */
+
+ else
+ {
+ /* Extend the chain by adding a new cluster after
+ * the last one
+ */
+
+ cluster = fat_extendchain(fs, ff->ff_currentcluster);
+ }
+
+ /* Verify the cluster number */
+
+ if (cluster < 0)
+ {
+ ret = cluster;
+ goto errout_with_semaphore;
+ }
+ else if (cluster < 2 || cluster >= fs->fs_nclusters)
+ {
+ ret = -ENOSPC;
+ goto errout_with_semaphore;
+ }
+
+ /* Setup to write the first sector from the new cluster */
+
+ ff->ff_currentcluster = cluster;
+ writesector = fat_cluster2sector(fs, cluster);
+ ff->ff_sectorsincluster = fs->fs_fatsecperclus;
+ }
+ }
+
+ /* Check if there is unwritten data in the file buffer */
+
+ ret = fat_ffcacheflush(fs, ff);
+ if (ret < 0)
+ {
+ goto errout_with_semaphore;
+ }
+
+ /* Check if the user has provided a buffer large enough to
+ * hold one or more complete sectors.
+ */
+
+ nsectors = buflen / fs->fs_hwsectorsize;
+ if (nsectors > 0)
+ {
+ /* Write maximum contiguous sectors directly from the user's
+ * buffer without using our tiny read buffer.
+ *
+ * Limit the number of sectors that we write on this time
+ * through the loop to the remaining contiguous sectors
+ * in this cluster
+ */
+
+ if (nsectors > ff->ff_sectorsincluster)
+ {
+ nsectors = ff->ff_sectorsincluster;
+ }
+
+ /* We are not sure of the state of the file buffer so
+ * the safest thing to do is just invalidate it
+ */
+
+ (void)fat_ffcacheinvalidate(fs, ff);
+
+ /* Write all of the sectors directory from user memory */
+
+ ret = fat_hwwrite(fs, userbuffer, writesector, nsectors);
+ if (ret < 0)
+ {
+ goto errout_with_semaphore;
+ }
+
+ ff->ff_sectorsincluster -= nsectors - 1;
+ writesize = nsectors * fs->fs_hwsectorsize;
+ ff->ff_bflags |= FFBUFF_MODIFIED;
+ }
+ else
+ {
+ /* We are write a partial sector. We will first have to
+ * read the full sector in memory as part of a read-modify-write
+ * operation.
+ */
+
+ if (ff->ff_position < ff->ff_size)
+ {
+ ff->ff_currentsector = writesector;
+ ret = fat_ffcacheread(fs, ff, writesector);
+ if (ret < 0)
+ {
+ goto errout_with_semaphore;
+ }
+ }
+
+ /* Copy the partial sector from the user buffer */
+
+ writesize = fs->fs_hwsectorsize - sectorindex;
+ if (writesize > buflen)
+ {
+ writesize = buflen;
+ }
+
+ memcpy(&ff->ff_buffer[sectorindex], userbuffer, writesize);
+ ff->ff_currentsector = writesector;
+ ff->ff_bflags |= (FFBUFF_DIRTY|FFBUFF_VALID|FFBUFF_MODIFIED);
+ }
+
+ /* Set up for the next write */
+
+ userbuffer += writesize;
+ ff->ff_position += writesize;
+ byteswritten += writesize;
+ buflen -= writesize;
+ }
+
+ /* The transfer has completed without error. Update the file size */
+
+ if (ff->ff_position > ff->ff_size)
+ {
+ ff->ff_size = ff->ff_position;
}
fat_semgive(fs);
- return -ENOSYS;
+ return byteswritten;
+
+ errout_with_semaphore:
+ fat_semgive(fs);
+ return ret;
}
/****************************************************************************
@@ -761,7 +973,8 @@ static int fat_sync(FAR struct file *filp)
DIR_PUTFSTCLUSTHI(direntry, ff->ff_startcluster >> 16);
wrttime = fat_gettime();
- DIR_PUTWRTTIME(direntry, wrttime);
+ DIR_PUTWRTTIME(direntry, wrttime & 0xffff);
+ DIR_PUTWRTDATE(direntry, wrttime >> 16);
/* Clear the modified bit in the flags */
diff --git a/nuttx/fs/fs_fat32.h b/nuttx/fs/fs_fat32.h
index 5687b2b16..9e10cd7d8 100644
--- a/nuttx/fs/fs_fat32.h
+++ b/nuttx/fs/fs_fat32.h
@@ -544,12 +544,16 @@ EXTERN int fat_hwread(struct fat_mountpt_s *fs, ubyte *buffer,
EXTERN int fat_hwwrite(struct fat_mountpt_s *fs, ubyte *buffer,
size_t sector, unsigned int nsectors);
-/* Cluster access helpers */
+/* Cluster / cluster chain access helpers */
EXTERN ssize_t fat_cluster2sector(struct fat_mountpt_s *fs, uint32 cluster );
-EXTERN ssize_t fat_getcluster(struct fat_mountpt_s *fs, unsigned int clusterno);
-EXTERN int fat_putcluster(struct fat_mountpt_s *fs, unsigned int clusterno,
+EXTERN ssize_t fat_getcluster(struct fat_mountpt_s *fs, uint32 clusterno);
+EXTERN int fat_putcluster(struct fat_mountpt_s *fs, uint32 clusterno,
size_t startsector);
+EXTERN int fat_removechain(struct fat_mountpt_s *fs, uint32 cluster);
+EXTERN sint32 fat_extendchain(struct fat_mountpt_s *fs, uint32 cluster);
+
+#define fat_createchain(fs) fat_extendchain(fs, 0)
/* Help for traverseing directory trees */
diff --git a/nuttx/fs/fs_fat32util.c b/nuttx/fs/fs_fat32util.c
index 55378a84b..826d13bec 100644
--- a/nuttx/fs/fs_fat32util.c
+++ b/nuttx/fs/fs_fat32util.c
@@ -4,6 +4,11 @@
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
+ * References:
+ * Microsoft FAT documentation
+ * FAT implementation 'Copyright (C) 2007, ChaN, all right reserved.'
+ * which has an unrestricted license.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -405,6 +410,127 @@ static inline int fat_dirname2path(char *path, struct fat_dirinfo_s *dirinfo)
}
/****************************************************************************
+ * Name: fat_allocatedirentry
+ *
+ * Desciption: Find a free directory entry
+ *
+ ****************************************************************************/
+
+static int fat_allocatedirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo)
+{
+ sint32 cluster;
+ size_t sector;
+ ubyte *direntry;
+ ubyte ch;
+ int ret;
+ int i;
+
+ /* Re-initialize directory object */
+
+ cluster = dirinfo->fd_startcluster;
+ if (cluster)
+ {
+ /* Cluster chain can be extended */
+
+ dirinfo->fd_currcluster = cluster;
+ dirinfo->fd_currsector = fat_cluster2sector(fs, cluster);
+ }
+ else
+ {
+ /* Fixed size FAT12/16 root directory is at fixxed offset/size */
+
+ dirinfo->fd_currsector = fs->fs_rootbase;
+ }
+ dirinfo->fd_index = 0;
+
+ for (;;)
+ {
+ unsigned int dirindex;
+
+ /* Read the directory sector into fs_buffer */
+
+ ret = fat_fscacheread(fs, dirinfo->fd_currsector);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* Get a pointer to the entry at fd_index */
+
+ dirindex = (dirinfo->fd_index & DIRSEC_NDXMASK(fs)) * 32;
+ direntry = &fs->fs_buffer[dirindex];
+
+ /* Check if this directory entry is empty */
+
+ ch = direntry[DIR_NAME];
+ if (ch == DIR0_ALLEMPTY || ch == DIR0_EMPTY)
+ {
+ /* It is empty -- we have found a directory entry */
+
+ dirinfo->fd_entry = direntry;
+ return OK;
+ }
+
+ ret = fat_nextdirentry(dirinfo);
+ if (ret < 0)
+ {
+ return ret;
+ }
+ }
+
+ /* If we get here, then we have reached the end of the directory table
+ * in this sector without finding a free directory enty.
+ *
+ * It this is a fixed size dirctory entry, then this is an error.
+ * Otherwise, we can try to extend the directory cluster chain to
+ * make space for the new directory entry.
+ */
+
+ if (!cluster)
+ {
+ /* The size is fixed */
+ return -ENOSPC;
+ }
+
+ /* Try to extend the cluster chain for this directory */
+
+ cluster = fat_extendchain(fs, dirinfo->fd_currcluster);
+ if (cluster < 0)
+ {
+ return cluster;
+ }
+
+ /* Flush out any cached date in fs_buffer.. we are going to use
+ * it to initialize the new directory cluster.
+ */
+
+ ret = fat_fscacheflush(fs);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* Clear all sectors comprising the new directory cluster */
+
+ fs->fs_currentsector = fat_cluster2sector(fs, cluster);
+ memset(fs->fs_buffer, 0, fs->fs_hwsectorsize);
+
+ sector = sector;
+ for (i = fs->fs_fatsecperclus; i; i--)
+ {
+ ret = fat_hwwrite(fs, fs->fs_buffer, sector, 1);
+ if ( ret < 0)
+ {
+ return ret;
+ }
+ sector++;
+ }
+
+ dirinfo->fd_entry = fs->fs_buffer;
+ return OK;
+}
+
+/****************************************************************************
* Name: fat_checkfsinfo
*
* Desciption: Read the FAT32 FSINFO sector
@@ -544,7 +670,6 @@ static int fat_checkbootrecord(struct fat_mountpt_s *fs)
fs->fs_fsinfo = 0;
fs->fs_type = FSTYPE_FAT16;
}
-
else if (!notfat32)
{
fs->fs_fsinfo = fs->fs_fatbase + MBR_GETFSINFO(fs->fs_buffer);
@@ -976,133 +1101,136 @@ int fat_hwwrite(struct fat_mountpt_s *fs, ubyte *buffer, size_t sector,
ssize_t fat_cluster2sector(struct fat_mountpt_s *fs, uint32 cluster )
{
- cluster -= 2;
- if (cluster >= fs->fs_nclusters - 2)
- {
- return -EINVAL;
- }
- return cluster * fs->fs_fatsecperclus + fs->fs_database;
+ cluster -= 2;
+ if (cluster >= fs->fs_nclusters - 2)
+ {
+ return -EINVAL;
+ }
+ return cluster * fs->fs_fatsecperclus + fs->fs_database;
}
/****************************************************************************
* Name: fat_getcluster
*
- * Desciption: Get the cluster start sector into the FAT
+ * Desciption: Get the cluster start sector into the FAT.
+ *
+ * Return: <0: error, >=0: sector number
*
****************************************************************************/
-ssize_t fat_getcluster(struct fat_mountpt_s *fs, unsigned int clusterno)
+ssize_t fat_getcluster(struct fat_mountpt_s *fs, uint32 clusterno)
{
- /* Verify that the cluster number is within range */
+ /* Verify that the cluster number is within range */
- if (clusterno >= 2 && clusterno < fs->fs_nclusters)
+ if (clusterno >= 2 && clusterno < fs->fs_nclusters)
{
- /* Okay.. Read the next cluster from the FAT. The way we will do
- * this depends on the type of FAT filesystm we are dealing with.
- */
+ /* Okay.. Read the next cluster from the FAT. The way we will do
+ * this depends on the type of FAT filesystm we are dealing with.
+ */
- switch (fs->fs_type)
+ switch (fs->fs_type)
{
- case FSTYPE_FAT12 :
+ case FSTYPE_FAT12 :
{
- size_t fatsector;
- unsigned int fatoffset;
- unsigned int startsector;
- unsigned int fatindex;
+ size_t fatsector;
+ unsigned int fatoffset;
+ unsigned int startsector;
+ unsigned int fatindex;
- /* FAT12 is more complex because it has 12-bits (1.5 bytes)
- * per FAT entry. Get the offset to the first byte:
- */
+ /* FAT12 is more complex because it has 12-bits (1.5 bytes)
+ * per FAT entry. Get the offset to the first byte:
+ */
- fatoffset = (clusterno * 3) / 2;
- fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
+ fatoffset = (clusterno * 3) / 2;
+ fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
- /* Read the sector at this offset */
+ /* Read the sector at this offset */
- if (fat_fscacheread(fs, fatsector) < 0)
+ if (fat_fscacheread(fs, fatsector) < 0)
{
- /* Read error */
- break;
+ /* Read error */
+ break;
}
- /* Get the first, LS byte of the cluster from the FAT */
+ /* Get the first, LS byte of the cluster from the FAT */
- fatindex = fatoffset & SEC_NDXMASK(fs);
- startsector = fs->fs_buffer[fatindex];
+ fatindex = fatoffset & SEC_NDXMASK(fs);
+ startsector = fs->fs_buffer[fatindex];
- /* With FAT12, the second byte of the cluster number may lie in
- * a different sector than the first byte.
- */
+ /* With FAT12, the second byte of the cluster number may lie in
+ * a different sector than the first byte.
+ */
- fatindex++;
- if (fatindex >= fs->fs_hwsectorsize)
+ fatindex++;
+ if (fatindex >= fs->fs_hwsectorsize)
{
- fatsector++;
- fatindex = 0;
+ fatsector++;
+ fatindex = 0;
- if (fat_fscacheread(fs, fatsector) < 0)
+ if (fat_fscacheread(fs, fatsector) < 0)
{
- /* Read error */
- break;
+ /* Read error */
+ break;
}
}
- /* Get the second, MS byte of the cluster for 16-bits. The
- * does not depend on the endian-ness of the target, but only
- * on the fact that the byte stream is little-endian.
- */
+ /* Get the second, MS byte of the cluster for 16-bits. The
+ * does not depend on the endian-ness of the target, but only
+ * on the fact that the byte stream is little-endian.
+ */
- startsector |= (unsigned int)fs->fs_buffer[fatindex] << 8;
+ startsector |= (unsigned int)fs->fs_buffer[fatindex] << 8;
- /* Now, pick out the correct 12 bit cluster start sector value */
+ /* Now, pick out the correct 12 bit cluster start sector value */
- if ((clusterno & 1) != 0)
+ if ((clusterno & 1) != 0)
{
- /* Odd.. take the MS 12-bits */
- startsector >>= 4;
+ /* Odd.. take the MS 12-bits */
+ startsector >>= 4;
}
- else
+ else
{
- /* Even.. take the LS 12-bits */
- startsector &= 0x0fff;
+ /* Even.. take the LS 12-bits */
+ startsector &= 0x0fff;
}
- return startsector;
+ return startsector;
}
- case FSTYPE_FAT16 :
+ case FSTYPE_FAT16 :
{
- unsigned int fatoffset = 2 * clusterno;
- size_t fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
- unsigned int fatindex = fatoffset & SEC_NDXMASK(fs);
+ unsigned int fatoffset = 2 * clusterno;
+ size_t fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
+ unsigned int fatindex = fatoffset & SEC_NDXMASK(fs);
- if (fat_fscacheread(fs, fatsector) < 0)
+ if (fat_fscacheread(fs, fatsector) < 0)
{
- /* Read error */
- break;
+ /* Read error */
+ break;
}
- return FAT_GETFAT16(fs->fs_buffer, fatindex);
+ return FAT_GETFAT16(fs->fs_buffer, fatindex);
}
- case FSTYPE_FAT32 :
+ case FSTYPE_FAT32 :
{
- unsigned int fatoffset = 4 * clusterno;
- size_t fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
- unsigned int fatindex = fatoffset & SEC_NDXMASK(fs);
+ unsigned int fatoffset = 4 * clusterno;
+ size_t fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
+ unsigned int fatindex = fatoffset & SEC_NDXMASK(fs);
- if (fat_fscacheread(fs, fatsector) < 0)
+ if (fat_fscacheread(fs, fatsector) < 0)
{
- /* Read error */
- break;
+ /* Read error */
+ break;
}
- return FAT_GETFAT16(fs->fs_buffer, fatindex) & 0x0fffffff;
+ return FAT_GETFAT16(fs->fs_buffer, fatindex) & 0x0fffffff;
}
- default:
- break;
+ default:
+ break;
}
}
- /* There is no cluster information, or an error occured */
- return (ssize_t)ERROR;
+ /* There is no cluster information, or an error occured */
+
+ return (ssize_t)-EINVAL;
}
/****************************************************************************
@@ -1112,136 +1240,340 @@ ssize_t fat_getcluster(struct fat_mountpt_s *fs, unsigned int clusterno)
*
****************************************************************************/
-int fat_putcluster(struct fat_mountpt_s *fs, unsigned int clusterno, size_t startsector)
+int fat_putcluster(struct fat_mountpt_s *fs, uint32 clusterno, size_t startsector)
{
- /* Verify that the cluster number is within range. Zero erases the cluster. */
+ /* Verify that the cluster number is within range. Zero erases the cluster. */
- if (clusterno == 0 || (clusterno >= 2 && clusterno < fs->fs_nclusters))
- {
- /* Okay.. Write the next cluster into the FAT. The way we will do
- * this depends on the type of FAT filesystm we are dealing with.
- */
+ if (clusterno == 0 || (clusterno >= 2 && clusterno < fs->fs_nclusters))
+ {
+ /* Okay.. Write the next cluster into the FAT. The way we will do
+ * this depends on the type of FAT filesystm we are dealing with.
+ */
- switch (fs->fs_type)
- {
- case FSTYPE_FAT12 :
- {
- size_t fatsector;
- unsigned int fatoffset;
- unsigned int fatindex;
- ubyte value;
-
- /* FAT12 is more complex because it has 12-bits (1.5 bytes)
- * per FAT entry. Get the offset to the first byte:
- */
-
- fatoffset = (clusterno * 3) / 2;
- fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
-
- /* Make sure that the sector at this offset is in the cache */
-
- if (fat_fscacheread(fs, fatsector)< 0)
- {
- /* Read error */
- break;
- }
-
- /* Output the LS byte first handling the 12-bit alignment within
- * the 16-bits
- */
-
- fatindex = fatoffset & SEC_NDXMASK(fs);
- if ((clusterno & 1) != 0)
- {
- value = (fs->fs_buffer[fatindex] & 0x0f) | startsector << 4;
- }
- else
- {
- value = (ubyte)startsector;
- }
- fs->fs_buffer[fatindex] = value;
-
- /* With FAT12, the second byte of the cluster number may lie in
- * a different sector than the first byte.
- */
-
- fatindex++;
- if (fatindex >= fs->fs_hwsectorsize)
- {
- /* Read the next sector */
-
- fatsector++;
- fatindex = 0;
-
- /* Set the dirty flag to make sure the sector that we
- * just modified is written out.
- */
-
- fs->fs_dirty = TRUE;
- if (fat_fscacheread(fs, fatsector) < 0)
- {
- /* Read error */
- break;
- }
- }
-
- /* Output the MS byte first handling the 12-bit alignment within
- * the 16-bits
- */
-
- if ((clusterno & 1) != 0)
- {
- value = (ubyte)(startsector >> 4);
- }
- else
- {
- value = (fs->fs_buffer[fatindex] & 0xf0) | (startsector & 0x0f);
- }
- fs->fs_buffer[fatindex] = value;
- }
- break;
+ switch (fs->fs_type)
+ {
+ case FSTYPE_FAT12 :
+ {
+ size_t fatsector;
+ unsigned int fatoffset;
+ unsigned int fatindex;
+ ubyte value;
- case FSTYPE_FAT16 :
- {
- unsigned int fatoffset = 2 * clusterno;
- size_t fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
- unsigned int fatindex = fatoffset & SEC_NDXMASK(fs);
-
- if (fat_fscacheread(fs, fatsector) < 0)
- {
- /* Read error */
- break;
- }
- FAT_PUTFAT16(fs->fs_buffer, fatindex, startsector & 0xffff);
- }
- break;
+ /* FAT12 is more complex because it has 12-bits (1.5 bytes)
+ * per FAT entry. Get the offset to the first byte:
+ */
- case FSTYPE_FAT32 :
- {
- unsigned int fatoffset = 4 * clusterno;
- size_t fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
- unsigned int fatindex = fatoffset & SEC_NDXMASK(fs);
-
- if (fat_fscacheread(fs, fatsector) < 0)
- {
- /* Read error */
- break;
- }
- FAT_PUTFAT32(fs->fs_buffer, fatindex, startsector & 0x0fffffff);
- }
- break;
+ fatoffset = (clusterno * 3) / 2;
+ fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
- default:
- return ERROR;
- }
+ /* Make sure that the sector at this offset is in the cache */
- /* Mark the modified sector as "dirty" and return success */
+ if (fat_fscacheread(fs, fatsector)< 0)
+ {
+ /* Read error */
+ break;
+ }
- fs->fs_dirty = 1;
- return OK;
- }
- return ERROR;
- }
+ /* Output the LS byte first handling the 12-bit alignment within
+ * the 16-bits
+ */
+
+ fatindex = fatoffset & SEC_NDXMASK(fs);
+ if ((clusterno & 1) != 0)
+ {
+ value = (fs->fs_buffer[fatindex] & 0x0f) | startsector << 4;
+ }
+ else
+ {
+ value = (ubyte)startsector;
+ }
+ fs->fs_buffer[fatindex] = value;
+
+ /* With FAT12, the second byte of the cluster number may lie in
+ * a different sector than the first byte.
+ */
+
+ fatindex++;
+ if (fatindex >= fs->fs_hwsectorsize)
+ {
+ /* Read the next sector */
+
+ fatsector++;
+ fatindex = 0;
+
+ /* Set the dirty flag to make sure the sector that we
+ * just modified is written out.
+ */
+
+ fs->fs_dirty = TRUE;
+ if (fat_fscacheread(fs, fatsector) < 0)
+ {
+ /* Read error */
+ break;
+ }
+ }
+
+ /* Output the MS byte first handling the 12-bit alignment within
+ * the 16-bits
+ */
+
+ if ((clusterno & 1) != 0)
+ {
+ value = (ubyte)(startsector >> 4);
+ }
+ else
+ {
+ value = (fs->fs_buffer[fatindex] & 0xf0) | (startsector & 0x0f);
+ }
+ fs->fs_buffer[fatindex] = value;
+ }
+ break;
+
+ case FSTYPE_FAT16 :
+ {
+ unsigned int fatoffset = 2 * clusterno;
+ size_t fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
+ unsigned int fatindex = fatoffset & SEC_NDXMASK(fs);
+
+ if (fat_fscacheread(fs, fatsector) < 0)
+ {
+ /* Read error */
+ break;
+ }
+ FAT_PUTFAT16(fs->fs_buffer, fatindex, startsector & 0xffff);
+ }
+ break;
+
+ case FSTYPE_FAT32 :
+ {
+ unsigned int fatoffset = 4 * clusterno;
+ size_t fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
+ unsigned int fatindex = fatoffset & SEC_NDXMASK(fs);
+
+ if (fat_fscacheread(fs, fatsector) < 0)
+ {
+ /* Read error */
+ break;
+ }
+ FAT_PUTFAT32(fs->fs_buffer, fatindex, startsector & 0x0fffffff);
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* Mark the modified sector as "dirty" and return success */
+
+ fs->fs_dirty = 1;
+ return OK;
+ }
+
+ return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: fat_removechain
+ *
+ * Desciption: Remove an entire chain of clusters, starting with 'cluster'
+ *
+ ****************************************************************************/
+
+int fat_removechain(struct fat_mountpt_s *fs, uint32 cluster)
+{
+ sint32 nextcluster;
+ int ret;
+
+ /* Loop while there are clusters in the chain */
+
+ while (cluster >= 2 && cluster < fs->fs_nclusters)
+ {
+ /* Get the next cluster after the current one */
+
+ nextcluster = fat_getcluster(fs, cluster);
+ if (nextcluster < 0)
+ {
+ /* Error! */
+ return nextcluster;
+ }
+
+ /* Then nullify current cluster -- removing it from the chain */
+
+ ret = fat_putcluster(fs, cluster, 0);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* Update FSINFINFO data */
+
+ if (fs->fs_fsifreecount != 0xffffffff)
+ {
+ fs->fs_fsifreecount++;
+ fs->fs_fsidirty = 1;
+ }
+
+ /* Then set up to remove the next cluster */
+
+ cluster = nextcluster;
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: fat_extendchain
+ *
+ * Desciption: Add a new cluster to the chain following cluster (if cluster
+ * is non-NULL). if cluster is zero, then a new chain is created.
+ *
+ * Return: <0:error, 0: no free cluster, >=2: new cluster number
+ *
+ ****************************************************************************/
+
+sint32 fat_extendchain(struct fat_mountpt_s *fs, uint32 cluster)
+{
+ ssize_t startsector;
+ uint32 newcluster;
+ uint32 startcluster;
+ int ret;
+
+ /* The special value 0 is used when the new chain should start */
+
+ if (cluster == 0)
+ {
+ /* The FSINFO NextFree entry should be a good starting point
+ * in the search for a new cluster
+ */
+
+ startcluster = fs->fs_fsinextfree;
+ if (startcluster == 0 || startcluster >= fs->fs_nclusters)
+ {
+ /* But it is bad.. we have to start at the beginning */
+ startcluster = 1;
+ }
+ }
+ else
+ {
+ /* We are extending an existing chain. Verify that this
+ * is a valid cluster by examining its start sector.
+ */
+
+ startsector = fat_getcluster(fs, cluster);
+ if (startsector < 0)
+ {
+ /* An error occurred, return the error value */
+ return startsector;
+ }
+ else if (startsector < 2)
+ {
+ /* Oops.. this cluster does not exist. */
+ return 0;
+ }
+ else if (startsector < fs->fs_nclusters)
+ {
+ /* It is already followed by next cluster */
+ return startsector;
+ }
+
+ /* Okay.. it checks out */
+
+ startcluster = cluster;
+ }
+
+ /* Loop until (1) we discover that there are not free clusters
+ * (return 0), an errors occurs (return -errno), or (3) we find
+ * the next cluster (return the new cluster number).
+ */
+
+ newcluster = startcluster;
+ for (;;)
+ {
+ /* Examine the next cluster in the FAT */
+
+ newcluster++;
+ if (newcluster >= fs->fs_nclusters)
+ {
+ /* If we hit the end of the available clusters, then
+ * wrap back to the beginning because we might have
+ * started at a non-optimal place. But don't continue
+ * past the start cluster.
+ */
+
+ newcluster = 2;
+ if (newcluster > startcluster)
+ {
+ /* We are back past the starting cluster, then there
+ * is no free cluster.
+ */
+
+ return 0;
+ }
+ }
+
+ /* We have a candidate cluster. Check if the cluster number is
+ * mapped to a group of sectors.
+ */
+
+ startsector = fat_getcluster(fs, newcluster);
+ if (startsector == 0)
+ {
+ /* Found have found a free cluster break out*/
+ break;
+ }
+ else if (startsector < 0)
+ {
+ /* Some error occurred, return the error number */
+ return startsector;
+ }
+
+ /* We wrap all the back to the starting cluster? If so, then
+ * there are no free clusters.
+ */
+
+ if (newcluster == startcluster)
+ {
+ return 0;
+ }
+ }
+
+ /* We get here only if we break out with an available cluster
+ * number in 'newcluster' Now mark that cluster as in-use.
+ */
+
+ ret = fat_putcluster(fs, newcluster, 0x0fffffff);
+ if (ret < 0)
+ {
+ /* An error occurred */
+ return ret;
+ }
+
+ /* And link if to the start cluster (if any)*/
+
+ if (cluster)
+ {
+ /* There is a start cluster -- link it */
+
+ ret = fat_putcluster(fs, cluster, newcluster);
+ if (ret < 0)
+ {
+ return ret;
+ }
+ }
+
+ /* And update the FINSINFO for the next time we have to search */
+
+ fs->fs_fsinextfree = newcluster;
+ if (fs->fs_fsifreecount != 0xffffffff)
+ {
+ fs->fs_fsifreecount--;
+ fs->fs_fsidirty = 1;
+ }
+
+ /* Return then number of the new cluster that was added to the chain */
+
+ return newcluster;
+}
/****************************************************************************
* Name: fat_nextdirentry
@@ -1497,12 +1829,61 @@ int fat_finddirentry(struct fat_dirinfo_s *dirinfo, const char *path)
*
* Desciption: Truncate an existing file to zero length
*
+ * Assumptions: The caller holds mountpoint semaphore, fs_buffer holds
+ * the directory entry, dirinfo refers to the current fs_buffer content.
+ *
****************************************************************************/
int fat_dirtruncate(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo)
{
-#warning "File truncation logic not implemented"
- return -ENOSYS;
+ unsigned int startcluster;
+ uint32 writetime;
+ size_t savesector;
+ int ret;
+
+ /* Get start cluster of the file to truncate */
+
+ startcluster =
+ ((uint32)DIR_GETFSTCLUSTHI(dirinfo->fd_entry) << 16) |
+ DIR_GETFSTCLUSTLO(dirinfo->fd_entry);
+
+ /* Clear the cluster start value in the directory and set the file size
+ * to zero. This makes the file look empty but also have to dispose of
+ * all of the clusters in the chain.
+ */
+
+ DIR_PUTFSTCLUSTHI(dirinfo->fd_entry, 0);
+ DIR_PUTFSTCLUSTLO(dirinfo->fd_entry, 0);
+ DIR_PUTFILESIZE(dirinfo->fd_entry, 0);
+
+ /* Set the ARCHIVE attribute and update the write time */
+
+ DIR_PUTATTRIBUTES(dirinfo->fd_entry, FATATTR_ARCHIVE);
+
+ writetime = fat_gettime();
+ DIR_PUTWRTTIME(dirinfo->fd_entry, writetime & 0xffff);
+ DIR_PUTWRTDATE(dirinfo->fd_entry, writetime > 16);
+
+ /* This sector needs to be written back to disk eventually */
+
+ fs->fs_dirty = TRUE;
+
+ /* Now remove the entire cluster chain comprising the file */
+
+ savesector = fs->fs_currentsector;
+ ret = fat_removechain(fs, startcluster);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* Setup FSINFO to resuse this cluster next */
+
+ fs->fs_fsinextfree = startcluster - 1;
+
+ /* Make sure that the directory is still in the cache */
+
+ return fat_fscacheread(fs, savesector);
}
/****************************************************************************
@@ -1514,8 +1895,44 @@ int fat_dirtruncate(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo)
int fat_dircreate(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo)
{
-#warning "File truncation logic not implemented"
- return -ENOSYS;
+ ubyte *direntry;
+ uint32 time;
+ int ret;
+
+ /* Set up the directory entry */
+
+ ret = fat_allocatedirentry(fs, dirinfo);
+ if (ret != OK)
+ {
+ /* Failed to set up directory entry */
+ return ret;
+ }
+
+ /* Initialize the 32-byte directory entry */
+
+ direntry = dirinfo->fd_entry;
+ memset(direntry, 0, 32);
+
+ /* Directory name info */
+
+ memcpy(&direntry[DIR_NAME], dirinfo->fd_name, 8+3);
+#ifdef CONFIG_FLAT_LCNAMES
+ DIR_PUTNTRES(dirinfo->fd_entry, dirinfo->fd_ntflags);
+#else
+ DIR_PUTNTRES(dirinfo->fd_entry, 0);
+#endif
+
+ /* ARCHIVE attribute, write time, creation time */
+ DIR_PUTATTRIBUTES(dirinfo->fd_entry, FATATTR_ARCHIVE);
+
+ time = fat_gettime();
+ DIR_PUTWRTTIME(dirinfo->fd_entry, time & 0xffff);
+ DIR_PUTCRTIME(dirinfo->fd_entry, time & 0xffff);
+ DIR_PUTWRTDATE(dirinfo->fd_entry, time >> 16);
+ DIR_PUTCRDATE(dirinfo->fd_entry, time >> 16);
+
+ fs->fs_dirty = TRUE;
+ return OK;
}
/****************************************************************************