diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2007-05-20 23:22:56 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2007-05-20 23:22:56 +0000 |
commit | 4815a2fb0e87d0b64a61f57f287de92be5027e90 (patch) | |
tree | 0c7e51da8deec2627958437c76f329219dfa84f8 | |
parent | 87d2e8e9ebb04306b09e647833fac0a4f71acceb (diff) | |
download | px4-nuttx-4815a2fb0e87d0b64a61f57f287de92be5027e90.tar.gz px4-nuttx-4815a2fb0e87d0b64a61f57f287de92be5027e90.tar.bz2 px4-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.c | 41 | ||||
-rw-r--r-- | nuttx/fs/fs_fat32.c | 229 | ||||
-rw-r--r-- | nuttx/fs/fs_fat32.h | 10 | ||||
-rw-r--r-- | nuttx/fs/fs_fat32util.c | 819 |
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; } /**************************************************************************** |