diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2007-05-19 21:30:57 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2007-05-19 21:30:57 +0000 |
commit | a188db48c1a21f7cd67c2925f29a2369b3a8ab1b (patch) | |
tree | 250ba0ad072afebe02de99779c54c70dc4bbdb0a | |
parent | 1d58458830dde2a31b40883e04b4d3d643815592 (diff) | |
download | nuttx-a188db48c1a21f7cd67c2925f29a2369b3a8ab1b.tar.gz nuttx-a188db48c1a21f7cd67c2925f29a2369b3a8ab1b.tar.bz2 nuttx-a188db48c1a21f7cd67c2925f29a2369b3a8ab1b.zip |
Support for open of FAT fs
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@230 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r-- | nuttx/arch/sim/src/up_blockdevice.c | 8 | ||||
-rw-r--r-- | nuttx/arch/sim/src/up_deviceimage.c | 222 | ||||
-rw-r--r-- | nuttx/examples/mount/mount_main.c | 4 | ||||
-rw-r--r-- | nuttx/fs/Makefile | 2 | ||||
-rw-r--r-- | nuttx/fs/fs_fat32.c | 858 | ||||
-rw-r--r-- | nuttx/fs/fs_fat32.h | 351 | ||||
-rw-r--r-- | nuttx/fs/fs_fat32util.c | 1543 | ||||
-rw-r--r-- | nuttx/fs/fs_open.c | 2 | ||||
-rw-r--r-- | nuttx/include/nuttx/fs.h | 12 | ||||
-rw-r--r-- | nuttx/include/sys/stat.h | 49 |
10 files changed, 2203 insertions, 848 deletions
diff --git a/nuttx/arch/sim/src/up_blockdevice.c b/nuttx/arch/sim/src/up_blockdevice.c index 0753561bc..4bece0a2f 100644 --- a/nuttx/arch/sim/src/up_blockdevice.c +++ b/nuttx/arch/sim/src/up_blockdevice.c @@ -63,9 +63,9 @@ static int up_open(FAR struct inode *inode); static int up_close(FAR struct inode *inode); static ssize_t up_read(FAR struct inode *inode, unsigned char *buffer, - size_t start_sector, size_t nsectors); + size_t start_sector, unsigned int nsectors); static ssize_t up_write(FAR struct inode *inode, const unsigned char *buffer, - size_t start_sector, size_t nsectors); + size_t start_sector, unsigned int nsectors); static int up_geometry(FAR struct inode *inode, struct geometry *geometry); /**************************************************************************** @@ -117,7 +117,7 @@ static int up_close(FAR struct inode *inode) ****************************************************************************/ static ssize_t up_read(FAR struct inode *inode, unsigned char *buffer, - size_t start_sector, size_t nsectors) + size_t start_sector, unsigned int nsectors) { if (inode) { @@ -143,7 +143,7 @@ static ssize_t up_read(FAR struct inode *inode, unsigned char *buffer, ****************************************************************************/ static ssize_t up_write(FAR struct inode *inode, const unsigned char *buffer, - size_t start_sector, size_t nsectors) + size_t start_sector, unsigned int nsectors) { if (inode) { diff --git a/nuttx/arch/sim/src/up_deviceimage.c b/nuttx/arch/sim/src/up_deviceimage.c index 7484240d0..9a28f4edd 100644 --- a/nuttx/arch/sim/src/up_deviceimage.c +++ b/nuttx/arch/sim/src/up_deviceimage.c @@ -75,8 +75,8 @@ * /sbin/mkdosfs -C -F 32 -I -n "NuttXTestVol" -S 512 -v nuttx-test.vfat 1024 * sudo mkdir /mnt/loop * sudo mount -o loop nuttx-test.vfat /mnt/loop - * mkdir /mnt/loop/nuttx-test - * echo "This is a test" >/mnt/loop/nuttx-test/test-file.txt + * mkdir /mnt/loop/TestDir + * echo "This is a test" >/mnt/loop/TestDir/TestFile.txt * sudo umount /mnt/loop * gzip nuttx-test.vfat * xxd -g 1 nuttx-test.vfat.gz >some-file @@ -87,126 +87,96 @@ static const unsigned char g_vfatdata[] = { - 0x08, 0x1d, 0xed, 0xdd, 0x4d, 0x6b, 0x13, 0x41, 0x18, 0x00, 0xe0, 0x69, - 0x2d, 0xb6, 0x54, 0xfa, 0x71, 0x12, 0x3c, 0x39, 0x78, 0x53, 0x48, 0xa0, - 0x55, 0x7a, 0x36, 0x07, 0xab, 0xa7, 0x22, 0x75, 0x5b, 0x72, 0x12, 0x52, - 0x92, 0x6a, 0x68, 0x4c, 0x4a, 0x76, 0x8b, 0x2d, 0x48, 0x6f, 0xbd, 0xfb, - 0x2f, 0xc4, 0x62, 0x4f, 0x7a, 0x13, 0xc5, 0x3f, 0x90, 0x7f, 0xe1, 0x2d, - 0x97, 0x1e, 0x7b, 0x32, 0x6e, 0x4c, 0x53, 0x2c, 0x22, 0x7e, 0x80, 0x44, - 0xf1, 0x79, 0x76, 0x67, 0x66, 0xd9, 0x97, 0x81, 0x59, 0xe6, 0x65, 0x19, - 0xd8, 0x85, 0xe9, 0x96, 0x9f, 0x3f, 0xd9, 0xaa, 0xb6, 0xd2, 0xcd, 0x34, - 0x84, 0xf1, 0xb1, 0x18, 0xc6, 0x43, 0x08, 0x53, 0x27, 0x21, 0xc4, 0x70, - 0x3b, 0x0c, 0xcd, 0x9f, 0xb6, 0xfd, 0xd8, 0x58, 0xb8, 0x18, 0xce, 0xbb, - 0x7e, 0xfc, 0xfa, 0xee, 0xf2, 0xca, 0x4e, 0x96, 0x95, 0x93, 0x5a, 0x9a, - 0xad, 0xb7, 0x96, 0x4b, 0xc9, 0xcd, 0xc5, 0x18, 0xe3, 0xec, 0xd5, 0xf7, - 0x4f, 0x9f, 0xbd, 0xba, 0xf6, 0x21, 0xbb, 0xb4, 0xfe, 0x66, 0xf6, 0xed, - 0x64, 0xe8, 0xcc, 0x3f, 0xec, 0x1e, 0x2f, 0x7e, 0xec, 0x5c, 0xee, 0x5c, - 0xe9, 0x7e, 0x4a, 0x1e, 0xd7, 0xd3, 0x98, 0x9f, 0xcd, 0x56, 0x16, 0x2b, - 0x71, 0xa3, 0xd5, 0xca, 0x2a, 0x1b, 0x8d, 0x5a, 0xac, 0xd6, 0xd3, 0xad, - 0x62, 0x8c, 0xf7, 0x1b, 0xb5, 0x4a, 0x5a, 0x8b, 0xf5, 0x66, 0x5a, 0x6b, - 0x9f, 0x8b, 0x6f, 0x36, 0x5a, 0xdb, 0xdb, 0x7b, 0xb1, 0xd2, 0xac, 0xce, - 0x4c, 0x6f, 0xb7, 0x6b, 0x69, 0x9a, 0x5f, 0xee, 0xc5, 0xad, 0xda, 0x5e, - 0xcc, 0x5a, 0x31, 0x6b, 0xe7, 0x91, 0x47, 0x95, 0x7a, 0x33, 0x16, 0x8b, - 0xc5, 0x38, 0x33, 0x1d, 0xf8, 0x91, 0xb5, 0xc3, 0xd5, 0xd5, 0x4a, 0x69, - 0xd4, 0xa3, 0xe0, 0xcf, 0x6a, 0xb7, 0x4b, 0x95, 0x77, 0x93, 0x21, 0x4c, - 0x7c, 0x13, 0x59, 0x3b, 0x1c, 0xc1, 0x70, 0x00, 0x80, 0x11, 0xeb, 0x5a, - 0xff, 0xff, 0xc7, 0xac, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x76, 0x27, 0xbd, 0xde, 0x5c, 0x2f, - 0x2f, 0xc3, 0xb6, 0x5f, 0x46, 0x3d, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xe0, 0xd7, 0xf8, 0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xbe, 0xaf, 0x36, 0xee, 0x9c, 0x0a, 0xe1, 0xc6, 0x8b, - 0xa3, 0xa5, 0xa3, 0xa5, 0x41, 0x3b, 0x88, 0x97, 0x9a, 0x61, 0x27, 0x64, - 0xf9, 0xb1, 0x1b, 0xe6, 0xc2, 0xbd, 0x42, 0x7e, 0x51, 0x0b, 0x69, 0x5e, - 0xf7, 0xf5, 0x72, 0x2b, 0x6b, 0x49, 0x52, 0x2e, 0xec, 0x2f, 0xc4, 0x18, - 0xe7, 0x43, 0xb5, 0xf3, 0x72, 0xd0, 0xbf, 0xdf, 0x5e, 0x18, 0xe1, 0x53, - 0xf1, 0xb3, 0x8a, 0xf1, 0xcc, 0x7c, 0x08, 0x07, 0xa7, 0xf3, 0x77, 0x70, - 0x36, 0x7f, 0xc5, 0xe2, 0xf7, 0xe2, 0x83, 0xfe, 0xa5, 0x61, 0x42, 0x14, - 0xf2, 0xfc, 0xb8, 0xb5, 0x19, 0xea, 0xa1, 0x91, 0xdf, 0x28, 0x7e, 0xc9, - 0x90, 0xdd, 0xbc, 0x4e, 0xee, 0x3c, 0x48, 0x0a, 0xcb, 0xfb, 0x0b, 0x49, - 0x39, 0x89, 0xe7, 0xf3, 0x63, 0x22, 0xf8, 0xd1, 0x64, 0xf4, 0x86, 0x1b, - 0xf1, 0x56, 0x62, 0x96, 0xbf, 0x04, 0xec, 0x99, 0x0b, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xbb, 0x3e, 0x03 + 0x08, 0x1d, 0xed, 0xdd, 0xcf, 0x6a, 0x13, 0x41, 0x18, 0x00, 0xf0, 0xa9, 0x16, 0x5b, 0x2a, 0x6d, + 0x73, 0x12, 0x3c, 0x39, 0x78, 0xf3, 0xb2, 0x87, 0x0a, 0x3d, 0x78, 0x32, 0xd0, 0x06, 0x0a, 0xa2, + 0xa5, 0xa6, 0xa5, 0x17, 0x95, 0x2d, 0xd9, 0x6a, 0x68, 0x4c, 0xda, 0xec, 0x8a, 0x2d, 0x78, 0xf3, + 0x01, 0xf4, 0x39, 0x8a, 0xb7, 0x7a, 0x13, 0xc5, 0x17, 0xe8, 0x5b, 0x78, 0xcb, 0xc5, 0x63, 0x4f, + 0xc6, 0x8d, 0x69, 0x8b, 0x45, 0xc4, 0x3f, 0x20, 0x51, 0xfc, 0xfd, 0xd8, 0xe1, 0xdb, 0xd9, 0x8f, + 0x81, 0x59, 0xe6, 0x63, 0x59, 0xd8, 0x85, 0xe9, 0xad, 0xbf, 0x7c, 0xbc, 0xd5, 0xe8, 0xe4, 0x9b, + 0x79, 0x08, 0xe7, 0xc6, 0x62, 0x38, 0x17, 0x42, 0x98, 0x3c, 0x0a, 0x21, 0x86, 0x9b, 0xe1, 0x44, + 0xe5, 0x38, 0x0e, 0x72, 0x63, 0xe1, 0x42, 0x38, 0xeb, 0xda, 0xf2, 0xbd, 0x3b, 0xb5, 0xdb, 0x4f, + 0x8a, 0x62, 0xbd, 0x9e, 0xe5, 0xc5, 0x5a, 0xa7, 0x56, 0xad, 0x5f, 0x9f, 0x8b, 0x31, 0xce, 0x5c, + 0x79, 0xf7, 0xf4, 0xd9, 0xab, 0xab, 0xef, 0x8b, 0x8b, 0x6b, 0xaf, 0x67, 0xde, 0x4c, 0x84, 0xc3, + 0xca, 0xfd, 0xde, 0xc7, 0xb9, 0x0f, 0x87, 0x97, 0x0e, 0x2f, 0xf7, 0x3e, 0xd5, 0x1f, 0x35, 0xf3, + 0x58, 0x1e, 0xed, 0x4e, 0x11, 0xd3, 0xb8, 0xd1, 0xe9, 0x14, 0xe9, 0x46, 0x2b, 0x8b, 0x8d, 0x66, + 0xbe, 0x95, 0xc4, 0xb8, 0xdc, 0xca, 0xd2, 0x3c, 0x8b, 0xcd, 0x76, 0x9e, 0x75, 0xcf, 0xe4, 0x37, + 0x5b, 0x9d, 0xed, 0xed, 0xbd, 0x98, 0xb6, 0x1b, 0xd3, 0x53, 0xdb, 0xdd, 0x2c, 0xcf, 0xcb, 0xd3, + 0xbd, 0xb8, 0x95, 0xed, 0xc5, 0xa2, 0x13, 0x8b, 0x6e, 0x99, 0x79, 0x98, 0x36, 0xdb, 0x31, 0x49, + 0x92, 0x38, 0x3d, 0x15, 0xf8, 0x91, 0xd5, 0xfd, 0x95, 0x95, 0xb4, 0x3a, 0xea, 0x59, 0xf0, 0x67, + 0x75, 0xbb, 0xd5, 0xf4, 0xed, 0x44, 0x08, 0xe3, 0xdf, 0x64, 0x56, 0xf7, 0x47, 0x30, 0x1d, 0x00, + 0x60, 0xc4, 0x7a, 0xde, 0xff, 0xff, 0x63, 0xde, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x76, 0x47, 0xfd, 0xfe, 0x6c, 0xbf, 0x6c, 0x27, 0x71, 0xd0, + 0x46, 0x3d, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xd7, 0xf8, 0xfe, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xbe, 0xaf, 0x36, 0xee, 0x9c, 0x0c, 0xe1, 0xc6, 0xf3, + 0x83, 0xf9, 0x83, 0xf9, 0x61, 0x1c, 0xe6, 0xab, 0xf5, 0x90, 0x85, 0x3c, 0x14, 0x61, 0x21, 0xcc, + 0x86, 0x07, 0xcd, 0xd0, 0x2d, 0xaf, 0xf5, 0xbf, 0x18, 0xc6, 0xfa, 0xe2, 0xdd, 0xfa, 0xc2, 0xd2, + 0x4a, 0x2c, 0x55, 0x42, 0xe3, 0xc5, 0xf1, 0xf8, 0x41, 0x3c, 0x3f, 0xd2, 0xfb, 0xe2, 0xe7, 0x24, + 0xf1, 0x54, 0x25, 0x84, 0x9d, 0xe3, 0xf5, 0xdb, 0x39, 0x5d, 0xbf, 0x24, 0xf9, 0x5e, 0x7e, 0x38, + 0xfe, 0xb4, 0x3e, 0x6a, 0x65, 0x7d, 0xec, 0x36, 0x43, 0xab, 0xec, 0x26, 0x65, 0x77, 0xb7, 0xcc, + 0x15, 0x65, 0x1b, 0xd4, 0x47, 0x6d, 0xe9, 0xd6, 0x62, 0x7d, 0xbd, 0x1e, 0xcf, 0xd6, 0xc7, 0x78, + 0xf0, 0xa3, 0xc9, 0xe8, 0x9d, 0x6c, 0xc4, 0x9b, 0xc6, 0xa2, 0x7c, 0x08, 0xd8, 0x33, 0x17, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x77, 0x7d, 0x06 }; @@ -369,15 +339,15 @@ int main(int argc, char **argv, char **envp) deviceimage = up_deviceimage(); if (deviceimage) - { + { printf("Inflate SUCCEEDED\n"); free(deviceimage); return 0; - } + } else - { + { printf("Inflate FAILED\n"); return 1; - } + } } #endif diff --git a/nuttx/examples/mount/mount_main.c b/nuttx/examples/mount/mount_main.c index 3ba8f96d5..274a35010 100644 --- a/nuttx/examples/mount/mount_main.c +++ b/nuttx/examples/mount/mount_main.c @@ -63,8 +63,8 @@ static const char g_source[] = "/dev/blkdev"; static const char g_target[] = "/mnt/fs"; static const char g_filesystemtype[] = "vfat"; -static const char g_testfile1[] = "/mnt/fs/nuttx-test/test-file.txt"; -static const char g_testfile2[] = "/mnt/fs/nuttx-test/write-test.txt"; +static const char g_testfile1[] = "/mnt/fs/TestDir/TestFile.txt"; +static const char g_testfile2[] = "/mnt/fs/TestDir/WriteTest.txt"; static const char g_testmsg[] = "This is a write test"; /**************************************************************************** diff --git a/nuttx/fs/Makefile b/nuttx/fs/Makefile index 38465a52e..2691e9ff2 100644 --- a/nuttx/fs/Makefile +++ b/nuttx/fs/Makefile @@ -48,7 +48,7 @@ CSRCS = fs_open.c fs_close.c fs_read.c fs_write.c fs_ioctl.c fs_dup.c \ fs_registerblockdriver.c fs_unregisterblockdriver.c \ fs_mount.c fs_umount.c fs_inodeaddref.c fs_inoderelease.c ifeq ($(CONFIG_FS_FAT),y) -CSRCS += fs_fat32.c +CSRCS += fs_fat32.c fs_fat32util.c endif COBJS = $(CSRCS:.c=$(OBJEXT)) diff --git a/nuttx/fs/fs_fat32.c b/nuttx/fs/fs_fat32.c index 6f3e35e74..007bfdcec 100644 --- a/nuttx/fs/fs_fat32.c +++ b/nuttx/fs/fs_fat32.c @@ -39,9 +39,12 @@ #include <nuttx/config.h> #include <sys/types.h> +#include <sys/stat.h> #include <stdlib.h> +#include <string.h> #include <semaphore.h> #include <assert.h> +#include <fcntl.h> #include <errno.h> #include <debug.h> @@ -56,163 +59,6 @@ * Definitions ****************************************************************************/ -/* Access to data in raw sector data */ - -#define UBYTE_VAL(p,o) (((ubyte*)(p))[o]) -#define UBYTE_PTR(p,o) &UBYTE_VAL(p,o) -#define UBYTE_PUT(p,o,v) (UBYTE_VAL(p,o)=(ubyte)(v)) - -#define UINT16_PTR(p,o) ((uint16*)UBYTE_PTR(p,o)) -#define UINT16_VAL(p,o) (*UINT16_PTR(p,o)) -#define UINT16_PUT(p,o,v) (UINT16_VAL(p,o)=(uint16)(v)) - -#define UINT32_PTR(p,o) ((uint32*)UBYTE_PTR(p,o)) -#define UINT32_VAL(p,o) (*UINT32_PTR(p,o)) -#define UINT32_PUT(p,o,v) (UINT32_VAL(p,o)=(uint32)(v)) - -/* Regardless of the endian-ness of the target or alignment of the data, no - * special operations are required for byte, string or byte array accesses. - * The FAT data stream is little endian so multiple byte values must be - * accessed byte-by-byte for big-endian targets. - */ - -#define MBR_GETSECPERCLUS(p) UBYTE_VAL(p,BS_SECPERCLUS) -#define MBR_GETNUMFATS(p) UBYTE_VAL(p,BS_NUMFATS) -#define MBR_GETMEDIA(p) UBYTE_VAL(p,BS_MEDIA) -#define MBR_GETDRVNUM16(p) UBYTE_VAL(p,BS16_DRVNUM) -#define MBR_GETDRVNUM32(p) UBYTE_VAL(p,BS32_DRVNUM) -#define MBR_GETBOOTSIG16(p) UBYTE_VAL(p,BS16_BOOTSIG) -#define MBR_GETBOOTSIG32(p) UBYTE_VAL(p,BS32_BOOTSIG) - -#define MBR_PUTSECPERCLUS(p,v) UBYTE_PUT(p,BS_SECPERCLUS),v) -#define MBR_PUTNUMFATS(p,v) UBYTE_PUT(p,BS_NUMFATS,v) -#define MBR_PUTMEDIA(p,v) UBYTE_PUT(p,BS_MEDIA,v) -#define MBR_PUTDRVNUM16(p,v) UBYTE_PUT(p,BS16_DRVNUM,v) -#define MBR_PUTDRVNUM32(p,v) UBYTE_PUT(p,BS32_DRVNUM,v) -#define MBR_PUTBOOTSIG16(p,v) UBYTE_PUT(p,BS16_BOOTSIG,v) -#define MBR_PUTBOOTSIG32(p,v) UBYTE_PUT(p,BS32_BOOTSIG,v) - -/* For the all targets, unaligned values need to be accessed byte-by-byte. - * Some architectures may handle unaligned accesses with special interrupt - * handlers. But even in that case, it is more efficient to avoid the traps. - */ - -/* Unaligned multi-byte access macros */ - -#define MBR_GETBYTESPERSEC(p) fat_getuint16(UBYTE_PTR(p,BS_BYTESPERSEC)) -#define MBR_GETROOTENTCNT(p) fat_getuint16(UBYTE_PTR(p,BS_ROOTENTCNT)) -#define MBR_GETTOTSEC16(p) fat_getuint16(UBYTE_PTR(p,BS_TOTSEC16)) -#define MBR_GETVOLID16(p) fat_getuint32(UBYTE_PTR(p,BS16_VOLID)) -#define MBR_GETVOLID32(p) fat_getuint32(UBYTE_PTR(p,BS32_VOLID)) - -#define MBR_PUTBYTESPERSEC(p,v) fat_putuint16(UBYTE_PTR(p,BS_BYTESPERSEC),v) -#define MBR_PUTROOTENTCNT(p,v) fat_putuint16(UBYTE_PTR(p,BS_ROOTENTCNT),v) -#define MBR_PUTTOTSEC16(p,v) fat_putuint16(UBYTE_PTR(p,BS_TOTSEC16),v) -#define MBR_PUTVOLID16(p,v) fat_putuint32(UBYTE_PTR(p,BS16_VOLID),v) -#define MBR_PUTVOLID32(p,v) fat_putuint32(UBYTE_PTR(p,BS32_VOLID),v) - -/* But for multi-byte values, the endian-ness of the target vs. the little - * endian order of the byte stream or alignment of the data within the byte - * stream can force special, byte-by-byte accesses. - */ - -#ifdef CONFIG_ARCH_BIGENDIAN -/* If the target is big-endian, then even aligned multi-byte values must be - * accessed byte-by-byte. - */ - -# define MBR_GETRESVDSECCOUNT(p) fat_getuint16(UBYTE_PTR(p,BS_RESVDSECCOUNT)) -# define MBR_GETFATSZ16(p) fat_getuint16(UBYTE_PTR(p,BS_FATSZ16)) -# define MBR_GETSECPERTRK(p) fat_getuint16(UBYTE_PTR(p,BS_SECPERTRK)) -# define MBR_GETNUMHEADS(p) fat_getuint16(UBYTE_PTR(p,BS_NUMHEADS)) -# define MBR_GETHIDSEC(p) fat_getuint32(UBYTE_PTR(p,BS_HIDSEC)) -# define MBR_GETTOTSEC32(p) fat_getuint32(UBYTE_PTR(p,BS_TOTSEC32)) -# define MBR_GETFATSZ32(p) fat_getuint32(UBYTE_PTR(p,BS32_FATSZ32)) -# define MBR_GETEXTFLAGS(p) fat_getuint16(UBYTE_PTR(p,BS32_EXTFLAGS)) -# define MBR_GETFSVER(p) fat_getuint16(UBYTE_PTR(p,BS32_FSVER)) -# define MBR_GETROOTCLUS(p) fat_getuint32(UBYTE_PTR(p,BS32_ROOTCLUS)) -# define MBR_GETFSINFO(p) fat_getuint16(UBYTE_PTR(p,BS32_FSINFO)) -# define MBR_GETBKBOOTSEC(p) fat_getuint16(UBYTE_PTR(p,BS32_BKBOOTSEC)) -# define MBR_GETSIGNATURE(p) fat_getuint16(UBYTE_PTR(p,BS_SIGNATURE)) - -# define MBR_GETPARTSECTOR(s) fat_getuint32(s); - -# define FSI_GETLEADSIG(p) fat_getuint32(UBYTE_PTR(p,FSI_LEADSIG)) -# define FSI_GETSTRUCTSIG(p) fat_getuint32(UBYTE_PTR(p,FSI_STRUCTSIG)) -# define FSI_GETFREECOUNT(p) fat_getuint32(UBYTE_PTR(p,FSI_FREECOUNT)) -# define FSI_GETNXTFREE(p) fat_getuint32(UBYTE_PTR(p,FSI_NXTFREE)) -# define FSI_GETTRAILSIG(p) fat_getuint32(UBYTE_PTR(p,FSI_TRAILSIG)) - -# define MBR_PUTRESVDSECCOUNT(p,v) fat_putuint16(UBYTE_PTR(p,BS_RESVDSECCOUNT,v)) -# define MBR_PUTFATSZ16(p,v) fat_putuint16(UBYTE_PTR(p,BS_FATSZ16,v)) -# define MBR_PUTSECPERTRK(p,v) fat_putuint16(UBYTE_PTR(p,BS_SECPERTRK,v)) -# define MBR_PUTNUMHEADS(p,v) fat_putuint16(UBYTE_PTR(p,BS_NUMHEADS,v)) -# define MBR_PUTHIDSEC(p,v) fat_putuint32(UBYTE_PTR(p,BS_HIDSEC,v)) -# define MBR_PUTTOTSEC32(p,v) fat_putuint32(UBYTE_PTR(p,BS_TOTSEC32,v)) -# define MBR_PUTFATSZ32(p,v) fat_putuint32(UBYTE_PTR(p,BS32_FATSZ32,v)) -# define MBR_PUTEXTFLAGS(p,v) fat_putuint16(UBYTE_PTR(p,BS32_EXTFLAGS,v)) -# define MBR_PUTFSVER(p,v) fat_putuint16(UBYTE_PTR(p,BS32_FSVER,v)) -# define MBR_PUTROOTCLUS(p,v) fat_putuint32(UBYTE_PTR(p,BS32_ROOTCLUS,v)) -# define MBR_PUTFSINFO(p,v) fat_putuint16(UBYTE_PTR(p,BS32_FSINFO,v)) -# define MBR_PUTBKBOOTSEC(p,v) fat_putuint16(UBYTE_PTR(p,BS32_BKBOOTSEC,v)) -# define MBR_PUTSIGNATURE(p,v) fat_getuint16(UBYTE_PTR(p,BS_SIGNATURE),v) - -# define FSI_PUTLEADSIG(p,v) fat_putuint32(UBYTE_PTR(p,FSI_LEADSIG),v) -# define FSI_PUTSTRUCTSIG(p,v) fat_putuint32(UBYTE_PTR(p,FSI_STRUCTSIG),v) -# define FSI_PUTFREECOUNT(p,v) fat_putuint32(UBYTE_PTR(p,FSI_FREECOUNT),v) -# define FSI_PUTNXTFREE(p,v) fat_putuint32(UBYTE_PTR(p,FSI_NXTFREE),v) -# define FSI_PUTTRAILSIG(p,v) fat_putuint32(UBYTE_PTR(p,FSI_TRAILSIG),v) - -#else - -/* But nothing special has to be done for the little endian-case for access - * to aligned mulitbyte values. - */ - -# define MBR_GETRESVDSECCOUNT(p) UINT16_VAL(p,BS_RESVDSECCOUNT) -# define MBR_GETFATSZ16(p) UINT16_VAL(p,BS_FATSZ16) -# define MBR_GETSECPERTRK(p) UINT16_VAL(p,BS_SECPERTRK) -# define MBR_GETNUMHEADS(p) UINT16_VAL(p,BS_NUMHEADS) -# define MBR_GETHIDSEC(p) UINT32_VAL(p,BS_HIDSEC) -# define MBR_GETTOTSEC32(p) UINT32_VAL(p,BS_TOTSEC32) -# define MBR_GETFATSZ32(p) UINT32_VAL(p,BS32_FATSZ32) -# define MBR_GETEXTFLAGS(p) UINT16_VAL(p,BS32_EXTFLAGS) -# define MBR_GETFSVER(p) UINT16_VAL(p,BS32_FSVER) -# define MBR_GETROOTCLUS(p) UINT32_VAL(p,BS32_ROOTCLUS) -# define MBR_GETFSINFO(p) UINT16_VAL(p,BS32_FSINFO) -# define MBR_GETBKBOOTSEC(p) UINT16_VAL(p,BS32_BKBOOTSEC) -# define MBR_GETSIGNATURE(p) UINT16_VAL(p,BS_SIGNATURE) - -# define MBR_GETPARTSECTOR(s) (*((uint32*)(s))) - -# define FSI_GETLEADSIG(p) UINT32_VAL(p,FSI_LEADSIG) -# define FSI_GETSTRUCTSIG(p) UINT32_VAL(p,FSI_STRUCTSIG) -# define FSI_GETFREECOUNT(p) UINT32_VAL(p,FSI_FREECOUNT) -# define FSI_GETNXTFREE(p) UINT32_VAL(p,FSI_NXTFREE) -# define FSI_GETTRAILSIG(p) UINT32_VAL(p,FSI_TRAILSIG) - -# define MBR_PUTRESVDSECCOUNT(p,v) UINT16_PUT(p,BS_RESVDSECCOUNT,v) -# define MBR_PUTFATSZ16(p,v) UINT16_PUT(p,BS_FATSZ16,v) -# define MBR_PUTSECPERTRK(p,v) UINT16_PUT(p,BS_SECPERTRK,v) -# define MBR_PUTNUMHEADS(p,v) UINT16_PUT(p,BS_NUMHEADS,v) -# define MBR_PUTHIDSEC(p,v) UINT32_PUT(p,BS_HIDSEC,v) -# define MBR_PUTTOTSEC32(p,v) UINT32_PUT(p,BS_TOTSEC32,v) -# define MBR_PUTFATSZ32(p,v) UINT32_PUT(p,BS32_FATSZ32,v) -# define MBR_PUTEXTFLAGS(p,v) UINT16_PUT(p,BS32_EXTFLAGS,v) -# define MBR_PUTFSVER(p,v) UINT16_PUT(p,BS32_FSVER,v) -# define MBR_PUTROOTCLUS(p,v) UINT32_PUT(p,BS32_ROOTCLUS,v) -# define MBR_PUTFSINFO(p,v) UINT16_PUT(p,BS32_FSINFO,v) -# define MBR_PUTBKBOOTSEC(p,v) UINT16_PUT(p,BS32_BKBOOTSEC,v) -# define MBR_PUTSIGNATURE(p,v) UINT16_PUT(p,BS_SIGNATURE,v) - -# define FSI_PUTLEADSIG(p) UINT32_PUT(p,FSI_LEADSIG) -# define FSI_PUTSTRUCTSIG(p) UINT32_PUT(p,FSI_STRUCTSIG) -# define FSI_PUTFREECOUNT(p) UINT32_PUT(p,FSI_FREECOUNT) -# define FSI_PUTNXTFREE(p) UINT32_PUT(p,FSI_NXTFREE) -# define FSI_PUTTRAILSIG(p) UINT32_PUT(p,FSI_TRAILSIG) - -#endif - /**************************************************************************** * Private Types ****************************************************************************/ @@ -221,8 +67,8 @@ * Private Function Prototypes ****************************************************************************/ -static int fat_open(FAR struct file *filp, FAR struct inode *inode, - const char *rel_path, int oflags, mode_t mode); +static int fat_open(FAR struct file *filp, const char *rel_path, + int oflags, mode_t mode); static int fat_close(FAR struct file *filp); static ssize_t fat_read(FAR struct file *filp, char *buffer, size_t buflen); static ssize_t fat_write(FAR struct file *filp, const char *buffer, @@ -263,550 +109,181 @@ const struct mountpt_operations fat_operations = ****************************************************************************/ /**************************************************************************** - * Name: fat_getuint16 - ****************************************************************************/ - -static uint16 fat_getuint16(ubyte *ptr) -{ -#ifdef CONFIG_ARCH_BIGENDIAN - /* The bytes always have to be swapped if the target is big-endian */ - - return ((uint16)ptr[0] << 8) | ptr[1]; -#else - /* Byte-by-byte transfer is still necessary if the address is un-aligned */ - - return ((uint16)ptr[1] << 8) | ptr[0]; -#endif -} - -/**************************************************************************** - * Name: fat_getuint32 - ****************************************************************************/ - -static uint32 fat_getuint32(ubyte *ptr) -{ -#ifdef CONFIG_ARCH_BIGENDIAN - /* The bytes always have to be swapped if the target is big-endian */ - - return ((uint32)fat_getuint16(&ptr[0]) << 16) | fat_getuint16(&ptr[2]); -#else - /* Byte-by-byte transfer is still necessary if the address is un-aligned */ - - return ((uint32)fat_getuint16(&ptr[2]) << 16) | fat_getuint16(&ptr[0]); -#endif -} - -/**************************************************************************** - * Name: fat_putuint16 + * Name: fat_open ****************************************************************************/ -static void fat_putuint16(ubyte *ptr, uint16 value16) +static int fat_open(FAR struct file *filp, const char *rel_path, + int oflags, mode_t mode) { - ubyte *val = (ubyte*)&value16; -#ifdef CONFIG_ARCH_BIGENDIAN - /* The bytes always have to be swapped if the target is big-endian */ - - ptr[0] = val[1]; - ptr[1] = val[0]; -#else - /* Byte-by-byte transfer is still necessary if the address is un-aligned */ - - ptr[0] = val[0]; - ptr[1] = val[1]; -#endif -} + struct fat_dirinfo_s dirinfo; + struct inode *inode; + struct fat_mountpt_s *fs; + struct fat_file_s *ff; + int ret; -/**************************************************************************** - * Name: fat_putuint32 - ****************************************************************************/ + /* Sanity checks */ -static void fat_putuint32(ubyte *ptr, uint32 value32) -{ - uint16 *val = (uint16*)&value32; -#ifdef CONFIG_ARCH_BIGENDIAN - /* The bytes always have to be swapped if the target is big-endian */ + DEBUGASSERT(filp->f_priv == NULL && filp->f_inode != NULL); - fat_putuint16(&ptr[0], val[2]); - fat_putuint16(&ptr[2], val[0]); -#else - /* Byte-by-byte transfer is still necessary if the address is un-aligned */ + /* Get the mountpoint inode reference from the file structure and the + * mountpoint private data from the inode structure + */ - fat_putuint16(&ptr[0], val[0]); - fat_putuint16(&ptr[2], val[2]); -#endif -} + inode = filp->f_inode; + fs = inode->i_private; -/**************************************************************************** - * Name: fat_semtake - ****************************************************************************/ + DEBUGASSERT(fs != NULL); -static void fat_semtake(struct fat_mountpt_s *fs) -{ - /* Take the semaphore (perhaps waiting) */ + /* Check if the mount is still healthy */ - while (sem_wait(&fs->fs_sem) != 0) + fat_semtake(fs); + ret = fat_checkmount(fs); + if (ret != OK) { - /* The only case that an error should occur here is if - * the wait was awakened by a signal. - */ - - ASSERT(*get_errno_ptr() == EINTR); + goto errout_with_semaphore; } -} -/**************************************************************************** - * Name: fat_semgive - ****************************************************************************/ + /* Initialize the directory info structure */ -static inline void fat_semgive(struct fat_mountpt_s *fs) -{ - sem_post(&fs->fs_sem); -} + memset(&dirinfo, 0, sizeof(struct fat_dirinfo_s)); + dirinfo.fs = fs; -/**************************************************************************** - * Name: fat_checkmount - * - * Desciption: Check if the mountpoint is still valid. - * - * The caller should hold the mountpoint semaphore - * - ****************************************************************************/ + /* Locate the directory entry for this path */ -static int fat_checkmount(struct fat_mountpt_s *fs) -{ - /* If the fs_mounted flag is FALSE, then we have already handled the loss - * of the mount. + ret = fat_finddirentry(&dirinfo, rel_path); + + /* Three possibililities: (1) a node exists for the rel_path and + * dirinfo describes the directory entry of the entity, (2) the + * node does not exist, or (3) some error occurred. */ - if (fs->fs_mounted) + if (ret == OK) { - struct fat_file_s *file; + boolean readonly; - /* We still think the mount is healthy. Check an see if this is - * still the case - */ + /* The name exists -- but is it a file or a directory? */ - if (fs->fs_blkdriver) + if (dirinfo.fd_entry == NULL || + (DIR_GETATTRIBUTES(dirinfo.fd_entry) & FATATTR_DIRECTORY)) { - struct inode *inode = fs->fs_blkdriver; - if (inode && inode->u.i_bops && inode->u.i_bops->geometry) - { - struct geometry geo; - int errcode = inode->u.i_bops->geometry(inode, &geo); - if (errcode == OK && geo.geo_available && !geo.geo_mediachanged) - { - return OK; - } - } + /* It is a directory */ + ret = -EISDIR; + goto errout_with_semaphore; } - /* If we get here, the mount is NOT healthy */ + /* It would be an error if we are asked to create it exclusively */ - fs->fs_mounted = FALSE; + if ((oflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) + { + /* Already exists -- can't create it exclusively */ + ret = -EEXIST; + goto errout_with_semaphore; + } - /* Make sure that this is flagged in every opened file */ +#ifdef CONFIG_FILE_MODE +# warning "Missing check for privileges based on inode->i_mode" +#endif - for (file = fs->fs_head; file; file = file->ff_next) - { - file->ff_open = FALSE; - } - } - return -ENODEV; -} + /* Check if the caller has sufficient privileges to open the file */ -/**************************************************************************** - * Name: fat_bread - * - * Desciption: Read the specified sector - * - ****************************************************************************/ + readonly = ((DIR_GETATTRIBUTES(dirinfo.fd_entry) & FATATTR_READONLY) != 0); + if (((oflags && O_WRONLY) != 0) && readonly) + { + ret = -EACCES; + goto errout_with_semaphore; + } -static int fat_bread(struct fat_mountpt_s *fs, size_t sector) -{ - int ret = -ENODEV; - if (fs && fs->fs_blkdriver ) - { - struct inode *inode = fs->fs_blkdriver; - if (inode && inode->u.i_bops && inode->u.i_bops->read) + /* If O_TRUNC is specified and the file is opened for writing, + * then truncate the file. This operation requires that the file is + * writable, but we have already checked that. O_TRUNC without write + * access is ignored. + */ + + if ((oflags & (O_TRUNC|O_WRONLY)) == (O_TRUNC|O_WRONLY)) { - ssize_t nSectorsRead = inode->u.i_bops->read(inode, fs->fs_buffer, - sector, 1); - if (nSectorsRead == 1) - { - ret = OK; - } - else if (nSectorsRead < 0) + /* Truncate the file to zero length */ + + ret = fat_dirtruncate(fs, &dirinfo); + if (ret < 0) { - ret = nSectorsRead; + goto errout_with_semaphore; } } - } - return ret; -} -/**************************************************************************** - * Name: fat_readfsinfo - * - * Desciption: Read the FAT32 FSINFO sector - * - ****************************************************************************/ + /* fall through to finish the file open operations */ -static int fat_readfsinfo(struct fat_mountpt_s *fs) -{ - /* Verify that this is, indeed, an FSINFO sector */ - - if (FSI_GETLEADSIG(fs->fs_buffer) == 0x41615252 && - FSI_GETSTRUCTSIG(fs->fs_buffer) == 0x61417272 && - FSI_GETTRAILSIG(fs->fs_buffer) == 0xaa550000) - { - fs->fs_fsinextfree = FSI_GETFREECOUNT(fs->fs_buffer); - fs->fs_fsifreecount = FSI_GETNXTFREE(fs->fs_buffer); - return OK; } - return -ENODEV; -} - -/**************************************************************************** - * Name: fat_checkbootrecord - * - * Desciption: Read a sector and verify that it is a a FAT boot record. - * - ****************************************************************************/ - -static int fat_checkbootrecord(struct fat_mountpt_s *fs) -{ - uint32 ndatasectors; - uint32 fatsize; - uint16 rootdirsectors = 0; - boolean notfat32 = FALSE; - - /* Verify the MBR signature at offset 510 in the sector (true even - * if the sector size is greater than 512. All FAT file systems have - * this signature. On a FAT32 volume, the RootEntCount , FatSz16, and - * FatSz32 values should always be zero. The FAT sector size should - * match the reported hardware sector size. - */ - - if (MBR_GETSIGNATURE(fs->fs_buffer) != 0xaa55 || - MBR_GETBYTESPERSEC(fs->fs_buffer) != fs->fs_hwsectorsize) + else if (ret == -ENOENT) { - return -ENODEV; - } - - /* Verify the FAT32 file system type. The determination of the file - * system type is based on the number of clusters on the volume: FAT12 - * volume has < 4085 cluseter, a FAT16 volume has fewer than 65,525 - * clusters, and any larger is FAT32. - * - * Get the number of 32-bit directory entries in root directory (zero - * for FAT32. - */ - - fs->fs_rootentcnt = MBR_GETROOTENTCNT(fs->fs_buffer); - if (fs->fs_rootentcnt != 0) - { - notfat32 = TRUE; /* Must be zero for FAT32 */ - rootdirsectors = (32 * fs->fs_rootentcnt + fs->fs_hwsectorsize - 1) / fs->fs_hwsectorsize; - } - - /* Determine the number of sectors in a FAT. */ + /* The file does not exist. Were we asked to create it? */ - fs->fs_fatsize = MBR_GETFATSZ16(fs->fs_buffer); /* Should be zero */ - if (fs->fs_fatsize) - { - notfat32 = TRUE; /* Must be zero for FAT32 */ - } - else - { - fs->fs_fatsize = MBR_GETFATSZ32(fs->fs_buffer); - } + if ((oflags && O_CREAT) == 0) + { + /* No.. then we fail with -ENOENT */ + ret = -ENOENT; + goto errout_with_semaphore; + } - if (!fs->fs_fatsize || fs->fs_fatsize >= fs->fs_hwnsectors) - { - return -ENODEV; - } + /* Yes.. create the file */ - /* Get the total number of sectors on the volume. */ + ret = fat_dircreate(fs, &dirinfo); + if ( ret < 0) + { + goto errout_with_semaphore; + } - fs->fs_fattotsec = MBR_GETTOTSEC16(fs->fs_buffer); /* Should be zero */ - if (fs->fs_fattotsec) - { - notfat32 = TRUE; /* Must be zero for FAT32 */ + /* Fall through to finish the file open operation */ } else { - fs->fs_fattotsec = MBR_GETTOTSEC32(fs->fs_buffer); - } - - if (!fs->fs_fattotsec || fs->fs_fattotsec > fs->fs_hwnsectors) - { - return -ENODEV; - } - - /* Get the total number of reserved sectors */ - - fs->fs_fatresvdseccount = MBR_GETRESVDSECCOUNT(fs->fs_buffer); - if (fs->fs_fatresvdseccount > fs->fs_hwnsectors) - { - return -ENODEV; - } - - /* Get the number of FATs. This is probably two but could have other values */ - - fs->fs_fatnumfats = MBR_GETNUMFATS(fs->fs_buffer); - fatsize = fs->fs_fatnumfats * fs->fs_fatsize; - - /* Get the total number of data sectors */ - - ndatasectors = fs->fs_fattotsec - fs->fs_fatresvdseccount - fatsize - rootdirsectors; - if (ndatasectors > fs->fs_hwnsectors) - { - return -ENODEV; - } - - /* Get the sectors per cluster */ - - fs->fs_fatsecperclus = MBR_GETSECPERCLUS(fs->fs_buffer); - - /* Calculate the number of clusters */ - - fs->fs_nclusters = ndatasectors / fs->fs_fatsecperclus; - - /* Finally, the test: */ - - if (fs->fs_nclusters < 4085) - { - fs->fs_fsinfo = 0; - fs->fs_type = FSTYPE_FAT12; - } - else if (fs->fs_nclusters < 65525) - { - fs->fs_fsinfo = 0; - fs->fs_type = FSTYPE_FAT16; - } + /* An error occurred while checking for file existence -- + * such as if an invalid path were provided. + */ - else if (!notfat32) - { - fs->fs_fsinfo = fs->fs_fatbase + MBR_GETFSINFO(fs->fs_buffer); - fs->fs_type = FSTYPE_FAT32; - } - else - { - return -ENODEV; + goto errout_with_semaphore; } - /* We have what appears to be a valid FAT filesystem! Save a few more things - * from the boot record that we will need later. + /* Create an instance of the file private date to describe the opened + * file. */ - fs->fs_fatbase += fs->fs_fatresvdseccount; - - if (fs->fs_type == FSTYPE_FAT32) - { - fs->fs_rootbase = MBR_GETROOTCLUS(fs->fs_buffer); - } - else - { - fs->fs_rootbase = fs->fs_fatbase + fatsize; - } - - fs->fs_database = fs->fs_fatbase + fatsize + fs->fs_rootentcnt / (fs->fs_hwsectorsize / 32); - fs->fs_fsifreecount = 0xffffffff; - - return OK; -} - -/**************************************************************************** - * Name: fat_mount - * - * Desciption: This function is called only when the mountpoint is first - * established. It initializes the mountpoint structure and verifies - * that a valid FAT32 filesystem is provided by the block driver. - * - * The caller should hold the mountpoint semaphore - * - ****************************************************************************/ - -static int fat_mount(struct fat_mountpt_s *fs, boolean writeable) -{ - FAR struct inode *inode; - struct geometry geo; - int ret; - - /* Assume that the mount is successful */ - - fs->fs_mounted = TRUE; - - /* Check if there is media available */ - - inode = fs->fs_blkdriver; - if (!inode || !inode->u.i_bops || !inode->u.i_bops->geometry || - inode->u.i_bops->geometry(inode, &geo) != OK || !geo.geo_available) - { - ret = -ENODEV; - goto errout; - } - - /* Make sure that that the media is write-able (if write access is needed) */ - - if (writeable && !geo.geo_writeenabled) - { - ret = -EACCES; - goto errout; - } - - /* Save the hardware geometry */ - - fs->fs_hwsectorsize = geo.geo_sectorsize; - fs->fs_hwnsectors = geo.geo_nsectors; - - /* Allocate a buffer to hold one hardware sector */ - - fs->fs_buffer = (ubyte*)malloc(fs->fs_hwsectorsize); - if (!fs->fs_buffer) + ff = (struct fat_file_s *)zalloc(sizeof(struct fat_file_s)); + if (!ff) { ret = -ENOMEM; - goto errout; - } - - /* Search FAT boot record on the drive. First check at sector zero. This - * could be either the boot record or a partition that refers to the boot - * record. - * - * First read sector zero. This will be the first access to the drive and a - * likely failure point. - */ - - fs->fs_fatbase = 0; - ret = fat_bread(fs, 0); - if (ret < 0) - { - goto errout_with_buffer; - } - - if (fat_checkbootrecord(fs) != OK) - { - /* The contents of sector 0 is not a boot record. It could be a - * partition, however. Assume it is a partition and get the offset - * into the partition table. This table is at offset MBR_TABLE and is - * indexed by 16x the partition number. Here we support only - * parition 0. - */ - - ubyte *partition = &fs->fs_buffer[MBR_TABLE + 0]; - - /* Check if the partition exists and, if so, get the bootsector for that - * partition and see if we can find the boot record there. - */ - - if (partition[4]) - { - /* There appears to be a partition, get the sector number of the - * partition (LBA) - */ - - fs->fs_fatbase = MBR_GETPARTSECTOR(&partition[8]); - - /* Read the new candidate boot sector */ - - ret = fat_bread(fs, 0); - if (ret < 0) - { - goto errout_with_buffer; - } - - /* Check if this is a boot record */ - - if (fat_checkbootrecord(fs) != OK) - { - goto errout_with_buffer; - } - } + goto errout_with_semaphore; } + + /* Initialize the file private data (only need to initialize non-zero elements) */ - /* We have what appears to be a valid FAT filesystem! Now read the - * FSINFO sector (FAT32 only) - */ + ff->ff_open = TRUE; + ff->ff_oflags = oflags; + ff->ff_sectorsincluster = 1; - if (fs->fs_type == FSTYPE_FAT32) - { - ret = fat_readfsinfo(fs); - if (ret != OK) - { - goto errout_with_buffer; - } - } - - /* We did it! */ - - dbg("FAT%d:\n", fs->fs_type == 0 ? 12 : fs->fs_type == 1 ? 16 : 32); - dbg("\tHW sector size: %d\n", fs->fs_hwsectorsize); - dbg("\t sectors: %d\n", fs->fs_hwnsectors); - dbg("\tFAT reserved: %d\n", fs->fs_fatresvdseccount); - dbg("\t sectors: %d\n", fs->fs_fattotsec); - dbg("\t start sector: %d\n", fs->fs_fatbase); - dbg("\t root sector: %d\n", fs->fs_rootbase); - dbg("\t root entries: %d\n", fs->fs_rootentcnt); - dbg("\t data sector: %d\n", fs->fs_database); - dbg("\t FSINFO sector: %d\n", fs->fs_fsinfo); - dbg("\t Num FATs: %d\n", fs->fs_fatnumfats); - dbg("\t FAT size: %d\n", fs->fs_fatsize); - dbg("\t sectors/cluster: %d\n", fs->fs_fatsecperclus); - dbg("\t max clusters: %d\n", fs->fs_nclusters); - dbg("\tFSI free count %d\n", fs->fs_fsifreecount); - dbg("\t next free %d\n", fs->fs_fsinextfree); + /* Save information that can be used later to recover the directory entry */ - return OK; + ff->ff_dirsector = fs->fs_sector; + ff->ff_dirindex = dirinfo.fd_index; - errout_with_buffer: - free(fs->fs_buffer); - fs->fs_buffer = 0; - errout: - fs->fs_mounted = FALSE; - return ret; -} + /* File cluster/size info */ -/**************************************************************************** - * Name: fat_open - ****************************************************************************/ + ff->ff_startcluster = + ((uint32)DIR_GETFSTCLUSTHI(dirinfo.fd_entry) << 16) | + DIR_GETFSTCLUSTLO(dirinfo.fd_entry); -static int fat_open(FAR struct file *filp, FAR struct inode *inode, - const char *rel_path, int oflags, mode_t mode) -{ - struct fat_mountpt_s *fs = (struct fat_mountpt_s *)inode->i_private; - struct fat_file_s *ff; - int ret = OK; - - /* Make sure that the mount is still healthy */ - if (!fs) - { - ret = -ENOSYS; - goto errout; - } + ff->ff_size = DIR_GETFILESIZE(dirinfo.fd_entry); - fat_semtake(fs); - ret = fat_checkmount(fs); - if (ret != OK) - { - goto errout_with_semaphore; - } + /* In write/append mode, we need to set the file pointer to the end of the file */ - /* Allocate a new private instance for the struct file */ - - ff = (struct fat_file_s *)malloc(sizeof(struct fat_file_s)); - if (!ff) + if ((oflags && (O_APPEND|O_WRONLY)) == (O_APPEND|O_WRONLY)) { - ret = -ENOMEM; - goto errout_with_semaphore; + ff->ff_position = ff->ff_size; } + return OK; - /* Find the requested path and open or create the file */ -#warning "Open logic missing" + /* Attach the private date to the struct file instance */ - /* Initialize the new private instance */ - - ff->ff_parent = fs; - ff->ff_open = TRUE; + filp->f_priv = ff; /* Then insert the new instance into the mountpoint structure. * It needs to be there (1) to handle error conditions that effect @@ -820,11 +297,10 @@ static int fat_open(FAR struct file *filp, FAR struct inode *inode, fat_semgive(fs); return OK; - errout_with_alloc: - free(ff); + /* Error exits */ + errout_with_semaphore: fat_semgive(fs); - errout: return ret; } @@ -834,13 +310,21 @@ static int fat_open(FAR struct file *filp, FAR struct inode *inode, static int fat_close(FAR struct file *filp) { - struct fat_file_s *ff = filp->f_priv; + struct inode *inode; struct fat_mountpt_s *fs; + struct fat_file_s *ff; - if (!ff || !(fs = ff->ff_parent)) - { - return -EINVAL; - } + /* Sanity checks */ + + DEBUGASSERT(filp->f_priv != NULL && filp->f_inode != NULL); + + /* Recover our private data from struct file instance */ + + ff = filp->f_priv; + inode = filp->f_inode; + fs = inode->i_private; + + DEBUGASSERT(fs != NULL); /* Do not check if the mount is healthy. We must support closing of * the file even when there is healthy mount. @@ -855,14 +339,22 @@ static int fat_close(FAR struct file *filp) static ssize_t fat_read(FAR struct file *filp, char *buffer, size_t buflen) { - struct fat_file_s *ff = filp->f_priv; + struct inode *inode; struct fat_mountpt_s *fs; - int ret; + struct fat_file_s *ff; + int ret; - if (!ff || !(fs = ff->ff_parent)) - { - return -EINVAL; - } + /* Sanity checks */ + + DEBUGASSERT(filp->f_priv != NULL && filp->f_inode != NULL); + + /* Recover our private data from struct file instance */ + + ff = filp->f_priv; + inode = filp->f_inode; + fs = inode->i_private; + + DEBUGASSERT(fs != NULL); /* Make sure that the mount is still healthy */ @@ -881,14 +373,22 @@ static ssize_t fat_read(FAR struct file *filp, char *buffer, size_t buflen) static ssize_t fat_write(FAR struct file *filp, const char *buffer, size_t buflen) { - struct fat_file_s *ff = filp->f_priv; + struct inode *inode; struct fat_mountpt_s *fs; - int ret; + struct fat_file_s *ff; + int ret; - if (!ff || !(fs = ff->ff_parent)) - { - return -EINVAL; - } + /* Sanity checks */ + + DEBUGASSERT(filp->f_priv != NULL && filp->f_inode != NULL); + + /* Recover our private data from struct file instance */ + + ff = filp->f_priv; + inode = filp->f_inode; + fs = inode->i_private; + + DEBUGASSERT(fs != NULL); /* Make sure that the mount is still healthy */ @@ -906,14 +406,22 @@ static ssize_t fat_write(FAR struct file *filp, const char *buffer, static off_t fat_seek(FAR struct file *filp, off_t offset, int whence) { - struct fat_file_s *ff = filp->f_priv; + struct inode *inode; struct fat_mountpt_s *fs; - int ret; + struct fat_file_s *ff; + int ret; - if (!ff || !(fs = ff->ff_parent)) - { - return -EINVAL; - } + /* Sanity checks */ + + DEBUGASSERT(filp->f_priv != NULL && filp->f_inode != NULL); + + /* Recover our private data from struct file instance */ + + ff = filp->f_priv; + inode = filp->f_inode; + fs = inode->i_private; + + DEBUGASSERT(fs != NULL); /* Make sure that the mount is still healthy */ @@ -931,14 +439,22 @@ static off_t fat_seek(FAR struct file *filp, off_t offset, int whence) static int fat_ioctl(FAR struct file *filp, int cmd, unsigned long arg) { - struct fat_file_s *ff = filp->f_priv; + struct inode *inode; struct fat_mountpt_s *fs; - int ret; + struct fat_file_s *ff; + int ret; - if (!ff || !(fs = ff->ff_parent)) - { - return -EINVAL; - } + /* Sanity checks */ + + DEBUGASSERT(filp->f_priv != NULL && filp->f_inode != NULL); + + /* Recover our private data from struct file instance */ + + ff = filp->f_priv; + inode = filp->f_inode; + fs = inode->i_private; + + DEBUGASSERT(fs != NULL); /* Make sure that the mount is still healthy */ diff --git a/nuttx/fs/fs_fat32.h b/nuttx/fs/fs_fat32.h index 59588616a..ecb5ff66c 100644 --- a/nuttx/fs/fs_fat32.h +++ b/nuttx/fs/fs_fat32.h @@ -1,5 +1,5 @@ /**************************************************************************** - * fs_fat.h + * fs_fat32.h * * Copyright (C) 2007 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <spudmonkey@racsa.co.cr> @@ -105,12 +105,65 @@ #define BS_SIGNATURE 510 /* 2@510: Valid MBRs have 0x55aa here */ +/**************************************************************************** + * Each FAT directory entry is 32-bytes long. The following define offsets + * relative to the beginning of a directory entry. + */ + +#define DIR_NAME 0 /* 11@ 0: NAME: 8 bytes + 3 byte extension */ +#define DIR_ATTRIBUTES 11 /* 1@11: File attibutes (see below) */ +#define DIR_NTRES 12 /* 1@12: Reserved for use by NT */ +#define DIR_CRTTIMETENTH 13 /* 1@13: Tenth sec creation timestamp */ +#define DIR_CRTIME 14 /* 2@14: Time file created */ +#define DIR_CRDATE 16 /* 2@16: Date file created */ +#define DIR_LASTACCDATE 18 /* 2@19: Last access date */ +#define DIR_FSTCLUSTHI 20 /* 2@20: MS first cluster number */ +#define DIR_WRTTIME 22 /* 2@22: Time of last write */ +#define DIR_WRTDATE 24 /* 2@24: Date of last write */ +#define DIR_FSTCLUSTLO 26 /* 2@26: LS first cluster number */ +#define DIR_FILESIZE 28 /* 4@28: File size in bytes */ + +/* First byte of the directory name has special meanings: */ + +#define DIR0_EMPTY 0xe5 /* The directory entry is empty */ +#define DIR0_ALLEMPTY 0x00 /* This entry and all following are empty */ +#define DIR0_E5 0x05 /* The actual value is 0xe5 */ + +/* NTRES flags in the FAT directory */ + +#define FATNTRES_LCNAME 0x08 /* Lower case in name */ +#define FATNTRES_LCEXT 0x10 /* Lower case in extension */ + +/* File attribute bits in FAT directory entry */ + +#define FATATTR_READONLY 0x01 +#define FATATTR_HIDDEN 0x02 +#define FATATTR_SYSTEM 0x04 +#define FATATTR_VOLUMEID 0x08 +#define FATATTR_DIRECTORY 0x10 +#define FATATTR_ARCHIVE 0x20 + +#define FATATTR_LONGNAME \ + (FATATTR_READONLY|FATATTR_HIDDEN|FATATTR_SYSTEM|FATATTR_VOLUMEID) + /* File system types */ #define FSTYPE_FAT12 0 #define FSTYPE_FAT16 1 #define FSTYPE_FAT32 2 +/* Directory indexing helper. Each directory entry is 32-bytes in length. + * The number of directory entries in a sector then varies with the size + * of the sector supported in hardware. + */ + +#define DIRSEC_NDXMASK(f) (((f)->fs_hwsectorsize - 1) >> 5) +#define DIRSEC_NDIRS(f) (((f)->fs_hwsectorsize) >> 5) +#define DIRSEC_BYTENDX(f,i) (((i) & DIRSEC_NDXMASK(fs)) << 5) + +#define SEC_NDXMASK(f) ((f)->fs_hwsectorsize - 1) +#define SEC_NSECTORS(f,n) ((n) / (f)->fs_hwsectorsize) + /**************************************************************************** * These offset describe the FSINFO sector */ @@ -124,37 +177,223 @@ #define FSI_TRAILSIG 508 /* 4@508: 0xaa550000 */ /**************************************************************************** - * Public Types - ****************************************************************************/ + * Access to data in raw sector data */ -struct fat_direntry_s -{ - ubyte fde_name[8]; /* name */ - ubyte fde_ext[3]; /* name and extension */ - ubyte fde_attr; /* attribute bits */ - ubyte fde_lcase; /* Case for base and extension */ - ubyte fde_ctimecs; /* Creation time, centiseconds (0-199) */ - ubyte fde_ctime[2]; /* Creation time */ - ubyte fde_cdate[2]; /* Creation date */ - ubyte fde_adate[2]; /* Last access date */ - ubyte fde_starthi[2]; /* High 16 bits of cluster in FAT32 */ - ubyte fde_time[2]; /* Date */ - ubyte fde_date[2]; /* Time */ - ubyte fde_start[2]; /* First cluster */ - ubyte fde_size[4]; /* file size (in bytes) */ -}; +#define UBYTE_VAL(p,o) (((ubyte*)(p))[o]) +#define UBYTE_PTR(p,o) &UBYTE_VAL(p,o) +#define UBYTE_PUT(p,o,v) (UBYTE_VAL(p,o)=(ubyte)(v)) -struct fat_dirslot_s -{ - ubyte fds_id; /* sequence number for slot */ - ubyte fds_name0_4[10]; /* first 5 characters in name */ - ubyte fds_attr; /* attribute byte */ - ubyte fds_reserved; /* always 0 */ - ubyte fds_alias_checksum; /* checksum for 8.3 alias */ - ubyte fds_name5_10[12]; /* 6 more characters in name */ - ubyte fds_start[2]; /* starting cluster number, 0 in long slots */ - ubyte fds_name11_12[4]; /* last 2 characters in name */ -}; +#define UINT16_PTR(p,o) ((uint16*)UBYTE_PTR(p,o)) +#define UINT16_VAL(p,o) (*UINT16_PTR(p,o)) +#define UINT16_PUT(p,o,v) (UINT16_VAL(p,o)=(uint16)(v)) + +#define UINT32_PTR(p,o) ((uint32*)UBYTE_PTR(p,o)) +#define UINT32_VAL(p,o) (*UINT32_PTR(p,o)) +#define UINT32_PUT(p,o,v) (UINT32_VAL(p,o)=(uint32)(v)) + +/* Regardless of the endian-ness of the target or alignment of the data, no + * special operations are required for byte, string or byte array accesses. + * The FAT data stream is little endian so multiple byte values must be + * accessed byte-by-byte for big-endian targets. + */ + +#define MBR_GETSECPERCLUS(p) UBYTE_VAL(p,BS_SECPERCLUS) +#define MBR_GETNUMFATS(p) UBYTE_VAL(p,BS_NUMFATS) +#define MBR_GETMEDIA(p) UBYTE_VAL(p,BS_MEDIA) +#define MBR_GETDRVNUM16(p) UBYTE_VAL(p,BS16_DRVNUM) +#define MBR_GETDRVNUM32(p) UBYTE_VAL(p,BS32_DRVNUM) +#define MBR_GETBOOTSIG16(p) UBYTE_VAL(p,BS16_BOOTSIG) +#define MBR_GETBOOTSIG32(p) UBYTE_VAL(p,BS32_BOOTSIG) + +#define DIR_GETATTRIBUTES(p) UBYTE_VAL(p,DIR_ATTRIBUTES) +#define DIR_GETNTRES(p) UBYTE_VAL(p,DIR_NTRES) +#define DIR_GETCRTTIMETENTH(p) UBYTE_VAL(p,DIR_CRTTIMETENTH) + +#define MBR_PUTSECPERCLUS(p,v) UBYTE_PUT(p,BS_SECPERCLUS),v) +#define MBR_PUTNUMFATS(p,v) UBYTE_PUT(p,BS_NUMFATS,v) +#define MBR_PUTMEDIA(p,v) UBYTE_PUT(p,BS_MEDIA,v) +#define MBR_PUTDRVNUM16(p,v) UBYTE_PUT(p,BS16_DRVNUM,v) +#define MBR_PUTDRVNUM32(p,v) UBYTE_PUT(p,BS32_DRVNUM,v) +#define MBR_PUTBOOTSIG16(p,v) UBYTE_PUT(p,BS16_BOOTSIG,v) +#define MBR_PUTBOOTSIG32(p,v) UBYTE_PUT(p,BS32_BOOTSIG,v) + +#define DIR_PUTATTRIBUTES(p,v) UBYTE_PUT(p,DIR_ATTRIBUTES,v) +#define DIR_PUTNTRES(p,v) UBYTE_PUT(p,DIR_NTRES,v) +#define DIR_PUTCRTTIMETENTH(p,v) UBYTE_PUT(p,DIR_CRTTIMETENTH,v) + +/* For the all targets, unaligned values need to be accessed byte-by-byte. + * Some architectures may handle unaligned accesses with special interrupt + * handlers. But even in that case, it is more efficient to avoid the traps. + */ + +/* Unaligned multi-byte access macros */ + +#define MBR_GETBYTESPERSEC(p) fat_getuint16(UBYTE_PTR(p,BS_BYTESPERSEC)) +#define MBR_GETROOTENTCNT(p) fat_getuint16(UBYTE_PTR(p,BS_ROOTENTCNT)) +#define MBR_GETTOTSEC16(p) fat_getuint16(UBYTE_PTR(p,BS_TOTSEC16)) +#define MBR_GETVOLID16(p) fat_getuint32(UBYTE_PTR(p,BS16_VOLID)) +#define MBR_GETVOLID32(p) fat_getuint32(UBYTE_PTR(p,BS32_VOLID)) + +#define MBR_PUTBYTESPERSEC(p,v) fat_putuint16(UBYTE_PTR(p,BS_BYTESPERSEC),v) +#define MBR_PUTROOTENTCNT(p,v) fat_putuint16(UBYTE_PTR(p,BS_ROOTENTCNT),v) +#define MBR_PUTTOTSEC16(p,v) fat_putuint16(UBYTE_PTR(p,BS_TOTSEC16),v) +#define MBR_PUTVOLID16(p,v) fat_putuint32(UBYTE_PTR(p,BS16_VOLID),v) +#define MBR_PUTVOLID32(p,v) fat_putuint32(UBYTE_PTR(p,BS32_VOLID),v) + +/* But for multi-byte values, the endian-ness of the target vs. the little + * endian order of the byte stream or alignment of the data within the byte + * stream can force special, byte-by-byte accesses. + */ + +#ifdef CONFIG_ARCH_BIGENDIAN + +/* If the target is big-endian, then even aligned multi-byte values must be + * accessed byte-by-byte. + */ + +# define MBR_GETRESVDSECCOUNT(p) fat_getuint16(UBYTE_PTR(p,BS_RESVDSECCOUNT)) +# define MBR_GETFATSZ16(p) fat_getuint16(UBYTE_PTR(p,BS_FATSZ16)) +# define MBR_GETSECPERTRK(p) fat_getuint16(UBYTE_PTR(p,BS_SECPERTRK)) +# define MBR_GETNUMHEADS(p) fat_getuint16(UBYTE_PTR(p,BS_NUMHEADS)) +# define MBR_GETHIDSEC(p) fat_getuint32(UBYTE_PTR(p,BS_HIDSEC)) +# define MBR_GETTOTSEC32(p) fat_getuint32(UBYTE_PTR(p,BS_TOTSEC32)) +# define MBR_GETFATSZ32(p) fat_getuint32(UBYTE_PTR(p,BS32_FATSZ32)) +# define MBR_GETEXTFLAGS(p) fat_getuint16(UBYTE_PTR(p,BS32_EXTFLAGS)) +# define MBR_GETFSVER(p) fat_getuint16(UBYTE_PTR(p,BS32_FSVER)) +# define MBR_GETROOTCLUS(p) fat_getuint32(UBYTE_PTR(p,BS32_ROOTCLUS)) +# define MBR_GETFSINFO(p) fat_getuint16(UBYTE_PTR(p,BS32_FSINFO)) +# define MBR_GETBKBOOTSEC(p) fat_getuint16(UBYTE_PTR(p,BS32_BKBOOTSEC)) +# define MBR_GETSIGNATURE(p) fat_getuint16(UBYTE_PTR(p,BS_SIGNATURE)) + +# define MBR_GETPARTSECTOR(s) fat_getuint32(s) + +# define FSI_GETLEADSIG(p) fat_getuint32(UBYTE_PTR(p,FSI_LEADSIG)) +# define FSI_GETSTRUCTSIG(p) fat_getuint32(UBYTE_PTR(p,FSI_STRUCTSIG)) +# define FSI_GETFREECOUNT(p) fat_getuint32(UBYTE_PTR(p,FSI_FREECOUNT)) +# define FSI_GETNXTFREE(p) fat_getuint32(UBYTE_PTR(p,FSI_NXTFREE)) +# define FSI_GETTRAILSIG(p) fat_getuint32(UBYTE_PTR(p,FSI_TRAILSIG)) + +# define DIR_GETCRTIME(p) fat_getuint16(UBYTE_PTR(p,DIR_CRTIME)) +# define DIR_GETCRDATE(p) fat_getuint16(UBYTE_PTR(p,DIR_CRDATE)) +# define DIR_GETLASTACCDATE(p) fat_getuint16(UBYTE_PTR(p,DIR_LASTACCDTE)) +# define DIR_GETFSTCLUSTHI(p) fat_getuint16(UBYTE_PTR(p,DIR_FSTCLUSTHI)) +# define DIR_GETWRTTIME(p) fat_getuint16(UBYTE_PTR(p,DIR_WRTTIME)) +# define DIR_GETWRTDATE(p) fat_getuint16(UBYTE_PTR(p,DIR_WRTDATE)) +# define DIR_GETFSTCLUSTLO(p) fat_getuint16(UBYTE_PTR(p,DIR_FSTCLUSTLO)) +# define DIR_GETFILESIZE(p) fat_getuint32(UBYTE_PTR(p,DIR_FILESIZE)) + +# define FAT_GETFAT16(p,i) fat_getuint16(UBYTE_PTR(p,i)) +# define FAT_GETFAT32(p,i) fat_getuint32(UBYTE_PTR(p,i)) + +# define MBR_PUTRESVDSECCOUNT(p,v) fat_putuint16(UBYTE_PTR(p,BS_RESVDSECCOUNT,v)) +# define MBR_PUTFATSZ16(p,v) fat_putuint16(UBYTE_PTR(p,BS_FATSZ16,v)) +# define MBR_PUTSECPERTRK(p,v) fat_putuint16(UBYTE_PTR(p,BS_SECPERTRK,v)) +# define MBR_PUTNUMHEADS(p,v) fat_putuint16(UBYTE_PTR(p,BS_NUMHEADS,v)) +# define MBR_PUTHIDSEC(p,v) fat_putuint32(UBYTE_PTR(p,BS_HIDSEC,v)) +# define MBR_PUTTOTSEC32(p,v) fat_putuint32(UBYTE_PTR(p,BS_TOTSEC32,v)) +# define MBR_PUTFATSZ32(p,v) fat_putuint32(UBYTE_PTR(p,BS32_FATSZ32,v)) +# define MBR_PUTEXTFLAGS(p,v) fat_putuint16(UBYTE_PTR(p,BS32_EXTFLAGS,v)) +# define MBR_PUTFSVER(p,v) fat_putuint16(UBYTE_PTR(p,BS32_FSVER,v)) +# define MBR_PUTROOTCLUS(p,v) fat_putuint32(UBYTE_PTR(p,BS32_ROOTCLUS,v)) +# define MBR_PUTFSINFO(p,v) fat_putuint16(UBYTE_PTR(p,BS32_FSINFO,v)) +# define MBR_PUTBKBOOTSEC(p,v) fat_putuint16(UBYTE_PTR(p,BS32_BKBOOTSEC,v)) +# define MBR_PUTSIGNATURE(p,v) fat_getuint16(UBYTE_PTR(p,BS_SIGNATURE),v) + +# define FSI_PUTLEADSIG(p,v) fat_putuint32(UBYTE_PTR(p,FSI_LEADSIG),v) +# define FSI_PUTSTRUCTSIG(p,v) fat_putuint32(UBYTE_PTR(p,FSI_STRUCTSIG),v) +# define FSI_PUTFREECOUNT(p,v) fat_putuint32(UBYTE_PTR(p,FSI_FREECOUNT),v) +# define FSI_PUTNXTFREE(p,v) fat_putuint32(UBYTE_PTR(p,FSI_NXTFREE),v) +# define FSI_PUTTRAILSIG(p,v) fat_putuint32(UBYTE_PTR(p,FSI_TRAILSIG),v) + +# define DIR_PUTCRTIME(p,v) fat_putuint16(UBYTE_PTR(p,DIR_CRTIME),v) +# define DIR_PUTCRDATE(p,v) fat_putuint16(UBYTE_PTR(p,DIR_CRDATE),v) +# define DIR_PUTLASTACCDATE(p,v) fat_putuint16(UBYTE_PTR(p,DIR_LASTACCDTE),v) +# define DIR_PUTFSTCLUSTHI(p,v) fat_putuint16(UBYTE_PTR(p,DIR_FSTCLUSTHI),v) +# define DIR_PUTWRTTIME(p,v) fat_putuint16(UBYTE_PTR(p,DIR_WRTTIME),v) +# define DIR_PUTWRTDATE(p,v) fat_putuint16(UBYTE_PTR(p,DIR_WRTDATE),v) +# define DIR_PUTFSTCLUSTLO(p,v) fat_putuint16(UBYTE_PTR(p,DIR_FSTCLUSTLO),v) +# define DIR_PUTFILESIZE(p,v) fat_putuint32(UBYTE_PTR(p,DIR_FILESIZE),v) + +# define FAT_PUTFAT16(p,i,v) fat_putuint16(UBYTE_PTR(p,i),v) +# define FAT_PUTFAT32(p,i,v) fat_putuint32(UBYTE_PTR(p,i),v) + +#else + +/* But nothing special has to be done for the little endian-case for access + * to aligned mulitbyte values. + */ + +# define MBR_GETRESVDSECCOUNT(p) UINT16_VAL(p,BS_RESVDSECCOUNT) +# define MBR_GETFATSZ16(p) UINT16_VAL(p,BS_FATSZ16) +# define MBR_GETSECPERTRK(p) UINT16_VAL(p,BS_SECPERTRK) +# define MBR_GETNUMHEADS(p) UINT16_VAL(p,BS_NUMHEADS) +# define MBR_GETHIDSEC(p) UINT32_VAL(p,BS_HIDSEC) +# define MBR_GETTOTSEC32(p) UINT32_VAL(p,BS_TOTSEC32) +# define MBR_GETFATSZ32(p) UINT32_VAL(p,BS32_FATSZ32) +# define MBR_GETEXTFLAGS(p) UINT16_VAL(p,BS32_EXTFLAGS) +# define MBR_GETFSVER(p) UINT16_VAL(p,BS32_FSVER) +# define MBR_GETROOTCLUS(p) UINT32_VAL(p,BS32_ROOTCLUS) +# define MBR_GETFSINFO(p) UINT16_VAL(p,BS32_FSINFO) +# define MBR_GETBKBOOTSEC(p) UINT16_VAL(p,BS32_BKBOOTSEC) +# define MBR_GETSIGNATURE(p) UINT16_VAL(p,BS_SIGNATURE) + +# define MBR_GETPARTSECTOR(s) (*((uint32*)(s))) + +# define FSI_GETLEADSIG(p) UINT32_VAL(p,FSI_LEADSIG) +# define FSI_GETSTRUCTSIG(p) UINT32_VAL(p,FSI_STRUCTSIG) +# define FSI_GETFREECOUNT(p) UINT32_VAL(p,FSI_FREECOUNT) +# define FSI_GETNXTFREE(p) UINT32_VAL(p,FSI_NXTFREE) +# define FSI_GETTRAILSIG(p) UINT32_VAL(p,FSI_TRAILSIG) + +# define DIR_GETCRTIME(p) UINT16_VAL(p,DIR_CRTIME) +# define DIR_GETCRDATE(p) UINT16_VAL(p,DIR_CRDATE) +# define DIR_GETLASTACCDATE(p) UINT16_VAL(p,DIR_LASTACCDTE) +# define DIR_GETFSTCLUSTHI(p) UINT16_VAL(p,DIR_FSTCLUSTHI) +# define DIR_GETWRTTIME(p) UINT16_VAL(p,DIR_WRTTIME) +# define DIR_GETWRTDATE(p) UINT16_VAL(p,DIR_WRTDATE) +# define DIR_GETFSTCLUSTLO(p) UINT16_VAL(p,DIR_FSTCLUSTLO) +# define DIR_GETFILESIZE(p) UINT32_VAL(p,DIR_FILESIZE) + +# define FAT_GETFAT16(p,i) UINT16_VAL(p,i) +# define FAT_GETFAT32(p,i) UINT32_VAL(p,i) + +# define MBR_PUTRESVDSECCOUNT(p,v) UINT16_PUT(p,BS_RESVDSECCOUNT,v) +# define MBR_PUTFATSZ16(p,v) UINT16_PUT(p,BS_FATSZ16,v) +# define MBR_PUTSECPERTRK(p,v) UINT16_PUT(p,BS_SECPERTRK,v) +# define MBR_PUTNUMHEADS(p,v) UINT16_PUT(p,BS_NUMHEADS,v) +# define MBR_PUTHIDSEC(p,v) UINT32_PUT(p,BS_HIDSEC,v) +# define MBR_PUTTOTSEC32(p,v) UINT32_PUT(p,BS_TOTSEC32,v) +# define MBR_PUTFATSZ32(p,v) UINT32_PUT(p,BS32_FATSZ32,v) +# define MBR_PUTEXTFLAGS(p,v) UINT16_PUT(p,BS32_EXTFLAGS,v) +# define MBR_PUTFSVER(p,v) UINT16_PUT(p,BS32_FSVER,v) +# define MBR_PUTROOTCLUS(p,v) UINT32_PUT(p,BS32_ROOTCLUS,v) +# define MBR_PUTFSINFO(p,v) UINT16_PUT(p,BS32_FSINFO,v) +# define MBR_PUTBKBOOTSEC(p,v) UINT16_PUT(p,BS32_BKBOOTSEC,v) +# define MBR_PUTSIGNATURE(p,v) UINT16_PUT(p,BS_SIGNATURE,v) + +# define FSI_PUTLEADSIG(p,v) UINT32_PUT(p,FSI_LEADSIG,v) +# define FSI_PUTSTRUCTSIG(p,v) UINT32_PUT(p,FSI_STRUCTSIG,v) +# define FSI_PUTFREECOUNT(p,v) UINT32_PUT(p,FSI_FREECOUNT,v) +# define FSI_PUTNXTFREE(p,v) UINT32_PUT(p,FSI_NXTFREE,v) +# define FSI_PUTTRAILSIG(p,v) UINT32_PUT(p,FSI_TRAILSIG,v) + +# define DIR_PUTCRTIME(p,v) UINT16_PUT(p,DIR_CRTIME,v) +# define DIR_PUTCRDATE(p,v) UINT16_PUT(p,DIR_CRDATE,v) +# define DIR_PUTLASTACCDATE(p,v) UINT16_PUT(p,DIR_LASTACCDTE,v) +# define DIR_PUTFSTCLUSTHI(p,v) UINT16_PUT(p,DIR_FSTCLUSTHI,v) +# define DIR_PUTWRTTIME(p,v) UINT16_PUT(p,DIR_WRTTIME,v) +# define DIR_PUTWRTDATE(p,v) UINT16_PUT(p,DIR_WRTDATE,v) +# define DIR_PUTFSTCLUSTLO(p,v) UINT16_PUT(p,DIR_FSTCLUSTLO,v) +# define DIR_PUTFILESIZE(p,v) UINT32_PUT(p,DIR_FILESIZE,v) + +# define FAT_PUTFAT16(p,i,v) UINT16_PUT(p,i,v) +# define FAT_PUTFAT32(p,i,v) UINT32_PUT(p,i,v) + +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ /* This structure represents the overall mountpoint state. An instance of this * structure is retained as inode private data on each mountpoint that is @@ -167,7 +406,6 @@ struct fat_mountpt_s struct inode *fs_blkdriver; /* The block driver inode that hosts the FAT32 fs */ struct fat_file_s *fs_head; /* A list to all files opened on this mountpoint */ - boolean fs_mounted; /* TRUE: The file system is ready */ sem_t fs_sem; /* Used to assume thread-safe access */ size_t fs_hwsectorsize; /* HW: Sector size reported by block driver*/ size_t fs_hwnsectors; /* HW: The number of sectors reported by the hardware */ @@ -175,6 +413,7 @@ struct fat_mountpt_s size_t fs_rootbase; /* MBR: Cluster no. of 1st cluster of root dir */ size_t fs_database; /* Logical block of start data sectors */ size_t fs_fsinfo; /* MBR: Sector number of FSINFO sector */ + size_t fs_sector; /* The sector number buffered in fs_buffer */ uint32 fs_nclusters; /* Maximum number of data clusters */ uint32 fs_fatsize; /* MBR: Count of sectors occupied by one fat */ uint32 fs_fattotsec; /* MBR: Total count of sectors on the volume */ @@ -182,6 +421,8 @@ struct fat_mountpt_s uint32 fs_fsinextfree; /* FSI: Cluster number of 1st free cluster */ uint16 fs_fatresvdseccount; /* MBR: The total number of reserved sectors */ uint16 fs_rootentcnt; /* MBR: Count of 32-bit root directory entries */ + boolean fs_mounted; /* TRUE: The file system is ready */ + boolean fs_dirty; /* TRUE: fs_buffer is dirty */ ubyte fs_type; /* FSTYPE_FAT12, FSTYPE_FAT16, or FSTYPE_FAT32 */ ubyte fs_fatnumfats; /* MBR: Number of FATs (probably 2) */ ubyte fs_fatsecperclus; /* MBR: Sectors per allocation unit: 2**n, n=0..7 */ @@ -189,15 +430,38 @@ struct fat_mountpt_s * from the device */ }; -/* This structure represents on open file under the mountpoint. An instance of this - * structure is retained as struct file specific information on each opened file. +/* This structure represents on open file under the mountpoint. An instance + * of this structure is retained as struct file specific information on each + * opened file. */ struct fat_file_s { - struct fat_file_s *ff_next; /* File structures are retained in a singly linked list */ - struct fat_mountpt_s *ff_parent; - boolean ff_open; /* TRUE: The file is (still) open */ + struct fat_file_s *ff_next; /* Retained in a singly linked list */ + boolean ff_open; /* TRUE: The file is (still) open */ + ubyte ff_oflags; /* Flags provided when file was opened */ + ubyte ff_sectorsincluster; /* Sectors remaining in cluster */ + uint16 ff_dirindex; /* Index into ff_dirsector to directory entry */ + size_t ff_dirsector; /* Sector containing the directory entry */ + size_t ff_position; /* File position for read/write/seek in bytes */ + size_t ff_size; /* Size of the file in bytes */ + size_t ff_startcluster; /* Start cluster of file on media */ +}; + +/* This structure is used internally for describing directory entries */ + +struct fat_dirinfo_s +{ + struct fat_mountpt_s *fs; /* Pointer to the parent mountpoint */ + ubyte fd_name[8+3]; /* Filename -- directory format*/ +#ifdef CONFIG_FAT_LCNAMES + ubyte fd_ntflags; /* NTRes lower case flags */ +#endif + uint16 fd_index; /* Current index */ + size_t fd_startcluster; /* Start cluster number */ + size_t fd_currcluster; /* Current cluster number */ + size_t fd_currsector; /* Current sector */ + ubyte *fd_entry; /* A pointer to the raw 32-byte entry */ }; /**************************************************************************** @@ -216,9 +480,22 @@ extern "C" { #define EXTERN extern #endif +EXTERN uint16 fat_getuint16(ubyte *ptr); +EXTERN uint32 fat_getuint32(ubyte *ptr); +EXTERN void fat_putuint16(ubyte *ptr, uint16 value16); +EXTERN void fat_putuint32(ubyte *ptr, uint32 value32); +EXTERN void fat_semtake(struct fat_mountpt_s *fs); +EXTERN void fat_semgive(struct fat_mountpt_s *fs); +EXTERN int fat_mount(struct fat_mountpt_s *fs, boolean writeable); +EXTERN int fat_checkmount(struct fat_mountpt_s *fs); +EXTERN int fat_nextdirentry(struct fat_dirinfo_s *dirinfo); +EXTERN int fat_finddirentry(struct fat_dirinfo_s *dirinfo, const char *path); +EXTERN int fat_dirtruncate(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo); +EXTERN int fat_dircreate(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo); + #undef EXTERN #if defined(__cplusplus) } #endif -#endif /* __FS_FAT_H */ +#endif /* __FS_FAT32_H */ diff --git a/nuttx/fs/fs_fat32util.c b/nuttx/fs/fs_fat32util.c new file mode 100644 index 000000000..6ca885496 --- /dev/null +++ b/nuttx/fs/fs_fat32util.c @@ -0,0 +1,1543 @@ +/**************************************************************************** + * fs_fat32util.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <sys/types.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <semaphore.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/fs.h> + +#include "fs_internal.h" +#include "fs_fat32.h" + +#if CONFIG_FS_FAT + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: fat_hwread + * + * Desciption: Read the specified sector into the sector buffer + * + ****************************************************************************/ + +static int fat_hwread(struct fat_mountpt_s *fs, ubyte *buffer, + size_t sector, unsigned int nsectors) +{ + int ret = -ENODEV; + if (fs && fs->fs_blkdriver ) + { + struct inode *inode = fs->fs_blkdriver; + if (inode && inode->u.i_bops && inode->u.i_bops->read) + { + ssize_t nSectorsRead = inode->u.i_bops->read(inode, buffer, + sector, nsectors); + if (nSectorsRead == nsectors) + { + ret = OK; + } + else if (nSectorsRead < 0) + { + ret = nSectorsRead; + } + } + } + return ret; +} + +/**************************************************************************** + * Name: fat_hwwrite + * + * Desciption: Write the sector buffer to the specified sector + * + ****************************************************************************/ + +static int fat_hwwrite(struct fat_mountpt_s *fs, ubyte *buffer, + size_t sector, unsigned int nsectors) +{ + int ret = -ENODEV; + if (fs && fs->fs_blkdriver ) + { + struct inode *inode = fs->fs_blkdriver; + if (inode && inode->u.i_bops && inode->u.i_bops->write) + { + ssize_t nSectorsWritten = + inode->u.i_bops->write(inode, buffer, sector, nsectors); + + if (nSectorsWritten == nsectors) + { + ret = OK; + } + else if (nSectorsWritten < 0) + { + ret = nSectorsWritten; + } + } + } + return ret; +} + +/**************************************************************************** + * Name: fat_cacheflush + * + * Desciption: Flush any dirty sectors as necessary + * + ****************************************************************************/ + +static int fat_cacheflush(struct fat_mountpt_s *fs) +{ + int ret; + + /* Check if the fs_buffer is dirty. In this case, we will write back the + * contents of fs_buffer. + */ + + if (fs->fs_dirty) + { + /* Write the dirty sector */ + + ret = fat_hwwrite(fs, fs->fs_buffer, fs->fs_sector, 1); + if (ret < 0) + { + return ret; + } + + /* Does the sector lie in the FAT region? */ + + if (fs->fs_sector < fs->fs_fatbase + fs->fs_fatsize) + { + /* Yes, then make the change in the FAT copy as well */ + int i; + + for (i = fs->fs_fatnumfats; i >= 2; i--) + { + fs->fs_sector += fs->fs_fatsize; + ret = fat_hwwrite(fs, fs->fs_buffer, fs->fs_sector, 1); + if (ret < 0) + { + return ret; + } + } + } + + /* No longer dirty */ + + fs->fs_dirty = FALSE; + } + return OK; +} + +/**************************************************************************** + * Name: fat_cacheread + * + * Desciption: Read the specified sector into the sector cache, flushing any + * existing dirty sectors as necessary. + * + ****************************************************************************/ + +static int fat_cacheread(struct fat_mountpt_s *fs, uint32 sector) +{ + int ret; + + /* fs->sector holds the current sector that is buffered in fs->fs_buffer. + * If the requested sector is the same as this sector, then we do nothing. + * Otherwise, we will have to read the new sector. + */ + + if (fs->fs_sector != sector) + { + /* We will need to read the new sector. First, flush the cached + * sector if it is dirty. + */ + + ret = fat_cacheflush(fs); + if (ret < 0) + { + return ret; + } + + /* Then read the specified sector into the cache */ + + ret = fat_hwread(fs, fs->fs_buffer, sector, 1); + if (ret < 0) + { + return ret; + } + + /* Update the cached sector number */ + + fs->fs_sector = sector; + } + return OK; +} + +/**************************************************************************** + * Name: fat_clustger2sector + * + * Desciption: Convert a cluster number to a start sector number + * + ****************************************************************************/ + +static 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; +} + +/**************************************************************************** + * Name: fat_getcluster + * + * Desciption: Get the cluster start sector into the FAT + * + ****************************************************************************/ + +static ssize_t fat_getcluster(struct fat_mountpt_s *fs, unsigned int clusterno) +{ + /* Verify that the cluster number is within range */ + + 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. + */ + + switch (fs->fs_type) + { + case FSTYPE_FAT12 : + { + 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: + */ + + fatoffset = (clusterno * 3) / 2; + fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset); + + /* Read the sector at this offset */ + + if (fat_cacheread(fs, fatsector) < 0) + { + /* Read error */ + break; + } + + /* Get the first, LS byte of the cluster from the FAT */ + + 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. + */ + + fatindex++; + if (fatindex >= fs->fs_hwsectorsize) + { + fatsector++; + fatindex = 0; + + if (fat_cacheread(fs, fatsector) < 0) + { + /* 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. + */ + + startsector |= (unsigned int)fs->fs_buffer[fatindex] << 8; + + /* Now, pick out the correct 12 bit cluster start sector value */ + + if ((clusterno & 1) != 0) + { + /* Odd.. take the MS 12-bits */ + startsector >>= 4; + } + else + { + /* Even.. take the LS 12-bits */ + startsector &= 0x0fff; + } + return startsector; + } + + 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_cacheread(fs, fatsector) < 0) + { + /* Read error */ + break; + } + return FAT_GETFAT16(fs->fs_buffer, fatindex); + } + + 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_cacheread(fs, fatsector) < 0) + { + /* Read error */ + break; + } + return FAT_GETFAT16(fs->fs_buffer, fatindex) & 0x0fffffff; + } + default: + break; + } + } + + /* There is no cluster information, or an error occured */ + return (ssize_t)ERROR; +} + +/**************************************************************************** + * Name: fat_putcluster + * + * Desciption: Write a new cluster start sector into the FAT + * + ****************************************************************************/ + +static int fat_putcluster(struct fat_mountpt_s *fs, unsigned int clusterno, size_t startsector) +{ + /* 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. + */ + + 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_cacheread(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_cacheread(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_cacheread(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_cacheread(fs, fatsector) < 0) + { + /* Read error */ + break; + } + FAT_PUTFAT32(fs->fs_buffer, fatindex, startsector & 0x0fffffff); + } + break; + + default: + return ERROR; + } + + /* Mark the modified sector as "dirty" and return success */ + + fs->fs_dirty = 1; + return OK; + } + return ERROR; + } + +/**************************************************************************** + * Name: fat_path2dirname + * + * Desciption: Convert a user filename into a properly formatted FAT + * (short) filname as it would appear in a directory entry. Here are the + * rules for the 11 byte name in the directory: + * + * The first byte: + * - 0xe5 = The directory is free + * - 0x00 = This directory and all following directories are free + * - 0x05 = Really 0xe5 + * - 0x20 = May NOT be ' ' + * + * Any bytes + * 0x00-0x1f = (except for 0x00 and 0x05 in the first byte) + * 0x22 = '"' + * 0x2a-0x2c = '*', '+', ',' + * 0x2e-0x2f = '.', '/' + * 0x3a-0x3f = ':', ';', '<', '=', '>', '?' + * 0x5b-0x5d = '[', '\\', ;]' + * 0x7c = '|' + * + * Upper case characters are not allowed in directory names (without some + * poorly documented operatgions on the NTRes directory byte). Lower case + * codes may represent different characters in other character sets ("DOS + * code pages". The logic below does not, at present, support any other + * character sets. + * + ****************************************************************************/ + +static inline int fat_path2dirname(const char **path, struct fat_dirinfo_s *dirinfo, + char *terminator) +{ +#ifdef CONFIG_FAT_LCNAMES + unsigned int ntlcenable = FATNTRES_LCNAME | FATNTRES_LCEXT; + unsigned int ntlcfound = 0; +#endif + const char *node = *path; + int endndx; + ubyte ch; + int ndx = 0; + + /* Initialized the name with all spaces */ + + memset(dirinfo->fd_name, ' ', 8+3); + + /* Loop until the name is successfully parsed or an error occurs */ + + endndx = 8; + for (;;) + { + /* Get the next byte from the path */ + + ch = *node++; + + /* Check if this the last byte in this node of the name */ + + if ((ch == '\0' || ch == '/') && ndx != 0 ) + { + /* Return the accumulated NT flags and the terminating character */ +#ifdef CONFIG_FAT_LCNAMES + dirinfo->fd_ntflags = ntlcfound & ntlcenable; +#endif + *terminator = ch; + *path = node; + return OK; + } + + /* Accept only the printable character set. Note the first byte + * of the name could be 0x05 meaning that is it 0xe5, but this is + * not a printable character in this character in either case. + */ + + else if (!isgraph(ch)) + { + goto errout; + } + + /* Check for transition from name to extension */ + + else if (ch == '.') + { + /* Starting the extension */ + + ndx = 8; + endndx = 11; + continue; + } + + /* Reject printable characters forbidden by FAT */ + + else if (ch == '"' || (ch >= '*' && ch <= ',') || + ch == '.' || ch == '/' || + (ch >= ':' && ch <= '?') || + (ch >= '[' && ch <= ']') || + (ch == '|')) + { + goto errout; + } + + /* Check for upper case charaters */ + +#ifdef CONFIG_FAT_LCNAMES + else if (isupper(ch)) + { + /* Some or all of the characters in the name or extension + * are upper case. Force all of the characters to be interpreted + * as upper case. + */ + + if ( endndx == 8) + { + /* Clear lower case name bit in mask*/ + ntlcenable &= FATNTRES_LCNAME; + } + else + { + /* Clear lower case extension in mask */ + ntlcenable &= FATNTRES_LCNAME; + } + } +#endif + + /* Check for lower case characters */ + + else if (islower(ch)) + { + /* Convert the character to upper case */ + + ch = toupper(ch); + + /* Some or all of the characters in the name or extension + * are lower case. They can be interpreted as lower case if + * only if all of the characters in the name or extension are + * lower case. + */ + +#ifdef CONFIG_FAT_LCNAMES + if ( endndx == 8) + { + /* Set lower case name bit */ + ntlcfound |= FATNTRES_LCNAME; + } + else + { + /* Set lower case extension bit */ + ntlcfound |= FATNTRES_LCNAME; + } +#endif + } + + /* Check if the file name exceeds the size permitted (without + * long file name support + */ + + if (ndx >= endndx) + { + goto errout; + } + + /* Save next character in the accumulated name */ + + dirinfo->fd_name[ndx++] = ch; + } + + errout: + return -EINVAL; +} + +/**************************************************************************** + * Name: fat_dirname2path + * + * Desciption: Convert a filename in a raw directory entry into a user + * filename. This is essentially the inverse operation of that performed + * by fat_path2dirname. See that function for more details. + * + ****************************************************************************/ + +static inline int fat_dirname2path(char *path, struct fat_dirinfo_s *dirinfo) +{ + const unsigned char *direntry = dirinfo->fd_entry; + int ch; + int ndx; + + /* Check if we will be doing upper to lower case conversions */ + +#ifdef CONFIG_FAT_LCNAMES + dirinfo->fd_ntflags = DIR_GETNTRES(direntry); +#endif + + /* Get the 8-byte filename */ + + for (ndx = 0; ndx < 8; ndx++) + { + /* Get the next filename character from the directory entry */ + + ch = direntry[ndx]; + + /* Any space (or ndx==8) terminates the filename */ + + if (ch == ' ') + { + break; + } + + /* In this version, we never write 0xe5 in the directoryfilenames + * (because we do not handle any character sets where 0xe5 is valid + * in a filaname), but we could encounted this in a filesystem + * written by some other system + */ + + if (ndx == 0 && ch == DIR0_E5) + { + ch = 0xe5; + } + + /* Check if we should perform upper to lower case conversion + * of the (whole) filename. + */ + +#ifdef CONFIG_FAT_LCNAMES + if (dirinfo->fd_ntflags & FATNTRES_LCNAME && isupper(ch)) + { + ch = tolower(ch); + } +#endif + /* Copy the next character into the filename */ + + *path++ = ch; + } + + /* Check if there is an extension */ + + if (direntry[8] != ' ') + { + /* Yes, output the dot before the extension */ + + *path++ = '.'; + + /* Then output the (up to) 3 character extension */ + + for (ndx = 8; ndx < 11; ndx++) + { + /* Get the next extensions character from the directory entry */ + + ch = dirinfo->fd_name[ndx]; + + /* Any space (or ndx==11) terminates the extension */ + + if (ch == ' ') + { + break; + } + + /* Check if we should perform upper to lower case conversion + * of the (whole) filename. + */ + +#ifdef CONFIG_FAT_LCNAMES + if (ntflags & FATNTRES_LCEXT && isupper(ch)) + { + ch = tolower(ch); + } +#endif + /* Copy the next character into the filename */ + + *path++ = ch; + } + } + + /* Put a null terminator at the end of the filename */ + + *path = '\0'; + return OK; +} + +/**************************************************************************** + * Name: fat_checkfsinfo + * + * Desciption: Read the FAT32 FSINFO sector + * + ****************************************************************************/ + +static int fat_checkfsinfo(struct fat_mountpt_s *fs) +{ + /* Verify that this is, indeed, an FSINFO sector */ + + if (FSI_GETLEADSIG(fs->fs_buffer) == 0x41615252 && + FSI_GETSTRUCTSIG(fs->fs_buffer) == 0x61417272 && + FSI_GETTRAILSIG(fs->fs_buffer) == 0xaa550000) + { + fs->fs_fsinextfree = FSI_GETFREECOUNT(fs->fs_buffer); + fs->fs_fsifreecount = FSI_GETNXTFREE(fs->fs_buffer); + return OK; + } + return -ENODEV; +} + +/**************************************************************************** + * Name: fat_checkbootrecord + * + * Desciption: Read a sector and verify that it is a a FAT boot record. + * + ****************************************************************************/ + +static int fat_checkbootrecord(struct fat_mountpt_s *fs) +{ + uint32 ndatasectors; + uint32 fatsize; + uint16 rootdirsectors = 0; + boolean notfat32 = FALSE; + + /* Verify the MBR signature at offset 510 in the sector (true even + * if the sector size is greater than 512. All FAT file systems have + * this signature. On a FAT32 volume, the RootEntCount , FatSz16, and + * FatSz32 values should always be zero. The FAT sector size should + * match the reported hardware sector size. + */ + + if (MBR_GETSIGNATURE(fs->fs_buffer) != 0xaa55 || + MBR_GETBYTESPERSEC(fs->fs_buffer) != fs->fs_hwsectorsize) + { + return -ENODEV; + } + + /* Verify the FAT32 file system type. The determination of the file + * system type is based on the number of clusters on the volume: FAT12 + * volume has < 4085 cluseter, a FAT16 volume has fewer than 65,525 + * clusters, and any larger is FAT32. + * + * Get the number of 32-bit directory entries in root directory (zero + * for FAT32. + */ + + fs->fs_rootentcnt = MBR_GETROOTENTCNT(fs->fs_buffer); + if (fs->fs_rootentcnt != 0) + { + notfat32 = TRUE; /* Must be zero for FAT32 */ + rootdirsectors = (32 * fs->fs_rootentcnt + fs->fs_hwsectorsize - 1) / fs->fs_hwsectorsize; + } + + /* Determine the number of sectors in a FAT. */ + + fs->fs_fatsize = MBR_GETFATSZ16(fs->fs_buffer); /* Should be zero */ + if (fs->fs_fatsize) + { + notfat32 = TRUE; /* Must be zero for FAT32 */ + } + else + { + fs->fs_fatsize = MBR_GETFATSZ32(fs->fs_buffer); + } + + if (!fs->fs_fatsize || fs->fs_fatsize >= fs->fs_hwnsectors) + { + return -ENODEV; + } + + /* Get the total number of sectors on the volume. */ + + fs->fs_fattotsec = MBR_GETTOTSEC16(fs->fs_buffer); /* Should be zero */ + if (fs->fs_fattotsec) + { + notfat32 = TRUE; /* Must be zero for FAT32 */ + } + else + { + fs->fs_fattotsec = MBR_GETTOTSEC32(fs->fs_buffer); + } + + if (!fs->fs_fattotsec || fs->fs_fattotsec > fs->fs_hwnsectors) + { + return -ENODEV; + } + + /* Get the total number of reserved sectors */ + + fs->fs_fatresvdseccount = MBR_GETRESVDSECCOUNT(fs->fs_buffer); + if (fs->fs_fatresvdseccount > fs->fs_hwnsectors) + { + return -ENODEV; + } + + /* Get the number of FATs. This is probably two but could have other values */ + + fs->fs_fatnumfats = MBR_GETNUMFATS(fs->fs_buffer); + fatsize = fs->fs_fatnumfats * fs->fs_fatsize; + + /* Get the total number of data sectors */ + + ndatasectors = fs->fs_fattotsec - fs->fs_fatresvdseccount - fatsize - rootdirsectors; + if (ndatasectors > fs->fs_hwnsectors) + { + return -ENODEV; + } + + /* Get the sectors per cluster */ + + fs->fs_fatsecperclus = MBR_GETSECPERCLUS(fs->fs_buffer); + + /* Calculate the number of clusters */ + + fs->fs_nclusters = ndatasectors / fs->fs_fatsecperclus; + + /* Finally, the test: */ + + if (fs->fs_nclusters < 4085) + { + fs->fs_fsinfo = 0; + fs->fs_type = FSTYPE_FAT12; + } + else if (fs->fs_nclusters < 65525) + { + fs->fs_fsinfo = 0; + fs->fs_type = FSTYPE_FAT16; + } + + else if (!notfat32) + { + fs->fs_fsinfo = fs->fs_fatbase + MBR_GETFSINFO(fs->fs_buffer); + fs->fs_type = FSTYPE_FAT32; + } + else + { + return -ENODEV; + } + + /* We have what appears to be a valid FAT filesystem! Save a few more things + * from the boot record that we will need later. + */ + + fs->fs_fatbase += fs->fs_fatresvdseccount; + + if (fs->fs_type == FSTYPE_FAT32) + { + fs->fs_rootbase = MBR_GETROOTCLUS(fs->fs_buffer); + } + else + { + fs->fs_rootbase = fs->fs_fatbase + fatsize; + } + + fs->fs_database = fs->fs_fatbase + fatsize + fs->fs_rootentcnt / DIRSEC_NDIRS(fs); + fs->fs_fsifreecount = 0xffffffff; + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: fat_getuint16 + ****************************************************************************/ + +uint16 fat_getuint16(ubyte *ptr) +{ +#ifdef CONFIG_ARCH_BIGENDIAN + /* The bytes always have to be swapped if the target is big-endian */ + + return ((uint16)ptr[0] << 8) | ptr[1]; +#else + /* Byte-by-byte transfer is still necessary if the address is un-aligned */ + + return ((uint16)ptr[1] << 8) | ptr[0]; +#endif +} + +/**************************************************************************** + * Name: fat_getuint32 + ****************************************************************************/ + +uint32 fat_getuint32(ubyte *ptr) +{ +#ifdef CONFIG_ARCH_BIGENDIAN + /* The bytes always have to be swapped if the target is big-endian */ + + return ((uint32)fat_getuint16(&ptr[0]) << 16) | fat_getuint16(&ptr[2]); +#else + /* Byte-by-byte transfer is still necessary if the address is un-aligned */ + + return ((uint32)fat_getuint16(&ptr[2]) << 16) | fat_getuint16(&ptr[0]); +#endif +} + +/**************************************************************************** + * Name: fat_putuint16 + ****************************************************************************/ + +void fat_putuint16(ubyte *ptr, uint16 value16) +{ + ubyte *val = (ubyte*)&value16; +#ifdef CONFIG_ARCH_BIGENDIAN + /* The bytes always have to be swapped if the target is big-endian */ + + ptr[0] = val[1]; + ptr[1] = val[0]; +#else + /* Byte-by-byte transfer is still necessary if the address is un-aligned */ + + ptr[0] = val[0]; + ptr[1] = val[1]; +#endif +} + +/**************************************************************************** + * Name: fat_putuint32 + ****************************************************************************/ + +void fat_putuint32(ubyte *ptr, uint32 value32) +{ + uint16 *val = (uint16*)&value32; +#ifdef CONFIG_ARCH_BIGENDIAN + /* The bytes always have to be swapped if the target is big-endian */ + + fat_putuint16(&ptr[0], val[2]); + fat_putuint16(&ptr[2], val[0]); +#else + /* Byte-by-byte transfer is still necessary if the address is un-aligned */ + + fat_putuint16(&ptr[0], val[0]); + fat_putuint16(&ptr[2], val[2]); +#endif +} + +/**************************************************************************** + * Name: fat_semtake + ****************************************************************************/ + +void fat_semtake(struct fat_mountpt_s *fs) +{ + /* Take the semaphore (perhaps waiting) */ + + while (sem_wait(&fs->fs_sem) != 0) + { + /* The only case that an error should occur here is if + * the wait was awakened by a signal. + */ + + ASSERT(*get_errno_ptr() == EINTR); + } +} + +/**************************************************************************** + * Name: fat_semgive + ****************************************************************************/ + +void fat_semgive(struct fat_mountpt_s *fs) +{ + sem_post(&fs->fs_sem); +} + +/**************************************************************************** + * Name: fat_mount + * + * Desciption: This function is called only when the mountpoint is first + * established. It initializes the mountpoint structure and verifies + * that a valid FAT32 filesystem is provided by the block driver. + * + * The caller should hold the mountpoint semaphore + * + ****************************************************************************/ + +int fat_mount(struct fat_mountpt_s *fs, boolean writeable) +{ + FAR struct inode *inode; + struct geometry geo; + int ret; + + /* Assume that the mount is successful */ + + fs->fs_mounted = TRUE; + + /* Check if there is media available */ + + inode = fs->fs_blkdriver; + if (!inode || !inode->u.i_bops || !inode->u.i_bops->geometry || + inode->u.i_bops->geometry(inode, &geo) != OK || !geo.geo_available) + { + ret = -ENODEV; + goto errout; + } + + /* Make sure that that the media is write-able (if write access is needed) */ + + if (writeable && !geo.geo_writeenabled) + { + ret = -EACCES; + goto errout; + } + + /* Save the hardware geometry */ + + fs->fs_hwsectorsize = geo.geo_sectorsize; + fs->fs_hwnsectors = geo.geo_nsectors; + + /* Allocate a buffer to hold one hardware sector */ + + fs->fs_buffer = (ubyte*)malloc(fs->fs_hwsectorsize); + if (!fs->fs_buffer) + { + ret = -ENOMEM; + goto errout; + } + + /* Search FAT boot record on the drive. First check at sector zero. This + * could be either the boot record or a partition that refers to the boot + * record. + * + * First read sector zero. This will be the first access to the drive and a + * likely failure point. + */ + + fs->fs_fatbase = 0; + ret = fat_hwread(fs, fs->fs_buffer, 0, 1); + if (ret < 0) + { + goto errout_with_buffer; + } + + if (fat_checkbootrecord(fs) != OK) + { + /* The contents of sector 0 is not a boot record. It could be a + * partition, however. Assume it is a partition and get the offset + * into the partition table. This table is at offset MBR_TABLE and is + * indexed by 16x the partition number. Here we support only + * parition 0. + */ + + ubyte *partition = &fs->fs_buffer[MBR_TABLE + 0]; + + /* Check if the partition exists and, if so, get the bootsector for that + * partition and see if we can find the boot record there. + */ + + if (partition[4]) + { + /* There appears to be a partition, get the sector number of the + * partition (LBA) + */ + + fs->fs_fatbase = MBR_GETPARTSECTOR(&partition[8]); + + /* Read the new candidate boot sector */ + + ret = fat_hwread(fs, fs->fs_buffer, fs->fs_fatbase, 1); + if (ret < 0) + { + goto errout_with_buffer; + } + + /* Check if this is a boot record */ + + if (fat_checkbootrecord(fs) != OK) + { + goto errout_with_buffer; + } + } + } + + /* We have what appears to be a valid FAT filesystem! Now read the + * FSINFO sector (FAT32 only) + */ + + if (fs->fs_type == FSTYPE_FAT32) + { + ret = fat_checkfsinfo(fs); + if (ret != OK) + { + goto errout_with_buffer; + } + } + + /* We did it! */ + + dbg("FAT%d:\n", fs->fs_type == 0 ? 12 : fs->fs_type == 1 ? 16 : 32); + dbg("\tHW sector size: %d\n", fs->fs_hwsectorsize); + dbg("\t sectors: %d\n", fs->fs_hwnsectors); + dbg("\tFAT reserved: %d\n", fs->fs_fatresvdseccount); + dbg("\t sectors: %d\n", fs->fs_fattotsec); + dbg("\t start sector: %d\n", fs->fs_fatbase); + dbg("\t root sector: %d\n", fs->fs_rootbase); + dbg("\t root entries: %d\n", fs->fs_rootentcnt); + dbg("\t data sector: %d\n", fs->fs_database); + dbg("\t FSINFO sector: %d\n", fs->fs_fsinfo); + dbg("\t Num FATs: %d\n", fs->fs_fatnumfats); + dbg("\t FAT size: %d\n", fs->fs_fatsize); + dbg("\t sectors/cluster: %d\n", fs->fs_fatsecperclus); + dbg("\t max clusters: %d\n", fs->fs_nclusters); + dbg("\tFSI free count %d\n", fs->fs_fsifreecount); + dbg("\t next free %d\n", fs->fs_fsinextfree); + + return OK; + + errout_with_buffer: + free(fs->fs_buffer); + fs->fs_buffer = 0; + errout: + fs->fs_mounted = FALSE; + return ret; +} + +/**************************************************************************** + * Name: fat_checkmount + * + * Desciption: Check if the mountpoint is still valid. + * + * The caller should hold the mountpoint semaphore + * + ****************************************************************************/ + +int fat_checkmount(struct fat_mountpt_s *fs) +{ + /* If the fs_mounted flag is FALSE, then we have already handled the loss + * of the mount. + */ + + if (fs && fs->fs_mounted) + { + struct fat_file_s *file; + + /* We still think the mount is healthy. Check an see if this is + * still the case + */ + + if (fs->fs_blkdriver) + { + struct inode *inode = fs->fs_blkdriver; + if (inode && inode->u.i_bops && inode->u.i_bops->geometry) + { + struct geometry geo; + int errcode = inode->u.i_bops->geometry(inode, &geo); + if (errcode == OK && geo.geo_available && !geo.geo_mediachanged) + { + return OK; + } + } + } + + /* If we get here, the mount is NOT healthy */ + + fs->fs_mounted = FALSE; + + /* Make sure that this is flagged in every opened file */ + + for (file = fs->fs_head; file; file = file->ff_next) + { + file->ff_open = FALSE; + } + } + return -ENODEV; +} + +/**************************************************************************** + * Name: fat_nextdirentry + * + * Desciption: Read the next directory entry from the sector in cache, + * reading the next sector(s) in the cluster as necessary. + * + ****************************************************************************/ + +int fat_nextdirentry(struct fat_dirinfo_s *dirinfo) +{ + struct fat_mountpt_s *fs = dirinfo->fs; + unsigned int cluster; + unsigned int ndx; + + /* Increment the index to the next 32-byte directory entry */ + + ndx = dirinfo->fd_index + 1; + + /* Check if all of the directory entries in this sectory have + * been examined. + */ + + if (ndx >= DIRSEC_NDIRS(fs)) + { + /* Yes, then we will have to read the next sector */ + + dirinfo->fd_currsector++; + + /* For FAT12/16, the root directory is a group of sectors relative + * to the first sector of the fat volume. + */ + + if (!dirinfo->fd_currcluster) + { + /* For FAT12/13, the boot record tells us number of 32-bit directories + * that are contained in the root directory. This should correspond to + * an even number of sectors. + */ + + if (ndx >= fs->fs_rootentcnt) + { + /* When we index past this count, we have examined all of the entries in + * the root directory. + */ + + return ERROR; + } + } + else + { + /* Not a FAT12/16 root directory, check if we have examined the entire + * cluster comprising the directory. + * + * The current sector within the cluster is the entry number divided + * byte the number of entries per sector + */ + + int sector = ndx / DIRSEC_NDIRS(fs); + + /* We are finished with the cluster when the last sector of the cluster + * has been examined. + */ + + if (sector >= fs->fs_fatsecperclus) + { + /* Get next cluster */ + + cluster = fat_getcluster(fs, dirinfo->fd_currcluster); + + /* Check if a valid cluster was obtained. */ + + if (cluster < 2 || cluster >= fs->fs_nclusters) + { + /* No, we have probably reached the end of the cluster list */ + return ERROR; + } + + /* Initialize for new cluster */ + + dirinfo->fd_currcluster = cluster; + dirinfo->fd_currsector = fat_cluster2sector(fs, cluster); + } + } + } + + /* Save the new index into dirinfo->fd_currsector */ + + dirinfo->fd_index = ndx; + return OK; +} + +/**************************************************************************** + * Name: fat_finddirentry + * + * Desciption: Given a path to something that may or may not be in the file + * system, return the directory entry of the item. + * + ****************************************************************************/ + +int fat_finddirentry(struct fat_dirinfo_s *dirinfo, const char *path) +{ + struct fat_mountpt_s *fs = dirinfo->fs; + size_t cluster; + ubyte *direntry = NULL; + char terminator; + int ret; + + /* Initialize to traverse the chain. Set it to the cluster of + * the root directory + */ + + cluster = fs->fs_rootbase; + if (fs->fs_type == FSTYPE_FAT32) + { + /* For FAT32, the root directory is variable sized and is a + * cluster chain like any other directory. fs_rootbase holds + * the first cluster of the root directory. + */ + + dirinfo->fd_startcluster = cluster; + dirinfo->fd_currcluster = cluster; + dirinfo->fd_currsector = fat_cluster2sector(fs, cluster); + } + else + { + /* For FAT12/16, the first sector of the root directory is a sector + * relative to the first sector of the fat volume. + */ + + dirinfo->fd_startcluster = 0; + dirinfo->fd_currcluster = 0; + dirinfo->fd_currsector = cluster; + } + + /* fd_index is the index into the current directory table */ + + dirinfo->fd_index = 0; + + /* If no path was provided, then the root directory must be exactly + * what the caller is looking for. + */ + + if (*path == '\0') + { + dirinfo->fd_entry = NULL; + return OK; + } + + /* Otherwise, loop until the path is found */ + + for (;;) + { + /* Convert the next the path segment name into the kind of + * name that we would see in the directory entry. + */ + + ret = fat_path2dirname(&path, dirinfo, &terminator); + if (ret < 0) + { + /* ERROR: The filename contains invalid characters or is + * too long. + */ + + return ret; + } + + /* Now search the current directory entry for an entry with this + * matching name. + */ + + for (;;) + { + /* Read the next sector into memory */ + + ret = fat_cacheread(fs, dirinfo->fd_currsector); + if (ret < 0) + { + return ret; + } + + /* Get a pointer to the directory entry */ + + direntry = &fs->fs_buffer[DIRSEC_BYTENDX(fs, dirinfo->fd_index)]; + + /* Check if we are at the end of the directory */ + + if (direntry[DIR_NAME] == DIR0_ALLEMPTY) + { + return -ENOENT; + } + + /* Check if we have found the directory entry that we are looking for */ + + if (direntry[DIR_NAME] != DIR0_EMPTY && + !(DIR_GETATTRIBUTES(direntry) & FATATTR_VOLUMEID) && + !memcmp(&direntry[DIR_NAME], dirinfo->fd_name, 8+3) ) + { + /* Yes.. break out of the loop */ + break; + } + + /* No... get the next directory index and try again */ + + if (fat_nextdirentry(dirinfo) != OK) + { + return -ENOENT; + } + } + + /* We get here only if we have found a directory entry that matches + * the path element that we are looking for. + * + * If the terminator character in the path was the end of the string + * then we have successfully found the directory entry that describes + * the path. + */ + + if (!terminator) + { + /* Return the pointer to the matching directory entry */ + dirinfo->fd_entry = direntry; + return OK; + } + + /* No.. then we have found one of the intermediate directories on + * the way to the final path target. In this case, make sure + * the thing that we found is, indeed, a directory. + */ + + if (!(DIR_GETATTRIBUTES(direntry) & FATATTR_DIRECTORY)) + { + /* Ooops.. we found something else */ + return -ENOTDIR; + } + + /* Get the cluster number of this directory */ + + cluster = + ((uint32)DIR_GETFSTCLUSTHI(direntry) << 16) | + DIR_GETFSTCLUSTLO(direntry); + + /* The restart scanning at the new directory */ + + dirinfo->fd_currcluster = dirinfo->fd_startcluster = cluster; + dirinfo->fd_currsector = fat_cluster2sector(fs, cluster); + dirinfo->fd_index = 2; + } +} + +/**************************************************************************** + * Name: fat_dirtruncate + * + * Desciption: Truncate an existing file to zero length + * + ****************************************************************************/ + +int fat_dirtruncate(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo) +{ +#warning "File truncation logic not implemented" + return -ENOSYS; +} + +/**************************************************************************** + * Name: fat_dircreate + * + * Desciption: Create a directory entry for a new file + * + ****************************************************************************/ + +int fat_dircreate(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo) +{ +#warning "File truncation logic not implemented" + return -ENOSYS; +} + +#endif /* CONFIG_FS_FAT */ diff --git a/nuttx/fs/fs_open.c b/nuttx/fs/fs_open.c index b0c9fee43..e954fb743 100644 --- a/nuttx/fs/fs_open.c +++ b/nuttx/fs/fs_open.c @@ -154,7 +154,7 @@ int open(const char *path, int oflags, ...) if (INODE_IS_MOUNTPT(inode)) { status = inode->u.i_mops->open((FAR struct file*)&list->fl_files[fd], - inode, relpath, oflags, mode); + relpath, oflags, mode); } else { diff --git a/nuttx/include/nuttx/fs.h b/nuttx/include/nuttx/fs.h index 06eefc8f7..9c4a538df 100644 --- a/nuttx/include/nuttx/fs.h +++ b/nuttx/include/nuttx/fs.h @@ -100,9 +100,9 @@ struct block_operations int (*open)(FAR struct inode *inode); int (*close)(FAR struct inode *inode); ssize_t (*read)(FAR struct inode *inode, unsigned char *buffer, - size_t start_sector, size_t nsectors); + size_t start_sector, unsigned int nsectors); ssize_t (*write)(FAR struct inode *inode, const unsigned char *buffer, - size_t start_sector, size_t nsectors); + size_t start_sector, unsigned int nsectors); int (*geometry)(FAR struct inode *inode, struct geometry *geometry); int (*ioctl)(FAR struct inode *inode, int cmd, unsigned long arg); }; @@ -122,8 +122,8 @@ struct mountpt_operations * information to manage privileges. */ - int (*open)(FAR struct file *filp, FAR struct inode *inode, - const char *rel_path, int oflags, mode_t mode); + int (*open)(FAR struct file *filp, const char *rel_path, + int oflags, mode_t mode); /* The following methods must be identical in signature and position because * the struct file_operations and struct mountp_operations are treated like @@ -189,8 +189,8 @@ struct file #if CONFIG_NFILE_DESCRIPTORS > 0 struct filelist { - sem_t fl_sem; /* Manage access to the file list */ - sint16 fl_crefs; /* Reference count */ + sem_t fl_sem; /* Manage access to the file list */ + sint16 fl_crefs; /* Reference count */ struct file fl_files[CONFIG_NFILE_DESCRIPTORS]; }; #endif diff --git a/nuttx/include/sys/stat.h b/nuttx/include/sys/stat.h new file mode 100644 index 000000000..12e78313c --- /dev/null +++ b/nuttx/include/sys/stat.h @@ -0,0 +1,49 @@ +/************************************************************ + * stat.h + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************/ + +#ifndef __SYS_STAT_H +#define __SYS_STAT_H + +/************************************************************ + * Included Files + ************************************************************/ + +#include <sys/types.h> + +/************************************************************ + * Type Definitions + ************************************************************/ + +#endif /* __SYS_STAT_H */ |