diff --git a/ChangeLog b/ChangeLog index e7dba2db7a..6efc3b98d0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -150,9 +150,9 @@ 0.2.7 2007-xx-xx Gregory Nutt - * Added stat() to fs layer - * Added stat() supported to FAT + * Added stat() to fs layer and to FAT * Fixed reference counting errors associated with mounted filesystems * Added fat_getattrib() and fat_setattrib() + * Added statfs() to fs layer and to FAT * Started m68322 diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index 0706b2f4cf..b9367abbef 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -584,10 +584,10 @@ Other memory: 0.2.7 2007-xx-xx Gregory Nutt - * Added stat() to fs layer - * Added stat() supported to FAT + * Added stat() to fs layer and to FAT * Fixed reference counting errors associated with mounted filesystems * Added fat_getattrib() and fat_setattrib() + * Added statfs() to fs layer and to FAT * Started m68322 diff --git a/fs/Makefile b/fs/Makefile index 49fdce3a59..0bae522158 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -43,7 +43,7 @@ AOBJS = $(ASRCS:.S=$(OBJEXT)) CSRCS = fs_open.c fs_close.c fs_read.c fs_write.c fs_ioctl.c fs_dup.c \ fs_opendir.c fs_closedir.c fs_stat.c fs_readdir.c fs_readdirr.c \ fs_seekdir.c fs_telldir.c fs_rewinddir.c fs_fsync.c fs_files.c \ - fs_inode.c fs_inodefind.c fs_inodereserve.c \ + fs_inode.c fs_inodefind.c fs_inodereserve.c fs_statfs.c \ fs_inoderemove.c fs_registerdriver.c fs_unregisterdriver.c \ fs_inodeaddref.c fs_inoderelease.c ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y) diff --git a/fs/fs_fat32.c b/fs/fs_fat32.c index 6aa58710fa..93ea721a9e 100644 --- a/fs/fs_fat32.c +++ b/fs/fs_fat32.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -93,6 +94,8 @@ static int fat_rewinddir(struct inode *mountpt, struct internal_dir_s *dir); static int fat_bind(FAR struct inode *blkdriver, const void *data, void **handle); static int fat_unbind(void *handle, FAR struct inode **blkdriver); +static int fat_statfs(struct inode *mountpt, struct statfs *buf); + static int fat_unlink(struct inode *mountpt, const char *relpath); static int fat_mkdir(struct inode *mountpt, const char *relpath, mode_t mode); @@ -131,6 +134,8 @@ const struct mountpt_operations fat_operations = fat_bind, fat_unbind, + fat_statfs, + fat_unlink, fat_mkdir, fat_rmdir, @@ -1578,6 +1583,59 @@ static int fat_unbind(void *handle, FAR struct inode **blkdriver) return ret; } +/**************************************************************************** + * Name: fat_statfs + * + * Description: Return filesystem statistics + * + ****************************************************************************/ + +static int fat_statfs(struct inode *mountpt, struct statfs *buf) +{ + struct fat_mountpt_s *fs; + int ret; + + /* Sanity checks */ + + DEBUGASSERT(mountpt && mountpt->i_private); + + /* Get the mountpoint private data from the inode structure */ + + fs = mountpt->i_private; + + /* Check if the mount is still healthy */ + + fat_semtake(fs); + ret = fat_checkmount(fs); + if (ret < 0) + { + goto errout_with_semaphore; + } + + /* Fill in the statfs info */ + + memset(buf, 0, sizeof(struct statfs)); + buf->f_type = MSDOS_SUPER_MAGIC; + + /* We will claim that the optimal transfer size is the size of a cluster in bytes */ + + buf->f_bsize = fs->fs_fatsecperclus * fs->fs_hwsectorsize; + + /* Everything else follows in units of clusters */ + + buf->f_blocks = fs->fs_nclusters; /* Total data blocks in the file system */ + ret = fat_nfreeclusters(fs, &buf->f_bfree); /* Free blocks in the file system */ + buf->f_bavail = buf->f_bfree; /* Free blocks avail to non-superuser */ + buf->f_namelen = (8+1+3); /* Maximum length of filenames */ + + fat_semgive(fs); + return OK; + +errout_with_semaphore: + fat_semgive(fs); + return ret; +} + /**************************************************************************** * Name: fat_unlink * diff --git a/fs/fs_fat32.h b/fs/fs_fat32.h index ff516be005..0ea0eca363 100644 --- a/fs/fs_fat32.h +++ b/fs/fs_fat32.h @@ -567,6 +567,7 @@ EXTERN int fat_ffcacheinvalidate(struct fat_mountpt_s *fs, struct fat_file_s /* FSINFO sector support */ EXTERN int fat_updatefsinfo(struct fat_mountpt_s *fs); +EXTERN int fat_nfreeclusters(struct fat_mountpt_s *fs, size_t *pfreeclusters); #undef EXTERN #if defined(__cplusplus) diff --git a/fs/fs_fat32util.c b/fs/fs_fat32util.c index f68d4cf1be..a21783e01e 100644 --- a/fs/fs_fat32util.c +++ b/fs/fs_fat32util.c @@ -861,7 +861,7 @@ ssize_t fat_cluster2sector(struct fat_mountpt_s *fs, uint32 cluster ) * * Desciption: Get the cluster start sector into the FAT. * - * Return: <0: error, >=0: sector number + * Return: <0: error, 0:cluster unassigned, >=0: start sector of cluster * ****************************************************************************/ @@ -2340,5 +2340,110 @@ int fat_updatefsinfo(struct fat_mountpt_s *fs) return ret; } +/**************************************************************************** + * Name: fat_nfreeclusters + * + * Desciption: Get the number of free clusters + * + ****************************************************************************/ + +int fat_nfreeclusters(struct fat_mountpt_s *fs, size_t *pfreeclusters) +{ + uint32 nfreeclusters; + + /* If number of the first free cluster is valid, then just return that value. */ + + if (fs->fs_fsifreecount <= fs->fs_nclusters - 2) + { + *pfreeclusters = fs->fs_fsifreecount; + return OK; + } + + /* Otherwise, we will have to count the number of free clusters */ + + nfreeclusters = 0; + if (fs->fs_type == FSTYPE_FAT12) + { + size_t sector; + + /* Examine every cluster in the fat */ + + for (sector = 2; sector < fs->fs_nclusters; sector++) + { + + /* If the cluster is unassigned, then increment the count of free clusters */ + + if ((uint16)fat_getcluster(fs, sector) == 0) + { + nfreeclusters++; + } + } + } + else + { + unsigned int cluster; + size_t fatsector; + unsigned int offset; + int ret; + + fatsector = fs->fs_fatbase; + offset = fs->fs_hwsectorsize; + + /* Examine each cluster in the fat */ + + for (cluster = fs->fs_nclusters; cluster > 0; cluster--) + { + /* If we are starting a new sector, then read the new sector in fs_buffer */ + + if (offset >= fs->fs_hwsectorsize) + { + ret = fat_fscacheread(fs, fatsector++); + if (ret < 0) + { + return ret; + } + + /* Reset the offset to the next FAT entry. + * Increment the sector number to read next time around. + */ + + offset = 0; + fatsector++; + } + + /* FAT16 and FAT32 differ only on the size of each cluster start + * sector number in the FAT. + */ + + if (fs->fs_type == FSTYPE_FAT16) + { + if (FAT_GETFAT16(fs->fs_buffer, offset) == 0) + { + nfreeclusters++; + } + offset += 2; + } + else + { + if (FAT_GETFAT32(fs->fs_buffer, offset) == 0) + { + nfreeclusters++; + } + + offset += 4; + } + } + } + + fs->fs_fsifreecount = nfreeclusters; + if (fs->fs_type == FSTYPE_FAT32) + { + fs->fs_fsidirty = TRUE; + } + + *pfreeclusters = nfreeclusters; + return OK; +} + #endif /* CONFIG_DISABLE_MOUNTPOUNT */ #endif /* CONFIG_FS_FAT */ diff --git a/fs/fs_statfs.c b/fs/fs_statfs.c index 24b9113ef1..515723ed60 100644 --- a/fs/fs_statfs.c +++ b/fs/fs_statfs.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include "fs_internal.h" @@ -61,6 +62,9 @@ static inline int statpsuedofs(FAR struct inode *inode, FAR struct statfs *buf) { + memset(buf, 0, sizeof(struct statfs)); + buf->f_type = PROC_SUPER_MAGIC; + buf->f_namelen = NAME_MAX; return OK; } @@ -132,7 +136,7 @@ int statfs(const char *path, struct statfs *buf) { /* Perform the rewinddir() operation */ - ret = inode->u.i_mops->statfs(inode, relpath, buf); + ret = inode->u.i_mops->statfs(inode, buf); } } else diff --git a/include/nuttx/fs.h b/include/nuttx/fs.h index 69d093716d..73c5096292 100644 --- a/include/nuttx/fs.h +++ b/include/nuttx/fs.h @@ -116,6 +116,8 @@ struct block_operations struct inode; struct internal_dir_s; +struct stat; +struct statfs; struct mountpt_operations { /* The mountpoint open method differs from the driver open method @@ -159,6 +161,10 @@ struct mountpt_operations int (*bind)(FAR struct inode *blkdriver, const void *data, void **handle); int (*unbind)(void *handle, FAR struct inode **blkdriver); + int (*statfs)(struct inode *mountpt, struct statfs *buf); + + /* Operations on pathes */ + int (*unlink)(struct inode *mountpt, const char *relpath); int (*mkdir)(struct inode *mountpt, const char *relpath, mode_t mode); int (*rmdir)(struct inode *mountpt, const char *relpath); diff --git a/include/sys/statfs.h b/include/sys/statfs.h index 7baf4be6fd..c677e7f1a0 100644 --- a/include/sys/statfs.h +++ b/include/sys/statfs.h @@ -102,7 +102,7 @@ struct statfs { uint32 f_type; /* Type of filesystem (see definitions above) */ size_t f_bsize; /* Optimal block size for transfers */ - size_t f_blocks; /* Totat data blocks in the file system of this size */ + size_t f_blocks; /* Total data blocks in the file system of this size */ size_t f_bfree; /* Free blocks in the file system */ size_t f_bavail; /* Free blocks avail to non-superuser */ size_t f_files; /* Total file nodes in the file system */