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

📄 fatfs.c

📁 嵌入式FAT文件系统
💻 C
📖 第 1 页 / 共 4 页
字号:

    if (err == ENOERR && (mode & O_TRUNC))
    {
        // If the O_TRUNC bit is set we must clean out the file data
        CYG_TRACE0(TFS, "truncating file"); 
        fatfs_trunc_file(disk, &node->dentry);
    }

    if (err != ENOERR)
        return err;
    
    if (S_ISDIR(node->dentry.mode))
        return EISDIR;

#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
    // if the file is read only and is opened for writing
    // fail with permission error
    if (S_FATFS_ISRDONLY(node->dentry.attrib) && (mode & O_WRONLY))
        return EACCES;
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES

    // Allocate file object private data and
    // make a reference to this file node

    fd = alloc_fatfs_fd(disk, node);
    if (NULL == fd)
        return EMFILE;

    fatfs_node_ref(disk, node);

    // Initialize the file object

    if (mode & O_APPEND)
        fatfs_setpos(disk, &node->dentry, &fd->pos, node->dentry.size);  
    
    file->f_flag   |= mode & CYG_FILE_MODE_MASK;
    file->f_type    = CYG_FILE_TYPE_FILE;
    file->f_ops     = &fatfs_fileops;
    file->f_offset  = (mode & O_APPEND) ? node->dentry.size : 0;
    file->f_data    = (CYG_ADDRWORD) fd;
    file->f_xops    = 0;

    return ENOERR;
}

// -------------------------------------------------------------------------
// fatfs_unlink()
// Remove a file link from its directory.

static int 
fatfs_unlink(cyg_mtab_entry *mte, 
             cyg_dir         dir, 
             const char     *name)
{
    fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
    fatfs_dirsearch_t   ds;
    int                 err;

    CYG_TRACE3(TFS, "unlink mte=%p dir=%p name='%s'", mte, dir, name);

    init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name);

    err = fatfs_find(&ds);

    if (err != ENOERR)
        return err;

    if (ds.node->refcnt > 0)
        return EBUSY;
    
#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
    // if the file is read only fail with permission error
    if (S_FATFS_ISRDONLY(ds.node->dentry.attrib))
        return EPERM;
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES

    err = fatfs_delete_file(disk, &ds.node->dentry);
    if (err == ENOERR)
        fatfs_node_free(disk, ds.node);
    
    return err;
}

// -------------------------------------------------------------------------
// fatfs_mkdir()
// Create a new directory.

static int
fatfs_mkdir(cyg_mtab_entry *mte, cyg_dir dir, const char *name)
{
    fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
    fatfs_dirsearch_t   ds;
    int                 err;
    cyg_uint8 shortname[12+1]={0};
    CYG_TRACE3(TFS, "mkdir mte=%p dir=%p name='%s'", mte, dir, name);

    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);

    err = fatfs_find(&ds);

    if (err == ENOENT)
    {
        if (ds.last)
        {
            fatfs_dir_entry_t new_dir_dentry;
            
            // The entry does not exist, and it is the last element in
            // the pathname, so we can create it here
           err=create_shortname(dir, disk,fatfs_utf8_table, ds.name,ds.namelen,shortname);
           if(err<0) return err;
            err = fatfs_create_dir(disk, 
                                   &ds.dir->dentry, 
                                   shortname,
                                   strlen(shortname),
                                   ds.name, 
                                   ds.namelen, 
                                   &new_dir_dentry);
            if (err != ENOERR)
                return err;
            
            fatfs_node_alloc(disk, &new_dir_dentry);

            return ENOERR;
        }
    } 
    else if (err == ENOERR)
    {
        return EEXIST;
    }
    
    return err;
}

// -------------------------------------------------------------------------
// fatfs_rmdir()
// Remove a directory.

static int 
fatfs_rmdir(cyg_mtab_entry *mte, cyg_dir dir, const char *name)
{
    fatfs_disk_t      *disk = (fatfs_disk_t *) mte->data;
    fatfs_dirsearch_t  ds;
    int                err;
    fatfs_node_t      *node;

    CYG_TRACE3(TFS, "rmdir mte=%p dir=%p name='%s'", mte, dir, name);

    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);

    err = fatfs_find(&ds);

    if (err != ENOERR)
        return err;
  
    if (!S_ISDIR(ds.node->dentry.mode))
        return EPERM;
 
    if (ds.node->refcnt > 0)
        return EBUSY;
    
    err = fatfs_delete_file(disk, &ds.node->dentry);
    if (err == ENOERR)
    {
        node = fatfs_node_find( disk, ".", 1, ds.node->dentry.cluster );
        if (node != NULL)
             fatfs_node_free(disk, node);

        node = fatfs_node_find( disk, "..", 2, ds.node->dentry.cluster );
        if (node != NULL)
            fatfs_node_free(disk, node);

        fatfs_node_free(disk, ds.node);
    }
    return err;
}

// -------------------------------------------------------------------------
// fatfs_rename()
// Rename a file/dir.

static int 
fatfs_rename(cyg_mtab_entry *mte, 
             cyg_dir         dir1, 
             const char     *name1,
             cyg_dir         dir2, 
             const char     *name2)
{
    fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
    fatfs_dirsearch_t   ds1, ds2;
    int                 err;
    cyg_uint8  shortname[12+1]={0};
    CYG_TRACE5(TFS, "rename mte=%p dir1=%p name1='%s' dir2=%p name2='%s'", 
                    mte, dir1, name1, dir2, name2);

    init_dirsearch(&ds1, disk, (fatfs_node_t *)dir1, name1);

    err = fatfs_find(&ds1);
    if (err != ENOERR)
        return err;

#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
    // if the file is read only fail with permission error
    if (S_FATFS_ISRDONLY(ds1.node->dentry.attrib))
        return EPERM;
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES

    // Protect the found nodes from being reused 
    // by the search for the ds2 dir/node pair 
    fatfs_node_ref(disk, ds1.dir);
    fatfs_node_ref(disk, ds1.node);
    
    init_dirsearch(&ds2, disk, (fatfs_node_t *) dir2, name2);
   
    err = fatfs_find(&ds2);

    // Check if the target name already exists
    if (err == ENOERR && ds2.last)
    {
        err = EEXIST;  
        goto out;  
    }
    
    // Check if the target dir doesn't exist
    if (err == ENOENT && !ds2.last)
        goto out;
    
    // Check if the target and the source are the same
    if (ds1.node == ds2.node)
    {
        err = ENOERR;
        goto out;
    }
    err=create_shortname(dir2, disk,fatfs_utf8_table, ds2.name,ds2.namelen,shortname);
    if(err<0) return err;
    err = fatfs_rename_file(disk, 
                            &ds1.dir->dentry, 
                            &ds1.node->dentry, 
                            &ds2.dir->dentry, 
                            shortname,
                            strlen(shortname),
                            ds2.name, 
                            ds2.namelen);  

    fatfs_node_rehash(disk, ds1.node);

out:
    // Unreference previousely protected nodes
    fatfs_node_unref(disk, ds1.dir);
    fatfs_node_unref(disk, ds1.node);
   
    if (err == ENOERR)
    {
        ds1.dir->dentry.atime =
        ds1.dir->dentry.mtime = 
        ds2.dir->dentry.atime = 
        ds2.dir->dentry.mtime = cyg_timestamp();    
    } 
    return err;
}

// -------------------------------------------------------------------------
// fatfs_link()
// Make a new directory entry for a file.

static int 
fatfs_link(cyg_mtab_entry *mte, 
           cyg_dir         dir1, 
           const char     *name1,
           cyg_dir         dir2, 
           const char     *name2, 
           int             type)
{
    CYG_TRACE6(TFS, "link mte=%p dir1=%p name1='%s' dir2=%p name2='%s' type=%d",
                    mte, dir1, name1, dir2, name2, type);

    // Linking not supported
    return EINVAL;
}

// -------------------------------------------------------------------------
// fatfs_opendir()
// Open a directory for reading.

static int
fatfs_opendir(cyg_mtab_entry *mte,
              cyg_dir         dir,
              const char     *name,
              cyg_file       *file)
{
    fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
    fatfs_fd_t         *fd;
    fatfs_dirsearch_t   ds;
    int                 err;

    CYG_TRACE4(TFS, "opendir mte=%p dir=%p name='%s' file=%p", 
                    mte, dir, name, file);

    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);

    err = fatfs_find(&ds);
    if (err != ENOERR)
        return err;

    if (!S_ISDIR(ds.node->dentry.mode)) 
        return ENOTDIR;

    // Allocate file object private data and
    // make a reference to this file node

    fd = alloc_fatfs_fd(disk, ds.node);
    if (NULL == fd)
        return EMFILE;
    
    fatfs_node_ref(disk, ds.node);
    
    // Initialize the file object

    file->f_type    = CYG_FILE_TYPE_FILE;
    file->f_ops     = &fatfs_dirops;
    file->f_data    = (CYG_ADDRWORD) fd;
    file->f_xops    = 0;
    file->f_offset  = 0;

    return ENOERR;
}

// -------------------------------------------------------------------------
// fatfs_chdir()
// Change directory support.

static int
fatfs_chdir(cyg_mtab_entry *mte,
            cyg_dir         dir,
            const char     *name,
            cyg_dir        *dir_out)
{
    fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;

    CYG_TRACE4(TFS, "chdir mte=%p dir=%p dir_out=%p name=%d", 
                    mte, dir, dir_out, name);

    if (dir_out != NULL)
    {
        // This is a request to get a new directory pointer in *dir_out
        
        fatfs_dirsearch_t ds1,ds2,*ds_out;
        int               err;

        init_dirsearch(&ds1, disk, (fatfs_node_t *) dir, name);

        err = fatfs_find(&ds1);
        if (err != ENOERR)
            return err;

        if (!S_ISDIR(ds1.node->dentry.mode))
            return ENOTDIR;

        if((ds1.node->dentry.filename[0]=='.')&&
	   (ds1.node->dentry.filename[1]=='.')&&
	   (ds1.node->dentry.filename[2]==0))
	{
		if(ds1.node->dentry.cluster==0)
		{
			ds2.node=disk->root;
			ds_out=&ds2;
		}
		else
		{	
			init_dirsearch(&ds2,disk,ds1.node,".");
			err=fatfs_find(&ds2);
			if(err!=ENOERR)
				return err;
			ds_out=&ds2;
		}
	}
	else
	{
		ds_out=&ds1;
	}
        if(ds_out->node!=disk->root)
		fatfs_node_ref(disk,ds_out->node);

        *dir_out = (cyg_dir) ds_out->node;
    }
    else
    {
        // If no output dir is required, this means that the mte and
        // dir arguments are the current cdir setting and we should
        // forget this fact.

        fatfs_node_t *node = (fatfs_node_t *) dir;

        if (node != disk->root)
            fatfs_node_unref(disk, node);
    }

    return ENOERR;
}

// -------------------------------------------------------------------------
// fatfs_stat()
// Get struct stat info for named object.

static int
fatfs_stat(cyg_mtab_entry *mte,
           cyg_dir         dir,
           const char     *name,
           struct stat    *buf)
{
    fatfs_disk_t      *disk = (fatfs_disk_t *) mte->data;
    fatfs_dirsearch_t  ds;
    int                err;

    CYG_TRACE4(TFS, "stat mte=%p dir=%p name='%s' buf=%p", 
                    mte, dir, name, buf);

    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);

    err = fatfs_find(&ds);
    if (err != ENOERR)
        return err;

    // Fill in the status
    
    buf->st_mode   = ds.node->dentry.mode;
#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
    if (!S_FATFS_ISRDONLY(ds.node->dentry.attrib))
        buf->st_mode |= (S_IWUSR | S_IWGRP | S_IWOTH);
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
    buf->st_ino    = (ino_t) ds.node->dentry.cluster;
    buf->st_dev    = 0;
    buf->st_nlink  = 1;
    buf->st_uid    = 0;
    buf->st_gid    = 0;
    buf->st_size   = ds.node->dentry.size;
    buf->st_atime  = ds.node->dentry.atime;
    buf->st_mtime  = ds.node->dentry.mtime;
    buf->st_ctime  = ds.node->dentry.ctime;

    return ENOERR;
}

#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
// -------------------------------------------------------------------------
// fatfs_set_attrib()
// Set FAT file system attributes for specified file

static int
fatfs_set_attrib(cyg_mtab_entry        *mte,
                 cyg_dir                dir,
                 const char            *name,
                 const cyg_fs_attrib_t  new_attrib)
{
    fatfs_disk_t      *disk = (fatfs_disk_t *) mte->data;
    fatfs_dirsearch_t  ds;
    int                err;

    CYG_TRACE4(TFS, "set_attrib mte=%p dir=%p name='%s' buf=%x", 
                    mte, dir, name, new_attrib);

    // Verify new_mode is valid
    if ((new_attrib & S_FATFS_ATTRIB) != new_attrib)
        return EINVAL;
    
    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);

    err = fatfs_find(&ds);
    if (err != ENOERR)
        return err;

    // Change the "changeable" mode bits for the file.
    ds.node->dentry.attrib = 
      (ds.node->dentry.attrib & (~S_FATFS_ATTRIB)) | new_attrib;

    return fatfs_write_dir_entry(disk,&ds.node->dentry);
}

// -------------------------------------------------------------------------
// fatfs_get_attrib()

⌨️ 快捷键说明

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