stat()函数解析

在完成任务的过程中遇到了一个问题就是调用stat函数获取文件信息的时候有些文件总是返回错误代码22(EVAL),后来一步一步跟踪到内核源码里面发现原来是文件名的长度超出了规定的长度。

因为是在nuttx上使用的该系统调用,所以以为是不是其中有bug,最后才知道是配置文件.config中配置CONFIG_FAT_MAXNAME为32太小了。之前也没有了解过该系统调用,所以就来仔细的看一看这个函数。

int stat(FAR const char *path, FAR struct stat *buf)

struct inode *inode_find(FAR const char *path, FAR const char **relpath)

首先根据路径名查找到相应的inode,inode是文件系统存放文件的一种形式,最小单位是扇区(sector),多个扇区集合成一个节点,节点分为文件信息节点和文件数据节点,注意的是一个目录名单独存放在一个节点中,linux中ext2/3/4文件系统都有这样的一种概念。

需要注意的是每一个节点都有9个标志位,有三组,每组中有3个标志位,分别表示可读,可写,可执行。

struct inode
  {
    FAR struct inode *i_peer;     /* Link to same level inode */
    FAR struct inode *i_child;    /* Link to lower level inode */
    int16_t           i_crefs;    /* References to inode */
    uint16_t          i_flags;    /* Flags for inode */
    union inode_ops_u u;          /* Inode operations */
  #ifdef CONFIG_FILE_MODE
    mode_t            i_mode;     /* Access mode flags */
  #endif
    FAR void         *i_private;  /* Per inode driver private data */
    char              i_name[1];  /* Name of inode (variable) */
  #ifdef CONFIG_SECURITY_IDMAC
    void             *i_security;
  #endif
  };

上面是nuttx中inode的数据结构,比linux中的inode数据结构简单很多,看了结构体中的内容可以看到其中肯定有链表的操作,而对文件操作则i_mode,注意i_mode的初始化操作是在mount操作,根据不同的文件系统格式来注册相应的回调函数。

static FAR const struct mountpt_operations *
 mount_findfs(FAR const struct fsmap_t *fstab, FAR const char *filesystemtype)

因为我使用的vfat格式的文件系统所以相应的回调函数是:

  const struct mountpt_operations fat_operations =
  {
    fat_open,          /* open */
    fat_close,         /* close */
    fat_read,          /* read */
    fat_write,         /* write */
    fat_seek,          /* seek */ 
    fat_ioctl,         /* ioctl */
  
    fat_sync,          /* sync */
    fat_dup,           /* dup */
     
    fat_opendir,       /* opendir */
    NULL,              /* closedir */
    fat_readdir,       /* readdir */
    fat_rewinddir,     /* rewinddir */
  
    fat_bind,          /* bind */
    fat_unbind,        /* unbind */
    fat_statfs,        /* statfs */
  
    fat_unlink,        /* unlinke */
    fat_mkdir,         /* mkdir */
    fat_rmdir,         /* rmdir */
    fat_rename,        /* rename */
    fat_stat           /* stat */
  };


在inode_find函数中最核心的函数是inode_search()。


FAR struct inode *inode_search(FAR const char **path,
                                FAR struct inode **peer,
                                FAR struct inode **parent,
                                FAR const char **relpath);
该函数根据文件名字依次一个一个寻找有相应的名字的inode(这里面就涉及了链表操作),并且返回。

找到相应的inode之后,就要执行一个相对中重要的函数

if (inode->u.i_mops && inode->u.i_mops->stat)
         {
           /* Perform the stat() operation */
 
           ret = inode->u.i_mops->stat(inode, relpath, buf);
         }
所以这里也就要调用之前已经注册好的vfat的相应stat回调函数。

static int fat_stat(FAR struct inode *mountpt, FAR const char *relpath,
                     FAR struct stat *buf);

该函数主要是找到相应的文件,并且把相应的文件信息填充到stat 结构体中

struct stat
 {
   mode_t    st_mode;    /* File type, atributes, and access mode bits */
   off_t     st_size;    /* Size of file/directory, in bytes */
   blksize_t st_blksize; /* Blocksize used for filesystem I/O */
   blkcnt_t  st_blocks;  /* Number of blocks allocated */
   time_t    st_atime;   /* Time of last access */
   time_t    st_mtime;   /* Time of last modification */
   time_t    st_ctime;   /* Time of last status change */
 };
在该函数中,比较重要的是

int fat_finddirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo,
                      const char *path);

而在这个函数中核心函数又是

static int fat_path2dirname(const char **path, struct fat_dirinfo_s *dirinfo,
                             char *terminator);


终于我们来到了最fat文件系统解析文件的最核心的函数了fat_parsesfname


Name: fat_parsesfname
  *
  * Desciption:  Convert a user filename into a properly formatted FAT
  *   (short 8.3) filename as it would appear in a directory entry.  Here are
  *    the rules for the 8+3 short file 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 ' '
  *
  *   Other characters may be any characters except for the following:
  *
  *     0x00-0x1f = (except for 0x00 and 0x05 in the first byte)
  *     0x22      = '"'
  *     0x2a-0x2c = '*', '+', ','
  *     0x2e-0x2f = '.', '/'
  *     0x3a-0x3f = ':', ';', '<', '=', '>', '?'
  *     0x5b-0x5d = '[', '\\', ;]'
  *     0x7c      = '|'
  *
  *   '.' May only occur once within string and only within the first 9
  *   bytes.  The '.' is not save in the directory, but is implicit in
  *   8+3 format.
  *
  *   Lower case characters are not allowed in directory names (without some
  *   poorly documented operations 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_parsesfname(const char **path,
                                   struct fat_dirinfo_s *dirinfo,
                                   char *terminator);

该函数会判断是不是可打印的字符,是不是被fat文件系统禁止的字符。

下面是nuttx中inode的数据结构,比linux中的inode数据结构简单很多,看了结构体中的内容可以看到其中肯定有链表的操作,而对文件操作则i_mode。
static inline int fat_parselfname(const char **path,
                                   struct fat_dirinfo_s *dirinfo,
                                   char *terminator)
该函数就是之前一直卡住我的问题,路径长度已经超过了事先定义好的长度。

当该路径名字符和fat文件系统的标准,之后就开始填充struct stat结构体了。


下面是nuttx中inode的数据结构,比linux中的inode数据结构简单很多,看了结构体中的内容可以看到其中肯定有链表的操作,而对文件操作则i_mode。

你可能感兴趣的:(nuttx)