⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fs_fat32.c

📁 這是一個實時嵌入式作業系統 實作了MCS51 ARM等MCU
💻 C
📖 第 1 页 / 共 4 页
字号:
/**************************************************************************** * fs_fat32.c * *   Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. *   Author: Gregory Nutt <spudmonkey@racsa.co.cr> * * References: *   Microsoft FAT documentation *   Some good ideas were leveraged from the FAT implementation: *     'Copyright (C) 2007, ChaN, all right reserved.' *     which has an unrestricted license. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 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 NuttX 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 <sys/stat.h>#include <sys/statfs.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <semaphore.h>#include <assert.h>#include <fcntl.h>#include <errno.h>#include <debug.h>#include <nuttx/fs.h>#include <nuttx/fat.h>#include "fs_internal.h"#include "fs_fat32.h"/**************************************************************************** * Definitions ****************************************************************************//**************************************************************************** * Private Types ****************************************************************************//**************************************************************************** * Private Function Prototypes ****************************************************************************/static int     fat_open(FAR struct file *filp, const char *relpath,                        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,                         size_t buflen);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);static int     fat_sync(FAR struct file *filp);static int     fat_opendir(struct inode *mountpt, const char *relpath,                           struct internal_dir_s *dir);static int     fat_readdir(struct inode *mountpt, struct internal_dir_s *dir);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);static int     fat_rmdir(struct inode *mountpt, const char *relpath);static int     fat_rename(struct inode *mountpt, const char *oldrelpath,                          const char *newrelpath);static int     fat_stat(struct inode *mountpt, const char *relpath, struct stat *buf);/**************************************************************************** * Private Variables ****************************************************************************//**************************************************************************** * Public Variables ****************************************************************************//* See fs_mount.c -- this structure is explicitly externed there. * We use the old-fashioned kind of initializers so that this will compile * with any compiler. */const struct mountpt_operations fat_operations ={  fat_open,  fat_close,  fat_read,  fat_write,  fat_seek,  fat_ioctl,  fat_sync,  fat_opendir,  NULL,  fat_readdir,  fat_rewinddir,  fat_bind,  fat_unbind,  fat_statfs,  fat_unlink,  fat_mkdir,  fat_rmdir,  fat_rename,  fat_stat};/**************************************************************************** * Private Functions ****************************************************************************//**************************************************************************** * Name: fat_open ****************************************************************************/static int fat_open(FAR struct file *filp, const char *relpath,                    int oflags, mode_t mode){  struct fat_dirinfo_s  dirinfo;  struct inode         *inode;  struct fat_mountpt_s *fs;  struct fat_file_s    *ff;  int                   ret;  /* Sanity checks */  DEBUGASSERT(filp->f_priv == NULL && filp->f_inode != NULL);  /* Get the mountpoint inode reference from the file structure and the   * mountpoint private data from the inode structure   */  inode = filp->f_inode;  fs    = inode->i_private;  DEBUGASSERT(fs != NULL);  /* Check if the mount is still healthy */  fat_semtake(fs);  ret = fat_checkmount(fs);  if (ret != OK)    {      goto errout_with_semaphore;    }  /* Initialize the directory info structure */  memset(&dirinfo, 0, sizeof(struct fat_dirinfo_s));  /* Locate the directory entry for this path */  ret = fat_finddirentry(fs, &dirinfo, relpath);  /* Three possibililities: (1) a node exists for the relpath and   * dirinfo describes the directory entry of the entity, (2) the   * node does not exist, or (3) some error occurred.   */  if (ret == OK)    {      boolean readonly;      /* The name exists -- but is it a file or a directory? */      if (dirinfo.fd_entry == NULL ||         (DIR_GETATTRIBUTES(dirinfo.fd_entry) & FATATTR_DIRECTORY))        {          /* It is a directory */          ret = -EISDIR;          goto errout_with_semaphore;        }      /* It would be an error if we are asked to create it exclusively */      if ((oflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))        {          /* Already exists -- can't create it exclusively */          ret = -EEXIST;          goto errout_with_semaphore;        }#ifdef CONFIG_FILE_MODE# warning "Missing check for privileges based on inode->i_mode"#endif      /* Check if the caller has sufficient privileges to open the file */      readonly = ((DIR_GETATTRIBUTES(dirinfo.fd_entry) & FATATTR_READONLY) != 0);      if (((oflags & O_WRONLY) != 0) && readonly)        {          ret = -EACCES;          goto errout_with_semaphore;        }      /* 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))        {          /* Truncate the file to zero length */          ret = fat_dirtruncate(fs, &dirinfo);          if (ret < 0)            {              goto errout_with_semaphore;            }        }      /* fall through to finish the file open operations */    }  else if (ret == -ENOENT)    {      /* The file does not exist.  Were we asked to create it? */      if ((oflags & O_CREAT) == 0)        {          /* No.. then we fail with -ENOENT */          ret = -ENOENT;          goto errout_with_semaphore;        }      /* Yes.. create the file */      ret = fat_dircreate(fs, &dirinfo);      if (ret < 0)        {          goto errout_with_semaphore;        }      /* Fall through to finish the file open operation */    }  else    {      /* An error occurred while checking for file existence --       * such as if an invalid path were provided.       */      goto errout_with_semaphore;    }  /* Create an instance of the file private date to describe the opened   * file.   */  ff = (struct fat_file_s *)zalloc(sizeof(struct fat_file_s));  if (!ff)    {      ret = -ENOMEM;      goto errout_with_semaphore;    }    /* Create a file buffer to support partial sector accesses */  ff->ff_buffer = (ubyte*)malloc(fs->fs_hwsectorsize);  if (!ff->ff_buffer)    {      ret = -ENOMEM;      goto errout_with_struct;    }  /* Initialize the file private data (only need to initialize non-zero elements) */  ff->ff_open             = TRUE;  ff->ff_oflags           = oflags;  ff->ff_sectorsincluster = 1;  /* Save information that can be used later to recover the directory entry */  ff->ff_dirsector        = fs->fs_currentsector;  ff->ff_dirindex         = dirinfo.dir.fd_index;  /* File cluster/size info */  ff->ff_startcluster     =    ((uint32)DIR_GETFSTCLUSTHI(dirinfo.fd_entry) << 16) |      DIR_GETFSTCLUSTLO(dirinfo.fd_entry);  ff->ff_size             = DIR_GETFILESIZE(dirinfo.fd_entry);  /* In write/append mode, we need to set the file pointer to the end of the file */  if ((oflags & (O_APPEND|O_WRONLY)) == (O_APPEND|O_WRONLY))    {        ff->ff_position   = ff->ff_size;    }  /* Attach the private date to the struct file instance */  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   * all files, and (2) to inform the umount logic that we are busy   * (but a simple reference count could have done that).   */  ff->ff_next = fs->fs_head;  fs->fs_head = ff->ff_next;  fat_semgive(fs);  return OK;  /* Error exits -- goto's are nasty things, but they sure can make error   * handling a lot simpler.   */errout_with_struct:  free(ff);errout_with_semaphore:  fat_semgive(fs);  return ret;}/**************************************************************************** * Name: fat_close ****************************************************************************/static int fat_close(FAR struct file *filp){  struct inode         *inode;  struct fat_mountpt_s *fs;  struct fat_file_s    *ff;  int                   ret = OK;  /* Sanity checks */  DEBUGASSERT(filp->f_priv != NULL && filp->f_inode != NULL);  /* Recover our private data from the 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.   */  /* Synchronize the file buffers and disk content; update times */  ret = fat_sync(filp);  /* Then deallocate the memory structures created when the open method   * was called.   *   * Free the sector buffer that was used to manage partial sector accesses.   */  if (ff->ff_buffer)  {      free(ff->ff_buffer);  }  /* Then free the file structure itself. */  free(ff);  filp->f_priv = NULL;  return ret;}/**************************************************************************** * Name: fat_read ****************************************************************************/static ssize_t fat_read(FAR struct file *filp, char *buffer, size_t buflen){  struct inode         *inode;  struct fat_mountpt_s *fs;  struct fat_file_s    *ff;  uint32                cluster;  unsigned int          bytesread;  unsigned int          readsize;  unsigned int          nsectors;  size_t                readsector;  size_t                bytesleft;  ubyte                 *userbuffer = (ubyte*)buffer;  int                   ret;  /* Sanity checks */  DEBUGASSERT(filp->f_priv != NULL && filp->f_inode != NULL);  /* Recover our private data from the 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 */  fat_semtake(fs);  ret = fat_checkmount(fs);  if (ret != OK)    {      goto errout_with_semaphore;    }  /* Check if the file was opened with read access */  if ((ff->ff_oflags & O_RDOK) == 0)    {      ret = -EACCES;      goto errout_with_semaphore;    }  /* Get the number of bytes left in the file */  bytesleft = ff->ff_size - ff->ff_position;  /* Truncate read count so that it does not exceed the number   * of bytes left in the file.   */  if (buflen > bytesleft)  {      buflen = bytesleft;  }  /* Loop until either (1) all data has been transferred, or (2) an   * error occurs.   */  readsize   = 0;  readsector = ff->ff_currentsector;  while (buflen > 0)    {      /* Get offset into the sector where we begin the read */      int sectorindex = ff->ff_position & SEC_NDXMASK(fs);      bytesread = 0;      /* Check if the current read stream happens to lie on a       * sector boundary.       */      if (sectorindex == 0)        {          /* Try to read another contiguous sector from the cluster */          ff->ff_sectorsincluster--;          /* Are there unread sectors remaining in the cluster? */          if (ff->ff_sectorsincluster > 0)            {              /* Yes.. There are more sectors in this cluster to be read               * just increment the current sector number and read.               */              readsector = ff->ff_currentsector + 1;            }          else            {              /* No.. Handle the case of the first sector of the file */              if (ff->ff_position == 0)                {                  /* Get the first cluster of the file */                  cluster = ff->ff_startcluster;                }              /* But in the general case, we have to find the next cluster               * in the FAT.               */              else                {                  cluster = fat_getcluster(fs, ff->ff_currentcluster);                }              /* Verify the cluster number */              if (cluster < 2 || cluster >= fs->fs_nclusters)                {                  ret = -EINVAL; /* Not the right error */                  goto errout_with_semaphore;                }              /* Setup to read the first sector from the new cluster */              ff->ff_currentcluster   = cluster;              ff->ff_sectorsincluster = fs->fs_fatsecperclus;              readsector              = fat_cluster2sector(fs, cluster);            }        }      /* Check if the user has provided a buffer large enough to       * hold one or more complete sectors.       */      nsectors = buflen / fs->fs_hwsectorsize;      if (nsectors > 0)        {          /* Read maximum contiguous sectors directly to the user's           * buffer without using our tiny read buffer.           *           * Limit the number of sectors that we read on this time           * through the loop to the remaining contiguous sectors           * in this cluster           */          if (nsectors > ff->ff_sectorsincluster)            {              nsectors = ff->ff_sectorsincluster;            }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -