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

📄 fatfs.c

📁 嵌入式FAT文件系统
💻 C
📖 第 1 页 / 共 4 页
字号:
    }
}
static cyg_uint16 fat_bad_char(cyg_uint16 w)
{
	return (w < 0x0020)
	    || (w == '*') || (w == '?') || (w == '<') || (w == '>')
	    || (w == '|') || (w == '"') || (w == ':') || (w == '/')
	    || (w == '\\');
	
}
static  cyg_uint16 fat_replace_char( cyg_uint16 w)
{
	return (w == '[') || (w == ']') || (w == ';') || (w == ',')
	    || (w == '+') || (w == '=');
}

static  cyg_uint16 fat_skip_char( cyg_uint16 w)
{
	return (w == '.') || (w == ' ');
}

static inline int fat_is_used_badchars(const cyg_uint16 *s, int len)
{
	int i;

	for (i = 0; i < len; i++)
		if (fat_bad_char(s[i]))
			return -EINVAL;
	return 0;
}
static int fat_valid_longname(const cyg_uint8 *name, cyg_uint32 len)
{
	if (name[len - 1] == ' ')
		return -EINVAL;
	if (len >= 256)
		return -ENAMETOOLONG;
	return 0;
}
struct shortname_info {
	unsigned char lower:1,
		      upper:1,
		      valid:1;
};
#define INIT_SHORTNAME_INFO(x)	do {		\
	(x)->lower = 1;				\
	(x)->upper = 1;				\
	(x)->valid = 1;				\
} while (0)

static cyg_uint32 to_shortname_char(struct nls_table *nls,
				    cyg_uint8 *buf, cyg_uint32 buf_size,
				    cyg_uint16 *src, struct shortname_info *info)
{
	int len;

	if (fat_skip_char(*src)) {
		info->valid = 0;
		return 0;
	}
	if (fat_replace_char(*src)) {
		info->valid = 0;
		buf[0] = '_';
		return 1;
	}

	len = nls->uni2char(*src, buf, buf_size);
	if (len <= 0) {
		info->valid = 0;
		buf[0] = '_';
		len = 1;
	} else if (len == 1) {
		unsigned char prev = buf[0];

		if (buf[0] >= 0x7F) {
			info->lower = 0;
			info->upper = 0;
		}

		buf[0] = nls_toupper(nls, buf[0]);
		if (isalpha(buf[0])) {
			if (buf[0] == prev)
				info->lower = 0;
			else
				info->upper = 0;
		}
	} else {
		info->lower = 0;
		info->upper = 0;
	}

	return len;
}
static cyg_uint16 uname[256]={0};
static cyg_uint8 tmp_name_res[12]={0};
int create_shortname(cyg_dir dir,
                         fatfs_disk_t *disk,
                        struct nls_table *nls,
			const char *name,int len,
			cyg_uint8 *name_res)
{
	cyg_uint16 *ip, *ext_start, *end, *name_start;
	cyg_uint8 base[9], ext[4], buf[8], *p;
	cyg_uint8 charbuf[NLS_MAX_CHARSET_SIZE];	
	int ret,ulen=0;
	int chl, chi;
	cyg_uint32 jiffies;
	int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen;
	int is_shortname;
	fatfs_dirsearch_t ds;
	struct shortname_info base_info, ext_info;
	jiffies=rand();
	is_shortname = 1;
	INIT_SHORTNAME_INFO(&base_info);
	INIT_SHORTNAME_INFO(&ext_info);
        for(i=0;i<len;)
        {
	        ret=fatfs_utf8_table->char2uni(name+i, len, &(uname[ulen]));
		if(ret<0)  return ret;
		if(ulen>=256) return -1;
		i+=ret;
		ulen++;
	}
	/* Now, we need to create a shortname from the long name */
	ext_start = end = &uname[ulen];
	while (--ext_start >= uname) {
		if (*ext_start == 0x002E) {	/* is `.' */
			if (ext_start == end - 1) {
				sz = ulen;
				ext_start = NULL;
			}
			break;
		}
	}
		if (ext_start == uname - 1) {
		sz = ulen;
		ext_start = NULL;
	} else if (ext_start) {
		/*
		 * Names which start with a dot could be just
		 * an extension eg. "...test".  In this case Win95
		 * uses the extension as the name and sets no extension.
		 */
		name_start = &uname[0];
		while (name_start < ext_start) {
			if (!fat_skip_char(*name_start))
				break;
			name_start++;
		}
		if (name_start != ext_start) {
			sz = ext_start - uname;
			ext_start++;
		} else {
			sz = ulen;
			ext_start = NULL;
		}
	}

	numtail_baselen = 6;
	numtail2_baselen = 2;
	for (baselen = i = 0, p = base, ip = uname; i < sz; i++, ip++) {
		chl = to_shortname_char(nls, charbuf, sizeof(charbuf),
					ip, &base_info);
		if (chl == 0)
			continue;

		if (baselen < 2 && (baselen + chl) > 2)
			numtail2_baselen = baselen;
		if (baselen < 6 && (baselen + chl) > 6)
			numtail_baselen = baselen;
		for (chi = 0; chi < chl; chi++) {
			*p++ = charbuf[chi];
			baselen++;
			if (baselen >= 8)
				break;
		}
		if (baselen >= 8) {
			if ((chi < chl - 1) || (ip + 1) - uname < sz)
				is_shortname = 0;
			break;
		}
	}
	if (baselen == 0) {
		return -EINVAL;
	}

	extlen = 0;
	if (ext_start) {
		for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) {
			chl = to_shortname_char(nls, charbuf, sizeof(charbuf),
						ip, &ext_info);
			if (chl == 0)
				continue;

			if ((extlen + chl) > 3) {
				is_shortname = 0;
				break;
			}
			for (chi = 0; chi < chl; chi++) {
				*p++ = charbuf[chi];
				extlen++;
			}
			if (extlen >= 3) {
				if (ip + 1 != end)
					is_shortname = 0;
				break;
			}
		}
	}
	ext[extlen] = '\0';
	base[baselen] = '\0';

	/* Yes, it can happen. ".\xe5" would do it. */
	if (base[0] == 0xe5)
		base[0] = 0x05;

	/* OK, at this point we know that base is not longer than 8 symbols,
	 * ext is not longer than 3, base is nonempty, both don't contain
	 * any bad symbols (lowercase transformed to uppercase).
	 */

	memset(name_res, ' ', 11);
	memcpy(name_res, base, baselen);
	memcpy(name_res + 8, ext, extlen);

	if (is_shortname && base_info.valid && ext_info.valid) {
		memset(tmp_name_res,0,12);
		for(i=10;i>=0;i--)
		{
                        if(name_res[i]==' ') continue;
			tmp_name_res[i]=name_res[i];
		}
		init_dirsearch(&ds,disk,(fatfs_node_t*)dir,tmp_name_res);
		if (fatfs_find(&ds)==ENOENT)
			return 0;
	}

	/*
	 * Try to find a unique extension.  This used to
	 * iterate through all possibilities sequentially,
	 * but that gave extremely bad performance.  Windows
	 * only tries a few cases before using random
	 * values for part of the base.
	 */

	if (baselen > 6) {
		baselen = numtail_baselen;
		name_res[7] = ' ';
	}
	name_res[baselen] = '~';
	for (i = 1; i < 10; i++) {
		int j;
		name_res[baselen + 1] = i + '0';
		memset(tmp_name_res,0,12);
		for(j=baselen+1;j>=0;j--)
		{
 /*                       if(name_res[j]==' ') continue;*/
			tmp_name_res[j]=name_res[j];
		}
		init_dirsearch(&ds,disk,(fatfs_node_t*)dir,tmp_name_res);
		if (fatfs_find(&ds)==ENOENT)
			return 0;
	}

	i = jiffies & 0xffff;
	sz = (jiffies >> 16) & 0x7;
	if (baselen > 2) {
		baselen = numtail2_baselen;
		name_res[7] = ' ';
	}
	name_res[baselen + 4] = '~';
	name_res[baselen + 5] = '1' + sz;
	while (1) {
		sprintf(buf, "%04X", i);
		memcpy(&name_res[baselen], buf, 4);
		memset(tmp_name_res,0,12);
		for(i=10;i>=0;i--)
		{
                        if(name_res[i]==' ') continue;
			tmp_name_res[i]=name_res[i];
		}
		init_dirsearch(&ds,disk,(fatfs_node_t*)dir,tmp_name_res);
		if (fatfs_find(&ds)==ENOENT)
			return 0;
		i -= 11;
	}
	return 0;
}

//==========================================================================
// Filesystem operations

// -------------------------------------------------------------------------
// fatfs_mount()
// Process a mount request. This mainly creates a root for the
// filesystem.
 static  fatfs_dir_entry_t   root_dentry;
static int 
fatfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte)
{
    cyg_io_handle_t     dev_h;
    fatfs_disk_t       *disk;
 
    Cyg_ErrNo           err;
    
    CYG_TRACE2(TFS, "mount fste=%p mte=%p", fste, mte);
    memset(&root_dentry,0,sizeof(fatfs_dir_entry_t));
    init_fatfs_fds();
    
    CYG_TRACE1(TFS, "looking up disk device '%s'", mte->devname);
    
    err = cyg_io_lookup(mte->devname, &dev_h);
    if (err != ENOERR)
        return err;

    disk = (fatfs_disk_t *)malloc(sizeof(fatfs_disk_t));
    if (NULL == disk)
        return ENOMEM;
        
    CYG_TRACE0(TFS, "initializing block cache"); 

    disk->bcache_mem = (cyg_uint8 *)malloc(CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE);
    if (NULL == disk->bcache_mem)
    {
        free(disk);
        return ENOMEM;
    }
    // FIXME: get block size from disk device
    err = cyg_blib_io_create(dev_h, disk->bcache_mem, 
            CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE, 512, &disk->blib);
    if (err != ENOERR)
    {
        free(disk->bcache_mem);
        free(disk);
        return err;
    }
    
    disk->dev_h = dev_h;

    CYG_TRACE0(TFS, "initializing disk");
    
    err = fatfs_init(disk);
    if (err != ENOERR)
    {
        cyg_blib_delete(&disk->blib);
        free(disk->bcache_mem);
        free(disk);
        return err;
    }
   
#if TFS    
    print_disk_info(disk);
#endif
   /*register the utf8*/
   fatfs_utf8_table=load_nls_utf8();
   if(NULL==fatfs_utf8_table)  return -1;
    CYG_TRACE0(TFS, "initializing node cache");

    fatfs_node_cache_init(disk);
    
    CYG_TRACE0(TFS, "initializing root node");
    
    fatfs_get_root_dir_entry(disk, &root_dentry);
    
    disk->root = fatfs_node_alloc(disk, &root_dentry);

    fatfs_node_ref(disk, disk->root);
    
    mte->root = (cyg_dir)disk->root;
    mte->data = (CYG_ADDRWORD)disk;

    CYG_TRACE0(TFS, "disk mounted");

    return ENOERR;
}

// -------------------------------------------------------------------------
// fatfs_umount()
// Unmount the filesystem. This will currently only succeed if the
// filesystem is empty.

static int
fatfs_umount(cyg_mtab_entry *mte)
{
    fatfs_disk_t  *disk  = (fatfs_disk_t *) mte->data;
    fatfs_node_t  *root  = (fatfs_node_t *) mte->root;

    CYG_TRACE3(TFS, "umount mte=%p %d live nodes %d dead nodes", 
                    mte, fatfs_get_live_node_count(disk), 
                    fatfs_get_dead_node_count(disk));

    if (root->refcnt > 1)
        return EBUSY;
    
    if (fatfs_get_live_node_count(disk) != 1)
        return EBUSY;

    fatfs_node_unref(disk, root);
    fatfs_node_cache_flush(disk);
    // FIXME: cache delete can fail if cache can't be synced
    cyg_blib_delete(&disk->blib); 
    free(disk->bcache_mem);
    free(disk);
    
    mte->root = CYG_DIR_NULL;
    mte->data = (CYG_ADDRWORD) NULL;
    unload_nls_utf8();
    CYG_TRACE0(TFS, "disk umounted");
    
    return ENOERR;
}

// -------------------------------------------------------------------------
// fatfs_open()
// Open a file for reading or writing.

static int 
fatfs_open(cyg_mtab_entry *mte,
           cyg_dir         dir, 
           const char     *name,
           int             mode,  
           cyg_file       *file)
{
    fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
    fatfs_node_t       *node = NULL;
    fatfs_fd_t         *fd;
    fatfs_dirsearch_t   ds;
    int                 err;
    cyg_uint8       shortname[12+1]={0};
    CYG_TRACE5(TFS, "open mte=%p dir=%p name='%s' mode=%d file=%p", 
                    mte, dir, name, mode, file);
   
    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);

    err = fatfs_find(&ds);

    if (err == ENOENT)
    {
        if (ds.last && (mode & O_CREAT))
        {
            fatfs_dir_entry_t new_file_dentry;
            
            // No node there, if the O_CREAT bit is set then we must
            // create a new one. The dir and name fields of the dirsearch
            // object will have been updated so we know where to put it.

            CYG_TRACE1(TFS, "creating new file '%s'", name); 
           err=create_shortname(dir, disk,fatfs_utf8_table, ds.name,ds.namelen,shortname);
           if(err<0) return err;	
            err = fatfs_create_file(disk, 
                                    &ds.dir->dentry, 
                                    shortname,
                                    strlen(shortname),
                                    ds.name, 
                                    ds.namelen, 
                                    &new_file_dentry);
            if (err != ENOERR)
                return err;

            node = fatfs_node_alloc(disk, &new_file_dentry);
            if (NULL == node)
                return EMFILE;
           
            // Update directory times
            ds.dir->dentry.atime =
            ds.dir->dentry.mtime = cyg_timestamp();
            
            err = ENOERR;
        }
    }
    else if (err == ENOERR)
    {
        // The node exists. If the O_CREAT and O_EXCL bits are set, we
        // must fail the open

        if ((mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
            err = EEXIST;
        else
            node = ds.node;
    }

⌨️ 快捷键说明

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