📄 fs_fat32.c
字号:
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) { fat_semgive(fs); return ret; } /* ioctl calls are just passed through to the contained block driver */ fat_semgive(fs); return -ENOSYS;}/**************************************************************************** * Name: fat_sync * * Description: Synchronize the file state on disk to match internal, in- * memory state. * ****************************************************************************/static int fat_sync(FAR struct file *filp){ struct inode *inode; struct fat_mountpt_s *fs; struct fat_file_s *ff; uint32 wrttime; ubyte *direntry; 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 has been modified in any way */ if ((ff->ff_bflags & FFBUFF_MODIFIED) != 0) { /* Flush any unwritten data in the file buffer */ ret = fat_ffcacheflush(fs, ff); if (ret < 0) { goto errout_with_semaphore; } /* Update the directory entry. First read the directory * entry into the fs_buffer (preserving the ff_buffer) */ ret = fat_fscacheread(fs, ff->ff_dirsector); if (ret < 0) { goto errout_with_semaphore; } /* Recover a pointer to the specific directory entry * in the sector using the saved directory index. */ direntry = &fs->fs_buffer[ff->ff_dirindex * 32]; /* Set the archive bit, set the write time, and update * anything that may have* changed in the directory * entry: the file size, and the start cluster */ direntry[DIR_ATTRIBUTES] |= FATATTR_ARCHIVE; DIR_PUTFILESIZE(direntry, ff->ff_size); DIR_PUTFSTCLUSTLO(direntry, ff->ff_startcluster); DIR_PUTFSTCLUSTHI(direntry, ff->ff_startcluster >> 16); wrttime = fat_systime2fattime(); DIR_PUTWRTTIME(direntry, wrttime & 0xffff); DIR_PUTWRTDATE(direntry, wrttime >> 16); /* Clear the modified bit in the flags */ ff->ff_bflags &= ~FFBUFF_MODIFIED; /* Flush these change to disk and update FSINFO (if * appropriate. */ fs->fs_dirty = TRUE; ret = fat_updatefsinfo(fs); }errout_with_semaphore: fat_semgive(fs); return ret;}/**************************************************************************** * Name: fat_opendir * * Description: Open a directory for read access * ****************************************************************************/static int fat_opendir(struct inode *mountpt, const char *relpath, struct internal_dir_s *dir){ struct fat_mountpt_s *fs; struct fat_dirinfo_s dirinfo; int ret; /* Sanity checks */ DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); /* Recover our private data from the inode instance */ fs = mountpt->i_private; /* Make sure that the mount is still healthy */ fat_semtake(fs); ret = fat_checkmount(fs); if (ret != OK) { goto errout_with_semaphore; } /* Find the requested directory */ ret = fat_finddirentry(fs, &dirinfo, relpath); if (ret < 0) { goto errout_with_semaphore; } /* Check if this is the root directory */ if (dirinfo.fd_entry == NULL) { /* Handle the FAT12/16/32 root directory using the values setup by * fat_finddirentry() above. */ dir->u.fat.fd_startcluster = dirinfo.dir.fd_startcluster; dir->u.fat.fd_currcluster = dirinfo.dir.fd_currcluster; dir->u.fat.fd_currsector = dirinfo.dir.fd_currsector; dir->u.fat.fd_index = dirinfo.dir.fd_index; } /* This is not the root directory. Verify that it is some kind of directory */ else if ((DIR_GETATTRIBUTES(dirinfo.fd_entry) & FATATTR_DIRECTORY) == 0) { /* The entry is not a directory */ ret = -ENOTDIR; goto errout_with_semaphore; } else { /* The entry is a directory */ dir->u.fat.fd_startcluster = ((uint32)DIR_GETFSTCLUSTHI(dirinfo.fd_entry) << 16) | DIR_GETFSTCLUSTLO(dirinfo.fd_entry); dir->u.fat.fd_currcluster = dir->u.fat.fd_startcluster; dir->u.fat.fd_currsector = fat_cluster2sector(fs, dir->u.fat.fd_currcluster); dir->u.fat.fd_index = 2; } fat_semgive(fs); return OK;errout_with_semaphore: fat_semgive(fs); return ERROR;}/**************************************************************************** * Name: fat_readdir * * Description: Read the next directory entry * ****************************************************************************/static int fat_readdir(struct inode *mountpt, struct internal_dir_s *dir){ struct fat_mountpt_s *fs; unsigned int dirindex; ubyte *direntry; ubyte ch; ubyte attribute; int ret = OK; /* Sanity checks */ DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); /* Recover our private data from the inode instance */ fs = mountpt->i_private; /* Make sure that the mount is still healthy */ fat_semtake(fs); ret = fat_checkmount(fs); if (ret != OK) { goto errout_with_semaphore; } /* Read the next directory entry */ dir->fd_dir.d_name[0] = '\0'; while (dir->u.fat.fd_currsector && dir->fd_dir.d_name[0] == '\0') { ret = fat_fscacheread(fs, dir->u.fat.fd_currsector); if (ret < 0) { goto errout_with_semaphore; } /* Get a reference to the current directory entry */ dirindex = (dir->u.fat.fd_index & DIRSEC_NDXMASK(fs)) * 32; direntry = &fs->fs_buffer[dirindex]; /* Has it reached to end of the directory */ ch = *direntry; if (ch == DIR0_ALLEMPTY) { /* We signal the end of the directory by returning the * special error -ENOENT */ ret = -ENOENT; goto errout_with_semaphore; } /* No, is the current entry a valid entry? */ attribute = DIR_GETATTRIBUTES(direntry); if (ch != DIR0_EMPTY && (attribute & FATATTR_VOLUMEID) == 0) { /* Yes.. get the name from the directory info */ (void)fat_dirname2path(dir->fd_dir.d_name, direntry); /* And the file type */ if ((attribute & FATATTR_DIRECTORY) == 0) { dir->fd_dir.d_type = DTYPE_FILE; } else { dir->fd_dir.d_type = DTYPE_DIRECTORY; } } /* Set up the next directory index */ if (fat_nextdirentry(fs, &dir->u.fat) != OK) { ret = -ENOENT; goto errout_with_semaphore; } } fat_semgive(fs); return OK;errout_with_semaphore: fat_semgive(fs); return ret;}/**************************************************************************** * Name: fat_rewindir * * Description: Reset directory read to the first entry * ****************************************************************************/static int fat_rewinddir(struct inode *mountpt, struct internal_dir_s *dir){ struct fat_mountpt_s *fs; int ret; /* Sanity checks */ DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); /* Recover our private data from the inode instance */ fs = mountpt->i_private; /* Make sure that the mount is still healthy */ fat_semtake(fs); ret = fat_checkmount(fs); if (ret != OK) { goto errout_with_semaphore; } /* Check if this is the root directory */ if (fs->fs_type != FSTYPE_FAT32 && dir->u.fat.fd_startcluster == 0) { /* Handle the FAT12/16 root directory */ dir->u.fat.fd_currcluster = 0; dir->u.fat.fd_currsector = fs->fs_rootbase; dir->u.fat.fd_index = 0; } else if (fs->fs_type == FSTYPE_FAT32 && dir->u.fat.fd_startcluster == fs->fs_rootbase) { /* Handle the FAT32 root directory */ dir->u.fat.fd_currcluster = dir->u.fat.fd_startcluster; dir->u.fat.fd_currsector = fat_cluster2sector(fs, fs->fs_rootbase); dir->u.fat.fd_index = 0; } /* This is not the root directory */ else { dir->u.fat.fd_currcluster = dir->u.fat.fd_startcluster; dir->u.fat.fd_currsector = fat_cluster2sector(fs, dir->u.fat.fd_currcluster); dir->u.fat.fd_index = 2; } fat_semgive(fs); return OK;errout_with_semaphore: fat_semgive(fs); return ERROR;}/**************************************************************************** * Name: fat_bind * * Description: This implements a portion of the mount operation. This * function allocates and initializes the mountpoint private data and * binds the blockdriver inode to the filesystem private data. The final * binding of the private data (containing the blockdriver) to the * mountpoint is performed by mount(). * ****************************************************************************/static int fat_bind(FAR struct inode *blkdriver, const void *data, void **handle){ struct fat_mountpt_s *fs; int ret; /* Open the block driver */ if (!blkdriver || !blkdriver->u.i_bops) { return -ENODEV; } if (blkdriver->u.i_bops->open && blkdriver->u.i_bops->open(blkdriver) != OK) { return -ENODEV; } /* Create an instance of the mountpt state structure */ fs = (struct fat_mountpt_s *)zalloc(sizeof(struct fat_mountpt_s)); if (!fs) { return -ENOMEM; } /* Initialize the allocated mountpt state structure. The filesystem is * responsible for one reference ont the blkdriver inode and does not * have to addref() here (but does have to release in ubind(). */ fs->fs_blkdriver = blkdriver; /* Save the block driver reference */ sem_init(&fs->fs_sem, 0, 0); /* Initialize the semaphore that controls access */ /* Then get information about the FAT32 filesystem on the devices managed * by this block driver. */ ret = fat_mount(fs, TRUE); if (ret != 0) { sem_destroy(&fs->fs_sem); free(fs); return ret; } *handle = (void*)fs; fat_semgive(fs); return OK;}/**************************************************************************** * Name: fat_unbind * * Description: This implements the filesystem portion of the umount * operation. * ****************************************************************************/static int fat_unbind(void *handle, FAR struct inode **blkdriver){ struct fat_mountpt_s *fs = (struct fat_mountpt_s*)handle; int ret; if (!fs) { return -EINVAL; } /* Check if there are sill any files opened on the filesystem. */ ret = OK; /* Assume success */ fat_semtake(fs); if (fs->fs_head) { /* We cannot unmount now.. there are open files */ ret = -EBUSY; } else { /* Unmount ... close the block driver */ if (fs->fs_blkdriver) { struct inode *inode = fs->fs_blkdriver; if (inode) { if (inode->u.i_bops && inode->u.i_bops->close) { (void)inode->u.i_bops->close(inode); } /* We hold a reference to the block driver but should * not but mucking with inodes in this context. So, we will just return * our contained reference to the block driver inode and let the umount * logic dispose of it. */ if (blkdriver) { *blkdriver = inode; } } } /* Release the mountpoint private data */ if (fs->fs_buffer) { free(fs->fs_buffer); } free(fs); } fat_semgive(fs); 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 * * Description: Remove a file
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -